8 #include <sys/socket.h>
11 #include <netinet/in.h>
12 #include <netinet/tcp.h>
14 #ifdef HAVE_LIBSYSTEMD
15 #include <systemd/sd-daemon.h>
19 set_nonblocking(int fd
)
23 flags
= fcntl(fd
, F_GETFL
, 0);
25 twarn("getting flags");
28 r
= fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
);
30 twarn("setting O_NONBLOCK");
37 make_inet_socket(char *host
, char *port
)
39 int fd
= -1, flags
, r
;
40 struct linger linger
= {0, 0};
41 struct addrinfo
*airoot
, *ai
, hints
;
43 memset(&hints
, 0, sizeof(hints
));
44 hints
.ai_family
= AF_UNSPEC
;
45 hints
.ai_socktype
= SOCK_STREAM
;
46 hints
.ai_flags
= AI_PASSIVE
;
47 r
= getaddrinfo(host
, port
, &hints
, &airoot
);
49 twarnx("getaddrinfo(): %s", gai_strerror(r
));
53 for (ai
= airoot
; ai
; ai
= ai
->ai_next
) {
54 fd
= socket(ai
->ai_family
, ai
->ai_socktype
, ai
->ai_protocol
);
60 r
= set_nonblocking(fd
);
67 r
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &flags
, sizeof flags
);
69 twarn("setting SO_REUSEADDR on fd %d", fd
);
73 r
= setsockopt(fd
, SOL_SOCKET
, SO_KEEPALIVE
, &flags
, sizeof flags
);
75 twarn("setting SO_KEEPALIVE on fd %d", fd
);
79 r
= setsockopt(fd
, SOL_SOCKET
, SO_LINGER
, &linger
, sizeof linger
);
81 twarn("setting SO_LINGER on fd %d", fd
);
85 r
= setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &flags
, sizeof flags
);
87 twarn("setting TCP_NODELAY on fd %d", fd
);
92 if (host
== NULL
&& ai
->ai_family
== AF_INET6
) {
94 r
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &flags
, sizeof(flags
));
96 twarn("setting IPV6_V6ONLY on fd %d", fd
);
102 r
= bind(fd
, ai
->ai_addr
, ai
->ai_addrlen
);
109 char hbuf
[NI_MAXHOST
], pbuf
[NI_MAXSERV
], *h
= host
, *p
= port
;
110 struct sockaddr_in addr
;
113 addrlen
= sizeof(addr
);
114 r
= getsockname(fd
, (struct sockaddr
*) &addr
, &addrlen
);
116 r
= getnameinfo((struct sockaddr
*) &addr
, addrlen
,
119 NI_NUMERICHOST
|NI_NUMERICSERV
);
125 if (ai
->ai_family
== AF_INET6
) {
126 printf("bind %d [%s]:%s\n", fd
, h
, p
);
128 printf("bind %d %s:%s\n", fd
, h
, p
);
132 r
= listen(fd
, 1024);
142 freeaddrinfo(airoot
);
151 make_unix_socket(char *path
)
155 struct sockaddr_un addr
;
156 const size_t maxlen
= sizeof(addr
.sun_path
) - 1; // Reserve the last position for '\0'
158 memset(&addr
, 0, sizeof(struct sockaddr_un
));
159 addr
.sun_family
= AF_UNIX
;
160 if (strlen(path
) > maxlen
) {
161 warnx("socket path %s is too long (%ld characters), where maximum allowed is %ld",
162 path
, strlen(path
), maxlen
);
165 strncpy(addr
.sun_path
, path
, maxlen
);
169 if (S_ISSOCK(st
.st_mode
)) {
170 warnx("removing existing local socket to replace it");
177 twarnx("another file already exists in the given path");
182 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
188 r
= set_nonblocking(fd
);
194 r
= bind(fd
, (struct sockaddr
*) &addr
, sizeof(struct sockaddr_un
));
201 printf("bind %d %s\n", fd
, path
);
204 r
= listen(fd
, 1024);
215 make_server_socket(char *host
, char *port
)
217 #ifdef HAVE_LIBSYSTEMD
220 /* See if we got a listen fd from systemd. If so, all socket options etc
221 * are already set, so we check that the fd is a TCP or UNIX listen socket
223 r
= sd_listen_fds(1);
225 twarn("sd_listen_fds");
230 twarnx("inherited more than one listen socket;"
231 " ignoring all but the first");
233 fd
= SD_LISTEN_FDS_START
;
234 r
= sd_is_socket_inet(fd
, 0, SOCK_STREAM
, 1, 0);
236 twarn("sd_is_socket_inet");
241 r
= sd_is_socket_unix(fd
, SOCK_STREAM
, 1, NULL
, 0);
243 twarn("sd_is_socket_unix");
248 twarnx("inherited fd is not a TCP or UNIX listening socket");
256 if (host
&& !strncmp(host
, "unix:", 5)) {
257 return make_unix_socket(&host
[5]);
259 return make_inet_socket(host
, port
);