diff options
Diffstat (limited to 'thirdparty/libwebsockets/lib/plat/unix/unix-sockets.c')
-rw-r--r-- | thirdparty/libwebsockets/lib/plat/unix/unix-sockets.c | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/thirdparty/libwebsockets/lib/plat/unix/unix-sockets.c b/thirdparty/libwebsockets/lib/plat/unix/unix-sockets.c new file mode 100644 index 0000000000..192dddee63 --- /dev/null +++ b/thirdparty/libwebsockets/lib/plat/unix/unix-sockets.c @@ -0,0 +1,263 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#include "core/private.h" + +#include <pwd.h> +#include <grp.h> + + + +int +lws_send_pipe_choked(struct lws *wsi) +{ + struct lws_pollfd fds; + struct lws *wsi_eff; + +#if defined(LWS_WITH_HTTP2) + wsi_eff = lws_get_network_wsi(wsi); +#else + wsi_eff = wsi; +#endif + + /* the fact we checked implies we avoided back-to-back writes */ + wsi_eff->could_have_pending = 0; + + /* treat the fact we got a truncated send pending as if we're choked */ + if (lws_has_buffered_out(wsi_eff) +#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) + ||wsi->http.comp_ctx.buflist_comp || + wsi->http.comp_ctx.may_have_more +#endif + ) + return 1; + + fds.fd = wsi_eff->desc.sockfd; + fds.events = POLLOUT; + fds.revents = 0; + + if (poll(&fds, 1, 0) != 1) + return 1; + + if ((fds.revents & POLLOUT) == 0) + return 1; + + /* okay to send another packet without blocking */ + + return 0; +} + + +int +lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt) +{ + int optval = 1; + socklen_t optlen = sizeof(optval); + +#ifdef LWS_WITH_IPV6 + optval = 0; + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void*)&optval, optlen); +#endif + +#if defined(__APPLE__) || \ + defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) || \ + defined(__HAIKU__) + struct protoent *tcp_proto; +#endif + + (void)fcntl(fd, F_SETFD, FD_CLOEXEC); + + if (!unix_skt && vhost->ka_time) { + /* enable keepalive on this socket */ + optval = 1; + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, + (const void *)&optval, optlen) < 0) + return 1; + +#if defined(__APPLE__) || \ + defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) || \ + defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun) || \ + defined(__HAIKU__) + + /* + * didn't find a way to set these per-socket, need to + * tune kernel systemwide values + */ +#else + /* set the keepalive conditions we want on it too */ + +#if defined(LWS_HAVE_TCP_USER_TIMEOUT) + optval = 1000 * (vhost->ka_time + + (vhost->ka_interval * vhost->ka_probes)); + if (setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, + (const void *)&optval, optlen) < 0) + return 1; +#endif + optval = vhost->ka_time; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, + (const void *)&optval, optlen) < 0) + return 1; + + optval = vhost->ka_interval; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, + (const void *)&optval, optlen) < 0) + return 1; + + optval = vhost->ka_probes; + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, + (const void *)&optval, optlen) < 0) + return 1; +#endif + } + +#if defined(SO_BINDTODEVICE) + if (!unix_skt && vhost->bind_iface && vhost->iface) { + lwsl_info("binding listen skt to %s using SO_BINDTODEVICE\n", vhost->iface); + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost->iface, + strlen(vhost->iface)) < 0) { + lwsl_warn("Failed to bind to device %s\n", vhost->iface); + return 1; + } + } +#endif + + /* Disable Nagle */ + optval = 1; +#if defined (__sun) || defined(__QNX__) + if (!unix_skt && setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0) + return 1; +#elif !defined(__APPLE__) && \ + !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && \ + !defined(__NetBSD__) && \ + !defined(__OpenBSD__) && \ + !defined(__HAIKU__) + if (!unix_skt && setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0) + return 1; +#else + tcp_proto = getprotobyname("TCP"); + if (!unix_skt && setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0) + return 1; +#endif + + /* We are nonblocking... */ + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + return 1; + + return 0; +} + + +/* cast a struct sockaddr_in6 * into addr for ipv6 */ + +int +lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr, + size_t addrlen) +{ + int rc = LWS_ITOSA_NOT_EXIST; + + struct ifaddrs *ifr; + struct ifaddrs *ifc; +#ifdef LWS_WITH_IPV6 + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; +#endif + + getifaddrs(&ifr); + for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) { + if (!ifc->ifa_addr) + continue; + + lwsl_debug(" interface %s vs %s (fam %d) ipv6 %d\n", + ifc->ifa_name, ifname, + ifc->ifa_addr->sa_family, ipv6); + + if (strcmp(ifc->ifa_name, ifname)) + continue; + + switch (ifc->ifa_addr->sa_family) { +#if defined(AF_PACKET) + case AF_PACKET: + /* interface exists but is not usable */ + rc = LWS_ITOSA_NOT_USABLE; + continue; +#endif + + case AF_INET: +#ifdef LWS_WITH_IPV6 + if (ipv6) { + /* map IPv4 to IPv6 */ + bzero((char *)&addr6->sin6_addr, + sizeof(struct in6_addr)); + addr6->sin6_addr.s6_addr[10] = 0xff; + addr6->sin6_addr.s6_addr[11] = 0xff; + memcpy(&addr6->sin6_addr.s6_addr[12], + &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr, + sizeof(struct in_addr)); + } else +#endif + memcpy(addr, + (struct sockaddr_in *)ifc->ifa_addr, + sizeof(struct sockaddr_in)); + break; +#ifdef LWS_WITH_IPV6 + case AF_INET6: + memcpy(&addr6->sin6_addr, + &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr, + sizeof(struct in6_addr)); + break; +#endif + default: + continue; + } + rc = LWS_ITOSA_USABLE; + } + + freeifaddrs(ifr); + + if (rc) { + /* check if bind to IP address */ +#ifdef LWS_WITH_IPV6 + if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1) + rc = LWS_ITOSA_USABLE; + else +#endif + if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1) + rc = LWS_ITOSA_USABLE; + } + + return rc; +} + + +const char * +lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) +{ + return inet_ntop(af, src, dst, cnt); +} + +int +lws_plat_inet_pton(int af, const char *src, void *dst) +{ + return inet_pton(af, src, dst); +} |