lws_intptr_t: fix ordering
[platform/upstream/libwebsockets.git] / test-server / test-server-libevent.c
1 /*
2  * libwebsockets-test-server - libwebsockets test implementation
3  *
4  * Copyright (C) 2011-2016 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 /* singlethreaded version --> no locks */
38
39 void test_server_lock(int care)
40 {
41 }
42 void test_server_unlock(int care)
43 {
44 }
45
46 /*
47  * This demo server shows how to use libwebsockets for one or more
48  * websocket protocols in the same server
49  *
50  * It defines the following websocket protocols:
51  *
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.
56  *
57  *  lws-mirror-protocol: copies any received packet to every connection also
58  *        using this protocol, including the sender
59  */
60
61 enum demo_protocols {
62   /* always first */
63   PROTOCOL_HTTP = 0,
64
65   PROTOCOL_DUMB_INCREMENT,
66   PROTOCOL_LWS_MIRROR,
67
68   /* always last */
69   DEMO_PROTOCOL_COUNT
70 };
71
72 /* list of supported protocols and callbacks */
73
74 static struct lws_protocols protocols[] = {
75   /* first protocol must always be HTTP handler */
76
77   {
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 */
82   },
83   {
84     "dumb-increment-protocol",
85     callback_dumb_increment,
86     sizeof(struct per_session_data__dumb_increment),
87     10,
88   },
89   {
90     "lws-mirror-protocol",
91     callback_lws_mirror,
92     sizeof(struct per_session_data__lws_mirror),
93     128,
94   },
95   {
96     "lws-status",
97     callback_lws_status,
98     sizeof(struct per_session_data__lws_status),
99     128,
100   },
101   { NULL, NULL, 0, 0 } /* terminator */
102 };
103
104 static const struct lws_extension exts[] = {
105   {
106     "permessage-deflate",
107     lws_extension_callback_pm_deflate,
108     "permessage-deflate; client_no_context_takeover; client_max_window_bits"
109   },
110   {
111     "deflate-frame",
112     lws_extension_callback_pm_deflate,
113     "deflate_frame"
114   },
115   { NULL, NULL, NULL /* terminator */ }
116 };
117
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)
121  */
122 static lws_fop_fd_t
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)
126 {
127   lws_fop_fd_t n;
128
129   /* call through to original platform implementation */
130   n = fops_plat.open(fops, vfs_path, vpath, flags);
131
132   lwsl_notice("%s: opening %s, ret %p\n", __func__, vfs_path, n);
133
134   return n;
135 }
136
137 void signal_cb(evutil_socket_t sock_fd, short events, void *ctx)
138 {
139   lwsl_notice("Signal caught, exiting...\n");
140   force_exit = 1;
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);
144   }
145 }
146
147 static void
148 ev_timeout_cb (evutil_socket_t sock_fd, short events, void *ctx)
149 {
150   lws_callback_on_writable_all_protocol(context,
151           &protocols[PROTOCOL_DUMB_INCREMENT]);
152 }
153
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' },
165 #endif
166   { "resource_path", required_argument,  NULL, 'r' },
167   { NULL, 0, 0, 0 }
168 };
169
170 int main(int argc, char **argv)
171 {
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];
180   char key_path[1024];
181   int use_ssl = 0;
182   int opts = 0;
183   int n = 0;
184 #ifndef _WIN32
185   int syslog_options = LOG_PID | LOG_PERROR;
186 #endif
187 #ifndef LWS_NO_DAEMONIZE
188   int daemonize = 0;
189 #endif
190
191   /*
192    * take care to zero down the info struct, he contains random garbaage
193    * from the stack otherwise
194    */
195   memset(&info, 0, sizeof info);
196   info.port = 7681;
197
198   while (n >= 0) {
199     n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
200     if (n < 0)
201       continue;
202     switch (n) {
203     case 'e':
204       opts |= LWS_SERVER_OPTION_LIBEVENT;
205       break;
206 #ifndef LWS_NO_DAEMONIZE
207     case 'D':
208       daemonize = 1;
209       #ifndef _WIN32
210       syslog_options &= ~LOG_PERROR;
211       #endif
212       break;
213 #endif
214     case 'd':
215       debug_level = atoi(optarg);
216       break;
217     case 's':
218       use_ssl = 1;
219       break;
220     case 'a':
221       opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
222       break;
223     case 'p':
224       info.port = atoi(optarg);
225       break;
226     case 'i':
227       strncpy(interface_name, optarg, sizeof interface_name);
228       interface_name[(sizeof interface_name) - 1] = '\0';
229       iface = interface_name;
230       break;
231     case 'c':
232       close_testing = 1;
233       fprintf(stderr, " Close testing mode -- closes on "
234              "client after 50 dumb increments"
235              "and suppresses lws_mirror spam\n");
236       break;
237     case 'r':
238       resource_path = optarg;
239       printf("Setting resource path to \"%s\"\n", resource_path);
240       break;
241     case 'h':
242       fprintf(stderr, "Usage: test-server "
243           "[--port=<p>] [--ssl] "
244           "[-d <log bitfield>] "
245           "[--resource_path <path>]\n");
246       exit(1);
247     }
248   }
249
250 #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
251   /*
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
255    */
256   if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
257     fprintf(stderr, "Failed to daemonize\n");
258     return 1;
259   }
260 #endif
261
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);
265   }
266
267 #ifndef _WIN32
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);
271 #endif
272
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);
275
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");
278
279   printf("Using resource path \"%s\"\n", resource_path);
280
281   info.iface = iface;
282   info.protocols = protocols;
283   info.extensions = exts;
284
285   info.ssl_cert_filepath = NULL;
286   info.ssl_private_key_filepath = NULL;
287
288   if (use_ssl) {
289     if (strlen(resource_path) > sizeof(cert_path) - 32) {
290       lwsl_err("resource path too long\n");
291       return -1;
292     }
293     sprintf(cert_path, "%s/libwebsockets-test-server.pem",
294                 resource_path);
295     if (strlen(resource_path) > sizeof(key_path) - 32) {
296       lwsl_err("resource path too long\n");
297       return -1;
298     }
299     sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
300                 resource_path);
301
302     info.ssl_cert_filepath = cert_path;
303     info.ssl_private_key_filepath = key_path;
304
305     opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
306   }
307   info.gid = -1;
308   info.uid = -1;
309   info.max_http_header_pool = 1;
310   info.options = opts | LWS_SERVER_OPTION_LIBEVENT;
311
312   context = lws_create_context(&info);
313   if (context == NULL) {
314     lwsl_err("libwebsocket init failed\n");
315     return -1;
316   }
317
318   /*
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)
322    */
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;
327
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);
332
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);
337
338   lws_context_destroy(context);
339   lwsl_notice("libwebsockets-test-server exited cleanly\n");
340
341 #ifndef _WIN32
342   closelog();
343 #endif
344
345   return 0;
346 }