diff --git a/.gitignore b/.gitignore index a75ffaef..ab798a91 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,8 @@ cmake_install.cmake # Ignore autogenerated version.h. /include/version.cmake /version.h + +# Ignore VSCore related stuff +build/ +settings.json +*.code-workspace \ No newline at end of file diff --git a/CHANGES.md b/CHANGES.md index 9c40b0dc..ffd177c6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,10 @@ +Feature added in 3.7.x +====================== +- Enabled support of RFC 7118 The WebSocket Protocol as a Transport for the Session Initiation Protocol (SIP) +- Based on libwebsocket and only in client mode and WSS only. +- added a -w1 option to specify SIP transport +- added a USE_WSS definition in CMakeList.txt to enable it + Features added in 3.7.5 ======================= diff --git a/CMakeLists.txt b/CMakeLists.txt index d7223a1b..ff61acbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,6 +111,10 @@ function(apply_common_sipp_dependencies TARGET_NAME) if(BUILD_STATIC AND MSYS) target_link_libraries(${TARGET_NAME} crypt32) endif() + + if(USE_WSS) + target_link_libraries(${TARGET_NAME} ${LIBWEBSOCKETS_LIBRARIES}) + endif() endfunction() optional_library(SCTP "Build with SCTP support") @@ -293,6 +297,17 @@ if(USE_SCTP) find_library(SCTP_LIBRARY sctp) endif() +# Option principale +option(USE_WSS "Enable WebSocket Secure (WSS) support via libwebsockets" OFF) + +if(USE_WSS) + find_package(PkgConfig REQUIRED) + pkg_check_modules(LIBWEBSOCKETS REQUIRED libwebsockets) + add_definitions("-DUSE_WSS") + set(LIBWEBSOCKETS_LIBRARIES ${LIBWEBSOCKETS_LIBRARIES}) + message(STATUS "Found libwebsockets: ${LIBWEBSOCKETS_LIBRARIES}") + +endif() # add the main executable add_sipp_target(sipp SOURCES "${PROJECT_SOURCE_DIR}/src/sipp.cpp" diff --git a/README.md b/README.md index f98ed7ef..5b7ca120 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,9 @@ This is the SIPp package. Please refer to the Normally, you should be able to build SIPp by using CMake: ``` -cmake . +mkdir build +cd build +cmake .. make ``` @@ -59,6 +61,26 @@ The TLS key log file format is described here: https://datatracker.ietf.org/doc/ _Please note the security considerations ("3. Security Considerations")!_ +To enable SIP over WebSocket feature pass `-DUSE_WSS=ON` to cmake. You need to have compiled [libwebsocket](https://libwebsockets.org/) before. +And on order to avoid dynamic dependency, use only the static version. Here are simple instructions to build the lib on for linux: + +``` +cd libwebsocket +mkdir build +cd build +cmake -DCMAKE_INSTALL_PREFIX=/usr -DLWS_WITHOUT_TESTAPPS=ON -DLWS_WITH_SSL=ON -DLWS_WITH_SHARED=OFF -DLWS_WITH_STATIC=OFF .. +make +sudo make install +``` +Then compile sipp with -DUSE_WSS=1 +``` +cd sipp +mkdir build +cd build +cmake .. -DUSE_WSS=1 +make +``` + ## Static builds SIPp can be built into a single static binary, removing the need for diff --git a/docs/installation.rst b/docs/installation.rst index 022bbc07..1c8ce2d0 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -66,6 +66,7 @@ Installing SIPp + For TLS support: OpenSSL >= 1.1.0 or WolfSSL >= 3.15.0 + For pcap play support: libpcap and libnet + For SCTP support: lksctp-tools + + For WSS support: libwebsocket + For distributed pauses: `Gnu Scientific Libraries`_ + You have four options to compile SIPp: diff --git a/docs/transport.rst b/docs/transport.rst index 50e85e26..ed7bc230 100644 --- a/docs/transport.rst +++ b/docs/transport.rst @@ -158,6 +158,12 @@ This mode is generally used for emulating user agents calling a SIP server. +WSS mode +```````` +sipp supports SIP over secure WebSocket in mono socket mode (-t w1). +Only client mode is supported for now. It is generally used to emulate +WebRTC clients. + IPv6 support ```````````` diff --git a/include/sipp.hpp b/include/sipp.hpp index 324f7614..c6ea3697 100644 --- a/include/sipp.hpp +++ b/include/sipp.hpp @@ -105,6 +105,7 @@ #define T_TCP 1 #define T_TLS 2 #define T_SCTP 3 +#define T_WSS 4 #ifdef USE_TLS #define DEFAULT_TLS_CERT "cacert.pem" @@ -113,7 +114,18 @@ #define DEFAULT_TLS_CRL "" #endif -#define TRANSPORT_TO_STRING(p) ((p==T_TCP) ? "TCP" : ((p==T_TLS)? "TLS" : ((p==T_UDP)? "UDP" : "SCTP"))) +inline const char * TRANSPORT_TO_STRING(int p) { + switch(p) + { + case T_TCP: return "TCP"; + case T_UDP: return "UDP"; + case T_TLS: return "TLS"; + case T_SCTP: return "SCTP"; + case T_WSS: return "WSS"; + default: break; + } + return "Unknown"; +} #define SIPP_MAXFDS 65536 diff --git a/include/socket.hpp b/include/socket.hpp index 2f1165d9..98d4f3bc 100644 --- a/include/socket.hpp +++ b/include/socket.hpp @@ -30,6 +30,10 @@ #define SCTP_UP 2 #endif +#ifdef USE_WSS +#include "libwebsockets.h" +#endif + /** * On some systems you must pass the exact sockaddr struct size to * connect/bind/sendto calls. Passing a length that is too large @@ -99,6 +103,10 @@ class SIPpSocket { int bind_to_device(const char* device_name); #endif +#ifdef USE_WSS + void lws_callback_wss(enum lws_callback_reasons reason, void *in, size_t len); +#endif + static void pollset_process(int wait); int ss_count = 1; /* How many users are there of this socket? */ @@ -150,6 +158,17 @@ class SIPpSocket { #ifdef USE_SCTP int sctpstate = SCTP_DOWN; #endif + +#ifdef USE_WSS + void init_lws_context(); + void close_wss(); + void wss_event_loop(int revents); + int wss_send(const void * buf, int len); + + struct lws *wsi; // Connexion WebSocket + bool wss_connected; + struct socketbuf * wss_out; +#endif }; diff --git a/src/call.cpp b/src/call.cpp index e4a583f9..5b44e1b0 100644 --- a/src/call.cpp +++ b/src/call.cpp @@ -1361,11 +1361,11 @@ bool call::connect_socket_if_needed() if (sipp_bind_socket(call_socket, &saddr, &call_port)) { ERROR_NO("Unable to bind UDP socket"); } - } else { /* TCP, SCTP or TLS. */ + } else { /* TCP, SCTP, WSS or TLS. */ struct sockaddr_storage *L_dest = &remote_sockaddr; if ((associate_socket(SIPpSocket::new_sipp_call_socket(use_ipv6, transport, &existing))) == nullptr) { - ERROR_NO("Unable to get a TCP/SCTP/TLS socket"); + ERROR_NO("Unable to get a TCP/SCTP/TLS/WSS socket"); } call_socket->ss_count++; @@ -5775,18 +5775,29 @@ call::T_ActionResult call::executeAction(const char* msg, message* curmsg) protocol = T_TLS; } else if (!strcmp(str_protocol, "sctp") || !strcmp(str_protocol, "SCTP")) { protocol = T_SCTP; - } else { + } else if (!strcmp(str_protocol, "wss") || !strcmp(str_protocol, "WSS")) { + protocol = T_WSS; + } + else { ERROR("Unknown transport for setdest: '%s'", str_protocol); } if (!call_socket && ((protocol == T_TCP && transport == T_TCP) || - (protocol == T_SCTP && transport == T_SCTP))) { + (protocol == T_SCTP && transport == T_SCTP) || + (protocol == T_WSS && transport == T_WSS))) { bool existing; + LOG_MSG("Creating new call socket"); if ((associate_socket(SIPpSocket::new_sipp_call_socket(use_ipv6, transport, &existing))) == nullptr) { - switch (protocol) { + switch (protocol) + { + case T_WSS: + ERROR_NO("Unable to get a WSS socket"); + break; + case T_SCTP: ERROR_NO("Unable to get a SCTP socket"); break; + default: ERROR_NO("Unable to get a TCP socket"); } @@ -5816,6 +5827,8 @@ call::T_ActionResult call::executeAction(const char* msg, message* curmsg) if (call_socket->ss_count > 1) { ERROR("Can not change destinations for a TCP/SCTP socket that has more than one user."); } + } else if (protocol == T_WSS) { + ERROR("Changing destinations is not supported for WSS."); } if (gai_getsockaddr(&call_peer, str_host, port, diff --git a/src/call_generation_task.cpp b/src/call_generation_task.cpp index c1b88a85..f7925506 100644 --- a/src/call_generation_task.cpp +++ b/src/call_generation_task.cpp @@ -165,6 +165,7 @@ bool CallGenerationTask::run() case T_TCP: case T_SCTP: case T_TLS: + case T_WSS: call_ptr->associate_socket(tcp_multiplex); tcp_multiplex->ss_count++; break; diff --git a/src/sipp.cpp b/src/sipp.cpp index f93078f7..3baa4229 100644 --- a/src/sipp.cpp +++ b/src/sipp.cpp @@ -174,6 +174,9 @@ struct sipp_option options_table[] = { #endif "- c1: u1 + compression (only if compression plugin loaded),\n" "- cn: un + compression (only if compression plugin loaded). This plugin is not provided with SIPp.\n" +#ifdef USE_WSS + "- w1: Secure Web Socket with one socket,\n" +#endif , SIPP_OPTION_TRANSPORT, nullptr, 1 }, {"i", "Set the local IP address for 'Contact:','Via:', and 'From:' headers. Default is primary host IP address.\n", SIPP_OPTION_IP, local_ip, 1}, @@ -1643,6 +1646,11 @@ int main(int argc, char *argv[]) ERROR("To use TLS transport you must compile SIPp with OpenSSL or WolfSSL"); #endif break; + + case 'w': + transport = T_WSS; + break; + case 'c': if (strlen(comp_error)) { ERROR("No " COMP_PLUGIN " plugin available: %s", comp_error); diff --git a/src/socket.cpp b/src/socket.cpp index 27473f9a..62056f2e 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -39,12 +39,17 @@ #include #include #include +#include #include "config.h" #include "sipp.hpp" #include "socket.hpp" #include "logger.hpp" +#ifdef USE_WSS +#include "libwebsockets.h" +#endif + extern bool do_hide; SIPpSocket *ctrl_socket = nullptr; @@ -69,6 +74,13 @@ int pending_messages = 0; std::map map_perip_fd; +#ifdef USE_WSS +static std::mutex lws_mutex; +static struct lws_context *lws_context = nullptr; // LWS context +static struct lws_vhost *lws_vh = nullptr; +#endif + + static void connect_to_peer( char *peer_host, int peer_port, struct sockaddr_storage *peer_sockaddr, char *peer_ip, int peer_ip_size, SIPpSocket **peer_socket); @@ -841,7 +853,7 @@ int SIPpSocket::empty() { int readsize=0; - if (ss_transport == T_UDP || ss_transport == T_SCTP) { + if (ss_transport == T_UDP || ss_transport == T_SCTP || ss_transport == T_WSS) { readsize = SIPP_MAX_MSG_SIZE; } else { readsize = tcp_readsize; @@ -875,25 +887,35 @@ int SIPpSocket::empty() ERROR("TLS support is not enabled!"); #endif break; + case T_SCTP: #ifdef USE_SCTP - struct sctp_sndrcvinfo recvinfo; - memset(&recvinfo, 0, sizeof(recvinfo)); - int msg_flags = 0; + { + struct sctp_sndrcvinfo recvinfo; + memset(&recvinfo, 0, sizeof(recvinfo)); + int msg_flags = 0; - ret = sctp_recvmsg(ss_fd, (void*)buffer, readsize, - (struct sockaddr *) &socketbuf->addr, &addrlen, &recvinfo, &msg_flags); + ret = sctp_recvmsg(ss_fd, (void*)buffer, readsize, + (struct sockaddr *) &socketbuf->addr, &addrlen, &recvinfo, &msg_flags); - if (MSG_NOTIFICATION & msg_flags) { - errno = 0; - handleSCTPNotify(buffer); - ret = -2; + if (MSG_NOTIFICATION & msg_flags) { + errno = 0; + handleSCTPNotify(buffer); + ret = -2; + } } #else ERROR("SCTP support is not enabled!"); #endif break; + +#ifdef USE_WSS + case T_WSS: + /* Inbound message handling is done in lws_cb()*/ + break; +#endif } + if (ret <= 0) { free_socketbuf(socketbuf); return ret; @@ -929,6 +951,11 @@ void SIPpSocket::invalidate() } #endif +#ifdef USE_WSS + // Close websocket connection + close_wss(); +#endif + /* In some error conditions, the socket FD has already been closed - if it hasn't, do so now. */ if (ss_fd != -1) { #ifdef HAVE_EPOLL @@ -1149,6 +1176,7 @@ void process_message(SIPpSocket *socket, char *msg, ssize_t msg_size, struct soc case T_TCP: case T_SCTP: case T_TLS: + case T_WSS: new_ptr->associate_socket(tcp_multiplex); tcp_multiplex->ss_count++; break; @@ -1239,6 +1267,252 @@ void process_message(SIPpSocket *socket, char *msg, ssize_t msg_size, struct soc } } + +#ifdef USE_WSS +static int lws_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) +{ + SIPpSocket *socket = (SIPpSocket *) user; + + if (socket) + { + socket->lws_callback_wss(reason, in, len); + } + return 0; +} + + +static struct lws_protocols protocols[] = +{ + { + "sip", + lws_cb, + 0, + SIPP_MAX_MSG_SIZE, + 0, + nullptr, + 0 + }, + { + "sip-wss", + lws_cb, + 0, + SIPP_MAX_MSG_SIZE, + 0, + nullptr, + 0 + }, + + { nullptr, nullptr, 0, 0, 0, nullptr, 0 } +}; + +static void sipp_lws_log_emit(int level, const char *line) +{ + // Redirige les logs de libwebsockets vers le système SIPp + switch(level) + { + case LLL_ERR: + WARNING("WSS: %s", line); + break; + + case LLL_WARN: + WARNING("WSS: %s", line); + break; + + default: + LOG_MSG("WSS: %s", line); + break; + + } +} + +void SIPpSocket::init_lws_context() +{ + std::lock_guard lock(lws_mutex); + if (lws_context) return; //Already created + + int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE; + //if (useLogf) log_level |= LLL_INFO; + lws_set_log_level(log_level, sipp_lws_log_emit); + + struct lws_context_creation_info info = {0}; + info.port = CONTEXT_PORT_NO_LISTEN; + info.protocols = protocols; + info.gid = -1; + info.uid = -1; + info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + info.timeout_secs = 40; + + lws_context = lws_create_context(&info); + if (!lws_context) + { + ERROR("WSS: Failed to create LWS context"); + } + + struct lws_context_creation_info vh_info; + memset(&vh_info, 0, sizeof(vh_info)); + vh_info.protocols = protocols; + vh_info.options = info.options; + vh_info.timeout_secs = info.timeout_secs; + + lws_vh = lws_create_vhost(lws_context, &vh_info); + if (!lws_vh) + { + ERROR("WSS: Impossible de créer le vhost LWS."); + } + LOG_MSG("WSS: context and vhost created.\n"); +} + +void SIPpSocket::lws_callback_wss(enum lws_callback_reasons reason, void *in, size_t len) +{ + switch (reason) + { + case LWS_CALLBACK_CLIENT_ESTABLISHED: + TRACE_MSG("WSS: Connected to %s.\n", remote_host); + ss_congested = false; + wss_connected = true; + break; + + case LWS_CALLBACK_CLIENT_RECEIVE: + if (len < SIPP_MAX_MSG_SIZE - 1 ) + { + struct sockaddr_storage src; + char msg[SIPP_MAX_MSG_SIZE]; + ssize_t len2; + + struct socketbuf * socketbuf = alloc_socketbuf((char *)in, len, 1, nullptr); + socketbuf->len = len; + buffer_read(socketbuf); + + /* Do we have a complete SIP message? */ + if (!ss_msglen) { + if (int msg_len = check_for_message()) { + ss_msglen = msg_len; + pending_messages++; + } + } + + len2 = read_message(msg, sizeof(msg), &src); + if (len2 > 2) { + process_message(this, msg, len, &src); + } + } + else + { + WARNING("WSS: Inbound WebSocket message too large. Dropping it"); + } + break; + + case LWS_CALLBACK_CLIENT_WRITEABLE: + ss_congested = false; + if (wss_out) { + int n = wss_send(wss_out->buf, wss_out->len); + if (n > 0) { + free_socketbuf(wss_out); + wss_out = nullptr; + } + } + else { + break; + } + + if (ss_out) + { + struct socketbuf *buf = ss_out; + while (ss_out) + { + int n = wss_send(buf->buf, buf->len); + if (n > 0) { + ss_out = buf->next; + free_socketbuf(buf); // frree the buffer + if (!ss_out) ss_out_tail = nullptr; + } + else + { + // Socket became non writeable + //WARNING("WSS: failed to send msg.\n"); + break; + } + } + } + break; + + case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: + ERROR("WSS: Failed to connect"); + this->invalidate(); + break; + + case LWS_CALLBACK_CLOSED: + LOG_MSG("WSS: Connection closed"); + this->invalidate(); + break; + + case LWS_CALLBACK_WSI_DESTROY: + LOG_MSG("WSS: internal websocket has been deleted."); + this->invalidate(); + break; + + default: + break; + } +} + +int SIPpSocket::wss_send(const void * buf, int len) +{ + if (wsi) { + unsigned char *lws_buf = (unsigned char*)malloc(LWS_PRE + len); + memcpy(lws_buf + LWS_PRE, buf, len); + + int n = lws_write(wsi, lws_buf + LWS_PRE, len, LWS_WRITE_TEXT); + free(lws_buf); + if (n > 0) { + return len; + } + else if (n < 0) { + return n; + } + else { + return -2; + } + } + else { + ERROR("Cannot write. WebSocket connection is not established"); + return -1; + } +} + +void SIPpSocket::close_wss() +{ + // Flush messages + if (wsi && ss_out) { + lws_callback_on_writable(wsi); + lws_service(lws_context, 100); + } + + // Close WSI + if (wsi) { + lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, LWS_TO_KILL_ASYNC); + wsi = nullptr; + } +} + +void SIPpSocket::wss_event_loop(int revents) +{ + if (ss_transport == T_WSS && lws_context) + { + struct lws_pollfd lws_pfd; + lws_pfd.fd = ss_fd; + lws_pfd.events = POLLIN | POLLOUT; + lws_pfd.revents = revents; + + int n = lws_service_fd(lws_context, &lws_pfd); + if (n < 0) { + TRACE_MSG("WSS: lws_service_fd() returned %d for fd=%d\n", n, ss_fd); + } + } +} + +#endif + SIPpSocket::SIPpSocket(bool use_ipv6, int transport, int fd, int accepting): ss_ipv6(use_ipv6), ss_transport(transport), @@ -1263,6 +1537,13 @@ SIPpSocket::SIPpSocket(bool use_ipv6, int transport, int fd, int accepting): SSL_set_bio(ss_ssl, ss_bio, ss_bio); } #endif + +#ifdef USE_WSS + wsi = nullptr; + if (transport == T_WSS) init_lws_context(); + wss_connected = false; + wss_out = nullptr; +#endif /* Store this socket in the tables. */ ss_pollidx = pollnfds++; sockets[ss_pollidx] = this; @@ -1314,6 +1595,7 @@ static int socket_fd(bool use_ipv6, int transport) ERROR("You do not have TLS support enabled!"); #endif case T_TCP: + case T_WSS: socket_type = SOCK_STREAM; protocol = IPPROTO_TCP; break; @@ -1505,9 +1787,9 @@ int SIPpSocket::connect(struct sockaddr_storage* dest) int ret; - assert(ss_transport == T_TCP || ss_transport == T_TLS || ss_transport == T_SCTP); + assert(ss_transport == T_TCP || ss_transport == T_TLS || ss_transport == T_SCTP || ss_transport == T_WSS); - if (ss_transport == T_TCP || ss_transport == T_TLS) { + if (ss_transport == T_TCP || ss_transport == T_TLS || ss_transport == T_WSS) { struct sockaddr_storage with_optional_port; int port = -1; memcpy(&with_optional_port, &local_sockaddr, sizeof(struct sockaddr_storage)); @@ -1571,10 +1853,53 @@ int SIPpSocket::connect(struct sockaddr_storage* dest) } #endif +#ifdef USE_WSS + if (ss_transport == T_WSS) + { + if (!lws_context) init_lws_context(); + lws_client_connect_info ccinfo = {0}; + + // Create WS cnx from socket FD + lws * wsi_temp = lws_adopt_socket_vhost(lws_vh, ss_fd); + if (!wsi_temp) + { + ERROR("Failed to create the WSS connection from fd %d.", ss_fd); + return -1; + } + + // Enlarge inactivity timeout of unused wsi_temp to 2 days + lws_set_timeout(wsi_temp, NO_PENDING_TIMEOUT, 48*3600); + memset(&ccinfo, 0, sizeof(ccinfo)); + ccinfo.context = lws_context; + ccinfo.vhost = lws_vh; + ccinfo.port = 443; // Need to be set but is not used + ccinfo.address = remote_ip; + ccinfo.path = "/"; + ccinfo.host = remote_host; + ccinfo.origin = "sipp-ws-endpoint"; + ccinfo.protocol = "sip"; + ccinfo.parent_wsi = wsi_temp; + ccinfo.ssl_connection = LCCSCF_USE_SSL; + + wsi = lws_client_connect_via_info(&ccinfo); + lws_set_wsi_user(wsi, this); + if (!wsi) { + ERROR("Failed to establish WS connection"); + return -2; + } + + lws_callback_on_writable(wsi); + while (!wss_connected && wsi) { + lws_service(lws_context, -1); + } + if (!wsi) { + return -3; + } + } +#endif return 0; } - int SIPpSocket::reconnect() { if ((!ss_invalid) && @@ -1725,7 +2050,7 @@ void sipp_customize_socket(SIPpSocket *socket) /* Allows fast TCP reuse of the socket */ if (socket->ss_transport == T_TCP || socket->ss_transport == T_TLS || - socket->ss_transport == T_SCTP) { + socket->ss_transport == T_SCTP || socket->ss_transport == T_WSS) { int sock_opt = 1; if (setsockopt(socket->ss_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt, @@ -2148,6 +2473,27 @@ ssize_t SIPpSocket::write_primitive(const char* buffer, size_t len, socklen_from_addr(dest)); break; +#ifdef USE_WSS + case T_WSS: + if (wsi) { + if (!wss_out) { + wss_out = alloc_socketbuf((char *) buffer, len, 1, nullptr); + wss_out->next = nullptr; + lws_callback_on_writable(wsi); + rc = len; + } + else { + errno = EWOULDBLOCK; + rc = 0; + } + } + else { + rc = -2; + errno = EPIPE; + } + break; +#endif + default: ERROR("Internal error, unknown transport type %d", ss_transport); } @@ -2195,6 +2541,18 @@ int SIPpSocket::write(const char *buffer, ssize_t len, int flags, struct sockadd if (rc < 0) { if ((errno == EWOULDBLOCK) && (flags & WS_BUFFER)) { buffer_write(buffer, len, dest); +#ifdef USE_WSS + if (ss_transport == T_WSS) { + if (wsi) + { + lws_callback_on_writable(wsi); + } + else + { + ERROR("No websocket connection"); + } + } +#endif return len; } else { return rc; @@ -2573,7 +2931,7 @@ int open_connections() } } - if ((!multisocket) && (transport == T_TCP || transport == T_TLS || transport == T_SCTP) && + if ((!multisocket) && (transport == T_TCP || transport == T_TLS || transport == T_SCTP || transport == T_WSS) && (sendMode != MODE_SERVER)) { if ((tcp_multiplex = new_sipp_socket(local_ip_is_ipv6, transport)) == nullptr) { ERROR_NO("Unable to get a TCP socket"); @@ -2860,6 +3218,7 @@ void SIPpSocket::pollset_process(int wait) } loops--; } + read_index = (read_index + 1) % pollnfds; } @@ -2868,6 +3227,8 @@ void SIPpSocket::pollset_process(int wait) return; } #endif + + /* Get socket events. */ #ifdef HAVE_EPOLL /* Ignore the wait parameter and always wait - when establishing TCP @@ -2895,6 +3256,7 @@ void SIPpSocket::pollset_process(int wait) assert(sock); + #ifdef HAVE_EPOLL if (epollevents[event_idx].events & EPOLLOUT) { #else @@ -2924,11 +3286,28 @@ void SIPpSocket::pollset_process(int wait) } } + #ifdef HAVE_EPOLL if (epollevents[event_idx].events & EPOLLIN) { #else if (pollfiles[poll_idx].revents & POLLIN) { #endif + +#ifdef USE_WSS + if (sock->ss_transport == T_WSS && lws_context) { +#ifdef HAVE_EPOLL + int revents = 0; + if (epollevents[event_idx].events & EPOLLIN) revents |= POLLIN; + if (epollevents[event_idx].events & EPOLLOUT) revents |= POLLOUT; + if (epollevents[event_idx].events & EPOLLERR) revents |= POLLERR; +#else + int revents = pollfiles[poll_idx].revents; +#endif + sock->wss_event_loop(revents); + } +#endif + + /* We can empty this socket. */ if ((transport == T_TCP || transport == T_TLS || transport == T_SCTP) && sock == main_socket) { SIPpSocket *new_sock = sock->accept(); @@ -3034,6 +3413,12 @@ void SIPpSocket::pollset_process(int wait) } pollfiles[poll_idx].revents = 0; #endif + +#ifdef USE_WSS + if (lws_context) { + lws_service(lws_context, -1); // LWS "tick" to handler internal timers + } +#endif } #ifndef HAVE_EPOLL