51b5903e441adb1c86b2bc74ca517b3450a344ec
[platform/upstream/libwebsockets.git] / test-server / test-fraggle.c
1 /*
2  * libwebsockets-test-fraggle - random fragmentation test
3  *
4  * Copyright (C) 2011-2016 Andy Green <andy@warmcat.com>
5  *
6  * This file is made available under the Creative Commons CC0 1.0
7  * Universal Public Domain Dedication.
8  *
9  * The person who associated a work with this deed has dedicated
10  * the work to the public domain by waiving all of his or her rights
11  * to the work worldwide under copyright law, including all related
12  * and neighboring rights, to the extent allowed by law. You can copy,
13  * modify, distribute and perform the work, even for commercial purposes,
14  * all without asking permission.
15  *
16  * The test apps are intended to be adapted for use in your code, which
17  * may be proprietary.  So unlike the library itself, they are licensed
18  * Public Domain.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <getopt.h>
24 #include <string.h>
25 #include "../lib/libwebsockets.h"
26
27 #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
28
29 static int client;
30 static int terminate;
31
32 enum demo_protocols {
33         PROTOCOL_FRAGGLE,
34
35         /* always last */
36         DEMO_PROTOCOL_COUNT
37 };
38
39 /* fraggle protocol */
40
41 enum fraggle_states {
42         FRAGSTATE_START_MESSAGE,
43         FRAGSTATE_RANDOM_PAYLOAD,
44         FRAGSTATE_POST_PAYLOAD_SUM,
45 };
46
47 struct per_session_data__fraggle {
48         int packets_left;
49         int total_message;
50         unsigned long sum;
51         enum fraggle_states state;
52 };
53
54 static int
55 callback_fraggle(struct lws *wsi, enum lws_callback_reasons reason,
56                  void *user, void *in, size_t len)
57 {
58         int n;
59         unsigned char buf[LWS_PRE + 8000];
60         struct per_session_data__fraggle *psf = user;
61         int chunk;
62         int write_mode = LWS_WRITE_CONTINUATION;
63         unsigned long sum;
64         unsigned char *p = (unsigned char *)in;
65         unsigned char *bp = &buf[LWS_PRE];
66         int ran;
67
68         switch (reason) {
69
70         case LWS_CALLBACK_ESTABLISHED:
71
72                 fprintf(stderr, "server sees client connect\n");
73                 psf->state = FRAGSTATE_START_MESSAGE;
74                 /* start the ball rolling */
75                 lws_callback_on_writable(wsi);
76                 break;
77
78         case LWS_CALLBACK_CLIENT_ESTABLISHED:
79
80                 fprintf(stderr, "client connects to server\n");
81                 psf->state = FRAGSTATE_START_MESSAGE;
82                 break;
83
84         case LWS_CALLBACK_CLIENT_RECEIVE:
85
86                 switch (psf->state) {
87
88                 case FRAGSTATE_START_MESSAGE:
89
90                         psf->state = FRAGSTATE_RANDOM_PAYLOAD;
91                         psf->sum = 0;
92                         psf->total_message = 0;
93                         psf->packets_left = 0;
94
95                         /* fallthru */
96
97                 case FRAGSTATE_RANDOM_PAYLOAD:
98
99                         for (n = 0; (unsigned int)n < len; n++)
100                                 psf->sum += p[n];
101
102                         psf->total_message += len;
103                         psf->packets_left++;
104
105                         if (lws_is_final_fragment(wsi))
106                                 psf->state = FRAGSTATE_POST_PAYLOAD_SUM;
107                         break;
108
109                 case FRAGSTATE_POST_PAYLOAD_SUM:
110
111                         sum = ((unsigned int)p[0]) << 24;
112                         sum |= p[1] << 16;
113                         sum |= p[2] << 8;
114                         sum |= p[3];
115                         if (sum == psf->sum)
116                                 fprintf(stderr, "EOM received %d correctly "
117                                                 "from %d fragments\n",
118                                         psf->total_message, psf->packets_left);
119                         else
120                                 fprintf(stderr, "**** ERROR at EOM: "
121                                                 "length %d, rx sum = 0x%lX, "
122                                                 "server says it sent 0x%lX\n",
123                                              psf->total_message, psf->sum, sum);
124
125                         psf->state = FRAGSTATE_START_MESSAGE;
126                         break;
127                 }
128                 break;
129
130         case LWS_CALLBACK_SERVER_WRITEABLE:
131
132                 switch (psf->state) {
133
134                 case FRAGSTATE_START_MESSAGE:
135                         lws_get_random(lws_get_context(wsi), &ran, sizeof(ran));
136                         psf->packets_left = (ran & 1023) + 1;
137                         fprintf(stderr, "Spamming %d random fragments\n",
138                                                              psf->packets_left);
139                         psf->sum = 0;
140                         psf->total_message = 0;
141                         write_mode = LWS_WRITE_BINARY;
142                         psf->state = FRAGSTATE_RANDOM_PAYLOAD;
143
144                         /* fallthru */
145
146                 case FRAGSTATE_RANDOM_PAYLOAD:
147
148                         /*
149                          * note how one chunk can be 8000, but we use the
150                          * default rx buffer size of 4096, so we exercise the
151                          * code for rx spill because the rx buffer is full
152                          */
153
154                         lws_get_random(lws_get_context(wsi), &ran, sizeof(ran));
155                         chunk = (ran & 511) + 1;
156                         psf->total_message += chunk;
157
158                         lws_get_random(lws_get_context(wsi), bp, chunk);
159                         for (n = 0; n < chunk; n++)
160                                 psf->sum += bp[n];
161
162                         psf->packets_left--;
163                         if (psf->packets_left)
164                                 write_mode |= LWS_WRITE_NO_FIN;
165                         else
166                                 psf->state = FRAGSTATE_POST_PAYLOAD_SUM;
167
168                         n = lws_write(wsi, bp, chunk, write_mode);
169                         if (n < 0)
170                                 return -1;
171                         if (n < chunk) {
172                                 lwsl_err("Partial write\n");
173                                 return -1;
174                         }
175
176                         lws_callback_on_writable(wsi);
177                         break;
178
179                 case FRAGSTATE_POST_PAYLOAD_SUM:
180
181                         fprintf(stderr, "Spamming session over, "
182                                         "len = %d. sum = 0x%lX\n",
183                                                   psf->total_message, psf->sum);
184
185                         bp[0] = psf->sum >> 24;
186                         bp[1] = (unsigned char)(psf->sum >> 16);
187                         bp[2] = (unsigned char)(psf->sum >> 8);
188                         bp[3] = (unsigned char)psf->sum;
189
190                         n = lws_write(wsi, (unsigned char *)bp,
191                                                            4, LWS_WRITE_BINARY);
192                         if (n < 0)
193                                 return -1;
194                         if (n < 4) {
195                                 lwsl_err("Partial write\n");
196                                 return -1;
197                         }
198
199                         psf->state = FRAGSTATE_START_MESSAGE;
200
201                         lws_callback_on_writable(wsi);
202                         break;
203                 }
204                 break;
205
206         case LWS_CALLBACK_CLOSED:
207
208                 terminate = 1;
209                 break;
210
211         /* because we are protocols[0] ... */
212
213         case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:
214                 if (strcmp(in, "deflate-stream") == 0) {
215                         fprintf(stderr, "denied deflate-stream extension\n");
216                         return 1;
217                 }
218                 break;
219
220         default:
221                 break;
222         }
223
224         return 0;
225 }
226
227
228 /* list of supported protocols and callbacks */
229
230 static struct lws_protocols protocols[] = {
231         {
232                 "fraggle-protocol",
233                 callback_fraggle,
234                 sizeof(struct per_session_data__fraggle),
235         },
236         {
237                 NULL, NULL, 0           /* End of list */
238         }
239 };
240
241 static const struct lws_extension exts[] = {
242         {
243                 "permessage-deflate",
244                 lws_extension_callback_pm_deflate,
245                 "permessage-deflate; client_no_context_takeover; client_max_window_bits"
246         },
247         {
248                 "deflate-frame",
249                 lws_extension_callback_pm_deflate,
250                 "deflate_frame"
251         },
252         { NULL, NULL, NULL /* terminator */ }
253 };
254
255 static struct option options[] = {
256         { "help",       no_argument,            NULL, 'h' },
257         { "debug",      required_argument,      NULL, 'd' },
258         { "port",       required_argument,      NULL, 'p' },
259         { "ssl",        no_argument,            NULL, 's' },
260         { "interface",  required_argument,      NULL, 'i' },
261         { "client",     no_argument,            NULL, 'c' },
262         { NULL, 0, 0, 0 }
263 };
264
265 int main(int argc, char **argv)
266 {
267         int n = 0;
268         int port = 7681;
269         int use_ssl = 0;
270         struct lws_context *context;
271         int opts = 0;
272         char interface_name[128] = "", ads_port[300];
273         const char *iface = NULL;
274         struct lws *wsi;
275         const char *address = NULL;
276         int server_port = port;
277         struct lws_context_creation_info info;
278
279         memset(&info, 0, sizeof info);
280         lwsl_notice("libwebsockets test server fraggle - license LGPL2.1+SLE\n");
281         lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
282
283         while (n >= 0) {
284                 n = getopt_long(argc, argv, "ci:hsp:d:", options, NULL);
285                 if (n < 0)
286                         continue;
287                 switch (n) {
288                 case 'd':
289                         lws_set_log_level(atoi(optarg), NULL);
290                         break;
291                 case 's':
292                         use_ssl = 1;
293                         break;
294                 case 'p':
295                         port = atoi(optarg);
296                         server_port = port;
297                         break;
298                 case 'i':
299                         strncpy(interface_name, optarg, sizeof interface_name);
300                         interface_name[(sizeof interface_name) - 1] = '\0';
301                         iface = interface_name;
302                         break;
303                 case 'c':
304                         client = 1;
305                         fprintf(stderr, " Client mode\n");
306                         break;
307                 case 'h':
308                         fprintf(stderr, "Usage: libwebsockets-test-fraggle "
309                                         "[--port=<p>] [--ssl] "
310                                         "[-d <log bitfield>] "
311                                         "[--client]\n");
312                         exit(1);
313                 }
314         }
315
316         if (client) {
317                 server_port = CONTEXT_PORT_NO_LISTEN;
318                 if (optind >= argc) {
319                         fprintf(stderr, "Must give address of server\n");
320                         return 1;
321                 }
322         }
323
324         info.port = server_port;
325         info.iface = iface;
326         info.protocols = protocols;
327         info.extensions = exts;
328
329         if (use_ssl) {
330                 info.ssl_cert_filepath = LOCAL_RESOURCE_PATH
331                                 "/libwebsockets-test-server.pem";
332                 info.ssl_private_key_filepath = LOCAL_RESOURCE_PATH
333                                 "/libwebsockets-test-server.key.pem";
334         }
335         info.gid = -1;
336         info.uid = -1;
337         info.options = opts;
338
339         context = lws_create_context(&info);
340         if (context == NULL) {
341                 fprintf(stderr, "libwebsocket init failed\n");
342                 return -1;
343         }
344
345         if (client) {
346                 struct lws_client_connect_info i;
347
348                 address = argv[optind];
349                 snprintf(ads_port, sizeof(ads_port), "%s:%u",
350                          address, port & 65535);
351                 memset(&i, 0, sizeof(i));
352                 i.context = context;
353                 i.address = address;
354                 i.port = port;
355                 i.ssl_connection = use_ssl;
356                 i.path = "/";
357                 i.host = ads_port;
358                 i.origin = ads_port;
359                 i.protocol = protocols[PROTOCOL_FRAGGLE].name;
360                 i.client_exts = exts;
361
362                 lwsl_notice("Connecting to %s:%u\n", address, port);
363                 wsi = lws_client_connect_via_info(&i);
364                 if (wsi == NULL) {
365                         fprintf(stderr, "Client connect to server failed\n");
366                         goto bail;
367                 }
368         }
369
370         n = 0;
371         while (!n && !terminate)
372                 n = lws_service(context, 50);
373
374         fprintf(stderr, "Terminating...\n");
375
376 bail:
377         lws_context_destroy(context);
378
379         return 0;
380 }