2 * sslproc.c: An interface to wsockd
3 * Copyright (C) 2007 Aaron Sethman <androsyn@ratbox.org>
4 * Copyright (C) 2007 ircd-ratbox development team
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
37 static void ws_read_ctl(rb_fde_t
* F
, void *data
);
38 static int wsockd_count
;
40 static char tmpbuf
[READBUF_SIZE
];
41 static char nul
= '\0';
45 typedef struct _ws_ctl_buf
50 rb_fde_t
*F
[MAXPASSFD
];
68 static rb_dlink_list wsock_daemons
;
70 static inline uint32_t
71 buf_to_uint32(char *buf
)
74 memcpy(&x
, buf
, sizeof(x
));
79 uint32_to_buf(char *buf
, uint32_t x
)
81 memcpy(buf
, &x
, sizeof(x
));
86 allocate_ws_daemon(rb_fde_t
* F
, rb_fde_t
* P
, int pid
)
90 if(F
== NULL
|| pid
< 0)
92 ctl
= rb_malloc(sizeof(ws_ctl_t
));
97 rb_dlinkAdd(ctl
, &ctl
->node
, &wsock_daemons
);
102 free_ws_daemon(ws_ctl_t
* ctl
)
105 ws_ctl_buf_t
*ctl_buf
;
110 RB_DLINK_FOREACH(ptr
, ctl
->readq
.head
)
113 for(x
= 0; x
< ctl_buf
->nfds
; x
++)
114 rb_close(ctl_buf
->F
[x
]);
116 rb_free(ctl_buf
->buf
);
120 RB_DLINK_FOREACH(ptr
, ctl
->writeq
.head
)
123 for(x
= 0; x
< ctl_buf
->nfds
; x
++)
124 rb_close(ctl_buf
->F
[x
]);
126 rb_free(ctl_buf
->buf
);
131 rb_dlinkDelete(&ctl
->node
, &wsock_daemons
);
135 static char *wsockd_path
;
137 static int wsockd_spin_count
= 0;
138 static time_t last_spin
;
139 static int wsockd_wait
= 0;
144 rb_dlink_node
*ptr
, *next
;
147 RB_DLINK_FOREACH_SAFE(ptr
, next
, wsock_daemons
.head
)
158 rb_kill(ctl
->pid
, SIGKILL
);
163 start_wsockd(ServerInfo
.wsockd_count
);
170 rb_dlink_node
*ptr
, *next
;
172 RB_DLINK_FOREACH_SAFE(ptr
, next
, wsock_daemons
.head
)
180 rb_kill(ctl
->pid
, SIGKILL
);
188 ws_dead(ws_ctl_t
* ctl
)
194 rb_kill(ctl
->pid
, SIGKILL
); /* make sure the process is really gone */
199 ilog(L_MAIN
, "wsockd helper died - attempting to restart");
200 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "wsockd helper died - attempting to restart");
206 ws_do_pipe(rb_fde_t
* F
, void *data
)
209 ws_ctl_t
*ctl
= data
;
210 retlen
= rb_write(F
, "0", 1);
211 if(retlen
== 0 || (retlen
< 0 && !rb_ignore_errno(errno
)))
216 rb_setselect(F
, RB_SELECT_READ
, ws_do_pipe
, data
);
220 restart_wsockd_event(void *unused
)
222 wsockd_spin_count
= 0;
225 if(ServerInfo
.wsockd_count
> get_wsockd_count())
227 int start
= ServerInfo
.wsockd_count
- get_wsockd_count();
228 ilog(L_MAIN
, "Attempting to restart wsockd processes");
229 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "Attempting to restart wsockd processes");
235 start_wsockd(int count
)
240 const char *suffix
= ".exe";
242 const char *suffix
= "";
245 char fullpath
[PATH_MAX
+ 1];
256 if(wsockd_spin_count
> 20 && (rb_current_time() - last_spin
< 5))
258 ilog(L_MAIN
, "wsockd helper is spinning - will attempt to restart in 1 minute");
259 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
260 "wsockd helper is spinning - will attempt to restart in 1 minute");
261 rb_event_add("restart_wsockd_event", restart_wsockd_event
, NULL
, 60);
267 last_spin
= rb_current_time();
269 if(wsockd_path
== NULL
)
271 snprintf(fullpath
, sizeof(fullpath
), "%s%cwsockd%s", ircd_paths
[IRCD_PATH_LIBEXEC
], RB_PATH_SEPARATOR
, suffix
);
273 if(access(fullpath
, X_OK
) == -1)
275 snprintf(fullpath
, sizeof(fullpath
), "%s%cbin%cwsockd%s",
276 ConfigFileEntry
.dpath
, RB_PATH_SEPARATOR
, RB_PATH_SEPARATOR
, suffix
);
277 if(access(fullpath
, X_OK
) == -1)
280 "Unable to execute wsockd%s in %s or %s/bin",
281 suffix
, ircd_paths
[IRCD_PATH_LIBEXEC
], ConfigFileEntry
.dpath
);
285 wsockd_path
= rb_strdup(fullpath
);
287 rb_strlcpy(buf
, "-ircd wsockd daemon", sizeof(buf
));
291 for(i
= 0; i
< count
; i
++)
294 if(rb_socketpair(AF_UNIX
, SOCK_DGRAM
, 0, &F1
, &F2
, "wsockd handle passing socket") == -1)
296 ilog(L_MAIN
, "Unable to create wsockd - rb_socketpair failed: %s", strerror(errno
));
300 rb_set_buffers(F1
, READBUF_SIZE
);
301 rb_set_buffers(F2
, READBUF_SIZE
);
302 snprintf(fdarg
, sizeof(fdarg
), "%d", rb_get_fd(F2
));
303 rb_setenv("CTL_FD", fdarg
, 1);
304 if(rb_pipe(&P1
, &P2
, "wsockd pipe") == -1)
306 ilog(L_MAIN
, "Unable to create wsockd - rb_pipe failed: %s", strerror(errno
));
309 snprintf(fdarg
, sizeof(fdarg
), "%d", rb_get_fd(P1
));
310 rb_setenv("CTL_PIPE", fdarg
, 1);
311 snprintf(s_pid
, sizeof(s_pid
), "%d", (int)getpid());
312 rb_setenv("CTL_PPID", s_pid
, 1);
315 SetHandleInformation((HANDLE
) rb_get_fd(F2
), HANDLE_FLAG_INHERIT
, 1);
316 SetHandleInformation((HANDLE
) rb_get_fd(P1
), HANDLE_FLAG_INHERIT
, 1);
319 pid
= rb_spawn_process(wsockd_path
, (const char **) parv
);
322 ilog(L_MAIN
, "Unable to create wsockd: %s\n", strerror(errno
));
332 ctl
= allocate_ws_daemon(F1
, P2
, pid
);
333 ws_read_ctl(ctl
->F
, ctl
);
341 ws_process_dead_fd(ws_ctl_t
* ctl
, ws_ctl_buf_t
* ctl_buf
)
343 struct Client
*client_p
;
347 if(ctl_buf
->buflen
< 6)
348 return; /* bogus message..drop it.. XXX should warn here */
350 fd
= buf_to_uint32(&ctl_buf
->buf
[1]);
351 rb_strlcpy(reason
, &ctl_buf
->buf
[5], sizeof(reason
));
352 client_p
= find_cli_connid_hash(fd
);
355 if(IsAnyServer(client_p
) || IsRegistered(client_p
))
357 /* read any last moment ERROR, QUIT or the like -- jilles */
358 if (!strcmp(reason
, "Remote host closed the connection"))
359 read_packet(client_p
->localClient
->F
, client_p
);
360 if (IsAnyDead(client_p
))
363 exit_client(client_p
, client_p
, &me
, reason
);
368 ws_process_cmd_recv(ws_ctl_t
* ctl
)
370 rb_dlink_node
*ptr
, *next
;
371 ws_ctl_buf_t
*ctl_buf
;
377 RB_DLINK_FOREACH_SAFE(ptr
, next
, ctl
->readq
.head
)
380 switch (*ctl_buf
->buf
)
383 ws_process_dead_fd(ctl
, ctl_buf
);
386 ilog(L_MAIN
, "Received invalid command from wsockd: %s", ctl_buf
->buf
);
387 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "Received invalid command from wsockd");
390 rb_dlinkDelete(ptr
, &ctl
->readq
);
391 rb_free(ctl_buf
->buf
);
399 ws_read_ctl(rb_fde_t
* F
, void *data
)
401 ws_ctl_buf_t
*ctl_buf
;
402 ws_ctl_t
*ctl
= data
;
409 ctl_buf
= rb_malloc(sizeof(ws_ctl_buf_t
));
410 ctl_buf
->buf
= rb_malloc(READSIZE
);
411 retlen
= rb_recv_fd_buf(ctl
->F
, ctl_buf
->buf
, READSIZE
, ctl_buf
->F
, 4);
412 ctl_buf
->buflen
= retlen
;
415 rb_free(ctl_buf
->buf
);
419 rb_dlinkAddTail(ctl_buf
, &ctl_buf
->node
, &ctl
->readq
);
423 if(retlen
== 0 || (retlen
< 0 && !rb_ignore_errno(errno
)))
428 ws_process_cmd_recv(ctl
);
429 rb_setselect(ctl
->F
, RB_SELECT_READ
, ws_read_ctl
, ctl
);
435 ws_ctl_t
*ctl
, *lowest
= NULL
;
438 RB_DLINK_FOREACH(ptr
, wsock_daemons
.head
)
450 if(ctl
->cli_count
< lowest
->cli_count
)
458 ws_write_ctl(rb_fde_t
* F
, void *data
)
460 ws_ctl_t
*ctl
= data
;
461 ws_ctl_buf_t
*ctl_buf
;
462 rb_dlink_node
*ptr
, *next
;
468 RB_DLINK_FOREACH_SAFE(ptr
, next
, ctl
->writeq
.head
)
471 /* in theory unix sock_dgram shouldn't ever short write this.. */
472 retlen
= rb_send_fd_buf(ctl
->F
, ctl_buf
->F
, ctl_buf
->nfds
, ctl_buf
->buf
, ctl_buf
->buflen
, ctl
->pid
);
475 rb_dlinkDelete(ptr
, &ctl
->writeq
);
476 for(x
= 0; x
< ctl_buf
->nfds
; x
++)
477 rb_close(ctl_buf
->F
[x
]);
478 rb_free(ctl_buf
->buf
);
482 if(retlen
== 0 || (retlen
< 0 && !rb_ignore_errno(errno
)))
489 rb_setselect(ctl
->F
, RB_SELECT_WRITE
, ws_write_ctl
, ctl
);
495 ws_cmd_write_queue(ws_ctl_t
* ctl
, rb_fde_t
** F
, int count
, const void *buf
, size_t buflen
)
497 ws_ctl_buf_t
*ctl_buf
;
504 ctl_buf
= rb_malloc(sizeof(ws_ctl_buf_t
));
505 ctl_buf
->buf
= rb_malloc(buflen
);
506 memcpy(ctl_buf
->buf
, buf
, buflen
);
507 ctl_buf
->buflen
= buflen
;
509 for(x
= 0; x
< count
&& x
< MAXPASSFD
; x
++)
511 ctl_buf
->F
[x
] = F
[x
];
513 ctl_buf
->nfds
= count
;
514 rb_dlinkAddTail(ctl_buf
, &ctl_buf
->node
, &ctl
->writeq
);
515 ws_write_ctl(ctl
->F
, ctl
);
519 start_wsockd_accept(rb_fde_t
* sslF
, rb_fde_t
* plainF
, uint32_t id
)
528 uint32_to_buf(&buf
[1], id
);
529 ctl
= which_wsockd();
533 ws_cmd_write_queue(ctl
, F
, 2, buf
, sizeof(buf
));
538 wsockd_decrement_clicount(ws_ctl_t
* ctl
)
544 if(ctl
->shutdown
&& !ctl
->cli_count
)
547 rb_kill(ctl
->pid
, SIGKILL
);
549 if(ctl
->dead
&& !ctl
->cli_count
)
556 cleanup_dead_ws(void *unused
)
558 rb_dlink_node
*ptr
, *next
;
560 RB_DLINK_FOREACH_SAFE(ptr
, next
, wsock_daemons
.head
)
563 if(ctl
->dead
&& !ctl
->cli_count
)
571 get_wsockd_count(void)
577 wsockd_foreach_info(void (*func
)(void *data
, pid_t pid
, int cli_count
, enum wsockd_status status
), void *data
)
579 rb_dlink_node
*ptr
, *next
;
581 RB_DLINK_FOREACH_SAFE(ptr
, next
, wsock_daemons
.head
)
584 func(data
, ctl
->pid
, ctl
->cli_count
,
585 ctl
->dead
? WSOCKD_DEAD
:
586 (ctl
->shutdown
? WSOCKD_SHUTDOWN
: WSOCKD_ACTIVE
));
593 rb_event_addish("cleanup_dead_ws", cleanup_dead_ws
, NULL
, 60);