blob: 9c798e4f518a69d8d407589df6cbef812d27b7c4 [file] [log] [blame]
Andy Green05a0a7b2010-10-31 17:51:39 +00001/*
2 * libwebsockets Copyright 2010 Andy Green <andy@warmcat.com>
3 * licensed under GPL2
4 */
5
Andy Greenff95d7a2010-10-28 22:36:01 +01006#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <ctype.h>
10#include <unistd.h>
Andy Green775c0dd2010-10-29 14:15:22 +010011#include <errno.h>
Andy Green5fd8a5e2010-10-31 11:57:17 +000012#include <sys/types.h>
13#include <sys/stat.h>
14#include <fcntl.h>
Andy Green251f6fa2010-11-03 11:13:06 +000015#include <signal.h>
Andy Greenff95d7a2010-10-28 22:36:01 +010016
17#include <sys/types.h>
18#include <sys/socket.h>
19#include <netinet/in.h>
20
21#include <poll.h>
22#include <sys/mman.h>
23
Andy Green3faa9c72010-11-08 17:03:03 +000024#ifdef LWS_OPENSSL_SUPPORT
25#include <openssl/ssl.h>
26#include <openssl/evp.h>
27#include <openssl/err.h>
28
29SSL_CTX *ssl_ctx;
30int use_ssl;
31#endif
32
33//#define DEBUG
34
Andy Greenff95d7a2010-10-28 22:36:01 +010035#include "libwebsockets.h"
36
Andy Green69fa0722010-11-03 08:25:13 +000037#ifdef DEBUG
38#define debug(format, args...) \
39 fprintf(stderr, format , ## args)
40#else
41#define debug(format, args...)
42#endif
43
Andy Greenff95d7a2010-10-28 22:36:01 +010044void md5(const unsigned char *input, int ilen, unsigned char output[16]);
Andy Green251f6fa2010-11-03 11:13:06 +000045static int
46libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len);
Andy Greenff95d7a2010-10-28 22:36:01 +010047
Andy Green251f6fa2010-11-03 11:13:06 +000048#define MAX_CLIENTS 100
Andy Green775c0dd2010-10-29 14:15:22 +010049#define LWS_MAX_HEADER_NAME_LENGTH 64
50#define LWS_MAX_HEADER_LEN 4096
51#define LWS_INITIAL_HDR_ALLOC 256
52#define LWS_ADDITIONAL_HDR_ALLOC 64
53
54
Andy Green3faa9c72010-11-08 17:03:03 +000055
Andy Green775c0dd2010-10-29 14:15:22 +010056enum lws_connection_states {
Andy Green5fd8a5e2010-10-31 11:57:17 +000057 WSI_STATE_HTTP,
58 WSI_STATE_HTTP_HEADERS,
Andy Green775c0dd2010-10-29 14:15:22 +010059 WSI_STATE_DEAD_SOCKET,
60 WSI_STATE_ESTABLISHED
61};
62
63enum lws_token_indexes {
64 WSI_TOKEN_GET_URI,
65 WSI_TOKEN_HOST,
66 WSI_TOKEN_CONNECTION,
67 WSI_TOKEN_KEY1,
68 WSI_TOKEN_KEY2,
69 WSI_TOKEN_PROTOCOL,
70 WSI_TOKEN_UPGRADE,
71 WSI_TOKEN_ORIGIN,
72 WSI_TOKEN_CHALLENGE,
73
74 /* always last real token index*/
75 WSI_TOKEN_COUNT,
76 /* parser state additions */
77 WSI_TOKEN_NAME_PART,
78 WSI_TOKEN_SKIPPING,
79 WSI_TOKEN_SKIPPING_SAW_CR,
80 WSI_PARSING_COMPLETE
81};
82
Andy Green4ea60062010-10-30 12:15:07 +010083enum lws_rx_parse_state {
84 LWS_RXPS_NEW,
85
86 LWS_RXPS_SEEN_76_FF,
87 LWS_RXPS_PULLING_76_LENGTH,
88
89 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED
90};
91
Andy Green775c0dd2010-10-29 14:15:22 +010092
93struct lws_tokens {
94 char * token;
95 int token_len;
96};
97
98
99/*
100 * This is totally opaque to code using the library. It's exported as a
Andy Greenab990e42010-10-31 12:42:52 +0000101 * forward-reference pointer-only declaration; the user can use the pointer with
102 * other APIs to get information out of it.
Andy Green775c0dd2010-10-29 14:15:22 +0100103 */
104
105struct libwebsocket {
106 int (*callback)(struct libwebsocket *,
Andy Green251f6fa2010-11-03 11:13:06 +0000107 enum libwebsocket_callback_reasons reason, void *, void *, size_t);
Andy Green775c0dd2010-10-29 14:15:22 +0100108
109 enum lws_connection_states state;
110
111 char name_buffer[LWS_MAX_HEADER_NAME_LENGTH];
112 int name_buffer_pos;
113 int current_alloc_len;
114 enum lws_token_indexes parser_state;
115 struct lws_tokens utf8_token[WSI_TOKEN_COUNT];
116 int ietf_spec_revision;
117
118 int sock;
Andy Green4ea60062010-10-30 12:15:07 +0100119
120 enum lws_rx_parse_state lws_rx_parse_state;
121 size_t rx_packet_length;
Andy Green251f6fa2010-11-03 11:13:06 +0000122
Andy Green3faa9c72010-11-08 17:03:03 +0000123#ifdef LWS_OPENSSL_SUPPORT
124 char m_fOccupied;
125 struct sockaddr_in m_addr;
126 int m_addrlen;
127
128 SSL *ssl;
129
130 // these are valid if it is a POST
131
132 char m_fOngoingPost;
133 int m_nSessionID;
134
135 time_t m_timeStarted;
136 long long m_llTransferred;
137 long long m_llSizeIfKnown;
138
139 char m_szTitle[PATH_MAX];
140 char m_szStatus[PATH_MAX];
141#endif
142
Andy Green251f6fa2010-11-03 11:13:06 +0000143 /* last */
144 char user_space[0];
Andy Green775c0dd2010-10-29 14:15:22 +0100145};
146
Andy Greenff95d7a2010-10-28 22:36:01 +0100147
148const struct lws_tokens lws_tokens[WSI_TOKEN_COUNT] = {
149 { "GET ", 4 },
150 { "Host:", 5 },
151 { "Connection:", 11 },
152 { "Sec-WebSocket-Key1:", 19 },
153 { "Sec-WebSocket-Key2:", 19 },
154 { "Sec-WebSocket-Protocol:", 23 },
155 { "Upgrade:", 8 },
156 { "Origin:", 7 },
157 { "\x0d\x0a", 2 },
158};
159
Andy Green251f6fa2010-11-03 11:13:06 +0000160static void
161libwebsocket_close_and_free_session(struct libwebsocket *wsi)
162{
163 int n = wsi->state;
164
165 wsi->state = WSI_STATE_DEAD_SOCKET;
166
167 if (wsi->callback && n == WSI_STATE_ESTABLISHED)
168 wsi->callback(wsi, LWS_CALLBACK_CLOSED, &wsi->user_space[0],
169 NULL, 0);
170
171 for (n = 0; n < WSI_TOKEN_COUNT; n++)
172 if (wsi->utf8_token[n].token)
173 free(wsi->utf8_token[n].token);
174
175// fprintf(stderr, "closing fd=%d\n", wsi->sock);
176
Andy Green3faa9c72010-11-08 17:03:03 +0000177#ifdef LWS_OPENSSL_SUPPORT
178 if (use_ssl) {
179 n = SSL_get_fd(wsi->ssl);
180 SSL_shutdown(wsi->ssl);
181 close(n);
182 SSL_free(wsi->ssl);
183 } else {
184#endif
185 shutdown(wsi->sock, SHUT_RDWR);
186 close(wsi->sock);
187#ifdef LWS_OPENSSL_SUPPORT
188 }
189#endif
Andy Green251f6fa2010-11-03 11:13:06 +0000190 free(wsi);
191}
192
Andy Greenab990e42010-10-31 12:42:52 +0000193/**
194 * libwebsocket_create_server() - Create the listening websockets server
195 * @port: Port to listen on
196 * @callback: The callback in user code to perform actual serving
197 * @protocol: Which version of the websockets protocol (currently 76)
Andy Green251f6fa2010-11-03 11:13:06 +0000198 * @user_area_size: How much memory to allocate per connection session
199 * which will be used by the user application to store
200 * per-session data. A pointer to this space is given
201 * when the user callback is called.
Andy Green3faa9c72010-11-08 17:03:03 +0000202 * @ssl_cert_filepath: If libwebsockets was compiled to use ssl, and you want
203 * to listen using SSL, set to the filepath to fetch the
204 * server cert from, otherwise NULL for unencrypted
205 * @ssl_private_key_filepath: filepath to private key if wanting SSL mode,
206 * else ignored
207 * @gid: group id to change to after setting listen socket, or -1.
208 * @uid: user id to change to after setting listen socket, or -1.
Andy Greenab990e42010-10-31 12:42:52 +0000209 *
210 * This function forks to create the listening socket and takes care
211 * of all initialization in one step.
212 *
213 * The callback function is called for a handful of events including
214 * http requests coming in, websocket connections becoming
215 * established, and data arriving; it's also called periodically to allow
216 * async transmission.
217 *
218 * The server created is a simple http server by default; part of the
219 * websocket standard is upgrading this http connection to a websocket one.
220 *
221 * This allows the same server to provide files like scripts and favicon /
222 * images or whatever over http and dynamic data over websockets all in
223 * one place; they're all handled in the user callback.
224 */
Andy Green4ea60062010-10-30 12:15:07 +0100225
Andy Greenea71ed12010-10-31 07:40:33 +0000226int libwebsocket_create_server(int port,
227 int (*callback)(struct libwebsocket *,
Andy Green251f6fa2010-11-03 11:13:06 +0000228 enum libwebsocket_callback_reasons,
229 void *, void *, size_t),
Andy Green3faa9c72010-11-08 17:03:03 +0000230 int protocol, size_t user_area_size,
231 const char * ssl_cert_filepath,
232 const char * ssl_private_key_filepath,
233 int gid, int uid)
Andy Greenff95d7a2010-10-28 22:36:01 +0100234{
235 int n;
Andy Green251f6fa2010-11-03 11:13:06 +0000236 int client;
Andy Green69fa0722010-11-03 08:25:13 +0000237 int sockfd;
Andy Green251f6fa2010-11-03 11:13:06 +0000238 int fd;
Andy Greenff95d7a2010-10-28 22:36:01 +0100239 unsigned int clilen;
240 struct sockaddr_in serv_addr, cli_addr;
Andy Green251f6fa2010-11-03 11:13:06 +0000241 struct libwebsocket *wsi[MAX_CLIENTS + 1];
242 struct pollfd fds[MAX_CLIENTS + 1];
243 int fds_count = 0;
Andy Green3faa9c72010-11-08 17:03:03 +0000244 unsigned char buf[1024];
Andy Green251f6fa2010-11-03 11:13:06 +0000245 int opt = 1;
Andy Greenff95d7a2010-10-28 22:36:01 +0100246
Andy Green3faa9c72010-11-08 17:03:03 +0000247#ifdef LWS_OPENSSL_SUPPORT
248 const SSL_METHOD *method;
249 char ssl_err_buf[512];
250
251 use_ssl = ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL;
252 if (use_ssl)
253 fprintf(stderr, " Compiled with SSL support, using it\n");
254 else
255 fprintf(stderr, " Compiled with SSL support, but not using it\n");
256
257#else
258 if (ssl_cert_filepath != NULL && ssl_private_key_filepath != NULL) {
259 fprintf(stderr, " Not compiled for OpenSSl support!\n");
260 return -1;
261 }
262 fprintf(stderr, " Compiled without SSL support, listening unencrypted\n");
263#endif
264
265#ifdef LWS_OPENSSL_SUPPORT
266 if (use_ssl) {
267 SSL_library_init();
268
269 OpenSSL_add_all_algorithms();
270 SSL_load_error_strings();
271
272 // Firefox insists on SSLv23 not SSLv3
273 // Konq disables SSLv2 by default now, SSLv23 works
274
275 method = SSLv23_server_method(); // create server instance
276 if (!method) {
277 fprintf(stderr, "problem creating ssl method: %s\n",
278 ERR_error_string(ERR_get_error(), ssl_err_buf));
279 return -1;
280 }
281 ssl_ctx = SSL_CTX_new(method); /* create context */
282 if (!ssl_ctx) {
283 printf("problem creating ssl context: %s\n",
284 ERR_error_string(ERR_get_error(), ssl_err_buf));
285 return -1;
286 }
287 /* set the local certificate from CertFile */
288 n = SSL_CTX_use_certificate_file(ssl_ctx,
289 ssl_cert_filepath, SSL_FILETYPE_PEM);
290 if (n != 1) {
291 fprintf(stderr, "problem getting cert '%s': %s\n",
292 ssl_cert_filepath,
293 ERR_error_string(ERR_get_error(), ssl_err_buf));
294 return -1;
295 }
296 /* set the private key from KeyFile */
297 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, ssl_private_key_filepath,
298 SSL_FILETYPE_PEM) != 1) {
299 fprintf(stderr, "ssl problem getting key '%s': %s\n", ssl_private_key_filepath, ERR_error_string(ERR_get_error(), ssl_err_buf));
300 return (-1);
301 }
302 /* verify private key */
303 if (!SSL_CTX_check_private_key(ssl_ctx)) {
304 fprintf(stderr, "Private SSL key does not match cert\n");
305 return (-1);
306 }
307
308 /* SSL is happy and has a cert it's content with */
309 }
310#endif
311
Andy Green251f6fa2010-11-03 11:13:06 +0000312 /* sanity check */
313
Andy Greenea71ed12010-10-31 07:40:33 +0000314 switch (protocol) {
315 case 0:
316 case 2:
317 case 76:
Andy Green5fd8a5e2010-10-31 11:57:17 +0000318 fprintf(stderr, " Using protocol v%d\n", protocol);
Andy Greenea71ed12010-10-31 07:40:33 +0000319 break;
320 default:
321 fprintf(stderr, "protocol %d not supported (try 0 2 or 76)\n",
322 protocol);
323 return -1;
324 }
Andy Green251f6fa2010-11-03 11:13:06 +0000325
326 if (!callback) {
327 fprintf(stderr, "callback is not optional!\n");
328 return -1;
329 }
Andy Greenff95d7a2010-10-28 22:36:01 +0100330
Andy Green775c0dd2010-10-29 14:15:22 +0100331 /* sit there listening for connects, accept and spawn session servers */
332
333 sockfd = socket(AF_INET, SOCK_STREAM, 0);
334 if (sockfd < 0) {
335 fprintf(stderr, "ERROR opening socket");
Andy Green251f6fa2010-11-03 11:13:06 +0000336 return -1;
Andy Green775c0dd2010-10-29 14:15:22 +0100337 }
Andy Green251f6fa2010-11-03 11:13:06 +0000338
339 /* allow us to restart even if old sockets in TIME_WAIT */
340 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
Andy Green775c0dd2010-10-29 14:15:22 +0100341
Andy Green251f6fa2010-11-03 11:13:06 +0000342 bzero((char *) &serv_addr, sizeof(serv_addr));
Andy Green775c0dd2010-10-29 14:15:22 +0100343 serv_addr.sin_family = AF_INET;
344 serv_addr.sin_addr.s_addr = INADDR_ANY;
345 serv_addr.sin_port = htons(port);
346 n = bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
347 if (n < 0) {
Andy Greenea71ed12010-10-31 07:40:33 +0000348 fprintf(stderr, "ERROR on binding to port %d (%d %d)\n", port, n,
349 errno);
Andy Green775c0dd2010-10-29 14:15:22 +0100350 return -1;
351 }
352
353 /* fork off a master server for this websocket server */
Andy Greenff95d7a2010-10-28 22:36:01 +0100354
355 n = fork();
356 if (n < 0) {
357 fprintf(stderr, "Failed on forking server thread: %d\n", n);
Andy Green251f6fa2010-11-03 11:13:06 +0000358 return -1;
Andy Greenff95d7a2010-10-28 22:36:01 +0100359 }
360
361 /* we are done as far as the caller is concerned */
362
363 if (n)
Andy Green251f6fa2010-11-03 11:13:06 +0000364 return sockfd;
Andy Greenff95d7a2010-10-28 22:36:01 +0100365
Andy Green3faa9c72010-11-08 17:03:03 +0000366 // drop any root privs for this thread
367
368 if (gid != -1)
369 if (setgid(gid))
370 fprintf(stderr, "setgid: %s\n", strerror(errno));
371 if (uid != -1)
372 if (setuid(uid))
373 fprintf(stderr, "setuid: %s\n", strerror(errno));
374
Andy Green251f6fa2010-11-03 11:13:06 +0000375 /* we are running in a forked subprocess now */
Andy Greenea71ed12010-10-31 07:40:33 +0000376
Andy Greenff95d7a2010-10-28 22:36:01 +0100377 listen(sockfd, 5);
Andy Green251f6fa2010-11-03 11:13:06 +0000378 fprintf(stderr, " Listening on port %d\n", port);
379
380 fds[0].fd = sockfd;
381 fds_count = 1;
382 fds[0].events = POLLIN;
Andy Greenff95d7a2010-10-28 22:36:01 +0100383
384 while (1) {
Andy Greenff95d7a2010-10-28 22:36:01 +0100385
Andy Green251f6fa2010-11-03 11:13:06 +0000386 n = poll(fds, fds_count, 50);
387 if (n < 0 || fds[0].revents & (POLLERR | POLLHUP)) {
388// fprintf(stderr, "Listen Socket dead\n");
389 goto fatal;
Andy Green775c0dd2010-10-29 14:15:22 +0100390 }
Andy Green251f6fa2010-11-03 11:13:06 +0000391 if (n == 0) /* poll timeout */
392 goto poll_out;
393
394 if (fds[0].revents & POLLIN) {
395
Andy Green3faa9c72010-11-08 17:03:03 +0000396 /* listen socket got an unencrypted connection... */
397
Andy Green251f6fa2010-11-03 11:13:06 +0000398 clilen = sizeof(cli_addr);
Andy Green3faa9c72010-11-08 17:03:03 +0000399 fd = accept(sockfd,
400 (struct sockaddr *)&cli_addr,
401 &clilen);
Andy Green251f6fa2010-11-03 11:13:06 +0000402 if (fd < 0) {
403 fprintf(stderr, "ERROR on accept");
404 continue;
405 }
Andy Green3faa9c72010-11-08 17:03:03 +0000406
Andy Green251f6fa2010-11-03 11:13:06 +0000407 if (fds_count >= MAX_CLIENTS) {
408 fprintf(stderr, "too busy");
409 close(fd);
410 continue;
411 }
Andy Green3faa9c72010-11-08 17:03:03 +0000412
Andy Green251f6fa2010-11-03 11:13:06 +0000413 wsi[fds_count] = malloc(sizeof(struct libwebsocket) +
414 user_area_size);
415 if (!wsi[fds_count])
416 return -1;
Andy Green3faa9c72010-11-08 17:03:03 +0000417
418
419#ifdef LWS_OPENSSL_SUPPORT
420 if (use_ssl) {
421
422 wsi[fds_count]->ssl = SSL_new(ssl_ctx); // get new SSL state with context
423 if (wsi[fds_count]->ssl == NULL) {
424 fprintf(stderr, "SSL_new failed: %s\n",
425 ERR_error_string(SSL_get_error(wsi[fds_count]->ssl, 0), NULL));
426 free(wsi[fds_count]);
427 continue;
428 }
429
430 SSL_set_fd(wsi[fds_count]->ssl, fd); // set SSL socket
431
432 n = SSL_accept(wsi[fds_count]->ssl);
433 if (n != 1) {
434 /* browsers seem to probe with various ssl params which fail then retry */
435 debug("SSL_accept failed for socket %u: %s\n",
436 fd,
437 ERR_error_string(SSL_get_error(wsi[fds_count]->ssl, n),
438 NULL));
439 SSL_free(wsi[fds_count]->ssl);
440 free(wsi[fds_count]);
441 continue;
442 }
443 debug("accepted new SSL conn port %u on fd=%d SSL ver %s\n",
444 ntohs(cli_addr.sin_port), fd, SSL_get_version(wsi[fds_count]->ssl));
445
446 } else {
447// fprintf(stderr, "accepted new conn port %u on fd=%d\n",
448// ntohs(cli_addr.sin_port), fd);
449 }
450#endif
451
452 /* intialize the instance struct */
453
Andy Green251f6fa2010-11-03 11:13:06 +0000454 wsi[fds_count]->sock = fd;
455 wsi[fds_count]->state = WSI_STATE_HTTP;
456 wsi[fds_count]->name_buffer_pos = 0;
457
458 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
459 wsi[fds_count]->utf8_token[n].token = NULL;
460 wsi[fds_count]->utf8_token[n].token_len = 0;
461 }
462
463 wsi[fds_count]->callback = callback;
464 wsi[fds_count]->ietf_spec_revision = protocol;
465
466 fds[fds_count].events = POLLIN;
467 fds[fds_count++].fd = fd;
Andy Green775c0dd2010-10-29 14:15:22 +0100468 }
469
Andy Green251f6fa2010-11-03 11:13:06 +0000470 /* check for activity on client sockets */
471
472 for (client = 1; client < fds_count; client++) {
473
474 /* handle session socket closed */
475
476 if (fds[client].revents & (POLLERR | POLLHUP)) {
477
478 fprintf(stderr, "Session Socket dead\n");
479
480 libwebsocket_close_and_free_session(wsi[client]);
481 goto nuke_this;
482 }
483
484 /* any incoming data ready? */
485
486 if (!(fds[client].revents & POLLIN))
487 continue;
488
489// fprintf(stderr, "POLLIN\n");
Andy Green3faa9c72010-11-08 17:03:03 +0000490
491#ifdef LWS_OPENSSL_SUPPORT
492 if (use_ssl)
493 n = SSL_read(wsi[client]->ssl, buf, sizeof buf);
494 else
495#endif
496 n = recv(fds[client].fd, buf, sizeof(buf), 0);
497
498// fprintf(stderr, "read returned %d\n", n);
499
Andy Green251f6fa2010-11-03 11:13:06 +0000500 if (n < 0) {
501 fprintf(stderr, "Socket read returned %d\n", n);
502 continue;
503 }
504 if (!n) {
505// fprintf(stderr, "POLLIN with 0 len waiting\n");
506 libwebsocket_close_and_free_session(wsi[client]);
507 goto nuke_this;
508 }
509
510 /* service incoming data */
511
512 if (libwebsocket_read(wsi[client], buf, n) >= 0)
513 continue;
514
515 /* it closed and nuked wsi[client] */
516nuke_this:
517 for (n = client; n < fds_count - 1; n++) {
518 fds[n] = fds[n + 1];
519 wsi[n] = wsi[n + 1];
520 }
521 fds_count--;
522 client--;
Andy Green775c0dd2010-10-29 14:15:22 +0100523 }
524
Andy Green251f6fa2010-11-03 11:13:06 +0000525poll_out:
526 for (client = 1; client < fds_count; client++) {
Andy Green775c0dd2010-10-29 14:15:22 +0100527
Andy Green251f6fa2010-11-03 11:13:06 +0000528 if (wsi[client]->state != WSI_STATE_ESTABLISHED)
529 continue;
530
531 if (!wsi[client]->callback)
532 continue;
Andy Green69fa0722010-11-03 08:25:13 +0000533
Andy Green251f6fa2010-11-03 11:13:06 +0000534 wsi[client]->callback(wsi[client], LWS_CALLBACK_SEND,
535 &wsi[client]->user_space[0], NULL, 0);
536 }
537
538 continue;
Andy Greenff95d7a2010-10-28 22:36:01 +0100539 }
Andy Green251f6fa2010-11-03 11:13:06 +0000540
541fatal:
Andy Green3faa9c72010-11-08 17:03:03 +0000542 /* listening socket */
Andy Green251f6fa2010-11-03 11:13:06 +0000543 close(fds[0].fd);
544 for (client = 1; client < fds_count; client++)
545 libwebsocket_close_and_free_session(wsi[client]);
Andy Greenff95d7a2010-10-28 22:36:01 +0100546
Andy Green3faa9c72010-11-08 17:03:03 +0000547#ifdef LWS_OPENSSL_SUPPORT
548 SSL_CTX_free(ssl_ctx);
549#endif
Andy Green251f6fa2010-11-03 11:13:06 +0000550 kill(0, SIGTERM);
551
552 return 0;
Andy Greenff95d7a2010-10-28 22:36:01 +0100553}
554
Andy Greenab990e42010-10-31 12:42:52 +0000555/**
556 * libwebsocket_get_uri() - Return the URI path being requested
557 * @wsi: Websocket instance
558 *
559 * The user code can find out the local path being opened from this
560 * call, it's valid on HTTP or established websocket connections.
561 * If the client opened the connection with "http://127.0.0.1/xyz/abc.d"
562 * then this call will return a pointer to "/xyz/abc.d"
563 */
564
Andy Green5fd8a5e2010-10-31 11:57:17 +0000565const char * libwebsocket_get_uri(struct libwebsocket *wsi)
566{
567 if (wsi->utf8_token[WSI_TOKEN_GET_URI].token)
568 return wsi->utf8_token[WSI_TOKEN_GET_URI].token;
569
570 return NULL;
571}
Andy Greenff95d7a2010-10-28 22:36:01 +0100572
573static int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c)
574{
575 int n;
576
577 switch (wsi->parser_state) {
578 case WSI_TOKEN_GET_URI:
579 case WSI_TOKEN_HOST:
580 case WSI_TOKEN_CONNECTION:
581 case WSI_TOKEN_KEY1:
582 case WSI_TOKEN_KEY2:
583 case WSI_TOKEN_PROTOCOL:
584 case WSI_TOKEN_UPGRADE:
585 case WSI_TOKEN_ORIGIN:
586 case WSI_TOKEN_CHALLENGE:
587
Andy Green69fa0722010-11-03 08:25:13 +0000588 debug("WSI_TOKEN_(%d) '%c'\n", wsi->parser_state, c);
Andy Greenff95d7a2010-10-28 22:36:01 +0100589
590 /* collect into malloc'd buffers */
591 /* optional space swallow */
592 if (!wsi->utf8_token[wsi->parser_state].token_len && c == ' ')
593 break;
594
595 /* special case space terminator for get-uri */
596 if (wsi->parser_state == WSI_TOKEN_GET_URI && c == ' ') {
597 wsi->utf8_token[wsi->parser_state].token[
598 wsi->utf8_token[wsi->parser_state].token_len] = '\0';
599 wsi->parser_state = WSI_TOKEN_SKIPPING;
600 break;
601 }
602
603 /* allocate appropriate memory */
Andy Green4ea60062010-10-30 12:15:07 +0100604 if (wsi->utf8_token[wsi->parser_state].token_len ==
605 wsi->current_alloc_len - 1) {
Andy Greenff95d7a2010-10-28 22:36:01 +0100606 /* need to extend */
607 wsi->current_alloc_len += LWS_ADDITIONAL_HDR_ALLOC;
608 if (wsi->current_alloc_len >= LWS_MAX_HEADER_LEN) {
609 /* it's waaay to much payload, fail it */
610 strcpy(wsi->utf8_token[wsi->parser_state].token,
Andy Green4ea60062010-10-30 12:15:07 +0100611 "!!! Length exceeded maximum supported !!!");
Andy Greenff95d7a2010-10-28 22:36:01 +0100612 wsi->parser_state = WSI_TOKEN_SKIPPING;
613 break;
614 }
615 wsi->utf8_token[wsi->parser_state].token =
616 realloc(wsi->utf8_token[wsi->parser_state].token,
617 wsi->current_alloc_len);
618 }
619
620 /* bail at EOL */
621 if (wsi->parser_state != WSI_TOKEN_CHALLENGE && c == '\x0d') {
622 wsi->utf8_token[wsi->parser_state].token[
623 wsi->utf8_token[wsi->parser_state].token_len] = '\0';
624 wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
625 break;
626 }
627
628 wsi->utf8_token[wsi->parser_state].token[
629 wsi->utf8_token[wsi->parser_state].token_len++] = c;
630
631 /* special payload limiting */
Andy Green775c0dd2010-10-29 14:15:22 +0100632 if (wsi->parser_state == WSI_TOKEN_CHALLENGE &&
633 wsi->utf8_token[wsi->parser_state].token_len == 8) {
Andy Green69fa0722010-11-03 08:25:13 +0000634 debug("Setting WSI_PARSING_COMPLETE\n");
Andy Green775c0dd2010-10-29 14:15:22 +0100635 wsi->parser_state = WSI_PARSING_COMPLETE;
636 break;
637 }
Andy Greenff95d7a2010-10-28 22:36:01 +0100638
639 break;
640
641 /* collecting and checking a name part */
642 case WSI_TOKEN_NAME_PART:
Andy Green69fa0722010-11-03 08:25:13 +0000643 debug("WSI_TOKEN_NAME_PART '%c'\n", c);
Andy Greenff95d7a2010-10-28 22:36:01 +0100644
645 if (wsi->name_buffer_pos == sizeof(wsi->name_buffer) - 1) {
646 /* name bigger than we can handle, skip until next */
647 wsi->parser_state = WSI_TOKEN_SKIPPING;
648 break;
649 }
650 wsi->name_buffer[wsi->name_buffer_pos++] = c;
651 wsi->name_buffer[wsi->name_buffer_pos] = '\0';
652
653 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
654 if (wsi->name_buffer_pos != lws_tokens[n].token_len)
655 continue;
656 if (strcmp(lws_tokens[n].token, wsi->name_buffer))
657 continue;
Andy Green69fa0722010-11-03 08:25:13 +0000658 debug("known hdr '%s'\n", wsi->name_buffer);
Andy Greenff95d7a2010-10-28 22:36:01 +0100659 wsi->parser_state = WSI_TOKEN_GET_URI + n;
660 wsi->current_alloc_len = LWS_INITIAL_HDR_ALLOC;
661 wsi->utf8_token[wsi->parser_state].token =
662 malloc(wsi->current_alloc_len);
663 wsi->utf8_token[wsi->parser_state].token_len = 0;
664 n = WSI_TOKEN_COUNT;
665 }
Andy Green5fd8a5e2010-10-31 11:57:17 +0000666
667 /* colon delimiter means we just don't know this name */
668
669 if (wsi->parser_state == WSI_TOKEN_NAME_PART && c == ':') {
Andy Green69fa0722010-11-03 08:25:13 +0000670 debug("skipping unknown header '%s'\n",
671 wsi->name_buffer);
Andy Green5fd8a5e2010-10-31 11:57:17 +0000672 wsi->parser_state = WSI_TOKEN_SKIPPING;
Andy Greenff95d7a2010-10-28 22:36:01 +0100673 break;
Andy Green5fd8a5e2010-10-31 11:57:17 +0000674 }
675
676 /* don't look for payload when it can just be http headers */
677
678 if (wsi->parser_state == WSI_TOKEN_CHALLENGE &&
679 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len) {
680 /* they're HTTP headers, not websocket upgrade! */
Andy Green69fa0722010-11-03 08:25:13 +0000681 debug("Setting WSI_PARSING_COMPLETE "
682 "from http headers\n");
Andy Green5fd8a5e2010-10-31 11:57:17 +0000683 wsi->parser_state = WSI_PARSING_COMPLETE;
684 }
Andy Greenff95d7a2010-10-28 22:36:01 +0100685 break;
686
687 /* skipping arg part of a name we didn't recognize */
688 case WSI_TOKEN_SKIPPING:
Andy Green69fa0722010-11-03 08:25:13 +0000689 debug("WSI_TOKEN_SKIPPING '%c'\n", c);
Andy Greenff95d7a2010-10-28 22:36:01 +0100690 if (c == '\x0d')
691 wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
692 break;
693 case WSI_TOKEN_SKIPPING_SAW_CR:
Andy Green69fa0722010-11-03 08:25:13 +0000694 debug("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
Andy Greenff95d7a2010-10-28 22:36:01 +0100695 if (c == '\x0a')
696 wsi->parser_state = WSI_TOKEN_NAME_PART;
697 else
698 wsi->parser_state = WSI_TOKEN_SKIPPING;
699 wsi->name_buffer_pos = 0;
700 break;
701 /* we're done, ignore anything else */
702 case WSI_PARSING_COMPLETE:
Andy Green69fa0722010-11-03 08:25:13 +0000703 debug("WSI_PARSING_COMPLETE '%c'\n", c);
Andy Greenff95d7a2010-10-28 22:36:01 +0100704 break;
705
706 default: /* keep gcc happy */
707 break;
708 }
709
710 return 0;
711}
712
713static int interpret_key(const char *key, unsigned int *result)
714{
715 char digits[20];
716 int digit_pos = 0;
717 const char *p = key;
718 int spaces = 0;
719
720 while (*p) {
721 if (isdigit(*p)) {
722 if (digit_pos == sizeof(digits) - 1)
723 return -1;
724 digits[digit_pos++] = *p;
725 }
726 p++;
727 }
728 digits[digit_pos] = '\0';
729 if (!digit_pos)
730 return -2;
731
732 while (*key) {
733 if (*key == ' ')
734 spaces++;
735 key++;
736 }
737
738 if (!spaces)
739 return -3;
740
741 *result = atol(digits) / spaces;
742
743 return 0;
744}
745
Andy Green4ea60062010-10-30 12:15:07 +0100746static int libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
747{
748 int n;
749 unsigned char buf[2];
750
751 switch (wsi->lws_rx_parse_state) {
752 case LWS_RXPS_NEW:
753
754 switch (wsi->ietf_spec_revision) {
755 /* Firefox 4.0b6 likes this as of 30 Oct */
756 case 76:
757 if (c == 0xff)
758 wsi->lws_rx_parse_state = LWS_RXPS_SEEN_76_FF;
759 break;
760 case 0:
761 break;
762 }
763 break;
764 case LWS_RXPS_SEEN_76_FF:
Andy Green69fa0722010-11-03 08:25:13 +0000765 if (c)
Andy Green4ea60062010-10-30 12:15:07 +0100766 break;
Andy Green4ea60062010-10-30 12:15:07 +0100767
Andy Green69fa0722010-11-03 08:25:13 +0000768 debug("Seen that client is requesting "
Andy Greene5eafd32010-10-31 13:11:57 +0000769 "a v76 close, sending ack\n");
Andy Green4ea60062010-10-30 12:15:07 +0100770 buf[0] = 0xff;
771 buf[1] = 0;
Andy Green3faa9c72010-11-08 17:03:03 +0000772 n = libwebsocket_write(wsi, buf, 2, LWS_WRITE_HTTP);
Andy Green4ea60062010-10-30 12:15:07 +0100773 if (n < 0) {
774 fprintf(stderr, "ERROR writing to socket");
775 return -1;
776 }
Andy Green69fa0722010-11-03 08:25:13 +0000777 debug(" v76 close ack sent, server closing skt\n");
Andy Green4ea60062010-10-30 12:15:07 +0100778 /* returning < 0 will get it closed in parent */
779 return -1;
780
781 case LWS_RXPS_PULLING_76_LENGTH:
782 break;
783 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
784 break;
785 }
786
787 return 0;
788}
789
790static int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
791 unsigned char *buf, size_t len)
792{
793 int n;
794
795 fprintf(stderr, "received %d byte packet\n", (int)len);
796 for (n = 0; n < len; n++)
797 fprintf(stderr, "%02X ", buf[n]);
798 fprintf(stderr, "\n");
799
800 /* let the rx protocol state machine have as much as it needs */
801
802 n = 0;
803 while (wsi->lws_rx_parse_state !=
804 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED && n < len)
805 if (libwebsocket_rx_sm(wsi, buf[n++]) < 0)
806 return -1;
807
Andy Greene5eafd32010-10-31 13:11:57 +0000808 if (n != len && wsi->callback)
Andy Green251f6fa2010-11-03 11:13:06 +0000809 wsi->callback(wsi, LWS_CALLBACK_RECEIVE, &wsi->user_space[0],
810 &buf[n], len - n);
Andy Green4ea60062010-10-30 12:15:07 +0100811
812 return -0;
813}
814
Andy Greenff95d7a2010-10-28 22:36:01 +0100815
816/*
817 * We have to take care about parsing because the headers may be split
818 * into multiple fragments. They may contain unknown headers with arbitrary
Andy Green775c0dd2010-10-29 14:15:22 +0100819 * argument lengths. So, we parse using a single-character at a time state
820 * machine that is completely independent of packet size.
Andy Greenff95d7a2010-10-28 22:36:01 +0100821 */
822
Andy Greenab990e42010-10-31 12:42:52 +0000823static int
824libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
Andy Greenff95d7a2010-10-28 22:36:01 +0100825{
826 size_t n;
827 char *p;
828 unsigned int key1, key2;
829 unsigned char sum[16];
Andy Green775c0dd2010-10-29 14:15:22 +0100830 char *response;
Andy Greenff95d7a2010-10-28 22:36:01 +0100831
832 switch (wsi->state) {
Andy Green5fd8a5e2010-10-31 11:57:17 +0000833 case WSI_STATE_HTTP:
834 wsi->state = WSI_STATE_HTTP_HEADERS;
Andy Greenff95d7a2010-10-28 22:36:01 +0100835 wsi->parser_state = WSI_TOKEN_NAME_PART;
Andy Green775c0dd2010-10-29 14:15:22 +0100836 /* fallthru */
Andy Green5fd8a5e2010-10-31 11:57:17 +0000837 case WSI_STATE_HTTP_HEADERS:
Andy Greenff95d7a2010-10-28 22:36:01 +0100838
Andy Green69fa0722010-11-03 08:25:13 +0000839 debug("issuing %d bytes to parser\n", (int)len);
840#ifdef DEBUG
841 fwrite(buf, 1, len, stderr);
842#endif
Andy Greenff95d7a2010-10-28 22:36:01 +0100843 for (n = 0; n< len; n++)
844 libwebsocket_parse(wsi, *buf++);
845
846 if (wsi->parser_state != WSI_PARSING_COMPLETE)
847 break;
Andy Green5fd8a5e2010-10-31 11:57:17 +0000848
849 /* is this websocket protocol or normal http 1.0? */
850
851 if (!wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
852 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len) {
853 if (wsi->callback)
Andy Greene5eafd32010-10-31 13:11:57 +0000854 (wsi->callback)(wsi, LWS_CALLBACK_HTTP,
Andy Green251f6fa2010-11-03 11:13:06 +0000855 &wsi->user_space[0],
Andy Greene5eafd32010-10-31 13:11:57 +0000856 NULL, 0);
Andy Green5fd8a5e2010-10-31 11:57:17 +0000857 wsi->state = WSI_STATE_HTTP;
858 return 0;
859 }
860
Andy Green5fd8a5e2010-10-31 11:57:17 +0000861 /* Websocket - confirm we have all the necessary pieces */
Andy Greenff95d7a2010-10-28 22:36:01 +0100862
Andy Green5fd8a5e2010-10-31 11:57:17 +0000863 if (!wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
Andy Greenff95d7a2010-10-28 22:36:01 +0100864 !wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
865 !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
866 !wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
Andy Green5fd8a5e2010-10-31 11:57:17 +0000867 !wsi->utf8_token[WSI_TOKEN_KEY2].token_len)
Andy Greenff95d7a2010-10-28 22:36:01 +0100868 /* completed header processing, but missing some bits */
869 goto bail;
Andy Greenff95d7a2010-10-28 22:36:01 +0100870
871 /* create the response packet */
872
Andy Green4ea60062010-10-30 12:15:07 +0100873 /* make a buffer big enough for everything */
874
Andy Green775c0dd2010-10-29 14:15:22 +0100875 response = malloc(256 +
Andy Greenff95d7a2010-10-28 22:36:01 +0100876 wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
877 wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
878 wsi->utf8_token[WSI_TOKEN_HOST].token_len +
879 wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
880 wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
881 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
Andy Green4ea60062010-10-30 12:15:07 +0100882 if (!response) {
883 fprintf(stderr, "Out of memory for response buffer\n");
884 goto bail;
885 }
Andy Greenff95d7a2010-10-28 22:36:01 +0100886
Andy Green775c0dd2010-10-29 14:15:22 +0100887 p = response;
Andy Green4ea60062010-10-30 12:15:07 +0100888 strcpy(p, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
889 "Upgrade: WebSocket\x0d\x0a");
890 p += strlen("HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0a"
891 "Upgrade: WebSocket\x0d\x0a");
Andy Greene5eafd32010-10-31 13:11:57 +0000892 strcpy(p, "Connection: Upgrade\x0d\x0a"
893 "Sec-WebSocket-Origin: ");
894 p += strlen("Connection: Upgrade\x0d\x0a"
895 "Sec-WebSocket-Origin: ");
Andy Greenff95d7a2010-10-28 22:36:01 +0100896 strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
897 p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
Andy Green3faa9c72010-11-08 17:03:03 +0000898#ifdef LWS_OPENSSL_SUPPORT
899 if (use_ssl) {
900 strcpy(p, "\x0d\x0aSec-WebSocket-Location: wss://");
901 p += strlen("\x0d\x0aSec-WebSocket-Location: wss://");
902 } else {
903#endif
904 strcpy(p, "\x0d\x0aSec-WebSocket-Location: ws://");
905 p += strlen("\x0d\x0aSec-WebSocket-Location: ws://");
906#ifdef LWS_OPENSSL_SUPPORT
907 }
908#endif
Andy Greenff95d7a2010-10-28 22:36:01 +0100909 strcpy(p, wsi->utf8_token[WSI_TOKEN_HOST].token);
910 p += wsi->utf8_token[WSI_TOKEN_HOST].token_len;
911 strcpy(p, wsi->utf8_token[WSI_TOKEN_GET_URI].token);
912 p += wsi->utf8_token[WSI_TOKEN_GET_URI].token_len;
Andy Greenea71ed12010-10-31 07:40:33 +0000913
Andy Greenff95d7a2010-10-28 22:36:01 +0100914 if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
Andy Greenea71ed12010-10-31 07:40:33 +0000915 strcpy(p, "\x0d\x0aSec-WebSocket-Protocol: ");
916 p += strlen("\x0d\x0aSec-WebSocket-Protocol: ");
Andy Greenff95d7a2010-10-28 22:36:01 +0100917 strcpy(p, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
918 p += wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len;
919 }
Andy Greenea71ed12010-10-31 07:40:33 +0000920
Andy Greenff95d7a2010-10-28 22:36:01 +0100921 strcpy(p, "\x0d\x0a\x0d\x0a");
922 p += strlen("\x0d\x0a\x0d\x0a");
923
Andy Green775c0dd2010-10-29 14:15:22 +0100924 /* convert the two keys into 32-bit integers */
925
Andy Greenff95d7a2010-10-28 22:36:01 +0100926 if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
927 goto bail;
Andy Greenff95d7a2010-10-28 22:36:01 +0100928 if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
929 goto bail;
Andy Green775c0dd2010-10-29 14:15:22 +0100930
931 /* lay them out in network byte order (MSB first */
Andy Greenff95d7a2010-10-28 22:36:01 +0100932
933 sum[0] = key1 >> 24;
934 sum[1] = key1 >> 16;
935 sum[2] = key1 >> 8;
936 sum[3] = key1;
937 sum[4] = key2 >> 24;
938 sum[5] = key2 >> 16;
939 sum[6] = key2 >> 8;
940 sum[7] = key2;
Andy Green775c0dd2010-10-29 14:15:22 +0100941
942 /* follow them with the challenge token we were sent */
943
Andy Greenff95d7a2010-10-28 22:36:01 +0100944 memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
945
Andy Green775c0dd2010-10-29 14:15:22 +0100946 /*
947 * compute the md5sum of that 16-byte series and use as our
948 * payload after our headers
949 */
950
Andy Greenff95d7a2010-10-28 22:36:01 +0100951 md5(sum, 16, (unsigned char *)p);
952 p += 16;
953
Andy Green4ea60062010-10-30 12:15:07 +0100954 /* it's complete: go ahead and send it */
Andy Greenff95d7a2010-10-28 22:36:01 +0100955
Andy Green69fa0722010-11-03 08:25:13 +0000956 debug("issuing response packet %d len\n",
957 (int)(p - response));
958#ifdef DEBUG
959 fwrite(response, 1, p - response, stderr);
960#endif
Andy Green3faa9c72010-11-08 17:03:03 +0000961 n = libwebsocket_write(wsi, (unsigned char *)response, p - response,
962 LWS_WRITE_HTTP);
Andy Green775c0dd2010-10-29 14:15:22 +0100963 if (n < 0) {
964 fprintf(stderr, "ERROR writing to socket");
965 goto bail;
966 }
Andy Green4ea60062010-10-30 12:15:07 +0100967
968 /* alright clean up and set ourselves into established state */
Andy Green775c0dd2010-10-29 14:15:22 +0100969
970 free(response);
971 wsi->state = WSI_STATE_ESTABLISHED;
Andy Green4ea60062010-10-30 12:15:07 +0100972 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
Andy Green775c0dd2010-10-29 14:15:22 +0100973
974 /* notify user code that we're ready to roll */
975
976 if (wsi->callback)
Andy Green251f6fa2010-11-03 11:13:06 +0000977 wsi->callback(wsi, LWS_CALLBACK_ESTABLISHED,
978 &wsi->user_space[0], NULL, 0);
Andy Greenff95d7a2010-10-28 22:36:01 +0100979 break;
980
981 case WSI_STATE_ESTABLISHED:
Andy Green4ea60062010-10-30 12:15:07 +0100982 if (libwebsocket_interpret_incoming_packet(wsi, buf, len) < 0)
983 goto bail;
Andy Greenff95d7a2010-10-28 22:36:01 +0100984 break;
985 default:
986 break;
987 }
988
989 return 0;
990
991bail:
Andy Green251f6fa2010-11-03 11:13:06 +0000992 libwebsocket_close_and_free_session(wsi);
Andy Greenff95d7a2010-10-28 22:36:01 +0100993 return -1;
994}
995
Andy Greenab990e42010-10-31 12:42:52 +0000996/**
997 * libwebsocket_write() - Apply protocol then write data to client
998 * @wsi: Websocket instance (available from user callback)
999 * @buf: The data to send. For data being sent on a websocket
1000 * connection (ie, not default http), this buffer MUST have
1001 * LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE the pointer
1002 * and an additional LWS_SEND_BUFFER_POST_PADDING bytes valid
1003 * in the buffer after (buf + len). This is so the protocol
1004 * header and trailer data can be added in-situ.
1005 * @len: Count of the data bytes in the payload starting from buf
1006 * @protocol: Use LWS_WRITE_HTTP to reply to an http connection, and one
1007 * of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate
1008 * data on a websockets connection. Remember to allow the extra
1009 * bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT
1010 * are used.
1011 *
1012 * This function provides the way to issue data back to the client
1013 * for both http and websocket protocols.
Andy Green4ea60062010-10-30 12:15:07 +01001014 *
Andy Greenab990e42010-10-31 12:42:52 +00001015 * In the case of sending using websocket protocol, be sure to allocate
1016 * valid storage before and after buf as explained above. This scheme
1017 * allows maximum efficiency of sending data and protocol in a single
1018 * packet while not burdening the user code with any protocol knowledge.
Andy Green4ea60062010-10-30 12:15:07 +01001019 */
1020
1021int libwebsocket_write(struct libwebsocket * wsi, unsigned char *buf,
Andy Green5fd8a5e2010-10-31 11:57:17 +00001022 size_t len, enum libwebsocket_write_protocol protocol)
Andy Green775c0dd2010-10-29 14:15:22 +01001023{
1024 int n;
Andy Green4ea60062010-10-30 12:15:07 +01001025 int pre = 0;
1026 int post = 0;
1027 unsigned int shift = 7;
Andy Green775c0dd2010-10-29 14:15:22 +01001028
Andy Green5fd8a5e2010-10-31 11:57:17 +00001029 if (protocol == LWS_WRITE_HTTP)
1030 goto send_raw;
1031
1032 /* websocket protocol, either binary or text */
1033
Andy Green775c0dd2010-10-29 14:15:22 +01001034 if (wsi->state != WSI_STATE_ESTABLISHED)
1035 return -1;
Andy Greenff95d7a2010-10-28 22:36:01 +01001036
Andy Green775c0dd2010-10-29 14:15:22 +01001037 switch (wsi->ietf_spec_revision) {
Andy Green69fa0722010-11-03 08:25:13 +00001038 /* chrome likes this as of 30 Oct */
Andy Green4ea60062010-10-30 12:15:07 +01001039 /* Firefox 4.0b6 likes this as of 30 Oct */
1040 case 76:
Andy Green5fd8a5e2010-10-31 11:57:17 +00001041 if (protocol == LWS_WRITE_BINARY) {
Andy Green4ea60062010-10-30 12:15:07 +01001042 /* in binary mode we send 7-bit used length blocks */
1043 pre = 1;
1044 while (len & (127 << shift)) {
1045 pre++;
1046 shift += 7;
1047 }
1048 n = 0;
1049 shift -= 7;
1050 while (shift >= 0) {
1051 if (shift)
1052 buf[0 - pre + n] =
1053 ((len >> shift) & 127) | 0x80;
1054 else
1055 buf[0 - pre + n] =
1056 ((len >> shift) & 127);
1057 n++;
1058 shift -= 7;
1059 }
1060 break;
Andy Green775c0dd2010-10-29 14:15:22 +01001061 }
Andy Green4ea60062010-10-30 12:15:07 +01001062
1063 /* frame type = text, length-free spam mode */
1064
1065 buf[-1] = 0;
1066 buf[len] = 0xff; /* EOT marker */
1067 pre = 1;
1068 post = 1;
Andy Green775c0dd2010-10-29 14:15:22 +01001069 break;
Andy Green4ea60062010-10-30 12:15:07 +01001070
Andy Green4ea60062010-10-30 12:15:07 +01001071 case 0:
1072 buf[-9] = 0xff;
1073#if defined __LP64__
1074 buf[-8] = len >> 56;
1075 buf[-7] = len >> 48;
1076 buf[-6] = len >> 40;
1077 buf[-5] = len >> 32;
1078#else
1079 buf[-8] = 0;
1080 buf[-7] = 0;
1081 buf[-6] = 0;
1082 buf[-5] = 0;
1083#endif
1084 buf[-4] = len >> 24;
1085 buf[-3] = len >> 16;
1086 buf[-2] = len >> 8;
1087 buf[-1] = len;
1088 pre = 9;
1089 break;
1090
Andy Green775c0dd2010-10-29 14:15:22 +01001091 /* just an unimplemented spec right now apparently */
1092 case 2:
Andy Green4ea60062010-10-30 12:15:07 +01001093 n = 4; /* text */
Andy Green5fd8a5e2010-10-31 11:57:17 +00001094 if (protocol == LWS_WRITE_BINARY)
Andy Green4ea60062010-10-30 12:15:07 +01001095 n = 5; /* binary */
Andy Green775c0dd2010-10-29 14:15:22 +01001096 if (len < 126) {
Andy Green4ea60062010-10-30 12:15:07 +01001097 buf[-2] = n;
1098 buf[-1] = len;
1099 pre = 2;
Andy Green775c0dd2010-10-29 14:15:22 +01001100 } else {
1101 if (len < 65536) {
Andy Green4ea60062010-10-30 12:15:07 +01001102 buf[-4] = n;
1103 buf[-3] = 126;
1104 buf[-2] = len >> 8;
1105 buf[-1] = len;
1106 pre = 4;
Andy Green775c0dd2010-10-29 14:15:22 +01001107 } else {
Andy Green4ea60062010-10-30 12:15:07 +01001108 buf[-10] = n;
1109 buf[-9] = 127;
1110#if defined __LP64__
1111 buf[-8] = (len >> 56) & 0x7f;
1112 buf[-7] = len >> 48;
1113 buf[-6] = len >> 40;
1114 buf[-5] = len >> 32;
1115#else
1116 buf[-8] = 0;
1117 buf[-7] = 0;
1118 buf[-6] = 0;
1119 buf[-5] = 0;
1120#endif
1121 buf[-4] = len >> 24;
1122 buf[-3] = len >> 16;
1123 buf[-2] = len >> 8;
1124 buf[-1] = len;
1125 pre = 10;
Andy Green775c0dd2010-10-29 14:15:22 +01001126 }
1127 }
Andy Green775c0dd2010-10-29 14:15:22 +01001128 break;
1129 }
Andy Green251f6fa2010-11-03 11:13:06 +00001130
1131#if 0
1132 for (n = 0; n < (len + pre + post); n++)
1133 fprintf(stderr, "%02X ", buf[n - pre]);
1134
1135 fprintf(stderr, "\n");
1136#endif
Andy Green775c0dd2010-10-29 14:15:22 +01001137
Andy Green5fd8a5e2010-10-31 11:57:17 +00001138send_raw:
Andy Green3faa9c72010-11-08 17:03:03 +00001139#ifdef LWS_OPENSSL_SUPPORT
1140 if (use_ssl) {
1141 n = SSL_write(wsi->ssl, buf - pre, len + pre + post);
1142 if (n < 0) {
1143 fprintf(stderr, "ERROR writing to socket");
1144 return -1;
1145 }
1146 } else {
1147#endif
1148 n = send(wsi->sock, buf - pre, len + pre + post, 0);
1149 if (n < 0) {
1150 fprintf(stderr, "ERROR writing to socket");
1151 return -1;
1152 }
1153#ifdef LWS_OPENSSL_SUPPORT
Andy Green775c0dd2010-10-29 14:15:22 +01001154 }
Andy Green3faa9c72010-11-08 17:03:03 +00001155#endif
Andy Green5fd8a5e2010-10-31 11:57:17 +00001156// fprintf(stderr, "written %d bytes to client\n", (int)len);
Andy Green775c0dd2010-10-29 14:15:22 +01001157
1158 return 0;
1159}
1160
Andy Greenff95d7a2010-10-28 22:36:01 +01001161
Andy Greenab990e42010-10-31 12:42:52 +00001162/**
1163 * libwebsockets_serve_http_file() - Send a file back to the client using http
1164 * @wsi: Websocket instance (available from user callback)
1165 * @file: The file to issue over http
1166 * @content_type: The http content type, eg, text/html
1167 *
1168 * This function is intended to be called from the callback in response
1169 * to http requests from the client. It allows the callback to issue
1170 * local files down the http link in a single step.
1171 */
1172
Andy Green5fd8a5e2010-10-31 11:57:17 +00001173int libwebsockets_serve_http_file(struct libwebsocket *wsi, const char * file,
1174 const char * content_type)
1175{
1176 int fd;
1177 struct stat stat;
1178 char buf[512];
1179 char *p = buf;
1180 int n;
1181
1182 fd = open(file, O_RDONLY);
1183 if (fd < 1) {
1184 p += sprintf(p, "HTTP/1.0 400 Bad\x0d\x0a"
1185 "Server: libwebsockets\x0d\x0a"
1186 "\x0d\x0a"
1187 );
Andy Greene5eafd32010-10-31 13:11:57 +00001188 libwebsocket_write(wsi, (unsigned char *)buf, p - buf,
1189 LWS_WRITE_HTTP);
Andy Green5fd8a5e2010-10-31 11:57:17 +00001190
1191 return -1;
1192 }
1193
1194 fstat(fd, &stat);
1195 p += sprintf(p, "HTTP/1.0 200 OK\x0d\x0a"
1196 "Server: libwebsockets\x0d\x0a"
1197 "Content-Type: %s\x0d\x0a"
1198 "Content-Length: %u\x0d\x0a"
Andy Greene5eafd32010-10-31 13:11:57 +00001199 "\x0d\x0a", content_type, (unsigned int)stat.st_size);
Andy Green5fd8a5e2010-10-31 11:57:17 +00001200
1201 libwebsocket_write(wsi, (unsigned char *)buf, p - buf, LWS_WRITE_HTTP);
1202
1203 n = 1;
1204 while (n > 0) {
1205 n = read(fd, buf, 512);
Andy Greene5eafd32010-10-31 13:11:57 +00001206 libwebsocket_write(wsi, (unsigned char *)buf, n,
1207 LWS_WRITE_HTTP);
Andy Green5fd8a5e2010-10-31 11:57:17 +00001208 }
1209
1210 close(fd);
1211
1212 return 0;
1213}