2 * libwebsockets-test-server - libwebsockets test implementation
4 * Copyright (C) 2011-2016 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 /* singlethreaded version --> no locks */
39 void test_server_lock(int care)
42 void test_server_unlock(int care)
47 * This demo server shows how to use libwebsockets for one or more
48 * websocket protocols in the same server
50 * It defines the following websocket protocols:
52 * dumb-increment-protocol: once the socket is opened, an incrementing
53 * ascii string is sent down it every 50ms.
54 * If you send "reset\n" on the websocket, then
55 * the incrementing number is reset to 0.
57 * lws-mirror-protocol: copies any received packet to every connection also
58 * using this protocol, including the sender
65 PROTOCOL_DUMB_INCREMENT,
72 /* list of supported protocols and callbacks */
74 static struct lws_protocols protocols[] = {
75 /* first protocol must always be HTTP handler */
78 "http-only", /* name */
79 callback_http, /* callback */
80 sizeof (struct per_session_data__http), /* per_session_data_size */
81 0, /* max frame size / rx buffer */
84 "dumb-increment-protocol",
85 callback_dumb_increment,
86 sizeof(struct per_session_data__dumb_increment),
90 "lws-mirror-protocol",
92 sizeof(struct per_session_data__lws_mirror),
98 sizeof(struct per_session_data__lws_status),
101 { NULL, NULL, 0, 0 } /* terminator */
104 static const struct lws_extension exts[] = {
106 "permessage-deflate",
107 lws_extension_callback_pm_deflate,
108 "permessage-deflate; client_no_context_takeover; client_max_window_bits"
112 lws_extension_callback_pm_deflate,
115 { NULL, NULL, NULL /* terminator */ }
118 /* this shows how to override the lws file operations. You don't need
119 * to do any of this unless you have a reason (eg, want to serve
120 * compressed files without decompressing the whole archive)
123 test_server_fops_open(const struct lws_plat_file_ops *fops,
124 const char *vfs_path, const char *vpath,
125 lws_fop_flags_t *flags)
129 /* call through to original platform implementation */
130 n = fops_plat.open(fops, vfs_path, vpath, flags);
132 lwsl_notice("%s: opening %s, ret %p\n", __func__, vfs_path, n);
137 void signal_cb(evutil_socket_t sock_fd, short events, void *ctx)
139 lwsl_notice("Signal caught, exiting...\n");
141 if (events & EV_SIGNAL) {
142 struct event_base *event_base_loop = event_get_base((struct event *) ctx);
143 event_base_loopbreak(event_base_loop);
148 ev_timeout_cb (evutil_socket_t sock_fd, short events, void *ctx)
150 lws_callback_on_writable_all_protocol(context,
151 &protocols[PROTOCOL_DUMB_INCREMENT]);
154 static struct option options[] = {
155 { "help", no_argument, NULL, 'h' },
156 { "debug", required_argument, NULL, 'd' },
157 { "port", required_argument, NULL, 'p' },
158 { "ssl", no_argument, NULL, 's' },
159 { "allow-non-ssl", no_argument, NULL, 'a' },
160 { "interface", required_argument, NULL, 'i' },
161 { "closetest", no_argument, NULL, 'c' },
162 { "libevent", no_argument, NULL, 'e' },
163 #ifndef LWS_NO_DAEMONIZE
164 { "daemonize", no_argument, NULL, 'D' },
166 { "resource_path", required_argument, NULL, 'r' },
170 int main(int argc, char **argv)
172 int sigs[] = { SIGINT, SIGKILL, SIGTERM, SIGSEGV, SIGFPE };
173 struct event *signals[ARRAY_SIZE(sigs)];
174 struct event_base *event_base_loop = event_base_new();
175 struct lws_context_creation_info info;
176 char interface_name[128] = "";
177 const char *iface = NULL;
178 struct event *timeout_watcher;
179 char cert_path[1024];
185 int syslog_options = LOG_PID | LOG_PERROR;
187 #ifndef LWS_NO_DAEMONIZE
192 * take care to zero down the info struct, he contains random garbaage
193 * from the stack otherwise
195 memset(&info, 0, sizeof info);
199 n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
204 opts |= LWS_SERVER_OPTION_LIBEVENT;
206 #ifndef LWS_NO_DAEMONIZE
210 syslog_options &= ~LOG_PERROR;
215 debug_level = atoi(optarg);
221 opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
224 info.port = atoi(optarg);
227 strncpy(interface_name, optarg, sizeof interface_name);
228 interface_name[(sizeof interface_name) - 1] = '\0';
229 iface = interface_name;
233 fprintf(stderr, " Close testing mode -- closes on "
234 "client after 50 dumb increments"
235 "and suppresses lws_mirror spam\n");
238 resource_path = optarg;
239 printf("Setting resource path to \"%s\"\n", resource_path);
242 fprintf(stderr, "Usage: test-server "
243 "[--port=<p>] [--ssl] "
244 "[-d <log bitfield>] "
245 "[--resource_path <path>]\n");
250 #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
252 * normally lock path would be /var/lock/lwsts or similar, to
253 * simplify getting started without having to take care about
254 * permissions or running as root, set to /tmp/.lwsts-lock
256 if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
257 fprintf(stderr, "Failed to daemonize\n");
262 for (n = 0; n < ARRAY_SIZE(sigs); n++) {
263 signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb, event_self_cbarg());
264 evsignal_add(signals[n], NULL);
268 /* we will only try to log things according to our debug_level */
269 setlogmask(LOG_UPTO (LOG_DEBUG));
270 openlog("lwsts", syslog_options, LOG_DAEMON);
273 /* tell the library what debug level to emit and to send it to syslog */
274 lws_set_log_level(debug_level, lwsl_emit_syslog);
276 lwsl_notice("libwebsockets test server libevent - license LGPL2.1+SLE\n");
277 lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
279 printf("Using resource path \"%s\"\n", resource_path);
282 info.protocols = protocols;
283 info.extensions = exts;
285 info.ssl_cert_filepath = NULL;
286 info.ssl_private_key_filepath = NULL;
289 if (strlen(resource_path) > sizeof(cert_path) - 32) {
290 lwsl_err("resource path too long\n");
293 sprintf(cert_path, "%s/libwebsockets-test-server.pem",
295 if (strlen(resource_path) > sizeof(key_path) - 32) {
296 lwsl_err("resource path too long\n");
299 sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
302 info.ssl_cert_filepath = cert_path;
303 info.ssl_private_key_filepath = key_path;
305 opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
309 info.max_http_header_pool = 1;
310 info.options = opts | LWS_SERVER_OPTION_LIBEVENT;
312 context = lws_create_context(&info);
313 if (context == NULL) {
314 lwsl_err("libwebsocket init failed\n");
319 * this shows how to override the lws file operations. You don't need
320 * to do any of this unless you have a reason (eg, want to serve
321 * compressed files without decompressing the whole archive)
323 /* stash original platform fops */
324 fops_plat = *(lws_get_fops(context));
325 /* override the active fops */
326 lws_get_fops(context)->open = test_server_fops_open;
328 // Don't use the default Signal Event Watcher & Handler
329 lws_event_sigint_cfg(context, 0, NULL);
330 // Initialize the LWS with libevent loop
331 lws_event_initloop(context, event_base_loop, 0);
333 timeout_watcher = evtimer_new(event_base_loop, ev_timeout_cb, NULL);
334 struct timeval tv = {0, 50000};
335 evtimer_add(timeout_watcher, &tv);
336 event_base_dispatch(event_base_loop);
338 lws_context_destroy(context);
339 lwsl_notice("libwebsockets-test-server exited cleanly\n");