]>
git.saurik.com Git - redis.git/blob - src/anet.c
ba4e6cce89bbc7a552e8510a03a2cb67c53af1f6
   1 /* anet.c -- Basic TCP socket stuff made a bit less boring 
   3  * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com> 
   6  * Redistribution and use in source and binary forms, with or without 
   7  * modification, are permitted provided that the following conditions are met: 
   9  *   * Redistributions of source code must retain the above copyright notice, 
  10  *     this list of conditions and the following disclaimer. 
  11  *   * Redistributions in binary form must reproduce the above copyright 
  12  *     notice, this list of conditions and the following disclaimer in the 
  13  *     documentation and/or other materials provided with the distribution. 
  14  *   * Neither the name of Redis nor the names of its contributors may be used 
  15  *     to endorse or promote products derived from this software without 
  16  *     specific prior written permission. 
  18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  28  * POSSIBILITY OF SUCH DAMAGE. 
  33 #include <sys/types.h> 
  34 #include <sys/socket.h> 
  37 #include <netinet/in.h> 
  38 #include <netinet/tcp.h> 
  39 #include <arpa/inet.h> 
  50 static void anetSetError(char *err
, const char *fmt
, ...) 
  56     vsnprintf(err
, ANET_ERR_LEN
, fmt
, ap
); 
  60 int anetNonBlock(char *err
, int fd
) 
  64     /* Set the socket nonblocking. 
  65      * Note that fcntl(2) for F_GETFL and F_SETFL can't be 
  66      * interrupted by a signal. */ 
  67     if ((flags 
= fcntl(fd
, F_GETFL
)) == -1) { 
  68         anetSetError(err
, "fcntl(F_GETFL): %s", strerror(errno
)); 
  71     if (fcntl(fd
, F_SETFL
, flags 
| O_NONBLOCK
) == -1) { 
  72         anetSetError(err
, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno
)); 
  78 int anetTcpNoDelay(char *err
, int fd
) 
  81     if (setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &yes
, sizeof(yes
)) == -1) 
  83         anetSetError(err
, "setsockopt TCP_NODELAY: %s", strerror(errno
)); 
  89 int anetSetSendBuffer(char *err
, int fd
, int buffsize
) 
  91     if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &buffsize
