blob: d35e826bb5f23115ee6093261bda8556e88a42f7 [file] [log] [blame]
Andy Greena0da8a82010-11-08 17:12:19 +00001/*
2 * libwebsockets-test-server - libwebsockets test implementation
3 *
4 * Copyright (C) 2010 Andy Green <andy@warmcat.com>
5 *
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 */
21
Andy Green775c0dd2010-10-29 14:15:22 +010022#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
Andy Greenea71ed12010-10-31 07:40:33 +000025#include <getopt.h>
Andy Green5fd8a5e2010-10-31 11:57:17 +000026#include <string.h>
27
Andy Green7310e9c2010-11-01 09:12:17 +000028#include "../lib/libwebsockets.h"
Andy Green775c0dd2010-10-29 14:15:22 +010029
Andy Greenfe2a0d22010-11-12 13:10:40 +000030/*
31 * This demo server shows how to use libwebsockets for one or more
32 * websocket protocols in the same server
33 *
34 * It defines the following websocket protocols:
35 *
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.
40 *
41 */
42
43
Andy Green3138e442010-11-01 09:20:48 +000044#define LOCAL_RESOURCE_PATH "/usr/share/libwebsockets-test-server"
Andy Greenea71ed12010-10-31 07:40:33 +000045static int port = 7681;
Andy Green3faa9c72010-11-08 17:03:03 +000046static int use_ssl = 0;
Andy Green775c0dd2010-10-29 14:15:22 +010047
Andy Green4f3943a2010-11-12 10:44:16 +000048/* this protocol server (always the first one) just knows how to do HTTP */
Andy Green251f6fa2010-11-03 11:13:06 +000049
Andy Green4f3943a2010-11-12 10:44:16 +000050static int callback_http(struct libwebsocket * wsi,
Andy Green251f6fa2010-11-03 11:13:06 +000051 enum libwebsocket_callback_reasons reason, void * user,
52 void *in, size_t len)
Andy Green775c0dd2010-10-29 14:15:22 +010053{
Andy Green775c0dd2010-10-29 14:15:22 +010054 switch (reason) {
Andy Green5fd8a5e2010-10-31 11:57:17 +000055 case LWS_CALLBACK_HTTP:
Andy Greena2b0ab02010-11-11 12:28:29 +000056 fprintf(stderr, "serving HTTP URI %s\n", in);
Andy Green3faa9c72010-11-08 17:03:03 +000057
Andy Greena2b0ab02010-11-11 12:28:29 +000058 if (in && strcmp(in, "/favicon.ico") == 0) {
Andy Green3138e442010-11-01 09:20:48 +000059 if (libwebsockets_serve_http_file(wsi,
60 LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon"))
Andy Greenab990e42010-10-31 12:42:52 +000061 fprintf(stderr, "Failed to send favicon\n");
Andy Green5fd8a5e2010-10-31 11:57:17 +000062 break;
63 }
64
65 /* send the script... when it runs it'll start websockets */
66
Andy Green3138e442010-11-01 09:20:48 +000067 if (libwebsockets_serve_http_file(wsi,
68 LOCAL_RESOURCE_PATH"/test.html", "text/html"))
Andy Green5fd8a5e2010-10-31 11:57:17 +000069 fprintf(stderr, "Failed to send HTTP file\n");
Andy Green5fd8a5e2010-10-31 11:57:17 +000070 break;
Andy Greena2b0ab02010-11-11 12:28:29 +000071
Andy Green4f3943a2010-11-12 10:44:16 +000072 default:
73 break;
Andy Green775c0dd2010-10-29 14:15:22 +010074 }
Andy Greenab990e42010-10-31 12:42:52 +000075
Andy Green775c0dd2010-10-29 14:15:22 +010076 return 0;
77}
78
Andy Green4f3943a2010-11-12 10:44:16 +000079/* dumb_increment protocol */
80
81struct per_session_data__dumb_increment {
82 int number;
83};
84
85static int
86callback_dumb_increment(struct libwebsocket * wsi,
87 enum libwebsocket_callback_reasons reason,
88 void * user, void *in, size_t len)
89{
90 int n;
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;
95
96 switch (reason) {
97
98 case LWS_CALLBACK_ESTABLISHED:
99 pss->number = 0;
100 break;
101
102 case LWS_CALLBACK_SEND:
103 n = sprintf(p, "%d", pss->number++);
104 n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
105 if (n < 0) {
106 fprintf(stderr, "ERROR writing to socket");
107 return 1;
108 }
109 break;
110
111 case LWS_CALLBACK_RECEIVE:
Andy Greenfe2a0d22010-11-12 13:10:40 +0000112 fprintf(stderr, "rx %d\n", len);
Andy Green4f3943a2010-11-12 10:44:16 +0000113 if (len < 6)
114 break;
115 if (strcmp(in, "reset\n") == 0)
116 pss->number = 0;
117 break;
118
119 default:
120 break;
121 }
122
123 return 0;
124}
125
126
Andy Greenfe2a0d22010-11-12 13:10:40 +0000127/* lws-mirror_protocol */
128
129#define MAX_MESSAGE_QUEUE 64
130const int MAX_COMMUNE_MEMBERS = 20;
131
132struct per_session_data__lws_mirror {
133 struct libwebsocket * wsi;
134 int ringbuffer_tail;
135};
136
137struct a_message {
138 struct per_session_data * sender;
139 void * payload;
140 size_t len;
141};
142
143static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
144static int ringbuffer_head;
145
146
147struct per_session_data * all_members;
148
149
150static int
151callback_lws_mirror(struct libwebsocket * wsi,
152 enum libwebsocket_callback_reasons reason,
153 void * user, void *in, size_t len)
154{
155 int n;
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;
160
161 switch (reason) {
162
163 case LWS_CALLBACK_ESTABLISHED:
164 pss->wsi = wsi;
165 pss->ringbuffer_tail = ringbuffer_head;
166 break;
167
168 case LWS_CALLBACK_SEND:
169 /* send everything that's pending */
170 while (pss->ringbuffer_tail != ringbuffer_head) {
171
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,
176 LWS_WRITE_TEXT);
177 if (n < 0) {
178 fprintf(stderr, "ERROR writing to socket");
179 exit(1);
180 }
181
182 if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
183 pss->ringbuffer_tail = 0;
184 else
185 pss->ringbuffer_tail++;
186 }
187 break;
188
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))
199 ringbuffer_head = 0;
200 else
201 ringbuffer_head++;
202 break;
203
204 default:
205 break;
206 }
207
208 return 0;
209}
210
211
Andy Green4f3943a2010-11-12 10:44:16 +0000212/* list of supported protocols and callbacks */
213
214static const struct libwebsocket_protocols protocols[] = {
215 {
216 .name = "http-only",
217 .callback = callback_http,
218 .per_session_data_size = 0,
219 },
220 {
221 .name = "dumb-increment-protocol",
222 .callback = callback_dumb_increment,
223 .per_session_data_size =
224 sizeof(struct per_session_data__dumb_increment),
225 },
Andy Greenfe2a0d22010-11-12 13:10:40 +0000226 {
227 .name = "lws-mirror-protocol",
228 .callback = callback_lws_mirror,
229 .per_session_data_size =
230 sizeof(struct per_session_data__lws_mirror),
231 },
Andy Green4f3943a2010-11-12 10:44:16 +0000232 { /* end of list */
233 .callback = NULL
234 }
235};
236
Andy Greenea71ed12010-10-31 07:40:33 +0000237static struct option options[] = {
238 { "help", no_argument, NULL, 'h' },
239 { "port", required_argument, NULL, 'p' },
Andy Green3faa9c72010-11-08 17:03:03 +0000240 { "ssl", no_argument, NULL, 's' },
Andy Greenea71ed12010-10-31 07:40:33 +0000241 { NULL, 0, 0, 0 }
242};
Andy Green775c0dd2010-10-29 14:15:22 +0100243
Andy Greenea71ed12010-10-31 07:40:33 +0000244int main(int argc, char **argv)
Andy Green775c0dd2010-10-29 14:15:22 +0100245{
Andy Greenea71ed12010-10-31 07:40:33 +0000246 int n = 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000247 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";
Andy Greenea71ed12010-10-31 07:40:33 +0000251
Andy Greenab990e42010-10-31 12:42:52 +0000252 fprintf(stderr, "libwebsockets test server\n"
Andy Green6452f1e2010-11-11 09:22:22 +0000253 "(C) Copyright 2010 Andy Green <andy@warmcat.com> "
254 "licensed under LGPL2.1\n");
Andy Greenea71ed12010-10-31 07:40:33 +0000255
256 while (n >= 0) {
Andy Green4f3943a2010-11-12 10:44:16 +0000257 n = getopt_long(argc, argv, "hp:", options, NULL);
Andy Greenea71ed12010-10-31 07:40:33 +0000258 if (n < 0)
259 continue;
260 switch (n) {
Andy Green3faa9c72010-11-08 17:03:03 +0000261 case 's':
262 use_ssl = 1;
263 break;
Andy Greenea71ed12010-10-31 07:40:33 +0000264 case 'p':
265 port = atoi(optarg);
266 break;
Andy Greenea71ed12010-10-31 07:40:33 +0000267 case 'h':
Andy Greenab990e42010-10-31 12:42:52 +0000268 fprintf(stderr, "Usage: test-server "
Andy Green4f3943a2010-11-12 10:44:16 +0000269 "[--port=<p>] [--ssl]\n");
Andy Greenea71ed12010-10-31 07:40:33 +0000270 exit(1);
271 }
Andy Greenea71ed12010-10-31 07:40:33 +0000272 }
Andy Green3faa9c72010-11-08 17:03:03 +0000273
274 if (!use_ssl)
275 cert_path = key_path = NULL;
Andy Greenea71ed12010-10-31 07:40:33 +0000276
Andy Green4f3943a2010-11-12 10:44:16 +0000277 if (libwebsocket_create_server(port, protocols,
278 cert_path, key_path, -1, -1) < 0) {
Andy Green775c0dd2010-10-29 14:15:22 +0100279 fprintf(stderr, "libwebsocket init failed\n");
280 return -1;
281 }
Andy Green775c0dd2010-10-29 14:15:22 +0100282
283 return 0;
284}