blob: 6f2e03b3364a05fe1d8529fc05835890accdd2e0 [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>
Andy Green775c0dd2010-10-29 14:15:22 +01006#include <errno.h>
Andy Greenff95d7a2010-10-28 22:36:01 +01007
8#include <sys/types.h>
9#include <sys/socket.h>
10#include <netinet/in.h>
11
12#include <poll.h>
13#include <sys/mman.h>
14
15#include "libwebsockets.h"
16
17void md5(const unsigned char *input, int ilen, unsigned char output[16]);
Andy Green775c0dd2010-10-29 14:15:22 +010018static void libwebsocket_service(struct libwebsocket *wsi, int sock);
Andy Greenff95d7a2010-10-28 22:36:01 +010019
Andy Green775c0dd2010-10-29 14:15:22 +010020#define LWS_MAX_HEADER_NAME_LENGTH 64
21#define LWS_MAX_HEADER_LEN 4096
22#define LWS_INITIAL_HDR_ALLOC 256
23#define LWS_ADDITIONAL_HDR_ALLOC 64
24
25
26enum lws_connection_states {
27 WSI_STATE_CLOSED,
28 WSI_STATE_HANDSHAKE_RX,
29 WSI_STATE_DEAD_SOCKET,
30 WSI_STATE_ESTABLISHED
31};
32
33enum lws_token_indexes {
34 WSI_TOKEN_GET_URI,
35 WSI_TOKEN_HOST,
36 WSI_TOKEN_CONNECTION,
37 WSI_TOKEN_KEY1,
38 WSI_TOKEN_KEY2,
39 WSI_TOKEN_PROTOCOL,
40 WSI_TOKEN_UPGRADE,
41 WSI_TOKEN_ORIGIN,
42 WSI_TOKEN_CHALLENGE,
43
44 /* always last real token index*/
45 WSI_TOKEN_COUNT,
46 /* parser state additions */
47 WSI_TOKEN_NAME_PART,
48 WSI_TOKEN_SKIPPING,
49 WSI_TOKEN_SKIPPING_SAW_CR,
50 WSI_PARSING_COMPLETE
51};
52
53
54struct lws_tokens {
55 char * token;
56 int token_len;
57};
58
59
60/*
61 * This is totally opaque to code using the library. It's exported as a
62 * forward-reference pointer-only declaration.
63 */
64
65struct libwebsocket {
66 int (*callback)(struct libwebsocket *,
67 enum libwebsocket_callback_reasons reason);
68
69 enum lws_connection_states state;
70
71 char name_buffer[LWS_MAX_HEADER_NAME_LENGTH];
72 int name_buffer_pos;
73 int current_alloc_len;
74 enum lws_token_indexes parser_state;
75 struct lws_tokens utf8_token[WSI_TOKEN_COUNT];
76 int ietf_spec_revision;
77
78 int sock;
79};
80
Andy Greenff95d7a2010-10-28 22:36:01 +010081
82const struct lws_tokens lws_tokens[WSI_TOKEN_COUNT] = {
83 { "GET ", 4 },
84 { "Host:", 5 },
85 { "Connection:", 11 },
86 { "Sec-WebSocket-Key1:", 19 },
87 { "Sec-WebSocket-Key2:", 19 },
88 { "Sec-WebSocket-Protocol:", 23 },
89 { "Upgrade:", 8 },
90 { "Origin:", 7 },
91 { "\x0d\x0a", 2 },
92};
93
Andy Green775c0dd2010-10-29 14:15:22 +010094int libwebsocket_create_server(int port, int (*callback)(struct libwebsocket *, enum libwebsocket_callback_reasons))
Andy Greenff95d7a2010-10-28 22:36:01 +010095{
96 int n;
97 int sockfd, newsockfd;
98 unsigned int clilen;
99 struct sockaddr_in serv_addr, cli_addr;
100 int pid;
Andy Green775c0dd2010-10-29 14:15:22 +0100101 struct libwebsocket *wsi = malloc(sizeof(struct libwebsocket));
102
103 if (!wsi)
104 return -1;
Andy Greenff95d7a2010-10-28 22:36:01 +0100105
106 wsi->state = WSI_STATE_CLOSED;
107 wsi->name_buffer_pos = 0;
Andy Greenff95d7a2010-10-28 22:36:01 +0100108
109 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
110 wsi->utf8_token[n].token = NULL;
111 wsi->utf8_token[n].token_len = 0;
112 }
Andy Green775c0dd2010-10-29 14:15:22 +0100113
114 wsi->callback = callback;
115 wsi->ietf_spec_revision = 0;
Andy Greenff95d7a2010-10-28 22:36:01 +0100116
Andy Green775c0dd2010-10-29 14:15:22 +0100117 /* sit there listening for connects, accept and spawn session servers */
118
119 sockfd = socket(AF_INET, SOCK_STREAM, 0);
120 if (sockfd < 0) {
121 fprintf(stderr, "ERROR opening socket");
122 }
123 bzero((char *) &serv_addr, sizeof(serv_addr));
124
125 serv_addr.sin_family = AF_INET;
126 serv_addr.sin_addr.s_addr = INADDR_ANY;
127 serv_addr.sin_port = htons(port);
128 n = bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
129 if (n < 0) {
130 fprintf(stderr, "ERROR on binding %d %d\n", n, errno);
131 return -1;
132 }
133
134 /* fork off a master server for this websocket server */
Andy Greenff95d7a2010-10-28 22:36:01 +0100135
136 n = fork();
137 if (n < 0) {
138 fprintf(stderr, "Failed on forking server thread: %d\n", n);
139 exit(1);
140 }
141
142 /* we are done as far as the caller is concerned */
143
144 if (n)
145 return 0;
146
Andy Greenff95d7a2010-10-28 22:36:01 +0100147
148 listen(sockfd, 5);
149
150 while (1) {
151 clilen = sizeof(cli_addr);
152
153 newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
Andy Green775c0dd2010-10-29 14:15:22 +0100154 if (newsockfd < 0) {
Andy Greenff95d7a2010-10-28 22:36:01 +0100155 fprintf(stderr, "ERROR on accept");
Andy Green775c0dd2010-10-29 14:15:22 +0100156 continue;
157 }
Andy Greenff95d7a2010-10-28 22:36:01 +0100158
159 /* fork off a new server instance */
160
161 pid = fork();
Andy Green775c0dd2010-10-29 14:15:22 +0100162 if (pid < 0) {
Andy Greenff95d7a2010-10-28 22:36:01 +0100163 fprintf(stderr, "ERROR on fork");
Andy Green775c0dd2010-10-29 14:15:22 +0100164 continue;
165 }
166
167 if (pid) {
Andy Greenff95d7a2010-10-28 22:36:01 +0100168 close(newsockfd);
Andy Green775c0dd2010-10-29 14:15:22 +0100169 continue;
170 }
171
172 /* we are the session process */
173
174 close(sockfd);
175
176 /* sit in libwebsocket_service() until session socket closed */
177
178 libwebsocket_service(wsi, newsockfd);
179 exit(0);
Andy Greenff95d7a2010-10-28 22:36:01 +0100180 }
181}
182
183void libwebsocket_close(struct libwebsocket *wsi)
184{
185 int n;
186
187 wsi->state = WSI_STATE_DEAD_SOCKET;
188
Andy Green775c0dd2010-10-29 14:15:22 +0100189 if (wsi->callback)
190 wsi->callback(wsi, LWS_CALLBACK_CLOSED);
Andy Greenff95d7a2010-10-28 22:36:01 +0100191
192 for (n = 0; n < WSI_TOKEN_COUNT; n++)
193 if (wsi->utf8_token[n].token)
194 free(wsi->utf8_token[n].token);
Andy Greenff95d7a2010-10-28 22:36:01 +0100195}
196
197
198static int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c)
199{
200 int n;
201
202 switch (wsi->parser_state) {
203 case WSI_TOKEN_GET_URI:
204 case WSI_TOKEN_HOST:
205 case WSI_TOKEN_CONNECTION:
206 case WSI_TOKEN_KEY1:
207 case WSI_TOKEN_KEY2:
208 case WSI_TOKEN_PROTOCOL:
209 case WSI_TOKEN_UPGRADE:
210 case WSI_TOKEN_ORIGIN:
211 case WSI_TOKEN_CHALLENGE:
212
213// fprintf(stderr, "WSI_TOKEN_(body %d) '%c'\n", wsi->parser_state, c);
214
215 /* collect into malloc'd buffers */
216 /* optional space swallow */
217 if (!wsi->utf8_token[wsi->parser_state].token_len && c == ' ')
218 break;
219
220 /* special case space terminator for get-uri */
221 if (wsi->parser_state == WSI_TOKEN_GET_URI && c == ' ') {
222 wsi->utf8_token[wsi->parser_state].token[
223 wsi->utf8_token[wsi->parser_state].token_len] = '\0';
224 wsi->parser_state = WSI_TOKEN_SKIPPING;
225 break;
226 }
227
228 /* allocate appropriate memory */
229 if (wsi->utf8_token[wsi->parser_state].token_len == wsi->current_alloc_len - 1) {
230 /* need to extend */
231 wsi->current_alloc_len += LWS_ADDITIONAL_HDR_ALLOC;
232 if (wsi->current_alloc_len >= LWS_MAX_HEADER_LEN) {
233 /* it's waaay to much payload, fail it */
234 strcpy(wsi->utf8_token[wsi->parser_state].token,
235 "!!! Length exceeded maximum supported !!!");
236 wsi->parser_state = WSI_TOKEN_SKIPPING;
237 break;
238 }
239 wsi->utf8_token[wsi->parser_state].token =
240 realloc(wsi->utf8_token[wsi->parser_state].token,
241 wsi->current_alloc_len);
242 }
243
244 /* bail at EOL */
245 if (wsi->parser_state != WSI_TOKEN_CHALLENGE && c == '\x0d') {
246 wsi->utf8_token[wsi->parser_state].token[
247 wsi->utf8_token[wsi->parser_state].token_len] = '\0';
248 wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
249 break;
250 }
251
252 wsi->utf8_token[wsi->parser_state].token[
253 wsi->utf8_token[wsi->parser_state].token_len++] = c;
254
255 /* special payload limiting */
Andy Green775c0dd2010-10-29 14:15:22 +0100256 if (wsi->parser_state == WSI_TOKEN_CHALLENGE &&
257 wsi->utf8_token[wsi->parser_state].token_len == 8) {
258// fprintf(stderr, "Setting WSI_PARSING_COMPLETE\n");
259 wsi->parser_state = WSI_PARSING_COMPLETE;
260 break;
261 }
Andy Greenff95d7a2010-10-28 22:36:01 +0100262
263 break;
264
265 /* collecting and checking a name part */
266 case WSI_TOKEN_NAME_PART:
267// fprintf(stderr, "WSI_TOKEN_NAME_PART '%c'\n", c);
268
269 if (wsi->name_buffer_pos == sizeof(wsi->name_buffer) - 1) {
270 /* name bigger than we can handle, skip until next */
271 wsi->parser_state = WSI_TOKEN_SKIPPING;
272 break;
273 }
274 wsi->name_buffer[wsi->name_buffer_pos++] = c;
275 wsi->name_buffer[wsi->name_buffer_pos] = '\0';
276
277 for (n = 0; n < WSI_TOKEN_COUNT; n++) {
278 if (wsi->name_buffer_pos != lws_tokens[n].token_len)
279 continue;
280 if (strcmp(lws_tokens[n].token, wsi->name_buffer))
281 continue;
282 wsi->parser_state = WSI_TOKEN_GET_URI + n;
283 wsi->current_alloc_len = LWS_INITIAL_HDR_ALLOC;
284 wsi->utf8_token[wsi->parser_state].token =
285 malloc(wsi->current_alloc_len);
286 wsi->utf8_token[wsi->parser_state].token_len = 0;
287 n = WSI_TOKEN_COUNT;
288 }
289 if (wsi->parser_state != WSI_TOKEN_NAME_PART)
290 break;
291 break;
292
293 /* skipping arg part of a name we didn't recognize */
294 case WSI_TOKEN_SKIPPING:
295// fprintf(stderr, "WSI_TOKEN_SKIPPING '%c'\n", c);
296 if (c == '\x0d')
297 wsi->parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
298 break;
299 case WSI_TOKEN_SKIPPING_SAW_CR:
300// fprintf(stderr, "WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
301 if (c == '\x0a')
302 wsi->parser_state = WSI_TOKEN_NAME_PART;
303 else
304 wsi->parser_state = WSI_TOKEN_SKIPPING;
305 wsi->name_buffer_pos = 0;
306 break;
307 /* we're done, ignore anything else */
308 case WSI_PARSING_COMPLETE:
309// fprintf(stderr, "WSI_PARSING_COMPLETE '%c'\n", c);
310 break;
311
312 default: /* keep gcc happy */
313 break;
314 }
315
316 return 0;
317}
318
319static int interpret_key(const char *key, unsigned int *result)
320{
321 char digits[20];
322 int digit_pos = 0;
323 const char *p = key;
324 int spaces = 0;
325
326 while (*p) {
327 if (isdigit(*p)) {
328 if (digit_pos == sizeof(digits) - 1)
329 return -1;
330 digits[digit_pos++] = *p;
331 }
332 p++;
333 }
334 digits[digit_pos] = '\0';
335 if (!digit_pos)
336 return -2;
337
338 while (*key) {
339 if (*key == ' ')
340 spaces++;
341 key++;
342 }
343
344 if (!spaces)
345 return -3;
346
347 *result = atol(digits) / spaces;
348
349 return 0;
350}
351
352
353/*
354 * We have to take care about parsing because the headers may be split
355 * into multiple fragments. They may contain unknown headers with arbitrary
Andy Green775c0dd2010-10-29 14:15:22 +0100356 * argument lengths. So, we parse using a single-character at a time state
357 * machine that is completely independent of packet size.
Andy Greenff95d7a2010-10-28 22:36:01 +0100358 */
359
360int libwebsocket_read(struct libwebsocket *wsi, unsigned char * buf, size_t len)
361{
362 size_t n;
363 char *p;
364 unsigned int key1, key2;
365 unsigned char sum[16];
Andy Green775c0dd2010-10-29 14:15:22 +0100366 char *response;
Andy Greenff95d7a2010-10-28 22:36:01 +0100367
368 switch (wsi->state) {
369 case WSI_STATE_CLOSED:
370 wsi->state = WSI_STATE_HANDSHAKE_RX;
371 wsi->parser_state = WSI_TOKEN_NAME_PART;
Andy Green775c0dd2010-10-29 14:15:22 +0100372 /* fallthru */
Andy Greenff95d7a2010-10-28 22:36:01 +0100373 case WSI_STATE_HANDSHAKE_RX:
374
375 fprintf(stderr, "issuing %ld bytes to parser\n", len);
376
377
378 fwrite(buf, 1, len, stderr);
379 for (n = 0; n< len; n++)
380 libwebsocket_parse(wsi, *buf++);
381
382 if (wsi->parser_state != WSI_PARSING_COMPLETE)
383 break;
384
385 fprintf(stderr, "Preparing return packet\n");
386
387
388 /* Confirm we have all the necessary pieces */
389
390 if (
391 !wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len ||
392 !wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len ||
393 !wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len ||
394 !wsi->utf8_token[WSI_TOKEN_HOST].token_len ||
395 !wsi->utf8_token[WSI_TOKEN_CHALLENGE].token_len ||
396 !wsi->utf8_token[WSI_TOKEN_KEY1].token_len ||
397 !wsi->utf8_token[WSI_TOKEN_KEY2].token_len) {
398
399 /* completed header processing, but missing some bits */
400 goto bail;
401 }
402
403 /* create the response packet */
404
Andy Green775c0dd2010-10-29 14:15:22 +0100405 response = malloc(256 +
Andy Greenff95d7a2010-10-28 22:36:01 +0100406 wsi->utf8_token[WSI_TOKEN_UPGRADE].token_len +
407 wsi->utf8_token[WSI_TOKEN_CONNECTION].token_len +
408 wsi->utf8_token[WSI_TOKEN_HOST].token_len +
409 wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len +
410 wsi->utf8_token[WSI_TOKEN_GET_URI].token_len +
411 wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len);
412
413
414 fprintf(stderr, "'%s;\n", wsi->utf8_token[WSI_TOKEN_HOST].token);
415
Andy Green775c0dd2010-10-29 14:15:22 +0100416 p = response;
Andy Greenff95d7a2010-10-28 22:36:01 +0100417 strcpy(p, "HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0aUpgrade: WebSocket\x0d\x0a");
418 p += strlen("HTTP/1.1 101 WebSocket Protocol Handshake\x0d\x0aUpgrade: WebSocket\x0d\x0a");
419 strcpy(p, "Connection: Upgrade\x0d\x0aSec-WebSocket-Origin: ");
420 p += strlen("Connection: Upgrade\x0d\x0aSec-WebSocket-Origin: ");
421 strcpy(p, wsi->utf8_token[WSI_TOKEN_ORIGIN].token);
422 p += wsi->utf8_token[WSI_TOKEN_ORIGIN].token_len;
423 strcpy(p, "\x0d\x0aSec-WebSocket-Location: ws://");
424 p += strlen("\x0d\x0aSec-WebSocket-Location: ws://");
425 strcpy(p, wsi->utf8_token[WSI_TOKEN_HOST].token);
426 p += wsi->utf8_token[WSI_TOKEN_HOST].token_len;
427 strcpy(p, wsi->utf8_token[WSI_TOKEN_GET_URI].token);
428 p += wsi->utf8_token[WSI_TOKEN_GET_URI].token_len;
429 strcpy(p, "\x0d\x0aSec-WebSocket-Protocol: ");
430 p += strlen("\x0d\x0aSec-WebSocket-Protocol: ");
431 if (wsi->utf8_token[WSI_TOKEN_PROTOCOL].token) {
432 strcpy(p, wsi->utf8_token[WSI_TOKEN_PROTOCOL].token);
433 p += wsi->utf8_token[WSI_TOKEN_PROTOCOL].token_len;
Andy Green775c0dd2010-10-29 14:15:22 +0100434 } else {
435 strcpy(p, "none");
436 p += strlen("none");
Andy Greenff95d7a2010-10-28 22:36:01 +0100437 }
438 strcpy(p, "\x0d\x0a\x0d\x0a");
439 p += strlen("\x0d\x0a\x0d\x0a");
440
Andy Green775c0dd2010-10-29 14:15:22 +0100441 /* convert the two keys into 32-bit integers */
442
Andy Greenff95d7a2010-10-28 22:36:01 +0100443 if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY1].token, &key1))
444 goto bail;
445
446 if (interpret_key(wsi->utf8_token[WSI_TOKEN_KEY2].token, &key2))
447 goto bail;
Andy Green775c0dd2010-10-29 14:15:22 +0100448
449 /* lay them out in network byte order (MSB first */
Andy Greenff95d7a2010-10-28 22:36:01 +0100450
451 sum[0] = key1 >> 24;
452 sum[1] = key1 >> 16;
453 sum[2] = key1 >> 8;
454 sum[3] = key1;
455 sum[4] = key2 >> 24;
456 sum[5] = key2 >> 16;
457 sum[6] = key2 >> 8;
458 sum[7] = key2;
Andy Green775c0dd2010-10-29 14:15:22 +0100459
460 /* follow them with the challenge token we were sent */
461
Andy Greenff95d7a2010-10-28 22:36:01 +0100462 memcpy(&sum[8], wsi->utf8_token[WSI_TOKEN_CHALLENGE].token, 8);
463
Andy Green775c0dd2010-10-29 14:15:22 +0100464 /*
465 * compute the md5sum of that 16-byte series and use as our
466 * payload after our headers
467 */
468
Andy Greenff95d7a2010-10-28 22:36:01 +0100469 md5(sum, 16, (unsigned char *)p);
470 p += 16;
471
Andy Green775c0dd2010-10-29 14:15:22 +0100472 /* it's complete, go ahead and send it */
Andy Greenff95d7a2010-10-28 22:36:01 +0100473
Andy Green775c0dd2010-10-29 14:15:22 +0100474 fprintf(stderr, "issuing response packet %d len\n",
475 (int)(p - response));
476 fwrite(response, 1, p - response, stderr);
477
478 n = write(wsi->sock, response, p - response);
479 if (n < 0) {
480 fprintf(stderr, "ERROR writing to socket");
481 goto bail;
482 }
483
484 free(response);
485 wsi->state = WSI_STATE_ESTABLISHED;
486
487 /* notify user code that we're ready to roll */
488
489 if (wsi->callback)
490 wsi->callback(wsi, LWS_CALLBACK_ESTABLISHED);
Andy Greenff95d7a2010-10-28 22:36:01 +0100491 break;
492
493 case WSI_STATE_ESTABLISHED:
Andy Green775c0dd2010-10-29 14:15:22 +0100494 fprintf(stderr, "received %ld byte packet\n", len);
Andy Greenff95d7a2010-10-28 22:36:01 +0100495 break;
496 default:
497 break;
498 }
499
500 return 0;
501
502bail:
503 libwebsocket_close(wsi);
504 return -1;
505}
506
Andy Green775c0dd2010-10-29 14:15:22 +0100507int libwebsocket_write(struct libwebsocket * wsi, void *buf, size_t len)
508{
509 int n;
510 unsigned char hdr[9];
511
512 if (wsi->state != WSI_STATE_ESTABLISHED)
513 return -1;
Andy Greenff95d7a2010-10-28 22:36:01 +0100514
Andy Green775c0dd2010-10-29 14:15:22 +0100515 switch (wsi->ietf_spec_revision) {
516 /* chrome */
517 case 0:
518 hdr[0] = 0xff;
519 hdr[1] = len >> 56;
520 hdr[2] = len >> 48;
521 hdr[3] = len >> 40;
522 hdr[4] = len >> 32;
523 hdr[5] = len >> 24;
524 hdr[6] = len >> 16;
525 hdr[7] = len >> 8;
526 hdr[8] = len;
527
528 n = write(wsi->sock, hdr, sizeof hdr);
529 if (n < 0) {
530 fprintf(stderr, "ERROR writing to socket");
531 return -1;
532 }
533 break;
534 /* just an unimplemented spec right now apparently */
535 case 2:
536 n = 0;
537 if (len < 126) {
538 hdr[n++] = 0x04;
539 hdr[n++] = len;
540 } else {
541 if (len < 65536) {
542 hdr[n++] = 0x04; /* text frame */
543 hdr[n++] = 126;
544 hdr[n++] = len >> 8;
545 hdr[n++] = len;
546 } else {
547 hdr[n++] = 0x04;
548 hdr[n++] = 127;
549 hdr[n++] = len >> 24;
550 hdr[n++] = len >> 16;
551 hdr[n++] = len >> 8;
552 hdr[n++] = len;
553 }
554 }
555 n = write(wsi->sock, hdr, n);
556 if (n < 0) {
557 fprintf(stderr, "ERROR writing to socket");
558 return -1;
559 }
560 break;
561 }
562
563 n = write(wsi->sock, buf, len);
564 if (n < 0) {
565 fprintf(stderr, "ERROR writing to socket");
566 return -1;
567 }
568
569 fprintf(stderr, "written %d bytes to websocket\n", (int)len);
570
571 return 0;
572}
573
574static void libwebsocket_service(struct libwebsocket *wsi, int sock)
Andy Greenff95d7a2010-10-28 22:36:01 +0100575{
576 int n;
577 unsigned char buf[256];
578 struct pollfd fds;
579
580 wsi->sock = sock;
581
582 fds.fd = sock;
583 fds.events = POLLIN | POLLOUT;
584
585 while (1) {
586
587 n = poll(&fds, 1, 10);
588 if (n < 0) {
589 fprintf(stderr, "Socket dead (poll = %d)\n", n);
590 return;
591 }
592
593 if (fds.revents & (POLLERR | POLLHUP)) {
594 fprintf(stderr, "Socket dead\n");
595 return;
596 }
597
598 if (wsi->state == WSI_STATE_DEAD_SOCKET)
599 return;
600
601
602 if (fds.revents & POLLIN) {
603
604// fprintf(stderr, "POLLIN\n");
605
606 n = read(sock, buf, sizeof(buf));
607 if (n < 0) {
608 fprintf(stderr, "Socket read returned %d\n", n);
609 continue;
610 }
611 if (n)
612 libwebsocket_read(wsi, buf, n);
613 }
614
Andy Green775c0dd2010-10-29 14:15:22 +0100615 if (wsi->state != WSI_STATE_ESTABLISHED)
Andy Greenff95d7a2010-10-28 22:36:01 +0100616 continue;
Andy Greenff95d7a2010-10-28 22:36:01 +0100617
Andy Green775c0dd2010-10-29 14:15:22 +0100618 if (wsi->callback)
619 wsi->callback(wsi, LWS_CALLBACK_SEND);
Andy Greenff95d7a2010-10-28 22:36:01 +0100620 }
621}
622