Use ftruncate() as it's much more portable (#341)
[beanstalkd.git] / net.c
blob6ccae17af2c365a5a94587777e6adef4d72e654e
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 r = bind(fd, ai->ai_addr, ai->ai_addrlen);
102 if (r == -1) {
103 twarn("bind()");
104 close(fd);
105 continue;
107 if (verbose) {
108 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], *h = host, *p = port;
109 struct sockaddr_in addr;
110 socklen_t addrlen;
112 addrlen = sizeof(addr);
113 r = getsockname(fd, (struct sockaddr *) &addr, &addrlen);
114 if (!r) {
115 r = getnameinfo((struct sockaddr *) &addr, addrlen,
116 hbuf, sizeof(hbuf),
117 pbuf, sizeof(pbuf),
118 NI_NUMERICHOST|NI_NUMERICSERV);
119 if (!r) {
120 h = hbuf;
121 p = pbuf;
124 if (ai->ai_family == AF_INET6) {
125 printf("bind %d [%s]:%s\n", fd, h, p);
126 } else {
127 printf("bind %d %s:%s\n", fd, h, p);
131 r = listen(fd, 1024);
132 if (r == -1) {
133 twarn("listen()");
134 close(fd);
135 continue;
138 break;
141 freeaddrinfo(airoot);
143 if(ai == NULL)
144 fd = -1;
146 return fd;