From 096fe6189f03033e7cd25c2260dd8f54ff060ce3 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 28 Apr 2010 21:37:20 +0100 Subject: [PATCH] control stuff compiles --- backends/innduct.c | 191 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 184 insertions(+), 7 deletions(-) diff --git a/backends/innduct.c b/backends/innduct.c index e9da15b..4d5e747 100644 --- a/backends/innduct.c +++ b/backends/innduct.c @@ -201,6 +201,7 @@ perl -ne 'print if m/-8\<-/..m/-\>8-/; print "\f" if m/-\^L-/' backends/innduct. #define INNDCOMMCHILD_ESTATUS_NONESUCH 27 #define MAX_LINE_FEEDFILE (NNTP_MSGID_MAXLEN + sizeof(TOKEN)*2 + 10) +#define MAX_CONTROL_COMMAND 1000 #define VA va_list al; va_start(al,fmt) #define PRINTF(f,a) __attribute__((__format__(printf,f,a))) @@ -480,9 +481,6 @@ static FILE *defer; static InputFile *main_input_file, *flushing_input_file, *backlog_input_file; static int sm_period_counter; -/* control_init initialises */ -static int control_master; - /* initialisation to 0 is good */ static int until_connect, until_backlog_nextscan; static double accept_proportion; @@ -568,7 +566,7 @@ static char *xasprintf(const char *fmt, ...) { } static int close_perhaps(int *fd) { - if (!*fd) return 0; + if (*fd <= 0) return 0; int r= close(*fd); *fd=0; return r; @@ -578,7 +576,7 @@ static void xclose(int fd, const char *what, const char *what2) { if (r) sysdie("close %s%s",what,what2?what2:""); } static void xclose_perhaps(int *fd, const char *what, const char *what2) { - if (!*fd) return; + if (*fd <= 0) return; xclose(*fd,what,what2); *fd=0; } @@ -646,6 +644,11 @@ static time_t xtime(void) { return now; } +static void xsetnonblock(int fd, int nonblocking) { + int errnoval= oop_fd_nonblock(fd, nonblocking); + if (errnoval) { errno= errnoval; sysdie("setnonblocking"); } +} + static void check_isreg(const struct stat *stab, const char *path, const char *what) { if (!S_ISREG(stab->st_mode)) @@ -707,6 +710,175 @@ static int isewouldblock(int errnoval) { /*========== command and control connections ==========*/ +static int control_master; + +typedef struct ControlConn ControlConn; +struct ControlConn { + void (*destroy)(ControlConn*); + int fd; + oop_read *rd; + FILE *out; + union { + struct sockaddr sa; + struct sockaddr_un un; + } sa; + socklen_t salen; +}; + +static const oop_rd_style control_rd_style= { + OOP_RD_DELIM_STRIP, '\n', + OOP_RD_NUL_FORBID, + OOP_RD_SHORTREC_FORBID +}; + +static void control_destroy(ControlConn *cc) { + cc->destroy(cc); +} + +static void control_checkouterr(ControlConn *cc /* may destroy*/) { + if (ferror(cc->out) | fflush(cc->out)) { + info("CTRL%d write error %s", cc->fd, strerror(errno)); + control_destroy(cc); + } +} + +static void control_prompt(ControlConn *cc /* may destroy*/) { + fprintf(cc->out, "%s|", sitename); + control_checkouterr(cc); +} + +typedef struct ControlCommand ControlCommand; +struct ControlCommand { + const char *cmd; + void (*f)(ControlConn *cc, const ControlCommand *ccmd, + const char *arg, size_t argsz); +}; + +static const ControlCommand control_commands[]; + +static void ccmd_help(ControlConn *cc, const ControlCommand *thisccmd, + const char *arg, size_t argsz) { + fputs("commands:\n", cc->out); + const ControlCommand *ccmd; + for (ccmd=control_commands; ccmd->cmd; ccmd++) + fprintf(cc->out, " %s\n", ccmd->cmd); +} + +static const ControlCommand control_commands[]= { + { "h", ccmd_help }, + { 0 } +}; + +static void *control_rd_ok(oop_source *lp, oop_read *oread, oop_rd_event ev, + const char *errmsg, int errnoval, + const char *data, size_t recsz, void *cc_v) { + ControlConn *cc= cc_v; + + if (!data) { + info("CTRL%d closed", cc->fd); + cc->destroy(cc); + return OOP_CONTINUE; + } + + if (recsz == 0) goto prompt; + + const ControlCommand *ccmd; + for (ccmd=control_commands; ccmd->cmd; ccmd++) { + int l= strlen(ccmd->cmd); + if (recsz < l) continue; + if (recsz > l && data[l] != ' ') continue; + if (memcmp(data, ccmd->cmd, l)) continue; + + int argl= (int)recsz - (l+1); + ccmd->f(cc, ccmd, argl>=0 ? data : 0, argl); + goto prompt; + } + + fputs("unknown command; h for help\n", cc->out); + + prompt: + control_prompt(cc); + return OOP_CONTINUE; +} + +static void *control_rd_err(oop_source *lp, oop_read *oread, oop_rd_event ev, + const char *errmsg, int errnoval, + const char *data, size_t recsz, void *cc_v) { + ControlConn *cc= cc_v; + + info("CTRL%d read error %s", cc->fd, errmsg); + cc->destroy(cc); + return OOP_CONTINUE; +} + +static int control_conn_startup(ControlConn *cc /* may destroy*/, + const char *how) { + cc->rd= oop_rd_new_fd(loop, cc->fd, 0,0); + if (!cc->rd) { warn("oop_rd_new_fd control failed"); return -1; } + + int er= oop_rd_read(cc->rd, &control_rd_style, MAX_CONTROL_COMMAND, + control_rd_ok, cc, + control_rd_err, cc); + if (er) { errno= er; syswarn("oop_rd_read control failed"); return -1; } + + info("CTRL%d %s ready", cc->fd, how); + control_prompt(cc); + return 0; +} + +static void control_stdio_destroy(ControlConn *cc) { + if (cc->rd) { + oop_rd_cancel(cc->rd); + errno= oop_rd_delete_tidy(cc->rd); + if (errno) syswarn("oop_rd_delete tidy failed (no-nonblock stdin?)"); + } + free(cc); +} + +static void control_stdio(void) { + ControlConn *cc= xmalloc(sizeof(*cc)); + memset(cc,0,sizeof(*cc)); + cc->destroy= control_stdio_destroy; + + cc->fd= 0; + cc->out= stdout; + int r= control_conn_startup(cc,"stdio"); + if (r) cc->destroy(cc); +} + +static void control_accepted_destroy(ControlConn *cc) { + if (cc->rd) { + oop_rd_cancel(cc->rd); + oop_rd_delete_kill(cc->rd); + } + if (cc->out) { fclose(cc->out); cc->fd=0; } + close_perhaps(&cc->fd); + free(cc); +} + +static void *control_master_readable(oop_source *lp, int master, + oop_event ev, void *u) { + ControlConn *cc= xmalloc(sizeof(*cc)); + memset(cc,0,sizeof(*cc)); + cc->destroy= control_accepted_destroy; + + cc->salen= sizeof(cc->sa); + cc->fd= accept(master, &cc->sa.sa, &cc->salen); + if (cc->fd<0) { syswarn("error accepting control connection"); goto x; } + + cc->out= fdopen(cc->fd, "w"); + if (!cc->out) { syswarn("error fdopening accepted control conn"); goto x; } + + int r= control_conn_startup(cc, "accepted"); + if (r) goto x; + + return OOP_CONTINUE; + + x: + cc->destroy(cc); + return OOP_CONTINUE; +} + #define NOCONTROL(...) do{ \ syswarn("no control socket, because failed to " __VA_ARGS__); \ goto nocontrol; \ @@ -787,7 +959,9 @@ static void control_init(void) { r= listen(control_master, 5); if (r) NOCONTROL("listen"); - //loop->on_fd(loop, control_master, OOP_READ, control_master_readable, 0); + xsetnonblock(control_master, 1); + + loop->on_fd(loop, control_master, OOP_READ, control_master_readable, 0); info("control socket ok, real path %s", sa.un.sun_path); return; @@ -1026,7 +1200,7 @@ static void *connchild_event(oop_source *lp, int fd, oop_event e, void *u) { loop->on_fd(loop, conn->fd, OOP_EXCEPTION, conn_exception, conn); conn->rd= oop_rd_new_fd(loop,conn->fd, 0, 0); /* sets nonblocking, too */ - if (!conn->fd) sysdie("oop_rd_new_fd (fd=%d)",conn->fd); + if (!conn->fd) die("oop_rd_new_fd conn failed (fd=%d)",conn->fd); int r= oop_rd_read(conn->rd, &peer_rd_style, NNTP_STRLEN, &peer_rd_ok, conn, &peer_rd_err, conn); @@ -2968,6 +3142,9 @@ int main(int argc, char **argv) { self_pid= getpid(); if (self_pid==-1) sysdie("getpid"); + if (!become_daemon) + control_stdio(); + statemc_lock(); notice("starting"); -- 2.30.2