diff options
Diffstat (limited to 'thirdparty/libwebsockets/plat/lws-plat-unix.c')
| -rw-r--r-- | thirdparty/libwebsockets/plat/lws-plat-unix.c | 303 |
1 files changed, 211 insertions, 92 deletions
diff --git a/thirdparty/libwebsockets/plat/lws-plat-unix.c b/thirdparty/libwebsockets/plat/lws-plat-unix.c index a51e67bb8..bacc6af64 100644 --- a/thirdparty/libwebsockets/plat/lws-plat-unix.c +++ b/thirdparty/libwebsockets/plat/lws-plat-unix.c @@ -19,7 +19,8 @@ * MA 02110-1301 USA */ -#include "private-libwebsockets.h" +#define _GNU_SOURCE +#include "core/private.h" #include <pwd.h> #include <grp.h> @@ -29,6 +30,56 @@ #endif #include <dirent.h> +int +lws_plat_socket_offset(void) +{ + return 0; +} + +int +lws_plat_pipe_create(struct lws *wsi) +{ + struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; + +#if defined(LWS_HAVE_PIPE2) + return pipe2(pt->dummy_pipe_fds, O_NONBLOCK); +#else + return pipe(pt->dummy_pipe_fds); +#endif +} + +int +lws_plat_pipe_signal(struct lws *wsi) +{ + struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; + char buf = 0; + int n; + + n = write(pt->dummy_pipe_fds[1], &buf, 1); + + return n != 1; +} + +void +lws_plat_pipe_close(struct lws *wsi) +{ + struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; + + if (pt->dummy_pipe_fds[0] && pt->dummy_pipe_fds[0] != -1) + close(pt->dummy_pipe_fds[0]); + if (pt->dummy_pipe_fds[1] && pt->dummy_pipe_fds[1] != -1) + close(pt->dummy_pipe_fds[1]); + + pt->dummy_pipe_fds[0] = pt->dummy_pipe_fds[1] = -1; +} + +#ifdef __QNX__ +# include "netinet/tcp_var.h" +# define TCP_KEEPINTVL TCPCTL_KEEPINTVL +# define TCP_KEEPIDLE TCPCTL_KEEPIDLE +# define TCP_KEEPCNT TCPCTL_KEEPCNT +#endif + unsigned long long time_in_microseconds(void) { struct timeval tv; @@ -52,6 +103,10 @@ lws_send_pipe_choked(struct lws *wsi) #if defined(LWS_WITH_HTTP2) wsi_eff = lws_get_network_wsi(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 (wsi_eff->trunc_len) return 1; @@ -77,29 +132,6 @@ lws_poll_listen_fd(struct lws_pollfd *fd) return poll(fd, 1, 0); } -LWS_VISIBLE void -lws_cancel_service_pt(struct lws *wsi) -{ - struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; - char buf = 0; - - if (write(pt->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1) - lwsl_err("Cannot write to dummy pipe"); -} - -LWS_VISIBLE void -lws_cancel_service(struct lws_context *context) -{ - struct lws_context_per_thread *pt = &context->pt[0]; - char buf = 0, m = context->count_threads; - - while (m--) { - if (write(pt->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1) - lwsl_err("Cannot write to dummy pipe"); - pt++; - } -} - LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line) { int syslog_level = LOG_DEBUG; @@ -124,9 +156,10 @@ LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line) LWS_VISIBLE LWS_EXTERN int _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi) { + volatile struct lws_foreign_thread_pollfd *ftp, *next; + volatile struct lws_context_per_thread *vpt; struct lws_context_per_thread *pt; int n = -1, m, c; - char buf; /* stay dead once we are dead */ @@ -134,15 +167,15 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi) return 1; pt = &context->pt[tsi]; + vpt = (volatile struct lws_context_per_thread *)pt; lws_stats_atomic_bump(context, pt, LWSSTATS_C_SERVICE_ENTRY, 1); if (timeout_ms < 0) goto faked_service; - lws_libev_run(context, tsi); - lws_libuv_run(context, tsi); - lws_libevent_run(context, tsi); + if (context->event_loop_ops->run_pt) + context->event_loop_ops->run_pt(context, tsi); if (!context->service_tid_detected) { struct lws _lws; @@ -169,15 +202,73 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi) timeout_ms = 0; } + if (timeout_ms) { + lws_pt_lock(pt, __func__); + /* don't stay in poll wait longer than next hr timeout */ + lws_usec_t t = __lws_hrtimer_service(pt); + if ((lws_usec_t)timeout_ms * 1000 > t) + timeout_ms = t / 1000; + lws_pt_unlock(pt); + } + + vpt->inside_poll = 1; + lws_memory_barrier(); n = poll(pt->fds, pt->fds_count, timeout_ms); + vpt->inside_poll = 0; + lws_memory_barrier(); -#ifdef LWS_OPENSSL_SUPPORT - if (!n && !pt->rx_draining_ext_list && - !lws_ssl_anybody_has_buffered_read_tsi(context, tsi)) { -#else - if (!pt->rx_draining_ext_list && !n) /* poll timeout */ { + /* Collision will be rare and brief. Just spin until it completes */ + while (vpt->foreign_spinlock) + ; + + /* + * At this point we are not inside a foreign thread pollfd change, + * and we have marked ourselves as outside the poll() wait. So we + * are the only guys that can modify the lws_foreign_thread_pollfd + * list on the pt. Drain the list and apply the changes to the + * affected pollfds in the correct order. + */ + + lws_pt_lock(pt, __func__); + + ftp = vpt->foreign_pfd_list; + //lwsl_notice("cleared list %p\n", ftp); + while (ftp) { + struct lws *wsi; + struct lws_pollfd *pfd; + + next = ftp->next; + pfd = &vpt->fds[ftp->fd_index]; + if (lws_socket_is_valid(pfd->fd)) { + wsi = wsi_from_fd(context, pfd->fd); + if (wsi) + __lws_change_pollfd(wsi, ftp->_and, ftp->_or); + } + lws_free((void *)ftp); + ftp = next; + } + vpt->foreign_pfd_list = NULL; + lws_memory_barrier(); + + /* we have come out of a poll wait... check the hrtimer list */ + + __lws_hrtimer_service(pt); + + lws_pt_unlock(pt); + + m = 0; +#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS) + m |= !!pt->ws.rx_draining_ext_list; #endif + + if (pt->context->tls_ops && + pt->context->tls_ops->fake_POLLIN_for_buffered) + m |= pt->context->tls_ops->fake_POLLIN_for_buffered(pt); + + if (!m && !n) { /* nothing to do */ lws_service_fd_tsi(context, NULL, tsi); + lws_service_do_ripe_rxflow(pt); + return 0; } @@ -194,18 +285,12 @@ faked_service: c = n; /* any socket with events to service? */ - for (n = 0; n < pt->fds_count && c; n++) { + for (n = 0; n < (int)pt->fds_count && c; n++) { if (!pt->fds[n].revents) continue; c--; - if (pt->fds[n].fd == pt->dummy_pipe_fds[0]) { - if (read(pt->fds[n].fd, &buf, 1) != 1) - lwsl_err("Cannot read from dummy pipe."); - continue; - } - m = lws_service_fd_tsi(context, &pt->fds[n], tsi); if (m < 0) return -1; @@ -214,6 +299,8 @@ faked_service: n--; } + lws_service_do_ripe_rxflow(pt); + return 0; } @@ -262,6 +349,14 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd) */ #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) @@ -292,7 +387,7 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd) /* Disable Nagle */ optval = 1; -#if defined (__sun) +#if defined (__sun) || defined(__QNX__) if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0) return 1; #elif !defined(__APPLE__) && \ @@ -317,7 +412,7 @@ lws_plat_set_socket_options(struct lws_vhost *vhost, int fd) #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) static void -_lws_plat_apply_caps(int mode, cap_value_t *cv, int count) +_lws_plat_apply_caps(int mode, const cap_value_t *cv, int count) { cap_t caps; @@ -334,7 +429,7 @@ _lws_plat_apply_caps(int mode, cap_value_t *cv, int count) #endif LWS_VISIBLE void -lws_plat_drop_app_privileges(struct lws_context_creation_info *info) +lws_plat_drop_app_privileges(const struct lws_context_creation_info *info) { #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) int n; @@ -449,8 +544,8 @@ lws_plat_plugins_init(struct lws_context * context, const char * const *d) } plugin->list = context->plugin_list; context->plugin_list = plugin; - strncpy(plugin->name, namelist[i]->d_name, sizeof(plugin->name) - 1); - plugin->name[sizeof(plugin->name) - 1] = '\0'; + lws_strncpy(plugin->name, namelist[i]->d_name, + sizeof(plugin->name)); plugin->l = l; plugin->caps = lcaps; context->plugin_protocol_count += lcaps.count_protocols; @@ -543,9 +638,6 @@ lws_plat_context_early_destroy(struct lws_context *context) LWS_VISIBLE void lws_plat_context_late_destroy(struct lws_context *context) { - struct lws_context_per_thread *pt = &context->pt[0]; - int m = context->count_threads; - #ifdef LWS_WITH_PLUGINS if (context->plugin_list) lws_plat_plugins_destroy(context); @@ -554,13 +646,6 @@ lws_plat_context_late_destroy(struct lws_context *context) if (context->lws_lookup) lws_free(context->lws_lookup); - while (m--) { - if (pt->dummy_pipe_fds[0]) - close(pt->dummy_pipe_fds[0]); - if (pt->dummy_pipe_fds[1]) - close(pt->dummy_pipe_fds[1]); - pt++; - } if (!context->fd_random) lwsl_err("ZERO RANDOM FD\n"); if (context->fd_random != LWS_INVALID_FILE) @@ -573,7 +658,7 @@ LWS_VISIBLE int lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr, size_t addrlen) { - int rc = -1; + int rc = LWS_ITOSA_NOT_EXIST; struct ifaddrs *ifr; struct ifaddrs *ifc; @@ -586,12 +671,19 @@ lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr, if (!ifc->ifa_addr) continue; - lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname); + 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) { @@ -619,20 +711,20 @@ lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr, default: continue; } - rc = 0; + rc = LWS_ITOSA_USABLE; } freeifaddrs(ifr); - if (rc == -1) { + if (rc) { /* check if bind to IP address */ #ifdef LWS_WITH_IPV6 if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1) - rc = 0; + rc = LWS_ITOSA_USABLE; else #endif if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1) - rc = 0; + rc = LWS_ITOSA_USABLE; } return rc; @@ -643,9 +735,8 @@ lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi) { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; - lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ); - lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ); - lws_libevent_io(wsi, LWS_EV_START | LWS_EV_READ); + if (context->event_loop_ops->io) + context->event_loop_ops->io(wsi, LWS_EV_START | LWS_EV_READ); pt->fds[pt->fds_count++].revents = 0; } @@ -656,9 +747,9 @@ lws_plat_delete_socket_from_fds(struct lws_context *context, { struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; - lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE); - lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE); - lws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE); + if (context->event_loop_ops->io) + context->event_loop_ops->io(wsi, + LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE); pt->fds_count--; } @@ -739,7 +830,8 @@ _lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset) { lws_fileofs_t r; - if (offset > 0 && offset > fop_fd->len - fop_fd->pos) + if (offset > 0 && + offset > (lws_fileofs_t)fop_fd->len - (lws_fileofs_t)fop_fd->pos) offset = fop_fd->len - fop_fd->pos; if ((lws_fileofs_t)fop_fd->pos + offset < 0) @@ -793,13 +885,11 @@ _lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount, return 0; } - LWS_VISIBLE int lws_plat_init(struct lws_context *context, - struct lws_context_creation_info *info) + const struct lws_context_creation_info *info) { - struct lws_context_per_thread *pt = &context->pt[0]; - int n = context->count_threads, fd; + int fd; /* master context has the global fd lookup array */ context->lws_lookup = lws_zalloc(sizeof(struct lws *) * @@ -821,26 +911,6 @@ lws_plat_init(struct lws_context *context, return 1; } - if (!lws_libev_init_fd_table(context) && - !lws_libuv_init_fd_table(context) && - !lws_libevent_init_fd_table(context)) { - /* otherwise libev/uv/event handled it instead */ - - while (n--) { - if (pipe(pt->dummy_pipe_fds)) { - lwsl_err("Unable to create pipe\n"); - return 1; - } - - /* use the read end of pipe as first item */ - pt->fds[0].fd = pt->dummy_pipe_fds[0]; - pt->fds[0].events = LWS_POLLIN; - pt->fds[0].revents = 0; - pt->fds_count = 1; - pt++; - } - } - #ifdef LWS_WITH_PLUGINS if (info->plugin_dirs) lws_plat_plugins_init(context, info->plugin_dirs); @@ -848,3 +918,52 @@ lws_plat_init(struct lws_context *context, return 0; } + +LWS_VISIBLE int +lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf, + int len) +{ + int n; + + n = write(fd, buf, len); + + fsync(fd); + lseek(fd, 0, SEEK_SET); + + return n != len; +} + +LWS_VISIBLE int +lws_plat_write_file(const char *filename, void *buf, int len) +{ + int m, fd; + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); + + if (fd == -1) + return 1; + + m = write(fd, buf, len); + close(fd); + + return m != len; +} + +LWS_VISIBLE int +lws_plat_read_file(const char *filename, void *buf, int len) +{ + int n, fd = open(filename, O_RDONLY); + if (fd == -1) + return -1; + + n = read(fd, buf, len); + close(fd); + + return n; +} + +LWS_VISIBLE int +lws_plat_recommended_rsa_bits(void) +{ + return 4096; +} |
