libbb: move netlink socket binding to the utility function
No binary (build failed)
—
(log yok)
| @@ -688,6 +688,7 @@ int xsocket_stream(len_and_sockaddr **lsap) FAST_FUNC; | |
| /* NB: these set SO_REUSEADDR before bind */ | |
| int create_and_bind_stream_or_die(const char *bindaddr, int port) FAST_FUNC; | |
| int create_and_bind_dgram_or_die(const char *bindaddr, int port) FAST_FUNC; | |
| + | int create_and_bind_to_netlink(int proto, int grp, unsigned rcvbuf) FAST_FUNC; |
| /* Create client TCP socket connected to peer:port. Peer cannot be NULL. | |
| * Peer can be numeric IP ("N.N.N.N"), numeric IPv6 address or hostname, | |
| * and can have ":PORT" suffix (for IPv6 use "[X:X:...:X]:PORT"). | |
| @@ -11,6 +11,9 @@ | |
| #include <netinet/in.h> | |
| #include <net/if.h> | |
| #include <sys/un.h> | |
| + | #if ENABLE_IFPLUGD || ENABLE_FEATURE_MDEV_DAEMON || ENABLE_UEVENT |
| + | # include <linux/netlink.h> |
| + | #endif |
| #include "libbb.h" | |
| int FAST_FUNC setsockopt_int(int fd, int level, int optname, int optval) | |
| @@ -412,6 +415,38 @@ int FAST_FUNC create_and_bind_dgram_or_die(const char *bindaddr, int port) | |
| } | |
| + | #if ENABLE_IFPLUGD || ENABLE_FEATURE_MDEV_DAEMON || ENABLE_UEVENT |
| + | int FAST_FUNC create_and_bind_to_netlink(int proto, int grp, unsigned rcvbuf) |
| + | { |
| + | struct sockaddr_nl sa; |
| + | int fd; |
| + | |
| + | memset(&sa, 0, sizeof(sa)); |
| + | sa.nl_family = AF_NETLINK; |
| + | sa.nl_pid = getpid(); |
| + | sa.nl_groups = grp; |
| + | fd = xsocket(AF_NETLINK, SOCK_DGRAM, proto); |
| + | xbind(fd, (struct sockaddr *) &sa, sizeof(sa)); |
| + | close_on_exec_on(fd); |
| + | |
| + | if (rcvbuf != 0) { |
| + | // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl |
| + | setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, rcvbuf); |
| + | setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, rcvbuf); |
| + | # if 0 |
| + | { |
| + | int z; |
| + | socklen_t zl = sizeof(z); |
| + | getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &z, &zl); |
| + | bb_error_msg("SO_RCVBUF:%d", z); |
| + | } |
| + | # endif |
| + | } |
| + | |
| + | return fd; |
| + | } |
| + | #endif |
| + | |
| int FAST_FUNC create_and_connect_stream_or_die(const char *peer, int port) | |
| { | |
| int fd; | |
| @@ -604,15 +604,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv) | |
| xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), ioctl_fd); | |
| if (opts & FLAG_MONITOR) { | |
| - | struct sockaddr_nl addr; |
| - | int fd = xsocket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); |
| - | |
| - | memset(&addr, 0, sizeof(addr)); |
| - | addr.nl_family = AF_NETLINK; |
| - | addr.nl_groups = RTMGRP_LINK; |
| - | addr.nl_pid = getpid(); |
| - | |
| - | xbind(fd, (struct sockaddr*)&addr, sizeof(addr)); |
| + | int fd = create_and_bind_to_netlink(NETLINK_ROUTE, RTMGRP_LINK, 0); |
| xmove_fd(fd, netlink_fd); | |
| } | |
| @@ -1225,28 +1225,16 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |
| /* | |
| * Daemon mode listening on uevent netlink socket. | |
| */ | |
| - | struct sockaddr_nl sa; |
| int fd; | |
| - | //TODO: reuse same code in uevent |
| - | // Subscribe for UEVENT kernel messages |
| - | sa.nl_family = AF_NETLINK; |
| - | sa.nl_pad = 0; |
| - | sa.nl_pid = getpid(); |
| - | sa.nl_groups = 1 << 0; |
| - | fd = xsocket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); |
| - | xbind(fd, (struct sockaddr *) &sa, sizeof(sa)); |
| - | close_on_exec_on(fd); |
| - | |
| - | // Without a sufficiently big RCVBUF, a ton of simultaneous events |
| - | // can trigger ENOBUFS on read, which is unrecoverable. |
| - | // Reproducer: |
| - | // mdev -d |
| - | // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';' |
| - | // |
| - | // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl |
| - | setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, RCVBUF); |
| - | setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, RCVBUF); |
| + | /* Subscribe for UEVENT kernel messages */ |
| + | /* Without a sufficiently big RCVBUF, a ton of simultaneous events |
| + | * can trigger ENOBUFS on read, which is unrecoverable. |
| + | * Reproducer: |
| + | * mdev -d |
| + | * find /sys -name uevent -exec sh -c 'echo add >"{}"' ';' |
| + | */ |
| + | fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT, 1 << 0, RCVBUF); |
| /* | |
| * Make inital scan after the uevent socket is alive and | |
| @@ -46,37 +46,19 @@ enum { RCVBUF = 2 * 1024 * 1024 }; | |
| int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |
| int uevent_main(int argc UNUSED_PARAM, char **argv) | |
| { | |
| - | struct sockaddr_nl sa; |
| int fd; | |
| INIT_G(); | |
| argv++; | |
| - | // Subscribe for UEVENT kernel messages |
| - | sa.nl_family = AF_NETLINK; |
| - | sa.nl_pad = 0; |
| - | sa.nl_pid = getpid(); |
| - | sa.nl_groups = 1 << 0; |
| - | fd = xsocket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); |
| - | xbind(fd, (struct sockaddr *) &sa, sizeof(sa)); |
| - | close_on_exec_on(fd); |
| - | |
| + | // Subscribe for UEVENT kernel messages. |
| // Without a sufficiently big RCVBUF, a ton of simultaneous events | |
| // can trigger ENOBUFS on read, which is unrecoverable. | |
| // Reproducer: | |
| // uevent mdev & | |
| // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';' | |
| - | // |
| - | // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl |
| - | setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, RCVBUF); |
| - | setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, RCVBUF); |
| - | if (0) { |
| - | int z; |
| - | socklen_t zl = sizeof(z); |
| - | getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &z, &zl); |
| - | bb_error_msg("SO_RCVBUF:%d", z); |
| - | } |
| + | fd = create_and_bind_to_netlink(NETLINK_KOBJECT_UEVENT, /*groups:*/ 1 << 0, RCVBUF); |
| for (;;) { | |
| char *netbuf; | |
| @@ -118,14 +100,15 @@ int uevent_main(int argc UNUSED_PARAM, char **argv) | |
| } | |
| env[idx] = NULL; | |
| - | idx = 0; |
| - | while (env[idx]) |
| - | putenv(env[idx++]); |
| - | if (argv[0]) |
| + | if (argv[0]) { |
| + | idx = 0; |
| + | while (env[idx]) |
| + | putenv(env[idx++]); |
| spawn_and_wait(argv); | |
| - | idx = 0; |
| - | while (env[idx]) |
| - | bb_unsetenv(env[idx++]); |
| + | idx = 0; |
| + | while (env[idx]) |
| + | bb_unsetenv(env[idx++]); |
| + | } |
| munmap(netbuf, BUFFER_SIZE); | |
| } | |