libevent: update to use static plugins and work with new libevent2
[platform/upstream/libwebsockets.git] / test-server / test-server-libevent.c
1 /*
2  * libwebsockets-test-server - libwebsockets test implementation
3  *
4  * Copyright (C) 2011-2017 Andy Green <andy@warmcat.com>
5  *
6  * This file is made available under the Creative Commons CC0 1.0
7  * Universal Public Domain Dedication.
8  *
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.
15  *
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
18  * Public Domain.
19  */
20 #include "test-server.h"
21
22 int close_testing;
23 int max_poll_elements;
24 int debug_level = 7;
25 volatile int force_exit = 0;
26 struct lws_context *context;
27 struct lws_plat_file_ops fops_plat;
28
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;
32
33 #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param)
34 char crl_path[1024] = "";
35 #endif
36
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"
41
42 /* singlethreaded version --> no locks */
43
44 void test_server_lock(int care)
45 {
46 }
47 void test_server_unlock(int care)
48 {
49 }
50
51 /*
52  * This demo server shows how to use libwebsockets for one or more
53  * websocket protocols in the same server
54  *
55  * It defines the following websocket protocols:
56  *
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.
61  *
62  *  lws-mirror-protocol: copies any received packet to every connection also
63  *        using this protocol, including the sender
64  */
65
66 enum demo_protocols {
67         /* always first */
68         PROTOCOL_HTTP = 0,
69
70         PROTOCOL_DUMB_INCREMENT,
71         PROTOCOL_LWS_MIRROR,
72         PROTOCOL_LWS_META,
73
74         /* always last */
75         DEMO_PROTOCOL_COUNT
76 };
77
78 /* list of supported protocols and callbacks */
79
80 static struct lws_protocols protocols[] = {
81                 /* first protocol must always be HTTP handler */
82
83                 {
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 */
88                 },
89                 {
90                                 "dumb-increment-protocol",
91                                 callback_dumb_increment,
92                                 sizeof(struct per_session_data__dumb_increment),
93                                 10,
94                 },
95
96                 LWS_PLUGIN_PROTOCOL_MIRROR,
97                 LWS_PLUGIN_PROTOCOL_LWS_STATUS,
98                 LWS_PLUGIN_PROTOCOL_LWS_META,
99                 { NULL, NULL, 0, 0 } /* terminator */
100 };
101
102 static const struct lws_extension exts[] = {
103                 {
104                                 "permessage-deflate",
105                                 lws_extension_callback_pm_deflate,
106                                 "permessage-deflate; client_no_context_takeover; client_max_window_bits"
107                 },
108                 {
109                                 "deflate-frame",
110                                 lws_extension_callback_pm_deflate,
111                                 "deflate_frame"
112                 },
113                 { NULL, NULL, NULL /* terminator */ }
114 };
115
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)
119  */
120 static lws_fop_fd_t
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)
124 {
125         lws_fop_fd_t n;
126
127         /* call through to original platform implementation */
128         n = fops_plat.open(fops, vfs_path, vpath, flags);
129
130         lwsl_notice("%s: opening %s, ret %p\n", __func__, vfs_path, n);
131
132         return n;
133 }
134
135 void signal_cb(evutil_socket_t sock_fd, short events, void *ctx)
136 {
137         struct event_base *event_base_loop = ctx;
138
139         lwsl_notice("Signal caught, exiting...\n");
140         force_exit = 1;
141         if (events & EV_SIGNAL)
142                 event_base_loopbreak(event_base_loop);
143 }
144
145 static void
146 ev_timeout_cb (evutil_socket_t sock_fd, short events, void *ctx)
147 {
148         lws_callback_on_writable_all_protocol(context,
149                         &protocols[PROTOCOL_DUMB_INCREMENT]);
150 }
151
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' },
163 #endif
164                 { "resource_path", required_argument,  NULL, 'r' },
165                 { NULL, 0, 0, 0 }
166 };
167
168 int main(int argc, char **argv)
169 {
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];
178         char key_path[1024];
179         int use_ssl = 0;
180         int opts = 0;
181         int n = 0;
182 #ifndef _WIN32
183         int syslog_options = LOG_PID | LOG_PERROR;
184 #endif
185 #ifndef LWS_NO_DAEMONIZE
186         int daemonize = 0;
187 #endif
188
189         /*
190          * take care to zero down the info struct, he contains random garbaage
191          * from the stack otherwise
192          */
193         memset(&info, 0, sizeof info);
194         info.port = 7681;
195
196         while (n >= 0) {
197                 n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
198                 if (n < 0)
199                         continue;
200                 switch (n) {
201                 case 'e':
202                         opts |= LWS_SERVER_OPTION_LIBEVENT;
203                         break;
204 #ifndef LWS_NO_DAEMONIZE
205                 case 'D':
206                         daemonize = 1;
207 #ifndef _WIN32
208                         syslog_options &= ~LOG_PERROR;
209 #endif
210                         break;
211 #endif
212                 case 'd':
213                         debug_level = atoi(optarg);
214                         break;
215                 case 's':
216                         use_ssl = 1;
217                         break;
218                 case 'a':
219                         opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
220                         break;
221                 case 'p':
222                         info.port = atoi(optarg);
223                         break;
224                 case 'i':
225                         strncpy(interface_name, optarg, sizeof interface_name);
226                         interface_name[(sizeof interface_name) - 1] = '\0';
227                         iface = interface_name;
228                         break;
229                 case 'c':
230                         close_testing = 1;
231                         fprintf(stderr, " Close testing mode -- closes on "
232                                         "client after 50 dumb increments"
233                                         "and suppresses lws_mirror spam\n");
234                         break;
235                 case 'r':
236                         resource_path = optarg;
237                         printf("Setting resource path to \"%s\"\n", resource_path);
238                         break;
239                 case 'h':
240                         fprintf(stderr, "Usage: test-server "
241                                         "[--port=<p>] [--ssl] "
242                                         "[-d <log bitfield>] "
243                                         "[--resource_path <path>]\n");
244                         exit(1);
245                 }
246         }
247
248 #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
249         /*
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
253          */
254         if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
255                 fprintf(stderr, "Failed to daemonize\n");
256                 return 1;
257         }
258 #endif
259
260         for (n = 0; n < ARRAY_SIZE(sigs); n++) {
261                 signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb, event_base_loop);
262
263                 evsignal_add(signals[n], NULL);
264         }
265
266 #ifndef _WIN32
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);
270 #endif
271
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);
274
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");
277
278         printf("Using resource path \"%s\"\n", resource_path);
279
280         info.iface = iface;
281         info.protocols = protocols;
282         info.extensions = exts;
283
284         info.ssl_cert_filepath = NULL;
285         info.ssl_private_key_filepath = NULL;
286
287         if (use_ssl) {
288                 if (strlen(resource_path) > sizeof(cert_path) - 32) {
289                         lwsl_err("resource path too long\n");
290                         return -1;
291                 }
292                 sprintf(cert_path, "%s/libwebsockets-test-server.pem",
293                                 resource_path);
294                 if (strlen(resource_path) > sizeof(key_path) - 32) {
295                         lwsl_err("resource path too long\n");
296                         return -1;
297                 }
298                 sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
299                                 resource_path);
300
301                 info.ssl_cert_filepath = cert_path;
302                 info.ssl_private_key_filepath = key_path;
303
304                 opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
305         }
306         info.gid = -1;
307         info.uid = -1;
308         info.max_http_header_pool = 1;
309         info.options = opts | LWS_SERVER_OPTION_LIBEVENT;
310
311         context = lws_create_context(&info);
312         if (context == NULL) {
313                 lwsl_err("libwebsocket init failed\n");
314                 return -1;
315         }
316
317         /*
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)
321          */
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;
326
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);
331
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);
336
337         lws_context_destroy(context);
338         lwsl_notice("libwebsockets-test-server exited cleanly\n");
339
340 #ifndef _WIN32
341         closelog();
342 #endif
343
344         return 0;
345 }