blob: dacc22fa22253cf5c40355ac2f4f08e03f170903 [file] [log] [blame]
Andy Greena0da8a82010-11-08 17:12:19 +00001/*
2 * libwebsockets-test-server - libwebsockets test implementation
Andy Greene77ddd82010-11-13 10:03:47 +00003 *
Andy Green6964bb52011-01-23 16:50:33 +00004 * Copyright (C) 2010-2011 Andy Green <andy@warmcat.com>
Andy Greena0da8a82010-11-08 17:12:19 +00005 *
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 */
Joakim Soderbergd2edfec2013-02-06 15:27:27 +090021#ifdef CMAKE_BUILD
22#include "lws_config.h"
23#endif
Andy Greena0da8a82010-11-08 17:12:19 +000024
Andy Green775c0dd2010-10-29 14:15:22 +010025#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
Andy Greenea71ed12010-10-31 07:40:33 +000028#include <getopt.h>
Andy Green5fd8a5e2010-10-31 11:57:17 +000029#include <string.h>
Andy Green90c7cbc2011-01-27 06:26:52 +000030#include <sys/time.h>
Andy Greenfbf48222013-02-14 23:06:37 +080031#include <sys/stat.h>
32#include <fcntl.h>
Andy Green5fc460c2013-01-15 19:44:33 +080033#include <assert.h>
Joakim Soderbergf272cb02013-02-13 09:29:26 +080034#ifdef WIN32
35
36#ifdef EXTERNAL_POLL
37 #ifndef WIN32_LEAN_AND_MEAN
38 #define WIN32_LEAN_AND_MEAN
39 #endif
40 #include <winsock2.h>
41 #include <ws2tcpip.h>
42 #include <stddef.h>
43
44 #include "websock-w32.h"
45#endif
46
47#else // NOT WIN32
Andy Green058ba812013-01-19 11:32:18 +080048#include <syslog.h>
Joakim Soderberg4c531232013-02-06 15:26:58 +090049#endif
Joakim Soderbergf272cb02013-02-13 09:29:26 +080050
Andy Green08f2c012013-01-30 08:02:26 +080051#include <signal.h>
Andy Green5fd8a5e2010-10-31 11:57:17 +000052
Andy Green7310e9c2010-11-01 09:12:17 +000053#include "../lib/libwebsockets.h"
Andy Green775c0dd2010-10-29 14:15:22 +010054
Andy Green69758fa2011-03-07 07:08:07 +000055static int close_testing;
Edwin van den Oetelaar596b2202013-01-20 20:51:14 +080056int max_poll_elements;
Andy Green5fc460c2013-01-15 19:44:33 +080057
Edwin van den Oetelaar596b2202013-01-20 20:51:14 +080058struct pollfd *pollfds;
59int *fd_lookup;
Edwin van der Oetelaar6c720c42013-01-17 11:16:15 +080060int count_pollfds;
Andy Green08f2c012013-01-30 08:02:26 +080061int force_exit = 0;
Andy Greenfd6764a2013-01-19 11:11:42 +080062
Andy Greenfe2a0d22010-11-12 13:10:40 +000063/*
64 * This demo server shows how to use libwebsockets for one or more
65 * websocket protocols in the same server
66 *
67 * It defines the following websocket protocols:
68 *
69 * dumb-increment-protocol: once the socket is opened, an incrementing
70 * ascii string is sent down it every 50ms.
Andy Green90c7cbc2011-01-27 06:26:52 +000071 * If you send "reset\n" on the websocket, then
72 * the incrementing number is reset to 0.
Andy Green51959682010-11-12 14:12:13 +000073 *
74 * lws-mirror-protocol: copies any received packet to every connection also
Andy Green90c7cbc2011-01-27 06:26:52 +000075 * using this protocol, including the sender
Andy Greenfe2a0d22010-11-12 13:10:40 +000076 */
77
Andy Greenc87fc2f2011-01-18 15:29:04 +000078enum demo_protocols {
79 /* always first */
80 PROTOCOL_HTTP = 0,
81
82 PROTOCOL_DUMB_INCREMENT,
83 PROTOCOL_LWS_MIRROR,
84
85 /* always last */
86 DEMO_PROTOCOL_COUNT
87};
88
Andy Greenfe2a0d22010-11-12 13:10:40 +000089
Andy Greencce2a812012-04-12 11:06:05 +080090#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
Joakim Soderbergf0ee6692013-03-18 17:08:25 +000091char *resource_path = LOCAL_RESOURCE_PATH;
Andy Green775c0dd2010-10-29 14:15:22 +010092
Andy Greenbb2dc8a2013-01-16 10:06:28 +080093/*
94 * We take a strict whitelist approach to stop ../ attacks
95 */
96
97struct serveable {
98 const char *urlpath;
99 const char *mimetype;
100};
101
102static const struct serveable whitelist[] = {
103 { "/favicon.ico", "image/x-icon" },
104 { "/libwebsockets.org-logo.png", "image/png" },
105
106 /* last one is the default served if no match */
107 { "/test.html", "text/html" },
108};
109
Andy Greenfbf48222013-02-14 23:06:37 +0800110struct per_session_data__http {
111 int fd;
112};
113
Andy Green4f3943a2010-11-12 10:44:16 +0000114/* this protocol server (always the first one) just knows how to do HTTP */
Andy Green251f6fa2010-11-03 11:13:06 +0000115
Andy Green6ee372f2012-04-09 15:09:01 +0800116static int callback_http(struct libwebsocket_context *context,
Andy Green62c54d22011-02-14 09:14:25 +0000117 struct libwebsocket *wsi,
Andy Greene77ddd82010-11-13 10:03:47 +0000118 enum libwebsocket_callback_reasons reason, void *user,
Andy Green251f6fa2010-11-03 11:13:06 +0000119 void *in, size_t len)
Andy Green775c0dd2010-10-29 14:15:22 +0100120{
Andy Green058ba812013-01-19 11:32:18 +0800121#if 0
Andy Green863d4d22011-02-13 08:40:37 +0000122 char client_name[128];
123 char client_ip[128];
Andy Green058ba812013-01-19 11:32:18 +0800124#endif
Andy Greenbb2dc8a2013-01-16 10:06:28 +0800125 char buf[256];
Andy Greend91561c2013-04-30 06:51:10 +0800126 char leaf_path[1024];
Andy Green6cd88802013-11-09 11:06:29 +0800127 char b64[64];
128 struct timeval tv;
Andy Greenfc7c5e42013-02-23 10:50:10 +0800129 int n, m;
Andy Greenfbf48222013-02-14 23:06:37 +0800130 unsigned char *p;
Andy Green6cd88802013-11-09 11:06:29 +0800131 char *other_headers;
Andy Green73a820a2013-02-18 11:32:49 +0800132 static unsigned char buffer[4096];
Andy Greenfbf48222013-02-14 23:06:37 +0800133 struct stat stat_buf;
Andy Greend91561c2013-04-30 06:51:10 +0800134 struct per_session_data__http *pss =
135 (struct per_session_data__http *)user;
Andy Greena50dd1a2013-01-15 12:39:48 +0800136#ifdef EXTERNAL_POLL
Andy Green50097dd2013-02-15 22:36:30 +0800137 int fd = (int)(long)in;
Andy Greena50dd1a2013-01-15 12:39:48 +0800138#endif
Andy Green863d4d22011-02-13 08:40:37 +0000139
Andy Green775c0dd2010-10-29 14:15:22 +0100140 switch (reason) {
Andy Green5fd8a5e2010-10-31 11:57:17 +0000141 case LWS_CALLBACK_HTTP:
Andy Greene77ddd82010-11-13 10:03:47 +0000142
Andy Greenfbf48222013-02-14 23:06:37 +0800143 /* check for the "send a big file by hand" example case */
144
145 if (!strcmp((const char *)in, "/leaf.jpg")) {
Andy Greend91561c2013-04-30 06:51:10 +0800146 if (strlen(resource_path) > sizeof(leaf_path) - 10)
147 return -1;
148 sprintf(leaf_path, "%s/leaf.jpg", resource_path);
Andy Greenfbf48222013-02-14 23:06:37 +0800149
150 /* well, let's demonstrate how to send the hard way */
151
152 p = buffer;
153
Michel Archambaulte8c00aa2013-03-14 11:45:49 -0400154#ifdef WIN32
Joakim Soderbergf0ee6692013-03-18 17:08:25 +0000155 pss->fd = open(leaf_path, O_RDONLY | _O_BINARY);
Michel Archambaulte8c00aa2013-03-14 11:45:49 -0400156#else
Joakim Soderbergf0ee6692013-03-18 17:08:25 +0000157 pss->fd = open(leaf_path, O_RDONLY);
Michel Archambaulte8c00aa2013-03-14 11:45:49 -0400158#endif
159
Andy Greenfbf48222013-02-14 23:06:37 +0800160 if (pss->fd < 0)
161 return -1;
162
163 fstat(pss->fd, &stat_buf);
164
165 /*
166 * we will send a big jpeg file, but it could be
167 * anything. Set the Content-Type: appropriately
168 * so the browser knows what to do with it.
169 */
170
171 p += sprintf((char *)p,
172 "HTTP/1.0 200 OK\x0d\x0a"
173 "Server: libwebsockets\x0d\x0a"
Luce46043c2013-02-23 11:01:21 +0800174 "Content-Type: image/jpeg\x0d\x0a"
Andy Greenfbf48222013-02-14 23:06:37 +0800175 "Content-Length: %u\x0d\x0a\x0d\x0a",
176 (unsigned int)stat_buf.st_size);
177
178 /*
179 * send the http headers...
180 * this won't block since it's the first payload sent
181 * on the connection since it was established
Andy Greenfc7c5e42013-02-23 10:50:10 +0800182 * (too small for partial)
Andy Greenfbf48222013-02-14 23:06:37 +0800183 */
184
185 n = libwebsocket_write(wsi, buffer,
186 p - buffer, LWS_WRITE_HTTP);
187
188 if (n < 0) {
189 close(pss->fd);
190 return -1;
191 }
192 /*
193 * book us a LWS_CALLBACK_HTTP_WRITEABLE callback
194 */
195 libwebsocket_callback_on_writable(context, wsi);
196 break;
197 }
198
199 /* if not, send a file the easy way */
200
Andy Greenbb2dc8a2013-01-16 10:06:28 +0800201 for (n = 0; n < (sizeof(whitelist) / sizeof(whitelist[0]) - 1); n++)
Andy Green36eb70d2013-02-01 08:42:15 +0800202 if (in && strcmp((const char *)in, whitelist[n].urlpath) == 0)
Andy Greenbb2dc8a2013-01-16 10:06:28 +0800203 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000204
Joakim Soderbergf0ee6692013-03-18 17:08:25 +0000205 sprintf(buf, "%s%s", resource_path, whitelist[n].urlpath);
Andy Green5fd8a5e2010-10-31 11:57:17 +0000206
Andy Green6cd88802013-11-09 11:06:29 +0800207 /* demostrates how to set a cookie on / */
208
209 other_headers = NULL;
210 if (!strcmp((const char *)in, "/") &&
211 !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
212 /* this isn't very unguessable but it'll do for us */
213 gettimeofday(&tv, NULL);
214 sprintf(b64, "LWS_%u_%u_COOKIE",
215 (unsigned int)tv.tv_sec,
216 (unsigned int)tv.tv_usec);
217
218 sprintf(leaf_path,
219 "Set-Cookie: test=LWS_%u_%u_COOKIE;Max-Age=360000\x0d\x0a",
220 (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec);
221 other_headers = leaf_path;
222 lwsl_err(other_headers);
223 }
224
225 if (libwebsockets_serve_http_file(context, wsi, buf,
226 whitelist[n].mimetype, other_headers))
Andy Greenfbf48222013-02-14 23:06:37 +0800227 return -1; /* through completion or error, close the socket */
Andy Green24b588b2013-01-13 09:53:18 +0800228
Andy Greend280b6e2013-01-15 13:40:23 +0800229 /*
230 * notice that the sending of the file completes asynchronously,
231 * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
232 * it's done
233 */
234
Andy Greenbb2dc8a2013-01-16 10:06:28 +0800235 break;
Andy Greend280b6e2013-01-15 13:40:23 +0800236
237 case LWS_CALLBACK_HTTP_FILE_COMPLETION:
Andy Green058ba812013-01-19 11:32:18 +0800238// lwsl_info("LWS_CALLBACK_HTTP_FILE_COMPLETION seen\n");
Andy Greend280b6e2013-01-15 13:40:23 +0800239 /* kill the connection after we sent one file */
Andy Greenfbf48222013-02-14 23:06:37 +0800240 return -1;
241
242 case LWS_CALLBACK_HTTP_WRITEABLE:
243 /*
244 * we can send more of whatever it is we were sending
245 */
246
247 do {
248 n = read(pss->fd, buffer, sizeof buffer);
249 /* problem reading, close conn */
250 if (n < 0)
251 goto bail;
252 /* sent it all, close conn */
253 if (n == 0)
254 goto bail;
255 /*
256 * because it's HTTP and not websocket, don't need to take
257 * care about pre and postamble
258 */
Andy Greenfc7c5e42013-02-23 10:50:10 +0800259 m = libwebsocket_write(wsi, buffer, n, LWS_WRITE_HTTP);
260 if (m < 0)
Andy Greenfbf48222013-02-14 23:06:37 +0800261 /* write failed, close conn */
262 goto bail;
Andy Greenfc7c5e42013-02-23 10:50:10 +0800263 if (m != n)
264 /* partial write, adjust */
265 lseek(pss->fd, m - n, SEEK_CUR);
Andy Greenfbf48222013-02-14 23:06:37 +0800266
267 } while (!lws_send_pipe_choked(wsi));
268 libwebsocket_callback_on_writable(context, wsi);
269 break;
270
271bail:
272 close(pss->fd);
273 return -1;
Andy Greena2b0ab02010-11-11 12:28:29 +0000274
Andy Green863d4d22011-02-13 08:40:37 +0000275 /*
276 * callback for confirming to continue with client IP appear in
277 * protocol 0 callback since no websocket protocol has been agreed
278 * yet. You can just ignore this if you won't filter on client IP
279 * since the default uhandled callback return is 0 meaning let the
280 * connection continue.
281 */
282
283 case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
Andy Green058ba812013-01-19 11:32:18 +0800284#if 0
Edwin van den Oetelaar8c8a8e12013-02-20 20:56:59 +0800285 libwebsockets_get_peer_addresses(context, wsi, (int)(long)in, client_name,
Andy Green863d4d22011-02-13 08:40:37 +0000286 sizeof(client_name), client_ip, sizeof(client_ip));
287
Andy Green058ba812013-01-19 11:32:18 +0800288 fprintf(stderr, "Received network connect from %s (%s)\n",
289 client_name, client_ip);
290#endif
Andy Green863d4d22011-02-13 08:40:37 +0000291 /* if we returned non-zero from here, we kill the connection */
292 break;
293
Andy Greena50dd1a2013-01-15 12:39:48 +0800294#ifdef EXTERNAL_POLL
295 /*
296 * callbacks for managing the external poll() array appear in
297 * protocol 0 callback
298 */
299
300 case LWS_CALLBACK_ADD_POLL_FD:
Edwin van der Oetelaar6c720c42013-01-17 11:16:15 +0800301
Edwin van den Oetelaar596b2202013-01-20 20:51:14 +0800302 if (count_pollfds >= max_poll_elements) {
Andy Green058ba812013-01-19 11:32:18 +0800303 lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
Andy Greena50dd1a2013-01-15 12:39:48 +0800304 return 1;
Andy Green5fc460c2013-01-15 19:44:33 +0800305 }
Andy Green5fc460c2013-01-15 19:44:33 +0800306
Edwin van der Oetelaar6c720c42013-01-17 11:16:15 +0800307 fd_lookup[fd] = count_pollfds;
308 pollfds[count_pollfds].fd = fd;
309 pollfds[count_pollfds].events = (int)(long)len;
Andy Greena50dd1a2013-01-15 12:39:48 +0800310 pollfds[count_pollfds++].revents = 0;
311 break;
312
313 case LWS_CALLBACK_DEL_POLL_FD:
Edwin van der Oetelaar6c720c42013-01-17 11:16:15 +0800314 if (!--count_pollfds)
315 break;
316 m = fd_lookup[fd];
317 /* have the last guy take up the vacant slot */
318 pollfds[m] = pollfds[count_pollfds];
319 fd_lookup[pollfds[count_pollfds].fd] = m;
Andy Greena50dd1a2013-01-15 12:39:48 +0800320 break;
321
322 case LWS_CALLBACK_SET_MODE_POLL_FD:
Edwin van der Oetelaar6c720c42013-01-17 11:16:15 +0800323 pollfds[fd_lookup[fd]].events |= (int)(long)len;
Andy Greena50dd1a2013-01-15 12:39:48 +0800324 break;
325
326 case LWS_CALLBACK_CLEAR_MODE_POLL_FD:
Edwin van der Oetelaar6c720c42013-01-17 11:16:15 +0800327 pollfds[fd_lookup[fd]].events &= ~(int)(long)len;
Andy Greena50dd1a2013-01-15 12:39:48 +0800328 break;
329#endif
Edwin van der Oetelaar6c720c42013-01-17 11:16:15 +0800330
Andy Green4f3943a2010-11-12 10:44:16 +0000331 default:
332 break;
Andy Green775c0dd2010-10-29 14:15:22 +0100333 }
Andy Greenab990e42010-10-31 12:42:52 +0000334
Andy Green775c0dd2010-10-29 14:15:22 +0100335 return 0;
336}
337
Andy Green38c4f0c2011-02-13 08:54:05 +0000338/*
339 * this is just an example of parsing handshake headers, you don't need this
340 * in your code unless you will filter allowing connections by the header
341 * content
342 */
343
344static void
Andy Green16ab3182013-02-10 18:02:31 +0800345dump_handshake_info(struct libwebsocket *wsi)
Andy Green38c4f0c2011-02-13 08:54:05 +0000346{
347 int n;
Andy Green6cd88802013-11-09 11:06:29 +0800348 static const char *token_names[] = {
Peter Hinz56885f32011-03-02 22:03:47 +0000349 /*[WSI_TOKEN_GET_URI] =*/ "GET URI",
350 /*[WSI_TOKEN_HOST] =*/ "Host",
351 /*[WSI_TOKEN_CONNECTION] =*/ "Connection",
352 /*[WSI_TOKEN_KEY1] =*/ "key 1",
353 /*[WSI_TOKEN_KEY2] =*/ "key 2",
354 /*[WSI_TOKEN_PROTOCOL] =*/ "Protocol",
355 /*[WSI_TOKEN_UPGRADE] =*/ "Upgrade",
356 /*[WSI_TOKEN_ORIGIN] =*/ "Origin",
357 /*[WSI_TOKEN_DRAFT] =*/ "Draft",
358 /*[WSI_TOKEN_CHALLENGE] =*/ "Challenge",
Andy Green38c4f0c2011-02-13 08:54:05 +0000359
360 /* new for 04 */
Peter Hinz56885f32011-03-02 22:03:47 +0000361 /*[WSI_TOKEN_KEY] =*/ "Key",
362 /*[WSI_TOKEN_VERSION] =*/ "Version",
363 /*[WSI_TOKEN_SWORIGIN] =*/ "Sworigin",
Andy Green38c4f0c2011-02-13 08:54:05 +0000364
365 /* new for 05 */
Peter Hinz56885f32011-03-02 22:03:47 +0000366 /*[WSI_TOKEN_EXTENSIONS] =*/ "Extensions",
Andy Green38c4f0c2011-02-13 08:54:05 +0000367
368 /* client receives these */
Peter Hinz56885f32011-03-02 22:03:47 +0000369 /*[WSI_TOKEN_ACCEPT] =*/ "Accept",
370 /*[WSI_TOKEN_NONCE] =*/ "Nonce",
371 /*[WSI_TOKEN_HTTP] =*/ "Http",
Andy Greencc13c6f2013-11-09 10:09:09 +0800372
373 "Accept:",
374 "If-Modified-Since:",
375 "Accept-Encoding:",
376 "Accept-Language:",
377 "Pragma:",
378 "Cache-Control:",
379 "Authorization:",
380 "Cookie:",
381 "Content-Type:",
382 "Date:",
383 "Range:",
384 "Referer:"
385
Andy Greena41314f2011-05-23 10:00:03 +0100386 /*[WSI_TOKEN_MUXURL] =*/ "MuxURL",
Andy Green38c4f0c2011-02-13 08:54:05 +0000387 };
Andy Green16ab3182013-02-10 18:02:31 +0800388 char buf[256];
Andy Green6ee372f2012-04-09 15:09:01 +0800389
Andy Green6cd88802013-11-09 11:06:29 +0800390 for (n = 0; n < sizeof(token_names) / sizeof(token_names[0]); n++) {
Andy Green16ab3182013-02-10 18:02:31 +0800391 if (!lws_hdr_total_length(wsi, n))
Andy Green38c4f0c2011-02-13 08:54:05 +0000392 continue;
393
Andy Green16ab3182013-02-10 18:02:31 +0800394 lws_hdr_copy(wsi, buf, sizeof buf, n);
395
396 fprintf(stderr, " %s = %s\n", token_names[n], buf);
Andy Green38c4f0c2011-02-13 08:54:05 +0000397 }
398}
399
Andy Green4f3943a2010-11-12 10:44:16 +0000400/* dumb_increment protocol */
401
Andy Green0ca6a172010-12-19 20:50:01 +0000402/*
403 * one of these is auto-created for each connection and a pointer to the
404 * appropriate instance is passed to the callback in the user parameter
405 *
406 * for this example protocol we use it to individualize the count for each
407 * connection.
408 */
409
Andy Green4f3943a2010-11-12 10:44:16 +0000410struct per_session_data__dumb_increment {
411 int number;
412};
413
414static int
Andy Green6ee372f2012-04-09 15:09:01 +0800415callback_dumb_increment(struct libwebsocket_context *context,
Andy Green62c54d22011-02-14 09:14:25 +0000416 struct libwebsocket *wsi,
Andy Green4f3943a2010-11-12 10:44:16 +0000417 enum libwebsocket_callback_reasons reason,
Andy Greene77ddd82010-11-13 10:03:47 +0000418 void *user, void *in, size_t len)
Andy Green4f3943a2010-11-12 10:44:16 +0000419{
Andy Green3390efd2013-03-23 09:46:18 +0800420 int n, m;
Andy Green90c7cbc2011-01-27 06:26:52 +0000421 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
Andy Green4f3943a2010-11-12 10:44:16 +0000422 LWS_SEND_BUFFER_POST_PADDING];
Andy Green90c7cbc2011-01-27 06:26:52 +0000423 unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
Andy Green36eb70d2013-02-01 08:42:15 +0800424 struct per_session_data__dumb_increment *pss = (struct per_session_data__dumb_increment *)user;
Andy Greene77ddd82010-11-13 10:03:47 +0000425
Andy Green4f3943a2010-11-12 10:44:16 +0000426 switch (reason) {
427
428 case LWS_CALLBACK_ESTABLISHED:
Andy Green058ba812013-01-19 11:32:18 +0800429 lwsl_info("callback_dumb_increment: "
Andy Green6ee372f2012-04-09 15:09:01 +0800430 "LWS_CALLBACK_ESTABLISHED\n");
Andy Green4f3943a2010-11-12 10:44:16 +0000431 pss->number = 0;
432 break;
433
Andy Green6f520a52013-01-29 17:57:39 +0800434 case LWS_CALLBACK_SERVER_WRITEABLE:
Andy Green90c7cbc2011-01-27 06:26:52 +0000435 n = sprintf((char *)p, "%d", pss->number++);
Andy Green3390efd2013-03-23 09:46:18 +0800436 m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
437 if (m < n) {
Andy Green51b20ee2013-02-17 09:14:08 +0800438 lwsl_err("ERROR %d writing to di socket\n", n);
439 return -1;
Andy Green4f3943a2010-11-12 10:44:16 +0000440 }
Andy Green69758fa2011-03-07 07:08:07 +0000441 if (close_testing && pss->number == 50) {
Andy Green058ba812013-01-19 11:32:18 +0800442 lwsl_info("close tesing limit, closing\n");
Andy Green508946c2013-02-12 10:19:08 +0800443 return -1;
Andy Green69758fa2011-03-07 07:08:07 +0000444 }
Andy Green4f3943a2010-11-12 10:44:16 +0000445 break;
446
447 case LWS_CALLBACK_RECEIVE:
Andy Green058ba812013-01-19 11:32:18 +0800448// fprintf(stderr, "rx %d\n", (int)len);
Andy Green4f3943a2010-11-12 10:44:16 +0000449 if (len < 6)
450 break;
Andy Green36eb70d2013-02-01 08:42:15 +0800451 if (strcmp((const char *)in, "reset\n") == 0)
Andy Green4f3943a2010-11-12 10:44:16 +0000452 pss->number = 0;
453 break;
Andy Green38c4f0c2011-02-13 08:54:05 +0000454 /*
455 * this just demonstrates how to use the protocol filter. If you won't
456 * study and reject connections based on header content, you don't need
457 * to handle this callback
458 */
459
460 case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
Andy Green16ab3182013-02-10 18:02:31 +0800461 dump_handshake_info(wsi);
Andy Green38c4f0c2011-02-13 08:54:05 +0000462 /* you could return non-zero here and kill the connection */
463 break;
Andy Green4f3943a2010-11-12 10:44:16 +0000464
465 default:
466 break;
467 }
468
469 return 0;
470}
471
472
Andy Greenfe2a0d22010-11-12 13:10:40 +0000473/* lws-mirror_protocol */
474
Andy Greenca0a1292013-03-16 11:24:23 +0800475#define MAX_MESSAGE_QUEUE 32
Andy Green90c7cbc2011-01-27 06:26:52 +0000476
477struct per_session_data__lws_mirror {
478 struct libwebsocket *wsi;
479 int ringbuffer_tail;
480};
481
482struct a_message {
483 void *payload;
484 size_t len;
485};
486
487static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
488static int ringbuffer_head;
489
Andy Greenfe2a0d22010-11-12 13:10:40 +0000490static int
Andy Green6ee372f2012-04-09 15:09:01 +0800491callback_lws_mirror(struct libwebsocket_context *context,
Andy Green62c54d22011-02-14 09:14:25 +0000492 struct libwebsocket *wsi,
Andy Greenfe2a0d22010-11-12 13:10:40 +0000493 enum libwebsocket_callback_reasons reason,
Andy Greene77ddd82010-11-13 10:03:47 +0000494 void *user, void *in, size_t len)
Andy Greenfe2a0d22010-11-12 13:10:40 +0000495{
496 int n;
Andy Green36eb70d2013-02-01 08:42:15 +0800497 struct per_session_data__lws_mirror *pss = (struct per_session_data__lws_mirror *)user;
Andy Greene77ddd82010-11-13 10:03:47 +0000498
Andy Greenfe2a0d22010-11-12 13:10:40 +0000499 switch (reason) {
500
Andy Green90c7cbc2011-01-27 06:26:52 +0000501 case LWS_CALLBACK_ESTABLISHED:
Andy Greenca0a1292013-03-16 11:24:23 +0800502 lwsl_info("callback_lws_mirror: LWS_CALLBACK_ESTABLISHED\n");
Andy Green90c7cbc2011-01-27 06:26:52 +0000503 pss->ringbuffer_tail = ringbuffer_head;
504 pss->wsi = wsi;
505 break;
506
Andy Greena7109e62013-02-11 12:05:54 +0800507 case LWS_CALLBACK_PROTOCOL_DESTROY:
508 lwsl_notice("mirror protocol cleaning up\n");
509 for (n = 0; n < sizeof ringbuffer / sizeof ringbuffer[0]; n++)
510 if (ringbuffer[n].payload)
511 free(ringbuffer[n].payload);
512 break;
513
Andy Green9e4c2b62011-03-07 20:47:39 +0000514 case LWS_CALLBACK_SERVER_WRITEABLE:
Andy Green69758fa2011-03-07 07:08:07 +0000515 if (close_testing)
516 break;
Andy Green3182ece2013-01-20 17:08:31 +0800517 while (pss->ringbuffer_tail != ringbuffer_head) {
Andy Green90c7cbc2011-01-27 06:26:52 +0000518
519 n = libwebsocket_write(wsi, (unsigned char *)
520 ringbuffer[pss->ringbuffer_tail].payload +
521 LWS_SEND_BUFFER_PRE_PADDING,
522 ringbuffer[pss->ringbuffer_tail].len,
523 LWS_WRITE_TEXT);
Andy Green3390efd2013-03-23 09:46:18 +0800524 if (n < ringbuffer[pss->ringbuffer_tail].len) {
Andy Green51b20ee2013-02-17 09:14:08 +0800525 lwsl_err("ERROR %d writing to mirror socket\n", n);
526 return -1;
Andy Green90c7cbc2011-01-27 06:26:52 +0000527 }
Andy Greenca0a1292013-03-16 11:24:23 +0800528 if (n < ringbuffer[pss->ringbuffer_tail].len)
529 lwsl_err("mirror partial write %d vs %d\n",
530 n, ringbuffer[pss->ringbuffer_tail].len);
Andy Green90c7cbc2011-01-27 06:26:52 +0000531
532 if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
533 pss->ringbuffer_tail = 0;
534 else
535 pss->ringbuffer_tail++;
536
Andy Green706961d2013-01-17 16:50:35 +0800537 if (((ringbuffer_head - pss->ringbuffer_tail) &
Andy Greenb55451c2013-03-16 12:32:27 +0800538 (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15))
539 libwebsocket_rx_flow_allow_all_protocol(
540 libwebsockets_get_protocol(wsi));
541
Andy Green3182ece2013-01-20 17:08:31 +0800542 // lwsl_debug("tx fifo %d\n", (ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1));
Andy Green706961d2013-01-17 16:50:35 +0800543
Andy Green3182ece2013-01-20 17:08:31 +0800544 if (lws_send_pipe_choked(wsi)) {
545 libwebsocket_callback_on_writable(context, wsi);
Andy Greenca0a1292013-03-16 11:24:23 +0800546 break;
Andy Green3182ece2013-01-20 17:08:31 +0800547 }
Andy Greenca0a1292013-03-16 11:24:23 +0800548 /*
549 * for tests with chrome on same machine as client and
550 * server, this is needed to stop chrome choking
551 */
552 usleep(1);
Andy Green90c7cbc2011-01-27 06:26:52 +0000553 }
554 break;
555
Andy Greenfe2a0d22010-11-12 13:10:40 +0000556 case LWS_CALLBACK_RECEIVE:
Andy Green90c7cbc2011-01-27 06:26:52 +0000557
Andy Green706961d2013-01-17 16:50:35 +0800558 if (((ringbuffer_head - pss->ringbuffer_tail) &
559 (MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) {
Andy Green058ba812013-01-19 11:32:18 +0800560 lwsl_err("dropping!\n");
Andy Green706961d2013-01-17 16:50:35 +0800561 goto choke;
562 }
563
Andy Green90c7cbc2011-01-27 06:26:52 +0000564 if (ringbuffer[ringbuffer_head].payload)
565 free(ringbuffer[ringbuffer_head].payload);
566
567 ringbuffer[ringbuffer_head].payload =
568 malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
569 LWS_SEND_BUFFER_POST_PADDING);
570 ringbuffer[ringbuffer_head].len = len;
571 memcpy((char *)ringbuffer[ringbuffer_head].payload +
572 LWS_SEND_BUFFER_PRE_PADDING, in, len);
573 if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
574 ringbuffer_head = 0;
575 else
576 ringbuffer_head++;
577
Andy Green706961d2013-01-17 16:50:35 +0800578 if (((ringbuffer_head - pss->ringbuffer_tail) &
Andy Green3182ece2013-01-20 17:08:31 +0800579 (MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2))
Andy Green706961d2013-01-17 16:50:35 +0800580 goto done;
Andy Green90c7cbc2011-01-27 06:26:52 +0000581
Andy Green706961d2013-01-17 16:50:35 +0800582choke:
Andy Greenb55451c2013-03-16 12:32:27 +0800583 lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi);
584 libwebsocket_rx_flow_control(wsi, 0);
Andy Green706961d2013-01-17 16:50:35 +0800585
Andy Green058ba812013-01-19 11:32:18 +0800586// lwsl_debug("rx fifo %d\n", (ringbuffer_head - pss->ringbuffer_tail) & (MAX_MESSAGE_QUEUE - 1));
Andy Green706961d2013-01-17 16:50:35 +0800587done:
Andy Green90c7cbc2011-01-27 06:26:52 +0000588 libwebsocket_callback_on_writable_all_protocol(
589 libwebsockets_get_protocol(wsi));
Andy Greenfe2a0d22010-11-12 13:10:40 +0000590 break;
Andy Green706961d2013-01-17 16:50:35 +0800591
Andy Green38c4f0c2011-02-13 08:54:05 +0000592 /*
593 * this just demonstrates how to use the protocol filter. If you won't
594 * study and reject connections based on header content, you don't need
595 * to handle this callback
596 */
597
598 case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
Andy Green16ab3182013-02-10 18:02:31 +0800599 dump_handshake_info(wsi);
Andy Green38c4f0c2011-02-13 08:54:05 +0000600 /* you could return non-zero here and kill the connection */
601 break;
Andy Greenfe2a0d22010-11-12 13:10:40 +0000602
603 default:
604 break;
605 }
606
607 return 0;
608}
609
610
Andy Green4f3943a2010-11-12 10:44:16 +0000611/* list of supported protocols and callbacks */
612
Andy Greenb45993c2010-12-18 15:13:50 +0000613static struct libwebsocket_protocols protocols[] = {
Andy Green0ca6a172010-12-19 20:50:01 +0000614 /* first protocol must always be HTTP handler */
Peter Hinz56885f32011-03-02 22:03:47 +0000615
616 {
617 "http-only", /* name */
618 callback_http, /* callback */
Andy Greenfbf48222013-02-14 23:06:37 +0800619 sizeof (struct per_session_data__http), /* per_session_data_size */
Andy Green54495112013-02-06 21:10:16 +0900620 0, /* max frame size / rx buffer */
Andy Green4f3943a2010-11-12 10:44:16 +0000621 },
Peter Hinz56885f32011-03-02 22:03:47 +0000622 {
623 "dumb-increment-protocol",
624 callback_dumb_increment,
625 sizeof(struct per_session_data__dumb_increment),
Andy Green54495112013-02-06 21:10:16 +0900626 10,
Andy Green4f3943a2010-11-12 10:44:16 +0000627 },
Peter Hinz56885f32011-03-02 22:03:47 +0000628 {
629 "lws-mirror-protocol",
630 callback_lws_mirror,
Andy Green54495112013-02-06 21:10:16 +0900631 sizeof(struct per_session_data__lws_mirror),
Andy Greene7c97e82013-02-09 14:07:32 +0800632 128,
Andy Greenfe2a0d22010-11-12 13:10:40 +0000633 },
Andy Green54495112013-02-06 21:10:16 +0900634 { NULL, NULL, 0, 0 } /* terminator */
Andy Green4f3943a2010-11-12 10:44:16 +0000635};
636
Andy Green08f2c012013-01-30 08:02:26 +0800637void sighandler(int sig)
638{
639 force_exit = 1;
640}
641
Andy Greenea71ed12010-10-31 07:40:33 +0000642static struct option options[] = {
Andy Green90c7cbc2011-01-27 06:26:52 +0000643 { "help", no_argument, NULL, 'h' },
Andy Green46ef0cf2013-01-10 22:28:59 +0800644 { "debug", required_argument, NULL, 'd' },
Andy Green90c7cbc2011-01-27 06:26:52 +0000645 { "port", required_argument, NULL, 'p' },
646 { "ssl", no_argument, NULL, 's' },
Andy Green6ee372f2012-04-09 15:09:01 +0800647 { "interface", required_argument, NULL, 'i' },
Andy Green69758fa2011-03-07 07:08:07 +0000648 { "closetest", no_argument, NULL, 'c' },
Andy Green5c54d622013-01-21 12:58:04 +0800649#ifndef LWS_NO_DAEMONIZE
Andy Greenfd6764a2013-01-19 11:11:42 +0800650 { "daemonize", no_argument, NULL, 'D' },
651#endif
Joakim Soderbergf0ee6692013-03-18 17:08:25 +0000652 { "resource_path", required_argument, NULL, 'r' },
Andy Greenea71ed12010-10-31 07:40:33 +0000653 { NULL, 0, 0, 0 }
654};
Andy Green775c0dd2010-10-29 14:15:22 +0100655
Andy Greenea71ed12010-10-31 07:40:33 +0000656int main(int argc, char **argv)
Andy Green775c0dd2010-10-29 14:15:22 +0100657{
Joakim Soderbergf0ee6692013-03-18 17:08:25 +0000658 char cert_path[1024];
659 char key_path[1024];
Andy Greenea71ed12010-10-31 07:40:33 +0000660 int n = 0;
Andy Green0ca6a172010-12-19 20:50:01 +0000661 int use_ssl = 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000662 struct libwebsocket_context *context;
Andy Green8014b292011-01-30 20:57:25 +0000663 int opts = 0;
Andy Green32375b72011-02-19 08:32:53 +0000664 char interface_name[128] = "";
Joakim Soderberg63ff1202013-02-11 17:52:23 +0100665 const char *iface = NULL;
Joakim Soderberg4c531232013-02-06 15:26:58 +0900666#ifndef WIN32
Andy Greenfd6764a2013-01-19 11:11:42 +0800667 int syslog_options = LOG_PID | LOG_PERROR;
Joakim Soderberg4c531232013-02-06 15:26:58 +0900668#endif
Andy Green90c7cbc2011-01-27 06:26:52 +0000669 unsigned int oldus = 0;
Andy Green1b265272013-02-09 14:01:09 +0800670 struct lws_context_creation_info info;
Andy Green6f520a52013-01-29 17:57:39 +0800671
Andy Green058ba812013-01-19 11:32:18 +0800672 int debug_level = 7;
Andy Green5c54d622013-01-21 12:58:04 +0800673#ifndef LWS_NO_DAEMONIZE
Andy Greenfd6764a2013-01-19 11:11:42 +0800674 int daemonize = 0;
675#endif
Andy Greene77ddd82010-11-13 10:03:47 +0000676
Andy Green1b265272013-02-09 14:01:09 +0800677 memset(&info, 0, sizeof info);
678 info.port = 7681;
679
Andy Greenea71ed12010-10-31 07:40:33 +0000680 while (n >= 0) {
Joakim Soderbergf0ee6692013-03-18 17:08:25 +0000681 n = getopt_long(argc, argv, "ci:hsp:d:Dr:", options, NULL);
Andy Greenea71ed12010-10-31 07:40:33 +0000682 if (n < 0)
683 continue;
684 switch (n) {
Andy Green5c54d622013-01-21 12:58:04 +0800685#ifndef LWS_NO_DAEMONIZE
Andy Greenfd6764a2013-01-19 11:11:42 +0800686 case 'D':
687 daemonize = 1;
Joakim Soderberg4c531232013-02-06 15:26:58 +0900688 #ifndef WIN32
Andy Greenfd6764a2013-01-19 11:11:42 +0800689 syslog_options &= ~LOG_PERROR;
Joakim Soderberg4c531232013-02-06 15:26:58 +0900690 #endif
Andy Greenfd6764a2013-01-19 11:11:42 +0800691 break;
692#endif
Andy Green46ef0cf2013-01-10 22:28:59 +0800693 case 'd':
Andy Green058ba812013-01-19 11:32:18 +0800694 debug_level = atoi(optarg);
Andy Green46ef0cf2013-01-10 22:28:59 +0800695 break;
Andy Green3faa9c72010-11-08 17:03:03 +0000696 case 's':
697 use_ssl = 1;
698 break;
Andy Greenea71ed12010-10-31 07:40:33 +0000699 case 'p':
Andy Green1b265272013-02-09 14:01:09 +0800700 info.port = atoi(optarg);
Andy Greenea71ed12010-10-31 07:40:33 +0000701 break;
Andy Green32375b72011-02-19 08:32:53 +0000702 case 'i':
703 strncpy(interface_name, optarg, sizeof interface_name);
704 interface_name[(sizeof interface_name) - 1] = '\0';
Joakim Soderberg63ff1202013-02-11 17:52:23 +0100705 iface = interface_name;
Andy Green32375b72011-02-19 08:32:53 +0000706 break;
Andy Green69758fa2011-03-07 07:08:07 +0000707 case 'c':
708 close_testing = 1;
709 fprintf(stderr, " Close testing mode -- closes on "
710 "client after 50 dumb increments"
711 "and suppresses lws_mirror spam\n");
712 break;
Joakim Soderbergf0ee6692013-03-18 17:08:25 +0000713 case 'r':
714 resource_path = optarg;
715 printf("Setting resource path to \"%s\"\n", resource_path);
716 break;
Andy Greenea71ed12010-10-31 07:40:33 +0000717 case 'h':
Andy Greenab990e42010-10-31 12:42:52 +0000718 fprintf(stderr, "Usage: test-server "
Andy Green46ef0cf2013-01-10 22:28:59 +0800719 "[--port=<p>] [--ssl] "
Joakim Soderbergf0ee6692013-03-18 17:08:25 +0000720 "[-d <log bitfield>] "
721 "[--resource_path <path>]\n");
Andy Greenea71ed12010-10-31 07:40:33 +0000722 exit(1);
723 }
Andy Greenea71ed12010-10-31 07:40:33 +0000724 }
Andy Green3faa9c72010-11-08 17:03:03 +0000725
Joakim Soderberg4c531232013-02-06 15:26:58 +0900726#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
Andy Greenfd6764a2013-01-19 11:11:42 +0800727 /*
728 * normally lock path would be /var/lock/lwsts or similar, to
729 * simplify getting started without having to take care about
730 * permissions or running as root, set to /tmp/.lwsts-lock
731 */
732 if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
733 fprintf(stderr, "Failed to daemonize\n");
734 return 1;
735 }
Andy Green24cba922013-01-19 13:56:10 +0800736#endif
Andy Green08f2c012013-01-30 08:02:26 +0800737
738 signal(SIGINT, sighandler);
739
Joakim Soderberg4c531232013-02-06 15:26:58 +0900740#ifndef WIN32
Andy Greenfd6764a2013-01-19 11:11:42 +0800741 /* we will only try to log things according to our debug_level */
742 setlogmask(LOG_UPTO (LOG_DEBUG));
743 openlog("lwsts", syslog_options, LOG_DAEMON);
Joakim Soderberg4c531232013-02-06 15:26:58 +0900744#endif
Andy Green058ba812013-01-19 11:32:18 +0800745
746 /* tell the library what debug level to emit and to send it to syslog */
747 lws_set_log_level(debug_level, lwsl_emit_syslog);
748
Andy Greenfd6764a2013-01-19 11:11:42 +0800749 lwsl_notice("libwebsockets test server - "
750 "(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> - "
Andy Green058ba812013-01-19 11:32:18 +0800751 "licensed under LGPL2.1\n");
Edwin van den Oetelaar596b2202013-01-20 20:51:14 +0800752#ifdef EXTERNAL_POLL
753 max_poll_elements = getdtablesize();
754 pollfds = malloc(max_poll_elements * sizeof (struct pollfd));
755 fd_lookup = malloc(max_poll_elements * sizeof (int));
756 if (pollfds == NULL || fd_lookup == NULL) {
757 lwsl_err("Out of memory pollfds=%d\n", max_poll_elements);
758 return -1;
759 }
760#endif
Andy Greene77ddd82010-11-13 10:03:47 +0000761
Joakim Soderberg63ff1202013-02-11 17:52:23 +0100762 info.iface = iface;
Andy Green1b265272013-02-09 14:01:09 +0800763 info.protocols = protocols;
Andy Green3182ece2013-01-20 17:08:31 +0800764#ifndef LWS_NO_EXTENSIONS
Joakim Soderbergf272cb02013-02-13 09:29:26 +0800765 info.extensions = libwebsocket_get_internal_extensions();
Andy Green3182ece2013-01-20 17:08:31 +0800766#endif
Andy Green1b265272013-02-09 14:01:09 +0800767 if (!use_ssl) {
768 info.ssl_cert_filepath = NULL;
769 info.ssl_private_key_filepath = NULL;
770 } else {
Andy Green6c720702013-05-02 08:15:53 +0800771 if (strlen(resource_path) > sizeof(cert_path) - 32) {
772 lwsl_err("resource path too long\n");
773 return -1;
774 }
775 sprintf(cert_path, "%s/libwebsockets-test-server.pem",
776 resource_path);
777 if (strlen(resource_path) > sizeof(key_path) - 32) {
778 lwsl_err("resource path too long\n");
779 return -1;
780 }
781 sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
782 resource_path);
Joakim Soderbergf0ee6692013-03-18 17:08:25 +0000783
784 info.ssl_cert_filepath = cert_path;
785 info.ssl_private_key_filepath = key_path;
Andy Green1b265272013-02-09 14:01:09 +0800786 }
787 info.gid = -1;
788 info.uid = -1;
789 info.options = opts;
790
791 context = libwebsocket_create_context(&info);
Andy Green4739e5c2011-01-22 12:51:57 +0000792 if (context == NULL) {
Andy Green058ba812013-01-19 11:32:18 +0800793 lwsl_err("libwebsocket init failed\n");
Andy Green775c0dd2010-10-29 14:15:22 +0100794 return -1;
795 }
Andy Green775c0dd2010-10-29 14:15:22 +0100796
Andy Green3928f612012-07-20 12:58:38 +0800797 n = 0;
Andy Green08f2c012013-01-30 08:02:26 +0800798 while (n >= 0 && !force_exit) {
Andy Green90c7cbc2011-01-27 06:26:52 +0000799 struct timeval tv;
800
801 gettimeofday(&tv, NULL);
Andy Greenb45993c2010-12-18 15:13:50 +0000802
803 /*
Andy Green6f520a52013-01-29 17:57:39 +0800804 * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every
805 * live websocket connection using the DUMB_INCREMENT protocol,
806 * as soon as it can take more packets (usually immediately)
Andy Greenb45993c2010-12-18 15:13:50 +0000807 */
808
Andy Green90c7cbc2011-01-27 06:26:52 +0000809 if (((unsigned int)tv.tv_usec - oldus) > 50000) {
Andy Green6f520a52013-01-29 17:57:39 +0800810 libwebsocket_callback_on_writable_all_protocol(&protocols[PROTOCOL_DUMB_INCREMENT]);
Andy Green90c7cbc2011-01-27 06:26:52 +0000811 oldus = tv.tv_usec;
812 }
Andy Greene92cd172011-01-19 13:11:55 +0000813
Andy Greena50dd1a2013-01-15 12:39:48 +0800814#ifdef EXTERNAL_POLL
Andy Greene92cd172011-01-19 13:11:55 +0000815
Andy Greena50dd1a2013-01-15 12:39:48 +0800816 /*
817 * this represents an existing server's single poll action
818 * which also includes libwebsocket sockets
819 */
820
821 n = poll(pollfds, count_pollfds, 50);
822 if (n < 0)
823 continue;
824
Andy Greend280b6e2013-01-15 13:40:23 +0800825
Andy Greena50dd1a2013-01-15 12:39:48 +0800826 if (n)
827 for (n = 0; n < count_pollfds; n++)
828 if (pollfds[n].revents)
829 /*
830 * returns immediately if the fd does not
831 * match anything under libwebsockets
832 * control
833 */
834 if (libwebsocket_service_fd(context,
835 &pollfds[n]) < 0)
836 goto done;
Andy Greena50dd1a2013-01-15 12:39:48 +0800837#else
Andy Green0d49c8d2013-02-02 23:02:56 +0800838 /*
839 * If libwebsockets sockets are all we care about,
840 * you can use this api which takes care of the poll()
841 * and looping through finding who needed service.
842 *
843 * If no socket needs service, it'll return anyway after
844 * the number of ms in the second argument.
845 */
846
Andy Green3928f612012-07-20 12:58:38 +0800847 n = libwebsocket_service(context, 50);
Andy Greena50dd1a2013-01-15 12:39:48 +0800848#endif
Andy Greenb45993c2010-12-18 15:13:50 +0000849 }
850
Andy Greena50dd1a2013-01-15 12:39:48 +0800851#ifdef EXTERNAL_POLL
852done:
853#endif
Andy Greened11a022011-01-20 10:23:50 +0000854
Andy Green6964bb52011-01-23 16:50:33 +0000855 libwebsocket_context_destroy(context);
856
Andy Green058ba812013-01-19 11:32:18 +0800857 lwsl_notice("libwebsockets-test-server exited cleanly\n");
858
Joakim Soderberg4c531232013-02-06 15:26:58 +0900859#ifndef WIN32
Andy Green058ba812013-01-19 11:32:18 +0800860 closelog();
Joakim Soderberg4c531232013-02-06 15:26:58 +0900861#endif
Andy Green058ba812013-01-19 11:32:18 +0800862
Andy Green775c0dd2010-10-29 14:15:22 +0100863 return 0;
864}