shrink the hashmap when it's too sparse
[beanstalkd.git] / net.c
blob212b8942cd4b94380149a24b18efa329a6ed2244
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 == -1)
52 return twarn("getaddrinfo()"), -1;
54 for(ai = airoot; ai; ai = ai->ai_next) {
55 fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
56 if (fd == -1) {
57 twarn("socket()");
58 continue;
61 flags = fcntl(fd, F_GETFL, 0);
62 if (flags < 0) {
63 twarn("getting flags");
64 close(fd);
65 continue;
68 r = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
69 if (r == -1) {
70 twarn("setting O_NONBLOCK");
71 close(fd);
72 continue;
75 flags = 1;
76 r = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof flags);
77 if (r == -1) {
78 twarn("setting SO_REUSEADDR on fd %d", fd);
79 close(fd);
80 continue;
82 r = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof flags);
83 if (r == -1) {
84 twarn("setting SO_KEEPALIVE on fd %d", fd);
85 close(fd);
86 continue;
88 r = setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof linger);
89 if (r == -1) {
90 twarn("setting SO_LINGER on fd %d", fd);
91 close(fd);
92 continue;
94 r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof flags);
95 if (r == -1) {
96 twarn("setting TCP_NODELAY on fd %d", fd);
97 close(fd);
98 continue;
101 if (verbose) {
102 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], *h = host, *p = port;
103 r = getnameinfo(ai->ai_addr, ai->ai_addrlen,
104 hbuf, sizeof hbuf,
105 pbuf, sizeof pbuf,
106 NI_NUMERICHOST|NI_NUMERICSERV);
107 if (!r) {
108 h = hbuf;
109 p = pbuf;
111 if (ai->ai_family == AF_INET6) {
112 printf("bind %d [%s]:%s\n", fd, h, p);
113 } else {
114 printf("bind %d %s:%s\n", fd, h, p);
117 r = bind(fd, ai->ai_addr, ai->ai_addrlen);
118 if (r == -1) {
119 twarn("bind()");
120 close(fd);
121 continue;
124 r = listen(fd, 1024);
125 if (r == -1) {
126 twarn("listen()");
127 close(fd);
128 continue;
131 break;
134 freeaddrinfo(airoot);
136 if(ai == NULL)
137 fd = -1;
139 return fd;