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