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