tizen 2.3.1 release
[external/libwebsockets.git] / test-server / test-fraggle.c
1 /*
2  * libwebsockets-test-fraggle - random fragmentation test
3  *
4  * Copyright (C) 2010-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 #include <sys/time.h>
28
29 #ifdef CMAKE_BUILD
30 #include "lws_config.h"
31 #endif
32
33 #include "../lib/libwebsockets.h"
34
35 #define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
36
37 static int client;
38 static int terminate;
39
40 enum demo_protocols {
41         PROTOCOL_FRAGGLE,
42
43         /* always last */
44         DEMO_PROTOCOL_COUNT
45 };
46
47 /* fraggle protocol */
48
49 enum fraggle_states {
50         FRAGSTATE_START_MESSAGE,
51         FRAGSTATE_RANDOM_PAYLOAD,
52         FRAGSTATE_POST_PAYLOAD_SUM,
53 };
54
55 struct per_session_data__fraggle {
56         int packets_left;
57         int total_message;
58         unsigned long sum;
59         enum fraggle_states state;
60 };
61
62 static int
63 callback_fraggle(struct libwebsocket_context *context,
64                         struct libwebsocket *wsi,
65                         enum libwebsocket_callback_reasons reason,
66                                                void *user, void *in, size_t len)
67 {
68         int n;
69         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 8000 +
70                                                   LWS_SEND_BUFFER_POST_PADDING];
71         struct per_session_data__fraggle *psf = user;
72         int chunk;
73         int write_mode = LWS_WRITE_CONTINUATION;
74         unsigned long sum;
75         unsigned char *p = (unsigned char *)in;
76         unsigned char *bp = &buf[LWS_SEND_BUFFER_PRE_PADDING];
77
78         switch (reason) {
79
80         case LWS_CALLBACK_ESTABLISHED:
81
82                 fprintf(stderr, "server sees client connect\n");
83                 psf->state = FRAGSTATE_START_MESSAGE;
84                 /* start the ball rolling */
85                 libwebsocket_callback_on_writable(context, wsi);
86                 break;
87
88         case LWS_CALLBACK_CLIENT_ESTABLISHED:
89
90                 fprintf(stderr, "client connects to server\n");
91                 psf->state = FRAGSTATE_START_MESSAGE;
92                 break;
93
94         case LWS_CALLBACK_CLIENT_RECEIVE:
95
96                 switch (psf->state) {
97
98                 case FRAGSTATE_START_MESSAGE:
99
100                         psf->state = FRAGSTATE_RANDOM_PAYLOAD;
101                         psf->sum = 0;
102                         psf->total_message = 0;
103                         psf->packets_left = 0;
104
105                         /* fallthru */
106
107                 case FRAGSTATE_RANDOM_PAYLOAD:
108
109                         for (n = 0; n < len; n++)
110                                 psf->sum += p[n];
111
112                         psf->total_message += len;
113                         psf->packets_left++;
114
115                         if (libwebsocket_is_final_fragment(wsi))
116                                 psf->state = FRAGSTATE_POST_PAYLOAD_SUM;
117                         break;
118
119                 case FRAGSTATE_POST_PAYLOAD_SUM:
120
121                         sum = p[0] << 24;
122                         sum |= p[1] << 16;
123                         sum |= p[2] << 8;
124                         sum |= p[3];
125                         if (sum == psf->sum)
126                                 fprintf(stderr, "EOM received %d correctly "
127                                                 "from %d fragments\n",
128                                         psf->total_message, psf->packets_left);
129                         else
130                                 fprintf(stderr, "**** ERROR at EOM: "
131                                                 "length %d, rx sum = 0x%lX, "
132                                                 "server says it sent 0x%lX\n",
133                                              psf->total_message, psf->sum, sum);
134
135                         psf->state = FRAGSTATE_START_MESSAGE;
136                         break;
137                 }
138                 break;
139
140         case LWS_CALLBACK_SERVER_WRITEABLE:
141
142                 switch (psf->state) {
143
144                 case FRAGSTATE_START_MESSAGE:
145
146                         psf->packets_left = (random() % 1024) + 1;
147                         fprintf(stderr, "Spamming %d random fragments\n",
148                                                              psf->packets_left);
149                         psf->sum = 0;
150                         psf->total_message = 0;
151                         write_mode = LWS_WRITE_BINARY;
152                         psf->state = FRAGSTATE_RANDOM_PAYLOAD;
153
154                         /* fallthru */
155
156                 case FRAGSTATE_RANDOM_PAYLOAD:
157
158                         /*
159                          * note how one chunk can be 8000, but we use the
160                          * default rx buffer size of 4096, so we exercise the
161                          * code for rx spill because the rx buffer is full
162                          */
163
164                         chunk = (random() % 8000) + 1;
165                         psf->total_message += chunk;
166
167                         libwebsockets_get_random(context, bp, chunk);
168                         for (n = 0; n < chunk; n++)
169                                 psf->sum += bp[n];
170
171                         psf->packets_left--;
172                         if (psf->packets_left)
173                                 write_mode |= LWS_WRITE_NO_FIN;
174                         else
175                                 psf->state = FRAGSTATE_POST_PAYLOAD_SUM;
176
177                         n = libwebsocket_write(wsi, bp, chunk, write_mode);
178                         if (n < 0)
179                                 return -1;
180                         if (n < chunk) {
181                                 lwsl_err("Partial write\n");
182                                 return -1;
183                         }
184
185                         libwebsocket_callback_on_writable(context, wsi);
186                         break;
187
188                 case FRAGSTATE_POST_PAYLOAD_SUM:
189
190                         fprintf(stderr, "Spamming session over, "
191                                         "len = %d. sum = 0x%lX\n",
192                                                   psf->total_message, psf->sum);
193
194                         bp[0] = psf->sum >> 24;
195                         bp[1] = psf->sum >> 16;
196                         bp[2] = psf->sum >> 8;
197                         bp[3] = psf->sum;
198
199                         n = libwebsocket_write(wsi, (unsigned char *)bp,
200                                                            4, LWS_WRITE_BINARY);
201                         if (n < 0)
202                                 return -1;
203                         if (n < 4) {
204                                 lwsl_err("Partial write\n");
205                                 return -1;
206                         }
207
208                         psf->state = FRAGSTATE_START_MESSAGE;
209
210                         libwebsocket_callback_on_writable(context, wsi);
211                         break;
212                 }
213                 break;
214
215         case LWS_CALLBACK_CLOSED:
216
217                 terminate = 1;
218                 break;
219
220         /* because we are protocols[0] ... */
221
222         case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:
223                 if (strcmp(in, "deflate-stream") == 0) {
224                         fprintf(stderr, "denied deflate-stream extension\n");
225                         return 1;
226                 }
227                 break;
228
229         default:
230                 break;
231         }
232
233         return 0;
234 }
235
236
237
238 /* list of supported protocols and callbacks */
239
240 static struct libwebsocket_protocols protocols[] = {
241         {
242                 "fraggle-protocol",
243                 callback_fraggle,
244                 sizeof(struct per_session_data__fraggle),
245         },
246         {
247                 NULL, NULL, 0           /* End of list */
248         }
249 };
250
251 static struct option options[] = {
252         { "help",       no_argument,            NULL, 'h' },
253         { "debug",      required_argument,      NULL, 'd' },
254         { "port",       required_argument,      NULL, 'p' },
255         { "ssl",        no_argument,            NULL, 's' },
256         { "interface",  required_argument,      NULL, 'i' },
257         { "client",     no_argument,            NULL, 'c' },
258         { NULL, 0, 0, 0 }
259 };
260
261 int main(int argc, char **argv)
262 {
263         int n = 0;
264         int port = 7681;
265         int use_ssl = 0;
266         struct libwebsocket_context *context;
267         int opts = 0;
268         char interface_name[128] = "";
269         const char *iface = NULL;
270         struct libwebsocket *wsi;
271         const char *address;
272         int server_port = port;
273         struct lws_context_creation_info info;
274
275         memset(&info, 0, sizeof info);
276
277         fprintf(stderr, "libwebsockets test fraggle\n"
278                         "(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> "
279                                                     "licensed under LGPL2.1\n");
280
281         while (n >= 0) {
282                 n = getopt_long(argc, argv, "ci:hsp:d:", options, NULL);
283                 if (n < 0)
284                         continue;
285                 switch (n) {
286                 case 'd':
287                         lws_set_log_level(atoi(optarg), NULL);
288                         break;
289                 case 's':
290                         use_ssl = 1;
291                         break;
292                 case 'p':
293                         port = atoi(optarg);
294                         server_port = port;
295                         break;
296                 case 'i':
297                         strncpy(interface_name, optarg, sizeof interface_name);
298                         interface_name[(sizeof interface_name) - 1] = '\0';
299                         iface = interface_name;
300                         break;
301                 case 'c':
302                         client = 1;
303                         fprintf(stderr, " Client mode\n");
304                         break;
305                 case 'h':
306                         fprintf(stderr, "Usage: libwebsockets-test-fraggle "
307                                         "[--port=<p>] [--ssl] "
308                                         "[-d <log bitfield>] "
309                                         "[--client]\n");
310                         exit(1);
311                 }
312         }
313
314         if (client) {
315                 server_port = CONTEXT_PORT_NO_LISTEN;
316                 if (optind >= argc) {
317                         fprintf(stderr, "Must give address of server\n");
318                         return 1;
319                 }
320         }
321
322         info.port = server_port;
323         info.iface = iface;
324         info.protocols = protocols;
325 #ifndef LWS_NO_EXTENSIONS
326         info.extensions = libwebsocket_get_internal_extensions();
327 #endif
328         if (use_ssl) {
329                 info.ssl_cert_filepath = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
330                 info.ssl_private_key_filepath = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
331         }
332         info.gid = -1;
333         info.uid = -1;
334         info.options = opts;
335
336         context = libwebsocket_create_context(&info);
337         if (context == NULL) {
338                 fprintf(stderr, "libwebsocket init failed\n");
339                 return -1;
340         }
341
342         if (client) {
343                 address = argv[optind];
344                 fprintf(stderr, "Connecting to %s:%u\n", address, port);
345                 wsi = libwebsocket_client_connect(context, address,
346                                                    port, use_ssl, "/", address,
347                                  "origin", protocols[PROTOCOL_FRAGGLE].name,
348                                                                   -1);
349                 if (wsi == NULL) {
350                         fprintf(stderr, "Client connect to server failed\n");
351                         goto bail;
352                 }
353         }
354
355         n = 0;
356         while (!n && !terminate)
357                 n = libwebsocket_service(context, 50);
358
359         fprintf(stderr, "Terminating...\n");
360
361 bail:
362         libwebsocket_context_destroy(context);
363
364         return 0;
365 }