]>
git.saurik.com Git - redis.git/blob - src/anet.c
514da8face645d2d4e2edac9b478cee2a0e0febc
   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> 
  36 #include <netinet/in.h> 
  37 #include <netinet/tcp.h> 
  38 #include <arpa/inet.h> 
  49 static void anetSetError(char *err
, const char *fmt
, ...) 
  55     vsnprintf(err
, ANET_ERR_LEN
, fmt
, ap
); 
  59 int anetNonBlock(char *err
, int fd
) 
  63     /* Set the socket nonblocking. 
  64      * Note that fcntl(2) for F_GETFL and F_SETFL can't be 
  65      * interrupted by a signal. */ 
  66     if ((flags 
= fcntl(fd
, F_GETFL
)) == -1) { 
  67         anetSetError(err
, "fcntl(F_GETFL): %s\n", strerror(errno
)); 
  70     if (fcntl(fd
, F_SETFL
, flags 
| O_NONBLOCK
) == -1) { 
  71         anetSetError(err
, "fcntl(F_SETFL,O_NONBLOCK): %s\n", strerror(errno
)); 
  77 int anetTcpNoDelay(char *err
, int fd
) 
  80     if (setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &yes
, sizeof(yes
)) == -1) 
  82         anetSetError(err
, "setsockopt TCP_NODELAY: %s\n", strerror(errno
)); 
  88 int anetSetSendBuffer(char *err
, int fd
, int buffsize
) 
  90     if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &buffsize
, sizeof(buffsize
)) == -1) 
  92         anetSetError(err
, "setsockopt SO_SNDBUF: %s\n", strerror(errno
)); 
  98 int anetTcpKeepAlive(char *err
, int fd
) 
 101     if (setsockopt(fd
, SOL_SOCKET
, SO_KEEPALIVE
, &yes
, sizeof(yes
)) == -1) { 
 102         anetSetError(err
, "setsockopt SO_KEEPALIVE: %s\n", strerror(errno
)); 
 108 int anetResolve(char *err
, char *host
, char *ipbuf
) 
 110     struct sockaddr_in sa
; 
 112     sa
.sin_family 
= AF_INET
; 
 113     if (inet_aton(host
, &sa
.sin_addr
) == 0) { 
 116         he 
= gethostbyname(host
); 
 118             anetSetError(err
, "can't resolve: %s\n", host
); 
 121         memcpy(&sa
.sin_addr
, he
->h_addr
, sizeof(struct in_addr
)); 
 123     strcpy(ipbuf
,inet_ntoa(sa
.sin_addr
)); 
 127 #define ANET_CONNECT_NONE 0 
 128 #define ANET_CONNECT_NONBLOCK 1 
 129 static int anetTcpGenericConnect(char *err
, char *addr
, int port
, int flags
) 
 132     struct sockaddr_in sa
; 
 134     if ((s 
= socket(AF_INET
, SOCK_STREAM
, 0)) == -1) { 
 135         anetSetError(err
, "creating socket: %s\n", strerror(errno
)); 
 138     /* Make sure connection-intensive things like the redis benckmark 
 139      * will be able to close/open sockets a zillion of times */ 
 140     setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)); 
 142     sa
.sin_family 
= AF_INET
; 
 143     sa
.sin_port 
= htons(port
); 
 144     if (inet_aton(addr
, &sa
.sin_addr
) == 0) { 
 147         he 
= gethostbyname(addr
); 
 149             anetSetError(err
, "can't resolve: %s\n", addr
); 
 153         memcpy(&sa
.sin_addr
, he
->h_addr
, sizeof(struct in_addr
)); 
 155     if (flags 
& ANET_CONNECT_NONBLOCK
) { 
 156         if (anetNonBlock(err
,s
) != ANET_OK
) 
 159     if (connect(s
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) { 
 160         if (errno 
== EINPROGRESS 
&& 
 161             flags 
& ANET_CONNECT_NONBLOCK
) 
 164         anetSetError(err
, "connect: %s\n", strerror(errno
)); 
 171 int anetTcpConnect(char *err
, char *addr
, int port
) 
 173     return anetTcpGenericConnect(err
,addr
,port
,ANET_CONNECT_NONE
); 
 176 int anetTcpNonBlockConnect(char *err
, char *addr
, int port
) 
 178     return anetTcpGenericConnect(err
,addr
,port
,ANET_CONNECT_NONBLOCK
); 
 181 int anetUnixGenericConnect(char *err
, char *path
, int flags
) 
 184     struct sockaddr_un sa
; 
 186     if ((s 
= socket(AF_LOCAL
,SOCK_STREAM
,0)) == -1) { 
 187         anetSetError(err
, "creating socket: %s\n", strerror(errno
)); 
 190     sa
.sun_family 
= AF_LOCAL
; 
 191     strncpy(sa
.sun_path
,path
,sizeof(sa
.sun_path
)-1); 
 192     if (flags 
& ANET_CONNECT_NONBLOCK
) { 
 193         if (anetNonBlock(err
,s
) != ANET_OK
) 
 196     if (connect(s
,(struct sockaddr
*)&sa
,sizeof(sa
)) == -1) { 
 197         if (errno 
== EINPROGRESS 
&& 
 198             flags 
& ANET_CONNECT_NONBLOCK
) 
 201         anetSetError(err
, "connect: %s\n", strerror(errno
)); 
 208 int anetUnixConnect(char *err
, char *path
) 
 210     return anetUnixGenericConnect(err
,path
,ANET_CONNECT_NONE
); 
 213 int anetUnixNonBlockConnect(char *err
, char *path
) 
 215     return anetUnixGenericConnect(err
,path
,ANET_CONNECT_NONBLOCK
); 
 218 /* Like read(2) but make sure 'count' is read before to return 
 219  * (unless error or EOF condition is encountered) */ 
 220 int anetRead(int fd
, char *buf
, int count
) 
 222     int nread
, totlen 
= 0; 
 223     while(totlen 
!= count
) { 
 224         nread 
= read(fd
,buf
,count
-totlen
); 
 225         if (nread 
== 0) return totlen
; 
 226         if (nread 
== -1) return -1; 
 233 /* Like write(2) but make sure 'count' is read before to return 
 234  * (unless error is encountered) */ 
 235 int anetWrite(int fd
, char *buf
, int count
) 
 237     int nwritten
, totlen 
= 0; 
 238     while(totlen 
!= count
) { 
 239         nwritten 
= write(fd
,buf
,count
-totlen
); 
 240         if (nwritten 
== 0) return totlen
; 
 241         if (nwritten 
== -1) return -1; 
 248 int anetTcpServer(char *err
, int port
, char *bindaddr
) 
 251     struct sockaddr_in sa
; 
 253     if ((s 
= socket(AF_INET
, SOCK_STREAM
, 0)) == -1) { 
 254         anetSetError(err
, "socket: %s\n", strerror(errno
)); 
 257     if (setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) == -1) { 
 258         anetSetError(err
, "setsockopt SO_REUSEADDR: %s\n", strerror(errno
)); 
 262     memset(&sa
,0,sizeof(sa
)); 
 263     sa
.sin_family 
= AF_INET
; 
 264     sa
.sin_port 
= htons(port
); 
 265     sa
.sin_addr
.s_addr 
= htonl(INADDR_ANY
); 
 267         if (inet_aton(bindaddr
, &sa
.sin_addr
) == 0) { 
 268             anetSetError(err
, "Invalid bind address\n"); 
 273     if (bind(s
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) { 
 274         anetSetError(err
, "bind: %s\n", strerror(errno
)); 
 278     if (listen(s
, 511) == -1) { /* the magic 511 constant is from nginx */ 
 279         anetSetError(err
, "listen: %s\n", strerror(errno
)); 
 286 int anetUnixServer(char *err
, char *path
) 
 289     struct sockaddr_un sa
; 
 291     if ((s 
= socket(AF_LOCAL
,SOCK_STREAM
,0)) == -1) { 
 292         anetSetError(err
, "socket: %s\n", strerror(errno
)); 
 295     memset(&sa
,0,sizeof(sa
)); 
 296     sa
.sun_family 
= AF_LOCAL
; 
 297     strncpy(sa
.sun_path
,path
,sizeof(sa
.sun_path
)-1); 
 298     if (bind(s
,(struct sockaddr
*)&sa
,SUN_LEN(&sa
)) == -1) { 
 299         anetSetError(err
, "bind: %s\n", strerror(errno
)); 
 303     if (listen(s
, 511) == -1) { /* the magic 511 constant is from nginx */ 
 304         anetSetError(err
, "listen: %s\n", strerror(errno
)); 
 311 int anetAccept(char *err
, int serversock
, char *ip
, int *port
) 
 314     struct sockaddr_in sa
; 
 319         fd 
= accept(serversock
, (struct sockaddr
*)&sa
, &saLen
); 
 324                 anetSetError(err
, "accept: %s\n", strerror(errno
)); 
 330     if (ip
) strcpy(ip
,inet_ntoa(sa
.sin_addr
)); 
 331     if (port
) *port 
= ntohs(sa
.sin_port
);