]>
git.saurik.com Git - redis.git/blob - anet.c
893f42c81ded22ae93cb73004b4d4435ec825220
   1 /* anet.c -- Basic TCP socket stuff made a bit less boring 
   3  * Copyright (c) 2006-2009, 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> 
  35 #include <netinet/in.h> 
  36 #include <netinet/tcp.h> 
  37 #include <arpa/inet.h> 
  48 static void anetSetError(char *err
, const char *fmt
, ...) 
  54     vsnprintf(err
, ANET_ERR_LEN
, fmt
, ap
); 
  58 int anetNonBlock(char *err
, int fd
) 
  62     /* Set the socket nonblocking. 
  63      * Note that fcntl(2) for F_GETFL and F_SETFL can't be 
  64      * interrupted by a signal. */ 
  65     if ((flags 
= fcntl(fd
, F_GETFL
)) == -1) { 
  66         anetSetError(err
, "fcntl(F_GETFL): %s\n", strerror(errno
)); 
  69     if (fcntl(fd
, F_SETFL
, flags 
| O_NONBLOCK
) == -1) { 
  70         anetSetError(err
, "fcntl(F_SETFL,O_NONBLOCK): %s\n", strerror(errno
)); 
  76 int anetTcpNoDelay(char *err
, int fd
) 
  79     if (setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &yes
, sizeof(yes
)) == -1) 
  81         anetSetError(err
, "setsockopt TCP_NODELAY: %s\n", strerror(errno
)); 
  87 int anetSetSendBuffer(char *err
, int fd
, int buffsize
) 
  89     if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &buffsize
, sizeof(buffsize
)) == -1) 
  91         anetSetError(err
, "setsockopt SO_SNDBUF: %s\n", strerror(errno
)); 
  97 int anetTcpKeepAlive(char *err
, int fd
) 
 100     if (setsockopt(fd
, SOL_SOCKET
, SO_KEEPALIVE
, &yes
, sizeof(yes
)) == -1) { 
 101         anetSetError(err
, "setsockopt SO_KEEPALIVE: %s\n", strerror(errno
)); 
 107 int anetResolve(char *err
, char *host
, char *ipbuf
) 
 109     struct sockaddr_in sa
; 
 111     sa
.sin_family 
= AF_INET
; 
 112     if (inet_aton(host
, &sa
.sin_addr
) == 0) { 
 115         he 
= gethostbyname(host
); 
 117             anetSetError(err
, "can't resolve: %s\n", host
); 
 120         memcpy(&sa
.sin_addr
, he
->h_addr
, sizeof(struct in_addr
)); 
 122     strcpy(ipbuf
,inet_ntoa(sa
.sin_addr
)); 
 126 #define ANET_CONNECT_NONE 0 
 127 #define ANET_CONNECT_NONBLOCK 1 
 128 static int anetTcpGenericConnect(char *err
, char *addr
, int port
, int flags
) 
 131     struct sockaddr_in sa
; 
 133     if ((s 
= socket(AF_INET
, SOCK_STREAM
, 0)) == -1) { 
 134         anetSetError(err
, "creating socket: %s\n", strerror(errno
)); 
 137     /* Make sure connection-intensive things like the redis benckmark 
 138      * will be able to close/open sockets a zillion of times */ 
 139     setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)); 
 141     sa
.sin_family 
= AF_INET
; 
 142     sa
.sin_port 
= htons(port
); 
 143     if (inet_aton(addr
, &sa
.sin_addr
) == 0) { 
 146         he 
= gethostbyname(addr
); 
 148             anetSetError(err
, "can't resolve: %s\n", addr
); 
 152         memcpy(&sa
.sin_addr
, he
->h_addr
, sizeof(struct in_addr
)); 
 154     if (flags 
& ANET_CONNECT_NONBLOCK
) { 
 155         if (anetNonBlock(err
,s
) != ANET_OK
) 
 158     if (connect(s
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) { 
 159         if (errno 
== EINPROGRESS 
&& 
 160             flags 
& ANET_CONNECT_NONBLOCK
) 
 163         anetSetError(err
, "connect: %s\n", strerror(errno
)); 
 170 int anetTcpConnect(char *err
, char *addr
, int port
) 
 172     return anetTcpGenericConnect(err
,addr
,port
,ANET_CONNECT_NONE
); 
 175 int anetTcpNonBlockConnect(char *err
, char *addr
, int port
) 
 177     return anetTcpGenericConnect(err
,addr
,port
,ANET_CONNECT_NONBLOCK
); 
 180 /* Like read(2) but make sure 'count' is read before to return 
 181  * (unless error or EOF condition is encountered) */ 
 182 int anetRead(int fd
, char *buf
, int count
) 
 184     int nread
, totlen 
= 0; 
 185     while(totlen 
!= count
) { 
 186         nread 
= read(fd
,buf
,count
-totlen
); 
 187         if (nread 
== 0) return totlen
; 
 188         if (nread 
== -1) return -1; 
 195 /* Like write(2) but make sure 'count' is read before to return 
 196  * (unless error is encountered) */ 
 197 int anetWrite(int fd
, char *buf
, int count
) 
 199     int nwritten
, totlen 
= 0; 
 200     while(totlen 
!= count
) { 
 201         nwritten 
= write(fd
,buf
,count
-totlen
); 
 202         if (nwritten 
== 0) return totlen
; 
 203         if (nwritten 
== -1) return -1; 
 210 int anetTcpServer(char *err
, int port
, char *bindaddr
) 
 213     struct sockaddr_in sa
; 
 215     if ((s 
= socket(AF_INET
, SOCK_STREAM
, 0)) == -1) { 
 216         anetSetError(err
, "socket: %s\n", strerror(errno
)); 
 219     if (setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) == -1) { 
 220         anetSetError(err
, "setsockopt SO_REUSEADDR: %s\n", strerror(errno
)); 
 224     memset(&sa
,0,sizeof(sa
)); 
 225     sa
.sin_family 
= AF_INET
; 
 226     sa
.sin_port 
= htons(port
); 
 227     sa
.sin_addr
.s_addr 
= htonl(INADDR_ANY
); 
 229         if (inet_aton(bindaddr
, &sa
.sin_addr
) == 0) { 
 230             anetSetError(err
, "Invalid bind address\n"); 
 235     if (bind(s
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) { 
 236         anetSetError(err
, "bind: %s\n", strerror(errno
)); 
 240     if (listen(s
, 32) == -1) { 
 241         anetSetError(err
, "listen: %s\n", strerror(errno
)); 
 248 int anetAccept(char *err
, int serversock
, char *ip
, int *port
) 
 251     struct sockaddr_in sa
; 
 256         fd 
= accept(serversock
, (struct sockaddr
*)&sa
, &saLen
); 
 261                 anetSetError(err
, "accept: %s\n", strerror(errno
)); 
 267     if (ip
) strcpy(ip
,inet_ntoa(sa
.sin_addr
)); 
 268     if (port
) *port 
= ntohs(sa
.sin_port
);