LCOV - code coverage report
Current view: directory - redis/src - anet.c (source / functions) Found Hit Coverage
Test: redis.info Lines: 177 54 30.5 %
Date: 2012-04-04 Functions: 22 10 45.5 %
Colors: not hit hit

       1                 : /* anet.c -- Basic TCP socket stuff made a bit less boring
       2                 :  *
       3                 :  * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
       4                 :  * All rights reserved.
       5                 :  *
       6                 :  * Redistribution and use in source and binary forms, with or without
       7                 :  * modification, are permitted provided that the following conditions are met:
       8                 :  *
       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.
      17                 :  *
      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.
      29                 :  */
      30                 : 
      31                 : #include "fmacros.h"
      32                 : 
      33                 : #include <sys/types.h>
      34                 : #include <sys/socket.h>
      35                 : #include <sys/stat.h>
      36                 : #include <sys/un.h>
      37                 : #include <netinet/in.h>
      38                 : #include <netinet/tcp.h>
      39                 : #include <arpa/inet.h>
      40                 : #include <unistd.h>
      41                 : #include <fcntl.h>
      42                 : #include <string.h>
      43                 : #include <netdb.h>
      44                 : #include <errno.h>
      45                 : #include <stdarg.h>
      46                 : #include <stdio.h>
      47                 : 
      48                 : #include "anet.h"
      49                 : 
      50               0 : static void anetSetError(char *err, const char *fmt, ...)
      51                 : {
      52                 :     va_list ap;
      53                 : 
      54               0 :     if (!err) return;
      55               0 :     va_start(ap, fmt);
      56                 :     vsnprintf(err, ANET_ERR_LEN, fmt, ap);
      57               0 :     va_end(ap);
      58                 : }
      59                 : 
      60             213 : int anetNonBlock(char *err, int fd)
      61                 : {
      62                 :     int flags;
      63                 : 
      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             213 :     if ((flags = fcntl(fd, F_GETFL)) == -1) {
      68               0 :         anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno));
      69               0 :         return ANET_ERR;
      70                 :     }
      71             213 :     if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
      72               0 :         anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
      73               0 :         return ANET_ERR;
      74                 :     }
      75             213 :     return ANET_OK;
      76                 : }
      77                 : 
      78             202 : int anetTcpNoDelay(char *err, int fd)
      79                 : {
      80             202 :     int yes = 1;
      81             202 :     if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1)
      82                 :     {
      83               0 :         anetSetError(err, "setsockopt TCP_NODELAY: %s", strerror(errno));
      84               0 :         return ANET_ERR;
      85                 :     }
      86             202 :     return ANET_OK;
      87                 : }
      88                 : 
      89               0 : int anetSetSendBuffer(char *err, int fd, int buffsize)
      90                 : {
      91               0 :     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)) == -1)
      92                 :     {
      93               0 :         anetSetError(err, "setsockopt SO_SNDBUF: %s", strerror(errno));
      94               0 :         return ANET_ERR;
      95                 :     }
      96               0 :     return ANET_OK;
      97                 : }
      98                 : 
      99               0 : int anetTcpKeepAlive(char *err, int fd)
     100                 : {
     101               0 :     int yes = 1;
     102               0 :     if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) == -1) {
     103               0 :         anetSetError(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno));
     104               0 :         return ANET_ERR;
     105                 :     }
     106               0 :     return ANET_OK;
     107                 : }
     108                 : 
     109               0 : int anetResolve(char *err, char *host, char *ipbuf)
     110                 : {
     111                 :     struct sockaddr_in sa;
     112                 : 
     113               0 :     sa.sin_family = AF_INET;
     114               0 :     if (inet_aton(host, &sa.sin_addr) == 0) {
     115                 :         struct hostent *he;
     116                 : 
     117               0 :         he = gethostbyname(host);
     118               0 :         if (he == NULL) {
     119               0 :             anetSetError(err, "can't resolve: %s", host);
     120               0 :             return ANET_ERR;
     121                 :         }
     122               0 :         memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
     123                 :     }
     124               0 :     strcpy(ipbuf,inet_ntoa(sa.sin_addr));
     125               0 :     return ANET_OK;
     126                 : }
     127                 : 
     128              64 : static int anetCreateSocket(char *err, int domain) {
     129              64 :     int s, on = 1;
     130              64 :     if ((s = socket(domain, SOCK_STREAM, 0)) == -1) {
     131               0 :         anetSetError(err, "creating socket: %s", strerror(errno));
     132               0 :         return ANET_ERR;
     133                 :     }
     134                 : 
     135                 :     /* Make sure connection-intensive things like the redis benckmark
     136                 :      * will be able to close/open sockets a zillion of times */
     137              64 :     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
     138               0 :         anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno));
     139               0 :         return ANET_ERR;
     140                 :     }
     141              64 :     return s;
     142                 : }
     143                 : 
     144                 : #define ANET_CONNECT_NONE 0
     145                 : #define ANET_CONNECT_NONBLOCK 1
     146              11 : static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
     147                 : {
     148                 :     int s;
     149                 :     struct sockaddr_in sa;
     150                 : 
     151              11 :     if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
     152               0 :         return ANET_ERR;
     153                 : 
     154              11 :     sa.sin_family = AF_INET;
     155              11 :     sa.sin_port = htons(port);
     156              11 :     if (inet_aton(addr, &sa.sin_addr) == 0) {
     157                 :         struct hostent *he;
     158                 : 
     159               0 :         he = gethostbyname(addr);
     160               0 :         if (he == NULL) {
     161               0 :             anetSetError(err, "can't resolve: %s", addr);
     162               0 :             close(s);
     163               0 :             return ANET_ERR;
     164                 :         }
     165               0 :         memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
     166                 :     }
     167              11 :     if (flags & ANET_CONNECT_NONBLOCK) {
     168              11 :         if (anetNonBlock(err,s) != ANET_OK)
     169               0 :             return ANET_ERR;
     170                 :     }
     171              11 :     if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
     172              22 :         if (errno == EINPROGRESS &&
     173              11 :             flags & ANET_CONNECT_NONBLOCK)
     174              11 :             return s;
     175                 : 
     176               0 :         anetSetError(err, "connect: %s", strerror(errno));
     177               0 :         close(s);
     178               0 :         return ANET_ERR;
     179                 :     }
     180               0 :     return s;
     181                 : }
     182                 : 
     183               0 : int anetTcpConnect(char *err, char *addr, int port)
     184                 : {
     185               0 :     return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONE);
     186                 : }
     187                 : 
     188              11 : int anetTcpNonBlockConnect(char *err, char *addr, int port)
     189                 : {
     190              11 :     return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK);
     191                 : }
     192                 : 
     193               0 : int anetUnixGenericConnect(char *err, char *path, int flags)
     194                 : {
     195                 :     int s;
     196                 :     struct sockaddr_un sa;
     197                 : 
     198               0 :     if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR)
     199               0 :         return ANET_ERR;
     200                 : 
     201               0 :     sa.sun_family = AF_LOCAL;
     202               0 :     strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
     203               0 :     if (flags & ANET_CONNECT_NONBLOCK) {
     204               0 :         if (anetNonBlock(err,s) != ANET_OK)
     205               0 :             return ANET_ERR;
     206                 :     }
     207               0 :     if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) == -1) {
     208               0 :         if (errno == EINPROGRESS &&
     209               0 :             flags & ANET_CONNECT_NONBLOCK)
     210               0 :             return s;
     211                 : 
     212               0 :         anetSetError(err, "connect: %s", strerror(errno));
     213               0 :         close(s);
     214               0 :         return ANET_ERR;
     215                 :     }
     216               0 :     return s;
     217                 : }
     218                 : 
     219               0 : int anetUnixConnect(char *err, char *path)
     220                 : {
     221               0 :     return anetUnixGenericConnect(err,path,ANET_CONNECT_NONE);
     222                 : }
     223                 : 
     224               0 : int anetUnixNonBlockConnect(char *err, char *path)
     225                 : {
     226               0 :     return anetUnixGenericConnect(err,path,ANET_CONNECT_NONBLOCK);
     227                 : }
     228                 : 
     229                 : /* Like read(2) but make sure 'count' is read before to return
     230                 :  * (unless error or EOF condition is encountered) */
     231               0 : int anetRead(int fd, char *buf, int count)
     232                 : {
     233               0 :     int nread, totlen = 0;
     234               0 :     while(totlen != count) {
     235               0 :         nread = read(fd,buf,count-totlen);
     236               0 :         if (nread == 0) return totlen;
     237               0 :         if (nread == -1) return -1;
     238               0 :         totlen += nread;
     239               0 :         buf += nread;
     240                 :     }
     241               0 :     return totlen;
     242                 : }
     243                 : 
     244                 : /* Like write(2) but make sure 'count' is read before to return
     245                 :  * (unless error is encountered) */
     246               0 : int anetWrite(int fd, char *buf, int count)
     247                 : {
     248               0 :     int nwritten, totlen = 0;
     249               0 :     while(totlen != count) {
     250               0 :         nwritten = write(fd,buf,count-totlen);
     251               0 :         if (nwritten == 0) return totlen;
     252               0 :         if (nwritten == -1) return -1;
     253               0 :         totlen += nwritten;
     254               0 :         buf += nwritten;
     255                 :     }
     256               0 :     return totlen;
     257                 : }
     258                 : 
     259              53 : static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
     260              53 :     if (bind(s,sa,len) == -1) {
     261               0 :         anetSetError(err, "bind: %s", strerror(errno));
     262               0 :         close(s);
     263               0 :         return ANET_ERR;
     264                 :     }
     265              53 :     if (listen(s, 511) == -1) { /* the magic 511 constant is from nginx */
     266               0 :         anetSetError(err, "listen: %s", strerror(errno));
     267               0 :         close(s);
     268               0 :         return ANET_ERR;
     269                 :     }
     270              53 :     return ANET_OK;
     271                 : }
     272                 : 
     273              53 : int anetTcpServer(char *err, int port, char *bindaddr)
     274                 : {
     275                 :     int s;
     276                 :     struct sockaddr_in sa;
     277                 : 
     278              53 :     if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
     279               0 :         return ANET_ERR;
     280                 : 
     281                 :     memset(&sa,0,sizeof(sa));
     282              53 :     sa.sin_family = AF_INET;
     283              53 :     sa.sin_port = htons(port);
     284              53 :     sa.sin_addr.s_addr = htonl(INADDR_ANY);
     285              53 :     if (bindaddr && inet_aton(bindaddr, &sa.sin_addr) == 0) {
     286               0 :         anetSetError(err, "invalid bind address");
     287               0 :         close(s);
     288               0 :         return ANET_ERR;
     289                 :     }
     290              53 :     if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR)
     291               0 :         return ANET_ERR;
     292              53 :     return s;
     293                 : }
     294                 : 
     295               0 : int anetUnixServer(char *err, char *path, mode_t perm)
     296                 : {
     297                 :     int s;
     298                 :     struct sockaddr_un sa;
     299                 : 
     300               0 :     if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR)
     301               0 :         return ANET_ERR;
     302                 : 
     303                 :     memset(&sa,0,sizeof(sa));
     304               0 :     sa.sun_family = AF_LOCAL;
     305               0 :     strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
     306               0 :     if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR)
     307               0 :         return ANET_ERR;
     308               0 :     if (perm)
     309               0 :         chmod(sa.sun_path, perm);
     310               0 :     return s;
     311                 : }
     312                 : 
     313             193 : static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
     314                 :     int fd;
     315                 :     while(1) {
     316             193 :         fd = accept(s,sa,len);
     317             193 :         if (fd == -1) {
     318               0 :             if (errno == EINTR)
     319               0 :                 continue;
     320                 :             else {
     321               0 :                 anetSetError(err, "accept: %s", strerror(errno));
     322               0 :                 return ANET_ERR;
     323                 :             }
     324                 :         }
     325                 :         break;
     326               0 :     }
     327             193 :     return fd;
     328                 : }
     329                 : 
     330             193 : int anetTcpAccept(char *err, int s, char *ip, int *port) {
     331                 :     int fd;
     332                 :     struct sockaddr_in sa;
     333             193 :     socklen_t salen = sizeof(sa);
     334             193 :     if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
     335               0 :         return ANET_ERR;
     336                 : 
     337             193 :     if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
     338             193 :     if (port) *port = ntohs(sa.sin_port);
     339             193 :     return fd;
     340                 : }
     341                 : 
     342               0 : int anetUnixAccept(char *err, int s) {
     343                 :     int fd;
     344                 :     struct sockaddr_un sa;
     345               0 :     socklen_t salen = sizeof(sa);
     346               0 :     if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
     347               0 :         return ANET_ERR;
     348                 : 
     349               0 :     return fd;
     350                 : }
     351                 : 
     352          150745 : int anetPeerToString(int fd, char *ip, int *port) {
     353                 :     struct sockaddr_in sa;
     354          150745 :     socklen_t salen = sizeof(sa);
     355                 : 
     356          150745 :     if (getpeername(fd,(struct sockaddr*)&sa,&salen) == -1) {
     357               0 :         *port = 0;
     358               0 :         ip[0] = '?';
     359               0 :         ip[1] = '\0';
     360               0 :         return -1;
     361                 :     }
     362          150745 :     if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
     363          150745 :     if (port) *port = ntohs(sa.sin_port);
     364          150745 :     return 0;
     365                 : }

Generated by: LCOV version 1.7