2 * libwebsockets-test-server-extpoll - libwebsockets external poll loop sample
4 * This acts the same as libwebsockets-test-server but works with the poll
5 * loop taken out of libwebsockets and into this app. It's an example of how
6 * you can integrate libwebsockets polling into an app that already has its
9 * Copyright (C) 2010-2011 Andy Green <andy@warmcat.com>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation:
14 * version 2.1 of the License.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35 #include "../lib/libwebsockets.h"
39 * This demo server shows how to use libwebsockets for one or more
40 * websocket protocols in the same server
42 * It defines the following websocket protocols:
44 * dumb-increment-protocol: once the socket is opened, an incrementing
45 * ascii string is sent down it every 50ms.
46 * If you send "reset\n" on the websocket, then
47 * the incrementing number is reset to 0.
49 * lws-mirror-protocol: copies any received packet to every connection also
50 * using this protocol, including the sender
53 #define MAX_POLL_ELEMENTS 100
54 struct pollfd pollfds[100];
55 int count_pollfds = 0;
63 PROTOCOL_DUMB_INCREMENT,
71 #define LOCAL_RESOURCE_PATH DATADIR"/libwebsockets-test-server"
73 /* this protocol server (always the first one) just knows how to do HTTP */
75 static int callback_http(struct libwebsocket *wsi,
76 enum libwebsocket_callback_reasons reason, void *user,
80 case LWS_CALLBACK_HTTP:
81 fprintf(stderr, "serving HTTP URI %s\n", (char *)in);
83 if (in && strcmp(in, "/favicon.ico") == 0) {
84 if (libwebsockets_serve_http_file(wsi,
85 LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon"))
86 fprintf(stderr, "Failed to send favicon\n");
90 /* send the script... when it runs it'll start websockets */
92 if (libwebsockets_serve_http_file(wsi,
93 LOCAL_RESOURCE_PATH"/test.html", "text/html"))
94 fprintf(stderr, "Failed to send HTTP file\n");
104 /* dumb_increment protocol */
107 * one of these is auto-created for each connection and a pointer to the
108 * appropriate instance is passed to the callback in the user parameter
110 * for this example protocol we use it to individualize the count for each
114 struct per_session_data__dumb_increment {
119 callback_dumb_increment(struct libwebsocket *wsi,
120 enum libwebsocket_callback_reasons reason,
121 void *user, void *in, size_t len)
124 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
125 LWS_SEND_BUFFER_POST_PADDING];
126 unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
127 struct per_session_data__dumb_increment *pss = user;
131 case LWS_CALLBACK_ESTABLISHED:
136 * in this protocol, we just use the broadcast action as the chance to
137 * send our own connection-specific data and ignore the broadcast info
138 * that is available in the 'in' parameter
141 case LWS_CALLBACK_BROADCAST:
142 n = sprintf((char *)p, "%d", pss->number++);
143 n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
145 fprintf(stderr, "ERROR writing to socket");
150 case LWS_CALLBACK_RECEIVE:
151 fprintf(stderr, "rx %d\n", (int)len);
154 if (strcmp(in, "reset\n") == 0)
166 /* lws-mirror_protocol */
168 #define MAX_MESSAGE_QUEUE 64
170 struct per_session_data__lws_mirror {
171 struct libwebsocket *wsi;
180 static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
181 static int ringbuffer_head;
185 callback_lws_mirror(struct libwebsocket *wsi,
186 enum libwebsocket_callback_reasons reason,
187 void *user, void *in, size_t len)
190 struct per_session_data__lws_mirror *pss = user;
194 case LWS_CALLBACK_ESTABLISHED:
195 pss->ringbuffer_tail = ringbuffer_head;
199 case LWS_CALLBACK_CLIENT_WRITEABLE:
200 if (pss->ringbuffer_tail != ringbuffer_head) {
202 n = libwebsocket_write(wsi, (unsigned char *)
203 ringbuffer[pss->ringbuffer_tail].payload +
204 LWS_SEND_BUFFER_PRE_PADDING,
205 ringbuffer[pss->ringbuffer_tail].len,
208 fprintf(stderr, "ERROR writing to socket");
212 if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
213 pss->ringbuffer_tail = 0;
215 pss->ringbuffer_tail++;
217 if (((ringbuffer_head - pss->ringbuffer_tail) %
218 MAX_MESSAGE_QUEUE) < (MAX_MESSAGE_QUEUE - 15))
219 libwebsocket_rx_flow_control(wsi, 1);
221 libwebsocket_callback_on_writable(wsi);
226 case LWS_CALLBACK_BROADCAST:
227 n = libwebsocket_write(wsi, in, len, LWS_WRITE_TEXT);
229 fprintf(stderr, "mirror write failed\n");
232 case LWS_CALLBACK_RECEIVE:
234 if (ringbuffer[ringbuffer_head].payload)
235 free(ringbuffer[ringbuffer_head].payload);
237 ringbuffer[ringbuffer_head].payload =
238 malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
239 LWS_SEND_BUFFER_POST_PADDING);
240 ringbuffer[ringbuffer_head].len = len;
241 memcpy((char *)ringbuffer[ringbuffer_head].payload +
242 LWS_SEND_BUFFER_PRE_PADDING, in, len);
243 if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
248 if (((ringbuffer_head - pss->ringbuffer_tail) %
249 MAX_MESSAGE_QUEUE) > (MAX_MESSAGE_QUEUE - 10))
250 libwebsocket_rx_flow_control(wsi, 0);
252 libwebsocket_callback_on_writable_all_protocol(
253 libwebsockets_get_protocol(wsi));
264 /* list of supported protocols and callbacks */
266 static struct libwebsocket_protocols protocols[] = {
267 /* first protocol must always be HTTP handler */
270 .callback = callback_http,
272 [PROTOCOL_DUMB_INCREMENT] = {
273 .name = "dumb-increment-protocol",
274 .callback = callback_dumb_increment,
275 .per_session_data_size =
276 sizeof(struct per_session_data__dumb_increment),
278 [PROTOCOL_LWS_MIRROR] = {
279 .name = "lws-mirror-protocol",
280 .callback = callback_lws_mirror,
281 .per_session_data_size =
282 sizeof(struct per_session_data__lws_mirror),
284 [DEMO_PROTOCOL_COUNT] = { /* end of list */
289 static struct option options[] = {
290 { "help", no_argument, NULL, 'h' },
291 { "port", required_argument, NULL, 'p' },
292 { "ssl", no_argument, NULL, 's' },
293 { "killmask", no_argument, NULL, 'k' },
297 int main(int argc, char **argv)
300 const char *cert_path =
301 LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
302 const char *key_path =
303 LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
304 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 +
305 LWS_SEND_BUFFER_POST_PADDING];
308 struct libwebsocket_context *context;
310 unsigned int oldus = 0;
312 fprintf(stderr, "libwebsockets test server with external poll()\n"
313 "(C) Copyright 2010-2011 Andy Green <andy@warmcat.com> "
314 "licensed under LGPL2.1\n");
317 n = getopt_long(argc, argv, "khsp:", options, NULL);
325 opts = LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK;
331 fprintf(stderr, "Usage: test-server "
332 "[--port=<p>] [--ssl]\n");
338 cert_path = key_path = NULL;
340 context = libwebsocket_create_context(port, protocols, cert_path,
341 key_path, -1, -1, opts);
342 if (context == NULL) {
343 fprintf(stderr, "libwebsocket init failed\n");
347 buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x';
350 * This is an example of an existing application's explicit poll()
351 * loop that libwebsockets can integrate with.
358 * this represents an existing server's single poll action
359 * which also includes libwebsocket sockets
362 n = poll(pollfds, count_pollfds, 25);
367 for (n = 0; n < count_pollfds; n++)
368 if (pollfds[n].revents)
370 * returns immediately if the fd does not
371 * match anything under libwebsockets
374 libwebsocket_service_fd(context,
377 /* do our broadcast periodically */
379 gettimeofday(&tv, NULL);
382 * This broadcasts to all dumb-increment-protocol connections
385 * We're just sending a character 'x', in these examples the
386 * callbacks send their own per-connection content.
388 * You have to send something with nonzero length to get the
389 * callback actions delivered.
391 * We take care of pre-and-post padding allocation.
394 if (((unsigned int)tv.tv_usec - oldus) > 50000) {
395 libwebsockets_broadcast(
396 &protocols[PROTOCOL_DUMB_INCREMENT],
397 &buf[LWS_SEND_BUFFER_PRE_PADDING], 1);
403 libwebsocket_context_destroy(context);