jabberd2  2.6.1
websocket.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2015 Tomasz Sterna
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; version 2 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
17  */
18 
25 #include "sx.h"
26 #include <stdarg.h>
27 #include <string.h>
28 
29 static const char websocket_guid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
30 
31 static http_parser_settings settings;
32 
33 /* parts of github.com/payden src/websock.c by Payden Sutherland follow */
34 #define MASK_LENGTH 4
35 #define FRAME_CHUNK_LENGTH 1024
36 
37 #define WS_OPCODE_CONTINUE 0x0
38 #define WS_OPCODE_TEXT 0x1
39 #define WS_OPCODE_BINARY 0x2
40 #define WS_OPCODE_CLOSE 0x8
41 #define WS_OPCODE_PING 0x9
42 #define WS_OPCODE_PONG 0xa
43 
44 #define WS_FRAGMENT_FIN (1 << 7)
45 
46 #define WS_CLOSE_NORMAL 1000
47 #define WS_CLOSE_GOING_AWAY 1001
48 #define WS_CLOSE_PROTOCOL_ERROR 1002
49 #define WS_CLOSE_NOT_ALLOWED 1003
50 #define WS_CLOSE_RESERVED 1004
51 #define WS_CLOSE_NO_CODE 1005
52 #define WS_CLOSE_DIRTY 1006
53 #define WS_CLOSE_WRONG_TYPE 1007
54 #define WS_CLOSE_POLICY_VIOLATION 1008
55 #define WS_CLOSE_MESSAGE_TOO_BIG 1009
56 #define WS_CLOSE_UNEXPECTED_ERROR 1011
57 
59  sw_start = 0,
64 };
65 
66 typedef struct _libwebsock_frame {
67  unsigned int fin;
68  unsigned int opcode;
69  unsigned int mask_offset;
70  unsigned int payload_offset;
71  unsigned int rawdata_idx;
72  unsigned int rawdata_sz;
73  unsigned int size;
74  unsigned int payload_len_short;
75  unsigned int payload_len;
76  char *rawdata;
77  unsigned char mask[4];
80 
81 static inline int libwebsock_read_header(libwebsock_frame *frame) {
82  int i, new_size;
83  enum WS_FRAME_STATE state;
84 
85  state = frame->state;
86  switch (state) {
87  case sw_start:
88  if (frame->rawdata_idx < 2) {
89  return 0;
90  }
91  frame->state = sw_got_two;
92  case sw_got_two:
93  frame->mask_offset = 2;
94  frame->fin = (*(frame->rawdata) & 0x80) == 0x80 ? 1 : 0;
95  frame->opcode = *(frame->rawdata) & 0xf;
96  frame->payload_len_short = *(frame->rawdata + 1) & 0x7f;
97  frame->state = sw_got_short_len;
98  case sw_got_short_len:
99  switch (frame->payload_len_short) {
100  case 126:
101  if (frame->rawdata_idx < 4) {
102  return 0;
103  }
104  frame->mask_offset += 2;
105  frame->payload_offset = frame->mask_offset + MASK_LENGTH;
106  frame->payload_len = ntohs(
107  *((unsigned short int *) (frame->rawdata + 2)));
108  frame->state = sw_got_full_len;
109  break;
110  case 127:
111  if (frame->rawdata_idx < 10) {
112  return 0;
113  }
114  frame->mask_offset += 8;
115  frame->payload_offset = frame->mask_offset + MASK_LENGTH;
116  frame->payload_len = ntohl(*((unsigned int *) (frame->rawdata + 6)));
117  frame->state = sw_got_full_len;
118  break;
119  default:
120  frame->payload_len = frame->payload_len_short;
121  frame->payload_offset = frame->mask_offset + MASK_LENGTH;
122  frame->state = sw_got_full_len;
123  break;
124  }
125  case sw_got_full_len:
126  if (frame->rawdata_idx < frame->payload_offset) {
127  return 0;
128  }
129  for (i = 0; i < MASK_LENGTH; i++) {
130  frame->mask[i] = *(frame->rawdata + frame->mask_offset + i) & 0xff;
131  }
132  frame->state = sw_loaded_mask;
133  frame->size = frame->payload_offset + frame->payload_len;
134  if (frame->size > frame->rawdata_sz) {
135  new_size = frame->size;
136  new_size--;
137  new_size |= new_size >> 1;
138  new_size |= new_size >> 2;
139  new_size |= new_size >> 4;
140  new_size |= new_size >> 8;
141  new_size |= new_size >> 16;
142  new_size++;
143  frame->rawdata_sz = new_size;
144  frame->rawdata = (char *) realloc(frame->rawdata, new_size);
145  }
146  return 1;
147  case sw_loaded_mask:
148  return 1;
149  }
150  return 0;
151 }
152 
153 sx_buf_t libwebsock_fragment_buffer(const char *data, unsigned int len, int flags) {
154  unsigned int *payload_len_32_be;
155  unsigned short int *payload_len_short_be;
156  unsigned char finNopcode, payload_len_small;
157  unsigned int payload_offset = 2;
158  unsigned int frame_size;
159  char *frame;
160 
161  finNopcode = flags & 0xff;
162  if (len <= 125) {
163  frame_size = 2 + len;
164  payload_len_small = len & 0xff;
165  } else if (len > 125 && len <= 0xffff) {
166  frame_size = 4 + len;
167  payload_len_small = 126;
168  payload_offset += 2;
169  } else if (len > 0xffff && len <= 0xfffffff0) {
170  frame_size = 10 + len;
171  payload_len_small = 127;
172  payload_offset += 8;
173  } else {
174  _sx_debug(ZONE,
175  "libwebsock does not support frame payload sizes over %u bytes long\n",
176  0xfffffff0);
177  return NULL;
178  }
179  sx_buf_t buf = _sx_buffer_new(NULL, frame_size, NULL, NULL);
180  frame = buf->data;
181  payload_len_small &= 0x7f;
182  *frame = finNopcode;
183  *(frame + 1) = payload_len_small;
184  if (payload_len_small == 126) {
185  len &= 0xffff;
186  payload_len_short_be = (unsigned short *) ((char *) frame + 2);
187  *payload_len_short_be = htons(len);
188  }
189  if (payload_len_small == 127) {
190  payload_len_32_be = (unsigned int *) ((char *) frame + 2);
191  *payload_len_32_be++ = 0;
192  *payload_len_32_be = htonl(len);
193  }
194  memcpy(frame + payload_offset, data, len);
195 
196  return buf;
197 }
198 
199 int libwebsock_close_with_reason(sx_t s, _sx_websocket_conn_t sc, unsigned short code, const char *reason);
200 
201 int libwebsock_send_fragment(sx_t s, _sx_websocket_conn_t sc, const char *data, unsigned int len, int flags) {
202  sx_buf_t buf = libwebsock_fragment_buffer(data, len, flags);
203  if (buf == NULL) {
204  return libwebsock_close_with_reason(s, sc, WS_CLOSE_UNEXPECTED_ERROR, "Internal server error");
205  }
206  jqueue_push(s->wbufq, buf, 0);
207  s->want_write = 1;
208  return _sx_event(s, event_WANT_WRITE, NULL);
209 }
210 
211 int libwebsock_close_with_reason(sx_t s, _sx_websocket_conn_t sc, unsigned short code, const char *reason)
212 {
213  unsigned int len;
214  unsigned short code_be;
215  char buf[128]; //w3 spec on WebSockets API (http://dev.w3.org/html5/websockets/) says reason shouldn't be over 123 bytes. I concur.
216  len = 2;
217  code_be = htobe16(code);
218  memcpy(buf, &code_be, 2);
219  if (reason) {
220  len += snprintf(buf + 2, 124, "%s", reason);
221  }
222 
223  sc->state = websocket_CLOSING;
224  int ret = libwebsock_send_fragment(s, sc, buf, len, WS_FRAGMENT_FIN | WS_OPCODE_CLOSE);
225 
226  sx_close(s);
227  return ret;
228 }
229 
230 int libwebsock_close(sx_t s, _sx_websocket_conn_t sc)
231 {
232  return libwebsock_close_with_reason(s, sc, WS_CLOSE_NORMAL, NULL);
233 }
234 
235 void libwebsock_fail_connection(sx_t s, _sx_websocket_conn_t sc, unsigned short close_code) {
236  char close_frame[4] = { 0x88, 0x02, 0x00, 0x00 };
237  unsigned short *code_be = (unsigned short *) &close_frame[2];
238  *code_be = htobe16(WS_CLOSE_PROTOCOL_ERROR);
239 
240  sx_buf_t buf = _sx_buffer_new(NULL, sizeof(close_frame), NULL, NULL);
241  memcpy(buf->data, close_frame, buf->len);
242 
243  sc->state = websocket_CLOSING;
244  s->want_write = 1;
245  _sx_event(s, event_WANT_WRITE, NULL);
246 
247  sx_close(s);
248 }
249 
250 static int _sx_websocket_http_header_field(http_parser *parser, const char *chars, size_t length) {
251  _sx_debug(ZONE, "HTTP header field '%.*s'", length, chars);
252  _sx_websocket_conn_t sc = (_sx_websocket_conn_t) parser->data;
253  if(sc->header_value) {
254  // new field incoming
255  xhash_put(sc->headers,
256  strunescape(sc->p, spool_print(sc->field)),
257  strunescape(sc->p, spool_print(sc->value)));
258  sc->header_value = 0;
259  sc->field = spool_new(sc->p);
260  }
261  spool_escape(sc->field, chars, length);
262  return 0;
263 }
264 
265 static int _sx_websocket_http_header_value(http_parser *parser, const char *chars, size_t length) {
266  _sx_debug(ZONE, "HTTP header value '%.*s'", length, chars);
267  _sx_websocket_conn_t sc = (_sx_websocket_conn_t) parser->data;
268  if(!sc->header_value) {
269  // field name complete
270  sc->header_value = 1;
271  sc->value = spool_new(sc->p);
272  }
273  spool_escape(sc->value, chars, length);
274  return 0;
275 }
276 
277 static int _sx_websocket_http_headers_complete(http_parser *parser) {
278  _sx_websocket_conn_t sc = (_sx_websocket_conn_t) parser->data;
279  _sx_debug(ZONE, "HTTP headers complete: %d %s HTTP/%d.%d", parser->status_code, http_method_str(parser->method), parser->http_major, parser->http_minor);
280  if (sc->header_value) {
281  /* pull last value by switching to field parser */
282  _sx_websocket_http_header_field(parser, "", 0);
283  }
284  return 1;
285 }
286 
287 static void _sx_websocket_http_return(sx_t s, char *status, char *headers_format, ...) {
288  char* http =
289  "HTTP/1.1 %s\r\n"
290  "%s"
291  "Server: " PACKAGE_STRING "\r\n"
292  "Expires: Fri, 10 Oct 1997 10:10:10 GMT\r\n"
293  "Pragma: no-cache\r\n"
294  "Cache-control: private\r\n"
295  "\r\n";
296 
297  /* build additional headers */
298  char headers[1024];
299  va_list args;
300  va_start(args, headers_format);
301  vsnprintf(headers, sizeof(headers), headers_format, args);
302  va_end(args);
303 
304  /* build HTTP answer */
305  sx_buf_t buf = _sx_buffer_new(NULL, j_strlen(http) + j_strlen(status) + j_strlen(headers), NULL, NULL);
306  buf->len = sprintf(buf->data, http, status, headers);
307  jqueue_push(s->wbufq, buf, 0);
308 
309  /* stuff to write */
310  s->want_write = 1;
311  _sx_event(s, event_WANT_WRITE, NULL);
312 }
313 
315  _sx_websocket_conn_t sc = (_sx_websocket_conn_t) s->plugin_data[p->index];
316  int i, j, ret, err;
317  char *newbuf;
318  sha1_state_t sha1;
319  unsigned char hash[20];
320 
321  /* if not wrapped yet */
322  if(!(s->flags & SX_WEBSOCKET_WRAPPER)) {
323  /* look for HTTP handshake */
324  if(s->state == state_NONE && sc->state == websocket_PRE && buf->len >= 5 && strncmp("GET /", buf->data, 5) == 0) {
325  _sx_debug(ZONE, "got HTTP handshake");
326  sc->state = websocket_HEADERS;
327  }
328 
329  /* pass buffers through http_parser */
330  if(s->state == state_NONE && sc->state == websocket_HEADERS) {
331  _sx_debug(ZONE, "parsing HTTP headers");
332  if(buf->len > 0) {
333  _sx_debug(ZONE, "loading %d bytes into http_parser %.*s", buf->len, buf->len, buf->data);
334 
335  ret = http_parser_execute(&sc->parser, &settings, buf->data, buf->len);
336 
337  if (sc->parser.upgrade) {
338  /* check for required websocket upgrade headers */
339  char *upgrade = xhash_get(sc->headers, "Upgrade");
340  char *connection = xhash_get(sc->headers, "Connection");
341  char *key = xhash_get(sc->headers, "Sec-WebSocket-Key");
342  char *proto = xhash_get(sc->headers, "Sec-WebSocket-Protocol");
343  int version = j_atoi(xhash_get(sc->headers, "Sec-WebSocket-Version"), -1);
344  if(j_strcmp(upgrade, "websocket") || connection == NULL || strcasestr(connection, "Upgrade") == NULL || j_strcmp(proto, "xmpp") || version != 13) {
345  _sx_debug(ZONE, "Upgrade: %s", upgrade);
346  _sx_debug(ZONE, "Connection: %s", connection);
347  _sx_debug(ZONE, "Sec-WebSocket-Key: %s", key);
348  _sx_debug(ZONE, "Sec-WebSocket-Protocol: %s", proto);
349  _sx_debug(ZONE, "Sec-WebSocket-Version: %d", version);
350  _sx_websocket_http_return(s, "400 Bad Request", "");
351  sx_close(s);
352  return -2;
353  }
354 
355  /* we're good to go */
356 
357  sha1_init(&sha1);
358  sha1_append(&sha1, key, j_strlen(key));
359  sha1_append(&sha1, websocket_guid, sizeof(websocket_guid) -1);
360  sha1_finish(&sha1, hash);
361  char * accept = b64_encode(hash, sizeof(hash));
362 
363  /* switch protocols */
364  _sx_websocket_http_return(s, "101 Switching Protocols",
365  "Upgrade: websocket\r\n"
366  "Connection: Upgrade\r\n"
367  "Sec-WebSocket-Accept: %s\r\n"
368  "Sec-WebSocket-Protocol: xmpp\r\n",
369  accept);
370  free(accept);
371 
372  /* and move past headers */
373  sc->state = websocket_ACTIVE;
375 
376  return 0;
377  } else if (ret != buf->len) {
378  /* throw an error */
379  sx_error(s, stream_err_BAD_FORMAT, http_errno_description(sc->parser.http_errno));
380  sx_close(s);
381  return -2;
382  } else if (p->private) {
383  char *http_forward = p->private;
384  _sx_debug(ZONE, "bouncing HTTP request to %s", http_forward);
385  _sx_websocket_http_return(s, "301 Found", "Location: %s\r\nConnection: close\r\n", http_forward);
386  sx_close(s);
387  return -1;
388  }
389 
390  _sx_debug(ZONE, "unhandling HTTP request");
391  _sx_websocket_http_return(s, "403 Forbidden", "Connection: close\r\n");
392  sx_close(s);
393  return -1;
394  }
395 
396  _sx_buffer_clear(buf);
397  /* flag we want to read */
398  s->want_read = 1;
399 
400  return 0;
401  }
402  }
403 
404  /* only bothering if it is active websocket */
405  if(!(s->flags & SX_WEBSOCKET_WRAPPER) || sc->state != websocket_ACTIVE)
406  return 1;
407 
408  _sx_debug(ZONE, "Unwraping WebSocket frame: %d bytes", buf->len);
409 
410  char *data = buf->data;
411  for (i = 0; i < buf->len;) {
412  libwebsock_frame *frame;
413  if (sc->frame == NULL) {
414  frame = (libwebsock_frame *) calloc(1, sizeof(libwebsock_frame));
415  frame->payload_len = -1;
417  frame->rawdata = (char *) malloc(FRAME_CHUNK_LENGTH);
418  sc->frame = frame;
419  } else {
420  frame = sc->frame;
421  }
422 
423  *(frame->rawdata + frame->rawdata_idx++) = *data++;
424  i++;
425 
426  if (frame->state != sw_loaded_mask) {
427  err = libwebsock_read_header(frame);
428  if (err == -1) {
429  if (sc->state != websocket_CLOSING) {
431  }
432  return -2;
433  }
434  if (err == 0) {
435  continue;
436  }
437  }
438 
439  if (frame->rawdata_idx < frame->size) {
440  if (buf->len - i >= frame->size - frame->rawdata_idx) {
441  //remaining in current vector completes frame. Copy remaining frame size
442  memcpy(frame->rawdata + frame->rawdata_idx, data,
443  frame->size - frame->rawdata_idx);
444  data += frame->size - frame->rawdata_idx;
445  i += frame->size - frame->rawdata_idx;
446  frame->rawdata_idx = frame->size;
447  } else {
448  //not complete frame, copy the rest of this vector into frame.
449  memcpy(frame->rawdata + frame->rawdata_idx, data, buf->len - i);
450  frame->rawdata_idx += buf->len - i;
451  i = buf->len;
452  _sx_debug(ZONE, "more frame data to come");
453  continue;
454  }
455  }
456 
457  //have full frame at this point
458  _sx_debug(ZONE, "FIN: %d", frame->fin);
459  _sx_debug(ZONE, "Opcode: %x", frame->opcode);
460  _sx_debug(ZONE, "mask_offset: %d", frame->mask_offset);
461  _sx_debug(ZONE, "payload_offset: %d", frame->payload_offset);
462  _sx_debug(ZONE, "rawdata_idx: %d", frame->rawdata_idx);
463  _sx_debug(ZONE, "rawdata_sz: %d", frame->rawdata_sz);
464  _sx_debug(ZONE, "payload_len: %u", frame->payload_len);
465 
466  if (frame->opcode != WS_OPCODE_CONTINUE) {
467  sc->opcode = frame->opcode;
468  }
469 
470  switch (sc->opcode) {
471  case WS_OPCODE_TEXT:
472  /* unmask content */
473  for (j = 0; j < frame->payload_len; j++)
474  frame->rawdata[frame->payload_offset + j] ^= frame->mask[j % 4];
475  _sx_debug(ZONE, "payload: %.*s", frame->payload_len, frame->rawdata + frame->payload_offset);
476  sc->buf = realloc(sc->buf, sc->buf_len + frame->payload_len);
477  newbuf = sc->buf + sc->buf_len;
478  strncpy(newbuf, frame->rawdata + frame->payload_offset, frame->payload_len);
479  sc->buf_len += frame->payload_len;
480  /* hack unclose <open ... /> */
481  if (frame->payload_len >= 7 && strncmp(newbuf, "<open", 5) == 0 && strncmp(newbuf + frame->payload_len - 2, "/>", 2) == 0) {
482  sc->buf_len--;
483  sc->buf[sc->buf_len - 1] = '>';
484  }
485  break;
486  case WS_OPCODE_CLOSE:
487  libwebsock_close(s, sc);
488  break;
489  case WS_OPCODE_PING:
491  break;
492  case WS_OPCODE_PONG:
493  s->want_read = 1;
494  default:
495  _sx_debug(ZONE, "unhandled opcode: %x", frame->opcode);
496  break;
497  }
498 
499  free(frame->rawdata);
500  free(frame);
501  sc->frame = NULL;
502 
503  if (sc->state == websocket_CLOSING) {
504  _sx_buffer_clear(buf);
505  return 0;
506  }
507  }
508 
509  _sx_debug(ZONE, "passing buffer: %.*s", sc->buf_len, sc->buf);
510  _sx_buffer_set(buf, sc->buf, sc->buf_len, NULL);
511  sc->buf_len = 0;
512 
513  return 1;
514 }
515 
517  _sx_websocket_conn_t sc = (_sx_websocket_conn_t) s->plugin_data[p->index];
518 
519  /* only bothering if it is active websocket */
520  if(!(s->flags & SX_WEBSOCKET_WRAPPER))
521  return 1;
522 
523  _sx_debug(ZONE, "in _sx_websocket_wio");
524 
525  if(buf->len > 0) {
526  _sx_debug(ZONE, "wrapping %d bytes in WebSocket frame", buf->len);
528  if (frame == NULL) {
529  return libwebsock_close_with_reason(s, sc, WS_CLOSE_UNEXPECTED_ERROR, "Internal server error");
530  }
531  _sx_buffer_set(buf, frame->data, frame->len, frame->data);
532  free(frame);
533  }
534  _sx_debug(ZONE, "passing %d bytes frame", buf->len);
535 
536  return 1;
537 }
538 
539 static void _sx_websocket_new(sx_t s, sx_plugin_t p) {
540  _sx_websocket_conn_t sc = (_sx_websocket_conn_t) s->plugin_data[p->index];
541 
542  if(sc != NULL)
543  return;
544 
545  _sx_debug(ZONE, "preparing for HTTP websocket connect for %d", s->tag);
546 
547  sc = (_sx_websocket_conn_t) calloc(1, sizeof(struct _sx_websocket_conn_st));
548 
549  sc->state = websocket_PRE;
550  sc->p = pool_new();
551  sc->field = spool_new(sc->p);
552  sc->value = spool_new(sc->p);
553  sc->headers = xhash_new(11);
554  sc->buf = malloc(1024);
555  sc->parser.data = sc;
556 
557  /* initialize parser */
558  http_parser_init(&sc->parser, HTTP_REQUEST);
559 
560  s->plugin_data[p->index] = (void *) sc;
561 
562  /* bring the plugin online */
563  _sx_chain_io_plugin(s, p);
564 }
565 
568  _sx_websocket_conn_t sc = (_sx_websocket_conn_t) s->plugin_data[p->index];
569 
570  if(sc == NULL)
571  return;
572 
573  log_debug(ZONE, "cleaning up websocket state");
574 
575  pool_free(sc->p);
576 
577  if (sc->frame) free(((libwebsock_frame *)sc->frame)->rawdata);
578  free(sc->frame);
579  free(sc);
580 
581  s->plugin_data[p->index] = NULL;
582 }
583 
585 int sx_websocket_init(sx_env_t env, sx_plugin_t p, va_list args) {
586 
587  _sx_debug(ZONE, "initialising websocket plugin");
588 
590  p->rio = _sx_websocket_rio;
591  p->wio = _sx_websocket_wio;
593 
594  char *http_forward = va_arg(args, char*);
595  p->private = http_forward;
596 
597  settings.on_headers_complete = _sx_websocket_http_headers_complete;
598  settings.on_header_field = _sx_websocket_http_header_field;
599  settings.on_header_value = _sx_websocket_http_header_value;
600 
601  return 0;
602 }
enum WS_FRAME_STATE state
Definition: websocket.c:78
void(* free)(sx_t s, sx_plugin_t p)
Definition: sx.h:357
void pool_free(pool_t p)
Definition: pool.c:226
Definition: sx.h:113
static void _sx_websocket_http_return(sx_t s, char *status, char *headers_format,...)
Definition: websocket.c:287
_sx_state_t state
Definition: sx.h:319
#define _sx_event(s, e, data)
Definition: sx.h:395
void(* server)(sx_t s, sx_plugin_t p)
Definition: sx.h:360
unsigned int flags
Definition: sx.h:276
#define WS_CLOSE_PROTOCOL_ERROR
Definition: websocket.c:48
jqueue_t wbufq
Definition: sx.h:301
unsigned int mask_offset
Definition: websocket.c:69
char * b64_encode(char *buf, int len)
Definition: base64.c:260
Definition: sx.h:70
an environment
Definition: sx.h:382
int tag
Definition: sx.h:258
a plugin
Definition: sx.h:347
void libwebsock_fail_connection(sx_t s, _sx_websocket_conn_t sc, unsigned short close_code)
Definition: websocket.c:235
int j_atoi(const char *a, int def)
Definition: str.c:87
void _sx_chain_io_plugin(sx_t s, sx_plugin_t p)
Definition: chain.c:25
static int _sx_websocket_http_header_value(http_parser *parser, const char *chars, size_t length)
Definition: websocket.c:265
unsigned int opcode
Definition: websocket.c:68
#define pool_new()
Definition: pool.h:97
static void _sx_websocket_new(sx_t s, sx_plugin_t p)
Definition: websocket.c:539
unsigned int payload_len_short
Definition: websocket.c:74
static int libwebsock_read_header(libwebsock_frame *frame)
Definition: websocket.c:81
static int _sx_websocket_http_headers_complete(http_parser *parser)
Definition: websocket.c:277
static int _sx_websocket_http_header_field(http_parser *parser, const char *chars, size_t length)
Definition: websocket.c:250
holds the state for a single stream
Definition: sx.h:253
char * data
Definition: sx.h:114
void sha1_init(sha1_state_t *ctx)
Definition: sha1.c:33
void jqueue_push(jqueue_t q, void *data, int priority)
Definition: jqueue.c:44
void xhash_put(xht h, const char *key, void *val)
Definition: xhash.c:163
char * strunescape(pool_t p, char *buf)
Definition: str.c:238
unsigned int rawdata_idx
Definition: websocket.c:71
sx_buf_t _sx_buffer_new(const char *data, int len, _sx_notify_t notify, void *notify_arg)
utility: make a new buffer if len>0 but data is NULL, the buffer will contain that many bytes of garb...
Definition: sx.c:220
#define WS_OPCODE_CONTINUE
Definition: websocket.c:37
#define WS_CLOSE_NORMAL
Definition: websocket.c:46
int j_strcmp(const char *a, const char *b)
Definition: str.c:43
#define WS_OPCODE_CLOSE
Definition: websocket.c:40
void sx_close(sx_t s)
Definition: io.c:512
void sha1_finish(sha1_state_t *ctx, unsigned char hashout[20])
Definition: sha1.c:70
#define log_debug(...)
Definition: log.h:65
const char * spool_print(spool s)
Definition: str.c:186
#define SX_WEBSOCKET_WRAPPER
Definition: plugins.h:34
#define _sx_debug
Definition: sx.h:408
WS_FRAME_STATE
Definition: websocket.c:58
void sx_error(sx_t s, int err, const char *text)
Definition: error.c:94
int libwebsock_close_with_reason(sx_t s, _sx_websocket_conn_t sc, unsigned short code, const char *reason)
Definition: websocket.c:211
#define FRAME_CHUNK_LENGTH
Definition: websocket.c:35
unsigned int payload_offset
Definition: websocket.c:70
struct _libwebsock_frame libwebsock_frame
unsigned char mask[4]
Definition: websocket.c:77
static http_parser_settings settings
Definition: websocket.c:31
int libwebsock_close(sx_t s, _sx_websocket_conn_t sc)
Definition: websocket.c:230
static int _sx_websocket_rio(sx_t s, sx_plugin_t p, sx_buf_t buf)
Definition: websocket.c:314
int sx_websocket_init(sx_env_t env, sx_plugin_t p, va_list args)
args: none
Definition: websocket.c:585
unsigned int len
Definition: sx.h:115
void * private
Definition: sx.h:354
int(* wio)(sx_t s, sx_plugin_t p, sx_buf_t buf)
Definition: sx.h:363
sx_buf_t libwebsock_fragment_buffer(const char *data, unsigned int len, int flags)
Definition: websocket.c:153
void _sx_buffer_clear(sx_buf_t buf)
utility: clear out a buffer, but don&#39;t deallocate it
Definition: sx.c:252
unsigned int rawdata_sz
Definition: websocket.c:72
#define WS_CLOSE_UNEXPECTED_ERROR
Definition: websocket.c:56
void sha1_append(sha1_state_t *ctx, const unsigned char *dataIn, int len)
Definition: sha1.c:52
#define WS_OPCODE_TEXT
Definition: websocket.c:38
static int _sx_websocket_wio(sx_t s, sx_plugin_t p, sx_buf_t buf)
Definition: websocket.c:516
unsigned int payload_len
Definition: websocket.c:75
int libwebsock_send_fragment(sx_t s, _sx_websocket_conn_t sc, const char *data, unsigned int len, int flags)
Definition: websocket.c:201
static void _sx_websocket_free(sx_t s, sx_plugin_t p)
cleanup
Definition: websocket.c:567
#define stream_err_BAD_FORMAT
Definition: sx.h:124
void * xhash_get(xht h, const char *key)
Definition: xhash.c:184
unsigned int size
Definition: websocket.c:73
static const char websocket_guid[]
this plugin implements WebSocket C2S access RFC 7395 : An Extensible Messaging and Presence Protocol ...
Definition: websocket.c:29
#define ZONE
Definition: mio_impl.h:76
int want_read
Definition: sx.h:306
void _sx_buffer_set(sx_buf_t buf, char *newdata, int newlength, char *newheap)
utility: reset a sx_buf_t&#39;s contents.
Definition: sx.c:299
int(* rio)(sx_t s, sx_plugin_t p, sx_buf_t buf)
Definition: sx.h:364
xht xhash_new(int prime)
Definition: xhash.c:96
int j_strlen(const char *a)
Definition: str.c:79
void spool_escape(spool s, const char *raw, int len)
Definition: str.c:155
int index
Definition: sx.h:352
#define WS_OPCODE_PONG
Definition: websocket.c:42
unsigned int fin
Definition: websocket.c:67
int want_write
Definition: sx.h:306
spool spool_new(pool_t p)
Definition: str.c:119
#define WS_FRAGMENT_FIN
Definition: websocket.c:44
#define WS_OPCODE_PING
Definition: websocket.c:41
void ** plugin_data
Definition: sx.h:330
#define MASK_LENGTH
Definition: websocket.c:34