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;
48 static int use_ssl = 0;
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 unsigned char *p = (unsigned char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
96 struct per_session_data__dumb_increment * pss = user;
100 case LWS_CALLBACK_ESTABLISHED:
104 case LWS_CALLBACK_SEND:
105 n = sprintf(p, "%d", pss->number++);
106 n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
108 fprintf(stderr, "ERROR writing to socket");
113 case LWS_CALLBACK_RECEIVE:
114 fprintf(stderr, "rx %d\n", len);
117 if (strcmp(in, "reset\n") == 0)
129 /* lws-mirror_protocol */
131 #define MAX_MESSAGE_QUEUE 64
133 struct per_session_data__lws_mirror {
134 struct libwebsocket * wsi;
143 static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
144 static int ringbuffer_head;
148 callback_lws_mirror(struct libwebsocket * wsi,
149 enum libwebsocket_callback_reasons reason,
150 void * user, void *in, size_t len)
153 char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
154 LWS_SEND_BUFFER_POST_PADDING];
155 unsigned char *p = (unsigned char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
156 struct per_session_data__lws_mirror * pss = user;
160 case LWS_CALLBACK_ESTABLISHED:
162 pss->ringbuffer_tail = ringbuffer_head;
165 case LWS_CALLBACK_SEND:
166 /* send everything that's pending */
167 while (pss->ringbuffer_tail != ringbuffer_head) {
169 n = libwebsocket_write(wsi,
170 (unsigned char *)ringbuffer[pss->ringbuffer_tail].payload +
171 LWS_SEND_BUFFER_PRE_PADDING,
172 ringbuffer[pss->ringbuffer_tail].len,
175 fprintf(stderr, "ERROR writing to socket");
179 if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
180 pss->ringbuffer_tail = 0;
182 pss->ringbuffer_tail++;
186 case LWS_CALLBACK_RECEIVE:
187 if (ringbuffer[ringbuffer_head].payload)
188 free(ringbuffer[ringbuffer_head].payload );
190 ringbuffer[ringbuffer_head].payload =
191 malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
192 LWS_SEND_BUFFER_POST_PADDING);
193 ringbuffer[ringbuffer_head].len = len;
194 memcpy(ringbuffer[ringbuffer_head].payload +
195 LWS_SEND_BUFFER_PRE_PADDING, in, len);
196 if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
210 /* list of supported protocols and callbacks */
212 static const struct libwebsocket_protocols protocols[] = {
215 .callback = callback_http,
216 .per_session_data_size = 0,
219 .name = "dumb-increment-protocol",
220 .callback = callback_dumb_increment,
221 .per_session_data_size =
222 sizeof(struct per_session_data__dumb_increment),
225 .name = "lws-mirror-protocol",
226 .callback = callback_lws_mirror,
227 .per_session_data_size =
228 sizeof(struct per_session_data__lws_mirror),
235 static struct option options[] = {
236 { "help", no_argument, NULL, 'h' },
237 { "port", required_argument, NULL, 'p' },
238 { "ssl", no_argument, NULL, 's' },
242 int main(int argc, char **argv)
245 const char * cert_path =
246 LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
247 const char * key_path =
248 LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
250 fprintf(stderr, "libwebsockets test server\n"
251 "(C) Copyright 2010 Andy Green <andy@warmcat.com> "
252 "licensed under LGPL2.1\n");
255 n = getopt_long(argc, argv, "hp:", options, NULL);
266 fprintf(stderr, "Usage: test-server "
267 "[--port=<p>] [--ssl]\n");
273 cert_path = key_path = NULL;
275 if (libwebsocket_create_server(port, protocols,
276 cert_path, key_path, -1, -1) < 0) {
277 fprintf(stderr, "libwebsocket init failed\n");