f4995c7c66357d247361f0aaf50fa752b6f3022d
[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
32 /*
33  * This demo server shows how to use libwebsockets for one or more
34  * websocket protocols in the same server
35  *
36  * It defines the following websocket protocols:
37  *
38  *  dumb-increment-protocol:  once the socket is opened, an incrementing
39  *                              ascii string is sent down it every 50ms.
40  *                              If you send "reset\n" on the websocket, then
41  *                              the incrementing number is reset to 0.
42  *
43  *  lws-mirror-protocol: copies any received packet to every connection also
44  *                              using this protocol, including the sender
45  */
46
47 enum demo_protocols {
48         /* always first */
49         PROTOCOL_HTTP = 0,
50
51         PROTOCOL_DUMB_INCREMENT,
52         PROTOCOL_LWS_MIRROR,
53
54         /* always last */
55         DEMO_PROTOCOL_COUNT
56 };
57
58
59 #define LOCAL_RESOURCE_PATH DATADIR"/libwebsockets-test-server"
60
61 /* this protocol server (always the first one) just knows how to do HTTP */
62
63 static int callback_http(struct libwebsocket *wsi,
64                 enum libwebsocket_callback_reasons reason, void *user,
65                                                            void *in, size_t len)
66 {
67         char client_name[128];
68         char client_ip[128];
69
70         switch (reason) {
71         case LWS_CALLBACK_HTTP:
72                 fprintf(stderr, "serving HTTP URI %s\n", (char *)in);
73
74                 if (in && strcmp(in, "/favicon.ico") == 0) {
75                         if (libwebsockets_serve_http_file(wsi,
76                              LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon"))
77                                 fprintf(stderr, "Failed to send favicon\n");
78                         break;
79                 }
80
81                 /* send the script... when it runs it'll start websockets */
82
83                 if (libwebsockets_serve_http_file(wsi,
84                                   LOCAL_RESOURCE_PATH"/test.html", "text/html"))
85                         fprintf(stderr, "Failed to send HTTP file\n");
86                 break;
87
88         /*
89          * callback for confirming to continue with client IP appear in
90          * protocol 0 callback since no websocket protocol has been agreed
91          * yet.  You can just ignore this if you won't filter on client IP
92          * since the default uhandled callback return is 0 meaning let the
93          * connection continue.
94          */
95
96         case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
97
98                 libwebsockets_get_peer_addresses((int)(long)user, client_name,
99                              sizeof(client_name), client_ip, sizeof(client_ip));
100
101                 fprintf(stderr, "Received network connect from %s (%s)\n",
102                                                         client_name, client_ip);
103
104                 /* if we returned non-zero from here, we kill the connection */
105                 break;
106
107         default:
108                 break;
109         }
110
111         return 0;
112 }
113
114 /* dumb_increment protocol */
115
116 /*
117  * one of these is auto-created for each connection and a pointer to the
118  * appropriate instance is passed to the callback in the user parameter
119  *
120  * for this example protocol we use it to individualize the count for each
121  * connection.
122  */
123
124 struct per_session_data__dumb_increment {
125         int number;
126 };
127
128 static int
129 callback_dumb_increment(struct libwebsocket *wsi,
130                         enum libwebsocket_callback_reasons reason,
131                                                void *user, void *in, size_t len)
132 {
133         int n;
134         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
135                                                   LWS_SEND_BUFFER_POST_PADDING];
136         unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
137         struct per_session_data__dumb_increment *pss = user;
138
139         switch (reason) {
140
141         case LWS_CALLBACK_ESTABLISHED:
142                 pss->number = 0;
143                 break;
144
145         /*
146          * in this protocol, we just use the broadcast action as the chance to
147          * send our own connection-specific data and ignore the broadcast info
148          * that is available in the 'in' parameter
149          */
150
151         case LWS_CALLBACK_BROADCAST:
152                 n = sprintf((char *)p, "%d", pss->number++);
153                 n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
154                 if (n < 0) {
155                         fprintf(stderr, "ERROR writing to socket");
156                         return 1;
157                 }
158                 break;
159
160         case LWS_CALLBACK_RECEIVE:
161                 fprintf(stderr, "rx %d\n", (int)len);
162                 if (len < 6)
163                         break;
164                 if (strcmp(in, "reset\n") == 0)
165                         pss->number = 0;
166                 break;
167
168         default:
169                 break;
170         }
171
172         return 0;
173 }
174
175
176 /* lws-mirror_protocol */
177
178 #define MAX_MESSAGE_QUEUE 64
179
180 struct per_session_data__lws_mirror {
181         struct libwebsocket *wsi;
182         int ringbuffer_tail;
183 };
184
185 struct a_message {
186         void *payload;
187         size_t len;
188 };
189
190 static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
191 static int ringbuffer_head;
192
193
194 static int
195 callback_lws_mirror(struct libwebsocket *wsi,
196                         enum libwebsocket_callback_reasons reason,
197                                                void *user, void *in, size_t len)
198 {
199         int n;
200         struct per_session_data__lws_mirror *pss = user;
201
202         switch (reason) {
203
204         case LWS_CALLBACK_ESTABLISHED:
205                 pss->ringbuffer_tail = ringbuffer_head;
206                 pss->wsi = wsi;
207                 break;
208
209         case LWS_CALLBACK_CLIENT_WRITEABLE:
210                 if (pss->ringbuffer_tail != ringbuffer_head) {
211
212                         n = libwebsocket_write(wsi, (unsigned char *)
213                                    ringbuffer[pss->ringbuffer_tail].payload +
214                                    LWS_SEND_BUFFER_PRE_PADDING,
215                                    ringbuffer[pss->ringbuffer_tail].len,
216                                                                 LWS_WRITE_TEXT);
217                         if (n < 0) {
218                                 fprintf(stderr, "ERROR writing to socket");
219                                 exit(1);
220                         }
221
222                         if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
223                                 pss->ringbuffer_tail = 0;
224                         else
225                                 pss->ringbuffer_tail++;
226
227                         if (((ringbuffer_head - pss->ringbuffer_tail) %
228                                   MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15))
229                                 libwebsocket_rx_flow_control(wsi, 1);
230
231                         libwebsocket_callback_on_writable(wsi);
232
233                 }
234                 break;
235
236         case LWS_CALLBACK_BROADCAST:
237                 n = libwebsocket_write(wsi, in, len, LWS_WRITE_TEXT);
238                 if (n < 0)
239                         fprintf(stderr, "mirror write failed\n");
240                 break;
241
242         case LWS_CALLBACK_RECEIVE:
243
244                 if (ringbuffer[ringbuffer_head].payload)
245                         free(ringbuffer[ringbuffer_head].payload);
246
247                 ringbuffer[ringbuffer_head].payload =
248                                 malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
249                                                   LWS_SEND_BUFFER_POST_PADDING);
250                 ringbuffer[ringbuffer_head].len = len;
251                 memcpy((char *)ringbuffer[ringbuffer_head].payload +
252                                           LWS_SEND_BUFFER_PRE_PADDING, in, len);
253                 if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
254                         ringbuffer_head = 0;
255                 else
256                         ringbuffer_head++;
257
258                 if (((ringbuffer_head - pss->ringbuffer_tail) %
259                                   MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10))
260                         libwebsocket_rx_flow_control(wsi, 0);
261
262                 libwebsocket_callback_on_writable_all_protocol(
263                                                libwebsockets_get_protocol(wsi));
264                 break;
265
266         default:
267                 break;
268         }
269
270         return 0;
271 }
272
273
274 /* list of supported protocols and callbacks */
275
276 static struct libwebsocket_protocols protocols[] = {
277         /* first protocol must always be HTTP handler */
278         [PROTOCOL_HTTP] = {
279                 .name = "http-only",
280                 .callback = callback_http,
281         },
282         [PROTOCOL_DUMB_INCREMENT] = {
283                 .name = "dumb-increment-protocol",
284                 .callback = callback_dumb_increment,
285                 .per_session_data_size =
286                                 sizeof(struct per_session_data__dumb_increment),
287         },
288         [PROTOCOL_LWS_MIRROR] = {
289                 .name = "lws-mirror-protocol",
290                 .callback = callback_lws_mirror,
291                 .per_session_data_size =
292                                 sizeof(struct per_session_data__lws_mirror),
293         },
294         [DEMO_PROTOCOL_COUNT] = {  /* end of list */
295                 .callback = NULL
296         }
297 };
298
299 static struct option options[] = {
300         { "help",       no_argument,            NULL, 'h' },
301         { "port",       required_argument,      NULL, 'p' },
302         { "ssl",        no_argument,            NULL, 's' },
303         { "killmask",   no_argument,            NULL, 'k' },
304         { NULL, 0, 0, 0 }
305 };
306
307 int main(int argc, char **argv)
308 {
309         int n = 0;
310         const char *cert_path =
311                             LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
312         const char *key_path =
313                         LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
314         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 +
315                                                   LWS_SEND_BUFFER_POST_PADDING];
316         int port = 7681;
317         int use_ssl = 0;
318         struct libwebsocket_context *context;
319         int opts = 0;
320 #ifdef LWS_NO_FORK
321         unsigned int oldus = 0;
322 #endif
323
324         fprintf(stderr, "libwebsockets test server\n"
325                         "(C) Copyright 2010-2011 Andy Green <andy@warmcat.com> "
326                                                     "licensed under LGPL2.1\n");
327
328         while (n >= 0) {
329                 n = getopt_long(argc, argv, "khsp:", options, NULL);
330                 if (n < 0)
331                         continue;
332                 switch (n) {
333                 case 's':
334                         use_ssl = 1;
335                         break;
336                 case 'k':
337                         opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK;
338                         break;
339                 case 'p':
340                         port = atoi(optarg);
341                         break;
342                 case 'h':
343                         fprintf(stderr, "Usage: test-server "
344                                              "[--port=<p>] [--ssl]\n");
345                         exit(1);
346                 }
347         }
348
349         if (!use_ssl)
350                 cert_path = key_path = NULL;
351
352         context = libwebsocket_create_context(port, protocols, cert_path,
353                                                 key_path, -1, -1, opts);
354         if (context == NULL) {
355                 fprintf(stderr, "libwebsocket init failed\n");
356                 return -1;
357         }
358
359         buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x';
360
361 #ifdef LWS_NO_FORK
362
363         /*
364          * This example shows how to work with no forked service loop
365          */
366
367         fprintf(stderr, " Using no-fork service loop\n");
368
369         while (1) {
370                 struct timeval tv;
371
372                 gettimeofday(&tv, NULL);
373
374                 /*
375                  * This broadcasts to all dumb-increment-protocol connections
376                  * at 20Hz.
377                  *
378                  * We're just sending a character 'x', in these examples the
379                  * callbacks send their own per-connection content.
380                  *
381                  * You have to send something with nonzero length to get the
382                  * callback actions delivered.
383                  *
384                  * We take care of pre-and-post padding allocation.
385                  */
386
387                 if (((unsigned int)tv.tv_usec - oldus) > 50000) {
388                         libwebsockets_broadcast(
389                                         &protocols[PROTOCOL_DUMB_INCREMENT],
390                                         &buf[LWS_SEND_BUFFER_PRE_PADDING], 1);
391                         oldus = tv.tv_usec;
392                 }
393
394                 /*
395                  * This example server does not fork or create a thread for
396                  * websocket service, it all runs in this single loop.  So,
397                  * we have to give the websockets an opportunity to service
398                  * "manually".
399                  *
400                  * If no socket is needing service, the call below returns
401                  * immediately and quickly.
402                  */
403
404                 libwebsocket_service(context, 50);
405         }
406
407 #else
408
409         /*
410          * This example shows how to work with the forked websocket service loop
411          */
412
413         fprintf(stderr, " Using forked service loop\n");
414
415         /*
416          * This forks the websocket service action into a subprocess so we
417          * don't have to take care about it.
418          */
419
420         n = libwebsockets_fork_service_loop(context);
421         if (n < 0) {
422                 fprintf(stderr, "Unable to fork service loop %d\n", n);
423                 return 1;
424         }
425
426         while (1) {
427
428                 usleep(50000);
429
430                 /*
431                  * This broadcasts to all dumb-increment-protocol connections
432                  * at 20Hz.
433                  *
434                  * We're just sending a character 'x', in these examples the
435                  * callbacks send their own per-connection content.
436                  *
437                  * You have to send something with nonzero length to get the
438                  * callback actions delivered.
439                  *
440                  * We take care of pre-and-post padding allocation.
441                  */
442
443                 libwebsockets_broadcast(&protocols[PROTOCOL_DUMB_INCREMENT],
444                                         &buf[LWS_SEND_BUFFER_PRE_PADDING], 1);
445         }
446
447 #endif
448
449         libwebsocket_context_destroy(context);
450
451         return 0;
452 }