fork-sever-process-and-introduce-broadcast-api.patch
[profile/ivi/libwebsockets.git] / test-server / test-server.c
1 /*
2  * libwebsockets-test-server - libwebsockets test implementation
3  *
4  * Copyright (C) 2010 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
28 #include "../lib/libwebsockets.h"
29
30 /*
31  * This demo server shows how to use libwebsockets for one or more
32  * websocket protocols in the same server
33  *
34  * It defines the following websocket protocols:
35  *
36  *  dumb-increment-protocol:  once the socket is opened, an incrementing
37  *                              ascii string is sent down it every 50ms.
38  *                              If you send "reset\n" on the websocket, then
39  *                              the incrementing number is reset to 0.
40  *
41  *  lws-mirror-protocol: copies any received packet to every connection also
42  *                              using this protocol, including the sender
43  */
44
45
46 #define LOCAL_RESOURCE_PATH "/usr/share/libwebsockets-test-server"
47 static int port = 7681;
48 static int use_ssl;
49
50 /* this protocol server (always the first one) just knows how to do HTTP */
51
52 static int callback_http(struct libwebsocket *wsi,
53                 enum libwebsocket_callback_reasons reason, void *user,
54                                                            void *in, size_t len)
55 {
56         switch (reason) {
57         case LWS_CALLBACK_HTTP:
58                 fprintf(stderr, "serving HTTP URI %s\n", in);
59
60                 if (in && strcmp(in, "/favicon.ico") == 0) {
61                         if (libwebsockets_serve_http_file(wsi,
62                              LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon"))
63                                 fprintf(stderr, "Failed to send favicon\n");
64                         break;
65                 }
66
67                 /* send the script... when it runs it'll start websockets */
68
69                 if (libwebsockets_serve_http_file(wsi,
70                                   LOCAL_RESOURCE_PATH"/test.html", "text/html"))
71                         fprintf(stderr, "Failed to send HTTP file\n");
72                 break;
73
74         default:
75                 break;
76         }
77
78         return 0;
79 }
80
81 /* dumb_increment protocol */
82
83 struct per_session_data__dumb_increment {
84         int number;
85 };
86
87 static int
88 callback_dumb_increment(struct libwebsocket *wsi,
89                         enum libwebsocket_callback_reasons reason,
90                                                void *user, void *in, size_t len)
91 {
92         int n;
93         char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
94                                                   LWS_SEND_BUFFER_POST_PADDING];
95         char *p = (char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
96         struct per_session_data__dumb_increment *pss = user;
97
98         switch (reason) {
99
100         case LWS_CALLBACK_ESTABLISHED:
101                 pss->number = 0;
102                 break;
103
104         /*
105          * in this protocol, we just use the broadcast action as the chance to
106          * send our own connection-specific data and ignore the broadcast info
107          * that is available in the 'in' parameter
108          */
109
110         case LWS_CALLBACK_BROADCAST:
111                 n = sprintf(p, "%d", pss->number++);
112                 n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
113                 if (n < 0) {
114                         fprintf(stderr, "ERROR writing to socket");
115                         return 1;
116                 }
117                 break;
118
119         case LWS_CALLBACK_RECEIVE:
120                 fprintf(stderr, "rx %d\n", len);
121                 if (len < 6)
122                         break;
123                 if (strcmp(in, "reset\n") == 0)
124                         pss->number = 0;
125                 break;
126
127         default:
128                 break;
129         }
130
131         return 0;
132 }
133
134
135 /* lws-mirror_protocol */
136
137 #define MAX_MESSAGE_QUEUE 64
138
139 struct per_session_data__lws_mirror {
140         struct libwebsocket *wsi;
141         int ringbuffer_tail;
142 };
143
144 struct a_message {
145         void *payload;
146         size_t len;
147 };
148
149 static struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
150 static int ringbuffer_head;
151
152
153 static int
154 callback_lws_mirror(struct libwebsocket *wsi,
155                         enum libwebsocket_callback_reasons reason,
156                                                void *user, void *in, size_t len)
157 {
158         int n;
159         char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
160                                                   LWS_SEND_BUFFER_POST_PADDING];
161         unsigned char *p = (unsigned char *)&buf[LWS_SEND_BUFFER_PRE_PADDING];
162         struct per_session_data__lws_mirror *pss = user;
163
164         switch (reason) {
165
166         case LWS_CALLBACK_ESTABLISHED:
167                 pss->wsi = wsi;
168                 pss->ringbuffer_tail = ringbuffer_head;
169                 break;
170
171         case LWS_CALLBACK_BROADCAST:
172                 n = libwebsocket_write(wsi, in, len, LWS_WRITE_TEXT);
173                 break;
174
175         case LWS_CALLBACK_RECEIVE:
176                 /*
177                  * copy the incoming packet to all other protocol users
178                  *
179                  * This demonstrates how easy it is to broadcast from inside
180                  * a callback.
181                  * 
182                  * How this works is it calls back to the callback for all
183                  * connected sockets using this protocol with
184                  * LWS_CALLBACK_BROADCAST reason.  Our handler for that above
185                  * writes the data down the socket.
186                  */
187                 libwebsockets_broadcast(libwebsockets_get_protocol(wsi),
188                                                                        in, len);
189                 break;
190
191         default:
192                 break;
193         }
194
195         return 0;
196 }
197
198
199 /* list of supported protocols and callbacks */
200
201 static struct libwebsocket_protocols protocols[] = {
202         {
203                 .name = "http-only",
204                 .callback = callback_http,
205                 .per_session_data_size = 0,
206         },
207         {
208                 .name = "dumb-increment-protocol",
209                 .callback = callback_dumb_increment,
210                 .per_session_data_size =
211                                 sizeof(struct per_session_data__dumb_increment),
212         },
213         {
214                 .name = "lws-mirror-protocol",
215                 .callback = callback_lws_mirror,
216                 .per_session_data_size =
217                                 sizeof(struct per_session_data__lws_mirror),
218         },
219         {  /* end of list */
220                 .callback = NULL
221         }
222 };
223
224 static struct option options[] = {
225         { "help",       no_argument, NULL, 'h' },
226         { "port",       required_argument, NULL, 'p' },
227         { "ssl",        no_argument, NULL, 's' },
228         { NULL, 0, 0, 0 }
229 };
230
231 int main(int argc, char **argv)
232 {
233         int n = 0;
234         const char *cert_path =
235                             LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
236         const char *key_path =
237                         LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
238         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1024 +
239                                                   LWS_SEND_BUFFER_POST_PADDING];
240
241         fprintf(stderr, "libwebsockets test server\n"
242                         "(C) Copyright 2010 Andy Green <andy@warmcat.com> "
243                                                     "licensed under LGPL2.1\n");
244
245         while (n >= 0) {
246                 n = getopt_long(argc, argv, "hp:", options, NULL);
247                 if (n < 0)
248                         continue;
249                 switch (n) {
250                 case 's':
251                         use_ssl = 1;
252                         break;
253                 case 'p':
254                         port = atoi(optarg);
255                         break;
256                 case 'h':
257                         fprintf(stderr, "Usage: test-server "
258                                              "[--port=<p>] [--ssl]\n");
259                         exit(1);
260                 }
261         }
262
263         if (!use_ssl)
264                 cert_path = key_path = NULL;
265
266         if (libwebsocket_create_server(port, protocols, cert_path, key_path,
267                                                                   -1, -1) < 0) {
268                 fprintf(stderr, "libwebsocket init failed\n");
269                 return -1;
270         }
271
272         /*
273          * After initializing and creating the websocket server in its own fork
274          * we return to the main process here
275          */
276
277         buf[LWS_SEND_BUFFER_PRE_PADDING] = 'x';
278
279         while (1) {
280                 
281                 sleep(1);
282
283                 /*
284                  * This broadcasts to all dumb-increment-protocol connections
285                  * once per second.
286                  * 
287                  * We're just sending a character 'x', in these examples the
288                  * callbacks send their own per-connection content.
289                  *
290                  * You have to send something with nonzero length to get the
291                  * callback actions delivered.
292                  *
293                  * We take care of pre-and-post padding allocation.
294                  */
295
296                 /* [1] == dumb-increment-protocol */
297                 libwebsockets_broadcast(&protocols[1],
298                                         &buf[LWS_SEND_BUFFER_PRE_PADDING], 1);
299         }
300
301         return 0;
302 }