diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README | 4 | ||||
-rw-r--r-- | bindtemp_un.c | 89 | ||||
-rw-r--r-- | libsimple.h | 1 | ||||
-rw-r--r-- | libsimple/net.h | 16 |
5 files changed, 110 insertions, 2 deletions
@@ -39,6 +39,7 @@ SUBHDR =\ libsimple/memalloc.h\ libsimple/memdup.h\ libsimple/memelem.h\ + libsimple/net.h\ libsimple/overflow.h\ libsimple/posix_memalign.h\ libsimple/posix_memalignz.h\ @@ -86,6 +87,7 @@ OBJ =\ asprintf.o\ bindex.o\ bindex_r.o\ + bindtemp_un.o\ callocn.o\ close.o\ close_range.o\ @@ -5,8 +5,8 @@ values for integer data types. All functions are namespaced with `libsimple_` and aliased with macro definitions to unnamespaced names unless there already is a macro with that -name. However, some functions are seen as libsimple specific and do not -have unnamespaced. +name. However, some functions are seen as libsimple specific and are not +namespaced. Programs using this library should define `char *argv0` and set it to the 0:th command line argument. diff --git a/bindtemp_un.c b/bindtemp_un.c new file mode 100644 index 0000000..0362e47 --- /dev/null +++ b/bindtemp_un.c @@ -0,0 +1,89 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +/** + * Fill a buffer with random alphanumerical symbols, and '_' and '-' + * + * @param buf The buffer to fill + * @param n The size of the buffer + */ +static void +random_alnum(char *buf, size_t n) +{ + size_t i; + int rnd; + double drnd; + +#if defined(__linux__) && defined(GRND_NONBLOCK) + ssize_t r = getrandom(buf, n, GRND_NONBLOCK); + i = r < 0 ? 0 : (size_t)r; +#else + i = 0; +#endif + + for (; i < n; i++) { + rnd = rand(); + drnd = (double)rnd / (double)RAND_MAX; + drnd *= 63; + rnd = (int)drnd; + buf[i] = (char)rnd; + } + + for (i = 0; i < n; i++) + buf[i] = "0123456789_abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ"[buf[i] & 63]; +} + + +int +libsimple_bindtemp_un(int fd, int dir_fd, struct sockaddr_un *addr, socklen_t *addrlen) +{ + int len, saved_errno = errno; + size_t rem, try_limit = 1000; + struct sockaddr_un addr_; + + if (!addr) + addr = &addr_; + if (addrlen) + *addrlen = sizeof(*addr); + + memset(addr, 0, sizeof(*addr)); + addr->sun_family = AF_UNIX; + + if (dir_fd == AT_FDCWD) + len = snprintf(addr->sun_path, sizeof(addr->sun_path), "tmp"); + else + len = snprintf(addr->sun_path, sizeof(addr->sun_path), "/dev/fd/%i/tmp", dir_fd); + if (len < 0 || (size_t)len >= sizeof(addr->sun_path) || sizeof(addr->sun_path) - (size_t)len < 6) + abort(); + rem = sizeof(addr->sun_path) - 1 - len; + addr->sun_path[sizeof(addr->sun_path) - 1] = 0; + + while (try_limit--) { + again: + random_alnum(&addr->sun_path[len], rem); + if (!bind(fd, (void *)&addr, (socklen_t)sizeof(*addr))) { + errno = saved_errno; + return 0; + } else if (errno == ENAMETOOLONG && rem > 5) { + addr->sun_path[len + --rem] = 0; + goto again; + } else if (errno != EEXIST && errno != EADDRINUSE) { + return -1; + } + } + return -1; +} + + +#else +#include "test.h" + +int +main(void) /* TODO add test */ +{ + return 0; +} + +#endif diff --git a/libsimple.h b/libsimple.h index bdfc7c7..1d72f46 100644 --- a/libsimple.h +++ b/libsimple.h @@ -167,6 +167,7 @@ #include "libsimple/search.h" #include "libsimple/random.h" #include "libsimple/abs.h" +#include "libsimple/net.h" /** diff --git a/libsimple/net.h b/libsimple/net.h new file mode 100644 index 0000000..c30020b --- /dev/null +++ b/libsimple/net.h @@ -0,0 +1,16 @@ +/* See LICENSE file for copyright and license details. */ + + +/** + * Bind a unix(7) socket to a random file name in a specific directory + * + * @param fd The socket's file descriptor + * @param dir_fd File descriptor to the directory the socket shall be + * stored in (may be `AT_FDCWD`) + * @param addr_out Output parameter for the socket name (may be `NULL`); + * `&strrchr(addr_out->sun_path, '/')[1]` will be the + * name of the file the socket will be bound to + * @param addrlen_out Output parameter for the size of the socket name (may be `NULL`) + * @return 0 on success, -1 on failure + */ +int libsimple_bindtemp_un(int fd, int dir_fd, struct sockaddr_un *addr_out, socklen_t *addrlen_out); /* TODO man */ |