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

, generated on Tue Sep 26 2023.