xref: /redis-3.2.3/src/anet.c (revision 414c3dea)
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