style-cleanups.patch
[profile/ivi/libwebsockets.git] / lib / libwebsockets.c
1 /*
2  * libwebsockets - small server side websockets and web server 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 "private-libwebsockets.h"
23
24 #ifdef LWS_OPENSSL_SUPPORT
25 SSL_CTX *ssl_ctx;
26 int use_ssl;
27 #endif
28
29
30 extern int 
31 libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len);
32
33
34
35 void 
36 libwebsocket_close_and_free_session(struct libwebsocket *wsi)
37 {
38         int n = wsi->state;
39
40         wsi->state = WSI_STATE_DEAD_SOCKET;
41
42         if (wsi->callback && n == WSI_STATE_ESTABLISHED)
43                 wsi->callback(wsi, LWS_CALLBACK_CLOSED, &wsi->user_space[0], 
44                                                                        NULL, 0);
45
46         for (n = 0; n < WSI_TOKEN_COUNT; n++)
47                 if (wsi->utf8_token[n].token)
48                         free(wsi->utf8_token[n].token);
49
50 //      fprintf(stderr, "closing fd=%d\n", wsi->sock);
51
52 #ifdef LWS_OPENSSL_SUPPORT
53         if (use_ssl) {
54                 n = SSL_get_fd(wsi->ssl);
55                 SSL_shutdown(wsi->ssl);
56                 close(n);
57                 SSL_free(wsi->ssl);
58         } else {
59 #endif
60                 shutdown(wsi->sock, SHUT_RDWR);
61                 close(wsi->sock);
62 #ifdef LWS_OPENSSL_SUPPORT
63         }
64 #endif
65         free(wsi);
66 }
67
68 /**
69  * libwebsocket_create_server() - Create the listening websockets server
70  * @port:       Port to listen on
71  * @callback:   The callback in user code to perform actual serving
72  * @protocol:   Which version of the websockets protocol (currently 76)
73  * @user_area_size:     How much memory to allocate per connection session
74  *                      which will be used by the user application to store
75  *                      per-session data.  A pointer to this space is given
76  *                      when the user callback is called.
77  * @ssl_cert_filepath:  If libwebsockets was compiled to use ssl, and you want
78  *                      to listen using SSL, set to the filepath to fetch the
79  *                      server cert from, otherwise NULL for unencrypted
80  * @ssl_private_key_filepath: filepath to private key if wanting SSL mode,
81  *                      else ignored
82  * @gid:        group id to change to after setting listen socket, or -1.
83  * @uid:        user id to change to after setting listen socket, or -1.
84  * 
85  *      This function forks to create the listening socket and takes care
86  *      of all initialization in one step.
87  * 
88  *      The callback function is called for a handful of events including
89  *      http requests coming in, websocket connections becoming
90  *      established, and data arriving; it's also called periodically to allow
91  *      async transmission.
92  * 
93  *      The server created is a simple http server by default; part of the
94  *      websocket standard is upgrading this http connection to a websocket one.
95  * 
96  *      This allows the same server to provide files like scripts and favicon /
97  *      images or whatever over http and dynamic data over websockets all in
98  *      one place; they're all handled in the user callback.
99  */
100
101 int libwebsocket_create_server(int port,
102                 int (*callback)(struct libwebsocket *,
103                                 enum libwebsocket_callback_reasons, 
104                                 void *, void *, size_t),
105                                         int protocol, size_t user_area_size,
106                                 const char * ssl_cert_filepath,
107                                 const char * ssl_private_key_filepath,
108                                 int gid, int uid)
109 {
110         int n;
111         int client;
112         int sockfd;
113         int fd;
114         unsigned int clilen;
115         struct sockaddr_in serv_addr, cli_addr;
116         struct libwebsocket *wsi[MAX_CLIENTS + 1];
117         struct pollfd fds[MAX_CLIENTS + 1];
118         int fds_count = 0;
119         unsigned char buf[1024];
120         int opt = 1;
121
122 #ifdef LWS_OPENSSL_SUPPORT
123         const SSL_METHOD *method;
124         char ssl_err_buf[512];
125
126         use_ssl = ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL;
127         if (use_ssl)
128                 fprintf(stderr, " Compiled with SSL support, using it\n");
129         else
130                 fprintf(stderr, " Compiled with SSL support, not using it\n");
131
132 #else
133         if (ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL) {
134                 fprintf(stderr, " Not compiled for OpenSSl support!\n");
135                 return -1;
136         }
137         fprintf(stderr, " Compiled without SSL support, serving unencrypted\n");
138 #endif
139
140 #ifdef LWS_OPENSSL_SUPPORT
141         if (use_ssl) {
142                 SSL_library_init();
143
144                 OpenSSL_add_all_algorithms();
145                 SSL_load_error_strings();
146
147                         // Firefox insists on SSLv23 not SSLv3
148                         // Konq disables SSLv2 by default now, SSLv23 works
149
150                 method = SSLv23_server_method();   // create server instance
151                 if (!method) {
152                         fprintf(stderr, "problem creating ssl method: %s\n",
153                                 ERR_error_string(ERR_get_error(), ssl_err_buf));
154                         return -1;
155                 }
156                 ssl_ctx = SSL_CTX_new(method);  /* create context */
157                 if (!ssl_ctx) {
158                         printf("problem creating ssl context: %s\n",
159                                 ERR_error_string(ERR_get_error(), ssl_err_buf));
160                         return -1;
161                 }
162                 /* set the local certificate from CertFile */
163                 n = SSL_CTX_use_certificate_file(ssl_ctx,
164                                         ssl_cert_filepath, SSL_FILETYPE_PEM);
165                 if (n != 1) {
166                         fprintf(stderr, "problem getting cert '%s': %s\n",
167                                 ssl_cert_filepath,
168                                 ERR_error_string(ERR_get_error(), ssl_err_buf));
169                         return -1;
170                 }
171                 /* set the private key from KeyFile */
172                 if (SSL_CTX_use_PrivateKey_file(ssl_ctx,
173                                                 ssl_private_key_filepath,
174                                                 SSL_FILETYPE_PEM) != 1) {
175                         fprintf(stderr, "ssl problem getting key '%s': %s\n",
176                                                 ssl_private_key_filepath,
177                                 ERR_error_string(ERR_get_error(), ssl_err_buf));
178                         return (-1);
179                 }
180                 /* verify private key */
181                 if (!SSL_CTX_check_private_key(ssl_ctx)) {
182                         fprintf(stderr, "Private SSL key doesn't match cert\n");
183                         return (-1);
184                 }
185
186                 /* SSL is happy and has a cert it's content with */
187         }
188 #endif
189
190         /* sanity check */
191
192         switch (protocol) {
193         case 0:
194         case 2:
195         case 76:
196                 fprintf(stderr, " Using protocol v%d\n", protocol);
197                 break;
198         default:
199                 fprintf(stderr, "protocol %d not supported (try 0 2 or 76)\n",
200                                                                       protocol);
201                 return -1;
202         }
203         
204         if (!callback) {
205                 fprintf(stderr, "callback is not optional!\n");
206                 return -1;
207         }
208  
209         /* sit there listening for connects, accept and spawn session servers */
210  
211         sockfd = socket(AF_INET, SOCK_STREAM, 0);
212         if (sockfd < 0) {
213                 fprintf(stderr, "ERROR opening socket");
214                 return -1;
215         }
216         
217         /* allow us to restart even if old sockets in TIME_WAIT */
218         setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
219
220         bzero((char *) &serv_addr, sizeof(serv_addr));
221         serv_addr.sin_family = AF_INET;
222         serv_addr.sin_addr.s_addr = INADDR_ANY;
223         serv_addr.sin_port = htons(port);
224         n = bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
225         if (n < 0) {
226               fprintf(stderr, "ERROR on binding to port %d (%d %d)\n", port, n,
227                                                                          errno);
228               return -1;
229         }
230  
231         /* fork off a master server for this websocket server */
232  
233         n = fork();
234         if (n < 0) {
235                 fprintf(stderr, "Failed on forking server thread: %d\n", n);
236                 return -1;
237         }
238         
239         /* we are done as far as the caller is concerned */
240         
241         if (n)
242                 return sockfd;
243  
244         // drop any root privs for this thread
245
246         if (gid != -1)
247                 if (setgid(gid))
248                         fprintf(stderr, "setgid: %s\n", strerror(errno));
249         if (uid != -1)
250                 if (setuid(uid))
251                         fprintf(stderr, "setuid: %s\n", strerror(errno));
252
253         /* we are running in a forked subprocess now */
254  
255         listen(sockfd, 5);
256         fprintf(stderr, " Listening on port %d\n", port);
257         
258         fds[0].fd = sockfd;
259         fds_count = 1;
260         fds[0].events = POLLIN;
261     
262         while (1) {
263
264                 n = poll(fds, fds_count, 50);
265                 if (n < 0 || fds[0].revents & (POLLERR | POLLHUP)) {
266 //                      fprintf(stderr, "Listen Socket dead\n");
267                         goto fatal;
268                 }
269                 if (n == 0) /* poll timeout */
270                         goto poll_out;
271
272                 if (fds[0].revents & POLLIN) {
273
274                         /* listen socket got an unencrypted connection... */
275
276                         clilen = sizeof(cli_addr);
277                         fd  = accept(sockfd,
278                                      (struct sockaddr *)&cli_addr,
279                                                                &clilen);
280                         if (fd < 0) {
281                                 fprintf(stderr, "ERROR on accept");
282                                 continue;
283                         }
284
285                         if (fds_count >= MAX_CLIENTS) {
286                                 fprintf(stderr, "too busy");
287                                 close(fd);
288                                 continue;
289                         }
290
291                         wsi[fds_count] = malloc(sizeof(struct libwebsocket) +
292                                                                 user_area_size);
293                         if (!wsi[fds_count])
294                                 return -1;
295
296
297 #ifdef LWS_OPENSSL_SUPPORT
298                         if (use_ssl) {
299
300                                 wsi[fds_count]->ssl = SSL_new(ssl_ctx);
301                                 if (wsi[fds_count]->ssl == NULL) {
302                                         fprintf(stderr, "SSL_new failed: %s\n",
303                                             ERR_error_string(SSL_get_error(
304                                                 wsi[fds_count]->ssl, 0), NULL));
305                                         free(wsi[fds_count]);
306                                         continue;
307                                 }
308
309                                 SSL_set_fd(wsi[fds_count]->ssl, fd);
310
311                                 n = SSL_accept(wsi[fds_count]->ssl);
312                                 if (n != 1) {
313                                         /*
314                                          * browsers seem to probe with various
315                                          * ssl params which fail then retry
316                                          * and succeed
317                                          */
318                                         debug("SSL_accept failed skt %u: %s\n",
319                                                 fd,
320                                                 ERR_error_string(SSL_get_error(
321                                                 wsi[fds_count]->ssl, n), NULL));
322                                         SSL_free(wsi[fds_count]->ssl);
323                                         free(wsi[fds_count]);
324                                         continue;
325                                 }
326                                 debug("accepted new SSL conn  "
327                                       "port %u on fd=%d SSL ver %s\n",
328                                         ntohs(cli_addr.sin_port), fd,
329                                           SSL_get_version(wsi[fds_count]->ssl));
330                                 
331                         } else {
332 //                      fprintf(stderr, "accepted new conn  port %u on fd=%d\n",
333 //                                                ntohs(cli_addr.sin_port), fd);
334                         }
335 #endif
336                         
337                         /* intialize the instance struct */
338
339                         wsi[fds_count]->sock = fd;
340                         wsi[fds_count]->state = WSI_STATE_HTTP;
341                         wsi[fds_count]->name_buffer_pos = 0;
342
343                         for (n = 0; n < WSI_TOKEN_COUNT; n++) {
344                                 wsi[fds_count]->utf8_token[n].token = NULL;
345                                 wsi[fds_count]->utf8_token[n].token_len = 0;
346                         }
347
348                         wsi[fds_count]->callback = callback;
349                         wsi[fds_count]->ietf_spec_revision = protocol;
350
351                         fds[fds_count].events = POLLIN;
352                         fds[fds_count++].fd = fd;
353                 }
354                 
355                 /* check for activity on client sockets */
356                 
357                 for (client = 1; client < fds_count; client++) {
358                         
359                         /* handle session socket closed */
360                         
361                         if (fds[client].revents & (POLLERR | POLLHUP)) {
362                                 
363                                 fprintf(stderr, "Session Socket dead\n");
364
365                                 libwebsocket_close_and_free_session(
366                                                                    wsi[client]);
367                                 goto nuke_this;
368                         }
369                         
370                         /* any incoming data ready? */
371
372                         if (!(fds[client].revents & POLLIN))
373                                 continue;
374                                 
375 //                      fprintf(stderr, "POLLIN\n");
376
377 #ifdef LWS_OPENSSL_SUPPORT
378                         if (use_ssl)
379                                 n = SSL_read(wsi[client]->ssl, buf, sizeof buf);
380                         else
381 #endif
382                                 n = recv(fds[client].fd, buf, sizeof(buf), 0);
383
384 //                      fprintf(stderr, "read returned %d\n", n);
385
386                         if (n < 0) {
387                                 fprintf(stderr, "Socket read returned %d\n", n);
388                                 continue;
389                         }
390                         if (!n) {
391 //                              fprintf(stderr, "POLLIN with 0 len waiting\n");
392                                 libwebsocket_close_and_free_session(
393                                                                    wsi[client]);
394                                 goto nuke_this;
395                         }
396                         
397                         /* service incoming data */
398
399                         if (libwebsocket_read(wsi[client], buf, n) >= 0)
400                                 continue;
401                         
402                         /* it closed and nuked wsi[client] */
403 nuke_this:
404                         for (n = client; n < fds_count - 1; n++) {
405                                 fds[n] = fds[n + 1];
406                                 wsi[n] = wsi[n + 1];
407                         }
408                         fds_count--;
409                         client--;
410                 }
411
412 poll_out:               
413                 for (client = 1; client < fds_count; client++) {
414
415                         if (wsi[client]->state != WSI_STATE_ESTABLISHED)
416                                 continue;
417                                                 
418                         if (!wsi[client]->callback)
419                                 continue;
420
421                         wsi[client]->callback(wsi[client], LWS_CALLBACK_SEND, 
422                                           &wsi[client]->user_space[0], NULL, 0);
423                 }
424                 
425                 continue;               
426         }
427         
428 fatal:
429         /* listening socket */
430         close(fds[0].fd);
431         for (client = 1; client < fds_count; client++)
432                 libwebsocket_close_and_free_session(wsi[client]);
433
434 #ifdef LWS_OPENSSL_SUPPORT
435         SSL_CTX_free(ssl_ctx);
436 #endif
437         kill(0, SIGTERM);
438         
439         return 0;
440 }
441
442