blob: 9e7c1d8999355dc2d8ac4ee8724a54b62d2fa7c5 [file] [log] [blame]
Andy Greenff95d7a2010-10-28 22:36:01 +01001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <ctype.h>
5#include <unistd.h>
6
7#include <sys/types.h>
8#include <sys/socket.h>
9#include <netinet/in.h>
10
11#include <poll.h>
12#include <sys/mman.h>
13
14#include "libwebsockets.h"
15
16void md5(const unsigned char *input, int ilen, unsigned char output[16]);
17
18void dostuff(struct libwebsocket *wsi, int sock);
19
20const struct lws_tokens lws_tokens[WSI_TOKEN_COUNT] = {
21 { "GET ", 4 },
22 { "Host:", 5 },
23 { "Connection:", 11 },
24 { "Sec-WebSocket-Key1:", 19 },
25 { "Sec-WebSocket-Key2:", 19 },
26 { "Sec-WebSocket-Protocol:", 23 },
27 { "Upgrade:", 8 },
28 { "Origin:", 7 },
29 { "\x0d\x0a", 2 },
30};
31
32int libwebsocket_init(struct libwebsocket *wsi, int port)
33{
34 int n;
35 int sockfd, newsockfd;
36 unsigned int clilen;
37 struct sockaddr_in serv_addr, cli_addr;
38 int pid;
39
40 wsi->state = WSI_STATE_CLOSED;
41 wsi->name_buffer_pos = 0;
42 wsi->response = NULL;
43
44 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
45 wsi->utf8_token[n].token = NULL;
46 wsi->utf8_token[n].token_len = 0;
47 }
48
49 /* fork off a master server for this websocket server */
50
51 n = fork();
52 if (n < 0) {
53 fprintf(stderr, "Failed on forking server thread: %d\n", n);
54 exit(1);
55 }
56
57 /* we are done as far as the caller is concerned */
58
59 if (n)
60 return 0;
61
62 /* sit there listening for connects, accept and spawn session servers */
63
64 sockfd = socket(AF_INET, SOCK_STREAM, 0);
65 if (sockfd < 0)
66 fprintf(stderr, "ERROR opening socket");
67 bzero((char *) &serv_addr, sizeof(serv_addr));
68
69 serv_addr.sin_family = AF_INET;
70 serv_addr.sin_addr.s_addr = INADDR_ANY;
71 serv_addr.sin_port = htons(port);
72 if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
73 fprintf(stderr, "ERROR on binding");
74
75 listen(sockfd, 5);
76
77 while (1) {
78 clilen = sizeof(cli_addr);
79
80 newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
81 if (newsockfd < 0)
82 fprintf(stderr, "ERROR on accept");
83
84 /* fork off a new server instance */
85
86 pid = fork();
87 if (pid < 0)
88 fprintf(stderr, "ERROR on fork");
89 if (!pid) {
90 close(sockfd);
91
92 /* sit in dostuff() until session socket closed */
93
94 dostuff(wsi, newsockfd);
95 exit(0);
96 } else
97 close(newsockfd);
98 }
99}
100
101void libwebsocket_close(struct libwebsocket *wsi)
102{
103 int n;
104
105 wsi->state = WSI_STATE_DEAD_SOCKET;
106
107 if (wsi->websocket_closed_callback)
108 wsi->websocket_closed_callback(wsi);
109
110 for (n = 0; n < WSI_TOKEN_COUNT; n++)
111 if (wsi->utf8_token[n].token)
112 free(wsi->utf8_token[n].token);
113
114 if (wsi->response)
115 free(wsi->response);
116}
117
118
119static int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c)
120{
121 int n;
122
123 switch (wsi->parser_state) {
124 case WSI_TOKEN_GET_URI:
125 case WSI_TOKEN_HOST:
126 case WSI_TOKEN_CONNECTION:
127 case WSI_TOKEN_KEY1:
128 case WSI_TOKEN_KEY2:
129 case WSI_TOKEN_PROTOCOL:
130 case WSI_TOKEN_UPGRADE:
131 case WSI_TOKEN_ORIGIN:
132 case WSI_TOKEN_CHALLENGE:
133
134// fprintf(stderr, "WSI_TOKEN_(body %d) '%c'\n", wsi->parser_state, c);
135
136 /* collect into malloc'd buffers */
137 /* optional space swallow */
138 if (!wsi->utf8_token[wsi->parser_state].token_len && c == ' ')
139 break;
140
141 /* special case space terminator for get-uri */
142 if (wsi->parser_state == WSI_TOKEN_GET_URI && c == ' ') {
143 wsi->utf8_token[wsi->parser_state].token[
144 wsi->utf8_token[wsi->parser_state].token_len] = '\0';
145 wsi->parser_state = WSI_TOKEN_SKIPPING;
146 break;
147 }
148
149 /* allocate appropriate memory */
150 if (wsi->utf8_token[wsi->parser_state].token_len == wsi->current_alloc_len - 1) {
151 /* need to extend */
152 wsi->current_alloc_len += LWS_ADDITIONAL_HDR_ALLOC;
153 if (wsi->current_alloc_len >= LWS_MAX_HEADER_LEN) {
154 /* it's waaay to much payload, fail it */
155 strcpy(wsi->utf8_token[wsi->parser_state].token,
156 "!!! Length exceeded maximum supported !!!");
157 wsi->parser_state = WSI_TOKEN_SKIPPING;
158 break;
159 }
160 wsi->utf8_token[wsi->parser_state].token =
161 realloc(wsi->utf8_token[wsi->parser_state].token,
162 wsi->current_alloc_len);
163 }
164
165 /* bail at EOL */
166 if (wsi->parser_state != WSI_TOKEN_CHALLENGE && c == '\x0d') {
167 wsi->utf8_token[wsi->parser_state].token[
168 wsi->utf8_token[wsi->parser_state].token_len] = '\0';
169 wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
170 break;
171 }
172
173 wsi->utf8_token[wsi->parser_state].token[
174 wsi->utf8_token[wsi->parser_state].token_len++] = c;
175
176 /* special payload limiting */
177 if (wsi->parser_state == WSI_TOKEN_CHALLENGE)
178 if (wsi->utf8_token[wsi->parser_state].token_len == 8) {
179// fprintf(stderr, "Setting WSI_PARSING_COMPLETE\n");
180 wsi->parser_state = WSI_PARSING_COMPLETE;
181 break;
182 }
183
184 break;
185
186 /* collecting and checking a name part */
187 case WSI_TOKEN_NAME_PART:
188// fprintf(stderr, "WSI_TOKEN_NAME_PART '%c'\n", c);
189
190 if (wsi->name_buffer_pos == sizeof(wsi->name_buffer) - 1) {
191 /* name bigger than we can handle, skip until next */
192 wsi->parser_state = WSI_TOKEN_SKIPPING;
193 break;
194 }
195 wsi->name_buffer[wsi->name_buffer_pos++] = c;
196 wsi->name_buffer[wsi->name_buffer_pos] = '\0';
197
198 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
199 if (wsi->name_buffer_pos != lws_tokens[n].token_len)
200 continue;
201 if (strcmp(lws_tokens[n].token, wsi->name_buffer))
202 continue;
203 wsi->parser_state = WSI_TOKEN_GET_URI + n;
204 wsi->current_alloc_len = LWS_INITIAL_HDR_ALLOC;
205 wsi->utf8_token[wsi->parser_state].token =
206 malloc(wsi->current_alloc_len);
207 wsi->utf8_token[wsi->parser_state].token_len = 0;
208 n = WSI_TOKEN_COUNT;
209 }
210 if (wsi->parser_state != WSI_TOKEN_NAME_PART)
211 break;
212 break;
213
214 /* skipping arg part of a name we didn't recognize */
215 case WSI_TOKEN_SKIPPING:
216// fprintf(stderr, "WSI_TOKEN_SKIPPING '%c'\n", c);
217 if (c == '\x0d')
218 wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
219 break;
220 case WSI_TOKEN_SKIPPING_SAW_CR:
221// fprintf(stderr, "WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
222 if (c == '\x0a')
223 wsi->parser_state = WSI_TOKEN_NAME_PART;
224 else
225 wsi->parser_state = WSI_TOKEN_SKIPPING;
226 wsi->name_buffer_pos = 0;
227 break;
228 /* we're done, ignore anything else */
229 case WSI_PARSING_COMPLETE:
230// fprintf(stderr, "WSI_PARSING_COMPLETE '%c'\n", c);
231 break;
232
233 default: /* keep gcc happy */
234 break;
235 }
236
237 return 0;
238}
239
240static int interpret_key(const char *key, unsigned int *result)
241{
242 char digits[20];
243 int digit_pos = 0;
244 const char *p = key;
245 int spaces = 0;
246
247 while (*p) {
248 if (isdigit(*p)) {
249 if (digit_pos == sizeof(digits) - 1)
250 return -1;
251 digits[digit_pos++] = *p;
252 }
253 p++;
254 }
255 digits[digit_pos] = '\0';
256 if (!digit_pos)
257 return -2;
258
259 while (*key) {
260 if (*key == ' ')
261 spaces++;
262 key++;
263 }
264
265 if (!spaces)
266 return -3;
267
268 *result = atol(digits) / spaces;
269
270 return 0;
271}
272
273
274/*
275 * We have to take care about parsing because the headers may be split
276 * into multiple fragments. They may contain unknown headers with arbitrary
277 * argument lengths.
278 */
279
280int libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
281{
282 size_t n;
283 char *p;
284 unsigned int key1, key2;
285 unsigned char sum[16];
286
287 switch (wsi->state) {
288 case WSI_STATE_CLOSED:
289 wsi->state = WSI_STATE_HANDSHAKE_RX;
290 wsi->parser_state = WSI_TOKEN_NAME_PART;
291 case WSI_STATE_HANDSHAKE_RX:
292
293 fprintf(stderr, "issuing %ld bytes to parser\n", len);
294
295
296 fwrite(buf, 1, len, stderr);
297 for (n = 0; n< len; n++)
298 libwebsocket_parse(wsi, *buf++);
299
300 if (wsi->parser_state != WSI_PARSING_COMPLETE)
301 break;
302
303 fprintf(stderr, "Preparing return packet\n");
304
305
306 /* Confirm we have all the necessary pieces */
307
308 if (
309 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
310 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
311 !wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
312 !wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
313 !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
314 !wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
315 !wsi->utf8_token[WSI_TOKEN_KEY2].token_len) {
316
317 /* completed header processing, but missing some bits */
318 goto bail;
319 }
320
321 /* create the response packet */
322
323 wsi->response = malloc(256 +
324 wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
325 wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
326 wsi->utf8_token[WSI_TOKEN_HOST].token_len +
327 wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
328 wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
329 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
330
331
332 fprintf(stderr, "'%s;\n", wsi->utf8_token[WSI_TOKEN_HOST].token);
333
334 p = wsi->response;
335 strcpy(p, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0aUpgrade: WebSocket\x0d\x0a");
336 p += strlen("HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0aUpgrade: WebSocket\x0d\x0a");
337 strcpy(p, "Connection: Upgrade\x0d\x0aSec-WebSocket-Origin: ");
338 p += strlen("Connection: Upgrade\x0d\x0aSec-WebSocket-Origin: ");
339 strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
340 p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
341 strcpy(p, "\x0d\x0aSec-WebSocket-Location: ws://");
342 p += strlen("\x0d\x0aSec-WebSocket-Location: ws://");
343 strcpy(p, wsi->utf8_token[WSI_TOKEN_HOST].token);
344 p += wsi->utf8_token[WSI_TOKEN_HOST].token_len;
345 strcpy(p, wsi->utf8_token[WSI_TOKEN_GET_URI].token);
346 p += wsi->utf8_token[WSI_TOKEN_GET_URI].token_len;
347 strcpy(p, "\x0d\x0aSec-WebSocket-Protocol: ");
348 p += strlen("\x0d\x0aSec-WebSocket-Protocol: ");
349 if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
350 strcpy(p, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
351 p += wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len;
352 }
353 strcpy(p, "\x0d\x0a\x0d\x0a");
354 p += strlen("\x0d\x0a\x0d\x0a");
355
356 if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
357 goto bail;
358
359 if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
360 goto bail;
361
362 sum[0] = key1 >> 24;
363 sum[1] = key1 >> 16;
364 sum[2] = key1 >> 8;
365 sum[3] = key1;
366 sum[4] = key2 >> 24;
367 sum[5] = key2 >> 16;
368 sum[6] = key2 >> 8;
369 sum[7] = key2;
370 memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
371
372 md5(sum, 16, (unsigned char *)p);
373 p += 16;
374
375 wsi->response_length = p - wsi->response;
376
377 wsi->state = WSI_STATE_ISSUE_HANDSHAKE;
378
379 if (wsi->websocket_established_callback)
380 wsi->websocket_established_callback(wsi);
381 break;
382
383 case WSI_STATE_ESTABLISHED:
384 break;
385 default:
386 break;
387 }
388
389 return 0;
390
391bail:
392 libwebsocket_close(wsi);
393 return -1;
394}
395
396
397void dostuff(struct libwebsocket *wsi, int sock)
398{
399 int n;
400 unsigned char buf[256];
401 struct pollfd fds;
402
403 wsi->sock = sock;
404
405 fds.fd = sock;
406 fds.events = POLLIN | POLLOUT;
407
408 while (1) {
409
410 n = poll(&fds, 1, 10);
411 if (n < 0) {
412 fprintf(stderr, "Socket dead (poll = %d)\n", n);
413 return;
414 }
415
416 if (fds.revents & (POLLERR | POLLHUP)) {
417 fprintf(stderr, "Socket dead\n");
418 return;
419 }
420
421 if (wsi->state == WSI_STATE_DEAD_SOCKET)
422 return;
423
424
425 if (fds.revents & POLLIN) {
426
427// fprintf(stderr, "POLLIN\n");
428
429 n = read(sock, buf, sizeof(buf));
430 if (n < 0) {
431 fprintf(stderr, "Socket read returned %d\n", n);
432 continue;
433 }
434 if (n)
435 libwebsocket_read(wsi, buf, n);
436 }
437
438 if (wsi->state == WSI_STATE_ISSUE_HANDSHAKE) {
439
440 fprintf(stderr, "issuing response packet %d len\n", wsi->response_length);
441
442 fwrite(wsi->response, 1, wsi->response_length, stderr);
443
444 n = write(sock, wsi->response, wsi->response_length);
445 if (n < 0) {
446 fprintf(stderr, "ERROR writing to socket");
447 exit(1);
448 }
449 wsi->state = WSI_STATE_ESTABLISHED;
450 continue;
451 }
452
453 if (wsi->websocket_send_callback)
454 wsi->websocket_send_callback(wsi);
455 }
456}
457