Properly catch and report getaddrinfo() errors
[beanstalkd.git] / net.c
blobcfa42dbc1256eb356138a22ffe39c3d3ebe2c53a
1 #include <netdb.h>
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <sys/socket.h>
8 #include <netinet/in.h>
9 #include <netinet/tcp.h>
10 #include "dat.h"
11 #include "sd-daemon.h"
13 int
14 make_server_socket(char *host, char *port)
16 int fd = -1, flags, r;
17 struct linger linger = {0, 0};
18 struct addrinfo *airoot, *ai, hints;
20 /* See if we got a listen fd from systemd. If so, all socket options etc
21 * are already set, so we check that the fd is a TCP listen socket and
22 * return. */
23 r = sd_listen_fds(1);
24 if (r < 0) {
25 return twarn("sd_listen_fds"), -1;
27 if (r > 0) {
28 if (r > 1) {
29 twarnx("inherited more than one listen socket;"
30 " ignoring all but the first");
32 fd = SD_LISTEN_FDS_START;
33 r = sd_is_socket_inet(fd, 0, SOCK_STREAM, 1, 0);
34 if (r < 0) {
35 errno = -r;
36 twarn("sd_is_socket_inet");
37 return -1;
39 if (!r) {
40 twarnx("inherited fd is not a TCP listen socket");
41 return -1;
43 return fd;
46 memset(&hints, 0, sizeof(hints));
47 hints.ai_family = PF_UNSPEC;
48 hints.ai_socktype = SOCK_STREAM;
49 hints.ai_flags = AI_PASSIVE;
50 r = getaddrinfo(host, port, &hints, &airoot);
51 if (r != 0) {
52 twarnx("getaddrinfo(): %s", gai_strerror(r));
53 return -1;
56 for(ai = airoot; ai; ai = ai->ai_next) {
57 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
58 if (fd == -1) {
59 twarn("socket()");
60 continue;
63 flags = fcntl(fd, F_GETFL, 0);
64 if (flags < 0) {
65 twarn("getting flags");
66 close(fd);
67 continue;
70 r = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
71 if (r == -1) {
72 twarn("setting O_NONBLOCK");
73 close(fd);
74 continue;
77 flags = 1;
78 r = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof flags);
79 if (r == -1) {
80 twarn("setting SO_REUSEADDR on fd %d", fd);
81 close(fd);
82 continue;
84 r = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof flags);
85 if (r == -1) {
86 twarn("setting SO_KEEPALIVE on fd %d", fd);
87 close(fd);
88 continue;
90 r = setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof linger);
91 if (r == -1) {
92 twarn("setting SO_LINGER on fd %d", fd);
93 close(fd);
94 continue;
96 r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof flags);
97 if (r == -1) {
98 twarn("setting TCP_NODELAY on fd %d", fd);
99 close(fd);
100 continue;
103 r = bind(fd, ai->ai_addr, ai->ai_addrlen);
104 if (r == -1) {
105 twarn("bind()");
106 close(fd);
107 continue;
109 if (verbose) {
110 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], *h = host, *p = port;
111 struct sockaddr_in addr;
112 socklen_t addrlen;
114 addrlen = sizeof(addr);
115 r = getsockname(fd, (struct sockaddr *) &addr, &addrlen);
116 if (!r) {
117 r = getnameinfo((struct sockaddr *) &addr, addrlen,
118 hbuf, sizeof(hbuf),
119 pbuf, sizeof(pbuf),
120 NI_NUMERICHOST|NI_NUMERICSERV);
121 if (!r) {
122 h = hbuf;
123 p = pbuf;
126 if (ai->ai_family == AF_INET6) {
127 printf("bind %d [%s]:%s\n", fd, h, p);
128 } else {
129 printf("bind %d %s:%s\n", fd, h, p);
133 r = listen(fd, 1024);
134 if (r == -1) {
135 twarn("listen()");
136 close(fd);
137 continue;
140 break;
143 freeaddrinfo(airoot);
145 if(ai == NULL)
146 fd = -1;
148 return fd;