LWS_VISIBLE int lws_plat_service(struct libwebsocket_context *context, int timeout_ms) { int n; int m; char buf; /* stay dead once we are dead */ if (!context) return 1; lws_libev_run(context); context->service_tid = context->protocols[0].callback(context, NULL, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); n = poll(context->fds, context->fds_count, timeout_ms); context->service_tid = 0; if (n == 0) /* poll timeout */ { libwebsocket_service_fd(context, NULL); return 0; } if (n < 0) { if (LWS_ERRNO != LWS_EINTR) return -1; return 0; } /* any socket with events to service? */ for (n = 0; n < context->fds_count; n++) { if (!context->fds[n].revents) continue; if (context->fds[n].fd == context->dummy_pipe_fds[0]) { if (read(context->fds[n].fd, &buf, 1) != 1) lwsl_err("Cannot read from dummy pipe."); continue; } m = libwebsocket_service_fd(context, &context->fds[n]); if (m < 0) return -1; /* if something closed, retry this slot */ if (m) n--; } return 0; }
LWS_VISIBLE LWS_EXTERN int _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; int n = -1, m, c; char buf; /* stay dead once we are dead */ if (!context || !context->vhost_list) return 1; if (timeout_ms < 0) goto faked_service; lws_libev_run(context, tsi); lws_libuv_run(context, tsi); if (!context->service_tid_detected) { struct lws _lws; memset(&_lws, 0, sizeof(_lws)); _lws.context = context; context->service_tid_detected = context->vhost_list->protocols[0].callback( &_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); } context->service_tid = context->service_tid_detected; /* * is there anybody with pending stuff that needs service forcing? */ if (!lws_service_adjust_timeout(context, 1, tsi)) { /* -1 timeout means just do forced service */ _lws_plat_service_tsi(context, -1, pt->tid); /* still somebody left who wants forced service? */ if (!lws_service_adjust_timeout(context, 1, pt->tid)) /* yes... come back again quickly */ timeout_ms = 0; } n = poll(pt->fds, pt->fds_count, timeout_ms); #ifdef LWS_OPENSSL_SUPPORT if (!pt->rx_draining_ext_list && !lws_ssl_anybody_has_buffered_read_tsi(context, tsi) && !n) { #else if (!pt->rx_draining_ext_list && !n) /* poll timeout */ { #endif lws_service_fd_tsi(context, NULL, tsi); return 0; } faked_service: m = lws_service_flag_pending(context, tsi); if (m) c = -1; /* unknown limit */ else if (n < 0) { if (LWS_ERRNO != LWS_EINTR) return -1; return 0; } else c = n; /* any socket with events to service? */ for (n = 0; n < 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; /* if something closed, retry this slot */ if (m) n--; } return 0; } LWS_VISIBLE int lws_plat_check_connection_error(struct lws *wsi) { return 0; } LWS_VISIBLE int lws_plat_service(struct lws_context *context, int timeout_ms) { return _lws_plat_service_tsi(context, timeout_ms, 0); } LWS_VISIBLE int lws_plat_set_socket_options(struct lws_vhost *vhost, int fd) { int optval = 1; socklen_t optlen = sizeof(optval); #if defined(__APPLE__) || \ defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ defined(__NetBSD__) || \ defined(__OpenBSD__) struct protoent *tcp_proto; #endif if (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) /* * 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 */ 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 } /* Disable Nagle */ optval = 1; #if defined (__sun) if (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__) if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0) return 1; #else tcp_proto = getprotobyname("TCP"); if (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; }
LWS_VISIBLE int lws_plat_service(struct lws_context *context, int timeout_ms) { int n; int m; char buf; #ifdef LWS_OPENSSL_SUPPORT struct lws *wsi, *wsi_next; #endif /* stay dead once we are dead */ if (!context) return 1; lws_libev_run(context); context->service_tid = context->protocols[0].callback(NULL, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); #ifdef LWS_OPENSSL_SUPPORT /* if we know we have non-network pending data, do not wait in poll */ if (lws_ssl_anybody_has_buffered_read(context)) timeout_ms = 0; #endif n = poll(context->fds, context->fds_count, timeout_ms); context->service_tid = 0; #ifdef LWS_OPENSSL_SUPPORT if (!lws_ssl_anybody_has_buffered_read(context) && n == 0) { #else if (n == 0) /* poll timeout */ { #endif lws_service_fd(context, NULL); return 0; } if (n < 0) { if (LWS_ERRNO != LWS_EINTR) return -1; return 0; } #ifdef LWS_OPENSSL_SUPPORT /* * For all guys with buffered SSL read data already saved up, if they * are not flowcontrolled, fake their POLLIN status so they'll get * service to use up the buffered incoming data, even though their * network socket may have nothing */ wsi = context->pending_read_list; while (wsi) { wsi_next = wsi->pending_read_list_next; context->fds[wsi->position_in_fds_table].revents |= context->fds[wsi->position_in_fds_table].events & POLLIN; if (context->fds[wsi->position_in_fds_table].revents & POLLIN) /* * he's going to get serviced now, take him off the * list of guys with buffered SSL. If he still has some * at the end of the service, he'll get put back on the * list then. */ lws_ssl_remove_wsi_from_buffered_list(wsi); wsi = wsi_next; } #endif /* any socket with events to service? */ for (n = 0; n < context->fds_count; n++) { if (!context->fds[n].revents) continue; if (context->fds[n].fd == context->dummy_pipe_fds[0]) { if (read(context->fds[n].fd, &buf, 1) != 1) lwsl_err("Cannot read from dummy pipe."); continue; } m = lws_service_fd(context, &context->fds[n]); if (m < 0) return -1; /* if something closed, retry this slot */ if (m) n--; } return 0; } LWS_VISIBLE int lws_plat_set_socket_options(struct lws_context *context, int fd) { int optval = 1; socklen_t optlen = sizeof(optval); #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ defined(__OpenBSD__) struct protoent *tcp_proto; #endif if (context->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(__NetBSD__) || \ defined(__CYGWIN__) || defined(__OpenBSD__) /* * 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 */ optval = context->ka_time; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, (const void *)&optval, optlen) < 0) return 1; optval = context->ka_interval; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, (const void *)&optval, optlen) < 0) return 1; optval = context->ka_probes; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, (const void *)&optval, optlen) < 0) return 1; #endif } /* Disable Nagle */ optval = 1; #if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ !defined(__OpenBSD__) if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0) return 1; #else tcp_proto = getprotobyname("TCP"); if (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; }