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.
44 #define LOCAL_RESOURCE_PATH "/usr/share/libwebsockets-test-server"
45 static int port = 7681;
46 static int use_ssl = 0;
48 /* this protocol server (always the first one) just knows how to do HTTP */
50 static int callback_http(struct libwebsocket * wsi,
51 enum libwebsocket_callback_reasons reason, void * user,
55 case LWS_CALLBACK_HTTP:
56 fprintf(stderr, "serving HTTP URI %s\n", in);
58 if (in && strcmp(in, "/favicon.ico") == 0) {
59 if (libwebsockets_serve_http_file(wsi,
60 LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon"))
61 fprintf(stderr, "Failed to send favicon\n");
65 /* send the script... when it runs it'll start websockets */
67 if (libwebsockets_serve_http_file(wsi,
68 LOCAL_RESOURCE_PATH"/test.html", "text/html"))
69 fprintf(stderr, "Failed to send HTTP file\n");
79 /* dumb_increment protocol */
81 struct per_session_data__dumb_increment {
86 callback_dumb_increment(struct libwebsocket * wsi,
87 enum libwebsocket_callback_reasons reason,
88 void * user, void *in, size_t len)
91 char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
92 LWS_SEND_BUFFER_POST_PADDING];
93 unsigned char *p = (unsigned char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
94 struct per_session_data__dumb_increment * pss = user;
98 case LWS_CALLBACK_ESTABLISHED:
102 case LWS_CALLBACK_SEND:
103 n = sprintf(p, "%d", pss->number++);
104 n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
106 fprintf(stderr, "ERROR writing to socket");
111 case LWS_CALLBACK_RECEIVE:
112 fprintf(stderr, "rx %d\n", len);
115 if (strcmp(in, "reset\n") == 0)
127 /* lws-mirror_protocol */
129 #define MAX_MESSAGE_QUEUE 64
130 const int MAX_COMMUNE_MEMBERS = 20;
132 struct per_session_data__lws_mirror {
133 struct libwebsocket * wsi;
138 struct per_session_data * sender;
143 static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
144 static int ringbuffer_head;
147 struct per_session_data * all_members;
151 callback_lws_mirror(struct libwebsocket * wsi,
152 enum libwebsocket_callback_reasons reason,
153 void * user, void *in, size_t len)
156 char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
157 LWS_SEND_BUFFER_POST_PADDING];
158 unsigned char *p = (unsigned char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
159 struct per_session_data__lws_mirror * pss = user;
163 case LWS_CALLBACK_ESTABLISHED:
165 pss->ringbuffer_tail = ringbuffer_head;
168 case LWS_CALLBACK_SEND:
169 /* send everything that's pending */
170 while (pss->ringbuffer_tail != ringbuffer_head) {
172 n = libwebsocket_write(wsi,
173 (unsigned char *)ringbuffer[pss->ringbuffer_tail].payload +
174 LWS_SEND_BUFFER_PRE_PADDING,
175 ringbuffer[pss->ringbuffer_tail].len,
178 fprintf(stderr, "ERROR writing to socket");
182 if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
183 pss->ringbuffer_tail = 0;
185 pss->ringbuffer_tail++;
189 case LWS_CALLBACK_RECEIVE:
190 // fprintf(stderr, "Received %d bytes payload\n", (int)len);
191 ringbuffer[ringbuffer_head].payload =
192 malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
193 LWS_SEND_BUFFER_POST_PADDING);
194 ringbuffer[ringbuffer_head].len = len;
195 ringbuffer[ringbuffer_head].sender = pss;
196 memcpy(ringbuffer[ringbuffer_head].payload +
197 LWS_SEND_BUFFER_PRE_PADDING, in, len);
198 if (ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
212 /* list of supported protocols and callbacks */
214 static const struct libwebsocket_protocols protocols[] = {
217 .callback = callback_http,
218 .per_session_data_size = 0,
221 .name = "dumb-increment-protocol",
222 .callback = callback_dumb_increment,
223 .per_session_data_size =
224 sizeof(struct per_session_data__dumb_increment),
227 .name = "lws-mirror-protocol",
228 .callback = callback_lws_mirror,
229 .per_session_data_size =
230 sizeof(struct per_session_data__lws_mirror),
237 static struct option options[] = {
238 { "help", no_argument, NULL, 'h' },
239 { "port", required_argument, NULL, 'p' },
240 { "ssl", no_argument, NULL, 's' },
244 int main(int argc, char **argv)
247 const char * cert_path =
248 LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
249 const char * key_path =
250 LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
252 fprintf(stderr, "libwebsockets test server\n"
253 "(C) Copyright 2010 Andy Green <andy@warmcat.com> "
254 "licensed under LGPL2.1\n");
257 n = getopt_long(argc, argv, "hp:", options, NULL);
268 fprintf(stderr, "Usage: test-server "
269 "[--port=<p>] [--ssl]\n");
275 cert_path = key_path = NULL;
277 if (libwebsocket_create_server(port, protocols,
278 cert_path, key_path, -1, -1) < 0) {
279 fprintf(stderr, "libwebsocket init failed\n");