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