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