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>
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.
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.
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
27 #define READBUF_SIZE 16384
30 static void setup_signals(void);
33 static inline uint32_t
34 buf_to_uint32(uint8_t *buf
)
37 memcpy(&x
, buf
, sizeof(x
));
42 uint32_to_buf(uint8_t *buf
, uint32_t x
)
44 memcpy(buf
, &x
, sizeof(x
));
48 typedef struct _mod_ctl_buf
53 rb_fde_t
*F
[MAXPASSFD
];
57 typedef struct _mod_ctl
67 static mod_ctl_t
*mod_ctl
;
73 rawbuf_head_t
*modbuf_out
;
74 rawbuf_head_t
*plainbuf_out
;
87 #define FLAG_CORK 0x01
88 #define FLAG_DEAD 0x02
89 #define FLAG_WSOCK 0x04
91 #define IsCork(x) ((x)->flags & FLAG_CORK)
92 #define IsDead(x) ((x)->flags & FLAG_DEAD)
93 #define IsWS(x) ((x)->flags & FLAG_WSOCK)
95 #define SetCork(x) ((x)->flags |= FLAG_CORK)
96 #define SetDead(x) ((x)->flags |= FLAG_DEAD)
97 #define SetWS(x) ((x)->flags |= FLAG_WSOCK)
99 #define ClearCork(x) ((x)->flags &= ~FLAG_CORK)
100 #define ClearDead(x) ((x)->flags &= ~FLAG_DEAD)
101 #define ClearWS(x) ((x)->flags &= ~FLAG_WSOCK)
104 #define WAIT_PLAIN 0x1
106 #define HASH_WALK_SAFE(i, max, ptr, next, table) for(i = 0; i < max; i++) { RB_DLINK_FOREACH_SAFE(ptr, next, table[i].head)
107 #define HASH_WALK_END }
108 #define CONN_HASH_SIZE 2000
109 #define connid_hash(x) (&connid_hash_table[(x % CONN_HASH_SIZE)])
111 static rb_dlink_list connid_hash_table
[CONN_HASH_SIZE
];
112 static rb_dlink_list dead_list
;
114 static void conn_plain_read_shutdown_cb(rb_fde_t
*fd
, void *data
);
118 dummy_handler(int sig
)
128 struct sigaction act
;
131 act
.sa_handler
= SIG_IGN
;
132 sigemptyset(&act
.sa_mask
);
133 sigaddset(&act
.sa_mask
, SIGPIPE
);
134 sigaddset(&act
.sa_mask
, SIGALRM
);
136 sigaddset(&act
.sa_mask
, SIGTRAP
);
140 sigaddset(&act
.sa_mask
, SIGWINCH
);
141 sigaction(SIGWINCH
, &act
, 0);
143 sigaction(SIGPIPE
, &act
, 0);
145 sigaction(SIGTRAP
, &act
, 0);
148 act
.sa_handler
= dummy_handler
;
149 sigaction(SIGALRM
, &act
, 0);
156 #if defined(RLIMIT_NOFILE) && defined(HAVE_SYS_RESOURCE_H)
159 if(!getrlimit(RLIMIT_NOFILE
, &limit
))
161 return limit
.rlim_cur
;
163 #endif /* RLIMIT_FD_MAX */
164 return MAXCONNECTIONS
;
168 conn_find_by_id(uint32_t id
)
173 RB_DLINK_FOREACH(ptr
, (connid_hash(id
))->head
)
176 if(conn
->id
== id
&& !IsDead(conn
))
183 conn_add_id_hash(conn_t
* conn
, uint32_t id
)
186 rb_dlinkAdd(conn
, &conn
->node
, connid_hash(id
));
190 free_conn(conn_t
* conn
)
192 rb_free_rawbuffer(conn
->modbuf_out
);
193 rb_free_rawbuffer(conn
->plainbuf_out
);
198 clean_dead_conns(void *unused
)
201 rb_dlink_node
*ptr
, *next
;
203 RB_DLINK_FOREACH_SAFE(ptr
, next
, dead_list
.head
)
209 dead_list
.tail
= dead_list
.head
= NULL
;
213 mod_write_ctl(rb_fde_t
*F
, void *data
)
215 mod_ctl_t
*ctl
= data
;
216 mod_ctl_buf_t
*ctl_buf
;
217 rb_dlink_node
*ptr
, *next
;
220 RB_DLINK_FOREACH_SAFE(ptr
, next
, ctl
->writeq
.head
)
223 retlen
= rb_send_fd_buf(ctl
->F
, ctl_buf
->F
, ctl_buf
->nfds
, ctl_buf
->buf
,
224 ctl_buf
->buflen
, ppid
);
227 rb_dlinkDelete(ptr
, &ctl
->writeq
);
228 for(x
= 0; x
< ctl_buf
->nfds
; x
++)
229 rb_close(ctl_buf
->F
[x
]);
230 rb_free(ctl_buf
->buf
);
234 if(retlen
== 0 || (retlen
< 0 && !rb_ignore_errno(errno
)))
238 if(rb_dlink_list_length(&ctl
->writeq
) > 0)
239 rb_setselect(ctl
->F
, RB_SELECT_WRITE
, mod_write_ctl
, ctl
);
243 mod_cmd_write_queue(mod_ctl_t
* ctl
, const void *data
, size_t len
)
245 mod_ctl_buf_t
*ctl_buf
;
246 ctl_buf
= rb_malloc(sizeof(mod_ctl_buf_t
));
247 ctl_buf
->buf
= rb_malloc(len
);
248 ctl_buf
->buflen
= len
;
249 memcpy(ctl_buf
->buf
, data
, len
);
251 rb_dlinkAddTail(ctl_buf
, &ctl_buf
->node
, &ctl
->writeq
);
252 mod_write_ctl(ctl
->F
, ctl
);
256 close_conn(conn_t
* conn
, int wait_plain
, const char *fmt
, ...)
259 char reason
[128]; /* must always be under 250 bytes */
265 rb_rawbuf_flush(conn
->modbuf_out
, conn
->mod_fd
);
266 rb_rawbuf_flush(conn
->plainbuf_out
, conn
->plain_fd
);
267 rb_close(conn
->mod_fd
);
270 rb_dlinkDelete(&conn
->node
, connid_hash(conn
->id
));
272 if(!wait_plain
|| fmt
== NULL
)
274 rb_close(conn
->plain_fd
);
275 rb_dlinkAdd(conn
, &conn
->node
, &dead_list
);
279 rb_setselect(conn
->plain_fd
, RB_SELECT_READ
, conn_plain_read_shutdown_cb
, conn
);
280 rb_setselect(conn
->plain_fd
, RB_SELECT_WRITE
, NULL
, NULL
);
283 vsnprintf(reason
, sizeof(reason
), fmt
, ap
);
287 uint32_to_buf(&buf
[1], conn
->id
);
288 rb_strlcpy((char *) &buf
[5], reason
, sizeof(buf
) - 5);
289 len
= (strlen(reason
) + 1) + 5;
290 mod_cmd_write_queue(conn
->ctl
, buf
, len
);
294 make_conn(mod_ctl_t
* ctl
, rb_fde_t
*mod_fd
, rb_fde_t
*plain_fd
)
296 conn_t
*conn
= rb_malloc(sizeof(conn_t
));
298 conn
->modbuf_out
= rb_new_rawbuffer();
299 conn
->plainbuf_out
= rb_new_rawbuffer();
300 conn
->mod_fd
= mod_fd
;
301 conn
->plain_fd
= plain_fd
;
309 cleanup_bad_message(mod_ctl_t
* ctl
, mod_ctl_buf_t
* ctlb
)
313 /* XXX should log this somehow */
314 for (i
= 0; i
< ctlb
->nfds
; i
++)
315 rb_close(ctlb
->F
[i
]);
319 conn_mod_handshake_cb(rb_fde_t
*fd
, void *data
)
321 char inbuf
[READBUF_SIZE
];
335 length
= rb_read(conn
->plain_fd
, inbuf
, sizeof(inbuf
));
336 if (length
== 0 || (length
< 0 && !rb_ignore_errno(errno
)))
338 close_conn(conn
, NO_WAIT
, "Connection closed");
345 conn_mod_read_cb(rb_fde_t
*fd
, void *data
)
350 conn_plain_read_cb(rb_fde_t
*fd
, void *data
)
355 conn_plain_read_shutdown_cb(rb_fde_t
*fd
, void *data
)
357 char inbuf
[READBUF_SIZE
];
366 length
= rb_read(conn
->plain_fd
, inbuf
, sizeof(inbuf
));
368 if(length
== 0 || (length
< 0 && !rb_ignore_errno(errno
)))
370 rb_close(conn
->plain_fd
);
371 rb_dlinkAdd(conn
, &conn
->node
, &dead_list
);
377 rb_setselect(conn
->plain_fd
, RB_SELECT_READ
, conn_plain_read_shutdown_cb
, conn
);
384 wsock_process(mod_ctl_t
* ctl
, mod_ctl_buf_t
* ctlb
)
389 conn
= make_conn(ctl
, ctlb
->F
[0], ctlb
->F
[1]);
391 id
= buf_to_uint32(&ctlb
->buf
[1]);
392 conn_add_id_hash(conn
, id
);
395 if(rb_get_type(conn
->mod_fd
) & RB_FD_UNKNOWN
)
396 rb_set_type(conn
->mod_fd
, RB_FD_SOCKET
);
398 if(rb_get_type(conn
->plain_fd
) == RB_FD_UNKNOWN
)
399 rb_set_type(conn
->plain_fd
, RB_FD_SOCKET
);
401 conn_mod_handshake_cb(conn
->mod_fd
, conn
);
405 mod_process_cmd_recv(mod_ctl_t
* ctl
)
407 rb_dlink_node
*ptr
, *next
;
408 mod_ctl_buf_t
*ctl_buf
;
410 RB_DLINK_FOREACH_SAFE(ptr
, next
, ctl
->readq
.head
)
414 switch (*ctl_buf
->buf
)
418 if (ctl_buf
->nfds
!= 2 || ctl_buf
->buflen
!= 5)
420 cleanup_bad_message(ctl
, ctl_buf
);
423 wsock_process(ctl
, ctl_buf
);
428 /* Log unknown commands */
430 rb_dlinkDelete(ptr
, &ctl
->readq
);
431 rb_free(ctl_buf
->buf
);
438 mod_read_ctl(rb_fde_t
*F
, void *data
)
440 mod_ctl_buf_t
*ctl_buf
;
441 mod_ctl_t
*ctl
= data
;
447 ctl_buf
= rb_malloc(sizeof(mod_ctl_buf_t
));
448 ctl_buf
->buf
= rb_malloc(READBUF_SIZE
);
449 ctl_buf
->buflen
= READBUF_SIZE
;
450 retlen
= rb_recv_fd_buf(ctl
->F
, ctl_buf
->buf
, ctl_buf
->buflen
, ctl_buf
->F
,
454 rb_free(ctl_buf
->buf
);
459 ctl_buf
->buflen
= retlen
;
460 rb_dlinkAddTail(ctl_buf
, &ctl_buf
->node
, &ctl
->readq
);
461 for (i
= 0; i
< MAXPASSFD
&& ctl_buf
->F
[i
] != NULL
; i
++)
468 if(retlen
== 0 || (retlen
< 0 && !rb_ignore_errno(errno
)))
471 mod_process_cmd_recv(ctl
);
472 rb_setselect(ctl
->F
, RB_SELECT_READ
, mod_read_ctl
, ctl
);
476 read_pipe_ctl(rb_fde_t
*F
, void *data
)
478 char inbuf
[READBUF_SIZE
];
480 while((retlen
= rb_read(F
, inbuf
, sizeof(inbuf
))) > 0)
482 ;; /* we don't do anything with the pipe really, just care if the other process dies.. */
484 if(retlen
== 0 || (retlen
< 0 && !rb_ignore_errno(errno
)))
486 rb_setselect(F
, RB_SELECT_READ
, read_pipe_ctl
, NULL
);
490 main(int argc
, char **argv
)
492 const char *s_ctlfd
, *s_pipe
, *s_pid
;
493 int ctlfd
, pipefd
, x
, maxfd
;
496 s_ctlfd
= getenv("CTL_FD");
497 s_pipe
= getenv("CTL_PIPE");
498 s_pid
= getenv("CTL_PPID");
500 if(s_ctlfd
== NULL
|| s_pipe
== NULL
|| s_pid
== NULL
)
503 "This is the charybdis wsockd for internal ircd use.\n");
505 "You aren't supposed to run me directly. Exiting.\n");
509 ctlfd
= atoi(s_ctlfd
);
510 pipefd
= atoi(s_pipe
);
514 for(x
= 0; x
< maxfd
; x
++)
516 if(x
!= ctlfd
&& x
!= pipefd
&& x
> 2)
519 x
= open("/dev/null", O_RDWR
);
523 if(ctlfd
!= 0 && pipefd
!= 0)
525 if(ctlfd
!= 1 && pipefd
!= 1)
527 if(ctlfd
!= 2 && pipefd
!= 2)
534 rb_lib_init(NULL
, NULL
, NULL
, 0, maxfd
, 1024, 4096);
535 rb_init_rawbuffers(1024);
537 mod_ctl
= rb_malloc(sizeof(mod_ctl_t
));
538 mod_ctl
->F
= rb_open(ctlfd
, RB_FD_SOCKET
, "ircd control socket");
539 mod_ctl
->F_pipe
= rb_open(pipefd
, RB_FD_PIPE
, "ircd pipe");
540 rb_set_nb(mod_ctl
->F
);
541 rb_set_nb(mod_ctl
->F_pipe
);
542 rb_event_addish("clean_dead_conns", clean_dead_conns
, NULL
, 10);
543 read_pipe_ctl(mod_ctl
->F_pipe
, NULL
);
544 mod_read_ctl(mod_ctl
->F
, mod_ctl
);