int main(int argc, char** argv) { Synapsis *wsI = new Synapsis(); wsI->connect("127.0.0.1",9002); while (1) { lws_service(wsI->context, 50); } return 0; }
int main(void) { /*server url will usd port 5000*/ int port = 5000; const char *interface = NULL; struct lws_context_creation_info info; struct lws_protocols protocol; struct lws_context *context; /*Not using ssl*/ const char *cert_path = NULL; const char *key_path = NULL; /*no special options*/ int opts = 0; /* register the signal SIGINT handler */ struct sigaction act; act.sa_handler = INT_HANDLER; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction( SIGINT, &act, 0); /* setup websocket protocol */ protocol.name = "my-echo-protocol"; protocol.callback = ws_service_callback; protocol.per_session_data_size=sizeof(struct per_session_data); protocol.rx_buffer_size = 0; /* setup websocket context info*/ memset(&info, 0, sizeof info); info.port = port; info.iface = interface; info.protocols = &protocol; info.extensions = lws_get_internal_extensions(); info.ssl_cert_filepath = cert_path; info.ssl_private_key_filepath = key_path; info.gid = -1; info.uid = -1; info.options = opts; /* create libwebsocket context. */ context = lws_create_context(&info); if (context == NULL) { printf(KRED"[Main] Websocket context create error.\n"RESET); return -1; } printf(KGRN"[Main] Websocket context create success.\n"RESET); /* websocket service */ while ( !destroy_flag ) { lws_service(context, 50); } usleep(10); lws_context_destroy(context); return 0; }
bool FJavascriptWebSocketServer::Tick() { if (IsAlive) { lws_service(Context, 0); lws_callback_on_writable_all_protocol(Context, &Protocols[0]); } return true; }
int main(int argc, const char **argv) { struct lws_context_creation_info info; const char *p, *plugin_dirs[] = { "/usr/local/share/libwebsockets-test-server/plugins", NULL }; int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE /* for LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ /* | LLL_DEBUG */; if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL); lwsl_user("LWS minimal http server TLS | visit https://localhost:7681\n"); signal(SIGINT, sigint_handler); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.port = 7681; info.mounts = &mount; info.error_document_404 = "/404.html"; info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | LWS_SERVER_OPTION_EXPLICIT_VHOSTS; info.ssl_cert_filepath = "localhost-100y.cert"; info.ssl_private_key_filepath = "localhost-100y.key"; info.plugin_dirs = plugin_dirs; info.pvo = &pvo; if (lws_cmdline_option(argc, argv, "-h")) info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK; context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); return 1; } info.headers = &pvo_hsbph[3]; if (!lws_create_vhost(context, &info)) { lwsl_err("lws init failed\n"); return 1; } while (n >= 0 && !interrupted) n = lws_service(context, 1000); lws_context_destroy(context); return 0; }
bool FLwsWebSocket::Tick(float DeltaTime) { if (LwsContext != nullptr) { // Hold on to a reference to this object, so we will not get destroyed while executing lws_service TSharedPtr<FLwsWebSocket> Keep = SharedThis(this); lws_service(LwsContext, 0); } return true; }
bool FWebSocketServer::Tick() { #if !PLATFORM_HTML5 if (IsAlive) { lws_service(Context, 0); lws_callback_on_writable_all_protocol(Context, &Protocols[0]); } #endif return true; }
void* WebSocketTcpServer::__websocket_thread__(void *arg) { LOG_DEBUG("\n"); WebSocketTcpServer *server = static_cast<WebSocketTcpServer*>(arg); server->m_run_thread = true; while ( server->m_run_thread ) { lws_service(server->m_context, 50); } return nullptr; }
void Webserver::worker(void *) { // server url will be ws://localhost:9000 const char *interface = NULL; struct lws_context *context = NULL; // we're not using ssl const char *cert_path = NULL; const char *key_path = NULL; //lws_set_log_level(7, lwsl_emit_syslog); //lws_set_log_level(1, lwsl_emit_syslog); // no special options int opts = 0; // create connection struct struct lws_context_creation_info info; memset(&info, 0, sizeof info); info.port = Webserver::instance()->getPort(); info.iface = interface; info.protocols = protocols; info.extensions = NULL; info.ssl_cert_filepath = cert_path; info.ssl_private_key_filepath = key_path; info.options = opts; info.gid = -1; info.uid = -1; // create libwebsocket context representing this server context = lws_create_context(&info); // make sure it starts if (context == NULL) { Webserver::instance()->mRunning = false; fprintf(stderr, "libwebsocket init failed\n"); return; } printf("starting server...\n"); // infinite loop, to end this server send SIGTERM. (CTRL+C) while (Webserver::instance()->mRunning.load()) { lws_service(context, Webserver::instance()->getTimeout()); //5 ms -> 200 samples / s //lws_service(context, 50); } lws_context_destroy(context); return; }
int main (int argc, char **argv) { int port = 9000; struct lws_context_creation_info context_info = { .port = port, .iface = NULL, .protocols = protocols, .ssl_cert_filepath = NULL, .ssl_private_key_filepath = NULL, .ssl_ca_filepath = NULL, .gid = -1, .uid = -1, .max_http_header_pool = 1, .options = 0, }; // create lws context representing this server context = lws_create_context(&context_info); if (context == NULL) { puts("lws init failed\n"); return -1; } signal(SIGINT, signal_callback_handler); // Setup child reaping handler struct sigaction sa; sa.sa_handler = &handle_sigchld; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; if (sigaction(SIGCHLD, &sa, 0) == -1) { perror(0); exit(1); } printf("starting server...\n"); while (true) { lws_service(context, 10); // ms //lws_callback_on_writable_all_protocol(context, &protocols[1]); usleep(1000); } lws_context_destroy(context); return 0; }
int main(int argc, const char **argv) { struct lws_context_creation_info info; struct lws_context *context; const char *p; int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE /* for LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ /* | LLL_DEBUG */; signal(SIGINT, sigint_handler); if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL); lwsl_user("LWS minimal raw file\n"); if (argc < 2) { lwsl_user("Usage: %s <file to monitor> " " eg, /dev/ttyUSB0 or /dev/input/event0 or " "/proc/self/fd/0\n", argv[0]); return 1; } signal(SIGINT, sigint_handler); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.port = CONTEXT_PORT_NO_LISTEN_SERVER; /* no listen socket for demo */ info.protocols = protocols; lws_strncpy(filepath, argv[1], sizeof(filepath)); context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); return 1; } while (n >= 0 && !interrupted) n = lws_service(context, 1000); lws_context_destroy(context); return 0; }
int main(int argc, const char **argv) { struct lws_context_creation_info info; struct lws_context *context; const char *p; int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE /* for LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ /* | LLL_DEBUG */; signal(SIGINT, sigint_handler); if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL); lwsl_user("LWS minimal ws client + permessage-deflate + multifragment bulk message\n"); lwsl_user(" needs minimal-ws-server-pmd-bulk running to communicate with\n"); lwsl_user(" %s [-n (no exts)] [-c (compressible)]\n", argv[0]); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = protocols; info.pvo = &pvo; if (!lws_cmdline_option(argc, argv, "-n")) info.extensions = extensions; info.pt_serv_buf_size = 32 * 1024; if (lws_cmdline_option(argc, argv, "-c")) options |= 1; context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); return 1; } while (n >= 0 && !interrupted) n = lws_service(context, 1000); lws_context_destroy(context); lwsl_user("Completed %s\n", interrupted == 2 ? "OK" : "failed"); return interrupted != 2; }
void * ps_websockets_thread (void * data) { struct lws_context * service = (struct lws_context *)data; if (service == NULL) { PS_LOG (LOG_ERR,"Invalid service\n"); return NULL; } while (g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) { lws_service (service, 50); } //lws_context_destroy(service); PS_LOG (LOG_INFO,"ps_websockets_thread: thread ended\n"); return NULL; }
static gboolean discord_ws_service_loop(gpointer data, gint fd, b_input_condition cond) { struct im_connection *ic = data; discord_data *dd = ic->proto_data; lws_service(dd->lwsctx, 0); if (dd->state == WS_CLOSING) { imc_logout(ic, TRUE); } return TRUE; }
int main(int argc, const char **argv) { struct lws_context_creation_info info; struct lws_context *context; const char *p; int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE /* for LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ /* | LLL_DEBUG */; signal(SIGINT, sigint_handler); if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL); lwsl_user("LWS minimal http server POST | visit http://localhost:7681\n"); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.port = 7681; info.protocols = protocols; info.mounts = &mount; info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE; if (lws_cmdline_option(argc, argv, "-s")) { info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; info.ssl_cert_filepath = "localhost-100y.cert"; info.ssl_private_key_filepath = "localhost-100y.key"; } context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); return 1; } while (n >= 0 && !interrupted) n = lws_service(context, 1000); lws_context_destroy(context); return 0; }
uint32 FNetworkFileServerHttp::Run() { UE_LOG(LogFileServer, Display, TEXT("Unreal Network File Http Server is ready for client connections on port %d"), Port); // start servicing. // service libwebsocket context. while(!StopRequested.GetValue()) { // service libwebsocket, have a slight delay so it doesn't spin on zero load. lws_service(Context, 10); lws_callback_on_writable_all_protocol(Context, &Protocols[0]); } UE_LOG(LogFileServer, Display, TEXT("Unreal Network File Http Server is now Shutting down ")); return true; }
int main(int argc, const char **argv) { struct lws_context_creation_info info; struct lws_context *context; const char *p; int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE /* for LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ /* | LLL_DEBUG */; signal(SIGINT, sigint_handler); if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL); lwsl_user("LWS minimal ws server + threads | visit http://localhost:7681\n"); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.port = 7681; info.mounts = &mount; info.protocols = protocols; info.pvo = &pvo; /* per-vhost options */ info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE; context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); return 1; } /* start the threads that create content */ while (!interrupted) if (lws_service(context, 1000)) interrupted = 1; lws_context_destroy(context); return 0; }
/** * Main Websockets thread * * @param data pointer to Websockets thread * @return 0 when success, otherwise error number */ int WebsocketThread( FThread *data ) { int cnt = 0; WebSocket *ws = (WebSocket *)data->t_Data; if( ws->ws_Context == NULL ) { FERROR("WsContext is empty\n"); return 0; } DEBUG1("[WS] Websocket thread started\n"); //signal( SIGPIPE, SIG_IGN ); //signal( SIGPIPE, hand ); //lws_set_log_level( LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO | LLL_DEBUG , NULL ); Log( FLOG_INFO, "[WS] Service will be started now\n" ); while( TRUE ) { int n = lws_service( ws->ws_Context, 500 ); if( ws->ws_Quit == TRUE && WSThreadNum <= 0 ) { break; } else if( ws->ws_Quit == TRUE ) { cnt++; if( cnt > 500 ) { Log( FLOG_INFO, "[WS] Service stopping threads: %d\n", WSThreadNum ); cnt = 0; } } } Log( FLOG_INFO, "[WS] Service stopped\n" ); done: data->t_Launched = FALSE; return 0; }
/* Thread */ void *janus_websockets_thread(void *data) { struct lws_context *service = (struct lws_context *)data; if(service == NULL) { JANUS_LOG(LOG_ERR, "Invalid service\n"); return NULL; } JANUS_LOG(LOG_INFO, "WebSockets thread started\n"); while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) { /* libwebsockets is single thread, we cycle through events here */ lws_service(service, 50); } /* Get rid of the WebSockets server */ lws_cancel_service(service); /* Done */ JANUS_LOG(LOG_INFO, "WebSockets thread ended\n"); return NULL; }
int main(int argc, const char **argv) { struct lws_context_creation_info info; struct lws_context *context; const char *p; int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE /* for LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ /* | LLL_DEBUG */; signal(SIGINT, sigint_handler); if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL); lwsl_user("LWS minimal ws client tx\n"); lwsl_user(" Run minimal-ws-broker and browse to that\n"); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ info.protocols = protocols; context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); return 1; } while (n >= 0 && !interrupted) n = lws_service(context, 1000); lws_context_destroy(context); lwsl_user("Completed\n"); return 0; }
void FWebSocket::HandlePacket() { #if !PLATFORM_HTML5 lws_service(Context, 0); if (!IsServerSide) lws_callback_on_writable_all_protocol(Context, &Protocols[0]); #else // PLATFORM_HTML5 fd_set Fdr; fd_set Fdw; int Res; // make sure that server.fd is ready to read / write FD_ZERO(&Fdr); FD_ZERO(&Fdw); FD_SET(SockFd, &Fdr); FD_SET(SockFd, &Fdw); Res = select(64, &Fdr, &Fdw, NULL, NULL); if (Res == -1) { UE_LOG(LogHTML5Networking, Warning, TEXT("Select Failed!")); return; } if (FD_ISSET(SockFd, &Fdr)) { // we can read! OnRawRecieve(NULL, NULL); } if (FD_ISSET(SockFd, &Fdw)) { // we can write OnRawWebSocketWritable(NULL); } #endif }
static int callback_minimal_broker(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct pss *pss = (struct pss *)user; int n; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: goto try; case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in : "(null)"); client_wsi = NULL; lws_timed_callback_vh_protocol(lws_get_vhost(wsi), lws_get_protocol(wsi), LWS_CALLBACK_USER, 1); break; /* --- client callbacks --- */ case LWS_CALLBACK_CLIENT_ESTABLISHED: lwsl_user("%s: established\n", __func__); lws_set_timer_usecs(wsi, 5 * LWS_USEC_PER_SEC); break; case LWS_CALLBACK_CLIENT_WRITEABLE: if (pss->send_a_ping) { uint8_t ping[LWS_PRE + 125]; int m; pss->send_a_ping = 0; n = 0; if (!zero_length_ping) n = lws_snprintf((char *)ping + LWS_PRE, 125, "ping body!"); lwsl_user("Sending PING %d...\n", n); m = lws_write(wsi, ping + LWS_PRE, n, LWS_WRITE_PING); if (m < n) { lwsl_err("sending ping failed: %d\n", m); return -1; } lws_callback_on_writable(wsi); } break; case LWS_CALLBACK_WS_CLIENT_DROP_PROTOCOL: client_wsi = NULL; lws_timed_callback_vh_protocol(lws_get_vhost(wsi), lws_get_protocol(wsi), LWS_CALLBACK_USER, 1); break; case LWS_CALLBACK_CLIENT_RECEIVE_PONG: lwsl_user("LWS_CALLBACK_CLIENT_RECEIVE_PONG\n"); lwsl_hexdump_notice(in, len); break; case LWS_CALLBACK_TIMER: /* we want to send a ws PING every few seconds */ pss->send_a_ping = 1; lws_callback_on_writable(wsi); lws_set_timer_usecs(wsi, 5 * LWS_USEC_PER_SEC); break; /* rate-limited client connect retries */ case LWS_CALLBACK_USER: lwsl_notice("%s: LWS_CALLBACK_USER\n", __func__); try: if (connect_client()) lws_timed_callback_vh_protocol(lws_get_vhost(wsi), lws_get_protocol(wsi), LWS_CALLBACK_USER, 1); break; default: break; } return lws_callback_http_dummy(wsi, reason, user, in, len); } static const struct lws_protocols protocols[] = { { "lws-ping-test", callback_minimal_broker, sizeof(struct pss), 0, }, { NULL, NULL, 0, 0 } }; static void sigint_handler(int sig) { interrupted = 1; } int main(int argc, const char **argv) { struct lws_context_creation_info info; const char *p; int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE /* for LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ /* | LLL_DEBUG */; signal(SIGINT, sigint_handler); if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL); lwsl_user("LWS minimal ws client PING\n"); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ info.protocols = protocols; #if defined(LWS_WITH_MBEDTLS) /* * OpenSSL uses the system trust store. mbedTLS has to be told which * CA to trust explicitly. */ info.client_ssl_ca_filepath = "./libwebsockets.org.cer"; #endif if (lws_cmdline_option(argc, argv, "-z")) zero_length_ping = 1; if ((p = lws_cmdline_option(argc, argv, "--protocol"))) pro = p; if ((p = lws_cmdline_option(argc, argv, "--server"))) { server_address = p; pro = "lws-minimal"; ssl_connection |= LCCSCF_ALLOW_SELFSIGNED; } if ((p = lws_cmdline_option(argc, argv, "--port"))) port = atoi(p); /* * since we know this lws context is only ever going to be used with * one client wsis / fds / sockets at a time, let lws know it doesn't * have to use the default allocations for fd tables up to ulimit -n. * It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we * will use. */ info.fd_limit_per_thread = 1 + 1 + 1; context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); return 1; } while (n >= 0 && !interrupted) n = lws_service(context, 1000); lws_context_destroy(context); lwsl_user("Completed\n"); return 0; }
int main(int argc, const char **argv) { struct lws_context_creation_info info; struct lws_context *context; const char *p; int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE /* for LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ /* | LLL_DEBUG */; if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL); lwsl_user("LWS minimal http server-multivhost | visit http://localhost:7681 / 7682\n"); signal(SIGINT, sigint_handler); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS | LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE; /* * Because of LWS_SERVER_OPTION_EXPLICIT_VHOSTS, this only creates * the context and no longer creates a default vhost */ context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); return 1; } /* it's our job now to create the vhosts we want: * * - "localhost1" listen on 7681 and serve ./mount-origin-localhost1/ * - "localhost2" listen on 7682 and serve ./mount-origin-localhost2/ * - "localhost3" share 7682 and serve ./mount-origin-localhost3/ * * Note lws supports dynamic vhost creation and destruction at runtime. * When using multi-vhost with your own protocols, you must provide a * pvo for each vhost naming each protocol you want enabled on it. * minimal-ws-server-threads demonstrates how to provide pvos. */ info.port = 7681; info.mounts = &mount_localhost1; info.error_document_404 = "/404.html"; info.vhost_name = "localhost1"; if (!lws_create_vhost(context, &info)) { lwsl_err("Failed to create first vhost\n"); goto bail; } info.port = 7682; info.mounts = &mount_localhost2; info.error_document_404 = "/404.html"; info.vhost_name = "localhost2"; if (!lws_create_vhost(context, &info)) { lwsl_err("Failed to create second vhost\n"); goto bail; } /* a second vhost listens on port 7682 */ info.mounts = &mount_localhost3; info.error_document_404 = "/404.html"; info.vhost_name = "localhost3"; info.finalize = vh_destruction_notification; info.finalize_arg = NULL; if (!lws_create_vhost(context, &info)) { lwsl_err("Failed to create third vhost\n"); goto bail; } if (lws_cmdline_option(argc, argv, "--die-after-vhost")) { lwsl_warn("bailing after creating vhosts\n"); goto bail; } while (n >= 0 && !interrupted) n = lws_service(context, 1000); bail: lws_context_destroy(context); return 0; }
int janus_websockets_send_message(void *transport, void *request_id, gboolean admin, json_t *message) { if(message == NULL) return -1; if(transport == NULL) { json_decref(message); return -1; } /* Make sure this is not related to a closed /freed WebSocket session */ janus_mutex_lock(&old_wss_mutex); janus_websockets_client *client = (janus_websockets_client *)transport; #ifdef HAVE_LIBWEBSOCKETS_NEWAPI if(g_list_find(old_wss, client) != NULL || !client->wsi) { #else if(g_list_find(old_wss, client) != NULL || !client->context || !client->wsi) { #endif json_decref(message); message = NULL; transport = NULL; janus_mutex_unlock(&old_wss_mutex); return -1; } janus_mutex_lock(&client->mutex); /* Convert to string and enqueue */ char *payload = json_dumps(message, json_format); g_async_queue_push(client->messages, payload); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(client->wsi); #else libwebsocket_callback_on_writable(client->context, client->wsi); #endif janus_mutex_unlock(&client->mutex); janus_mutex_unlock(&old_wss_mutex); json_decref(message); return 0; } void janus_websockets_session_created(void *transport, guint64 session_id) { /* We don't care */ } void janus_websockets_session_over(void *transport, guint64 session_id, gboolean timeout) { if(transport == NULL || !timeout) return; /* We only care if it's a timeout: if so, close the connection */ janus_websockets_client *client = (janus_websockets_client *)transport; /* Make sure this is not related to a closed WebSocket session */ janus_mutex_lock(&old_wss_mutex); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI if(g_list_find(old_wss, client) == NULL && client->wsi){ #else if(g_list_find(old_wss, client) == NULL && client->context && client->wsi){ #endif janus_mutex_lock(&client->mutex); client->session_timeout = 1; #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(client->wsi); #else libwebsocket_callback_on_writable(client->context, client->wsi); #endif janus_mutex_unlock(&client->mutex); } janus_mutex_unlock(&old_wss_mutex); } /* Thread */ void *janus_websockets_thread(void *data) { #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws_context *service = (struct lws_context *)data; #else struct libwebsocket_context *service = (struct libwebsocket_context *)data; #endif if(service == NULL) { JANUS_LOG(LOG_ERR, "Invalid service\n"); return NULL; } const char *type = NULL; if(service == wss) type = "WebSocket (Janus API)"; else if(service == swss) type = "Secure WebSocket (Janus API)"; else if(service == admin_wss) type = "WebSocket (Admin API)"; else if(service == admin_swss) type = "Secure WebSocket (Admin API)"; JANUS_LOG(LOG_INFO, "%s thread started\n", type); while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) { /* libwebsockets is single thread, we cycle through events here */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_service(service, 50); #else libwebsocket_service(service, 50); #endif } /* Get rid of the WebSockets server */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_cancel_service(service); #else libwebsocket_cancel_service(service); #endif /* Done */ JANUS_LOG(LOG_INFO, "%s thread ended\n", type); return NULL; } /* WebSockets */ static int janus_websockets_callback_http( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { /* This endpoint cannot be used for HTTP */ switch(reason) { case LWS_CALLBACK_HTTP: JANUS_LOG(LOG_VERB, "Rejecting incoming HTTP request on WebSockets endpoint\n"); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_return_http_status(wsi, 403, NULL); #else libwebsockets_return_http_status(this, wsi, 403, NULL); #endif /* Close and free connection */ return -1; case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: if (!in) { JANUS_LOG(LOG_VERB, "Rejecting incoming HTTP request on WebSockets endpoint: no sub-protocol specified\n"); return -1; } break; default: break; } return 0; } static int janus_websockets_callback_https( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { /* We just forward the event to the HTTP handler */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI return janus_websockets_callback_http(wsi, reason, user, in, len); #else return janus_websockets_callback_http(this, wsi, reason, user, in, len); #endif } /* This callback handles Janus API requests */ static int janus_websockets_common_callback( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len, gboolean admin) { const char *log_prefix = admin ? "AdminWSS" : "WSS"; janus_websockets_client *ws_client = (janus_websockets_client *)user; switch(reason) { case LWS_CALLBACK_ESTABLISHED: { /* Is there any filtering we should apply? */ char name[256], ip[256]; #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, 256, ip, 256); #else libwebsockets_get_peer_addresses(this, wsi, libwebsocket_get_socket_fd(wsi), name, 256, ip, 256); #endif JANUS_LOG(LOG_VERB, "[%s-%p] WebSocket connection opened from %s by %s\n", log_prefix, wsi, ip, name); if(!janus_websockets_is_allowed(ip, admin)) { JANUS_LOG(LOG_ERR, "[%s-%p] IP %s is unauthorized to connect to the WebSockets %s API interface\n", log_prefix, wsi, ip, admin ? "Admin" : "Janus"); /* Close the connection */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(wsi); #else libwebsocket_callback_on_writable(this, wsi); #endif return -1; } JANUS_LOG(LOG_VERB, "[%s-%p] WebSocket connection accepted\n", log_prefix, wsi); if(ws_client == NULL) { JANUS_LOG(LOG_ERR, "[%s-%p] Invalid WebSocket client instance...\n", log_prefix, wsi); return -1; } /* Clean the old sessions list, in case this pointer was used before */ janus_mutex_lock(&old_wss_mutex); if(g_list_find(old_wss, ws_client) != NULL) old_wss = g_list_remove(old_wss, ws_client); janus_mutex_unlock(&old_wss_mutex); /* Prepare the session */ #ifndef HAVE_LIBWEBSOCKETS_NEWAPI ws_client->context = this; #endif ws_client->wsi = wsi; ws_client->messages = g_async_queue_new(); ws_client->buffer = NULL; ws_client->buflen = 0; ws_client->bufpending = 0; ws_client->bufoffset = 0; ws_client->session_timeout = 0; ws_client->destroy = 0; janus_mutex_init(&ws_client->mutex); /* Let us know when the WebSocket channel becomes writeable */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(wsi); #else libwebsocket_callback_on_writable(this, wsi); #endif JANUS_LOG(LOG_VERB, "[%s-%p] -- Ready to be used!\n", log_prefix, wsi); /* Notify handlers about this new transport */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("connected")); json_object_set_new(info, "admin_api", admin ? json_true() : json_false()); json_object_set_new(info, "ip", json_string(ip)); gateway->notify_event(&janus_websockets_transport, ws_client, info); } return 0; } case LWS_CALLBACK_RECEIVE: { JANUS_LOG(LOG_HUGE, "[%s-%p] Got %zu bytes:\n", log_prefix, wsi, len); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI if(ws_client == NULL || ws_client->wsi == NULL) { #else if(ws_client == NULL || ws_client->context == NULL || ws_client->wsi == NULL) { #endif JANUS_LOG(LOG_ERR, "[%s-%p] Invalid WebSocket client instance...\n", log_prefix, wsi); return -1; } /* Is this a new message, or part of a fragmented one? */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI const size_t remaining = lws_remaining_packet_payload(wsi); #else const size_t remaining = libwebsockets_remaining_packet_payload(wsi); #endif if(ws_client->incoming == NULL) { JANUS_LOG(LOG_HUGE, "[%s-%p] First fragment: %zu bytes, %zu remaining\n", log_prefix, wsi, len, remaining); ws_client->incoming = g_malloc0(len+1); memcpy(ws_client->incoming, in, len); ws_client->incoming[len] = '\0'; JANUS_LOG(LOG_HUGE, "%s\n", ws_client->incoming); } else { size_t offset = strlen(ws_client->incoming); JANUS_LOG(LOG_HUGE, "[%s-%p] Appending fragment: offset %zu, %zu bytes, %zu remaining\n", log_prefix, wsi, offset, len, remaining); ws_client->incoming = g_realloc(ws_client->incoming, offset+len+1); memcpy(ws_client->incoming+offset, in, len); ws_client->incoming[offset+len] = '\0'; JANUS_LOG(LOG_HUGE, "%s\n", ws_client->incoming+offset); } #ifdef HAVE_LIBWEBSOCKETS_NEWAPI if(remaining > 0 || !lws_is_final_fragment(wsi)) { #else if(remaining > 0 || !libwebsocket_is_final_fragment(wsi)) { #endif /* Still waiting for some more fragments */ JANUS_LOG(LOG_HUGE, "[%s-%p] Waiting for more fragments\n", log_prefix, wsi); return 0; } JANUS_LOG(LOG_HUGE, "[%s-%p] Done, parsing message: %zu bytes\n", log_prefix, wsi, strlen(ws_client->incoming)); /* If we got here, the message is complete: parse the JSON payload */ json_error_t error; json_t *root = json_loads(ws_client->incoming, 0, &error); g_free(ws_client->incoming); ws_client->incoming = NULL; /* Notify the core, passing both the object and, since it may be needed, the error */ gateway->incoming_request(&janus_websockets_transport, ws_client, NULL, admin, root, &error); return 0; } case LWS_CALLBACK_SERVER_WRITEABLE: { #ifdef HAVE_LIBWEBSOCKETS_NEWAPI if(ws_client == NULL || ws_client->wsi == NULL) { #else if(ws_client == NULL || ws_client->context == NULL || ws_client->wsi == NULL) { #endif JANUS_LOG(LOG_ERR, "[%s-%p] Invalid WebSocket client instance...\n", log_prefix, wsi); return -1; } if(!ws_client->destroy && !g_atomic_int_get(&stopping)) { janus_mutex_lock(&ws_client->mutex); /* Check if we have a pending/partial write to complete first */ if(ws_client->buffer && ws_client->bufpending > 0 && ws_client->bufoffset > 0 && !ws_client->destroy && !g_atomic_int_get(&stopping)) { JANUS_LOG(LOG_HUGE, "[%s-%p] Completing pending WebSocket write (still need to write last %d bytes)...\n", log_prefix, wsi, ws_client->bufpending); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI int sent = lws_write(wsi, ws_client->buffer + ws_client->bufoffset, ws_client->bufpending, LWS_WRITE_TEXT); #else int sent = libwebsocket_write(wsi, ws_client->buffer + ws_client->bufoffset, ws_client->bufpending, LWS_WRITE_TEXT); #endif JANUS_LOG(LOG_HUGE, "[%s-%p] -- Sent %d/%d bytes\n", log_prefix, wsi, sent, ws_client->bufpending); if(sent > -1 && sent < ws_client->bufpending) { /* We still couldn't send everything that was left, we'll try and complete this in the next round */ ws_client->bufpending -= sent; ws_client->bufoffset += sent; } else { /* Clear the pending/partial write queue */ ws_client->bufpending = 0; ws_client->bufoffset = 0; } /* Done for this round, check the next response/notification later */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(wsi); #else libwebsocket_callback_on_writable(this, wsi); #endif janus_mutex_unlock(&ws_client->mutex); return 0; } /* Shoot all the pending messages */ char *response = g_async_queue_try_pop(ws_client->messages); if(response && !ws_client->destroy && !g_atomic_int_get(&stopping)) { /* Gotcha! */ int buflen = LWS_SEND_BUFFER_PRE_PADDING + strlen(response) + LWS_SEND_BUFFER_POST_PADDING; if(ws_client->buffer == NULL) { /* Let's allocate a shared buffer */ JANUS_LOG(LOG_HUGE, "[%s-%p] Allocating %d bytes (response is %zu bytes)\n", log_prefix, wsi, buflen, strlen(response)); ws_client->buflen = buflen; ws_client->buffer = g_malloc0(buflen); } else if(buflen > ws_client->buflen) { /* We need a larger shared buffer */ JANUS_LOG(LOG_HUGE, "[%s-%p] Re-allocating to %d bytes (was %d, response is %zu bytes)\n", log_prefix, wsi, buflen, ws_client->buflen, strlen(response)); ws_client->buflen = buflen; ws_client->buffer = g_realloc(ws_client->buffer, buflen); } memcpy(ws_client->buffer + LWS_SEND_BUFFER_PRE_PADDING, response, strlen(response)); JANUS_LOG(LOG_HUGE, "[%s-%p] Sending WebSocket message (%zu bytes)...\n", log_prefix, wsi, strlen(response)); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI int sent = lws_write(wsi, ws_client->buffer + LWS_SEND_BUFFER_PRE_PADDING, strlen(response), LWS_WRITE_TEXT); #else int sent = libwebsocket_write(wsi, ws_client->buffer + LWS_SEND_BUFFER_PRE_PADDING, strlen(response), LWS_WRITE_TEXT); #endif JANUS_LOG(LOG_HUGE, "[%s-%p] -- Sent %d/%zu bytes\n", log_prefix, wsi, sent, strlen(response)); if(sent > -1 && sent < (int)strlen(response)) { /* We couldn't send everything in a single write, we'll complete this in the next round */ ws_client->bufpending = strlen(response) - sent; ws_client->bufoffset = LWS_SEND_BUFFER_PRE_PADDING + sent; JANUS_LOG(LOG_HUGE, "[%s-%p] -- Couldn't write all bytes (%d missing), setting offset %d\n", log_prefix, wsi, ws_client->bufpending, ws_client->bufoffset); } /* We can get rid of the message */ free(response); /* Done for this round, check the next response/notification later */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(wsi); #else libwebsocket_callback_on_writable(this, wsi); #endif janus_mutex_unlock(&ws_client->mutex); return 0; } janus_mutex_unlock(&ws_client->mutex); } return 0; } case LWS_CALLBACK_CLOSED: { JANUS_LOG(LOG_VERB, "[%s-%p] WS connection down, closing\n", log_prefix, wsi); janus_websockets_destroy_client(ws_client, wsi, log_prefix); JANUS_LOG(LOG_VERB, "[%s-%p] -- closed\n", log_prefix, wsi); return 0; } case LWS_CALLBACK_WSI_DESTROY: { JANUS_LOG(LOG_VERB, "[%s-%p] WS connection down, destroying\n", log_prefix, wsi); janus_websockets_destroy_client(ws_client, wsi, log_prefix); JANUS_LOG(LOG_VERB, "[%s-%p] -- destroyed\n", log_prefix, wsi); return 0; } default: if(wsi != NULL) { JANUS_LOG(LOG_HUGE, "[%s-%p] %d (%s)\n", log_prefix, wsi, reason, janus_websockets_reason_string(reason)); } else { JANUS_LOG(LOG_HUGE, "[%s] %d (%s)\n", log_prefix, reason, janus_websockets_reason_string(reason)); } break; } return 0; } /* This callback handles Janus API requests */ static int janus_websockets_callback( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { #ifdef HAVE_LIBWEBSOCKETS_NEWAPI return janus_websockets_common_callback(wsi, reason, user, in, len, FALSE); #else return janus_websockets_common_callback(this, wsi, reason, user, in, len, FALSE); #endif } static int janus_websockets_callback_secure( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { /* We just forward the event to the Janus API handler */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI return janus_websockets_callback(wsi, reason, user, in, len); #else return janus_websockets_callback(this, wsi, reason, user, in, len); #endif } /* This callback handles Admin API requests */ static int janus_websockets_admin_callback( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { #ifdef HAVE_LIBWEBSOCKETS_NEWAPI return janus_websockets_common_callback(wsi, reason, user, in, len, TRUE); #else return janus_websockets_common_callback(this, wsi, reason, user, in, len, TRUE); #endif } static int janus_websockets_admin_callback_secure( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { /* We just forward the event to the Admin API handler */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI return janus_websockets_admin_callback(wsi, reason, user, in, len); #else return janus_websockets_admin_callback(this, wsi, reason, user, in, len); #endif }
int main(int argc, const char **argv) { struct lws_context_creation_info info; struct lws_context *context; const char *p; int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE /* for LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ /* | LLL_DEBUG */; signal(SIGINT, sigint_handler); if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL); lwsl_user("LWS minimal http server dynamic | visit http://localhost:7681\n"); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | LWS_SERVER_OPTION_EXPLICIT_VHOSTS; /* for testing ah queue, not useful in real world */ if (lws_cmdline_option(argc, argv, "--ah1")) info.max_http_header_pool = 1; context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); return 1; } /* http on 7681 */ info.port = 7681; info.protocols = protocols; info.mounts = &mount; info.vhost_name = "http"; if (!lws_create_vhost(context, &info)) { lwsl_err("Failed to create tls vhost\n"); goto bail; } /* https on 7682 */ info.port = 7682; info.error_document_404 = "/404.html"; info.ssl_cert_filepath = "localhost-100y.cert"; info.ssl_private_key_filepath = "localhost-100y.key"; info.vhost_name = "localhost"; if (!lws_create_vhost(context, &info)) { lwsl_err("Failed to create tls vhost\n"); goto bail; } while (n >= 0 && !interrupted) n = lws_service(context, 1000); bail: lws_context_destroy(context); return 0; }
int main(int argc, char **argv) { daemonize(); //saveData("admin",100,100,"admin"); config_obj=parseConfigFile(); ipWhitelist = cJSON_GetObjectItem(config_obj,"ipWhitelist"); wiringPiSetup(); pinDirections = cJSON_GetObjectItem(config_obj,"pinDirections"); handlePinsDirection(pinDirections); signal(SIGINT, sighandler); struct lws_context_creation_info info; unsigned int ms, oldms= 0; const char *iface = NULL; char cert_path[1024]; char key_path[1024]; int use_ssl = 0; int opts = 0; int n = 0; /* * take care to zero down the info struct, he contains random garbaage * from the stack otherwise */ memset(&info, 0, sizeof info); info.port = 7681; signal(SIGINT, sighandler); info.iface = iface; info.protocols = protocols; info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; if (use_ssl) { if (strlen(resource_path) > sizeof(cert_path) - 32) { lwsl_err("resource path too long\n"); return -1; } sprintf(cert_path, "%s/libwebsockets-test-server.pem", resource_path); if (strlen(resource_path) > sizeof(key_path) - 32) { lwsl_err("resource path too long\n"); return -1; } sprintf(key_path, "%s/libwebsockets-test-server.key.pem", resource_path); info.ssl_cert_filepath = cert_path; info.ssl_private_key_filepath = key_path; } info.gid = -1; info.uid = -1; info.max_http_header_pool = 1; info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8; info.extensions = NULL; context = lws_create_context(&info); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } n = 0; while (n >= 0 && !force_exit) { struct timeval tv; gettimeofday(&tv, NULL); /* * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every * live websocket connection using the DUMB_INCREMENT protocol, * as soon as it can take more packets (usually immediately) */ extern struct ram_usage ram_l; extern struct cpu_live cpu_l; extern struct cpu_freq cpu_freq; if(old_client_count!=client_count){ if(hash){ free(hash); } hash=rand_string(); lws_callback_on_writable_all_protocol(context, &protocols[PROTOCOL_GPIO]); lws_callback_on_writable_all_protocol(context, &protocols[PROTOCOL_DETAILS]); lws_callback_on_writable_all_protocol(context, &protocols[PROTOCOL_SERVICES]); lws_callback_on_writable_all_protocol(context, &protocols[PROTOCOL_HOME]); old_client_count=client_count; } ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); if ((ms - oldms) > 200 && get_client_count()>0 && (cpuLive(&cpu_l,5)==0 && ramLive(&ram_l,5)==0 && cpuLiveFreq(&cpu_freq)==0 )) { lws_callback_on_writable_all_protocol(context, &protocols[PROTOCOL_DETAILS]); oldms = ms; } n = lws_service(context, 50); } lws_context_destroy(context); lwsl_notice("libwebsockets-test-server exited cleanly\n"); return 0; }
int main(int argc, const char **argv) { struct lws_context_creation_info info; struct lws_client_connect_info i; struct lws_context *context; const char *p; int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE /* * For LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE * * | LLL_INFO | LLL_PARSER | LLL_HEADER | LLL_EXT | * LLL_CLIENT | LLL_LATENCY | LLL_DEBUG */ ; signal(SIGINT, sigint_handler); if ((p = lws_cmdline_option(argc, argv, "-d"))) logs = atoi(p); lws_set_log_level(logs, NULL); lwsl_user("LWS minimal http client [-d<verbosity>] [-l] [--h1]\n"); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ info.protocols = protocols; #if defined(LWS_WITH_MBEDTLS) /* * OpenSSL uses the system trust store. mbedTLS has to be told which * CA to trust explicitly. */ info.client_ssl_ca_filepath = "./warmcat.com.cer"; #endif context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); return 1; } memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */ i.context = context; i.ssl_connection = LCCSCF_USE_SSL; if (lws_cmdline_option(argc, argv, "-l")) { i.port = 7681; i.address = "localhost"; i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED; } else { i.port = 443; i.address = "warmcat.com"; } if (lws_cmdline_option(argc, argv, "--h1")) i.alpn = "http/1.1"; i.path = "/"; i.host = i.address; i.origin = i.address; i.method = "GET"; i.protocol = protocols[0].name; i.pwsi = &client_wsi; lws_client_connect_via_info(&i); while (n >= 0 && client_wsi && !interrupted) n = lws_service(context, 1000); lws_context_destroy(context); lwsl_user("Completed: %s\n", bad ? "failed" : "OK"); return bad; }
int main(int argc, char **argv) { struct lws_context_creation_info info; struct lws_vhost *vhost; char interface_name[128] = ""; unsigned int ms, oldms = 0; const char *iface = NULL; char cert_path[1024] = ""; char key_path[1024] = ""; char ca_path[1024] = ""; int uid = -1, gid = -1; int use_ssl = 0; int pp_secs = 0; int opts = 0; int n = 0; #ifndef _WIN32 /* LOG_PERROR is not POSIX standard, and may not be portable */ #ifdef __sun int syslog_options = LOG_PID; #else int syslog_options = LOG_PID | LOG_PERROR; #endif #endif #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif /* * take care to zero down the info struct, he contains random garbaage * from the stack otherwise */ memset(&info, 0, sizeof info); info.port = 7681; while (n >= 0) { n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:P:k", options, NULL); if (n < 0) continue; switch (n) { case 'e': opts |= LWS_SERVER_OPTION_LIBEV; break; #ifndef LWS_NO_DAEMONIZE case 'D': daemonize = 1; #if !defined(_WIN32) && !defined(__sun) syslog_options &= ~LOG_PERROR; #endif break; #endif case 'u': uid = atoi(optarg); break; case 'g': gid = atoi(optarg); break; case 'd': debug_level = atoi(optarg); break; case 's': use_ssl = 1; break; case 'a': opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT; break; case 'p': info.port = atoi(optarg); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; iface = interface_name; break; case 'k': info.bind_iface = 1; #if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP) info.caps[0] = CAP_NET_RAW; info.count_caps = 1; #endif break; case 'c': close_testing = 1; fprintf(stderr, " Close testing mode -- closes on " "client after 50 dumb increments" "and suppresses lws_mirror spam\n"); break; case 'r': resource_path = optarg; printf("Setting resource path to \"%s\"\n", resource_path); break; case 'C': strncpy(cert_path, optarg, sizeof(cert_path) - 1); cert_path[sizeof(cert_path) - 1] = '\0'; break; case 'K': strncpy(key_path, optarg, sizeof(key_path) - 1); key_path[sizeof(key_path) - 1] = '\0'; break; case 'A': strncpy(ca_path, optarg, sizeof(ca_path) - 1); ca_path[sizeof(ca_path) - 1] = '\0'; break; case 'P': pp_secs = atoi(optarg); lwsl_notice("Setting pingpong interval to %d\n", pp_secs); break; #if defined(LWS_OPENSSL_SUPPORT) case 'v': use_ssl = 1; opts |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT; break; #if defined(LWS_HAVE_SSL_CTX_set1_param) case 'R': strncpy(crl_path, optarg, sizeof(crl_path) - 1); crl_path[sizeof(crl_path) - 1] = '\0'; break; #endif #endif case 'h': fprintf(stderr, "Usage: test-server " "[--port=<p>] [--ssl] " "[-d <log bitfield>] " "[--resource_path <path>]\n"); exit(1); } } #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32) /* * normally lock path would be /var/lock/lwsts or similar, to * simplify getting started without having to take care about * permissions or running as root, set to /tmp/.lwsts-lock */ if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) { fprintf(stderr, "Failed to daemonize\n"); return 10; } #endif signal(SIGINT, sighandler); #ifndef _WIN32 /* we will only try to log things according to our debug_level */ setlogmask(LOG_UPTO(LOG_DEBUG)); openlog("lwsts", syslog_options, LOG_DAEMON); #endif /* tell the library what debug level to emit and to send it to syslog */ lws_set_log_level(debug_level, lwsl_emit_syslog); lwsl_notice("libwebsockets test server - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <*****@*****.**>\n"); printf("Using resource path \"%s\"\n", resource_path); #ifdef EXTERNAL_POLL max_poll_elements = getdtablesize(); pollfds = malloc(max_poll_elements * sizeof(struct lws_pollfd)); fd_lookup = malloc(max_poll_elements * sizeof(int)); if (pollfds == NULL || fd_lookup == NULL) { lwsl_err("Out of memory pollfds=%d\n", max_poll_elements); return -1; } #endif info.iface = iface; info.protocols = protocols; info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; info.ws_ping_pong_interval = pp_secs; if (use_ssl) { if (strlen(resource_path) > sizeof(cert_path) - 32) { lwsl_err("resource path too long\n"); return -1; } if (!cert_path[0]) sprintf(cert_path, "%s/libwebsockets-test-server.pem", resource_path); if (strlen(resource_path) > sizeof(key_path) - 32) { lwsl_err("resource path too long\n"); return -1; } if (!key_path[0]) sprintf(key_path, "%s/libwebsockets-test-server.key.pem", resource_path); info.ssl_cert_filepath = cert_path; info.ssl_private_key_filepath = key_path; if (ca_path[0]) info.ssl_ca_filepath = ca_path; } info.gid = gid; info.uid = uid; info.max_http_header_pool = 16; info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8 | LWS_SERVER_OPTION_EXPLICIT_VHOSTS | LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; info.extensions = exts; info.timeout_secs = 5; info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-GCM-SHA384:" "DHE-RSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-SHA384:" "HIGH:!aNULL:!eNULL:!EXPORT:" "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:" "!SHA1:!DHE-RSA-AES128-GCM-SHA256:" "!DHE-RSA-AES128-SHA256:" "!AES128-GCM-SHA256:" "!AES128-SHA256:" "!DHE-RSA-AES256-SHA256:" "!AES256-GCM-SHA384:" "!AES256-SHA256"; if (use_ssl) /* redirect guys coming on http */ info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS; printf("options:%x\r\n", info.options); printf("before create\n"); context = lws_create_context(&info); printf("end create\n"); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } printf("111111\r\n"); vhost = lws_create_vhost(context, &info); if (!vhost) { lwsl_err("vhost creation failed\n"); return -1; } printf("222222\r\n"); #if !defined(LWS_NO_CLIENT) && defined(LWS_OPENSSL_SUPPORT) lws_init_vhost_client_ssl(&info, vhost); #endif /* this shows how to override the lws file operations. You don't need * to do any of this unless you have a reason (eg, want to serve * compressed files without decompressing the whole archive) */ /* stash original platform fops */ fops_plat = *(lws_get_fops(context)); /* override the active fops */ lws_get_fops(context)->open = test_server_fops_open; n = 0; #ifdef EXTERNAL_POLL int ms_1sec = 0; #endif while (n >= 0 && !force_exit) { struct timeval tv; gettimeofday(&tv, NULL); /* * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every * live websocket connection using the DUMB_INCREMENT protocol, * as soon as it can take more packets (usually immediately) */ ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); if ((ms - oldms) > 1) { lws_callback_on_writable_all_protocol(context, &protocols [PROTOCOL_DUMB_INCREMENT]); oldms = ms; } lws_callback_on_writable_all_protocol(context, &protocols [PROTOCOL_FILE_SERVER_SEND]); #ifdef EXTERNAL_POLL /* * this represents an existing server's single poll action * which also includes libwebsocket sockets */ n = poll(pollfds, count_pollfds, 50); if (n < 0) continue; if (n) { for (n = 0; n < count_pollfds; n++) if (pollfds[n].revents) /* * returns immediately if the fd does not * match anything under libwebsockets * control */ if (lws_service_fd(context, &pollfds[n]) < 0) goto done; /* if needed, force-service wsis that may not have read all input */ while (!lws_service_adjust_timeout(context, 1, 0)) { lwsl_notice("extpoll doing forced service!\n"); lws_service_tsi(context, -1, 0); } } else { /* no revents, but before polling again, make lws check for any timeouts */ if (ms - ms_1sec > 1000) { lwsl_notice("1 per sec\n"); lws_service_fd(context, NULL); ms_1sec = ms; } } #else /* * If libwebsockets sockets are all we care about, * you can use this api which takes care of the poll() * and looping through finding who needed service. * * If no socket needs service, it'll return anyway after * the number of ms in the second argument. */ n = lws_service(context, 5); #endif } #ifdef EXTERNAL_POLL done: #endif lws_context_destroy(context); lwsl_notice("libwebsockets-test-server exited cleanly\n"); #ifndef _WIN32 closelog(); #endif return 0; }
int main(int argc, char **argv) { int n = 0, ret = 0, port = 7681, use_ssl = 0; unsigned int rl_dumb = 0, rl_mirror = 0; struct lws_context_creation_info info; struct lws_context *context; int ietf_version = -1; /* latest */ const char *address; memset(&info, 0, sizeof info); fprintf(stderr, "libwebsockets test client\n" "(C) Copyright 2010-2015 Andy Green <*****@*****.**> " "licensed under LGPL2.1\n"); if (argc < 2) goto usage; while (n >= 0) { n = getopt_long(argc, argv, "nuv:hsp:d:l", options, NULL); if (n < 0) continue; switch (n) { case 'd': lws_set_log_level(atoi(optarg), NULL); break; case 's': use_ssl = 2; /* 2 = allow selfsigned */ break; case 'p': port = atoi(optarg); break; case 'l': longlived = 1; break; case 'v': ietf_version = atoi(optarg); break; case 'u': deny_deflate = 1; break; case 'n': deny_mux = 1; break; case 'h': goto usage; } } if (optind >= argc) goto usage; signal(SIGINT, sighandler); address = argv[optind]; /* * create the websockets context. This tracks open connections and * knows how to route any traffic and which protocol version to use, * and if each connection is client or server side. * * For this client-only demo, we tell it to not listen on any port. */ info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = protocols; #ifndef LWS_NO_EXTENSIONS info.extensions = lws_get_internal_extensions(); #endif info.gid = -1; info.uid = -1; context = lws_create_context(&info); if (context == NULL) { fprintf(stderr, "Creating libwebsocket context failed\n"); return 1; } /* * sit there servicing the websocket context to handle incoming * packets, and drawing random circles on the mirror protocol websocket * * nothing happens until the client websocket connection is * asynchronously established... calling lws_client_connect() only * instantiates the connection logically, lws_service() progresses it * asynchronously. */ while (!force_exit) { if (!wsi_dumb && ratelimit_connects(&rl_dumb, 2u)) { lwsl_notice("dumb: connecting\n"); wsi_dumb = lws_client_connect(context, address, port, use_ssl, "/", argv[optind], argv[optind], protocols[PROTOCOL_DUMB_INCREMENT].name, ietf_version); } if (!wsi_mirror && ratelimit_connects(&rl_mirror, 2u)) { lwsl_notice("mirror: connecting\n"); wsi_mirror = lws_client_connect(context, address, port, use_ssl, "/", argv[optind], argv[optind], protocols[PROTOCOL_LWS_MIRROR].name, ietf_version); } lws_service(context, 500); } lwsl_err("Exiting\n"); lws_context_destroy(context); return ret; usage: fprintf(stderr, "Usage: libwebsockets-test-client " "<server address> [--port=<p>] " "[--ssl] [-k] [-v <ver>] " "[-d <log bitfield>] [-l]\n"); return 1; }
int main(int argc, char **argv) { int n = 0, ret = 0, port = 7681, use_ssl = 0, ietf_version = -1; unsigned int rl_dumb = 0, rl_mirror = 0, do_ws = 1, pp_secs = 0; struct lws_context_creation_info info; struct lws_client_connect_info i; struct lws_context *context; const char *prot, *p; char path[300]; char cert_path[1024] = ""; char key_path[1024] = ""; char ca_path[1024] = ""; memset(&info, 0, sizeof info); lwsl_notice("libwebsockets test client - license LGPL2.1+SLE\n"); lwsl_notice("(C) Copyright 2010-2016 Andy Green <*****@*****.**>\n"); if (argc < 2) goto usage; while (n >= 0) { n = getopt_long(argc, argv, "Snuv:hsp:d:lC:K:A:P:", options, NULL); if (n < 0) continue; switch (n) { case 'd': lws_set_log_level(atoi(optarg), NULL); break; case 's': /* lax SSL, allow selfsigned, skip checking hostname */ use_ssl = LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK; break; case 'S': /* Strict SSL, no selfsigned, check server hostname */ use_ssl = LCCSCF_USE_SSL; break; case 'p': port = atoi(optarg); break; case 'P': pp_secs = atoi(optarg); lwsl_notice("Setting pingpong interval to %d\n", pp_secs); break; case 'l': longlived = 1; break; case 'v': ietf_version = atoi(optarg); break; case 'u': deny_deflate = 1; break; case 'n': flag_no_mirror_traffic = 1; lwsl_notice("Disabled sending mirror data (for pingpong testing)\n"); break; case 'C': strncpy(cert_path, optarg, sizeof(cert_path) - 1); cert_path[sizeof(cert_path) - 1] = '\0'; break; case 'K': strncpy(key_path, optarg, sizeof(key_path) - 1); key_path[sizeof(key_path) - 1] = '\0'; break; case 'A': strncpy(ca_path, optarg, sizeof(ca_path) - 1); ca_path[sizeof(ca_path) - 1] = '\0'; break; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) case 'R': strncpy(crl_path, optarg, sizeof(crl_path) - 1); crl_path[sizeof(crl_path) - 1] = '\0'; break; #endif #endif #endif case 'h': goto usage; } } if (optind >= argc) goto usage; signal(SIGINT, sighandler); memset(&i, 0, sizeof(i)); i.port = port; if (lws_parse_uri(argv[optind], &prot, &i.address, &i.port, &p)) goto usage; /* add back the leading / on path */ path[0] = '/'; strncpy(path + 1, p, sizeof(path) - 2); path[sizeof(path) - 1] = '\0'; i.path = path; if (!strcmp(prot, "http") || !strcmp(prot, "ws")) use_ssl = 0; if (!strcmp(prot, "https") || !strcmp(prot, "wss")) if (!use_ssl) use_ssl = LCCSCF_USE_SSL; /* * create the websockets context. This tracks open connections and * knows how to route any traffic and which protocol version to use, * and if each connection is client or server side. * * For this client-only demo, we tell it to not listen on any port. */ info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = protocols; info.gid = -1; info.uid = -1; info.ws_ping_pong_interval = pp_secs; if (use_ssl) { info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; /* * If the server wants us to present a valid SSL client certificate * then we can set it up here. */ if (cert_path[0]) info.ssl_cert_filepath = cert_path; if (key_path[0]) info.ssl_private_key_filepath = key_path; /* * A CA cert and CRL can be used to validate the cert send by the server */ if (ca_path[0]) info.ssl_ca_filepath = ca_path; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) else if (crl_path[0]) lwsl_notice("WARNING, providing a CRL requires a CA cert!\n"); #endif #endif #endif } if (use_ssl & LCCSCF_USE_SSL) lwsl_notice(" Using SSL\n"); else lwsl_notice(" SSL disabled\n"); if (use_ssl & LCCSCF_ALLOW_SELFSIGNED) lwsl_notice(" Selfsigned certs allowed\n"); else lwsl_notice(" Cert must validate correctly (use -s to allow selfsigned)\n"); if (use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK) lwsl_notice(" Skipping peer cert hostname check\n"); else lwsl_notice(" Requiring peer cert hostname matches\n"); context = lws_create_context(&info); if (context == NULL) { fprintf(stderr, "Creating libwebsocket context failed\n"); return 1; } i.context = context; i.ssl_connection = use_ssl; i.host = i.address; i.origin = i.address; i.ietf_version_or_minus_one = ietf_version; i.client_exts = exts; if (!strcmp(prot, "http") || !strcmp(prot, "https")) { lwsl_notice("using %s mode (non-ws)\n", prot); i.method = "GET"; do_ws = 0; } else lwsl_notice("using %s mode (ws)\n", prot); /* * sit there servicing the websocket context to handle incoming * packets, and drawing random circles on the mirror protocol websocket * * nothing happens until the client websocket connection is * asynchronously established... calling lws_client_connect() only * instantiates the connection logically, lws_service() progresses it * asynchronously. */ while (!force_exit) { if (do_ws) { if (!wsi_dumb && ratelimit_connects(&rl_dumb, 2u)) { lwsl_notice("dumb: connecting\n"); i.protocol = protocols[PROTOCOL_DUMB_INCREMENT].name; i.pwsi = &wsi_dumb; lws_client_connect_via_info(&i); } if (!wsi_mirror && ratelimit_connects(&rl_mirror, 2u)) { lwsl_notice("mirror: connecting\n"); i.protocol = protocols[PROTOCOL_LWS_MIRROR].name; i.pwsi = &wsi_mirror; wsi_mirror = lws_client_connect_via_info(&i); } } else if (!wsi_dumb && ratelimit_connects(&rl_dumb, 2u)) { lwsl_notice("http: connecting\n"); i.pwsi = &wsi_dumb; lws_client_connect_via_info(&i); } lws_service(context, 500); } lwsl_err("Exiting\n"); lws_context_destroy(context); return ret; usage: fprintf(stderr, "Usage: libwebsockets-test-client " "<server address> [--port=<p>] " "[--ssl] [-k] [-v <ver>] " "[-d <log bitfield>] [-l]\n"); return 1; }
int main(int argc, char **argv) { struct lws_context_creation_info info; char interface_name[128] = ""; //unsigned int ms, oldms = 0; const char *iface = NULL; const char *ssl_cert = NULL; const char *ssl_private_key = NULL; char cert_path[1024]; char key_path[1024]; int use_ssl = 0; int opts = 0; int n = 0; //int daemonize = 0; /* * take care to zero down the info struct, he contains random garbaage * from the stack otherwise */ memset(&info, 0, sizeof info); info.port = 7681; /* * define ubus struct */ const char *ubus_socket = NULL; struct ubus_context *ctx; while (n >= 0) { n = getopt_long(argc, argv, "r:x:i:u:hsc:k:p:", options, NULL); if (n < 0) continue; switch (n) { //case 'd': // debug_level = atoi(optarg); // break; case 's': use_ssl = 1; break; case 'c': ssl_cert = optarg; printf("Setting ssl_cert path to \"%s\"\n", ssl_cert); break; case 'k': ssl_private_key = optarg; printf("Setting ssl_private_key path to \"%s\"\n", ssl_private_key); break; case 'p': info.port = atoi(optarg); break; case 'i': strncpy(interface_name, optarg, sizeof interface_name); interface_name[(sizeof interface_name) - 1] = '\0'; iface = interface_name; break; case 'x': strncpy(ubus_xevent, optarg, sizeof ubus_xevent); ubus_xevent[(sizeof ubus_xevent) - 1] = '\0'; ubusxevent = ubus_xevent; break; case 'h': fprintf(stderr, "Usage: ws-mirror-server " "-x <x> -[--port=<p>] [--ssl]\n" "-c <c> ssl_cert path -k <k> ssl_private_key path\n" "-x <x> ubus send path from ws e.g. \"linknxws\" or \"ws\"\n"); exit(1); } } signal(SIGINT, sighandler); /* Create ubus conection */ ctx = ubus_connect(ubus_socket); if (!ctx) { lwsl_err("Failed to connect to ubus\n"); return -1; } info.iface = iface; info.protocols = protocols; if (!use_ssl) { info.ssl_cert_filepath = NULL; info.ssl_private_key_filepath = NULL; } else { if (strlen(ssl_cert) > sizeof(cert_path) - 32) { lwsl_err("resource path too long\n"); return -1; } sprintf(cert_path, "%s",ssl_cert); if (strlen(ssl_private_key) > sizeof(key_path) - 32) { lwsl_err("resource path too long\n"); return -1; } sprintf(key_path, "%s",ssl_private_key); info.ssl_cert_filepath = cert_path; info.ssl_private_key_filepath = key_path; } info.gid = -1; info.uid = -1; info.max_http_header_pool = 1; info.options = opts; info.extensions = exts; context = lws_create_context(&info); if (context == NULL) { lwsl_err("libwebsocket init failed\n"); return -1; } n = 0; while (n >= 0 && !force_exit) { struct timeval tv; gettimeofday(&tv, NULL); n = lws_service(context, 50); if (n < 0) { lwsl_err("Unable to fork service loop %d\n", n); return -1; } } lws_context_destroy(context); lwsl_notice("libwebsockets-test-server exited cleanly\n"); return 0; }