blob: 5d98c0ecb5cf58b364264b598acf456a086bfb09 [file] [log] [blame]
Andy Green4739e5c2011-01-22 12:51:57 +00001/*
2 * libwebsockets-test-client - libwebsockets test implementation
3 *
4 * Copyright (C) 2011 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
22#include <stdio.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <getopt.h>
26#include <string.h>
27
Andy Green4739e5c2011-01-22 12:51:57 +000028#include "../lib/libwebsockets.h"
Andy Green4739e5c2011-01-22 12:51:57 +000029
Andy Green990d5062011-01-30 21:04:24 +000030static unsigned int opts;
Andy Greenb3ae0a32011-02-14 20:25:43 +000031static int was_closed;
Andy Green775884e2011-03-06 13:32:53 +000032static int deny_deflate;
Andy Green4084af12011-05-24 22:06:17 +010033static struct libwebsocket *wsi_mirror;
Andy Green990d5062011-01-30 21:04:24 +000034
Andy Green4739e5c2011-01-22 12:51:57 +000035/*
36 * This demo shows how to connect multiple websockets simultaneously to a
37 * websocket server (there is no restriction on their having to be the same
38 * server just it simplifies the demo).
39 *
40 * dumb-increment-protocol: we connect to the server and print the number
Andy Green90c7cbc2011-01-27 06:26:52 +000041 * we are given
Andy Green4739e5c2011-01-22 12:51:57 +000042 *
43 * lws-mirror-protocol: draws random circles, which are mirrored on to every
Andy Green90c7cbc2011-01-27 06:26:52 +000044 * client (see them being drawn in every browser
45 * session also using the test server)
Andy Green4739e5c2011-01-22 12:51:57 +000046 */
47
48enum demo_protocols {
49
50 PROTOCOL_DUMB_INCREMENT,
51 PROTOCOL_LWS_MIRROR,
52
53 /* always last */
54 DEMO_PROTOCOL_COUNT
55};
56
57
58/* dumb_increment protocol */
59
60static int
Andy Green62c54d22011-02-14 09:14:25 +000061callback_dumb_increment(struct libwebsocket_context * this,
62 struct libwebsocket *wsi,
Andy Green4739e5c2011-01-22 12:51:57 +000063 enum libwebsocket_callback_reasons reason,
64 void *user, void *in, size_t len)
65{
66 switch (reason) {
67
Andy Green4084af12011-05-24 22:06:17 +010068 case LWS_CALLBACK_CLOSED:
69 fprintf(stderr, "LWS_CALLBACK_CLOSED\n");
70 was_closed = 1;
71 break;
72
Andy Green4739e5c2011-01-22 12:51:57 +000073 case LWS_CALLBACK_CLIENT_RECEIVE:
Andy Green90c7cbc2011-01-27 06:26:52 +000074 ((char *)in)[len] = '\0';
75 fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in);
Andy Green4739e5c2011-01-22 12:51:57 +000076 break;
77
Andy Green775884e2011-03-06 13:32:53 +000078 /* because we are protocols[0] ... */
79
80 case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:
81 if (strcmp(in, "deflate-stream") == 0)
82 if (deny_deflate) {
83 fprintf(stderr, "denied deflate-stream extension\n");
84 return 1;
85 }
86 break;
87
Andy Green4739e5c2011-01-22 12:51:57 +000088 default:
89 break;
90 }
91
92 return 0;
93}
94
95
96/* lws-mirror_protocol */
97
Andy Green4739e5c2011-01-22 12:51:57 +000098
99static int
Andy Green62c54d22011-02-14 09:14:25 +0000100callback_lws_mirror(struct libwebsocket_context * this,
101 struct libwebsocket *wsi,
Andy Green4739e5c2011-01-22 12:51:57 +0000102 enum libwebsocket_callback_reasons reason,
103 void *user, void *in, size_t len)
104{
Andy Green90c7cbc2011-01-27 06:26:52 +0000105 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 +
106 LWS_SEND_BUFFER_POST_PADDING];
107 int l;
108
Andy Green4739e5c2011-01-22 12:51:57 +0000109 switch (reason) {
110
Andy Greenb3ae0a32011-02-14 20:25:43 +0000111 case LWS_CALLBACK_CLOSED:
Andy Green4084af12011-05-24 22:06:17 +0100112 fprintf(stderr, "mirror: LWS_CALLBACK_CLOSED\n");
113 wsi_mirror = NULL;
Andy Greenb3ae0a32011-02-14 20:25:43 +0000114 break;
115
Andy Green90c7cbc2011-01-27 06:26:52 +0000116 case LWS_CALLBACK_CLIENT_ESTABLISHED:
117
118 /*
119 * start the ball rolling,
Andy Greenb6e6ebe2011-01-27 06:36:39 +0000120 * LWS_CALLBACK_CLIENT_WRITEABLE will come next service
Andy Green90c7cbc2011-01-27 06:26:52 +0000121 */
122
Andy Green62c54d22011-02-14 09:14:25 +0000123 libwebsocket_callback_on_writable(this, wsi);
Andy Green90c7cbc2011-01-27 06:26:52 +0000124 break;
125
Andy Green4739e5c2011-01-22 12:51:57 +0000126 case LWS_CALLBACK_CLIENT_RECEIVE:
Andy Green90c7cbc2011-01-27 06:26:52 +0000127/* fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in); */
128 break;
129
130 case LWS_CALLBACK_CLIENT_WRITEABLE:
131
132 l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING],
133 "c #%06X %d %d %d;",
134 (int)random() & 0xffffff,
135 (int)random() % 500,
136 (int)random() % 250,
137 (int)random() % 24);
138
139 libwebsocket_write(wsi,
Andy Green990d5062011-01-30 21:04:24 +0000140 &buf[LWS_SEND_BUFFER_PRE_PADDING], l, opts | LWS_WRITE_TEXT);
Andy Green90c7cbc2011-01-27 06:26:52 +0000141
142 /* get notified as soon as we can write again */
143
Andy Green62c54d22011-02-14 09:14:25 +0000144 libwebsocket_callback_on_writable(this, wsi);
Andy Green90c7cbc2011-01-27 06:26:52 +0000145
Andy Greenb6e6ebe2011-01-27 06:36:39 +0000146 /*
147 * without at least this delay, we choke the browser
148 * and the connection stalls, despite we now take care about
149 * flow control
150 */
151
Andy Green90c7cbc2011-01-27 06:26:52 +0000152 usleep(200);
Andy Green4739e5c2011-01-22 12:51:57 +0000153 break;
154
155 default:
156 break;
157 }
158
159 return 0;
160}
161
162
163/* list of supported protocols and callbacks */
164
165static struct libwebsocket_protocols protocols[] = {
Peter Hinz56885f32011-03-02 22:03:47 +0000166 {
167 "dumb-increment-protocol",
168 callback_dumb_increment,
169 0,
Andy Green4739e5c2011-01-22 12:51:57 +0000170 },
Peter Hinz56885f32011-03-02 22:03:47 +0000171 {
172 "lws-mirror-protocol",
173 callback_lws_mirror,
174 0,
Andy Green4739e5c2011-01-22 12:51:57 +0000175 },
Peter Hinz56885f32011-03-02 22:03:47 +0000176 { /* end of list */
177 NULL,
178 NULL,
179 0
Andy Green4739e5c2011-01-22 12:51:57 +0000180 }
181};
182
183static struct option options[] = {
Andy Green90c7cbc2011-01-27 06:26:52 +0000184 { "help", no_argument, NULL, 'h' },
185 { "port", required_argument, NULL, 'p' },
186 { "ssl", no_argument, NULL, 's' },
Andy Green990d5062011-01-30 21:04:24 +0000187 { "killmask", no_argument, NULL, 'k' },
Andy Greenbfb051f2011-02-09 08:49:14 +0000188 { "version", required_argument, NULL, 'v' },
Andy Green775884e2011-03-06 13:32:53 +0000189 { "undeflated", no_argument, NULL, 'u' },
Andy Green4739e5c2011-01-22 12:51:57 +0000190 { NULL, 0, 0, 0 }
191};
192
193
194int main(int argc, char **argv)
195{
196 int n = 0;
197 int port = 7681;
198 int use_ssl = 0;
199 struct libwebsocket_context *context;
Andy Green1efb63c2011-02-06 17:42:06 +0000200 const char *address;
Andy Green4739e5c2011-01-22 12:51:57 +0000201 struct libwebsocket *wsi_dumb;
Andy Greenbfb051f2011-02-09 08:49:14 +0000202 int ietf_version = -1; /* latest */
Andy Green4084af12011-05-24 22:06:17 +0100203 int mirror_lifetime = 0;
Andy Green90c7cbc2011-01-27 06:26:52 +0000204
Andy Green4739e5c2011-01-22 12:51:57 +0000205 fprintf(stderr, "libwebsockets test client\n"
206 "(C) Copyright 2010 Andy Green <andy@warmcat.com> "
207 "licensed under LGPL2.1\n");
208
209 if (argc < 2)
210 goto usage;
211
Andy Green4739e5c2011-01-22 12:51:57 +0000212 while (n >= 0) {
Andy Green775884e2011-03-06 13:32:53 +0000213 n = getopt_long(argc, argv, "uv:khsp:", options, NULL);
Andy Green4739e5c2011-01-22 12:51:57 +0000214 if (n < 0)
215 continue;
216 switch (n) {
217 case 's':
Andy Green90c7cbc2011-01-27 06:26:52 +0000218 use_ssl = 2; /* 2 = allow selfsigned */
Andy Green4739e5c2011-01-22 12:51:57 +0000219 break;
220 case 'p':
221 port = atoi(optarg);
222 break;
Andy Green990d5062011-01-30 21:04:24 +0000223 case 'k':
224 opts = LWS_WRITE_CLIENT_IGNORE_XOR_MASK;
225 break;
Andy Greenbfb051f2011-02-09 08:49:14 +0000226 case 'v':
227 ietf_version = atoi(optarg);
228 break;
Andy Green775884e2011-03-06 13:32:53 +0000229 case 'u':
230 deny_deflate = 1;
231 break;
Andy Green4739e5c2011-01-22 12:51:57 +0000232 case 'h':
233 goto usage;
234 }
235 }
236
Andy Green1efb63c2011-02-06 17:42:06 +0000237 if (optind >= argc)
238 goto usage;
239
240 address = argv[optind];
241
Andy Green4739e5c2011-01-22 12:51:57 +0000242 /*
243 * create the websockets context. This tracks open connections and
244 * knows how to route any traffic and which protocol version to use,
245 * and if each connection is client or server side.
246 *
247 * For this client-only demo, we tell it to not listen on any port.
248 */
249
Andy Green32375b72011-02-19 08:32:53 +0000250 context = libwebsocket_create_context(CONTEXT_PORT_NO_LISTEN, NULL,
Andy Green4cd87a02011-03-06 13:15:32 +0000251 protocols, libwebsocket_internal_extensions,
252 NULL, NULL, -1, -1, 0);
Andy Green4739e5c2011-01-22 12:51:57 +0000253 if (context == NULL) {
254 fprintf(stderr, "Creating libwebsocket context failed\n");
255 return 1;
256 }
257
258
259 /* create a client websocket using dumb increment protocol */
260
Andy Green90c7cbc2011-01-27 06:26:52 +0000261 wsi_dumb = libwebsocket_client_connect(context, address, port, use_ssl,
Andy Green1efb63c2011-02-06 17:42:06 +0000262 "/", argv[optind], argv[optind],
Andy Greenbfb051f2011-02-09 08:49:14 +0000263 protocols[PROTOCOL_DUMB_INCREMENT].name, ietf_version);
Andy Green4739e5c2011-01-22 12:51:57 +0000264
265 if (wsi_dumb == NULL) {
266 fprintf(stderr, "libwebsocket dumb connect failed\n");
267 return -1;
268 }
269
Andy Green4739e5c2011-01-22 12:51:57 +0000270 fprintf(stderr, "Websocket connections opened\n");
271
272 /*
273 * sit there servicing the websocket context to handle incoming
274 * packets, and drawing random circles on the mirror protocol websocket
275 */
276
277 n = 0;
Andy Green4084af12011-05-24 22:06:17 +0100278 while (n >= 0 && !was_closed) {
Andy Green90c7cbc2011-01-27 06:26:52 +0000279 n = libwebsocket_service(context, 1000);
Andy Green4739e5c2011-01-22 12:51:57 +0000280
Andy Green4084af12011-05-24 22:06:17 +0100281 if (wsi_mirror == NULL) {
282
283 /* create a client websocket using mirror protocol */
284
285 wsi_mirror = libwebsocket_client_connect(context, address, port,
286 use_ssl, "/", argv[optind], argv[optind],
287 protocols[PROTOCOL_LWS_MIRROR].name, ietf_version);
288
289 if (wsi_mirror == NULL) {
290 fprintf(stderr, "libwebsocket dumb connect failed\n");
291 return -1;
292 }
293
294 mirror_lifetime = 10 + (random() & 1023);
295
296 fprintf(stderr, "opened mirror connection with %d lifetime\n", mirror_lifetime);
297
298 } else {
299
300 mirror_lifetime--;
301 if (mirror_lifetime == 0) {
302 fprintf(stderr, "closing mirror session\n");
303 libwebsocket_close_and_free_session(context,
304 wsi_mirror, LWS_CLOSE_STATUS_GOINGAWAY);
305
306 /*
307 * wsi_mirror will get set to NULL in
308 * callback when close completes
309 */
310 }
311 }
312 }
313
Andy Greenb3ae0a32011-02-14 20:25:43 +0000314 fprintf(stderr, "Exiting\n");
315
Andy Green6964bb52011-01-23 16:50:33 +0000316 libwebsocket_context_destroy(context);
317
Andy Green4739e5c2011-01-22 12:51:57 +0000318 return 0;
319
320usage:
321 fprintf(stderr, "Usage: libwebsockets-test-client "
322 "<server address> [--port=<p>] "
Andy Green5e1fa172011-02-10 09:07:05 +0000323 "[--ssl] [-k] [-v <ver>]\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000324 return 1;
325}