fix tests on freebsd
[beanstalkd.git] / net.c
blobbf01d4fbabb3e4cf882d3fa0c41c57ad6bcf16c2
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");
31 r = 1;
33 fd = SD_LISTEN_FDS_START;
34 r = sd_is_socket_inet(fd, 0, SOCK_STREAM, 1, 0);
35 if (r < 0) {
36 errno = -r;
37 twarn("sd_is_socket_inet");
38 return -1;
40 if (!r) {
41 twarnx("inherited fd is not a TCP listen socket");
42 return -1;
44 return fd;
47 memset(&hints, 0, sizeof(hints));
48 hints.ai_family = PF_UNSPEC;
49 hints.ai_socktype = SOCK_STREAM;
50 hints.ai_flags = AI_PASSIVE;
51 r = getaddrinfo(host, port, &hints, &airoot);
52 if (r == -1)
53 return twarn("getaddrinfo()"), -1;
55 for(ai = airoot; ai; ai = ai->ai_next) {
56 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
57 if (fd == -1) {
58 twarn("socket()");
59 continue;
62 flags = fcntl(fd, F_GETFL, 0);
63 if (flags < 0) {
64 twarn("getting flags");
65 close(fd);
66 continue;
69 r = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
70 if (r == -1) {
71 twarn("setting O_NONBLOCK");
72 close(fd);
73 continue;
76 flags = 1;
77 r = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof flags);
78 if (r == -1) {
79 twarn("setting SO_REUSEADDR on fd %d", fd);
80 close(fd);
81 continue;
83 r = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof flags);
84 if (r == -1) {
85 twarn("setting SO_KEEPALIVE on fd %d", fd);
86 close(fd);
87 continue;
89 r = setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof linger);
90 if (r == -1) {
91 twarn("setting SO_LINGER on fd %d", fd);
92 close(fd);
93 continue;
95 r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof flags);
96 if (r == -1) {
97 twarn("setting TCP_NODELAY on fd %d", fd);
98 close(fd);
99 continue;
102 if (verbose) {
103 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], *h = host, *p = port;
104 r = getnameinfo(ai->ai_addr, ai->ai_addrlen,
105 hbuf, sizeof hbuf,
106 pbuf, sizeof pbuf,
107 NI_NUMERICHOST|NI_NUMERICSERV);
108 if (!r) {
109 h = hbuf;
110 p = pbuf;
112 if (ai->ai_family == AF_INET6) {
113 printf("bind %d [%s]:%s\n", fd, h, p);
114 } else {
115 printf("bind %d %s:%s\n", fd, h, p);
118 r = bind(fd, ai->ai_addr, ai->ai_addrlen);
119 if (r == -1) {
120 twarn("bind()");
121 close(fd);
122 continue;
125 r = listen(fd, 1024);
126 if (r == -1) {
127 twarn("listen()");
128 close(fd);
129 continue;
132 break;
135 freeaddrinfo(airoot);
137 if(ai == NULL)
138 fd = -1;
140 return fd;