, sizeof(buffsize
)) == -1) 
  93         anetSetError(err
, "setsockopt SO_SNDBUF: %s", strerror(errno
)); 
  99 int anetTcpKeepAlive(char *err
, int fd
) 
 102     if (setsockopt(fd
, SOL_SOCKET
, SO_KEEPALIVE
, &yes
, sizeof(yes
)) == -1) { 
 103         anetSetError(err
, "setsockopt SO_KEEPALIVE: %s", strerror(errno
)); 
 109 int anetResolve(char *err
, char *host
, char *ipbuf
) 
 111     struct sockaddr_in sa
; 
 113     sa
.sin_family 
= AF_INET
; 
 114     if (inet_aton(host
, &sa
.sin_addr
) == 0) { 
 117         he 
= gethostbyname(host
); 
 119             anetSetError(err
, "can't resolve: %s", host
); 
 122         memcpy(&sa
.sin_addr
, he
->h_addr
, sizeof(struct in_addr
)); 
 124     strcpy(ipbuf
,inet_ntoa(sa
.sin_addr
)); 
 128 static int anetCreateSocket(char *err
, int domain
) { 
 130     if ((s 
= socket(domain
, SOCK_STREAM
, 0)) == -1) { 
 131         anetSetError(err
, "creating socket: %s", strerror(errno
)); 
 135     /* Make sure connection-intensive things like the redis benckmark 
 136      * will be able to close/open sockets a zillion of times */ 
 137     if (setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) == -1) { 
 138         anetSetError(err
, "setsockopt SO_REUSEADDR: %s", strerror(errno
)); 
 144 #define ANET_CONNECT_NONE 0 
 145 #define ANET_CONNECT_NONBLOCK 1 
 146 static int anetTcpGenericConnect(char *err
, char *addr
, int port
, int flags
) 
 149     struct sockaddr_in sa
; 
 151     if ((s 
= anetCreateSocket(err
,AF_INET
)) == ANET_ERR
) 
 154     sa
.sin_family 
= AF_INET
; 
 155     sa
.sin_port 
= htons(port
); 
 156     if (inet_aton(addr
, &sa
.sin_addr
) == 0) { 
 159         he 
= gethostbyname(addr
); 
 161             anetSetError(err
, "can't resolve: %s", addr
); 
 165         memcpy(&sa
.sin_addr
, he
->h_addr
, sizeof(struct in_addr
)); 
 167     if (flags 
& ANET_CONNECT_NONBLOCK
) { 
 168         if (anetNonBlock(err
,s
) != ANET_OK
) 
 171     if (connect(s
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) { 
 172         if (errno 
== EINPROGRESS 
&& 
 173             flags 
& ANET_CONNECT_NONBLOCK
) 
 176         anetSetError(err
, "connect: %s", strerror(errno
)); 
 183 int anetTcpConnect(char *err
, char *addr
, int port
) 
 185     return anetTcpGenericConnect(err
,addr
,port
,ANET_CONNECT_NONE
); 
 188 int anetTcpNonBlockConnect(char *err
, char *addr
, int port
) 
 190     return anetTcpGenericConnect(err
,addr
,port
,ANET_CONNECT_NONBLOCK
); 
 193 int anetUnixGenericConnect(char *err
, char *path
, int flags
) 
 196     struct sockaddr_un sa
; 
 198     if ((s 
= anetCreateSocket(err
,AF_LOCAL
)) == ANET_ERR
) 
 201     sa
.sun_family 
= AF_LOCAL
; 
 202     strncpy(sa
.sun_path
,path
,sizeof(sa
.sun_path
)-1); 
 203     if (flags 
& ANET_CONNECT_NONBLOCK
) { 
 204         if (anetNonBlock(err
,s
) != ANET_OK
) 
 207     if (connect(s
,(struct sockaddr
*)&sa
,sizeof(sa
)) == -1) { 
 208         if (errno 
== EINPROGRESS 
&& 
 209             flags 
& ANET_CONNECT_NONBLOCK
) 
 212         anetSetError(err
, "connect: %s", strerror(errno
)); 
 219 int anetUnixConnect(char *err
, char *path
) 
 221     return anetUnixGenericConnect(err
,path
,ANET_CONNECT_NONE
); 
 224 int anetUnixNonBlockConnect(char *err
, char *path
) 
 226     return anetUnixGenericConnect(err
,path
,ANET_CONNECT_NONBLOCK
); 
 229 /* Like read(2) but make sure 'count' is read before to return 
 230  * (unless error or EOF condition is encountered) */ 
 231 int anetRead(int fd
, char *buf
, int count
) 
 233     int nread
, totlen 
= 0; 
 234     while(totlen 
!= count
) { 
 235         nread 
= read(fd
,buf
,count
-totlen
); 
 236         if (nread 
== 0) return totlen
; 
 237         if (nread 
== -1) return -1; 
 244 /* Like write(2) but make sure 'count' is read before to return 
 245  * (unless error is encountered) */ 
 246 int anetWrite(int fd
, char *buf
, int count
) 
 248     int nwritten
, totlen 
= 0; 
 249     while(totlen 
!= count
) { 
 250         nwritten 
= write(fd
,buf
,count
-totlen
); 
 251         if (nwritten 
== 0) return totlen
; 
 252         if (nwritten 
== -1) return -1; 
 259 static int anetListen(char *err
, int s
, struct sockaddr 
*sa
, socklen_t len
) { 
 260     if (bind(s
,sa
,len
) == -1) { 
 261         anetSetError(err
, "bind: %s", strerror(errno
)); 
 265     if (listen(s
, 511) == -1) { /* the magic 511 constant is from nginx */ 
 266         anetSetError(err
, "listen: %s", strerror(errno
)); 
 273 int anetTcpServer(char *err
, int port
, char *bindaddr
) 
 276     struct sockaddr_in sa
; 
 278     if ((s 
= anetCreateSocket(err
,AF_INET
)) == ANET_ERR
) 
 281     memset(&sa
,0,sizeof(sa
)); 
 282     sa
.sin_family 
= AF_INET
; 
 283     sa
.sin_port 
= htons(port
); 
 284     sa
.sin_addr
.s_addr 
= htonl(INADDR_ANY
); 
 285     if (bindaddr 
&& inet_aton(bindaddr
, &sa
.sin_addr
) == 0) { 
 286         anetSetError(err
, "invalid bind address"); 
 290     if (anetListen(err
,s
,(struct sockaddr
*)&sa
,sizeof(sa
)) == ANET_ERR
) 
 295 int anetUnixServer(char *err
, char *path
, mode_t perm
) 
 298     struct sockaddr_un sa
; 
 300     if ((s 
= anetCreateSocket(err
,AF_LOCAL
)) == ANET_ERR
) 
 303     memset(&sa
,0,sizeof(sa
)); 
 304     sa
.sun_family 
= AF_LOCAL
; 
 305     strncpy(sa
.sun_path
,path
,sizeof(sa
.sun_path
)-1); 
 306     if (anetListen(err
,s
,(struct sockaddr
*)&sa
,sizeof(sa
)) == ANET_ERR
) 
 309         chmod(sa
.sun_path
, perm
); 
 313 static int anetGenericAccept(char *err
, int s
, struct sockaddr 
*sa
, socklen_t 
*len
) { 
 316         fd 
= accept(s
,sa
,len
); 
 321                 anetSetError(err
, "accept: %s", strerror(errno
)); 
 330 int anetTcpAccept(char *err
, int s
, char *ip
, int *port
) { 
 332     struct sockaddr_in sa
; 
 333     socklen_t salen 
= sizeof(sa
); 
 334     if ((fd 
= anetGenericAccept(err
,s
,(struct sockaddr
*)&sa
,&salen
)) == ANET_ERR
) 
 337     if (ip
) strcpy(ip
,inet_ntoa(sa
.sin_addr
)); 
 338     if (port
) *port 
= ntohs(sa
.sin_port
); 
 342 int anetUnixAccept(char *err
, int s
) { 
 344     struct sockaddr_un sa
; 
 345     socklen_t salen 
= sizeof(sa
); 
 346     if ((fd 
= anetGenericAccept(err
,s
,(struct sockaddr
*)&sa
,&salen
)) == ANET_ERR
) 
 352 int anetPeerToString(int fd
, char *ip
, int *port
) { 
 353     struct sockaddr_in sa
; 
 354     socklen_t salen 
= sizeof(sa
); 
 356     if (getpeername(fd
,(struct sockaddr
*)&sa
,&salen
) == -1) { 
 362     if (ip
) strcpy(ip
,inet_ntoa(sa
.sin_addr
)); 
 363     if (port
) *port 
= ntohs(sa
.sin_port
);