2 * libwebsockets-test-server - libwebsockets test implementation
4 * Copyright (C) 2011-2017 Andy Green <andy@warmcat.com>
6 * This file is made available under the Creative Commons CC0 1.0
7 * Universal Public Domain Dedication.
9 * The person who associated a work with this deed has dedicated
10 * the work to the public domain by waiving all of his or her rights
11 * to the work worldwide under copyright law, including all related
12 * and neighboring rights, to the extent allowed by law. You can copy,
13 * modify, distribute and perform the work, even for commercial purposes,
14 * all without asking permission.
16 * The test apps are intended to be adapted for use in your code, which
17 * may be proprietary. So unlike the library itself, they are licensed
20 #include "test-server.h"
23 int max_poll_elements;
25 volatile int force_exit = 0;
26 struct lws_context *context;
27 struct lws_plat_file_ops fops_plat;
29 /* http server gets files from this path */
30 #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
31 char *resource_path = LOCAL_RESOURCE_PATH;
33 #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param)
34 char crl_path[1024] = "";
37 #define LWS_PLUGIN_STATIC
38 #include "../plugins/protocol_lws_mirror.c"
39 #include "../plugins/protocol_lws_status.c"
40 #include "../plugins/protocol_lws_meta.c"
42 /* singlethreaded version --> no locks */
44 void test_server_lock(int care)
47 void test_server_unlock(int care)
52 * This demo server shows how to use libwebsockets for one or more
53 * websocket protocols in the same server
55 * It defines the following websocket protocols:
57 * dumb-increment-protocol: once the socket is opened, an incrementing
58 * ascii string is sent down it every 50ms.
59 * If you send "reset\n" on the websocket, then
60 * the incrementing number is reset to 0.
62 * lws-mirror-protocol: copies any received packet to every connection also
63 * using this protocol, including the sender
70 PROTOCOL_DUMB_INCREMENT,
78 /* list of supported protocols and callbacks */
80 static struct lws_protocols protocols[] = {
81 /* first protocol must always be HTTP handler */
84 "http-only", /* name */
85 callback_http, /* callback */
86 sizeof (struct per_session_data__http), /* per_session_data_size */
87 0, /* max frame size / rx buffer */
90 "dumb-increment-protocol",
91 callback_dumb_increment,
92 sizeof(struct per_session_data__dumb_increment),
96 LWS_PLUGIN_PROTOCOL_MIRROR,
97 LWS_PLUGIN_PROTOCOL_LWS_STATUS,
98 LWS_PLUGIN_PROTOCOL_LWS_META,
99 { NULL, NULL, 0, 0 } /* terminator */
102 static const struct lws_extension exts[] = {
104 "permessage-deflate",
105 lws_extension_callback_pm_deflate,
106 "permessage-deflate; client_no_context_takeover; client_max_window_bits"
110 lws_extension_callback_pm_deflate,
113 { NULL, NULL, NULL /* terminator */ }
116 /* this shows how to override the lws file operations. You don't need
117 * to do any of this unless you have a reason (eg, want to serve
118 * compressed files without decompressing the whole archive)
121 test_server_fops_open(const struct lws_plat_file_ops *fops,
122 const char *vfs_path, const char *vpath,
123 lws_fop_flags_t *flags)
127 /* call through to original platform implementation */
128 n = fops_plat.open(fops, vfs_path, vpath, flags);
130 lwsl_notice("%s: opening %s, ret %p\n", __func__, vfs_path, n);
135 void signal_cb(evutil_socket_t sock_fd, short events, void *ctx)
137 struct event_base *event_base_loop = ctx;
139 lwsl_notice("Signal caught, exiting...\n");
141 if (events & EV_SIGNAL)
142 event_base_loopbreak(event_base_loop);
146 ev_timeout_cb (evutil_socket_t sock_fd, short events, void *ctx)
148 lws_callback_on_writable_all_protocol(context,
149 &protocols[PROTOCOL_DUMB_INCREMENT]);
152 static struct option options[] = {
153 { "help", no_argument, NULL, 'h' },
154 { "debug", required_argument, NULL, 'd' },
155 { "port", required_argument, NULL, 'p' },
156 { "ssl", no_argument, NULL, 's' },
157 { "allow-non-ssl", no_argument, NULL, 'a' },
158 { "interface", required_argument, NULL, 'i' },
159 { "closetest", no_argument, NULL, 'c' },
160 { "libevent", no_argument, NULL, 'e' },
161 #ifndef LWS_NO_DAEMONIZE
162 { "daemonize", no_argument, NULL, 'D' },
164 { "resource_path", required_argument, NULL, 'r' },
168 int main(int argc, char **argv)
170 int sigs[] = { SIGINT, SIGKILL, SIGTERM, SIGSEGV, SIGFPE };
171 struct event *signals[ARRAY_SIZE(sigs)];
172 struct event_base *event_base_loop = event_base_new();
173 struct lws_context_creation_info info;
174 char interface_name[128] = "";
175 const char *iface = NULL;
176 struct event *timeout_watcher;
177 char cert_path[1024];
183 int syslog_options = LOG_PID | LOG_PERROR;
185 #ifndef LWS_NO_DAEMONIZE
190 * take care to zero down the info struct, he contains random garbaage
191 * from the stack otherwise
193 memset(&info, 0, sizeof info);
197 n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
202 opts |= LWS_SERVER_OPTION_LIBEVENT;
204 #ifndef LWS_NO_DAEMONIZE
208 syslog_options &= ~LOG_PERROR;
213 debug_level = atoi(optarg);
219 opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
222 info.port = atoi(optarg);
225 strncpy(interface_name, optarg, sizeof interface_name);
226 interface_name[(sizeof interface_name) - 1] = '\0';
227 iface = interface_name;
231 fprintf(stderr, " Close testing mode -- closes on "
232 "client after 50 dumb increments"
233 "and suppresses lws_mirror spam\n");
236 resource_path = optarg;
237 printf("Setting resource path to \"%s\"\n", resource_path);
240 fprintf(stderr, "Usage: test-server "
241 "[--port=<p>] [--ssl] "
242 "[-d <log bitfield>] "
243 "[--resource_path <path>]\n");
248 #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
250 * normally lock path would be /var/lock/lwsts or similar, to
251 * simplify getting started without having to take care about
252 * permissions or running as root, set to /tmp/.lwsts-lock
254 if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
255 fprintf(stderr, "Failed to daemonize\n");
260 for (n = 0; n < ARRAY_SIZE(sigs); n++) {
261 signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb, event_base_loop);
263 evsignal_add(signals[n], NULL);
267 /* we will only try to log things according to our debug_level */
268 setlogmask(LOG_UPTO (LOG_DEBUG));
269 openlog("lwsts", syslog_options, LOG_DAEMON);
272 /* tell the library what debug level to emit and to send it to syslog */
273 lws_set_log_level(debug_level, lwsl_emit_syslog);
275 lwsl_notice("libwebsockets test server libevent - license LGPL2.1+SLE\n");
276 lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
278 printf("Using resource path \"%s\"\n", resource_path);
281 info.protocols = protocols;
282 info.extensions = exts;
284 info.ssl_cert_filepath = NULL;
285 info.ssl_private_key_filepath = NULL;
288 if (strlen(resource_path) > sizeof(cert_path) - 32) {
289 lwsl_err("resource path too long\n");
292 sprintf(cert_path, "%s/libwebsockets-test-server.pem",
294 if (strlen(resource_path) > sizeof(key_path) - 32) {
295 lwsl_err("resource path too long\n");
298 sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
301 info.ssl_cert_filepath = cert_path;
302 info.ssl_private_key_filepath = key_path;
304 opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
308 info.max_http_header_pool = 1;
309 info.options = opts | LWS_SERVER_OPTION_LIBEVENT;
311 context = lws_create_context(&info);
312 if (context == NULL) {
313 lwsl_err("libwebsocket init failed\n");
318 * this shows how to override the lws file operations. You don't need
319 * to do any of this unless you have a reason (eg, want to serve
320 * compressed files without decompressing the whole archive)
322 /* stash original platform fops */
323 fops_plat = *(lws_get_fops(context));
324 /* override the active fops */
325 lws_get_fops(context)->open = test_server_fops_open;
327 // Don't use the default Signal Event Watcher & Handler
328 lws_event_sigint_cfg(context, 0, NULL);
329 // Initialize the LWS with libevent loop
330 lws_event_initloop(context, event_base_loop, 0);
332 timeout_watcher = event_new(event_base_loop, -1, EV_PERSIST, ev_timeout_cb, NULL);
333 struct timeval tv = {0, 50000};
334 evtimer_add(timeout_watcher, &tv);
335 event_base_dispatch(event_base_loop);
337 lws_context_destroy(context);
338 lwsl_notice("libwebsockets-test-server exited cleanly\n");