2 * libwebsockets-test-server - libwebsockets test implementation
4 * Copyright (C) 2010 Andy Green <andy@warmcat.com>
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.
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.
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,
28 #include "../lib/libwebsockets.h"
31 * This demo server shows how to use libwebsockets for one or more
32 * websocket protocols in the same server
34 * It defines the following websocket protocols:
36 * dumb-increment-protocol: once the socket is opened, an incrementing
37 * ascii string is sent down it every 50ms.
38 * If you send "reset\n" on the websocket, then
39 * the incrementing number is reset to 0.
41 * lws-mirror-protocol: copies any received packet to every connection also
42 * using this protocol, including the sender
46 #define LOCAL_RESOURCE_PATH "/usr/share/libwebsockets-test-server"
47 static int port = 7681;
50 /* this protocol server (always the first one) just knows how to do HTTP */
52 static int callback_http(struct libwebsocket *wsi,
53 enum libwebsocket_callback_reasons reason, void *user,
57 case LWS_CALLBACK_HTTP:
58 fprintf(stderr, "serving HTTP URI %s\n", in);
60 if (in && strcmp(in, "/favicon.ico") == 0) {
61 if (libwebsockets_serve_http_file(wsi,
62 LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon"))
63 fprintf(stderr, "Failed to send favicon\n");
67 /* send the script... when it runs it'll start websockets */
69 if (libwebsockets_serve_http_file(wsi,
70 LOCAL_RESOURCE_PATH"/test.html", "text/html"))
71 fprintf(stderr, "Failed to send HTTP file\n");
81 /* dumb_increment protocol */
83 struct per_session_data__dumb_increment {
88 callback_dumb_increment(struct libwebsocket *wsi,
89 enum libwebsocket_callback_reasons reason,
90 void *user, void *in, size_t len)
93 char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
94 LWS_SEND_BUFFER_POST_PADDING];
95 char *p = (char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
96 struct per_session_data__dumb_increment *pss = user;
100 case LWS_CALLBACK_ESTABLISHED:
105 * in this protocol, we just use the broadcast action as the chance to
106 * send our own connection-specific data and ignore the broadcast info
107 * that is available in the 'in' parameter
110 case LWS_CALLBACK_BROADCAST:
111 n = sprintf(p, "%d", pss->number++);
112 n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
114 fprintf(stderr, "ERROR writing to socket");
119 case LWS_CALLBACK_RECEIVE:
120 fprintf(stderr, "rx %d\n", len);
123 if (strcmp(in, "reset\n") == 0)
135 /* lws-mirror_protocol */
137 #define MAX_MESSAGE_QUEUE 64
139 struct per_session_data__lws_mirror {
140 struct libwebsocket *wsi;
149 static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
150 static int ringbuffer_head;
154 callback_lws_mirror(struct libwebsocket *wsi,
155 enum libwebsocket_callback_reasons reason,
156 void *user, void *in, size_t len)
159 char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
160 LWS_SEND_BUFFER_POST_PADDING];
161 unsigned char *p = (unsigned char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
162 struct per_session_data__lws_mirror *pss = user;
166 case LWS_CALLBACK_ESTABLISHED:
168 pss->ringbuffer_tail = ringbuffer_head;
171 case LWS_CALLBACK_BROADCAST:
172 n = libwebsocket_write(wsi, in, len, LWS_WRITE_TEXT);
175 case LWS_CALLBACK_RECEIVE:
177 * copy the incoming packet to all other protocol users
179 * This demonstrates how easy it is to broadcast from inside
182 * How this works is it calls back to the callback for all
183 * connected sockets using this protocol with
184 * LWS_CALLBACK_BROADCAST reason. Our handler for that above
185 * writes the data down the socket.
187 libwebsockets_broadcast(libwebsockets_get_protocol(wsi),
199 /* list of supported protocols and callbacks */
201 static struct libwebsocket_protocols protocols[] = {
204 .callback = callback_http,
205 .per_session_data_size = 0,
208 .name = "dumb-increment-protocol",
209 .callback = callback_dumb_increment,
210 .per_session_data_size =
211 sizeof(struct per_session_data__dumb_increment),
214 .name = "lws-mirror-protocol",
215 .callback = callback_lws_mirror,
216 .per_session_data_size =
217 sizeof(struct per_session_data__lws_mirror),
224 static struct option options[] = {
225 { "help", no_argument, NULL, 'h' },
226 { "port", required_argument, NULL, 'p' },
227 { "ssl", no_argument, NULL, 's' },
231 int main(int argc, char **argv)
234 const char *cert_path =
235 LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
236 const char *key_path =
237 LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
238 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 +
239 LWS_SEND_BUFFER_POST_PADDING];
241 fprintf(stderr, "libwebsockets test server\n"
242 "(C) Copyright 2010 Andy Green <andy@warmcat.com> "
243 "licensed under LGPL2.1\n");
246 n = getopt_long(argc, argv, "hp:", options, NULL);
257 fprintf(stderr, "Usage: test-server "
258 "[--port=<p>] [--ssl]\n");
264 cert_path = key_path = NULL;
266 if (libwebsocket_create_server(port, protocols, cert_path, key_path,
268 fprintf(stderr, "libwebsocket init failed\n");
273 * After initializing and creating the websocket server in its own fork
274 * we return to the main process here
277 buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x';
284 * This broadcasts to all dumb-increment-protocol connections
287 * We're just sending a character 'x', in these examples the
288 * callbacks send their own per-connection content.
290 * You have to send something with nonzero length to get the
291 * callback actions delivered.
293 * We take care of pre-and-post padding allocation.
296 /* [1] == dumb-increment-protocol */
297 libwebsockets_broadcast(&protocols[1],
298 &buf[LWS_SEND_BUFFER_PRE_PADDING], 1);