add-Sec-WebSocket-Draft-and-protocol-autodetect.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 #define LOCAL_RESOURCE_PATH "/usr/share/libwebsockets-test-server"
31 static int port = 7681;
32 static int use_ssl = 0;
33
34 struct per_session_data {
35         int number;
36 };
37
38  /**
39  * libwebsocket_callback() - User server actions
40  * @wsi:        Opaque websocket instance pointer
41  * @reason:     The reason for the call
42  * @user:       Pointer to per-session user data allocated by library
43  * @in:         Pointer used for some callback reasons
44  * @len:        Length set for some callback reasons
45  * 
46  *      This callback is the way the user controls what is served.  All the
47  *      protocol detail is hidden and handled by the library.
48  * 
49  *      For each connection / session there is user data allocated that is
50  *      pointed to by "user".  You set the size of this user data area when
51  *      the library is initialized with libwebsocket_create_server.
52  * 
53  *      You get an opportunity to initialize user data when called back with
54  *      LWS_CALLBACK_ESTABLISHED reason.
55  * 
56  *      LWS_CALLBACK_ESTABLISHED:  after successful websocket handshake
57  * 
58  *      LWS_CALLBACK_CLOSED: when the websocket session ends
59  *
60  *      LWS_CALLBACK_SEND: opportunity to send to client (you would use
61  *                              libwebsocket_write() taking care about the
62  *                              special buffer requirements
63  *      LWS_CALLBACK_RECEIVE: data has appeared for the server, it can be
64  *                              found at *in and is len bytes long
65  *
66  *      LWS_CALLBACK_HTTP: an http request has come from a client that is not
67  *                              asking to upgrade the connection to a websocket
68  *                              one.  This is a chance to serve http content,
69  *                              for example, to send a script to the client
70  *                              which will then open the websockets connection.
71  *                              @in points to the URI path requested and 
72  *                              libwebsockets_serve_http_file() makes it very
73  *                              simple to send back a file to the client.
74  *
75  *      LWS_CALLBACK_PROTOCOL_FILTER: before the confirmation handshake is sent
76  *                              the user callback is given a chance to confirm
77  *                              it's OK with the protocol that was requested
78  *                              from the client.  The protocol string (which
79  *                              may be NULL if no protocol header was sent)
80  *                              can be found at parameter @in.  Return 0 from
81  *                              the callback to allow the connection or nonzero
82  *                              to abort the connection.
83  */
84
85 static int websocket_callback(struct libwebsocket * wsi,
86                 enum libwebsocket_callback_reasons reason, void * user,
87                                                            void *in, size_t len)
88 {
89         int n;
90         char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
91                                                   LWS_SEND_BUFFER_POST_PADDING];
92         char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
93         struct per_session_data * pss = user;
94         
95         switch (reason) {
96         /*
97          * Websockets session handshake completed and is established
98          */
99         case LWS_CALLBACK_ESTABLISHED:
100                 fprintf(stderr, "Websocket connection established\n");
101                 pss->number = 0;
102                 break;
103
104         /*
105          * Websockets session is closed
106          */
107         case LWS_CALLBACK_CLOSED:
108                 fprintf(stderr, "Websocket connection closed\n");
109                 break;
110
111         /*
112          * Opportunity for us to send something on the connection
113          */
114         case LWS_CALLBACK_SEND: 
115                 n = sprintf(p, "%d", pss->number++);
116                 n = libwebsocket_write(wsi, (unsigned char *)p, n,
117                                                                 LWS_WRITE_TEXT);
118                 if (n < 0) {
119                         fprintf(stderr, "ERROR writing to socket");
120                         exit(1);
121                 }
122                 break;
123         /*
124          * Something has arrived for us on the connection, it's len bytes long
125          * and is available at *in
126          */
127         case LWS_CALLBACK_RECEIVE:
128                 fprintf(stderr, "Received %d bytes payload\n", (int)len);
129                 break;
130
131         /*
132          * The client has asked us for something in normal HTTP mode,
133          * not websockets mode.  Normally it means we want to send
134          * our script / html to the client, and when that script runs
135          * it will start up separate websocket connections.
136          * 
137          * Interpret the URI string to figure out what is needed to send
138          */
139                  
140         case LWS_CALLBACK_HTTP:
141
142                 fprintf(stderr, "serving HTTP URI %s\n", in);
143                 
144                 if (in && strcmp(in, "/favicon.ico") == 0) {
145                         if (libwebsockets_serve_http_file(wsi,
146                              LOCAL_RESOURCE_PATH"/favicon.ico", "image/x-icon"))
147                                 fprintf(stderr, "Failed to send favicon\n");
148                         break;
149                 }
150                 
151                 /* send the script... when it runs it'll start websockets */
152
153                 if (libwebsockets_serve_http_file(wsi,
154                                   LOCAL_RESOURCE_PATH"/test.html", "text/html"))
155                         fprintf(stderr, "Failed to send HTTP file\n");
156                 break;
157
158         /*
159          * This is our chance to choose if we support one of the requested
160          * protocols or not.  in points to the protocol string.  Nonzero return
161          * aborts the connection handshake
162          */
163
164         case LWS_CALLBACK_PROTOCOL_FILTER:
165                 if (in == NULL) {
166                         fprintf(stderr, "Client did not request protocol\n");
167                         /* accept it */
168                         return 0;
169                 }
170                 fprintf(stderr, "Client requested protocol '%s'\n", in);
171                 /* accept it */
172                 return 0;
173         }
174
175         return 0;
176 }
177
178 static struct option options[] = {
179         { "help",       no_argument, NULL, 'h' },
180         { "port",       required_argument, NULL, 'p' },
181         { "protocol",   required_argument, NULL, 'r' },
182         { "ssl",        no_argument, NULL, 's' },
183         { NULL, 0, 0, 0 }
184 };
185
186 int main(int argc, char **argv)
187 {
188         int n = 0;
189         const char * cert_path =
190                             LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
191         const char * key_path =
192                         LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
193
194         fprintf(stderr, "libwebsockets test server\n"
195                         "(C) Copyright 2010 Andy Green <andy@warmcat.com> "
196                                                     "licensed under LGPL2.1\n");
197         
198         while (n >= 0) {
199                 n = getopt_long(argc, argv, "hp:r:", options, NULL);
200                 if (n < 0)
201                         continue;
202                 switch (n) {
203                 case 's':
204                         use_ssl = 1;
205                         break;
206                 case 'p':
207                         port = atoi(optarg);
208                         break;
209                 case 'h':
210                         fprintf(stderr, "Usage: test-server "
211                                              "[--port=<p>] [--protocol=<v>]\n");
212                         exit(1);
213                 }
214         }
215
216         if (!use_ssl)
217                 cert_path = key_path = NULL;
218         
219         if (libwebsocket_create_server(port, websocket_callback,
220                                          sizeof(struct per_session_data),
221                                              cert_path, key_path, -1, -1) < 0) {
222                 fprintf(stderr, "libwebsocket init failed\n");
223                 return -1;
224         }
225         
226         /* just sit there until killed */
227                 
228         while (1)
229                 sleep(10);
230
231         return 0;
232 }