optimize extpoll fd delete
[profile/ivi/libwebsockets.git] / test-server / test-server.c
1 /*
2  * libwebsockets-test-server - libwebsockets test implementation
3  *
4  * Copyright (C) 2010-2011 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <getopt.h>
26 #include <string.h>
27 #include <sys/time.h>
28
29 #include "../lib/libwebsockets.h"
30
31 static int close_testing;
32
33 /*
34  * This demo server shows how to use libwebsockets for one or more
35  * websocket protocols in the same server
36  *
37  * It defines the following websocket protocols:
38  *
39  *  dumb-increment-protocol:  once the socket is opened, an incrementing
40  *                              ascii string is sent down it every 50ms.
41  *                              If you send "reset\n" on the websocket, then
42  *                              the incrementing number is reset to 0.
43  *
44  *  lws-mirror-protocol: copies any received packet to every connection also
45  *                              using this protocol, including the sender
46  */
47
48 enum demo_protocols {
49         /* always first */
50         PROTOCOL_HTTP = 0,
51
52         PROTOCOL_DUMB_INCREMENT,
53         PROTOCOL_LWS_MIRROR,
54
55         /* always last */
56         DEMO_PROTOCOL_COUNT
57 };
58
59
60 #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
61
62 /* this protocol server (always the first one) just knows how to do HTTP */
63
64 static int callback_http(struct libwebsocket_context *context,
65                 struct libwebsocket *wsi,
66                 enum libwebsocket_callback_reasons reason, void *user,
67                                                            void *in, size_t len)
68 {
69         char client_name[128];
70         char client_ip[128];
71
72         switch (reason) {
73         case LWS_CALLBACK_HTTP:
74                 fprintf(stderr, "serving HTTP URI %s\n", (char *)in);
75
76                 if (in && strcmp(in, "/favicon.ico") == 0) {
77                         if (libwebsockets_serve_http_file(wsi,
78                              LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon"))
79                                 fprintf(stderr, "Failed to send favicon\n");
80                         break;
81                 }
82
83                 /* send the script... when it runs it'll start websockets */
84
85                 if (libwebsockets_serve_http_file(wsi,
86                                   LOCAL_RESOURCE_PATH"/test.html", "text/html"))
87                         fprintf(stderr, "Failed to send HTTP file\n");
88
89                 /* we are done with this http connection */
90                 return 1;
91
92         /*
93          * callback for confirming to continue with client IP appear in
94          * protocol 0 callback since no websocket protocol has been agreed
95          * yet.  You can just ignore this if you won't filter on client IP
96          * since the default uhandled callback return is 0 meaning let the
97          * connection continue.
98          */
99
100         case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
101
102                 libwebsockets_get_peer_addresses((int)(long)user, client_name,
103                              sizeof(client_name), client_ip, sizeof(client_ip));
104
105                 fprintf(stderr, "Received network connect from %s (%s)\n",
106                                                         client_name, client_ip);
107
108                 /* if we returned non-zero from here, we kill the connection */
109                 break;
110
111         default:
112                 break;
113         }
114
115         return 0;
116 }
117
118
119 /*
120  * this is just an example of parsing handshake headers, you don't need this
121  * in your code unless you will filter allowing connections by the header
122  * content
123  */
124
125 static void
126 dump_handshake_info(struct lws_tokens *lwst)
127 {
128         int n;
129         static const char *token_names[WSI_TOKEN_COUNT] = {
130                 /*[WSI_TOKEN_GET_URI]           =*/ "GET URI",
131                 /*[WSI_TOKEN_HOST]              =*/ "Host",
132                 /*[WSI_TOKEN_CONNECTION]        =*/ "Connection",
133                 /*[WSI_TOKEN_KEY1]              =*/ "key 1",
134                 /*[WSI_TOKEN_KEY2]              =*/ "key 2",
135                 /*[WSI_TOKEN_PROTOCOL]          =*/ "Protocol",
136                 /*[WSI_TOKEN_UPGRADE]           =*/ "Upgrade",
137                 /*[WSI_TOKEN_ORIGIN]            =*/ "Origin",
138                 /*[WSI_TOKEN_DRAFT]             =*/ "Draft",
139                 /*[WSI_TOKEN_CHALLENGE]         =*/ "Challenge",
140
141                 /* new for 04 */
142                 /*[WSI_TOKEN_KEY]               =*/ "Key",
143                 /*[WSI_TOKEN_VERSION]           =*/ "Version",
144                 /*[WSI_TOKEN_SWORIGIN]          =*/ "Sworigin",
145
146                 /* new for 05 */
147                 /*[WSI_TOKEN_EXTENSIONS]        =*/ "Extensions",
148
149                 /* client receives these */
150                 /*[WSI_TOKEN_ACCEPT]            =*/ "Accept",
151                 /*[WSI_TOKEN_NONCE]             =*/ "Nonce",
152                 /*[WSI_TOKEN_HTTP]              =*/ "Http",
153                 /*[WSI_TOKEN_MUXURL]    =*/ "MuxURL",
154         };
155
156         for (n = 0; n < WSI_TOKEN_COUNT; n++) {
157                 if (lwst[n].token == NULL)
158                         continue;
159
160                 fprintf(stderr, "    %s = %s\n", token_names[n], lwst[n].token);
161         }
162 }
163
164 /* dumb_increment protocol */
165
166 /*
167  * one of these is auto-created for each connection and a pointer to the
168  * appropriate instance is passed to the callback in the user parameter
169  *
170  * for this example protocol we use it to individualize the count for each
171  * connection.
172  */
173
174 struct per_session_data__dumb_increment {
175         int number;
176 };
177
178 static int
179 callback_dumb_increment(struct libwebsocket_context *context,
180                         struct libwebsocket *wsi,
181                         enum libwebsocket_callback_reasons reason,
182                                                void *user, void *in, size_t len)
183 {
184         int n;
185         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
186                                                   LWS_SEND_BUFFER_POST_PADDING];
187         unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
188         struct per_session_data__dumb_increment *pss = user;
189
190         switch (reason) {
191
192         case LWS_CALLBACK_ESTABLISHED:
193                 fprintf(stderr, "callback_dumb_increment: "
194                                                  "LWS_CALLBACK_ESTABLISHED\n");
195                 pss->number = 0;
196                 break;
197
198         /*
199          * in this protocol, we just use the broadcast action as the chance to
200          * send our own connection-specific data and ignore the broadcast info
201          * that is available in the 'in' parameter
202          */
203
204         case LWS_CALLBACK_BROADCAST:
205                 n = sprintf((char *)p, "%d", pss->number++);
206                 n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
207                 if (n < 0) {
208                         fprintf(stderr, "ERROR %d writing to socket\n", n);
209                         return 1;
210                 }
211                 if (close_testing && pss->number == 50) {
212                         fprintf(stderr, "close tesing limit, closing\n");
213                         libwebsocket_close_and_free_session(context, wsi,
214                                                        LWS_CLOSE_STATUS_NORMAL);
215                 }
216                 break;
217
218         case LWS_CALLBACK_RECEIVE:
219                 fprintf(stderr, "rx %d\n", (int)len);
220                 if (len < 6)
221                         break;
222                 if (strcmp(in, "reset\n") == 0)
223                         pss->number = 0;
224                 break;
225         /*
226          * this just demonstrates how to use the protocol filter. If you won't
227          * study and reject connections based on header content, you don't need
228          * to handle this callback
229          */
230
231         case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
232                 dump_handshake_info((struct lws_tokens *)(long)user);
233                 /* you could return non-zero here and kill the connection */
234                 break;
235
236         default:
237                 break;
238         }
239
240         return 0;
241 }
242
243
244 /* lws-mirror_protocol */
245
246 #define MAX_MESSAGE_QUEUE 64
247
248 struct per_session_data__lws_mirror {
249         struct libwebsocket *wsi;
250         int ringbuffer_tail;
251 };
252
253 struct a_message {
254         void *payload;
255         size_t len;
256 };
257
258 static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
259 static int ringbuffer_head;
260
261
262 static int
263 callback_lws_mirror(struct libwebsocket_context *context,
264                         struct libwebsocket *wsi,
265                         enum libwebsocket_callback_reasons reason,
266                                                void *user, void *in, size_t len)
267 {
268         int n;
269         struct per_session_data__lws_mirror *pss = user;
270
271         switch (reason) {
272
273         case LWS_CALLBACK_ESTABLISHED:
274                 fprintf(stderr, "callback_lws_mirror: "
275                                                  "LWS_CALLBACK_ESTABLISHED\n");
276                 pss->ringbuffer_tail = ringbuffer_head;
277                 pss->wsi = wsi;
278                 break;
279
280         case LWS_CALLBACK_SERVER_WRITEABLE:
281                 if (close_testing)
282                         break;
283                 if (pss->ringbuffer_tail != ringbuffer_head) {
284
285                         n = libwebsocket_write(wsi, (unsigned char *)
286                                    ringbuffer[pss->ringbuffer_tail].payload +
287                                    LWS_SEND_BUFFER_PRE_PADDING,
288                                    ringbuffer[pss->ringbuffer_tail].len,
289                                                                 LWS_WRITE_TEXT);
290                         if (n < 0) {
291                                 fprintf(stderr, "ERROR %d writing to socket\n", n);
292                                 exit(1);
293                         }
294
295                         if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
296                                 pss->ringbuffer_tail = 0;
297                         else
298                                 pss->ringbuffer_tail++;
299
300                         if (((ringbuffer_head - pss->ringbuffer_tail) %
301                                   MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15))
302                                 libwebsocket_rx_flow_control(wsi, 1);
303
304                         libwebsocket_callback_on_writable(context, wsi);
305
306                 }
307                 break;
308
309         case LWS_CALLBACK_BROADCAST:
310                 n = libwebsocket_write(wsi, in, len, LWS_WRITE_TEXT);
311                 if (n < 0)
312                         fprintf(stderr, "mirror write failed\n");
313                 break;
314
315         case LWS_CALLBACK_RECEIVE:
316
317                 if (ringbuffer[ringbuffer_head].payload)
318                         free(ringbuffer[ringbuffer_head].payload);
319
320                 ringbuffer[ringbuffer_head].payload =
321                                 malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
322                                                   LWS_SEND_BUFFER_POST_PADDING);
323                 ringbuffer[ringbuffer_head].len = len;
324                 memcpy((char *)ringbuffer[ringbuffer_head].payload +
325                                           LWS_SEND_BUFFER_PRE_PADDING, in, len);
326                 if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
327                         ringbuffer_head = 0;
328                 else
329                         ringbuffer_head++;
330
331                 if (((ringbuffer_head - pss->ringbuffer_tail) %
332                                   MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10))
333                         libwebsocket_rx_flow_control(wsi, 0);
334
335                 libwebsocket_callback_on_writable_all_protocol(
336                                                libwebsockets_get_protocol(wsi));
337                 break;
338         /*
339          * this just demonstrates how to use the protocol filter. If you won't
340          * study and reject connections based on header content, you don't need
341          * to handle this callback
342          */
343
344         case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
345                 dump_handshake_info((struct lws_tokens *)(long)user);
346                 /* you could return non-zero here and kill the connection */
347                 break;
348
349         default:
350                 break;
351         }
352
353         return 0;
354 }
355
356
357 /* list of supported protocols and callbacks */
358
359 static struct libwebsocket_protocols protocols[] = {
360         /* first protocol must always be HTTP handler */
361
362         {
363                 "http-only",            /* name */
364                 callback_http,          /* callback */
365                 0                       /* per_session_data_size */
366         },
367         {
368                 "dumb-increment-protocol",
369                 callback_dumb_increment,
370                 sizeof(struct per_session_data__dumb_increment),
371         },
372         {
373                 "lws-mirror-protocol",
374                 callback_lws_mirror,
375                 sizeof(struct per_session_data__lws_mirror)
376         },
377         {
378                 NULL, NULL, 0           /* End of list */
379         }
380 };
381
382 static struct option options[] = {
383         { "help",       no_argument,            NULL, 'h' },
384         { "debug",      required_argument,      NULL, 'd' },
385         { "port",       required_argument,      NULL, 'p' },
386         { "ssl",        no_argument,            NULL, 's' },
387         { "killmask",   no_argument,            NULL, 'k' },
388         { "interface",  required_argument,      NULL, 'i' },
389         { "closetest",  no_argument,            NULL, 'c' },
390         { NULL, 0, 0, 0 }
391 };
392
393 int main(int argc, char **argv)
394 {
395         int n = 0;
396         const char *cert_path =
397                             LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
398         const char *key_path =
399                         LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
400         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 +
401                                                   LWS_SEND_BUFFER_POST_PADDING];
402         int port = 7681;
403         int use_ssl = 0;
404         struct libwebsocket_context *context;
405         int opts = 0;
406         char interface_name[128] = "";
407         const char *interface = NULL;
408 #ifdef LWS_NO_FORK
409         unsigned int oldus = 0;
410 #endif
411
412         fprintf(stderr, "libwebsockets test server\n"
413                         "(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> "
414                                                     "licensed under LGPL2.1\n");
415
416         while (n >= 0) {
417                 n = getopt_long(argc, argv, "ci:khsp:d:", options, NULL);
418                 if (n < 0)
419                         continue;
420                 switch (n) {
421                 case 'd':
422                         lws_set_log_level(atoi(optarg), NULL);
423                         break;
424                 case 's':
425                         use_ssl = 1;
426                         break;
427                 case 'k':
428                         opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK;
429                         break;
430                 case 'p':
431                         port = atoi(optarg);
432                         break;
433                 case 'i':
434                         strncpy(interface_name, optarg, sizeof interface_name);
435                         interface_name[(sizeof interface_name) - 1] = '\0';
436                         interface = interface_name;
437                         break;
438                 case 'c':
439                         close_testing = 1;
440                         fprintf(stderr, " Close testing mode -- closes on "
441                                            "client after 50 dumb increments"
442                                            "and suppresses lws_mirror spam\n");
443                         break;
444                 case 'h':
445                         fprintf(stderr, "Usage: test-server "
446                                         "[--port=<p>] [--ssl] "
447                                         "[-d <log bitfield>]\n");
448                         exit(1);
449                 }
450         }
451
452         if (!use_ssl)
453                 cert_path = key_path = NULL;
454
455         context = libwebsocket_create_context(port, interface, protocols,
456                                 libwebsocket_internal_extensions,
457                                 cert_path, key_path, NULL, -1, -1, opts, NULL);
458         if (context == NULL) {
459                 fprintf(stderr, "libwebsocket init failed\n");
460                 return -1;
461         }
462
463         buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x';
464
465 #ifdef LWS_NO_FORK
466
467         /*
468          * This example shows how to work with no forked service loop
469          */
470
471         fprintf(stderr, " Using no-fork service loop\n");
472
473         n = 0;
474         while (n >= 0) {
475                 struct timeval tv;
476
477                 gettimeofday(&tv, NULL);
478
479                 /*
480                  * This broadcasts to all dumb-increment-protocol connections
481                  * at 20Hz.
482                  *
483                  * We're just sending a character 'x', in these examples the
484                  * callbacks send their own per-connection content.
485                  *
486                  * You have to send something with nonzero length to get the
487                  * callback actions delivered.
488                  *
489                  * We take care of pre-and-post padding allocation.
490                  */
491
492                 if (((unsigned int)tv.tv_usec - oldus) > 50000) {
493                         libwebsockets_broadcast(
494                                         &protocols[PROTOCOL_DUMB_INCREMENT],
495                                         &buf[LWS_SEND_BUFFER_PRE_PADDING], 1);
496                         oldus = tv.tv_usec;
497                 }
498
499                 /*
500                  * This example server does not fork or create a thread for
501                  * websocket service, it all runs in this single loop.  So,
502                  * we have to give the websockets an opportunity to service
503                  * "manually".
504                  *
505                  * If no socket is needing service, the call below returns
506                  * immediately and quickly.  Negative return means we are
507                  * in process of closing
508                  */
509
510                 n = libwebsocket_service(context, 50);
511         }
512
513 #else
514
515         /*
516          * This example shows how to work with the forked websocket service loop
517          */
518
519         fprintf(stderr, " Using forked service loop\n");
520
521         /*
522          * This forks the websocket service action into a subprocess so we
523          * don't have to take care about it.
524          */
525
526         n = libwebsockets_fork_service_loop(context);
527         if (n < 0) {
528                 fprintf(stderr, "Unable to fork service loop %d\n", n);
529                 return 1;
530         }
531
532         while (1) {
533
534                 usleep(50000);
535
536                 /*
537                  * This broadcasts to all dumb-increment-protocol connections
538                  * at 20Hz.
539                  *
540                  * We're just sending a character 'x', in these examples the
541                  * callbacks send their own per-connection content.
542                  *
543                  * You have to send something with nonzero length to get the
544                  * callback actions delivered.
545                  *
546                  * We take care of pre-and-post padding allocation.
547                  */
548
549                 libwebsockets_broadcast(&protocols[PROTOCOL_DUMB_INCREMENT],
550                                         &buf[LWS_SEND_BUFFER_PRE_PADDING], 1);
551         }
552
553 #endif
554
555         libwebsocket_context_destroy(context);
556
557         return 0;
558 }