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 static void anetSetError(char *err, const char *fmt, ...) 51 { 52 va_list ap; 53 54 if (!err) return; 55 va_start(ap, fmt); 56 vsnprintf(err, ANET_ERR_LEN, fmt, ap); 57 va_end(ap); 58 } 59 60 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 if ((flags = fcntl(fd, F_GETFL)) == -1) { 68 anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno)); 69 return ANET_ERR; 70 } 71 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { 72 anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno)); 73 return ANET_ERR; 74 } 75 return ANET_OK; 76 } 77 78 int anetTcpNoDelay(char *err, int fd) 79 { 80 int yes = 1; 81 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) 82 { 83 anetSetError(err, "setsockopt TCP_NODELAY: %s", strerror(errno)); 84 return ANET_ERR; 85 } 86 return ANET_OK; 87 } 88 89 int anetSetSendBuffer(char *err, int fd, int buffsize) 90 { 91 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)) == -1) 92 { 93 anetSetError(err, "setsockopt SO_SNDBUF: %s", strerror(errno)); 94 return ANET_ERR; 95 } 96 return ANET_OK; 97 } 98 99 int anetTcpKeepAlive(char *err, int fd) 100 { 101 int yes = 1; 102 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) == -1) { 103 anetSetError(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno)); 104 return ANET_ERR; 105 } 106 return ANET_OK; 107 } 108 109 int anetResolve(char *err, char *host, char *ipbuf) 110 { 111 struct sockaddr_in sa; 112 113 sa.sin_family = AF_INET; 114 if (inet_aton(host, &sa.sin_addr) == 0) { 115 struct hostent *he; 116 117 he = gethostbyname(host); 118 if (he == NULL) { 119 anetSetError(err, "can't resolve: %s", host); 120 return ANET_ERR; 121 } 122 memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr)); 123 } 124 strcpy(ipbuf,inet_ntoa(sa.sin_addr)); 125 return ANET_OK; 126 } 127 128 static int anetCreateSocket(char *err, int domain) { 129 int s, on = 1; 130 if ((s = socket(domain, SOCK_STREAM, 0)) == -1) { 131 anetSetError(err, "creating socket: %s", strerror(errno)); 132 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 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { 138 anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno)); 139 return ANET_ERR; 140 } 141 return s; 142 } 143 144 #define ANET_CONNECT_NONE 0 145 #define ANET_CONNECT_NONBLOCK 1 146 static int anetTcpGenericConnect(char *err, char *addr, int port, int flags) 147 { 148 int s; 149 struct sockaddr_in sa; 150 151 if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR) 152 return ANET_ERR; 153 154 sa.sin_family = AF_INET; 155 sa.sin_port = htons(port); 156 if (inet_aton(addr, &sa.sin_addr) == 0) { 157 struct hostent *he; 158 159 he = gethostbyname(addr); 160 if (he == NULL) { 161 anetSetError(err, "can't resolve: %s", addr); 162 close(s); 163 return ANET_ERR; 164 } 165 memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr)); 166 } 167 if (flags & ANET_CONNECT_NONBLOCK) { 168 if (anetNonBlock(err,s) != ANET_OK) 169 return ANET_ERR; 170 } 171 if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -1) { 172 if (errno == EINPROGRESS && 173 flags & ANET_CONNECT_NONBLOCK) 174 return s; 175 176 anetSetError(err, "connect: %s", strerror(errno)); 177 close(s); 178 return ANET_ERR; 179 } 180 return s; 181 } 182 183 int anetTcpConnect(char *err, char *addr, int port) 184 { 185 return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONE); 186 } 187 188 int anetTcpNonBlockConnect(char *err, char *addr, int port) 189 { 190 return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK); 191 } 192 193 int anetUnixGenericConnect(char *err, char *path, int flags) 194 { 195 int s; 196 struct sockaddr_un sa; 197 198 if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR) 199 return ANET_ERR; 200 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) 205 return ANET_ERR; 206 } 207 if (connect(s,(struct sockaddr*)&sa,sizeof(sa)) == -1) { 208 if (errno == EINPROGRESS && 209 flags & ANET_CONNECT_NONBLOCK) 210 return s; 211 212 anetSetError(err, "connect: %s", strerror(errno)); 213 close(s); 214 return ANET_ERR; 215 } 216 return s; 217 } 218 219 int anetUnixConnect(char *err, char *path) 220 { 221 return anetUnixGenericConnect(err,path,ANET_CONNECT_NONE); 222 } 223 224 int anetUnixNonBlockConnect(char *err, char *path) 225 { 226 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 int anetRead(int fd, char *buf, int count) 232 { 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; 238 totlen += nread; 239 buf += nread; 240 } 241 return totlen; 242 } 243 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) 247 { 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; 253 totlen += nwritten; 254 buf += nwritten; 255 } 256 return totlen; 257 } 258 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)); 262 close(s); 263 return ANET_ERR; 264 } 265 if (listen(s, 511) == -1) { /* the magic 511 constant is from nginx */ 266 anetSetError(err, "listen: %s", strerror(errno)); 267 close(s); 268 return ANET_ERR; 269 } 270 return ANET_OK; 271 } 272 273 int anetTcpServer(char *err, int port, char *bindaddr) 274 { 275 int s; 276 struct sockaddr_in sa; 277 278 if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR) 279 return ANET_ERR; 280 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"); 287 close(s); 288 return ANET_ERR; 289 } 290 if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR) 291 return ANET_ERR; 292 return s; 293 } 294 295 int anetUnixServer(char *err, char *path, mode_t perm) 296 { 297 int s; 298 struct sockaddr_un sa; 299 300 if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR) 301 return ANET_ERR; 302 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) 307 return ANET_ERR; 308 if (perm) 309 chmod(sa.sun_path, perm); 310 return s; 311 } 312 313 static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) { 314 int fd; 315 while(1) { 316 fd = accept(s,sa,len); 317 if (fd == -1) { 318 if (errno == EINTR) 319 continue; 320 else { 321 anetSetError(err, "accept: %s", strerror(errno)); 322 return ANET_ERR; 323 } 324 } 325 break; 326 } 327 return fd; 328 } 329 330 int anetTcpAccept(char *err, int s, char *ip, int *port) { 331 int fd; 332 struct sockaddr_in sa; 333 socklen_t salen = sizeof(sa); 334 if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR) 335 return ANET_ERR; 336 337 if (ip) strcpy(ip,inet_ntoa(sa.sin_addr)); 338 if (port) *port = ntohs(sa.sin_port); 339 return fd; 340 } 341 342 int anetUnixAccept(char *err, int s) { 343 int fd; 344 struct sockaddr_un sa; 345 socklen_t salen = sizeof(sa); 346 if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR) 347 return ANET_ERR; 348 349 return fd; 350 } 351 352 int anetPeerToString(int fd, char *ip, int *port) { 353 struct sockaddr_in sa; 354 socklen_t salen = sizeof(sa); 355 356 if (getpeername(fd,(struct sockaddr*)&sa,&salen) == -1) return -1; 357 if (ip) strcpy(ip,inet_ntoa(sa.sin_addr)); 358 if (port) *port = ntohs(sa.sin_port); 359 return 0; 360 } 361