X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=usock.c;h=62a5f2067f9ffb890dd1b860a5e8d26a5ede7d1d;hb=f8b32f7620efdb73055f7fd6af4c796a770050e2;hp=6458151c02f91e2e8bbde46f04b52005b3d5982d;hpb=07dbea00588bf322e16076cf7d818a13f934301f;p=project%2Flibubox.git diff --git a/usock.c b/usock.c index 6458151..62a5f20 100644 --- a/usock.c +++ b/usock.c @@ -1,13 +1,33 @@ +/* + * usock - socket helper functions + * + * Copyright (C) 2010 Steven Barth + * Copyright (C) 2011-2012 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #include #include #include #include +#include #include #include #include #include #include #include +#include #include "usock.h" @@ -20,7 +40,7 @@ static void usock_set_flags(int sock, unsigned int type) fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK); } -static int usock_connect(struct sockaddr *sa, int sa_len, int family, int socktype, bool server) +static int usock_connect(int type, struct sockaddr *sa, int sa_len, int family, int socktype, bool server) { int sock; @@ -28,6 +48,8 @@ static int usock_connect(struct sockaddr *sa, int sa_len, int family, int sockty if (sock < 0) return -1; + usock_set_flags(sock, type); + if (server) { const int one = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); @@ -44,9 +66,11 @@ static int usock_connect(struct sockaddr *sa, int sa_len, int family, int sockty return -1; } -static int usock_unix(const char *host, int socktype, bool server) +static int usock_unix(int type, const char *host) { struct sockaddr_un sun = {.sun_family = AF_UNIX}; + bool server = !!(type & USOCK_SERVER); + int socktype = ((type & 0xff) == USOCK_TCP) ? SOCK_STREAM : SOCK_DGRAM; if (strlen(host) >= sizeof(sun.sun_path)) { errno = EINVAL; @@ -54,11 +78,13 @@ static int usock_unix(const char *host, int socktype, bool server) } strcpy(sun.sun_path, host); - return usock_connect((struct sockaddr*)&sun, sizeof(sun), AF_UNIX, socktype, server); + return usock_connect(type, (struct sockaddr*)&sun, sizeof(sun), AF_UNIX, socktype, server); } -static int usock_inet(int type, const char *host, const char *service, int socktype, bool server) +int usock_inet(int type, const char *host, const char *service, void *addr) { + int socktype = ((type & 0xff) == USOCK_TCP) ? SOCK_STREAM : SOCK_DGRAM; + bool server = !!(type & USOCK_SERVER); struct addrinfo *result, *rp; struct addrinfo hints = { .ai_family = (type & USOCK_IPV6ONLY) ? AF_INET6 : @@ -74,28 +100,66 @@ static int usock_inet(int type, const char *host, const char *service, int sockt return -1; for (rp = result; rp != NULL; rp = rp->ai_next) { - sock = usock_connect(rp->ai_addr, rp->ai_addrlen, rp->ai_family, socktype, server); - if (sock >= 0) + sock = usock_connect(type, rp->ai_addr, rp->ai_addrlen, rp->ai_family, socktype, server); + if (sock >= 0) { + if (addr) + memcpy(addr, rp->ai_addr, rp->ai_addrlen); break; + } } freeaddrinfo(result); return sock; } +const char *usock_port(int port) +{ + static char buffer[sizeof("65535\0")]; + + if (port < 0 || port > 65535) + return NULL; + + snprintf(buffer, sizeof(buffer), "%u", port); + + return buffer; +} + int usock(int type, const char *host, const char *service) { - int socktype = ((type & 0xff) == USOCK_TCP) ? SOCK_STREAM : SOCK_DGRAM; - bool server = !!(type & USOCK_SERVER); int sock; if (type & USOCK_UNIX) - sock = usock_unix(host, socktype, server); + sock = usock_unix(type, host); else - sock = usock_inet(type, host, service, socktype, server); + sock = usock_inet(type, host, service, NULL); if (sock < 0) return -1; - usock_set_flags(sock, type); return sock; } + +int usock_wait_ready(int fd, int msecs) { + struct pollfd fds[1]; + int res; + + fds[0].fd = fd; + fds[0].events = POLLOUT; + + res = poll(fds, 1, msecs); + if (res < 0) { + return errno; + } else if (res == 0) { + return -ETIMEDOUT; + } else { + int err = 0; + socklen_t optlen = sizeof(err); + + res = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen); + if (res) + return errno; + if (err) + return err; + } + + return 0; +}