1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include <arpa/inet.h>
30 #include <sys/types.h>
33 #include <sys/ioctl.h>
38 #include "socket-util.h"
42 int socket_address_listen(
43 const SocketAddress *a,
45 SocketAddressBindIPv6Only only,
46 const char *bind_to_device,
49 mode_t directory_mode,
58 if ((r = socket_address_verify(a)) < 0)
61 if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
64 r = label_socket_set(label);
68 fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, a->protocol);
69 r = fd < 0 ? -errno : 0;
76 if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
77 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
79 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
83 if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
85 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
90 if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
91 log_warning("IP_FREEBIND failed: %m");
96 if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
97 log_warning("IP_TRANSPARENT failed: %m");
102 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
105 if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
109 mkdir_parents(a->sockaddr.un.sun_path, directory_mode);
111 /* Enforce the right access mode for the socket*/
112 old_mask = umask(~ socket_mode);
114 /* Include the original umask in our mask */
115 umask(~socket_mode | old_mask);
117 r = label_bind(fd, &a->sockaddr.sa, a->size);
119 if (r < 0 && errno == EADDRINUSE) {
120 /* Unlink and try again */
121 unlink(a->sockaddr.un.sun_path);
122 r = bind(fd, &a->sockaddr.sa, a->size);
127 r = bind(fd, &a->sockaddr.sa, a->size);
132 if (socket_address_can_accept(a))
133 if (listen(fd, backlog) < 0)
141 close_nointr_nofail(fd);