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