X-Git-Url: https://jfr.im/git/irc/quakenet/newserv.git/blobdiff_plain/cf7ac0498e16225bd806871da7e6c63fc699a6f8..b64178fecdb1595793ca0c222284f19ef64ec937:/nterfacer/nterfacer.c diff --git a/nterfacer/nterfacer.c b/nterfacer/nterfacer.c index 70e9ed41..5efe8d97 100644 --- a/nterfacer/nterfacer.c +++ b/nterfacer/nterfacer.c @@ -23,6 +23,7 @@ #include "../core/config.h" #include "../core/events.h" #include "../lib/version.h" +#include "../core/schedule.h" #include "nterfacer.h" #include "logging.h" @@ -42,6 +43,7 @@ struct permitted *permits; int permit_count = 0; int ping_handler(struct rline *ri, int argc, char **argv); +static void nterfacer_sendcallback(struct rline *ri, int error, char *buf); void _init(void) { int loaded; @@ -50,12 +52,10 @@ void _init(void) { nrl = nterface_open_log("nterfacer", "logs/nterfacer.log", debug_mode); loaded = load_permits(); - if(!loaded) { - nterface_log(nrl, NL_ERROR, "No permits loaded successfully."); + nterface_log(nrl, NL_INFO, "Loaded %d permit%s successfully.", loaded, loaded==1?"":"s"); + + if(!loaded) return; - } else { - nterface_log(nrl, NL_INFO, "Loaded %d permit%s successfully.", loaded, loaded==1?"":"s"); - } nterfacer_events.on_accept = nterfacer_accept_event; nterfacer_events.on_line = nterfacer_line_event; @@ -82,6 +82,29 @@ void _init(void) { } void free_handler(struct handler *hp) { + struct rline *li, *pi = NULL; + + for(li=rlines;li;) { + if(li->handler == hp) { + if(li->socket) { + esocket_write_line(li->socket, "%d,OE%d,%s", li->id, BF_UNLOADED, "Service was unloaded."); + } else if(li->callback) { + nterfacer_sendcallback(li, BF_UNLOADED, "Service was unloaded."); + } + if(pi) { + pi->next = li->next; + ntfree(li); + li = pi->next; + } else { + rlines = li->next; + ntfree(li); + li = rlines; + } + } else { + pi=li,li=li->next; + } + } + freesstring(hp->command); ntfree(hp); } @@ -142,10 +165,8 @@ int load_permits(void) { hostnamesa = getconfigitems("nterfacer", "hostname"); passwordsa = getconfigitems("nterfacer", "password"); - if(!hostnamesa || !passwordsa) { - nterface_log(nrl, NL_ERROR, "Unable to load hostnames/passwords."); + if(!hostnamesa || !passwordsa) return 0; - } if(hostnamesa->cursi != passwordsa->cursi) { nterface_log(nrl, NL_ERROR, "Different number of hostnames/passwords in config file."); return 0; @@ -168,7 +189,7 @@ int load_permits(void) { continue; } - item->ihost = (*(struct in_addr *)host->h_addr).s_addr; + item->ihost = (*(struct in_addr *)host->h_addr_list[0]).s_addr; for(j=0;jihost) { nterface_log(nrl, NL_WARNING, "Host with items %d and %d is identical, dropping item %d.", j + 1, i + 1, i + 1); @@ -230,6 +251,7 @@ int setup_listening_socket(void) { if(bind(fd, (struct sockaddr *) &sin, sizeof(sin))) { nterface_log(nrl, NL_ERROR, "Unable to bind listen socket (%d).", errno); + close(fd); return -1; } @@ -237,6 +259,7 @@ int setup_listening_socket(void) { if(ioctl(fd, FIONBIO, &opt)) { nterface_log(nrl, NL_ERROR, "Unable to set listen socket non-blocking."); + close(fd); return -1; } @@ -300,7 +323,6 @@ void deregister_handler(struct handler *hl) { void deregister_service(struct service_node *service) { struct service_node *sp, *lp = NULL; - struct rline *li, *pi = NULL; for(sp=tree;sp;lp=sp,sp=sp->next) { if(sp == service) { @@ -318,21 +340,6 @@ void deregister_service(struct service_node *service) { free_handlers(service); - for(li=rlines;li;) { - if(li->service == service) { - if(pi) { - pi->next = li->next; - ntfree(li); - li = pi->next; - } else { - rlines = li->next; - ntfree(li); - li = rlines; - } - } else { - pi=li,li=li->next; - } - } freesstring(service->name); ntfree(service); @@ -354,6 +361,7 @@ void nterfacer_accept_event(struct esocket *socket) { if(ioctl(newfd, FIONBIO, &opt)) { nterface_log(nrl, NL_ERROR, "Unable to set accepted socket non-blocking."); + close(newfd); return; } @@ -548,7 +556,7 @@ int nterfacer_new_rline(char *line, struct esocket *socket, int *number) { if(*p == ',') break; - if(!*p || !(p + 1)) + if(!*p || !*(p + 1)) return RE_BAD_LINE; *p = '\0'; @@ -597,7 +605,6 @@ int nterfacer_new_rline(char *line, struct esocket *socket, int *number) { if(argcount) { parsebuf = (char *)ntmalloc(strlen(pp) + 1); MemCheckR(parsebuf, RE_MEM_ERROR); - newp = parsebuf; for(newp=args[0]=parsebuf,pp++;*pp;pp++) { if((*pp == '\\') && *(pp + 1)) { @@ -642,6 +649,7 @@ int nterfacer_new_rline(char *line, struct esocket *socket, int *number) { prequest->id = *number; prequest->next = rlines; prequest->socket = socket; + prequest->callback = NULL; rlines = prequest; re = (hl->function)(prequest, argcount, args); @@ -706,7 +714,7 @@ int ri_error(struct rline *li, int error_code, char *format, ...) { va_list ap; int retval = RE_OK; - if(li->socket) { + if(li->socket || li->callback) { va_start(ap, format); vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); @@ -714,9 +722,15 @@ int ri_error(struct rline *li, int error_code, char *format, ...) { for(tp=escapedbuf,p=buf;*p||(*tp='\0');*tp++=*p++) if((*p == ',') || (*p == '\\')) *tp++ = '\\'; + if(li->socket) { + if(esocket_write_line(li->socket, "%d,OE%d,%s", li->id, error_code, escapedbuf)) + retval = RE_SOCKET_ERROR; + } else { + if(error_code == 0) /* :P */ + error_code = -10000; - if(esocket_write_line(li->socket, "%d,OE%d,%s", li->id, error_code, escapedbuf)) - retval = RE_SOCKET_ERROR; + nterfacer_sendcallback(li, error_code, escapedbuf); + } } for(pp=rlines;pp;lp=pp,pp=pp->next) { @@ -738,9 +752,12 @@ int ri_final(struct rline *li) { struct rline *pp, *lp = NULL; int retval = RE_OK; - if(li->socket) + if(li->socket) { if(esocket_write_line(li->socket, "%d,OO%s", li->id, li->buf)) retval = RE_SOCKET_ERROR; + } else if(li->callback) { + nterfacer_sendcallback(li, 0, li->buf); + } for(pp=rlines;pp;lp=pp,pp=pp->next) { if(pp == li) { @@ -761,3 +778,149 @@ int ping_handler(struct rline *ri, int argc, char **argv) { ri_append(ri, "OK"); return ri_final(ri); } + +struct sched_rline { + rline rl; + int argc; + handler *hl; + void *schedule; + char argv[]; +}; + +static const int XMAXARGS = 50; + +static void execrline(void *arg) { + struct sched_rline *sr = arg; + int re, i; + char *argv[XMAXARGS], *buf; + + sr->schedule = NULL; + + buf = sr->argv; + for(i=0;iargc;i++) { + argv[i] = buf; + buf+=strlen(buf) + 1; + } + + re = (sr->hl->function)(&sr->rl, sr->argc, argv); + + if(re) + Error("nterfacer", ERR_WARNING, "sendline: error occured calling %p %d: %s", sr->hl->function, re, request_error(re)); +} + +void *nterfacer_sendline(char *service, char *command, int argc, char **argv, rline_callback callback, void *tag) { + struct service_node *servicep; + struct rline *prequest; + struct sched_rline *sr; + struct handler *hl; + int totallen, i; + char *buf; + + for(servicep=tree;servicep;servicep=servicep->next) + if(!strcmp(servicep->name->content, service)) + break; + + if(argc > XMAXARGS) + Error("nterfacer", ERR_STOP, "Over maximum arguments."); + + if(!servicep) { + Error("nterfacer", ERR_WARNING, "sendline: service not found: %s", service); + return NULL; + } + + for(hl=servicep->handlers;hl;hl=hl->next) + if(!strcmp(hl->command->content, command)) + break; + + if(!hl) { + Error("nterfacer", ERR_WARNING, "sendline: command not found: %s", command); + return NULL; + } + + if(argc < hl->args) { + Error("nterfacer", ERR_WARNING, "sendline: wrong number of arguments: %s", command); + return NULL; + } + + /* we have to create a copy of the arguments for reentrancy reasons, grr */ + totallen = 0; + for(i=0;irl; + + sr->argc = argc; + buf = sr->argv; + for(i=0;ihl = hl; + + prequest->service = servicep; + prequest->handler = hl; + prequest->buf[0] = '\0'; + prequest->curpos = prequest->buf; + prequest->tag = tag; + prequest->id = 0; + prequest->socket = NULL; + prequest->callback = callback; + + prequest->next = rlines; + rlines = prequest; + + scheduleoneshot(time(NULL), execrline, sr); + + return (void *)sr; +} + +void nterfacer_freeline(void *tag) { + struct sched_rline *prequest = tag; + + prequest->rl.callback = NULL; + if(prequest->schedule) + deleteschedule(prequest->schedule, execrline, NULL); +} + +#define MAX_LINES 8192 + +/* this bites */ +static void nterfacer_sendcallback(struct rline *ri, int error, char *buf) { + char *lines[MAX_LINES+1]; + char newbuf[MAX_BUFSIZE+5]; + char *s, *d, *laststart; + int linec = 0; + + for(s=buf,laststart=d=newbuf;*s;s++) { + if((*s == '\\') && *(s + 1)) { + if(*(s + 1) == ',') { + *d++ = ','; + } else if(*(s + 1) == '\\') { + *d++ = '\\'; + } + s++; + } else if(*s == ',') { + *d++ = '\0'; + if(linec >= MAX_LINES - 5) { + nterfacer_sendcallback(ri, BF_OVER, "Buffer overflow."); + return; + } + + lines[linec++] = laststart; + laststart = d; + } else { + *d++ = *s; + } + } + *d = '\0'; + lines[linec++] = laststart; + + ri->callback(error, linec, lines, ri->tag); +}