workaround for some gcc array bounds false positive
[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 #include <assert.h>
29
30 #include "../lib/libwebsockets.h"
31
32 static int close_testing;
33
34 #ifdef EXTERNAL_POLL
35 #define LWS_NO_FORK
36 #ifndef MAX_CLIENTS
37 #define MAX_POLL_ELEMENTS 100
38 #else
39 #define MAX_POLL_ELEMENTS (MAX_CLIENTS)
40 #endif
41
42 struct poll_hash_map {
43         int fd;
44         int index;
45 };
46
47 #define POLL_HASH_BITS 8
48
49 #define POLL_HASH_BUCKETS (1 << POLL_HASH_BITS)
50 #define POLL_ENTRIES_PER_BUCKET (MAX_POLL_ELEMENTS / (1 << (POLL_HASH_BITS - 2)))
51 #define POLL_HASH(num) (num & (POLL_HASH_BUCKETS - 1))
52
53 struct pollfd pollfds[MAX_POLL_ELEMENTS];
54 struct poll_hash_map pollfd_maps[POLL_HASH_BUCKETS][POLL_ENTRIES_PER_BUCKET];
55 int pollfd_count[POLL_HASH_BUCKETS];
56 int count_pollfds = 0;
57
58 static int find_poll_map_index(int hash, int fd)
59 {
60         int n;
61
62         for (n = 0; n < pollfd_count[hash]; n++)
63                 if (pollfd_maps[hash][n].fd == fd)
64                         return n;
65
66         return -1;
67 }
68
69 static int find_pollfd_index(int fd)
70 {
71         int n;
72         int hash = POLL_HASH(fd);
73
74         n = find_poll_map_index(hash, fd);
75         if (n < 0)
76                 return n;
77
78         return pollfd_maps[hash][n].index;
79 }
80
81 #endif /* EXTERNAL_POLL */
82
83 /*
84  * This demo server shows how to use libwebsockets for one or more
85  * websocket protocols in the same server
86  *
87  * It defines the following websocket protocols:
88  *
89  *  dumb-increment-protocol:  once the socket is opened, an incrementing
90  *                              ascii string is sent down it every 50ms.
91  *                              If you send "reset\n" on the websocket, then
92  *                              the incrementing number is reset to 0.
93  *
94  *  lws-mirror-protocol: copies any received packet to every connection also
95  *                              using this protocol, including the sender
96  */
97
98 enum demo_protocols {
99         /* always first */
100         PROTOCOL_HTTP = 0,
101
102         PROTOCOL_DUMB_INCREMENT,
103         PROTOCOL_LWS_MIRROR,
104
105         /* always last */
106         DEMO_PROTOCOL_COUNT
107 };
108
109
110 #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
111
112 /*
113  * We take a strict whitelist approach to stop ../ attacks
114  */
115
116 struct serveable {
117         const char *urlpath;
118         const char *mimetype;
119 }; 
120
121 static const struct serveable whitelist[] = {
122         { "/favicon.ico", "image/x-icon" },
123         { "/libwebsockets.org-logo.png", "image/png" },
124
125         /* last one is the default served if no match */
126         { "/test.html", "text/html" },
127 };
128
129 /* this protocol server (always the first one) just knows how to do HTTP */
130
131 static int callback_http(struct libwebsocket_context *context,
132                 struct libwebsocket *wsi,
133                 enum libwebsocket_callback_reasons reason, void *user,
134                                                            void *in, size_t len)
135 {
136         char client_name[128];
137         char client_ip[128];
138         char buf[256];
139         int n;
140 #ifdef EXTERNAL_POLL
141         int m, m1;
142         int hash, hash1;
143         int fd = (int)(long)user;
144 #endif
145
146         switch (reason) {
147         case LWS_CALLBACK_HTTP:
148
149                 for (n = 0; n < (sizeof(whitelist) / sizeof(whitelist[0]) - 1); n++)
150                         if (in && strcmp(in, whitelist[n].urlpath) == 0)
151                                 break;
152
153                 sprintf(buf, LOCAL_RESOURCE_PATH"%s", whitelist[n].urlpath);
154
155                 if (libwebsockets_serve_http_file(context, wsi, buf, whitelist[n].mimetype))
156                         fprintf(stderr, "Failed to send HTTP file\n");
157
158                 /*
159                  * notice that the sending of the file completes asynchronously,
160                  * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
161                  * it's done
162                  */
163
164                 break;
165
166         case LWS_CALLBACK_HTTP_FILE_COMPLETION:
167 //              fprintf(stderr, "LWS_CALLBACK_HTTP_FILE_COMPLETION seen\n");
168                 /* kill the connection after we sent one file */
169                 return 1;
170
171         /*
172          * callback for confirming to continue with client IP appear in
173          * protocol 0 callback since no websocket protocol has been agreed
174          * yet.  You can just ignore this if you won't filter on client IP
175          * since the default uhandled callback return is 0 meaning let the
176          * connection continue.
177          */
178
179         case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
180
181                 libwebsockets_get_peer_addresses((int)(long)user, client_name,
182                              sizeof(client_name), client_ip, sizeof(client_ip));
183
184 //              fprintf(stderr, "Received network connect from %s (%s)\n",
185 //                                                      client_name, client_ip);
186
187                 /* if we returned non-zero from here, we kill the connection */
188                 break;
189
190 #ifdef EXTERNAL_POLL
191         /*
192          * callbacks for managing the external poll() array appear in
193          * protocol 0 callback
194          */
195
196         case LWS_CALLBACK_ADD_POLL_FD:
197                 if (count_pollfds == MAX_POLL_ELEMENTS) {
198                         fprintf(stderr, "LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
199                         return 1;
200                 }
201                 hash = POLL_HASH(fd);
202                 if (pollfd_count[hash] == POLL_ENTRIES_PER_BUCKET) {
203                         fprintf(stderr, "LWS_CALLBACK_ADD_POLL_FD: hash table overflow\n");
204                         return 1;
205                 }
206
207 //              fprintf(stderr, "Adding fd %d at pollfd_maps[%d][%d], pollfds[%d]\n", fd, hash, pollfd_count[hash], count_pollfds);
208
209                 pollfd_maps[hash][pollfd_count[hash]].fd = fd;
210                 pollfd_maps[hash][pollfd_count[hash]++].index = count_pollfds;
211
212                 pollfds[count_pollfds].fd = (int)(long)user;
213                 pollfds[count_pollfds].events = (int)len;
214                 pollfds[count_pollfds++].revents = 0;
215                 break;
216
217         case LWS_CALLBACK_DEL_POLL_FD:
218                 hash = POLL_HASH(fd);
219                 n = find_poll_map_index(hash, fd);
220                 if (n < 0) {
221                         fprintf(stderr, "unable to find fd %d in poll_maps\n", fd);
222                         return 1;
223                 }
224                 m = pollfd_maps[hash][n].index;
225
226                 assert(pollfds[m].fd == fd);
227                 assert(count_pollfds);
228                 assert(pollfd_count[hash]);
229
230 //              fprintf(stderr, "Removing fd %d at pollfd_maps[%d][%d], pollfds[%d]\n", fd, hash, n, m);
231
232                 /*
233                  * swap the end guy into our vacant slot...
234                  * works ok if n is the end guy
235                  */
236
237                 count_pollfds--;
238                 if (count_pollfds) {
239
240                         /* end guy... */
241                         hash1 = POLL_HASH(pollfds[count_pollfds].fd);
242                         m1 = find_poll_map_index(hash1, pollfds[count_pollfds].fd);
243                         /* your index has changed... */
244                         pollfd_maps[hash1][m1].index = m;
245
246                         pollfds[m] = pollfds[count_pollfds];
247                         pollfds[count_pollfds].fd = -1;
248                 }
249
250                 /*
251                  * similar trick with hashtable
252                  * old end guy goes into vacant slot in hash table
253                  */
254
255 /* some versions of gcc see a false positive here, workaround */
256 #ifdef __GNUC__
257 #pragma GCC diagnostic ignored "-Warray-bounds"
258 #endif
259                 pollfd_count[hash]--;
260                 if (pollfd_count[hash]) {
261                         pollfd_maps[hash][n].index = pollfd_maps[hash][pollfd_count[hash]].index;
262                         pollfd_maps[hash][n].fd = pollfd_maps[hash][pollfd_count[hash]].fd;
263                 }
264 #ifdef __GNUC__
265 #pragma GCC diagnostic pop
266 #endif
267                 break;
268
269         case LWS_CALLBACK_SET_MODE_POLL_FD:
270                 n = find_pollfd_index(fd);
271                 if (n < 0) {
272                         fprintf(stderr, "unable to find fd %d\n", fd);
273                         return 1;
274                 }
275                 if(pollfds[n].fd != fd) {
276                         fprintf(stderr, "Setting fd %d, found at pollfd_index %d, actually fd %d\n", fd, n, pollfds[n].fd);
277                         assert(0);
278                 }
279                 pollfds[n].events |= (int)(long)len;
280                 break;
281
282         case LWS_CALLBACK_CLEAR_MODE_POLL_FD:
283                 n = find_pollfd_index(fd);
284                 if (n < 0) {
285                         fprintf(stderr, "unable to find fd %d\n", fd);
286                         return 1;
287                 }
288                 assert(pollfds[n].fd == fd);
289                 pollfds[n].events &= ~(int)(long)len;
290                 break;
291 #endif
292         default:
293                 break;
294         }
295
296         return 0;
297 }
298
299
300 /*
301  * this is just an example of parsing handshake headers, you don't need this
302  * in your code unless you will filter allowing connections by the header
303  * content
304  */
305
306 static void
307 dump_handshake_info(struct lws_tokens *lwst)
308 {
309         int n;
310         static const char *token_names[WSI_TOKEN_COUNT] = {
311                 /*[WSI_TOKEN_GET_URI]           =*/ "GET URI",
312                 /*[WSI_TOKEN_HOST]              =*/ "Host",
313                 /*[WSI_TOKEN_CONNECTION]        =*/ "Connection",
314                 /*[WSI_TOKEN_KEY1]              =*/ "key 1",
315                 /*[WSI_TOKEN_KEY2]              =*/ "key 2",
316                 /*[WSI_TOKEN_PROTOCOL]          =*/ "Protocol",
317                 /*[WSI_TOKEN_UPGRADE]           =*/ "Upgrade",
318                 /*[WSI_TOKEN_ORIGIN]            =*/ "Origin",
319                 /*[WSI_TOKEN_DRAFT]             =*/ "Draft",
320                 /*[WSI_TOKEN_CHALLENGE]         =*/ "Challenge",
321
322                 /* new for 04 */
323                 /*[WSI_TOKEN_KEY]               =*/ "Key",
324                 /*[WSI_TOKEN_VERSION]           =*/ "Version",
325                 /*[WSI_TOKEN_SWORIGIN]          =*/ "Sworigin",
326
327                 /* new for 05 */
328                 /*[WSI_TOKEN_EXTENSIONS]        =*/ "Extensions",
329
330                 /* client receives these */
331                 /*[WSI_TOKEN_ACCEPT]            =*/ "Accept",
332                 /*[WSI_TOKEN_NONCE]             =*/ "Nonce",
333                 /*[WSI_TOKEN_HTTP]              =*/ "Http",
334                 /*[WSI_TOKEN_MUXURL]    =*/ "MuxURL",
335         };
336
337         for (n = 0; n < WSI_TOKEN_COUNT; n++) {
338                 if (lwst[n].token == NULL)
339                         continue;
340
341                 fprintf(stderr, "    %s = %s\n", token_names[n], lwst[n].token);
342         }
343 }
344
345 /* dumb_increment protocol */
346
347 /*
348  * one of these is auto-created for each connection and a pointer to the
349  * appropriate instance is passed to the callback in the user parameter
350  *
351  * for this example protocol we use it to individualize the count for each
352  * connection.
353  */
354
355 struct per_session_data__dumb_increment {
356         int number;
357 };
358
359 static int
360 callback_dumb_increment(struct libwebsocket_context *context,
361                         struct libwebsocket *wsi,
362                         enum libwebsocket_callback_reasons reason,
363                                                void *user, void *in, size_t len)
364 {
365         int n;
366         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
367                                                   LWS_SEND_BUFFER_POST_PADDING];
368         unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
369         struct per_session_data__dumb_increment *pss = user;
370
371         switch (reason) {
372
373         case LWS_CALLBACK_ESTABLISHED:
374                 fprintf(stderr, "callback_dumb_increment: "
375                                                  "LWS_CALLBACK_ESTABLISHED\n");
376                 pss->number = 0;
377                 break;
378
379         /*
380          * in this protocol, we just use the broadcast action as the chance to
381          * send our own connection-specific data and ignore the broadcast info
382          * that is available in the 'in' parameter
383          */
384
385         case LWS_CALLBACK_BROADCAST:
386                 n = sprintf((char *)p, "%d", pss->number++);
387                 n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
388                 if (n < 0) {
389                         fprintf(stderr, "ERROR %d writing to socket\n", n);
390                         return 1;
391                 }
392                 if (close_testing && pss->number == 50) {
393                         fprintf(stderr, "close tesing limit, closing\n");
394                         libwebsocket_close_and_free_session(context, wsi,
395                                                        LWS_CLOSE_STATUS_NORMAL);
396                 }
397                 break;
398
399         case LWS_CALLBACK_RECEIVE:
400                 fprintf(stderr, "rx %d\n", (int)len);
401                 if (len < 6)
402                         break;
403                 if (strcmp(in, "reset\n") == 0)
404                         pss->number = 0;
405                 break;
406         /*
407          * this just demonstrates how to use the protocol filter. If you won't
408          * study and reject connections based on header content, you don't need
409          * to handle this callback
410          */
411
412         case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
413                 dump_handshake_info((struct lws_tokens *)(long)user);
414                 /* you could return non-zero here and kill the connection */
415                 break;
416
417         default:
418                 break;
419         }
420
421         return 0;
422 }
423
424
425 /* lws-mirror_protocol */
426
427 #define MAX_MESSAGE_QUEUE 64
428
429 struct per_session_data__lws_mirror {
430         struct libwebsocket *wsi;
431         int ringbuffer_tail;
432 };
433
434 struct a_message {
435         void *payload;
436         size_t len;
437 };
438
439 static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
440 static int ringbuffer_head;
441
442
443 static int
444 callback_lws_mirror(struct libwebsocket_context *context,
445                         struct libwebsocket *wsi,
446                         enum libwebsocket_callback_reasons reason,
447                                                void *user, void *in, size_t len)
448 {
449         int n;
450         struct per_session_data__lws_mirror *pss = user;
451
452         switch (reason) {
453
454         case LWS_CALLBACK_ESTABLISHED:
455                 fprintf(stderr, "callback_lws_mirror: "
456                                                  "LWS_CALLBACK_ESTABLISHED\n");
457                 pss->ringbuffer_tail = ringbuffer_head;
458                 pss->wsi = wsi;
459                 break;
460
461         case LWS_CALLBACK_SERVER_WRITEABLE:
462                 if (close_testing)
463                         break;
464                 if (pss->ringbuffer_tail != ringbuffer_head) {
465
466                         n = libwebsocket_write(wsi, (unsigned char *)
467                                    ringbuffer[pss->ringbuffer_tail].payload +
468                                    LWS_SEND_BUFFER_PRE_PADDING,
469                                    ringbuffer[pss->ringbuffer_tail].len,
470                                                                 LWS_WRITE_TEXT);
471                         if (n < 0) {
472                                 fprintf(stderr, "ERROR %d writing to socket\n", n);
473                                 exit(1);
474                         }
475
476                         if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
477                                 pss->ringbuffer_tail = 0;
478                         else
479                                 pss->ringbuffer_tail++;
480
481                         if (((ringbuffer_head - pss->ringbuffer_tail) %
482                                   MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15))
483                                 libwebsocket_rx_flow_control(wsi, 1);
484
485                         libwebsocket_callback_on_writable(context, wsi);
486
487                 }
488                 break;
489
490         case LWS_CALLBACK_BROADCAST:
491                 n = libwebsocket_write(wsi, in, len, LWS_WRITE_TEXT);
492                 if (n < 0)
493                         fprintf(stderr, "mirror write failed\n");
494                 break;
495
496         case LWS_CALLBACK_RECEIVE:
497
498                 if (ringbuffer[ringbuffer_head].payload)
499                         free(ringbuffer[ringbuffer_head].payload);
500
501                 ringbuffer[ringbuffer_head].payload =
502                                 malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
503                                                   LWS_SEND_BUFFER_POST_PADDING);
504                 ringbuffer[ringbuffer_head].len = len;
505                 memcpy((char *)ringbuffer[ringbuffer_head].payload +
506                                           LWS_SEND_BUFFER_PRE_PADDING, in, len);
507                 if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
508                         ringbuffer_head = 0;
509                 else
510                         ringbuffer_head++;
511
512                 if (((ringbuffer_head - pss->ringbuffer_tail) %
513                                   MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10))
514                         libwebsocket_rx_flow_control(wsi, 0);
515
516                 libwebsocket_callback_on_writable_all_protocol(
517                                                libwebsockets_get_protocol(wsi));
518                 break;
519         /*
520          * this just demonstrates how to use the protocol filter. If you won't
521          * study and reject connections based on header content, you don't need
522          * to handle this callback
523          */
524
525         case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
526                 dump_handshake_info((struct lws_tokens *)(long)user);
527                 /* you could return non-zero here and kill the connection */
528                 break;
529
530         default:
531                 break;
532         }
533
534         return 0;
535 }
536
537
538 /* list of supported protocols and callbacks */
539
540 static struct libwebsocket_protocols protocols[] = {
541         /* first protocol must always be HTTP handler */
542
543         {
544                 "http-only",            /* name */
545                 callback_http,          /* callback */
546                 0                       /* per_session_data_size */
547         },
548         {
549                 "dumb-increment-protocol",
550                 callback_dumb_increment,
551                 sizeof(struct per_session_data__dumb_increment),
552         },
553         {
554                 "lws-mirror-protocol",
555                 callback_lws_mirror,
556                 sizeof(struct per_session_data__lws_mirror)
557         },
558         {
559                 NULL, NULL, 0           /* End of list */
560         }
561 };
562
563 static struct option options[] = {
564         { "help",       no_argument,            NULL, 'h' },
565         { "debug",      required_argument,      NULL, 'd' },
566         { "port",       required_argument,      NULL, 'p' },
567         { "ssl",        no_argument,            NULL, 's' },
568         { "killmask",   no_argument,            NULL, 'k' },
569         { "interface",  required_argument,      NULL, 'i' },
570         { "closetest",  no_argument,            NULL, 'c' },
571         { NULL, 0, 0, 0 }
572 };
573
574 int main(int argc, char **argv)
575 {
576         int n = 0;
577         const char *cert_path =
578                             LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
579         const char *key_path =
580                         LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
581         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 +
582                                                   LWS_SEND_BUFFER_POST_PADDING];
583         int port = 7681;
584         int use_ssl = 0;
585         struct libwebsocket_context *context;
586         int opts = 0;
587         char interface_name[128] = "";
588         const char *interface = NULL;
589 #ifdef LWS_NO_FORK
590         unsigned int oldus = 0;
591 #endif
592
593         fprintf(stderr, "libwebsockets test server\n"
594                         "(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> "
595                                                     "licensed under LGPL2.1\n");
596
597         while (n >= 0) {
598                 n = getopt_long(argc, argv, "ci:khsp:d:", options, NULL);
599                 if (n < 0)
600                         continue;
601                 switch (n) {
602                 case 'd':
603                         lws_set_log_level(atoi(optarg), NULL);
604                         break;
605                 case 's':
606                         use_ssl = 1;
607                         break;
608                 case 'k':
609                         opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK;
610                         break;
611                 case 'p':
612                         port = atoi(optarg);
613                         break;
614                 case 'i':
615                         strncpy(interface_name, optarg, sizeof interface_name);
616                         interface_name[(sizeof interface_name) - 1] = '\0';
617                         interface = interface_name;
618                         break;
619                 case 'c':
620                         close_testing = 1;
621                         fprintf(stderr, " Close testing mode -- closes on "
622                                            "client after 50 dumb increments"
623                                            "and suppresses lws_mirror spam\n");
624                         break;
625                 case 'h':
626                         fprintf(stderr, "Usage: test-server "
627                                         "[--port=<p>] [--ssl] "
628                                         "[-d <log bitfield>]\n");
629                         exit(1);
630                 }
631         }
632
633         if (!use_ssl)
634                 cert_path = key_path = NULL;
635
636         context = libwebsocket_create_context(port, interface, protocols,
637                                 libwebsocket_internal_extensions,
638                                 cert_path, key_path, NULL, -1, -1, opts, NULL);
639         if (context == NULL) {
640                 fprintf(stderr, "libwebsocket init failed\n");
641                 return -1;
642         }
643
644         buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x';
645
646 #ifdef LWS_NO_FORK
647
648         /*
649          * This example shows how to work with no forked service loop
650          */
651
652         fprintf(stderr, " Using no-fork service loop\n");
653
654         n = 0;
655         while (n >= 0) {
656                 struct timeval tv;
657
658                 gettimeofday(&tv, NULL);
659
660                 /*
661                  * This broadcasts to all dumb-increment-protocol connections
662                  * at 20Hz.
663                  *
664                  * We're just sending a character 'x', in these examples the
665                  * callbacks send their own per-connection content.
666                  *
667                  * You have to send something with nonzero length to get the
668                  * callback actions delivered.
669                  *
670                  * We take care of pre-and-post padding allocation.
671                  */
672
673                 if (((unsigned int)tv.tv_usec - oldus) > 50000) {
674                         libwebsockets_broadcast(
675                                         &protocols[PROTOCOL_DUMB_INCREMENT],
676                                         &buf[LWS_SEND_BUFFER_PRE_PADDING], 1);
677                         oldus = tv.tv_usec;
678                 }
679
680                 /*
681                  * This example server does not fork or create a thread for
682                  * websocket service, it all runs in this single loop.  So,
683                  * we have to give the websockets an opportunity to service
684                  * "manually".
685                  *
686                  * If no socket is needing service, the call below returns
687                  * immediately and quickly.  Negative return means we are
688                  * in process of closing
689                  */
690 #ifdef EXTERNAL_POLL
691
692                 /*
693                  * this represents an existing server's single poll action
694                  * which also includes libwebsocket sockets
695                  */
696
697                 n = poll(pollfds, count_pollfds, 50);
698                 if (n < 0)
699                         continue;
700
701
702                 if (n)
703                         for (n = 0; n < count_pollfds; n++)
704                                 if (pollfds[n].revents)
705                                         /*
706                                         * returns immediately if the fd does not
707                                         * match anything under libwebsockets
708                                         * control
709                                         */
710                                         if (libwebsocket_service_fd(context,
711                                                                   &pollfds[n]) < 0)
712                                                 goto done;
713 #else
714                 n = libwebsocket_service(context, 50);
715 #endif
716         }
717
718 #else /* !LWS_NO_FORK */
719
720         /*
721          * This example shows how to work with the forked websocket service loop
722          */
723
724         fprintf(stderr, " Using forked service loop\n");
725
726         /*
727          * This forks the websocket service action into a subprocess so we
728          * don't have to take care about it.
729          */
730
731         n = libwebsockets_fork_service_loop(context);
732         if (n < 0) {
733                 fprintf(stderr, "Unable to fork service loop %d\n", n);
734                 return 1;
735         }
736
737         while (1) {
738
739                 usleep(50000);
740
741                 /*
742                  * This broadcasts to all dumb-increment-protocol connections
743                  * at 20Hz.
744                  *
745                  * We're just sending a character 'x', in these examples the
746                  * callbacks send their own per-connection content.
747                  *
748                  * You have to send something with nonzero length to get the
749                  * callback actions delivered.
750                  *
751                  * We take care of pre-and-post padding allocation.
752                  */
753
754                 libwebsockets_broadcast(&protocols[PROTOCOL_DUMB_INCREMENT],
755                                         &buf[LWS_SEND_BUFFER_PRE_PADDING], 1);
756         }
757
758 #endif
759 #ifdef EXTERNAL_POLL
760 done:
761 #endif
762
763         libwebsocket_context_destroy(context);
764
765         return 0;
766 }