blob: ac207385defe382e136a9bb26c8feb8b1e494bde [file] [log] [blame]
Andy Green05a0a7b2010-10-31 17:51:39 +00001/*
Andy Greena0da8a82010-11-08 17:12:19 +00002 * 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
Andy Green05a0a7b2010-10-31 17:51:39 +000020 */
21
Andy Greenff95d7a2010-10-28 22:36:01 +010022#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <unistd.h>
Andy Green775c0dd2010-10-29 14:15:22 +010027#include <errno.h>
Andy Green5fd8a5e2010-10-31 11:57:17 +000028#include <sys/types.h>
29#include <sys/stat.h>
30#include <fcntl.h>
Andy Green251f6fa2010-11-03 11:13:06 +000031#include <signal.h>
Andy Greenff95d7a2010-10-28 22:36:01 +010032
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <netinet/in.h>
36
37#include <poll.h>
38#include <sys/mman.h>
39
Andy Green3faa9c72010-11-08 17:03:03 +000040#ifdef LWS_OPENSSL_SUPPORT
41#include <openssl/ssl.h>
42#include <openssl/evp.h>
43#include <openssl/err.h>
44
45SSL_CTX *ssl_ctx;
46int use_ssl;
47#endif
48
49//#define DEBUG
50
Andy Greenff95d7a2010-10-28 22:36:01 +010051#include "libwebsockets.h"
52
Andy Green69fa0722010-11-03 08:25:13 +000053#ifdef DEBUG
54#define debug(format, args...) \
55 fprintf(stderr, format , ## args)
56#else
57#define debug(format, args...)
58#endif
59
Andy Greenff95d7a2010-10-28 22:36:01 +010060void md5(const unsigned char *input, int ilen, unsigned char output[16]);
Andy Green251f6fa2010-11-03 11:13:06 +000061static int
62libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len);
Andy Greenff95d7a2010-10-28 22:36:01 +010063
Andy Green251f6fa2010-11-03 11:13:06 +000064#define MAX_CLIENTS 100
Andy Green775c0dd2010-10-29 14:15:22 +010065#define LWS_MAX_HEADER_NAME_LENGTH 64
66#define LWS_MAX_HEADER_LEN 4096
67#define LWS_INITIAL_HDR_ALLOC 256
68#define LWS_ADDITIONAL_HDR_ALLOC 64
69
70
Andy Green3faa9c72010-11-08 17:03:03 +000071
Andy Green775c0dd2010-10-29 14:15:22 +010072enum lws_connection_states {
Andy Green5fd8a5e2010-10-31 11:57:17 +000073 WSI_STATE_HTTP,
74 WSI_STATE_HTTP_HEADERS,
Andy Green775c0dd2010-10-29 14:15:22 +010075 WSI_STATE_DEAD_SOCKET,
76 WSI_STATE_ESTABLISHED
77};
78
79enum lws_token_indexes {
80 WSI_TOKEN_GET_URI,
81 WSI_TOKEN_HOST,
82 WSI_TOKEN_CONNECTION,
83 WSI_TOKEN_KEY1,
84 WSI_TOKEN_KEY2,
85 WSI_TOKEN_PROTOCOL,
86 WSI_TOKEN_UPGRADE,
87 WSI_TOKEN_ORIGIN,
88 WSI_TOKEN_CHALLENGE,
89
90 /* always last real token index*/
91 WSI_TOKEN_COUNT,
92 /* parser state additions */
93 WSI_TOKEN_NAME_PART,
94 WSI_TOKEN_SKIPPING,
95 WSI_TOKEN_SKIPPING_SAW_CR,
96 WSI_PARSING_COMPLETE
97};
98
Andy Green4ea60062010-10-30 12:15:07 +010099enum lws_rx_parse_state {
100 LWS_RXPS_NEW,
101
102 LWS_RXPS_SEEN_76_FF,
103 LWS_RXPS_PULLING_76_LENGTH,
104
105 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED
106};
107
Andy Green775c0dd2010-10-29 14:15:22 +0100108
109struct lws_tokens {
110 char * token;
111 int token_len;
112};
113
114
115/*
116 * This is totally opaque to code using the library. It's exported as a
Andy Greenab990e42010-10-31 12:42:52 +0000117 * forward-reference pointer-only declaration; the user can use the pointer with
118 * other APIs to get information out of it.
Andy Green775c0dd2010-10-29 14:15:22 +0100119 */
120
121struct libwebsocket {
122 int (*callback)(struct libwebsocket *,
Andy Green251f6fa2010-11-03 11:13:06 +0000123 enum libwebsocket_callback_reasons reason, void *, void *, size_t);
Andy Green775c0dd2010-10-29 14:15:22 +0100124
125 enum lws_connection_states state;
126
127 char name_buffer[LWS_MAX_HEADER_NAME_LENGTH];
128 int name_buffer_pos;
129 int current_alloc_len;
130 enum lws_token_indexes parser_state;
131 struct lws_tokens utf8_token[WSI_TOKEN_COUNT];
132 int ietf_spec_revision;
133
134 int sock;
Andy Green4ea60062010-10-30 12:15:07 +0100135
136 enum lws_rx_parse_state lws_rx_parse_state;
137 size_t rx_packet_length;
Andy Green251f6fa2010-11-03 11:13:06 +0000138
Andy Green3faa9c72010-11-08 17:03:03 +0000139#ifdef LWS_OPENSSL_SUPPORT
140 char m_fOccupied;
141 struct sockaddr_in m_addr;
142 int m_addrlen;
143
144 SSL *ssl;
145
146 // these are valid if it is a POST
147
148 char m_fOngoingPost;
149 int m_nSessionID;
150
151 time_t m_timeStarted;
152 long long m_llTransferred;
153 long long m_llSizeIfKnown;
154
155 char m_szTitle[PATH_MAX];
156 char m_szStatus[PATH_MAX];
157#endif
158
Andy Green251f6fa2010-11-03 11:13:06 +0000159 /* last */
160 char user_space[0];
Andy Green775c0dd2010-10-29 14:15:22 +0100161};
162
Andy Greenff95d7a2010-10-28 22:36:01 +0100163
164const struct lws_tokens lws_tokens[WSI_TOKEN_COUNT] = {
165 { "GET ", 4 },
166 { "Host:", 5 },
167 { "Connection:", 11 },
168 { "Sec-WebSocket-Key1:", 19 },
169 { "Sec-WebSocket-Key2:", 19 },
170 { "Sec-WebSocket-Protocol:", 23 },
171 { "Upgrade:", 8 },
172 { "Origin:", 7 },
173 { "\x0d\x0a", 2 },
174};
175
Andy Green251f6fa2010-11-03 11:13:06 +0000176static void
177libwebsocket_close_and_free_session(struct libwebsocket *wsi)
178{
179 int n = wsi->state;
180
181 wsi->state = WSI_STATE_DEAD_SOCKET;
182
183 if (wsi->callback && n == WSI_STATE_ESTABLISHED)
184 wsi->callback(wsi, LWS_CALLBACK_CLOSED, &wsi->user_space[0],
185 NULL, 0);
186
187 for (n = 0; n < WSI_TOKEN_COUNT; n++)
188 if (wsi->utf8_token[n].token)
189 free(wsi->utf8_token[n].token);
190
191// fprintf(stderr, "closing fd=%d\n", wsi->sock);
192
Andy Green3faa9c72010-11-08 17:03:03 +0000193#ifdef LWS_OPENSSL_SUPPORT
194 if (use_ssl) {
195 n = SSL_get_fd(wsi->ssl);
196 SSL_shutdown(wsi->ssl);
197 close(n);
198 SSL_free(wsi->ssl);
199 } else {
200#endif
201 shutdown(wsi->sock, SHUT_RDWR);
202 close(wsi->sock);
203#ifdef LWS_OPENSSL_SUPPORT
204 }
205#endif
Andy Green251f6fa2010-11-03 11:13:06 +0000206 free(wsi);
207}
208
Andy Greenab990e42010-10-31 12:42:52 +0000209/**
210 * libwebsocket_create_server() - Create the listening websockets server
211 * @port: Port to listen on
212 * @callback: The callback in user code to perform actual serving
213 * @protocol: Which version of the websockets protocol (currently 76)
Andy Green251f6fa2010-11-03 11:13:06 +0000214 * @user_area_size: How much memory to allocate per connection session
215 * which will be used by the user application to store
216 * per-session data. A pointer to this space is given
217 * when the user callback is called.
Andy Green3faa9c72010-11-08 17:03:03 +0000218 * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want
219 * to listen using SSL, set to the filepath to fetch the
220 * server cert from, otherwise NULL for unencrypted
221 * @ssl_private_key_filepath: filepath to private key if wanting SSL mode,
222 * else ignored
223 * @gid: group id to change to after setting listen socket, or -1.
224 * @uid: user id to change to after setting listen socket, or -1.
Andy Greenab990e42010-10-31 12:42:52 +0000225 *
226 * This function forks to create the listening socket and takes care
227 * of all initialization in one step.
228 *
229 * The callback function is called for a handful of events including
230 * http requests coming in, websocket connections becoming
231 * established, and data arriving; it's also called periodically to allow
232 * async transmission.
233 *
234 * The server created is a simple http server by default; part of the
235 * websocket standard is upgrading this http connection to a websocket one.
236 *
237 * This allows the same server to provide files like scripts and favicon /
238 * images or whatever over http and dynamic data over websockets all in
239 * one place; they're all handled in the user callback.
240 */
Andy Green4ea60062010-10-30 12:15:07 +0100241
Andy Greenea71ed12010-10-31 07:40:33 +0000242int libwebsocket_create_server(int port,
243 int (*callback)(struct libwebsocket *,
Andy Green251f6fa2010-11-03 11:13:06 +0000244 enum libwebsocket_callback_reasons,
245 void *, void *, size_t),
Andy Green3faa9c72010-11-08 17:03:03 +0000246 int protocol, size_t user_area_size,
247 const char * ssl_cert_filepath,
248 const char * ssl_private_key_filepath,
249 int gid, int uid)
Andy Greenff95d7a2010-10-28 22:36:01 +0100250{
251 int n;
Andy Green251f6fa2010-11-03 11:13:06 +0000252 int client;
Andy Green69fa0722010-11-03 08:25:13 +0000253 int sockfd;
Andy Green251f6fa2010-11-03 11:13:06 +0000254 int fd;
Andy Greenff95d7a2010-10-28 22:36:01 +0100255 unsigned int clilen;
256 struct sockaddr_in serv_addr, cli_addr;
Andy Green251f6fa2010-11-03 11:13:06 +0000257 struct libwebsocket *wsi[MAX_CLIENTS + 1];
258 struct pollfd fds[MAX_CLIENTS + 1];
259 int fds_count = 0;
Andy Green3faa9c72010-11-08 17:03:03 +0000260 unsigned char buf[1024];
Andy Green251f6fa2010-11-03 11:13:06 +0000261 int opt = 1;
Andy Greenff95d7a2010-10-28 22:36:01 +0100262
Andy Green3faa9c72010-11-08 17:03:03 +0000263#ifdef LWS_OPENSSL_SUPPORT
264 const SSL_METHOD *method;
265 char ssl_err_buf[512];
266
267 use_ssl = ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL;
268 if (use_ssl)
269 fprintf(stderr, " Compiled with SSL support, using it\n");
270 else
271 fprintf(stderr, " Compiled with SSL support, but not using it\n");
272
273#else
274 if (ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL) {
275 fprintf(stderr, " Not compiled for OpenSSl support!\n");
276 return -1;
277 }
278 fprintf(stderr, " Compiled without SSL support, listening unencrypted\n");
279#endif
280
281#ifdef LWS_OPENSSL_SUPPORT
282 if (use_ssl) {
283 SSL_library_init();
284
285 OpenSSL_add_all_algorithms();
286 SSL_load_error_strings();
287
288 // Firefox insists on SSLv23 not SSLv3
289 // Konq disables SSLv2 by default now, SSLv23 works
290
291 method = SSLv23_server_method(); // create server instance
292 if (!method) {
293 fprintf(stderr, "problem creating ssl method: %s\n",
294 ERR_error_string(ERR_get_error(), ssl_err_buf));
295 return -1;
296 }
297 ssl_ctx = SSL_CTX_new(method); /* create context */
298 if (!ssl_ctx) {
299 printf("problem creating ssl context: %s\n",
300 ERR_error_string(ERR_get_error(), ssl_err_buf));
301 return -1;
302 }
303 /* set the local certificate from CertFile */
304 n = SSL_CTX_use_certificate_file(ssl_ctx,
305 ssl_cert_filepath, SSL_FILETYPE_PEM);
306 if (n != 1) {
307 fprintf(stderr, "problem getting cert '%s': %s\n",
308 ssl_cert_filepath,
309 ERR_error_string(ERR_get_error(), ssl_err_buf));
310 return -1;
311 }
312 /* set the private key from KeyFile */
313 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, ssl_private_key_filepath,
314 SSL_FILETYPE_PEM) != 1) {
315 fprintf(stderr, "ssl problem getting key '%s': %s\n", ssl_private_key_filepath, ERR_error_string(ERR_get_error(), ssl_err_buf));
316 return (-1);
317 }
318 /* verify private key */
319 if (!SSL_CTX_check_private_key(ssl_ctx)) {
320 fprintf(stderr, "Private SSL key does not match cert\n");
321 return (-1);
322 }
323
324 /* SSL is happy and has a cert it's content with */
325 }
326#endif
327
Andy Green251f6fa2010-11-03 11:13:06 +0000328 /* sanity check */
329
Andy Greenea71ed12010-10-31 07:40:33 +0000330 switch (protocol) {
331 case 0:
332 case 2:
333 case 76:
Andy Green5fd8a5e2010-10-31 11:57:17 +0000334 fprintf(stderr, " Using protocol v%d\n", protocol);
Andy Greenea71ed12010-10-31 07:40:33 +0000335 break;
336 default:
337 fprintf(stderr, "protocol %d not supported (try 0 2 or 76)\n",
338 protocol);
339 return -1;
340 }
Andy Green251f6fa2010-11-03 11:13:06 +0000341
342 if (!callback) {
343 fprintf(stderr, "callback is not optional!\n");
344 return -1;
345 }
Andy Greenff95d7a2010-10-28 22:36:01 +0100346
Andy Green775c0dd2010-10-29 14:15:22 +0100347 /* sit there listening for connects, accept and spawn session servers */
348
349 sockfd = socket(AF_INET, SOCK_STREAM, 0);
350 if (sockfd < 0) {
351 fprintf(stderr, "ERROR opening socket");
Andy Green251f6fa2010-11-03 11:13:06 +0000352 return -1;
Andy Green775c0dd2010-10-29 14:15:22 +0100353 }
Andy Green251f6fa2010-11-03 11:13:06 +0000354
355 /* allow us to restart even if old sockets in TIME_WAIT */
356 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
Andy Green775c0dd2010-10-29 14:15:22 +0100357
Andy Green251f6fa2010-11-03 11:13:06 +0000358 bzero((char *) &serv_addr, sizeof(serv_addr));
Andy Green775c0dd2010-10-29 14:15:22 +0100359 serv_addr.sin_family = AF_INET;
360 serv_addr.sin_addr.s_addr = INADDR_ANY;
361 serv_addr.sin_port = htons(port);
362 n = bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
363 if (n < 0) {
Andy Greenea71ed12010-10-31 07:40:33 +0000364 fprintf(stderr, "ERROR on binding to port %d (%d %d)\n", port, n,
365 errno);
Andy Green775c0dd2010-10-29 14:15:22 +0100366 return -1;
367 }
368
369 /* fork off a master server for this websocket server */
Andy Greenff95d7a2010-10-28 22:36:01 +0100370
371 n = fork();
372 if (n < 0) {
373 fprintf(stderr, "Failed on forking server thread: %d\n", n);
Andy Green251f6fa2010-11-03 11:13:06 +0000374 return -1;
Andy Greenff95d7a2010-10-28 22:36:01 +0100375 }
376
377 /* we are done as far as the caller is concerned */
378
379 if (n)
Andy Green251f6fa2010-11-03 11:13:06 +0000380 return sockfd;
Andy Greenff95d7a2010-10-28 22:36:01 +0100381
Andy Green3faa9c72010-11-08 17:03:03 +0000382 // drop any root privs for this thread
383
384 if (gid != -1)
385 if (setgid(gid))
386 fprintf(stderr, "setgid: %s\n", strerror(errno));
387 if (uid != -1)
388 if (setuid(uid))
389 fprintf(stderr, "setuid: %s\n", strerror(errno));
390
Andy Green251f6fa2010-11-03 11:13:06 +0000391 /* we are running in a forked subprocess now */
Andy Greenea71ed12010-10-31 07:40:33 +0000392
Andy Greenff95d7a2010-10-28 22:36:01 +0100393 listen(sockfd, 5);
Andy Green251f6fa2010-11-03 11:13:06 +0000394 fprintf(stderr, " Listening on port %d\n", port);
395
396 fds[0].fd = sockfd;
397 fds_count = 1;
398 fds[0].events = POLLIN;
Andy Greenff95d7a2010-10-28 22:36:01 +0100399
400 while (1) {
Andy Greenff95d7a2010-10-28 22:36:01 +0100401
Andy Green251f6fa2010-11-03 11:13:06 +0000402 n = poll(fds, fds_count, 50);
403 if (n < 0 || fds[0].revents & (POLLERR | POLLHUP)) {
404// fprintf(stderr, "Listen Socket dead\n");
405 goto fatal;
Andy Green775c0dd2010-10-29 14:15:22 +0100406 }
Andy Green251f6fa2010-11-03 11:13:06 +0000407 if (n == 0) /* poll timeout */
408 goto poll_out;
409
410 if (fds[0].revents & POLLIN) {
411
Andy Green3faa9c72010-11-08 17:03:03 +0000412 /* listen socket got an unencrypted connection... */
413
Andy Green251f6fa2010-11-03 11:13:06 +0000414 clilen = sizeof(cli_addr);
Andy Green3faa9c72010-11-08 17:03:03 +0000415 fd = accept(sockfd,
416 (struct sockaddr *)&cli_addr,
417 &clilen);
Andy Green251f6fa2010-11-03 11:13:06 +0000418 if (fd < 0) {
419 fprintf(stderr, "ERROR on accept");
420 continue;
421 }
Andy Green3faa9c72010-11-08 17:03:03 +0000422
Andy Green251f6fa2010-11-03 11:13:06 +0000423 if (fds_count >= MAX_CLIENTS) {
424 fprintf(stderr, "too busy");
425 close(fd);
426 continue;
427 }
Andy Green3faa9c72010-11-08 17:03:03 +0000428
Andy Green251f6fa2010-11-03 11:13:06 +0000429 wsi[fds_count] = malloc(sizeof(struct libwebsocket) +
430 user_area_size);
431 if (!wsi[fds_count])
432 return -1;
Andy Green3faa9c72010-11-08 17:03:03 +0000433
434
435#ifdef LWS_OPENSSL_SUPPORT
436 if (use_ssl) {
437
438 wsi[fds_count]->ssl = SSL_new(ssl_ctx); // get new SSL state with context
439 if (wsi[fds_count]->ssl == NULL) {
440 fprintf(stderr, "SSL_new failed: %s\n",
441 ERR_error_string(SSL_get_error(wsi[fds_count]->ssl, 0), NULL));
442 free(wsi[fds_count]);
443 continue;
444 }
445
446 SSL_set_fd(wsi[fds_count]->ssl, fd); // set SSL socket
447
448 n = SSL_accept(wsi[fds_count]->ssl);
449 if (n != 1) {
450 /* browsers seem to probe with various ssl params which fail then retry */
451 debug("SSL_accept failed for socket %u: %s\n",
452 fd,
453 ERR_error_string(SSL_get_error(wsi[fds_count]->ssl, n),
454 NULL));
455 SSL_free(wsi[fds_count]->ssl);
456 free(wsi[fds_count]);
457 continue;
458 }
459 debug("accepted new SSL conn port %u on fd=%d SSL ver %s\n",
460 ntohs(cli_addr.sin_port), fd, SSL_get_version(wsi[fds_count]->ssl));
461
462 } else {
463// fprintf(stderr, "accepted new conn port %u on fd=%d\n",
464// ntohs(cli_addr.sin_port), fd);
465 }
466#endif
467
468 /* intialize the instance struct */
469
Andy Green251f6fa2010-11-03 11:13:06 +0000470 wsi[fds_count]->sock = fd;
471 wsi[fds_count]->state = WSI_STATE_HTTP;
472 wsi[fds_count]->name_buffer_pos = 0;
473
474 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
475 wsi[fds_count]->utf8_token[n].token = NULL;
476 wsi[fds_count]->utf8_token[n].token_len = 0;
477 }
478
479 wsi[fds_count]->callback = callback;
480 wsi[fds_count]->ietf_spec_revision = protocol;
481
482 fds[fds_count].events = POLLIN;
483 fds[fds_count++].fd = fd;
Andy Green775c0dd2010-10-29 14:15:22 +0100484 }
485
Andy Green251f6fa2010-11-03 11:13:06 +0000486 /* check for activity on client sockets */
487
488 for (client = 1; client < fds_count; client++) {
489
490 /* handle session socket closed */
491
492 if (fds[client].revents & (POLLERR | POLLHUP)) {
493
494 fprintf(stderr, "Session Socket dead\n");
495
496 libwebsocket_close_and_free_session(wsi[client]);
497 goto nuke_this;
498 }
499
500 /* any incoming data ready? */
501
502 if (!(fds[client].revents & POLLIN))
503 continue;
504
505// fprintf(stderr, "POLLIN\n");
Andy Green3faa9c72010-11-08 17:03:03 +0000506
507#ifdef LWS_OPENSSL_SUPPORT
508 if (use_ssl)
509 n = SSL_read(wsi[client]->ssl, buf, sizeof buf);
510 else
511#endif
512 n = recv(fds[client].fd, buf, sizeof(buf), 0);
513
514// fprintf(stderr, "read returned %d\n", n);
515
Andy Green251f6fa2010-11-03 11:13:06 +0000516 if (n < 0) {
517 fprintf(stderr, "Socket read returned %d\n", n);
518 continue;
519 }
520 if (!n) {
521// fprintf(stderr, "POLLIN with 0 len waiting\n");
522 libwebsocket_close_and_free_session(wsi[client]);
523 goto nuke_this;
524 }
525
526 /* service incoming data */
527
528 if (libwebsocket_read(wsi[client], buf, n) >= 0)
529 continue;
530
531 /* it closed and nuked wsi[client] */
532nuke_this:
533 for (n = client; n < fds_count - 1; n++) {
534 fds[n] = fds[n + 1];
535 wsi[n] = wsi[n + 1];
536 }
537 fds_count--;
538 client--;
Andy Green775c0dd2010-10-29 14:15:22 +0100539 }
540
Andy Green251f6fa2010-11-03 11:13:06 +0000541poll_out:
542 for (client = 1; client < fds_count; client++) {
Andy Green775c0dd2010-10-29 14:15:22 +0100543
Andy Green251f6fa2010-11-03 11:13:06 +0000544 if (wsi[client]->state != WSI_STATE_ESTABLISHED)
545 continue;
546
547 if (!wsi[client]->callback)
548 continue;
Andy Green69fa0722010-11-03 08:25:13 +0000549
Andy Green251f6fa2010-11-03 11:13:06 +0000550 wsi[client]->callback(wsi[client], LWS_CALLBACK_SEND,
551 &wsi[client]->user_space[0], NULL, 0);
552 }
553
554 continue;
Andy Greenff95d7a2010-10-28 22:36:01 +0100555 }
Andy Green251f6fa2010-11-03 11:13:06 +0000556
557fatal:
Andy Green3faa9c72010-11-08 17:03:03 +0000558 /* listening socket */
Andy Green251f6fa2010-11-03 11:13:06 +0000559 close(fds[0].fd);
560 for (client = 1; client < fds_count; client++)
561 libwebsocket_close_and_free_session(wsi[client]);
Andy Greenff95d7a2010-10-28 22:36:01 +0100562
Andy Green3faa9c72010-11-08 17:03:03 +0000563#ifdef LWS_OPENSSL_SUPPORT
564 SSL_CTX_free(ssl_ctx);
565#endif
Andy Green251f6fa2010-11-03 11:13:06 +0000566 kill(0, SIGTERM);
567
568 return 0;
Andy Greenff95d7a2010-10-28 22:36:01 +0100569}
570
Andy Greenab990e42010-10-31 12:42:52 +0000571/**
572 * libwebsocket_get_uri() - Return the URI path being requested
573 * @wsi: Websocket instance
574 *
575 * The user code can find out the local path being opened from this
576 * call, it's valid on HTTP or established websocket connections.
577 * If the client opened the connection with "http://127.0.0.1/xyz/abc.d"
578 * then this call will return a pointer to "/xyz/abc.d"
579 */
580
Andy Green5fd8a5e2010-10-31 11:57:17 +0000581const char * libwebsocket_get_uri(struct libwebsocket *wsi)
582{
583 if (wsi->utf8_token[WSI_TOKEN_GET_URI].token)
584 return wsi->utf8_token[WSI_TOKEN_GET_URI].token;
585
586 return NULL;
587}
Andy Greenff95d7a2010-10-28 22:36:01 +0100588
589static int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c)
590{
591 int n;
592
593 switch (wsi->parser_state) {
594 case WSI_TOKEN_GET_URI:
595 case WSI_TOKEN_HOST:
596 case WSI_TOKEN_CONNECTION:
597 case WSI_TOKEN_KEY1:
598 case WSI_TOKEN_KEY2:
599 case WSI_TOKEN_PROTOCOL:
600 case WSI_TOKEN_UPGRADE:
601 case WSI_TOKEN_ORIGIN:
602 case WSI_TOKEN_CHALLENGE:
603
Andy Green69fa0722010-11-03 08:25:13 +0000604 debug("WSI_TOKEN_(%d) '%c'\n", wsi->parser_state, c);
Andy Greenff95d7a2010-10-28 22:36:01 +0100605
606 /* collect into malloc'd buffers */
607 /* optional space swallow */
608 if (!wsi->utf8_token[wsi->parser_state].token_len && c == ' ')
609 break;
610
611 /* special case space terminator for get-uri */
612 if (wsi->parser_state == WSI_TOKEN_GET_URI && c == ' ') {
613 wsi->utf8_token[wsi->parser_state].token[
614 wsi->utf8_token[wsi->parser_state].token_len] = '\0';
615 wsi->parser_state = WSI_TOKEN_SKIPPING;
616 break;
617 }
618
619 /* allocate appropriate memory */
Andy Green4ea60062010-10-30 12:15:07 +0100620 if (wsi->utf8_token[wsi->parser_state].token_len ==
621 wsi->current_alloc_len - 1) {
Andy Greenff95d7a2010-10-28 22:36:01 +0100622 /* need to extend */
623 wsi->current_alloc_len += LWS_ADDITIONAL_HDR_ALLOC;
624 if (wsi->current_alloc_len >= LWS_MAX_HEADER_LEN) {
625 /* it's waaay to much payload, fail it */
626 strcpy(wsi->utf8_token[wsi->parser_state].token,
Andy Green4ea60062010-10-30 12:15:07 +0100627 "!!! Length exceeded maximum supported !!!");
Andy Greenff95d7a2010-10-28 22:36:01 +0100628 wsi->parser_state = WSI_TOKEN_SKIPPING;
629 break;
630 }
631 wsi->utf8_token[wsi->parser_state].token =
632 realloc(wsi->utf8_token[wsi->parser_state].token,
633 wsi->current_alloc_len);
634 }
635
636 /* bail at EOL */
637 if (wsi->parser_state != WSI_TOKEN_CHALLENGE && c == '\x0d') {
638 wsi->utf8_token[wsi->parser_state].token[
639 wsi->utf8_token[wsi->parser_state].token_len] = '\0';
640 wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
641 break;
642 }
643
644 wsi->utf8_token[wsi->parser_state].token[
645 wsi->utf8_token[wsi->parser_state].token_len++] = c;
646
647 /* special payload limiting */
Andy Green775c0dd2010-10-29 14:15:22 +0100648 if (wsi->parser_state == WSI_TOKEN_CHALLENGE &&
649 wsi->utf8_token[wsi->parser_state].token_len == 8) {
Andy Green69fa0722010-11-03 08:25:13 +0000650 debug("Setting WSI_PARSING_COMPLETE\n");
Andy Green775c0dd2010-10-29 14:15:22 +0100651 wsi->parser_state = WSI_PARSING_COMPLETE;
652 break;
653 }
Andy Greenff95d7a2010-10-28 22:36:01 +0100654
655 break;
656
657 /* collecting and checking a name part */
658 case WSI_TOKEN_NAME_PART:
Andy Green69fa0722010-11-03 08:25:13 +0000659 debug("WSI_TOKEN_NAME_PART '%c'\n", c);
Andy Greenff95d7a2010-10-28 22:36:01 +0100660
661 if (wsi->name_buffer_pos == sizeof(wsi->name_buffer) - 1) {
662 /* name bigger than we can handle, skip until next */
663 wsi->parser_state = WSI_TOKEN_SKIPPING;
664 break;
665 }
666 wsi->name_buffer[wsi->name_buffer_pos++] = c;
667 wsi->name_buffer[wsi->name_buffer_pos] = '\0';
668
669 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
670 if (wsi->name_buffer_pos != lws_tokens[n].token_len)
671 continue;
672 if (strcmp(lws_tokens[n].token, wsi->name_buffer))
673 continue;
Andy Green69fa0722010-11-03 08:25:13 +0000674 debug("known hdr '%s'\n", wsi->name_buffer);
Andy Greenff95d7a2010-10-28 22:36:01 +0100675 wsi->parser_state = WSI_TOKEN_GET_URI + n;
676 wsi->current_alloc_len = LWS_INITIAL_HDR_ALLOC;
677 wsi->utf8_token[wsi->parser_state].token =
678 malloc(wsi->current_alloc_len);
679 wsi->utf8_token[wsi->parser_state].token_len = 0;
680 n = WSI_TOKEN_COUNT;
681 }
Andy Green5fd8a5e2010-10-31 11:57:17 +0000682
683 /* colon delimiter means we just don't know this name */
684
685 if (wsi->parser_state == WSI_TOKEN_NAME_PART && c == ':') {
Andy Green69fa0722010-11-03 08:25:13 +0000686 debug("skipping unknown header '%s'\n",
687 wsi->name_buffer);
Andy Green5fd8a5e2010-10-31 11:57:17 +0000688 wsi->parser_state = WSI_TOKEN_SKIPPING;
Andy Greenff95d7a2010-10-28 22:36:01 +0100689 break;
Andy Green5fd8a5e2010-10-31 11:57:17 +0000690 }
691
692 /* don't look for payload when it can just be http headers */
693
694 if (wsi->parser_state == WSI_TOKEN_CHALLENGE &&
695 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len) {
696 /* they're HTTP headers, not websocket upgrade! */
Andy Green69fa0722010-11-03 08:25:13 +0000697 debug("Setting WSI_PARSING_COMPLETE "
698 "from http headers\n");
Andy Green5fd8a5e2010-10-31 11:57:17 +0000699 wsi->parser_state = WSI_PARSING_COMPLETE;
700 }
Andy Greenff95d7a2010-10-28 22:36:01 +0100701 break;
702
703 /* skipping arg part of a name we didn't recognize */
704 case WSI_TOKEN_SKIPPING:
Andy Green69fa0722010-11-03 08:25:13 +0000705 debug("WSI_TOKEN_SKIPPING '%c'\n", c);
Andy Greenff95d7a2010-10-28 22:36:01 +0100706 if (c == '\x0d')
707 wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
708 break;
709 case WSI_TOKEN_SKIPPING_SAW_CR:
Andy Green69fa0722010-11-03 08:25:13 +0000710 debug("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
Andy Greenff95d7a2010-10-28 22:36:01 +0100711 if (c == '\x0a')
712 wsi->parser_state = WSI_TOKEN_NAME_PART;
713 else
714 wsi->parser_state = WSI_TOKEN_SKIPPING;
715 wsi->name_buffer_pos = 0;
716 break;
717 /* we're done, ignore anything else */
718 case WSI_PARSING_COMPLETE:
Andy Green69fa0722010-11-03 08:25:13 +0000719 debug("WSI_PARSING_COMPLETE '%c'\n", c);
Andy Greenff95d7a2010-10-28 22:36:01 +0100720 break;
721
722 default: /* keep gcc happy */
723 break;
724 }
725
726 return 0;
727}
728
729static int interpret_key(const char *key, unsigned int *result)
730{
731 char digits[20];
732 int digit_pos = 0;
733 const char *p = key;
734 int spaces = 0;
735
736 while (*p) {
737 if (isdigit(*p)) {
738 if (digit_pos == sizeof(digits) - 1)
739 return -1;
740 digits[digit_pos++] = *p;
741 }
742 p++;
743 }
744 digits[digit_pos] = '\0';
745 if (!digit_pos)
746 return -2;
747
748 while (*key) {
749 if (*key == ' ')
750 spaces++;
751 key++;
752 }
753
754 if (!spaces)
755 return -3;
756
757 *result = atol(digits) / spaces;
758
759 return 0;
760}
761
Andy Green4ea60062010-10-30 12:15:07 +0100762static int libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
763{
764 int n;
765 unsigned char buf[2];
766
767 switch (wsi->lws_rx_parse_state) {
768 case LWS_RXPS_NEW:
769
770 switch (wsi->ietf_spec_revision) {
771 /* Firefox 4.0b6 likes this as of 30 Oct */
772 case 76:
773 if (c == 0xff)
774 wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF;
775 break;
776 case 0:
777 break;
778 }
779 break;
780 case LWS_RXPS_SEEN_76_FF:
Andy Green69fa0722010-11-03 08:25:13 +0000781 if (c)
Andy Green4ea60062010-10-30 12:15:07 +0100782 break;
Andy Green4ea60062010-10-30 12:15:07 +0100783
Andy Green69fa0722010-11-03 08:25:13 +0000784 debug("Seen that client is requesting "
Andy Greene5eafd32010-10-31 13:11:57 +0000785 "a v76 close, sending ack\n");
Andy Green4ea60062010-10-30 12:15:07 +0100786 buf[0] = 0xff;
787 buf[1] = 0;
Andy Green3faa9c72010-11-08 17:03:03 +0000788 n = libwebsocket_write(wsi, buf, 2, LWS_WRITE_HTTP);
Andy Green4ea60062010-10-30 12:15:07 +0100789 if (n < 0) {
790 fprintf(stderr, "ERROR writing to socket");
791 return -1;
792 }
Andy Green69fa0722010-11-03 08:25:13 +0000793 debug(" v76 close ack sent, server closing skt\n");
Andy Green4ea60062010-10-30 12:15:07 +0100794 /* returning < 0 will get it closed in parent */
795 return -1;
796
797 case LWS_RXPS_PULLING_76_LENGTH:
798 break;
799 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
800 break;
801 }
802
803 return 0;
804}
805
806static int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
807 unsigned char *buf, size_t len)
808{
809 int n;
810
811 fprintf(stderr, "received %d byte packet\n", (int)len);
812 for (n = 0; n < len; n++)
813 fprintf(stderr, "%02X ", buf[n]);
814 fprintf(stderr, "\n");
815
816 /* let the rx protocol state machine have as much as it needs */
817
818 n = 0;
819 while (wsi->lws_rx_parse_state !=
820 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED && n < len)
821 if (libwebsocket_rx_sm(wsi, buf[n++]) < 0)
822 return -1;
823
Andy Greene5eafd32010-10-31 13:11:57 +0000824 if (n != len && wsi->callback)
Andy Green251f6fa2010-11-03 11:13:06 +0000825 wsi->callback(wsi, LWS_CALLBACK_RECEIVE, &wsi->user_space[0],
826 &buf[n], len - n);
Andy Green4ea60062010-10-30 12:15:07 +0100827
828 return -0;
829}
830
Andy Greenff95d7a2010-10-28 22:36:01 +0100831
832/*
833 * We have to take care about parsing because the headers may be split
834 * into multiple fragments. They may contain unknown headers with arbitrary
Andy Green775c0dd2010-10-29 14:15:22 +0100835 * argument lengths. So, we parse using a single-character at a time state
836 * machine that is completely independent of packet size.
Andy Greenff95d7a2010-10-28 22:36:01 +0100837 */
838
Andy Greenab990e42010-10-31 12:42:52 +0000839static int
840libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
Andy Greenff95d7a2010-10-28 22:36:01 +0100841{
842 size_t n;
843 char *p;
844 unsigned int key1, key2;
845 unsigned char sum[16];
Andy Green775c0dd2010-10-29 14:15:22 +0100846 char *response;
Andy Greenff95d7a2010-10-28 22:36:01 +0100847
848 switch (wsi->state) {
Andy Green5fd8a5e2010-10-31 11:57:17 +0000849 case WSI_STATE_HTTP:
850 wsi->state = WSI_STATE_HTTP_HEADERS;
Andy Greenff95d7a2010-10-28 22:36:01 +0100851 wsi->parser_state = WSI_TOKEN_NAME_PART;
Andy Green775c0dd2010-10-29 14:15:22 +0100852 /* fallthru */
Andy Green5fd8a5e2010-10-31 11:57:17 +0000853 case WSI_STATE_HTTP_HEADERS:
Andy Greenff95d7a2010-10-28 22:36:01 +0100854
Andy Green69fa0722010-11-03 08:25:13 +0000855 debug("issuing %d bytes to parser\n", (int)len);
856#ifdef DEBUG
857 fwrite(buf, 1, len, stderr);
858#endif
Andy Greenff95d7a2010-10-28 22:36:01 +0100859 for (n = 0; n< len; n++)
860 libwebsocket_parse(wsi, *buf++);
861
862 if (wsi->parser_state != WSI_PARSING_COMPLETE)
863 break;
Andy Green5fd8a5e2010-10-31 11:57:17 +0000864
865 /* is this websocket protocol or normal http 1.0? */
866
867 if (!wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
868 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len) {
869 if (wsi->callback)
Andy Greene5eafd32010-10-31 13:11:57 +0000870 (wsi->callback)(wsi, LWS_CALLBACK_HTTP,
Andy Green251f6fa2010-11-03 11:13:06 +0000871 &wsi->user_space[0],
Andy Greene5eafd32010-10-31 13:11:57 +0000872 NULL, 0);
Andy Green5fd8a5e2010-10-31 11:57:17 +0000873 wsi->state = WSI_STATE_HTTP;
874 return 0;
875 }
876
Andy Green5fd8a5e2010-10-31 11:57:17 +0000877 /* Websocket - confirm we have all the necessary pieces */
Andy Greenff95d7a2010-10-28 22:36:01 +0100878
Andy Green5fd8a5e2010-10-31 11:57:17 +0000879 if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
Andy Greenff95d7a2010-10-28 22:36:01 +0100880 !wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
881 !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
882 !wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
Andy Green5fd8a5e2010-10-31 11:57:17 +0000883 !wsi->utf8_token[WSI_TOKEN_KEY2].token_len)
Andy Greenff95d7a2010-10-28 22:36:01 +0100884 /* completed header processing, but missing some bits */
885 goto bail;
Andy Greenff95d7a2010-10-28 22:36:01 +0100886
887 /* create the response packet */
888
Andy Green4ea60062010-10-30 12:15:07 +0100889 /* make a buffer big enough for everything */
890
Andy Green775c0dd2010-10-29 14:15:22 +0100891 response = malloc(256 +
Andy Greenff95d7a2010-10-28 22:36:01 +0100892 wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
893 wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
894 wsi->utf8_token[WSI_TOKEN_HOST].token_len +
895 wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
896 wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
897 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
Andy Green4ea60062010-10-30 12:15:07 +0100898 if (!response) {
899 fprintf(stderr, "Out of memory for response buffer\n");
900 goto bail;
901 }
Andy Greenff95d7a2010-10-28 22:36:01 +0100902
Andy Green775c0dd2010-10-29 14:15:22 +0100903 p = response;
Andy Green4ea60062010-10-30 12:15:07 +0100904 strcpy(p, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
905 "Upgrade: WebSocket\x0d\x0a");
906 p += strlen("HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
907 "Upgrade: WebSocket\x0d\x0a");
Andy Greene5eafd32010-10-31 13:11:57 +0000908 strcpy(p, "Connection: Upgrade\x0d\x0a"
909 "Sec-WebSocket-Origin: ");
910 p += strlen("Connection: Upgrade\x0d\x0a"
911 "Sec-WebSocket-Origin: ");
Andy Greenff95d7a2010-10-28 22:36:01 +0100912 strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
913 p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
Andy Green3faa9c72010-11-08 17:03:03 +0000914#ifdef LWS_OPENSSL_SUPPORT
915 if (use_ssl) {
916 strcpy(p, "\x0d\x0aSec-WebSocket-Location: wss://");
917 p += strlen("\x0d\x0aSec-WebSocket-Location: wss://");
918 } else {
919#endif
920 strcpy(p, "\x0d\x0aSec-WebSocket-Location: ws://");
921 p += strlen("\x0d\x0aSec-WebSocket-Location: ws://");
922#ifdef LWS_OPENSSL_SUPPORT
923 }
924#endif
Andy Greenff95d7a2010-10-28 22:36:01 +0100925 strcpy(p, wsi->utf8_token[WSI_TOKEN_HOST].token);
926 p += wsi->utf8_token[WSI_TOKEN_HOST].token_len;
927 strcpy(p, wsi->utf8_token[WSI_TOKEN_GET_URI].token);
928 p += wsi->utf8_token[WSI_TOKEN_GET_URI].token_len;
Andy Greenea71ed12010-10-31 07:40:33 +0000929
Andy Greenff95d7a2010-10-28 22:36:01 +0100930 if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
Andy Greenea71ed12010-10-31 07:40:33 +0000931 strcpy(p, "\x0d\x0aSec-WebSocket-Protocol: ");
932 p += strlen("\x0d\x0aSec-WebSocket-Protocol: ");
Andy Greenff95d7a2010-10-28 22:36:01 +0100933 strcpy(p, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
934 p += wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len;
935 }
Andy Greenea71ed12010-10-31 07:40:33 +0000936
Andy Greenff95d7a2010-10-28 22:36:01 +0100937 strcpy(p, "\x0d\x0a\x0d\x0a");
938 p += strlen("\x0d\x0a\x0d\x0a");
939
Andy Green775c0dd2010-10-29 14:15:22 +0100940 /* convert the two keys into 32-bit integers */
941
Andy Greenff95d7a2010-10-28 22:36:01 +0100942 if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
943 goto bail;
Andy Greenff95d7a2010-10-28 22:36:01 +0100944 if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
945 goto bail;
Andy Green775c0dd2010-10-29 14:15:22 +0100946
947 /* lay them out in network byte order (MSB first */
Andy Greenff95d7a2010-10-28 22:36:01 +0100948
949 sum[0] = key1 >> 24;
950 sum[1] = key1 >> 16;
951 sum[2] = key1 >> 8;
952 sum[3] = key1;
953 sum[4] = key2 >> 24;
954 sum[5] = key2 >> 16;
955 sum[6] = key2 >> 8;
956 sum[7] = key2;
Andy Green775c0dd2010-10-29 14:15:22 +0100957
958 /* follow them with the challenge token we were sent */
959
Andy Greenff95d7a2010-10-28 22:36:01 +0100960 memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
961
Andy Green775c0dd2010-10-29 14:15:22 +0100962 /*
963 * compute the md5sum of that 16-byte series and use as our
964 * payload after our headers
965 */
966
Andy Greenff95d7a2010-10-28 22:36:01 +0100967 md5(sum, 16, (unsigned char *)p);
968 p += 16;
969
Andy Green4ea60062010-10-30 12:15:07 +0100970 /* it's complete: go ahead and send it */
Andy Greenff95d7a2010-10-28 22:36:01 +0100971
Andy Green69fa0722010-11-03 08:25:13 +0000972 debug("issuing response packet %d len\n",
973 (int)(p - response));
974#ifdef DEBUG
975 fwrite(response, 1, p - response, stderr);
976#endif
Andy Green3faa9c72010-11-08 17:03:03 +0000977 n = libwebsocket_write(wsi, (unsigned char *)response, p - response,
978 LWS_WRITE_HTTP);
Andy Green775c0dd2010-10-29 14:15:22 +0100979 if (n < 0) {
980 fprintf(stderr, "ERROR writing to socket");
981 goto bail;
982 }
Andy Green4ea60062010-10-30 12:15:07 +0100983
984 /* alright clean up and set ourselves into established state */
Andy Green775c0dd2010-10-29 14:15:22 +0100985
986 free(response);
987 wsi->state = WSI_STATE_ESTABLISHED;
Andy Green4ea60062010-10-30 12:15:07 +0100988 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
Andy Green775c0dd2010-10-29 14:15:22 +0100989
990 /* notify user code that we're ready to roll */
991
992 if (wsi->callback)
Andy Green251f6fa2010-11-03 11:13:06 +0000993 wsi->callback(wsi, LWS_CALLBACK_ESTABLISHED,
994 &wsi->user_space[0], NULL, 0);
Andy Greenff95d7a2010-10-28 22:36:01 +0100995 break;
996
997 case WSI_STATE_ESTABLISHED:
Andy Green4ea60062010-10-30 12:15:07 +0100998 if (libwebsocket_interpret_incoming_packet(wsi, buf, len) < 0)
999 goto bail;
Andy Greenff95d7a2010-10-28 22:36:01 +01001000 break;
1001 default:
1002 break;
1003 }
1004
1005 return 0;
1006
1007bail:
Andy Green251f6fa2010-11-03 11:13:06 +00001008 libwebsocket_close_and_free_session(wsi);
Andy Greenff95d7a2010-10-28 22:36:01 +01001009 return -1;
1010}
1011
Andy Greenab990e42010-10-31 12:42:52 +00001012/**
1013 * libwebsocket_write() - Apply protocol then write data to client
1014 * @wsi: Websocket instance (available from user callback)
1015 * @buf: The data to send. For data being sent on a websocket
1016 * connection (ie, not default http), this buffer MUST have
1017 * LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE the pointer
1018 * and an additional LWS_SEND_BUFFER_POST_PADDING bytes valid
1019 * in the buffer after (buf + len). This is so the protocol
1020 * header and trailer data can be added in-situ.
1021 * @len: Count of the data bytes in the payload starting from buf
1022 * @protocol: Use LWS_WRITE_HTTP to reply to an http connection, and one
1023 * of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate
1024 * data on a websockets connection. Remember to allow the extra
1025 * bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT
1026 * are used.
1027 *
1028 * This function provides the way to issue data back to the client
1029 * for both http and websocket protocols.
Andy Green4ea60062010-10-30 12:15:07 +01001030 *
Andy Greenab990e42010-10-31 12:42:52 +00001031 * In the case of sending using websocket protocol, be sure to allocate
1032 * valid storage before and after buf as explained above. This scheme
1033 * allows maximum efficiency of sending data and protocol in a single
1034 * packet while not burdening the user code with any protocol knowledge.
Andy Green4ea60062010-10-30 12:15:07 +01001035 */
1036
1037int libwebsocket_write(struct libwebsocket * wsi, unsigned char *buf,
Andy Green5fd8a5e2010-10-31 11:57:17 +00001038 size_t len, enum libwebsocket_write_protocol protocol)
Andy Green775c0dd2010-10-29 14:15:22 +01001039{
1040 int n;
Andy Green4ea60062010-10-30 12:15:07 +01001041 int pre = 0;
1042 int post = 0;
1043 unsigned int shift = 7;
Andy Green775c0dd2010-10-29 14:15:22 +01001044
Andy Green5fd8a5e2010-10-31 11:57:17 +00001045 if (protocol == LWS_WRITE_HTTP)
1046 goto send_raw;
1047
1048 /* websocket protocol, either binary or text */
1049
Andy Green775c0dd2010-10-29 14:15:22 +01001050 if (wsi->state != WSI_STATE_ESTABLISHED)
1051 return -1;
Andy Greenff95d7a2010-10-28 22:36:01 +01001052
Andy Green775c0dd2010-10-29 14:15:22 +01001053 switch (wsi->ietf_spec_revision) {
Andy Green69fa0722010-11-03 08:25:13 +00001054 /* chrome likes this as of 30 Oct */
Andy Green4ea60062010-10-30 12:15:07 +01001055 /* Firefox 4.0b6 likes this as of 30 Oct */
1056 case 76:
Andy Green5fd8a5e2010-10-31 11:57:17 +00001057 if (protocol == LWS_WRITE_BINARY) {
Andy Green4ea60062010-10-30 12:15:07 +01001058 /* in binary mode we send 7-bit used length blocks */
1059 pre = 1;
1060 while (len & (127 << shift)) {
1061 pre++;
1062 shift += 7;
1063 }
1064 n = 0;
1065 shift -= 7;
1066 while (shift >= 0) {
1067 if (shift)
1068 buf[0 - pre + n] =
1069 ((len >> shift) & 127) | 0x80;
1070 else
1071 buf[0 - pre + n] =
1072 ((len >> shift) & 127);
1073 n++;
1074 shift -= 7;
1075 }
1076 break;
Andy Green775c0dd2010-10-29 14:15:22 +01001077 }
Andy Green4ea60062010-10-30 12:15:07 +01001078
1079 /* frame type = text, length-free spam mode */
1080
1081 buf[-1] = 0;
1082 buf[len] = 0xff; /* EOT marker */
1083 pre = 1;
1084 post = 1;
Andy Green775c0dd2010-10-29 14:15:22 +01001085 break;
Andy Green4ea60062010-10-30 12:15:07 +01001086
Andy Green4ea60062010-10-30 12:15:07 +01001087 case 0:
1088 buf[-9] = 0xff;
1089#if defined __LP64__
1090 buf[-8] = len >> 56;
1091 buf[-7] = len >> 48;
1092 buf[-6] = len >> 40;
1093 buf[-5] = len >> 32;
1094#else
1095 buf[-8] = 0;
1096 buf[-7] = 0;
1097 buf[-6] = 0;
1098 buf[-5] = 0;
1099#endif
1100 buf[-4] = len >> 24;
1101 buf[-3] = len >> 16;
1102 buf[-2] = len >> 8;
1103 buf[-1] = len;
1104 pre = 9;
1105 break;
1106
Andy Green775c0dd2010-10-29 14:15:22 +01001107 /* just an unimplemented spec right now apparently */
1108 case 2:
Andy Green4ea60062010-10-30 12:15:07 +01001109 n = 4; /* text */
Andy Green5fd8a5e2010-10-31 11:57:17 +00001110 if (protocol == LWS_WRITE_BINARY)
Andy Green4ea60062010-10-30 12:15:07 +01001111 n = 5; /* binary */
Andy Green775c0dd2010-10-29 14:15:22 +01001112 if (len < 126) {
Andy Green4ea60062010-10-30 12:15:07 +01001113 buf[-2] = n;
1114 buf[-1] = len;
1115 pre = 2;
Andy Green775c0dd2010-10-29 14:15:22 +01001116 } else {
1117 if (len < 65536) {
Andy Green4ea60062010-10-30 12:15:07 +01001118 buf[-4] = n;
1119 buf[-3] = 126;
1120 buf[-2] = len >> 8;
1121 buf[-1] = len;
1122 pre = 4;
Andy Green775c0dd2010-10-29 14:15:22 +01001123 } else {
Andy Green4ea60062010-10-30 12:15:07 +01001124 buf[-10] = n;
1125 buf[-9] = 127;
1126#if defined __LP64__
1127 buf[-8] = (len >> 56) & 0x7f;
1128 buf[-7] = len >> 48;
1129 buf[-6] = len >> 40;
1130 buf[-5] = len >> 32;
1131#else
1132 buf[-8] = 0;
1133 buf[-7] = 0;
1134 buf[-6] = 0;
1135 buf[-5] = 0;
1136#endif
1137 buf[-4] = len >> 24;
1138 buf[-3] = len >> 16;
1139 buf[-2] = len >> 8;
1140 buf[-1] = len;
1141 pre = 10;
Andy Green775c0dd2010-10-29 14:15:22 +01001142 }
1143 }
Andy Green775c0dd2010-10-29 14:15:22 +01001144 break;
1145 }
Andy Green251f6fa2010-11-03 11:13:06 +00001146
1147#if 0
1148 for (n = 0; n < (len + pre + post); n++)
1149 fprintf(stderr, "%02X ", buf[n - pre]);
1150
1151 fprintf(stderr, "\n");
1152#endif
Andy Green775c0dd2010-10-29 14:15:22 +01001153
Andy Green5fd8a5e2010-10-31 11:57:17 +00001154send_raw:
Andy Green3faa9c72010-11-08 17:03:03 +00001155#ifdef LWS_OPENSSL_SUPPORT
1156 if (use_ssl) {
1157 n = SSL_write(wsi->ssl, buf - pre, len + pre + post);
1158 if (n < 0) {
1159 fprintf(stderr, "ERROR writing to socket");
1160 return -1;
1161 }
1162 } else {
1163#endif
1164 n = send(wsi->sock, buf - pre, len + pre + post, 0);
1165 if (n < 0) {
1166 fprintf(stderr, "ERROR writing to socket");
1167 return -1;
1168 }
1169#ifdef LWS_OPENSSL_SUPPORT
Andy Green775c0dd2010-10-29 14:15:22 +01001170 }
Andy Green3faa9c72010-11-08 17:03:03 +00001171#endif
Andy Green5fd8a5e2010-10-31 11:57:17 +00001172// fprintf(stderr, "written %d bytes to client\n", (int)len);
Andy Green775c0dd2010-10-29 14:15:22 +01001173
1174 return 0;
1175}
1176
Andy Greenff95d7a2010-10-28 22:36:01 +01001177
Andy Greenab990e42010-10-31 12:42:52 +00001178/**
1179 * libwebsockets_serve_http_file() - Send a file back to the client using http
1180 * @wsi: Websocket instance (available from user callback)
1181 * @file: The file to issue over http
1182 * @content_type: The http content type, eg, text/html
1183 *
1184 * This function is intended to be called from the callback in response
1185 * to http requests from the client. It allows the callback to issue
1186 * local files down the http link in a single step.
1187 */
1188
Andy Green5fd8a5e2010-10-31 11:57:17 +00001189int libwebsockets_serve_http_file(struct libwebsocket *wsi, const char * file,
1190 const char * content_type)
1191{
1192 int fd;
1193 struct stat stat;
1194 char buf[512];
1195 char *p = buf;
1196 int n;
1197
1198 fd = open(file, O_RDONLY);
1199 if (fd < 1) {
1200 p += sprintf(p, "HTTP/1.0 400 Bad\x0d\x0a"
1201 "Server: libwebsockets\x0d\x0a"
1202 "\x0d\x0a"
1203 );
Andy Greene5eafd32010-10-31 13:11:57 +00001204 libwebsocket_write(wsi, (unsigned char *)buf, p - buf,
1205 LWS_WRITE_HTTP);
Andy Green5fd8a5e2010-10-31 11:57:17 +00001206
1207 return -1;
1208 }
1209
1210 fstat(fd, &stat);
1211 p += sprintf(p, "HTTP/1.0 200 OK\x0d\x0a"
1212 "Server: libwebsockets\x0d\x0a"
1213 "Content-Type: %s\x0d\x0a"
1214 "Content-Length: %u\x0d\x0a"
Andy Greene5eafd32010-10-31 13:11:57 +00001215 "\x0d\x0a", content_type, (unsigned int)stat.st_size);
Andy Green5fd8a5e2010-10-31 11:57:17 +00001216
1217 libwebsocket_write(wsi, (unsigned char *)buf, p - buf, LWS_WRITE_HTTP);
1218
1219 n = 1;
1220 while (n > 0) {
1221 n = read(fd, buf, 512);
Andy Greene5eafd32010-10-31 13:11:57 +00001222 libwebsocket_write(wsi, (unsigned char *)buf, n,
1223 LWS_WRITE_HTTP);
Andy Green5fd8a5e2010-10-31 11:57:17 +00001224 }
1225
1226 close(fd);
1227
1228 return 0;
1229}