X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fnetwork%2Fserv_network.c;h=7955f5a2eb935ebe4b16336c2f0d51a9653a9a36;hb=e26a8dee20d1726b4995821f717f867f50fc5659;hp=ebac0f6b4de0a4d859316532edc3939efce07804;hpb=7239856720fe09b101458045f7d35fe76e4ce1fe;p=citadel.git diff --git a/citadel/modules/network/serv_network.c b/citadel/modules/network/serv_network.c index ebac0f6b4..7955f5a2e 100644 --- a/citadel/modules/network/serv_network.c +++ b/citadel/modules/network/serv_network.c @@ -1,11 +1,22 @@ /* - * $Id$ - * * This module handles shared rooms, inter-Citadel mail, and outbound * mailing list processing. * - * Copyright (C) 2000-2005 by Art Cancro and others. - * This code is released under the terms of the GNU General Public License. + * Copyright (c) 2000-2011 by the citadel.org team + * + * This program is open source software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * ** NOTE ** A word on the S_NETCONFIGS semaphore: * This is a fairly high-level type of critical section. It ensures that no @@ -44,6 +55,13 @@ # include # endif #endif +#ifdef HAVE_SYSCALL_H +# include +#else +# if HAVE_SYS_SYSCALL_H +# include +# endif +#endif #include #include @@ -54,9 +72,7 @@ #include "citserver.h" #include "support.h" #include "config.h" -#include "room_ops.h" #include "user_ops.h" -#include "policy.h" #include "database.h" #include "msgbase.h" #include "internet_addressing.h" @@ -64,19 +80,18 @@ #include "clientsocket.h" #include "file_ops.h" #include "citadel_dirs.h" +#include "threads.h" #ifndef HAVE_SNPRINTF #include "snprintf.h" #endif +#include "context.h" #include "ctdl_module.h" -/* Nonzero while we are doing network processing */ -static int doing_queue = 0; - /* * When we do network processing, it's accomplished in two passes; one to * gather a list of rooms and one to actually do them. It's ok that rplist @@ -203,14 +218,14 @@ int network_usetable(struct CtdlMessage *msg) { cdbut = cdb_fetch(CDB_USETABLE, msgid, strlen(msgid)); if (cdbut != NULL) { cdb_free(cdbut); + syslog(LOG_DEBUG, "network_usetable() : we already have %s\n", msgid); return(1); } /* If we got to this point, it's unique: add it. */ strcpy(ut.ut_msgid, msgid); ut.ut_timestamp = time(NULL); - cdb_store(CDB_USETABLE, msgid, strlen(msgid), - &ut, sizeof(struct UseTable) ); + cdb_store(CDB_USETABLE, msgid, strlen(msgid), &ut, sizeof(struct UseTable) ); return(0); } @@ -305,7 +320,7 @@ int is_valid_node(char *nexthop, char *secret, char *node) { * First try the neighbor nodes */ if (working_ignetcfg == NULL) { - lprintf(CTDL_ERR, "working_ignetcfg is NULL!\n"); + syslog(LOG_ERR, "working_ignetcfg is NULL!\n"); if (nexthop != NULL) { strcpy(nexthop, ""); } @@ -353,7 +368,7 @@ int is_valid_node(char *nexthop, char *secret, char *node) { /* * If we get to this point, the supplied node name is bogus. */ - lprintf(CTDL_ERR, "Invalid node name <%s>\n", node); + syslog(LOG_ERR, "Invalid node name <%s>\n", node); return(-1); } @@ -362,7 +377,7 @@ int is_valid_node(char *nexthop, char *secret, char *node) { void cmd_gnet(char *argbuf) { - char filename[SIZ]; + char filename[PATH_MAX]; char buf[SIZ]; FILE *fp; @@ -390,10 +405,13 @@ void cmd_gnet(char *argbuf) { void cmd_snet(char *argbuf) { - char tempfilename[SIZ]; - char filename[SIZ]; - char buf[SIZ]; - FILE *fp, *newfp; + char tempfilename[PATH_MAX]; + char filename[PATH_MAX]; + int TmpFD; + StrBuf *Line; + struct stat StatBuf; + long len; + int rc; unbuffer_output(); @@ -402,40 +420,67 @@ void cmd_snet(char *argbuf) { } else if (CtdlAccessCheck(ac_room_aide)) return; - CtdlMakeTempFileName(tempfilename, sizeof tempfilename); - assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir); + len = assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir); + memcpy(tempfilename, filename, len + 1); - fp = fopen(tempfilename, "w"); - if (fp == NULL) { - cprintf("%d Cannot open %s: %s\n", + memset(&StatBuf, 0, sizeof(struct stat)); + if ((stat(filename, &StatBuf) == -1) || (StatBuf.st_size == 0)) + StatBuf.st_size = 80; /* Not there or empty? guess 80 chars line. */ + + sprintf(tempfilename + len, ".%d", CC->cs_pid); + errno = 0; + TmpFD = open(tempfilename, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); + + if ((TmpFD > 0) && (errno == 0)) + { + char *tmp = malloc(StatBuf.st_size * 2); + memset(tmp, ' ', StatBuf.st_size * 2); + rc = write(TmpFD, tmp, StatBuf.st_size * 2); + free(tmp); + if ((rc <= 0) || (rc != StatBuf.st_size * 2)) + { + close(TmpFD); + cprintf("%d Unable to allocate the space required for %s: %s\n", + ERROR + INTERNAL_ERROR, + tempfilename, + strerror(errno)); + unlink(tempfilename); + return; + } + lseek(TmpFD, SEEK_SET, 0); + } + else { + cprintf("%d Unable to allocate the space required for %s: %s\n", ERROR + INTERNAL_ERROR, tempfilename, strerror(errno)); + unlink(tempfilename); + return; } + Line = NewStrBuf(); cprintf("%d %s\n", SEND_LISTING, tempfilename); - while (client_getln(buf, sizeof buf), strcmp(buf, "000")) { - fprintf(fp, "%s\n", buf); + + len = 0; + while (rc = CtdlClientGetLine(Line), + (rc >= 0)) + { + if ((rc == 3) && (strcmp(ChrPtr(Line), "000") == 0)) + break; + StrBufAppendBufPlain(Line, HKEY("\n"), 0); + write(TmpFD, ChrPtr(Line), StrLength(Line)); + len += StrLength(Line); } - fclose(fp); + FreeStrBuf(&Line); + ftruncate(TmpFD, len); + close(TmpFD); /* Now copy the temp file to its permanent location. * (We copy instead of link because they may be on different filesystems) */ begin_critical_section(S_NETCONFIGS); - fp = fopen(tempfilename, "r"); - if (fp != NULL) { - newfp = fopen(filename, "w"); - if (newfp != NULL) { - while (fgets(buf, sizeof buf, fp) != NULL) { - fprintf(newfp, "%s", buf); - } - fclose(newfp); - } - fclose(fp); - } + rename(tempfilename, filename); end_critical_section(S_NETCONFIGS); - unlink(tempfilename); } @@ -451,6 +496,7 @@ void network_deliver_digest(SpoolControl *sc) { size_t recps_len = SIZ; struct recptypes *valid; namelist *nptr; + char bounce_to[256]; if (sc->num_msgs_spooled < 1) { fclose(sc->digestfp); @@ -477,6 +523,15 @@ void network_deliver_digest(SpoolControl *sc) { msg->cm_fields['F'] = strdup(buf); msg->cm_fields['R'] = strdup(buf); + /* Set the 'List-ID' header */ + msg->cm_fields['L'] = malloc(1024); + snprintf(msg->cm_fields['L'], 1024, + "%s <%ld.list-id.%s>", + CC->room.QRname, + CC->room.QRnumber, + config.c_fqdn + ); + /* * Go fetch the contents of the digest */ @@ -486,7 +541,7 @@ void network_deliver_digest(SpoolControl *sc) { msg->cm_fields['M'] = malloc(msglen + 1); fseek(sc->digestfp, 0L, SEEK_SET); fread(msg->cm_fields['M'], (size_t)msglen, 1, sc->digestfp); - msg->cm_fields['M'][msglen] = 0; + msg->cm_fields['M'][msglen] = '\0'; fclose(sc->digestfp); sc->digestfp = NULL; @@ -503,7 +558,7 @@ void network_deliver_digest(SpoolControl *sc) { recps = malloc(recps_len); if (recps == NULL) { - lprintf(CTDL_EMERG, "Cannot allocate %ld bytes for recps...\n", (long)recps_len); + syslog(LOG_EMERG, "Cannot allocate %ld bytes for recps...\n", (long)recps_len); abort(); } @@ -517,10 +572,17 @@ void network_deliver_digest(SpoolControl *sc) { strcat(recps, nptr->name); } + /* Where do we want bounces and other noise to be heard? Surely not the list members! */ + snprintf(bounce_to, sizeof bounce_to, "room_aide@%s", config.c_fqdn); + /* Now submit the message */ valid = validate_recipients(recps, NULL, 0); free(recps); - CtdlSubmitMsg(msg, valid, NULL); + if (valid != NULL) { + valid->bounce_to = strdup(bounce_to); + valid->envelope_from = strdup(bounce_to); + CtdlSubmitMsg(msg, valid, NULL, 0); + } CtdlFreeMessage(msg); free_recipients(valid); } @@ -534,6 +596,7 @@ void network_deliver_list(struct CtdlMessage *msg, SpoolControl *sc) { size_t recps_len = SIZ; struct recptypes *valid; namelist *nptr; + char bounce_to[256]; /* Don't do this if there were no recipients! */ if (sc->listrecps == NULL) return; @@ -550,7 +613,7 @@ void network_deliver_list(struct CtdlMessage *msg, SpoolControl *sc) { recps = malloc(recps_len); if (recps == NULL) { - lprintf(CTDL_EMERG, "Cannot allocate %ld bytes for recps...\n", (long)recps_len); + syslog(LOG_EMERG, "Cannot allocate %ld bytes for recps...\n", (long)recps_len); abort(); } @@ -564,11 +627,18 @@ void network_deliver_list(struct CtdlMessage *msg, SpoolControl *sc) { strcat(recps, nptr->name); } + /* Where do we want bounces and other noise to be heard? Surely not the list members! */ + snprintf(bounce_to, sizeof bounce_to, "room_aide@%s", config.c_fqdn); + /* Now submit the message */ valid = validate_recipients(recps, NULL, 0); free(recps); - CtdlSubmitMsg(msg, valid, NULL); - free_recipients(valid); + if (valid != NULL) { + valid->bounce_to = strdup(bounce_to); + valid->envelope_from = strdup(bounce_to); + CtdlSubmitMsg(msg, valid, NULL, 0); + free_recipients(valid); + } /* Do not call CtdlFreeMessage(msg) here; the caller will free it. */ } @@ -582,13 +652,12 @@ void network_spool_msg(long msgnum, void *userdata) { SpoolControl *sc; int i; char *newpath = NULL; - size_t instr_len = SIZ; struct CtdlMessage *msg = NULL; namelist *nptr; maplist *mptr; struct ser_ret sermsg; FILE *fp; - char filename[SIZ]; + char filename[PATH_MAX]; char buf[SIZ]; int bang = 0; int send = 1; @@ -601,21 +670,75 @@ void network_spool_msg(long msgnum, void *userdata) { /* * Process mailing list recipients */ - instr_len = SIZ; if (sc->listrecps != NULL) { /* Fetch the message. We're going to need to modify it * in order to insert the [list name] in it, etc. */ msg = CtdlFetchMessage(msgnum, 1); if (msg != NULL) { + int rlen; + char *pCh; + StrBuf *Subject, *FlatSubject; + + if (msg->cm_fields['V'] == NULL){ + /* local message, no enVelope */ + StrBuf *Buf; + Buf = NewStrBuf(); + StrBufAppendBufPlain(Buf, msg->cm_fields['O'], -1, 0); + StrBufAppendBufPlain(Buf, HKEY("@"), 0); + StrBufAppendBufPlain(Buf, config.c_fqdn, -1, 0); + + msg->cm_fields['K'] = SmashStrBuf(&Buf); + } + else { + msg->cm_fields['K'] = strdup (msg->cm_fields['V']); + } + /* Set the 'List-ID' header */ + if (msg->cm_fields['L'] != NULL) { + free(msg->cm_fields['L']); + } + msg->cm_fields['L'] = malloc(1024); + snprintf(msg->cm_fields['L'], 1024, + "%s <%ld.list-id.%s>", + CC->room.QRname, + CC->room.QRnumber, + config.c_fqdn + ); /* Prepend "[List name]" to the subject */ if (msg->cm_fields['U'] == NULL) { - msg->cm_fields['U'] = strdup("(no subject)"); + Subject = NewStrBufPlain(HKEY("(no subject)")); } - snprintf(buf, sizeof buf, "[%s] %s", CC->room.QRname, msg->cm_fields['U']); - free(msg->cm_fields['U']); - msg->cm_fields['U'] = strdup(buf); + else { + Subject = NewStrBufPlain(msg->cm_fields['U'], -1); + } + FlatSubject = NewStrBufPlain(NULL, StrLength(Subject)); + StrBuf_RFC822_to_Utf8(FlatSubject, Subject, NULL, NULL); + + rlen = strlen(CC->room.QRname); + pCh = strstr(ChrPtr(FlatSubject), CC->room.QRname); + if ((pCh == NULL) || + (*(pCh + rlen) != ']') || + (pCh == ChrPtr(FlatSubject)) || + (*(pCh - 1) != '[') + ) + { + StrBuf *tmp; + StrBufPlain(Subject, HKEY("[")); + StrBufAppendBufPlain(Subject, CC->room.QRname, rlen, 0); + StrBufAppendBufPlain(Subject, HKEY("] "), 0); + StrBufAppendBuf(Subject, FlatSubject, 0); + tmp = Subject; Subject = FlatSubject; FlatSubject = tmp; /* so we can free the right one... */ + StrBufRFC2047encode(&Subject, FlatSubject); + } + + if (msg->cm_fields['U'] != NULL) + free (msg->cm_fields['U']); + msg->cm_fields['U'] = SmashStrBuf(&Subject); + + FreeStrBuf(&FlatSubject); + + /* else we won't modify the buffer, since the roomname is already here. */ /* Set the recipient of the list message to the * email address of the room itself. @@ -664,20 +787,17 @@ void network_spool_msg(long msgnum, void *userdata) { fprintf(sc->digestfp, "Subject: %s\n", msg->cm_fields['U']); } - CC->redirect_buffer = malloc(SIZ); - CC->redirect_len = 0; - CC->redirect_alloc = SIZ; - + CC->redirect_buffer = NewStrBufPlain(NULL, SIZ); + safestrncpy(CC->preferred_formats, "text/plain", sizeof CC->preferred_formats); - CtdlOutputPreLoadedMsg(msg, MT_CITADEL, HEADERS_NONE, 0, 0); + CtdlOutputPreLoadedMsg(msg, MT_CITADEL, HEADERS_NONE, 0, 0, 0); - striplt(CC->redirect_buffer); - fprintf(sc->digestfp, "\n%s\n", CC->redirect_buffer); + StrBufTrim(CC->redirect_buffer); + fwrite(HKEY("\n"), 1, sc->digestfp); + fwrite(SKEY(CC->redirect_buffer), 1, sc->digestfp); + fwrite(HKEY("\n"), 1, sc->digestfp); - free(CC->redirect_buffer); - CC->redirect_buffer = NULL; - CC->redirect_len = 0; - CC->redirect_alloc = 0; + FreeStrBuf(&CC->redirect_buffer); sc->num_msgs_spooled += 1; free(msg); @@ -687,7 +807,6 @@ void network_spool_msg(long msgnum, void *userdata) { /* * Process client-side list participations for this room */ - instr_len = SIZ; if (sc->participates != NULL) { msg = CtdlFetchMessage(msgnum, 1); if (msg != NULL) { @@ -735,7 +854,7 @@ void network_spool_msg(long msgnum, void *userdata) { msg->cm_fields['R'] = strdup(nptr->name); valid = validate_recipients(nptr->name, NULL, 0); - CtdlSubmitMsg(msg, valid, ""); + CtdlSubmitMsg(msg, valid, "", 0); free_recipients(valid); } @@ -784,19 +903,24 @@ void network_spool_msg(long msgnum, void *userdata) { /* Check for valid node name */ if (is_valid_node(NULL, NULL, mptr->remote_nodename) != 0) { - lprintf(CTDL_ERR, "Invalid node <%s>\n", - mptr->remote_nodename); + syslog(LOG_ERR, "Invalid node <%s>\n", mptr->remote_nodename); send = 0; } /* Check for split horizon */ - lprintf(CTDL_DEBUG, "Path is %s\n", msg->cm_fields['P']); + syslog(LOG_DEBUG, "Path is %s\n", msg->cm_fields['P']); bang = num_tokens(msg->cm_fields['P'], '!'); if (bang > 1) for (i=0; i<(bang-1); ++i) { - extract_token(buf, msg->cm_fields['P'], - i, '!', sizeof buf); + extract_token(buf, msg->cm_fields['P'], i, '!', sizeof buf); + syslog(LOG_DEBUG, "Compare <%s> to <%s>\n", + buf, mptr->remote_nodename) ; if (!strcasecmp(buf, mptr->remote_nodename)) { send = 0; + syslog(LOG_DEBUG, "Not sending to %s\n", + mptr->remote_nodename); + } + else { + syslog(LOG_DEBUG, "Sending to %s\n", mptr->remote_nodename); } } @@ -821,11 +945,14 @@ void network_spool_msg(long msgnum, void *userdata) { serialize_message(&sermsg, msg); if (sermsg.len > 0) { - /* write it to the spool file */ - snprintf(filename, sizeof filename,"%s/%s", - ctdl_netout_dir, - mptr->remote_nodename); - lprintf(CTDL_DEBUG, "Appending to %s\n", filename); + /* write it to a spool file */ + snprintf(filename, sizeof filename,"%s/%s@%lx%x", + ctdl_netout_dir, + mptr->remote_nodename, + time(NULL), + rand() + ); + syslog(LOG_DEBUG, "Appending to %s\n", filename); fp = fopen(filename, "ab"); if (fp != NULL) { fwrite(sermsg.ser, @@ -833,7 +960,7 @@ void network_spool_msg(long msgnum, void *userdata) { fclose(fp); } else { - lprintf(CTDL_ERR, "%s: %s\n", filename, strerror(errno)); + syslog(LOG_ERR, "%s: %s\n", filename, strerror(errno)); } /* free the serialized version */ @@ -863,7 +990,6 @@ int read_spoolcontrol_file(SpoolControl **scc, char *filename) char buf[SIZ]; char nodename[256]; char roomname[ROOMNAMELEN]; - char nexthop[256]; size_t miscsize = 0; size_t linesize = 0; int skipthisline = 0; @@ -883,48 +1009,38 @@ int read_spoolcontrol_file(SpoolControl **scc, char *filename) buf[strlen(buf)-1] = 0; extract_token(instr, buf, 0, '|', sizeof instr); - if (!strcasecmp(instr, "lastsent")) { + if (!strcasecmp(instr, strof(lastsent))) { sc->lastsent = extract_long(buf, 1); } - else if (!strcasecmp(instr, "listrecp")) { + else if (!strcasecmp(instr, strof(listrecp))) { nptr = (namelist *) malloc(sizeof(namelist)); nptr->next = sc->listrecps; extract_token(nptr->name, buf, 1, '|', sizeof nptr->name); sc->listrecps = nptr; } - else if (!strcasecmp(instr, "participate")) { + else if (!strcasecmp(instr, strof(participate))) { nptr = (namelist *) malloc(sizeof(namelist)); nptr->next = sc->participates; extract_token(nptr->name, buf, 1, '|', sizeof nptr->name); sc->participates = nptr; } - else if (!strcasecmp(instr, "digestrecp")) { + else if (!strcasecmp(instr, strof(digestrecp))) { nptr = (namelist *) malloc(sizeof(namelist)); nptr->next = sc->digestrecps; extract_token(nptr->name, buf, 1, '|', sizeof nptr->name); sc->digestrecps = nptr; } - else if (!strcasecmp(instr, "ignet_push_share")) { - /* by checking each node's validity, we automatically - * purge nodes which do not exist from room network - * configurations at this time. - */ + else if (!strcasecmp(instr, strof(ignet_push_share))) { extract_token(nodename, buf, 1, '|', sizeof nodename); extract_token(roomname, buf, 2, '|', sizeof roomname); - strcpy(nexthop, "xxx"); - if (is_valid_node(nexthop, NULL, nodename) == 0) { - if (IsEmptyStr(nexthop)) { - mptr = (maplist *) - malloc(sizeof(maplist)); - mptr->next = sc->ignet_push_shares; - strcpy(mptr->remote_nodename, nodename); - strcpy(mptr->remote_roomname, roomname); - sc->ignet_push_shares = mptr; - } - } + mptr = (maplist *) malloc(sizeof(maplist)); + mptr->next = sc->ignet_push_shares; + strcpy(mptr->remote_nodename, nodename); + strcpy(mptr->remote_roomname, roomname); + sc->ignet_push_shares = mptr; } else { /* Preserve 'other' lines ... *unless* they happen to @@ -932,12 +1048,12 @@ int read_spoolcontrol_file(SpoolControl **scc, char *filename) * timestamps. */ skipthisline = 0; - if (!strncasecmp(buf, "subpending|", 11)) { + if (!strncasecmp(buf, strof(subpending)"|", 11)) { if (time(NULL) - extract_long(buf, 4) > EXP) { skipthisline = 1; } } - if (!strncasecmp(buf, "unsubpending|", 13)) { + if (!strncasecmp(buf, strof(unsubpending)"|", 13)) { if (time(NULL) - extract_long(buf, 3) > EXP) { skipthisline = 1; } @@ -994,67 +1110,97 @@ void free_spoolcontrol_struct(SpoolControl **scc) int writenfree_spoolcontrol_file(SpoolControl **scc, char *filename) { - FILE *fp; + char tempfilename[PATH_MAX]; + int TmpFD; SpoolControl *sc; namelist *nptr = NULL; maplist *mptr = NULL; + long len; + time_t unixtime; + struct timeval tv; + long reltid; /* if we don't have SYS_gettid, use "random" value */ + StrBuf *Cfg; + int rc; + + len = strlen(filename); + memcpy(tempfilename, filename, len + 1); + +#if defined(HAVE_SYSCALL_H) && defined (SYS_gettid) + reltid = syscall(SYS_gettid); +#endif + gettimeofday(&tv, NULL); + /* Promote to time_t; types differ on some OSes (like darwin) */ + unixtime = tv.tv_sec; + + sprintf(tempfilename + len, ".%ld-%ld", reltid, unixtime); sc = *scc; - fp = fopen(filename, "w"); - if (fp == NULL) { - lprintf(CTDL_CRIT, "ERROR: cannot open %s: %s\n", + errno = 0; + TmpFD = open(tempfilename, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); + Cfg = NewStrBuf(); + if ((TmpFD < 0) || (errno != 0)) { + syslog(LOG_CRIT, "ERROR: cannot open %s: %s\n", filename, strerror(errno)); free_spoolcontrol_struct(scc); + unlink(tempfilename); } else { - fprintf(fp, "lastsent|%ld\n", sc->lastsent); - + fchown(TmpFD, config.c_ctdluid, 0); + StrBufAppendPrintf(Cfg, "lastsent|%ld\n", sc->lastsent); + /* Write out the listrecps while freeing from memory at the * same time. Am I clever or what? :) */ while (sc->listrecps != NULL) { - fprintf(fp, "listrecp|%s\n", sc->listrecps->name); + StrBufAppendPrintf(Cfg, "listrecp|%s\n", sc->listrecps->name); nptr = sc->listrecps->next; free(sc->listrecps); sc->listrecps = nptr; } /* Do the same for digestrecps */ while (sc->digestrecps != NULL) { - fprintf(fp, "digestrecp|%s\n", sc->digestrecps->name); + StrBufAppendPrintf(Cfg, "digestrecp|%s\n", sc->digestrecps->name); nptr = sc->digestrecps->next; free(sc->digestrecps); sc->digestrecps = nptr; } /* Do the same for participates */ while (sc->participates != NULL) { - fprintf(fp, "participate|%s\n", sc->participates->name); + StrBufAppendPrintf(Cfg, "participate|%s\n", sc->participates->name); nptr = sc->participates->next; free(sc->participates); sc->participates = nptr; } while (sc->ignet_push_shares != NULL) { - /* by checking each node's validity, we automatically - * purge nodes which do not exist from room network - * configurations at this time. - */ - if (is_valid_node(NULL, NULL, sc->ignet_push_shares->remote_nodename) == 0) { - } - fprintf(fp, "ignet_push_share|%s", - sc->ignet_push_shares->remote_nodename); + StrBufAppendPrintf(Cfg, "ignet_push_share|%s", sc->ignet_push_shares->remote_nodename); if (!IsEmptyStr(sc->ignet_push_shares->remote_roomname)) { - fprintf(fp, "|%s", sc->ignet_push_shares->remote_roomname); + StrBufAppendPrintf(Cfg, "|%s", sc->ignet_push_shares->remote_roomname); } - fprintf(fp, "\n"); + StrBufAppendPrintf(Cfg, "\n"); mptr = sc->ignet_push_shares->next; free(sc->ignet_push_shares); sc->ignet_push_shares = mptr; } if (sc->misc != NULL) { - fwrite(sc->misc, strlen(sc->misc), 1, fp); + StrBufAppendBufPlain(Cfg, sc->misc, -1, 0); } free(sc->misc); - fclose(fp); + rc = write(TmpFD, ChrPtr(Cfg), StrLength(Cfg)); + if ((rc >=0 ) && (rc == StrLength(Cfg))) + { + close(TmpFD); + rename(tempfilename, filename); + } + else { + syslog(LOG_EMERG, + "unable to write %s; [%s]; not enough space on the disk?\n", + tempfilename, + strerror(errno)); + close(TmpFD); + unlink(tempfilename); + } + FreeStrBuf(&Cfg); free(sc); *scc=NULL; } @@ -1095,7 +1241,7 @@ int is_recipient(SpoolControl *sc, const char *Name) */ void network_spoolout_room(char *room_to_spool) { char buf[SIZ]; - char filename[SIZ]; + char filename[PATH_MAX]; SpoolControl *sc; int i; @@ -1104,23 +1250,21 @@ void network_spoolout_room(char *room_to_spool) { * Normally this should never happen, but once in a while maybe a room gets * queued for networking and then deleted before it can happen. */ - if (getroom(&CC->room, room_to_spool) != 0) { - lprintf(CTDL_CRIT, "ERROR: cannot load <%s>\n", room_to_spool); + if (CtdlGetRoom(&CC->room, room_to_spool) != 0) { + syslog(LOG_CRIT, "ERROR: cannot load <%s>\n", room_to_spool); return; } assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir); - - lprintf(CTDL_INFO, "Networking started for <%s>\n", CC->room.QRname); begin_critical_section(S_NETCONFIGS); /* Only do net processing for rooms that have netconfigs */ - if (!read_spoolcontrol_file(&sc, filename)) { end_critical_section(S_NETCONFIGS); return; } + syslog(LOG_INFO, "Networking started for <%s>\n", CC->room.QRname); /* If there are digest recipients, we have to build a digest */ if (sc->digestrecps != NULL) { @@ -1152,7 +1296,7 @@ void network_spoolout_room(char *room_to_spool) { } /* Now rewrite the config file */ - writenfree_spoolcontrol_file (&sc, filename); + writenfree_spoolcontrol_file(&sc, filename); end_critical_section(S_NETCONFIGS); } @@ -1171,7 +1315,7 @@ int network_sync_to(char *target_node) { char sc_type[256]; char sc_node[256]; char sc_room[256]; - char filename[256]; + char filename[PATH_MAX]; FILE *fp; /* Grab the configuration line we're looking for */ @@ -1216,7 +1360,7 @@ int network_sync_to(char *target_node) { /* Concise cleanup because we know there's only one node in the sc */ free(sc.ignet_push_shares); - lprintf(CTDL_NOTICE, "Synchronized %d messages to <%s>\n", + syslog(LOG_NOTICE, "Synchronized %d messages to <%s>\n", num_spooled, target_node); return(num_spooled); } @@ -1335,7 +1479,7 @@ void network_bounce(struct CtdlMessage *msg, char *reason) { static int serialnum = 0; size_t size; - lprintf(CTDL_DEBUG, "entering network_bounce()\n"); + syslog(LOG_DEBUG, "entering network_bounce()\n"); if (msg == NULL) return; @@ -1419,12 +1563,12 @@ void network_bounce(struct CtdlMessage *msg, char *reason) { if ( (valid == NULL) && IsEmptyStr(force_room) ) { strcpy(force_room, config.c_aideroom); } - CtdlSubmitMsg(msg, valid, force_room); + CtdlSubmitMsg(msg, valid, force_room, 0); /* Clean up */ if (valid != NULL) free_recipients(valid); CtdlFreeMessage(msg); - lprintf(CTDL_DEBUG, "leaving network_bounce()\n"); + syslog(LOG_DEBUG, "leaving network_bounce()\n"); } @@ -1442,17 +1586,19 @@ void network_process_buffer(char *buffer, long size) { char target_room[ROOMNAMELEN]; struct ser_ret sermsg; char *oldpath = NULL; - char filename[SIZ]; + char filename[PATH_MAX]; FILE *fp; char nexthop[SIZ]; unsigned char firstbyte; unsigned char lastbyte; + syslog(LOG_DEBUG, "network_process_buffer() processing %ld bytes\n", size); + /* Validate just a little bit. First byte should be FF and * last byte should be 00. */ firstbyte = buffer[0]; lastbyte = buffer[size-1]; if ( (firstbyte != 255) || (lastbyte != 0) ) { - lprintf(CTDL_ERR, "Corrupt message ignored. Length=%ld, firstbyte = %d, lastbyte = %d\n", + syslog(LOG_ERR, "Corrupt message ignored. Length=%ld, firstbyte = %d, lastbyte = %d\n", size, firstbyte, lastbyte); return; } @@ -1479,9 +1625,7 @@ void network_process_buffer(char *buffer, long size) { /* route the message */ strcpy(nexthop, ""); - if (is_valid_node(nexthop, NULL, - msg->cm_fields['D']) == 0) { - + if (is_valid_node(nexthop, NULL, msg->cm_fields['D']) == 0) { /* prepend our node to the path */ if (msg->cm_fields['P'] != NULL) { oldpath = msg->cm_fields['P']; @@ -1504,19 +1648,21 @@ void network_process_buffer(char *buffer, long size) { strcpy(nexthop, msg->cm_fields['D']); } snprintf(filename, - sizeof filename, - "%s/%s", - ctdl_netout_dir, - nexthop); - lprintf(CTDL_DEBUG, "Appending to %s\n", filename); + sizeof filename, + "%s/%s@%lx%x", + ctdl_netout_dir, + nexthop, + time(NULL), + rand() + ); + syslog(LOG_DEBUG, "Appending to %s\n", filename); fp = fopen(filename, "ab"); if (fp != NULL) { - fwrite(sermsg.ser, - sermsg.len, 1, fp); + fwrite(sermsg.ser, sermsg.len, 1, fp); fclose(fp); } else { - lprintf(CTDL_ERR, "%s: %s\n", filename, strerror(errno)); + syslog(LOG_ERR, "%s: %s\n", filename, strerror(errno)); } free(sermsg.ser); CtdlFreeMessage(msg); @@ -1548,17 +1694,14 @@ void network_process_buffer(char *buffer, long size) { /* Learn network topology from the path */ if ((msg->cm_fields['N'] != NULL) && (msg->cm_fields['P'] != NULL)) { - network_learn_topology(msg->cm_fields['N'], - msg->cm_fields['P']); + network_learn_topology(msg->cm_fields['N'], msg->cm_fields['P']); } /* Is the sending node giving us a very persuasive suggestion about * which room this message should be saved in? If so, go with that. */ if (msg->cm_fields['C'] != NULL) { - safestrncpy(target_room, - msg->cm_fields['C'], - sizeof target_room); + safestrncpy(target_room, msg->cm_fields['C'], sizeof target_room); } /* Otherwise, does it have a recipient? If so, validate it... */ @@ -1570,6 +1713,7 @@ void network_process_buffer(char *buffer, long size) { "Please check the address and try sending the message again.\n"); msg = NULL; free_recipients(recp); + syslog(LOG_DEBUG, "Bouncing message due to invalid recipient address.\n"); return; } strcpy(target_room, ""); /* no target room if mail */ @@ -1579,9 +1723,7 @@ void network_process_buffer(char *buffer, long size) { * it has the O field (Originating room) set. */ else if (msg->cm_fields['O'] != NULL) { - safestrncpy(target_room, - msg->cm_fields['O'], - sizeof target_room); + safestrncpy(target_room, msg->cm_fields['O'], sizeof target_room); } /* Strip out fields that are only relevant during transit */ @@ -1597,7 +1739,7 @@ void network_process_buffer(char *buffer, long size) { /* save the message into a room */ if (PerformNetprocHooks(msg, target_room) == 0) { msg->cm_flags = CM_SKIP_HOOKS; - CtdlSubmitMsg(msg, recp, target_room); + CtdlSubmitMsg(msg, recp, target_room, 0); } CtdlFreeMessage(msg); free_recipients(recp); @@ -1617,8 +1759,9 @@ void network_process_message(FILE *fp, long msgstart, long msgend) { buffer = malloc(size); if (buffer != NULL) { fseek(fp, msgstart, SEEK_SET); - fread(buffer, size, 1, fp); - network_process_buffer(buffer, size); + if (fread(buffer, size, 1, fp) > 0) { + network_process_buffer(buffer, size); + } free(buffer); } @@ -1639,12 +1782,12 @@ void network_process_file(char *filename) { fp = fopen(filename, "rb"); if (fp == NULL) { - lprintf(CTDL_CRIT, "Error opening %s: %s\n", filename, strerror(errno)); + syslog(LOG_CRIT, "Error opening %s: %s\n", filename, strerror(errno)); return; } fseek(fp, 0L, SEEK_END); - lprintf(CTDL_INFO, "network: processing %ld bytes from %s\n", ftell(fp), filename); + syslog(LOG_INFO, "network: processing %ld bytes from %s\n", ftell(fp), filename); rewind(fp); /* Look for messages in the data stream and break them out */ @@ -1678,7 +1821,7 @@ void network_do_spoolin(void) { DIR *dp; struct dirent *d; struct stat statbuf; - char filename[256]; + char filename[PATH_MAX]; static time_t last_spoolin_mtime = 0L; /* @@ -1687,11 +1830,11 @@ void network_do_spoolin(void) { */ if (stat(ctdl_netin_dir, &statbuf)) return; if (statbuf.st_mtime == last_spoolin_mtime) { - lprintf(CTDL_DEBUG, "network: nothing in inbound queue\n"); + syslog(LOG_DEBUG, "network: nothing in inbound queue\n"); return; } last_spoolin_mtime = statbuf.st_mtime; - lprintf(CTDL_DEBUG, "network: processing inbound queue\n"); + syslog(LOG_DEBUG, "network: processing inbound queue\n"); /* * Ok, there's something interesting in there, so scan it. @@ -1702,10 +1845,11 @@ void network_do_spoolin(void) { while (d = readdir(dp), d != NULL) { if ((strcmp(d->d_name, ".")) && (strcmp(d->d_name, ".."))) { snprintf(filename, - sizeof filename, - "%s/%s", - ctdl_netin_dir, - d->d_name); + sizeof filename, + "%s/%s", + ctdl_netin_dir, + d->d_name + ); network_process_file(filename); } } @@ -1714,15 +1858,60 @@ void network_do_spoolin(void) { } /* - * Delete any files in the outbound queue that were intended - * to be sent to nodes which no longer exist. + * Step 1: consolidate files in the outbound queue into one file per neighbor node + * Step 2: delete any files in the outbound queue that were for neighbors who no longer exist. */ -void network_purge_spoolout(void) { +void network_consolidate_spoolout(void) { DIR *dp; struct dirent *d; - char filename[256]; + char filename[PATH_MAX]; + char cmd[PATH_MAX]; char nexthop[256]; int i; + char *ptr; + + /* Step 1: consolidate files in the outbound queue into one file per neighbor node */ + dp = opendir(ctdl_netout_dir); + if (dp == NULL) return; + while (d = readdir(dp), d != NULL) { + if ( + (strcmp(d->d_name, ".")) + && (strcmp(d->d_name, "..")) + && (strchr(d->d_name, '@') != NULL) + ) { + safestrncpy(nexthop, d->d_name, sizeof nexthop); + ptr = strchr(nexthop, '@'); + if (ptr) *ptr = 0; + + snprintf(filename, + sizeof filename, + "%s/%s", + ctdl_netout_dir, + d->d_name + ); + + syslog(LOG_DEBUG, "Consolidate %s to %s\n", filename, nexthop); + if (network_talking_to(nexthop, NTT_CHECK)) { + syslog(LOG_DEBUG, + "Currently online with %s - skipping for now\n", + nexthop + ); + } + else { + network_talking_to(nexthop, NTT_ADD); + snprintf(cmd, sizeof cmd, "/bin/cat %s >>%s/%s && /bin/rm -f %s", + filename, + ctdl_netout_dir, nexthop, + filename + ); + system(cmd); + network_talking_to(nexthop, NTT_REMOVE); + } + } + } + closedir(dp); + + /* Step 2: delete any files in the outbound queue that were for neighbors who no longer exist */ dp = opendir(ctdl_netout_dir); if (dp == NULL) return; @@ -1730,11 +1919,15 @@ void network_purge_spoolout(void) { while (d = readdir(dp), d != NULL) { if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) continue; + ptr = strchr(d->d_name, '@'); + if (d != NULL) + continue; snprintf(filename, - sizeof filename, - "%s/%s", - ctdl_netout_dir, - d->d_name); + sizeof filename, + "%s/%s", + ctdl_netout_dir, + d->d_name + ); strcpy(nexthop, ""); i = is_valid_node(nexthop, NULL, d->d_name); @@ -1752,39 +1945,70 @@ void network_purge_spoolout(void) { /* * receive network spool from the remote system */ -void receive_spool(int sock, char *remote_nodename) { - long download_len = 0L; - long bytes_received = 0L; - long bytes_copied = 0L; +void receive_spool(int *sock, char *remote_nodename) { + int download_len = 0L; + int bytes_received = 0L; char buf[SIZ]; - static char pbuf[IGNET_PACKET_SIZE]; char tempfilename[PATH_MAX]; - char filename[PATH_MAX]; - long plen; - FILE *fp, *newfp; + char permfilename[PATH_MAX]; + int plen; + FILE *fp; + + snprintf(tempfilename, + sizeof tempfilename, + "%s/%s.%lx%x", + ctdl_nettmp_dir, + remote_nodename, + time(NULL), + rand() + ); + + snprintf(permfilename, + sizeof permfilename, + "%s/%s.%lx%x", + ctdl_netin_dir, + remote_nodename, + time(NULL), + rand() + ); - CtdlMakeTempFileName(tempfilename, sizeof tempfilename); if (sock_puts(sock, "NDOP") < 0) return; if (sock_getln(sock, buf, sizeof buf) < 0) return; - lprintf(CTDL_DEBUG, "<%s\n", buf); + syslog(LOG_DEBUG, "<%s\n", buf); if (buf[0] != '2') { return; } + download_len = extract_long(&buf[4], 0); + if (download_len <= 0) { + return; + } bytes_received = 0L; fp = fopen(tempfilename, "w"); if (fp == NULL) { - lprintf(CTDL_CRIT, "cannot open download file locally: %s\n", - strerror(errno)); + syslog(LOG_CRIT, "Cannot create %s: %s\n", tempfilename, strerror(errno)); return; } + syslog(LOG_DEBUG, "Expecting to transfer %d bytes\n", download_len); while (bytes_received < download_len) { - snprintf(buf, sizeof buf, "READ %ld|%ld", - bytes_received, - ((download_len - bytes_received > IGNET_PACKET_SIZE) - ? IGNET_PACKET_SIZE : (download_len - bytes_received))); + /* + * If shutting down we can exit here and unlink the temp file. + * this shouldn't loose us any messages. + */ + if (server_shutting_down) + { + fclose(fp); + unlink(tempfilename); + return; + } + snprintf(buf, sizeof buf, "READ %d|%d", + bytes_received, + ((download_len - bytes_received > IGNET_PACKET_SIZE) + ? IGNET_PACKET_SIZE : (download_len - bytes_received)) + ); + if (sock_puts(sock, buf) < 0) { fclose(fp); unlink(tempfilename); @@ -1795,62 +2019,56 @@ void receive_spool(int sock, char *remote_nodename) { unlink(tempfilename); return; } + if (buf[0] == '6') { - plen = extract_long(&buf[4], 0); - if (sock_read(sock, pbuf, plen, 1) < 0) { + plen = extract_int(&buf[4], 0); + StrBuf *pbuf = NewStrBuf(); + if (socket_read_blob(sock, pbuf, plen, CLIENT_TIMEOUT) != plen) { + syslog(LOG_INFO, "Short read from peer; aborting.\n"); fclose(fp); unlink(tempfilename); + FreeStrBuf(&pbuf); return; } - fwrite((char *) pbuf, plen, 1, fp); - bytes_received = bytes_received + plen; + fwrite(ChrPtr(pbuf), plen, 1, fp); + bytes_received += plen; + FreeStrBuf(&pbuf); } } fclose(fp); + + /* Last chance for shutdown exit */ + if (server_shutting_down) + { + unlink(tempfilename); + return; + } + if (sock_puts(sock, "CLOS") < 0) { unlink(tempfilename); return; } + + /* + * From here on we must complete or messages will get lost + */ if (sock_getln(sock, buf, sizeof buf) < 0) { unlink(tempfilename); return; } - if (download_len > 0) { - lprintf(CTDL_NOTICE, "Received %ld octets from <%s>\n", download_len, remote_nodename); - } - lprintf(CTDL_DEBUG, "%s\n", buf); - - /* Now copy the temp file to its permanent location. - * (We copy instead of link because they may be on different filesystems) + + syslog(LOG_DEBUG, "%s\n", buf); + + /* + * Now move the temp file to its permanent location. */ - begin_critical_section(S_NETSPOOL); - snprintf(filename, - sizeof filename, - "%s/%s.%ld", - ctdl_netin_dir, - remote_nodename, - (long) getpid() - ); - fp = fopen(tempfilename, "r"); - if (fp != NULL) { - newfp = fopen(filename, "w"); - if (newfp != NULL) { - bytes_copied = 0L; - while (bytes_copied < download_len) { - plen = download_len - bytes_copied; - if (plen > sizeof buf) { - plen = sizeof buf; - } - fread(buf, plen, 1, fp); - fwrite(buf, plen, 1, newfp); - bytes_copied += plen; - } - fclose(newfp); - } - fclose(fp); + if (link(tempfilename, permfilename) != 0) { + syslog(LOG_ALERT, "Could not link %s to %s: %s\n", + tempfilename, permfilename, strerror(errno) + ); } - end_critical_section(S_NETSPOOL); + unlink(tempfilename); } @@ -1859,7 +2077,7 @@ void receive_spool(int sock, char *remote_nodename) { /* * transmit network spool to the remote system */ -void transmit_spool(int sock, char *remote_nodename) +void transmit_spool(int *sock, char *remote_nodename) { char buf[SIZ]; char pbuf[4096]; @@ -1870,20 +2088,20 @@ void transmit_spool(int sock, char *remote_nodename) if (sock_puts(sock, "NUOP") < 0) return; if (sock_getln(sock, buf, sizeof buf) < 0) return; - lprintf(CTDL_DEBUG, "<%s\n", buf); + syslog(LOG_DEBUG, "<%s\n", buf); if (buf[0] != '2') { return; } snprintf(sfname, sizeof sfname, - "%s/%s", - ctdl_netout_dir, - remote_nodename); + "%s/%s", + ctdl_netout_dir, + remote_nodename + ); fd = open(sfname, O_RDONLY); if (fd < 0) { if (errno != ENOENT) { - lprintf(CTDL_CRIT, "cannot open upload file locally: %s\n", - strerror(errno)); + syslog(LOG_CRIT, "cannot open %s: %s\n", sfname, strerror(errno)); } return; } @@ -1891,6 +2109,13 @@ void transmit_spool(int sock, char *remote_nodename) while (plen = (long) read(fd, pbuf, IGNET_PACKET_SIZE), plen > 0L) { bytes_to_write = plen; while (bytes_to_write > 0L) { + /* Exit if shutting down */ + if (server_shutting_down) + { + close(fd); + return; + } + snprintf(buf, sizeof buf, "WRIT %ld", bytes_to_write); if (sock_puts(sock, buf) < 0) { close(fd); @@ -1902,8 +2127,7 @@ void transmit_spool(int sock, char *remote_nodename) } thisblock = atol(&buf[4]); if (buf[0] == '7') { - if (sock_write(sock, pbuf, - (int) thisblock) < 0) { + if (sock_write(sock, pbuf, (int) thisblock) < 0) { close(fd); return; } @@ -1917,13 +2141,21 @@ void transmit_spool(int sock, char *remote_nodename) ABORTUPL: close(fd); + + /* Last chance for shutdown exit */ + if(server_shutting_down) + return; + if (sock_puts(sock, "UCLS 1") < 0) return; + + /* + * From here on we must complete or messages will get lost + */ if (sock_getln(sock, buf, sizeof buf) < 0) return; - lprintf(CTDL_NOTICE, "Sent %ld octets to <%s>\n", - bytes_written, remote_nodename); - lprintf(CTDL_DEBUG, "<%s\n", buf); + syslog(LOG_NOTICE, "Sent %ld octets to <%s>\n", bytes_written, remote_nodename); + syslog(LOG_DEBUG, "<%s\n", buf); if (buf[0] == '2') { - lprintf(CTDL_DEBUG, "Removing <%s>\n", sfname); + syslog(LOG_DEBUG, "Removing <%s>\n", sfname); unlink(sfname); } } @@ -1936,38 +2168,66 @@ ABORTUPL: void network_poll_node(char *node, char *secret, char *host, char *port) { int sock; char buf[SIZ]; + char err_buf[SIZ]; + char connected_to[SIZ]; + CitContext *CCC=CC; if (network_talking_to(node, NTT_CHECK)) return; network_talking_to(node, NTT_ADD); - lprintf(CTDL_NOTICE, "Connecting to <%s> at %s:%s\n", node, host, port); + syslog(LOG_DEBUG, "network: polling <%s>\n", node); + syslog(LOG_NOTICE, "Connecting to <%s> at %s:%s\n", node, host, port); - sock = sock_connect(host, port, "tcp"); + sock = sock_connect(host, port); if (sock < 0) { - lprintf(CTDL_ERR, "Could not connect: %s\n", strerror(errno)); + syslog(LOG_ERR, "Could not connect: %s\n", strerror(errno)); network_talking_to(node, NTT_REMOVE); return; } - lprintf(CTDL_DEBUG, "Connected!\n"); + syslog(LOG_DEBUG, "Connected!\n"); + CCC->SBuf.Buf = NewStrBuf(); + CCC->sMigrateBuf = NewStrBuf(); + CCC->SBuf.ReadWritePointer = NULL; /* Read the server greeting */ - if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; - lprintf(CTDL_DEBUG, ">%s\n", buf); - - /* Identify ourselves */ - snprintf(buf, sizeof buf, "NETP %s|%s", config.c_nodename, secret); - lprintf(CTDL_DEBUG, "<%s\n", buf); - if (sock_puts(sock, buf) <0) goto bail; - if (sock_getln(sock, buf, sizeof buf) < 0) goto bail; - lprintf(CTDL_DEBUG, ">%s\n", buf); - if (buf[0] != '2') goto bail; - - /* At this point we are authenticated. */ - receive_spool(sock, node); - transmit_spool(sock, node); - - sock_puts(sock, "QUIT"); -bail: sock_close(sock); + if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail; + syslog(LOG_DEBUG, ">%s\n", buf); + + /* Check that the remote is who we think it is and warn the Aide if not */ + extract_token (connected_to, buf, 1, ' ', sizeof connected_to); + if (strcmp(connected_to, node)) + { + snprintf(err_buf, sizeof(err_buf), + "Connected to node \"%s\" but I was expecting to connect to node \"%s\".", + connected_to, node + ); + syslog(LOG_ERR, "%s\n", err_buf); + CtdlAideMessage(err_buf, "Network error"); + } + else { + /* We're talking to the correct node. Now identify ourselves. */ + snprintf(buf, sizeof buf, "NETP %s|%s", config.c_nodename, secret); + syslog(LOG_DEBUG, "<%s\n", buf); + if (sock_puts(&sock, buf) <0) goto bail; + if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail; + syslog(LOG_DEBUG, ">%s\n", buf); + if (buf[0] != '2') { + goto bail; + } + + /* At this point we are authenticated. */ + if (!server_shutting_down) + receive_spool(&sock, node); + if (!server_shutting_down) + transmit_spool(&sock, node); + } + + sock_puts(&sock, "QUIT"); +bail: + FreeStrBuf(&CCC->SBuf.Buf); + FreeStrBuf(&CCC->sMigrateBuf); + if (sock != -1) + sock_close(sock); network_talking_to(node, NTT_REMOVE); } @@ -1989,12 +2249,14 @@ void network_poll_other_citadel_nodes(int full_poll) { char spoolfile[256]; if (working_ignetcfg == NULL) { - lprintf(CTDL_DEBUG, "No nodes defined - not polling\n"); + syslog(LOG_DEBUG, "network: no neighbor nodes are configured - not polling.\n"); return; } /* Use the string tokenizer to grab one line at a time */ for (i=0; iname, sizeof spoolroomname); begin_critical_section(S_RPLIST); @@ -2119,7 +2397,9 @@ void *network_do_queue(void *args) { } /* If there is anything in the inbound queue, process it */ - network_do_spoolin(); + if (!server_shutting_down) { + network_do_spoolin(); + } /* Save the network map back to disk */ write_network_map(); @@ -2128,17 +2408,15 @@ void *network_do_queue(void *args) { free_filter_list(filterlist); filterlist = NULL; - network_purge_spoolout(); + network_consolidate_spoolout(); - lprintf(CTDL_DEBUG, "network: queue run completed\n"); + syslog(LOG_DEBUG, "network: queue run completed\n"); if (full_processing) { last_run = time(NULL); } doing_queue = 0; - CtdlThreadSchedule("IGnet Network", CTDLTHREAD_BIGSTACK, network_do_queue, NULL, time(NULL) + 60); - return NULL; } @@ -2154,54 +2432,60 @@ void cmd_netp(char *cmdbuf) char secret[256]; char nexthop[256]; + char err_buf[SIZ]; /* Authenticate */ extract_token(node, cmdbuf, 0, '|', sizeof node); extract_token(pass, cmdbuf, 1, '|', sizeof pass); - if (doing_queue) { - lprintf(CTDL_WARNING, "Network node <%s> refused - spooling", node); - cprintf("%d spooling - try again in a few minutes\n", - ERROR + RESOURCE_BUSY); - return; - } - /* load the IGnet Configuration to check node validity */ load_working_ignetcfg(); v = is_valid_node(nexthop, secret, node); if (v != 0) { - lprintf(CTDL_WARNING, "Unknown node <%s>\n", node); - cprintf("%d authentication failed\n", - ERROR + PASSWORD_REQUIRED); + snprintf(err_buf, sizeof err_buf, + "An unknown Citadel server called \"%s\" attempted to connect from %s [%s].\n", + node, CC->cs_host, CC->cs_addr + ); + syslog(LOG_WARNING, "%s", err_buf); + cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED); + CtdlAideMessage(err_buf, "IGNet Networking."); return; } if (strcasecmp(pass, secret)) { - lprintf(CTDL_WARNING, "Bad password for network node <%s>", node); + snprintf(err_buf, sizeof err_buf, + "A Citadel server at %s [%s] failed to authenticate as network node \"%s\".\n", + CC->cs_host, CC->cs_addr, node + ); + syslog(LOG_WARNING, "%s", err_buf); cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED); + CtdlAideMessage(err_buf, "IGNet Networking."); return; } if (network_talking_to(node, NTT_CHECK)) { - lprintf(CTDL_WARNING, "Duplicate session for network node <%s>", node); + syslog(LOG_WARNING, "Duplicate session for network node <%s>", node); cprintf("%d Already talking to %s right now\n", ERROR + RESOURCE_BUSY, node); return; } safestrncpy(CC->net_node, node, sizeof CC->net_node); network_talking_to(node, NTT_ADD); - lprintf(CTDL_NOTICE, "Network node <%s> logged in\n", CC->net_node); - cprintf("%d authenticated as network node '%s'\n", CIT_OK, - CC->net_node); + syslog(LOG_NOTICE, "Network node <%s> logged in from %s [%s]\n", + CC->net_node, CC->cs_host, CC->cs_addr + ); + cprintf("%d authenticated as network node '%s'\n", CIT_OK, CC->net_node); } + int network_room_handler (struct ctdlroom *room) { network_queue_room(room, NULL); return 0; } + /* * Module entry point */ @@ -2214,12 +2498,9 @@ CTDL_MODULE_INIT(network) CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config"); CtdlRegisterProtoHook(cmd_netp, "NETP", "Identify as network poller"); CtdlRegisterProtoHook(cmd_nsyn, "NSYN", "Synchronize room to node"); -// CtdlRegisterSessionHook(network_do_queue, EVT_TIMER); - CtdlRegisterRoomHook(network_room_handler); + CtdlRegisterRoomHook(network_room_handler); CtdlRegisterCleanupHook(destroy_network_queue_room); + CtdlRegisterSessionHook(network_do_queue, EVT_TIMER); } - else - CtdlThreadSchedule("IGnet Network", CTDLTHREAD_BIGSTACK, network_do_queue, NULL, 0); - /* return our Subversion id for the Log */ - return "$Id$"; + return "network"; }