X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=socket-util.c;h=8141ab09ebcd3fa0c08d4a715c1e873f84c2b262;hb=2d02719c2bcf8b5e30228e00eaceae91946c7551;hp=0f5140ec5b9769a17d963c9e7c19a7dc271e28d6;hpb=47be870bd83fb3719dffc3ee9348a409ab762a14;p=elogind.git diff --git a/socket-util.c b/socket-util.c index 0f5140ec5..8141ab09e 100644 --- a/socket-util.c +++ b/socket-util.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "macro.h" #include "util.h" @@ -298,7 +300,15 @@ int socket_address_print(const SocketAddress *a, char **p) { } } -int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBindIPv6Only only, const char *bind_to_device, int *ret) { +int socket_address_listen( + const SocketAddress *a, + int backlog, + SocketAddressBindIPv6Only only, + const char *bind_to_device, + mode_t directory_mode, + mode_t socket_mode, + int *ret) { + int r, fd, one; assert(a); assert(ret); @@ -324,7 +334,31 @@ int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBind if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) goto fail; - if (bind(fd, &a->sockaddr.sa, a->size) < 0) + if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) { + mode_t old_mask; + + /* Create parents */ + mkdir_parents(a->sockaddr.un.sun_path, directory_mode); + + /* Enforce the right access mode for the socket*/ + old_mask = umask(~ socket_mode); + + /* Include the original umask in our mask */ + umask(~socket_mode | old_mask); + + r = bind(fd, &a->sockaddr.sa, a->size); + + if (r < 0 && errno == EADDRINUSE) { + /* Unlink and try again */ + unlink(a->sockaddr.un.sun_path); + r = bind(fd, &a->sockaddr.sa, a->size); + } + + umask(old_mask); + } else + r = bind(fd, &a->sockaddr.sa, a->size); + + if (r < 0) goto fail; if (a->type == SOCK_STREAM) @@ -336,6 +370,88 @@ int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBind fail: r = -errno; - close_nointr(fd); + close_nointr_nofail(fd); return r; } + +bool socket_address_can_accept(const SocketAddress *a) { + assert(a); + + return + a->type == SOCK_STREAM || + a->type == SOCK_SEQPACKET; +} + +bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) { + assert(a); + assert(b); + + /* Invalid addresses are unequal to all */ + if (socket_address_verify(a) < 0 || + socket_address_verify(b) < 0) + return false; + + if (a->type != b->type) + return false; + + if (a->size != b->size) + return false; + + if (socket_address_family(a) != socket_address_family(b)) + return false; + + switch (socket_address_family(a)) { + + case AF_INET: + if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr) + return false; + + if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port) + return false; + + break; + + case AF_INET6: + if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0) + return false; + + if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port) + return false; + + break; + + case AF_UNIX: + + if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0)) + return false; + + if (a->sockaddr.un.sun_path[0]) { + if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0) + return false; + } else { + if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0) + return false; + } + + break; + + default: + /* Cannot compare, so we assume the addresses are different */ + return false; + } + + return true; +} + +bool socket_address_is(const SocketAddress *a, const char *s) { + struct SocketAddress b; + + assert(a); + assert(s); + + if (socket_address_parse(&b, s) < 0) + return false; + + return socket_address_equal(a, &b); + +}