]> jfr.im git - solanum.git/blob - wsockd/wsockd.c
librb: define UINT32_MAX for FreeBSD 4.8
[solanum.git] / wsockd / wsockd.c
1 /*
2 * wsockd.c: charybdis websockets helper
3 * Copyright (C) 2007 Aaron Sethman <androsyn@ratbox.org>
4 * Copyright (C) 2007 ircd-ratbox development team
5 * Copyright (C) 2016 William Pitcock <nenolod@dereferenced.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
20 * USA
21 */
22
23 #include "stdinc.h"
24 #include "sha1.h"
25
26 #define MAXPASSFD 4
27 #ifndef READBUF_SIZE
28 #define READBUF_SIZE 16384
29 #endif
30
31 #define WEBSOCKET_SERVER_KEY "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
32 #define WEBSOCKET_ANSWER_STRING_1 "HTTP/1.1 101 Switching Protocols\r\nAccess-Control-Allow-Origin: *\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "
33 #define WEBSOCKET_ANSWER_STRING_2 "\r\n\r\n"
34
35 static void setup_signals(void);
36 static pid_t ppid;
37
38 static inline uint32_t
39 buf_to_uint32(uint8_t *buf)
40 {
41 uint32_t x;
42 memcpy(&x, buf, sizeof(x));
43 return x;
44 }
45
46 static inline void
47 uint32_to_buf(uint8_t *buf, uint32_t x)
48 {
49 memcpy(buf, &x, sizeof(x));
50 return;
51 }
52
53 typedef struct _mod_ctl_buf
54 {
55 rb_dlink_node node;
56 uint8_t *buf;
57 size_t buflen;
58 rb_fde_t *F[MAXPASSFD];
59 int nfds;
60 } mod_ctl_buf_t;
61
62 typedef struct _mod_ctl
63 {
64 rb_dlink_node node;
65 int cli_count;
66 rb_fde_t *F;
67 rb_fde_t *F_pipe;
68 rb_dlink_list readq;
69 rb_dlink_list writeq;
70 } mod_ctl_t;
71
72 static mod_ctl_t *mod_ctl;
73
74 typedef struct _conn
75 {
76 rb_dlink_node node;
77 mod_ctl_t *ctl;
78
79 rawbuf_head_t *modbuf_out;
80 rawbuf_head_t *modbuf_in;
81
82 buf_head_t plainbuf_out;
83 buf_head_t plainbuf_in;
84
85 uint32_t id;
86
87 rb_fde_t *mod_fd;
88 rb_fde_t *plain_fd;
89 uint64_t mod_out;
90 uint64_t mod_in;
91 uint64_t plain_in;
92 uint64_t plain_out;
93 uint8_t flags;
94
95 char client_key[37]; /* maximum 36 bytes + nul */
96 } conn_t;
97
98 #define WEBSOCKET_OPCODE_CONTINUATION_FRAME 0
99 #define WEBSOCKET_OPCODE_TEXT_FRAME 1
100 #define WEBSOCKET_OPCODE_BINARY_FRAME 2
101 #define WEBSOCKET_OPCODE_CLOSE_FRAME 8
102 #define WEBSOCKET_OPCODE_PING_FRAME 9
103 #define WEBSOCKET_OPCODE_PONG_FRAME 10
104
105 #define WEBSOCKET_MASK_LENGTH 4
106
107 #define WEBSOCKET_MAX_UNEXTENDED_PAYLOAD_DATA_LENGTH 125
108
109 typedef struct {
110 uint8_t opcode_rsv_fin; // opcode: 4, rsv1: 1, rsv2: 1, rsv3: 1, fin: 1
111 uint8_t payload_length_mask; // payload_length: 7, mask: 1
112 } ws_frame_hdr_t;
113
114 typedef struct {
115 ws_frame_hdr_t header;
116 uint8_t payload_data[WEBSOCKET_MAX_UNEXTENDED_PAYLOAD_DATA_LENGTH];
117 } ws_frame_payload_t;
118
119 typedef struct {
120 ws_frame_hdr_t header;
121 } ws_frame_t;
122
123 typedef struct {
124 ws_frame_hdr_t header;
125 uint16_t payload_length_extended;
126 } ws_frame_ext_t;
127
128 typedef struct {
129 ws_frame_hdr_t header;
130 uint64_t payload_length_extended;
131 } ws_frame_ext2_t;
132
133 static inline int
134 ws_frame_get_opcode(ws_frame_hdr_t *header)
135 {
136 return header->opcode_rsv_fin & 0xF;
137 }
138
139 static inline void
140 ws_frame_set_opcode(ws_frame_hdr_t *header, int opcode)
141 {
142 header->opcode_rsv_fin &= ~0xF;
143 header->opcode_rsv_fin |= opcode & 0xF;
144 }
145
146 static inline int
147 ws_frame_get_fin(ws_frame_hdr_t *header)
148 {
149 return (header->opcode_rsv_fin >> 7) & 0x1;
150 }
151
152 static inline void
153 ws_frame_set_fin(ws_frame_hdr_t *header, int fin)
154 {
155 header->opcode_rsv_fin &= ~(0x1 << 7);
156 header->opcode_rsv_fin |= (fin << 7) & (0x1 << 7);
157 }
158
159 static void close_conn(conn_t * conn, int wait_plain, const char *fmt, ...);
160 static void conn_mod_read_cb(rb_fde_t *fd, void *data);
161 static void conn_plain_read_cb(rb_fde_t *fd, void *data);
162 static void conn_plain_process_recvq(conn_t *conn);
163
164 #define FLAG_CORK 0x01
165 #define FLAG_DEAD 0x02
166 #define FLAG_WSOCK 0x04
167 #define FLAG_KEYED 0x08
168
169 #define IsCork(x) ((x)->flags & FLAG_CORK)
170 #define IsDead(x) ((x)->flags & FLAG_DEAD)
171 #define IsWS(x) ((x)->flags & FLAG_WSOCK)
172 #define IsKeyed(x) ((x)->flags & FLAG_KEYED)
173
174 #define SetCork(x) ((x)->flags |= FLAG_CORK)
175 #define SetDead(x) ((x)->flags |= FLAG_DEAD)
176 #define SetWS(x) ((x)->flags |= FLAG_WSOCK)
177 #define SetKeyed(x) ((x)->flags |= FLAG_KEYED)
178
179 #define ClearCork(x) ((x)->flags &= ~FLAG_CORK)
180 #define ClearDead(x) ((x)->flags &= ~FLAG_DEAD)
181 #define ClearWS(x) ((x)->flags &= ~FLAG_WSOCK)
182 #define ClearKeyed(x) ((x)->flags &= ~FLAG_KEYED)
183
184 #define NO_WAIT 0x0
185 #define WAIT_PLAIN 0x1
186
187 #define HASH_WALK_SAFE(i, max, ptr, next, table) for(i = 0; i < max; i++) { RB_DLINK_FOREACH_SAFE(ptr, next, table[i].head)
188 #define HASH_WALK_END }
189 #define CONN_HASH_SIZE 2000
190 #define connid_hash(x) (&connid_hash_table[(x % CONN_HASH_SIZE)])
191
192 static const char *remote_closed = "Remote host closed the connection";
193
194 static rb_dlink_list connid_hash_table[CONN_HASH_SIZE];
195 static rb_dlink_list dead_list;
196
197 static void conn_plain_read_shutdown_cb(rb_fde_t *fd, void *data);
198
199 #ifndef _WIN32
200 static void
201 dummy_handler(int sig)
202 {
203 return;
204 }
205 #endif
206
207 static void
208 setup_signals()
209 {
210 #ifndef _WIN32
211 struct sigaction act;
212
213 act.sa_flags = 0;
214 act.sa_handler = SIG_IGN;
215 sigemptyset(&act.sa_mask);
216 sigaddset(&act.sa_mask, SIGPIPE);
217 sigaddset(&act.sa_mask, SIGALRM);
218 #ifdef SIGTRAP
219 sigaddset(&act.sa_mask, SIGTRAP);
220 #endif
221
222 #ifdef SIGWINCH
223 sigaddset(&act.sa_mask, SIGWINCH);
224 sigaction(SIGWINCH, &act, 0);
225 #endif
226 sigaction(SIGPIPE, &act, 0);
227 #ifdef SIGTRAP
228 sigaction(SIGTRAP, &act, 0);
229 #endif
230
231 act.sa_handler = dummy_handler;
232 sigaction(SIGALRM, &act, 0);
233 #endif
234 }
235
236 static int
237 maxconn(void)
238 {
239 #if defined(RLIMIT_NOFILE) && defined(HAVE_SYS_RESOURCE_H)
240 struct rlimit limit;
241
242 if(!getrlimit(RLIMIT_NOFILE, &limit))
243 {
244 return limit.rlim_cur;
245 }
246 #endif /* RLIMIT_FD_MAX */
247 return MAXCONNECTIONS;
248 }
249
250 static conn_t *
251 conn_find_by_id(uint32_t id)
252 {
253 rb_dlink_node *ptr;
254 conn_t *conn;
255
256 RB_DLINK_FOREACH(ptr, (connid_hash(id))->head)
257 {
258 conn = ptr->data;
259 if(conn->id == id && !IsDead(conn))
260 return conn;
261 }
262 return NULL;
263 }
264
265 static void
266 conn_add_id_hash(conn_t * conn, uint32_t id)
267 {
268 conn->id = id;
269 rb_dlinkAdd(conn, &conn->node, connid_hash(id));
270 }
271
272 static void
273 free_conn(conn_t * conn)
274 {
275 rb_linebuf_donebuf(&conn->plainbuf_in);
276 rb_linebuf_donebuf(&conn->plainbuf_out);
277
278 rb_free_rawbuffer(conn->modbuf_in);
279 rb_free_rawbuffer(conn->modbuf_out);
280
281 rb_free(conn);
282 }
283
284 static void
285 clean_dead_conns(void *unused)
286 {
287 conn_t *conn;
288 rb_dlink_node *ptr, *next;
289
290 RB_DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
291 {
292 conn = ptr->data;
293 free_conn(conn);
294 }
295
296 dead_list.tail = dead_list.head = NULL;
297 }
298
299 static void
300 conn_plain_write_sendq(rb_fde_t *fd, void *data)
301 {
302 conn_t *conn = data;
303 int retlen;
304
305 if(IsDead(conn))
306 return;
307
308 while((retlen = rb_linebuf_flush(fd, &conn->plainbuf_out)) > 0)
309 conn->plain_out += retlen;
310
311 if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
312 {
313 close_conn(data, NO_WAIT, NULL);
314 return;
315 }
316
317 if(rb_linebuf_alloclen(&conn->plainbuf_out) > 0)
318 rb_setselect(conn->plain_fd, RB_SELECT_WRITE, conn_plain_write_sendq, conn);
319 else
320 rb_setselect(conn->plain_fd, RB_SELECT_WRITE, NULL, NULL);
321 }
322
323 static void
324 conn_mod_write_sendq(rb_fde_t *fd, void *data)
325 {
326 conn_t *conn = data;
327 const char *err;
328 int retlen;
329
330 if(IsDead(conn))
331 return;
332
333 while((retlen = rb_rawbuf_flush(conn->modbuf_out, fd)) > 0)
334 conn->mod_out += retlen;
335
336 if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
337 {
338 if(retlen == 0)
339 close_conn(conn, WAIT_PLAIN, "%s", remote_closed);
340 err = strerror(errno);
341 close_conn(conn, WAIT_PLAIN, "Write error: %s", err);
342 return;
343 }
344
345 if(rb_rawbuf_length(conn->modbuf_out) > 0)
346 rb_setselect(conn->mod_fd, RB_SELECT_WRITE, conn_mod_write_sendq, conn);
347 else
348 rb_setselect(conn->mod_fd, RB_SELECT_WRITE, NULL, NULL);
349
350 if(IsCork(conn) && rb_rawbuf_length(conn->modbuf_out) == 0)
351 {
352 ClearCork(conn);
353 conn_plain_read_cb(conn->plain_fd, conn);
354 }
355 }
356
357 static void
358 conn_mod_write(conn_t * conn, void *data, size_t len)
359 {
360 if(IsDead(conn)) /* no point in queueing to a dead man */
361 return;
362 rb_rawbuf_append(conn->modbuf_out, data, len);
363 }
364
365 static void
366 conn_mod_write_short_frame(conn_t * conn, void *data, int len)
367 {
368 ws_frame_hdr_t hdr;
369
370 ws_frame_set_opcode(&hdr, WEBSOCKET_OPCODE_TEXT_FRAME);
371 ws_frame_set_fin(&hdr, 1);
372 hdr.payload_length_mask = (len + 2) & 0x7f;
373
374 conn_mod_write(conn, &hdr, sizeof(hdr));
375 conn_mod_write(conn, data, len);
376 conn_mod_write(conn, "\r\n", 2);
377 }
378
379 static void
380 conn_mod_write_long_frame(conn_t * conn, void *data, int len)
381 {
382 ws_frame_ext_t hdr;
383
384 ws_frame_set_opcode(&hdr.header, WEBSOCKET_OPCODE_TEXT_FRAME);
385 ws_frame_set_fin(&hdr.header, 1);
386 hdr.header.payload_length_mask = 126;
387 hdr.payload_length_extended = htons(len + 2);
388
389 conn_mod_write(conn, &hdr, sizeof(hdr));
390 conn_mod_write(conn, data, len);
391 conn_mod_write(conn, "\r\n", 2);
392 }
393
394 static void
395 conn_mod_write_frame(conn_t *conn, void *data, int len)
396 {
397 if(IsDead(conn)) /* no point in queueing to a dead man */
398 return;
399
400 if (len < 123)
401 return conn_mod_write_short_frame(conn, data, len);
402
403 return conn_mod_write_long_frame(conn, data, len);
404 }
405
406 static void
407 conn_plain_write(conn_t * conn, void *data, size_t len)
408 {
409 if(IsDead(conn)) /* again no point in queueing to dead men */
410 return;
411 rb_linebuf_put(&conn->plainbuf_out, data, len);
412 }
413
414 static void
415 mod_write_ctl(rb_fde_t *F, void *data)
416 {
417 mod_ctl_t *ctl = data;
418 mod_ctl_buf_t *ctl_buf;
419 rb_dlink_node *ptr, *next;
420 int retlen, x;
421
422 RB_DLINK_FOREACH_SAFE(ptr, next, ctl->writeq.head)
423 {
424 ctl_buf = ptr->data;
425 retlen = rb_send_fd_buf(ctl->F, ctl_buf->F, ctl_buf->nfds, ctl_buf->buf,
426 ctl_buf->buflen, ppid);
427 if(retlen > 0)
428 {
429 rb_dlinkDelete(ptr, &ctl->writeq);
430 for(x = 0; x < ctl_buf->nfds; x++)
431 rb_close(ctl_buf->F[x]);
432 rb_free(ctl_buf->buf);
433 rb_free(ctl_buf);
434
435 }
436 if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
437 exit(0);
438
439 }
440 if(rb_dlink_list_length(&ctl->writeq) > 0)
441 rb_setselect(ctl->F, RB_SELECT_WRITE, mod_write_ctl, ctl);
442 }
443
444 static void
445 mod_cmd_write_queue(mod_ctl_t * ctl, const void *data, size_t len)
446 {
447 mod_ctl_buf_t *ctl_buf;
448 ctl_buf = rb_malloc(sizeof(mod_ctl_buf_t));
449 ctl_buf->buf = rb_malloc(len);
450 ctl_buf->buflen = len;
451 memcpy(ctl_buf->buf, data, len);
452 ctl_buf->nfds = 0;
453 rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->writeq);
454 mod_write_ctl(ctl->F, ctl);
455 }
456
457 static void
458 close_conn(conn_t * conn, int wait_plain, const char *fmt, ...)
459 {
460 va_list ap;
461 char reason[128]; /* must always be under 250 bytes */
462 uint8_t buf[256];
463 int len;
464 if(IsDead(conn))
465 return;
466
467 if (IsKeyed(conn))
468 conn_plain_process_recvq(conn);
469
470 rb_rawbuf_flush(conn->modbuf_out, conn->mod_fd);
471 rb_linebuf_flush(conn->plain_fd, &conn->plainbuf_out);
472 rb_close(conn->mod_fd);
473 SetDead(conn);
474
475 rb_dlinkDelete(&conn->node, connid_hash(conn->id));
476
477 if(!wait_plain || fmt == NULL)
478 {
479 rb_close(conn->plain_fd);
480 rb_dlinkAdd(conn, &conn->node, &dead_list);
481 return;
482 }
483
484 rb_setselect(conn->plain_fd, RB_SELECT_READ, conn_plain_read_shutdown_cb, conn);
485 rb_setselect(conn->plain_fd, RB_SELECT_WRITE, NULL, NULL);
486
487 va_start(ap, fmt);
488 vsnprintf(reason, sizeof(reason), fmt, ap);
489 va_end(ap);
490
491 buf[0] = 'D';
492 uint32_to_buf(&buf[1], conn->id);
493 rb_strlcpy((char *) &buf[5], reason, sizeof(buf) - 5);
494 len = (strlen(reason) + 1) + 5;
495 mod_cmd_write_queue(conn->ctl, buf, len);
496 }
497
498 static conn_t *
499 make_conn(mod_ctl_t * ctl, rb_fde_t *mod_fd, rb_fde_t *plain_fd)
500 {
501 conn_t *conn = rb_malloc(sizeof(conn_t));
502 conn->ctl = ctl;
503 conn->mod_fd = mod_fd;
504 conn->plain_fd = plain_fd;
505 conn->id = -1;
506 rb_set_nb(mod_fd);
507 rb_set_nb(plain_fd);
508
509 rb_linebuf_newbuf(&conn->plainbuf_in);
510 rb_linebuf_newbuf(&conn->plainbuf_out);
511
512 conn->modbuf_in = rb_new_rawbuffer();
513 conn->modbuf_out = rb_new_rawbuffer();
514
515 return conn;
516 }
517
518 static void
519 cleanup_bad_message(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb)
520 {
521 int i;
522
523 /* XXX should log this somehow */
524 for (i = 0; i < ctlb->nfds; i++)
525 rb_close(ctlb->F[i]);
526 }
527
528 static void
529 ws_frame_unmask(char *msg, int length, uint8_t maskval[WEBSOCKET_MASK_LENGTH])
530 {
531 int i;
532
533 for (i = 0; i < length; i++)
534 msg[i] = msg[i] ^ maskval[i % 4];
535 }
536
537 static void
538 conn_mod_process_frame(conn_t *conn, ws_frame_hdr_t *hdr, int masked)
539 {
540 char msg[WEBSOCKET_MAX_UNEXTENDED_PAYLOAD_DATA_LENGTH];
541 uint8_t maskval[WEBSOCKET_MASK_LENGTH];
542 int dolen;
543
544 /* if we're masked, we get to collect the masking key for this frame */
545 if (masked)
546 {
547 dolen = rb_rawbuf_get(conn->modbuf_in, maskval, sizeof(maskval));
548 if (!dolen)
549 {
550 close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking unmask key");
551 return;
552 }
553 }
554
555 dolen = rb_rawbuf_get(conn->modbuf_in, msg, hdr->payload_length_mask);
556 if (!dolen)
557 {
558 close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking message");
559 return;
560 }
561
562 if (masked)
563 ws_frame_unmask(msg, dolen, maskval);
564
565 rb_linebuf_parse(&conn->plainbuf_out, msg, dolen, 1);
566 }
567
568 static void
569 conn_mod_process_large(conn_t *conn, ws_frame_hdr_t *hdr, int masked)
570 {
571 char msg[READBUF_SIZE];
572 uint16_t msglen;
573 uint8_t maskval[WEBSOCKET_MASK_LENGTH];
574 int dolen;
575
576 memset(msg, 0, sizeof msg);
577
578 dolen = rb_rawbuf_get(conn->modbuf_in, &msglen, sizeof(msglen));
579 if (!dolen)
580 {
581 close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking message size");
582 return;
583 }
584
585 msglen = ntohs(msglen);
586
587 if (masked)
588 {
589 dolen = rb_rawbuf_get(conn->modbuf_in, maskval, sizeof(maskval));
590 if (!dolen)
591 {
592 close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking unmask key");
593 return;
594 }
595 }
596
597 dolen = rb_rawbuf_get(conn->modbuf_in, msg, msglen);
598 if (!dolen)
599 {
600 close_conn(conn, WAIT_PLAIN, "websocket error: fault unpacking message");
601 return;
602 }
603
604 if (masked)
605 ws_frame_unmask(msg, dolen, maskval);
606
607 rb_linebuf_parse(&conn->plainbuf_out, msg, dolen, 1);
608 }
609
610 static void
611 conn_mod_process_huge(conn_t *conn, ws_frame_hdr_t *hdr, int masked)
612 {
613 /* XXX implement me */
614 }
615
616 static void
617 conn_mod_process(conn_t *conn)
618 {
619 ws_frame_hdr_t hdr;
620
621 while (1)
622 {
623 int masked;
624 int dolen = rb_rawbuf_get(conn->modbuf_in, &hdr, sizeof(hdr));
625 if (dolen != sizeof(hdr))
626 break;
627
628 masked = (hdr.payload_length_mask >> 7) == 1;
629
630 hdr.payload_length_mask &= 0x7f;
631 switch (hdr.payload_length_mask)
632 {
633 case 126:
634 conn_mod_process_large(conn, &hdr, masked);
635 break;
636 case 127:
637 conn_mod_process_huge(conn, &hdr, masked);
638 break;
639 default:
640 conn_mod_process_frame(conn, &hdr, masked);
641 break;
642 }
643 }
644
645 conn_plain_write_sendq(conn->plain_fd, conn);
646 }
647
648 static void
649 conn_mod_handshake_process(conn_t *conn)
650 {
651 char inbuf[READBUF_SIZE];
652
653 memset(inbuf, 0, sizeof inbuf);
654
655 while (1)
656 {
657 char *p = NULL;
658
659 int dolen = rb_rawbuf_get(conn->modbuf_in, inbuf, sizeof inbuf);
660 if (!dolen)
661 break;
662
663 if ((p = rb_strcasestr(inbuf, "Sec-WebSocket-Key:")) != NULL)
664 {
665 char *start, *end;
666
667 start = p + strlen("Sec-WebSocket-Key:");
668
669 for (; start < (inbuf + READBUF_SIZE) && *start; start++)
670 {
671 if (*start != ' ' && *start != '\t')
672 break;
673 }
674
675 for (end = start; end < (inbuf + READBUF_SIZE) && *end; end++)
676 {
677 if (*end == '\r' || *end == '\n')
678 {
679 *end = '\0';
680 break;
681 }
682 }
683
684 rb_strlcpy(conn->client_key, start, sizeof(conn->client_key));
685 SetKeyed(conn);
686 }
687 }
688
689 if (IsKeyed(conn))
690 {
691 SHA1 sha1;
692 uint8_t digest[SHA1_DIGEST_LENGTH];
693 char *resp;
694
695 sha1_init(&sha1);
696 sha1_update(&sha1, (uint8_t *) conn->client_key, strlen(conn->client_key));
697 sha1_update(&sha1, (uint8_t *) WEBSOCKET_SERVER_KEY, strlen(WEBSOCKET_SERVER_KEY));
698 sha1_final(&sha1, digest);
699
700 resp = (char *) rb_base64_encode(digest, SHA1_DIGEST_LENGTH);
701
702 conn_mod_write(conn, WEBSOCKET_ANSWER_STRING_1, strlen(WEBSOCKET_ANSWER_STRING_1));
703 conn_mod_write(conn, resp, strlen(resp));
704 conn_mod_write(conn, WEBSOCKET_ANSWER_STRING_2, strlen(WEBSOCKET_ANSWER_STRING_2));
705
706 rb_free(resp);
707 }
708
709 conn_mod_write_sendq(conn->mod_fd, conn);
710 }
711
712 static void
713 conn_mod_read_cb(rb_fde_t *fd, void *data)
714 {
715 char inbuf[READBUF_SIZE];
716
717 memset(inbuf, 0, sizeof inbuf);
718
719 conn_t *conn = data;
720 int length = 0;
721 if (conn == NULL)
722 return;
723
724 if (IsDead(conn))
725 return;
726
727 while (1)
728 {
729 if (IsDead(conn))
730 return;
731
732 length = rb_read(fd, inbuf, sizeof(inbuf));
733
734 if (length < 0)
735 {
736 if (rb_ignore_errno(errno))
737 {
738 rb_setselect(fd, RB_SELECT_READ, conn_mod_read_cb, conn);
739 conn_plain_write_sendq(conn->plain_fd, conn);
740 }
741 else
742 close_conn(conn, NO_WAIT, "Connection closed");
743
744 return;
745 }
746 else if (length == 0)
747 {
748 close_conn(conn, NO_WAIT, "Connection closed");
749 return;
750 }
751
752 rb_rawbuf_append(conn->modbuf_in, inbuf, length);
753 if (!IsKeyed(conn))
754 conn_mod_handshake_process(conn);
755 else
756 conn_mod_process(conn);
757
758 if (length < sizeof(inbuf))
759 {
760 rb_setselect(fd, RB_SELECT_READ, conn_mod_read_cb, conn);
761 return;
762 }
763 }
764 }
765
766 static bool
767 plain_check_cork(conn_t * conn)
768 {
769 if(rb_rawbuf_length(conn->modbuf_out) >= 4096)
770 {
771 /* if we have over 4k pending outbound, don't read until
772 * we've cleared the queue */
773 SetCork(conn);
774 rb_setselect(conn->plain_fd, RB_SELECT_READ, NULL, NULL);
775 /* try to write */
776 if (IsKeyed(conn))
777 conn_mod_write_sendq(conn->mod_fd, conn);
778 return true;
779 }
780
781 return false;
782 }
783
784 static void
785 conn_plain_process_recvq(conn_t *conn)
786 {
787 char inbuf[READBUF_SIZE];
788
789 memset(inbuf, 0, sizeof inbuf);
790
791 while (1)
792 {
793 int dolen = rb_linebuf_get(&conn->plainbuf_in, inbuf, sizeof inbuf, LINEBUF_COMPLETE, LINEBUF_PARSED);
794 if (!dolen)
795 break;
796
797 conn_mod_write_frame(conn, inbuf, dolen);
798 }
799
800 if (IsKeyed(conn))
801 conn_mod_write_sendq(conn->mod_fd, conn);
802 }
803
804 static void
805 conn_plain_read_cb(rb_fde_t *fd, void *data)
806 {
807 char inbuf[READBUF_SIZE];
808
809 memset(inbuf, 0, sizeof inbuf);
810
811 conn_t *conn = data;
812 int length = 0;
813 if(conn == NULL)
814 return;
815
816 if(IsDead(conn))
817 return;
818
819 if(plain_check_cork(conn))
820 return;
821
822 while(1)
823 {
824 if(IsDead(conn))
825 return;
826
827 length = rb_read(conn->plain_fd, inbuf, sizeof(inbuf));
828
829 if(length == 0 || (length < 0 && !rb_ignore_errno(errno)))
830 {
831 close_conn(conn, NO_WAIT, NULL);
832 return;
833 }
834
835 if(length < 0)
836 {
837 rb_setselect(conn->plain_fd, RB_SELECT_READ, conn_plain_read_cb, conn);
838 if (IsKeyed(conn))
839 conn_plain_process_recvq(conn);
840 return;
841 }
842 conn->plain_in += length;
843
844 (void) rb_linebuf_parse(&conn->plainbuf_in, inbuf, length, 0);
845
846 if(IsDead(conn))
847 return;
848 if(plain_check_cork(conn))
849 return;
850 }
851 }
852
853 static void
854 conn_plain_read_shutdown_cb(rb_fde_t *fd, void *data)
855 {
856 char inbuf[READBUF_SIZE];
857 conn_t *conn = data;
858 int length = 0;
859
860 if(conn == NULL)
861 return;
862
863 while(1)
864 {
865 length = rb_read(conn->plain_fd, inbuf, sizeof(inbuf));
866
867 if(length == 0 || (length < 0 && !rb_ignore_errno(errno)))
868 {
869 rb_close(conn->plain_fd);
870 rb_dlinkAdd(conn, &conn->node, &dead_list);
871 return;
872 }
873
874 if(length < 0)
875 {
876 rb_setselect(conn->plain_fd, RB_SELECT_READ, conn_plain_read_shutdown_cb, conn);
877 return;
878 }
879 }
880 }
881
882 static void
883 wsock_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb)
884 {
885 conn_t *conn;
886 uint32_t id;
887
888 conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]);
889
890 id = buf_to_uint32(&ctlb->buf[1]);
891 conn_add_id_hash(conn, id);
892 SetWS(conn);
893
894 if(rb_get_type(conn->mod_fd) & RB_FD_UNKNOWN)
895 rb_set_type(conn->mod_fd, RB_FD_SOCKET);
896
897 if(rb_get_type(conn->plain_fd) == RB_FD_UNKNOWN)
898 rb_set_type(conn->plain_fd, RB_FD_SOCKET);
899
900 conn_mod_read_cb(conn->mod_fd, conn);
901 conn_plain_read_cb(conn->plain_fd, conn);
902 }
903
904 static void
905 mod_process_cmd_recv(mod_ctl_t * ctl)
906 {
907 rb_dlink_node *ptr, *next;
908 mod_ctl_buf_t *ctl_buf;
909
910 RB_DLINK_FOREACH_SAFE(ptr, next, ctl->readq.head)
911 {
912 ctl_buf = ptr->data;
913
914 switch (*ctl_buf->buf)
915 {
916 case 'A':
917 {
918 if (ctl_buf->nfds != 2 || ctl_buf->buflen != 5)
919 {
920 cleanup_bad_message(ctl, ctl_buf);
921 break;
922 }
923 wsock_process(ctl, ctl_buf);
924 break;
925 }
926 default:
927 break;
928 /* Log unknown commands */
929 }
930 rb_dlinkDelete(ptr, &ctl->readq);
931 rb_free(ctl_buf->buf);
932 rb_free(ctl_buf);
933 }
934
935 }
936
937 static void
938 mod_read_ctl(rb_fde_t *F, void *data)
939 {
940 mod_ctl_buf_t *ctl_buf;
941 mod_ctl_t *ctl = data;
942 int retlen;
943 int i;
944
945 do
946 {
947 ctl_buf = rb_malloc(sizeof(mod_ctl_buf_t));
948 ctl_buf->buf = rb_malloc(READBUF_SIZE);
949 ctl_buf->buflen = READBUF_SIZE;
950 retlen = rb_recv_fd_buf(ctl->F, ctl_buf->buf, ctl_buf->buflen, ctl_buf->F,
951 MAXPASSFD);
952 if(retlen <= 0)
953 {
954 rb_free(ctl_buf->buf);
955 rb_free(ctl_buf);
956 }
957 else
958 {
959 ctl_buf->buflen = retlen;
960 rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->readq);
961 for (i = 0; i < MAXPASSFD && ctl_buf->F[i] != NULL; i++)
962 ;
963 ctl_buf->nfds = i;
964 }
965 }
966 while(retlen > 0);
967
968 if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
969 exit(0);
970
971 mod_process_cmd_recv(ctl);
972 rb_setselect(ctl->F, RB_SELECT_READ, mod_read_ctl, ctl);
973 }
974
975 static void
976 read_pipe_ctl(rb_fde_t *F, void *data)
977 {
978 char inbuf[READBUF_SIZE];
979 int retlen;
980 while((retlen = rb_read(F, inbuf, sizeof(inbuf))) > 0)
981 {
982 ;; /* we don't do anything with the pipe really, just care if the other process dies.. */
983 }
984 if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
985 exit(0);
986 rb_setselect(F, RB_SELECT_READ, read_pipe_ctl, NULL);
987 }
988
989 int
990 main(int argc, char **argv)
991 {
992 const char *s_ctlfd, *s_pipe, *s_pid;
993 int ctlfd, pipefd, x, maxfd;
994 maxfd = maxconn();
995
996 s_ctlfd = getenv("CTL_FD");
997 s_pipe = getenv("CTL_PIPE");
998 s_pid = getenv("CTL_PPID");
999
1000 if(s_ctlfd == NULL || s_pipe == NULL || s_pid == NULL)
1001 {
1002 fprintf(stderr,
1003 "This is the charybdis wsockd for internal ircd use.\n");
1004 fprintf(stderr,
1005 "You aren't supposed to run me directly. Exiting.\n");
1006 exit(1);
1007 }
1008
1009 ctlfd = atoi(s_ctlfd);
1010 pipefd = atoi(s_pipe);
1011 ppid = atoi(s_pid);
1012 x = 0;
1013 #ifndef _WIN32
1014 for(x = 0; x < maxfd; x++)
1015 {
1016 if(x != ctlfd && x != pipefd && x > 2)
1017 close(x);
1018 }
1019 x = open("/dev/null", O_RDWR);
1020
1021 if(x >= 0)
1022 {
1023 if(ctlfd != 0 && pipefd != 0)
1024 dup2(x, 0);
1025 if(ctlfd != 1 && pipefd != 1)
1026 dup2(x, 1);
1027 if(ctlfd != 2 && pipefd != 2)
1028 dup2(x, 2);
1029 if(x > 2)
1030 close(x);
1031 }
1032 #endif
1033 setup_signals();
1034 rb_lib_init(NULL, NULL, NULL, 0, maxfd, 1024, 4096);
1035 rb_linebuf_init(4096);
1036 rb_init_rawbuffers(4096);
1037
1038 mod_ctl = rb_malloc(sizeof(mod_ctl_t));
1039 mod_ctl->F = rb_open(ctlfd, RB_FD_SOCKET, "ircd control socket");
1040 mod_ctl->F_pipe = rb_open(pipefd, RB_FD_PIPE, "ircd pipe");
1041 rb_set_nb(mod_ctl->F);
1042 rb_set_nb(mod_ctl->F_pipe);
1043 rb_event_addish("clean_dead_conns", clean_dead_conns, NULL, 10);
1044 read_pipe_ctl(mod_ctl->F_pipe, NULL);
1045 mod_read_ctl(mod_ctl->F, mod_ctl);
1046
1047 rb_lib_loop(0);
1048 return 0;
1049 }