X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fnetwork%2Fserv_network.c;h=7955f5a2eb935ebe4b16336c2f0d51a9653a9a36;hb=e26a8dee20d1726b4995821f717f867f50fc5659;hp=fa50506609dfe7839fdf83cb707ae5ed89c81c62;hpb=f15df94047f9c4f9a2faddd4700ac24b46afd923;p=citadel.git diff --git a/citadel/modules/network/serv_network.c b/citadel/modules/network/serv_network.c index fa5050660..7955f5a2e 100644 --- a/citadel/modules/network/serv_network.c +++ b/citadel/modules/network/serv_network.c @@ -1,12 +1,10 @@ /* - * $Id$ - * * This module handles shared rooms, inter-Citadel mail, and outbound * mailing list processing. * - * Copyright (c) 2000-2010 by the citadel.org team + * Copyright (c) 2000-2011 by the citadel.org team * - * This program is free software; you can redistribute it and/or modify + * 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. @@ -57,6 +55,13 @@ # include # endif #endif +#ifdef HAVE_SYSCALL_H +# include +#else +# if HAVE_SYS_SYSCALL_H +# include +# endif +#endif #include #include @@ -87,9 +92,6 @@ -/* 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 @@ -216,7 +218,7 @@ int network_usetable(struct CtdlMessage *msg) { cdbut = cdb_fetch(CDB_USETABLE, msgid, strlen(msgid)); if (cdbut != NULL) { cdb_free(cdbut); - CtdlLogPrintf(CTDL_DEBUG, "network_usetable() : we already have %s\n", msgid); + syslog(LOG_DEBUG, "network_usetable() : we already have %s\n", msgid); return(1); } @@ -318,7 +320,7 @@ int is_valid_node(char *nexthop, char *secret, char *node) { * First try the neighbor nodes */ if (working_ignetcfg == NULL) { - CtdlLogPrintf(CTDL_ERR, "working_ignetcfg is NULL!\n"); + syslog(LOG_ERR, "working_ignetcfg is NULL!\n"); if (nexthop != NULL) { strcpy(nexthop, ""); } @@ -366,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. */ - CtdlLogPrintf(CTDL_ERR, "Invalid node name <%s>\n", node); + syslog(LOG_ERR, "Invalid node name <%s>\n", node); return(-1); } @@ -405,8 +407,11 @@ void cmd_gnet(char *argbuf) { void cmd_snet(char *argbuf) { char tempfilename[PATH_MAX]; char filename[PATH_MAX]; - char buf[SIZ]; - FILE *fp, *newfp; + int TmpFD; + StrBuf *Line; + struct stat StatBuf; + long len; + int rc; unbuffer_output(); @@ -415,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) >= 0 && 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); } @@ -462,7 +494,6 @@ void network_deliver_digest(SpoolControl *sc) { long msglen; char *recps = NULL; size_t recps_len = SIZ; - size_t siz; struct recptypes *valid; namelist *nptr; char bounce_to[256]; @@ -509,7 +540,7 @@ void network_deliver_digest(SpoolControl *sc) { msg->cm_fields['M'] = malloc(msglen + 1); fseek(sc->digestfp, 0L, SEEK_SET); - siz = fread(msg->cm_fields['M'], (size_t)msglen, 1, sc->digestfp); + fread(msg->cm_fields['M'], (size_t)msglen, 1, sc->digestfp); msg->cm_fields['M'][msglen] = '\0'; fclose(sc->digestfp); @@ -527,7 +558,7 @@ void network_deliver_digest(SpoolControl *sc) { recps = malloc(recps_len); if (recps == NULL) { - CtdlLogPrintf(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(); } @@ -582,7 +613,7 @@ void network_deliver_list(struct CtdlMessage *msg, SpoolControl *sc) { recps = malloc(recps_len); if (recps == NULL) { - CtdlLogPrintf(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(); } @@ -621,7 +652,6 @@ 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; @@ -640,14 +670,29 @@ 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']); @@ -662,11 +707,38 @@ void network_spool_msg(long msgnum, void *userdata) { /* Prepend "[List name]" to the subject */ if (msg->cm_fields['U'] == NULL) { - msg->cm_fields['U'] = strdup("(no subject)"); + Subject = NewStrBufPlain(HKEY("(no subject)")); + } + else { + Subject = NewStrBufPlain(msg->cm_fields['U'], -1); } - snprintf(buf, sizeof buf, "[%s] %s", CC->room.QRname, msg->cm_fields['U']); - free(msg->cm_fields['U']); - msg->cm_fields['U'] = strdup(buf); + 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. @@ -735,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) { @@ -832,24 +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) { - CtdlLogPrintf(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 */ - CtdlLogPrintf(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); - CtdlLogPrintf(CTDL_DEBUG, "Compare <%s> to <%s>\n", + syslog(LOG_DEBUG, "Compare <%s> to <%s>\n", buf, mptr->remote_nodename) ; if (!strcasecmp(buf, mptr->remote_nodename)) { send = 0; - CtdlLogPrintf(CTDL_DEBUG, "Not sending to %s\n", + syslog(LOG_DEBUG, "Not sending to %s\n", mptr->remote_nodename); } else { - CtdlLogPrintf(CTDL_DEBUG, "Sending to %s\n", mptr->remote_nodename); + syslog(LOG_DEBUG, "Sending to %s\n", mptr->remote_nodename); } } @@ -874,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); - CtdlLogPrintf(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, @@ -886,7 +960,7 @@ void network_spool_msg(long msgnum, void *userdata) { fclose(fp); } else { - CtdlLogPrintf(CTDL_ERR, "%s: %s\n", filename, strerror(errno)); + syslog(LOG_ERR, "%s: %s\n", filename, strerror(errno)); } /* free the serialized version */ @@ -1036,60 +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) { - CtdlLogPrintf(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) { - 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; } @@ -1140,7 +1251,7 @@ void network_spoolout_room(char *room_to_spool) { * queued for networking and then deleted before it can happen. */ if (CtdlGetRoom(&CC->room, room_to_spool) != 0) { - CtdlLogPrintf(CTDL_CRIT, "ERROR: cannot load <%s>\n", room_to_spool); + syslog(LOG_CRIT, "ERROR: cannot load <%s>\n", room_to_spool); return; } @@ -1153,7 +1264,7 @@ void network_spoolout_room(char *room_to_spool) { end_critical_section(S_NETCONFIGS); return; } - CtdlLogPrintf(CTDL_INFO, "Networking started for <%s>\n", CC->room.QRname); + 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) { @@ -1185,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); } @@ -1249,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); - CtdlLogPrintf(CTDL_NOTICE, "Synchronized %d messages to <%s>\n", + syslog(LOG_NOTICE, "Synchronized %d messages to <%s>\n", num_spooled, target_node); return(num_spooled); } @@ -1368,7 +1479,7 @@ void network_bounce(struct CtdlMessage *msg, char *reason) { static int serialnum = 0; size_t size; - CtdlLogPrintf(CTDL_DEBUG, "entering network_bounce()\n"); + syslog(LOG_DEBUG, "entering network_bounce()\n"); if (msg == NULL) return; @@ -1457,7 +1568,7 @@ void network_bounce(struct CtdlMessage *msg, char *reason) { /* Clean up */ if (valid != NULL) free_recipients(valid); CtdlFreeMessage(msg); - CtdlLogPrintf(CTDL_DEBUG, "leaving network_bounce()\n"); + syslog(LOG_DEBUG, "leaving network_bounce()\n"); } @@ -1481,13 +1592,13 @@ void network_process_buffer(char *buffer, long size) { unsigned char firstbyte; unsigned char lastbyte; - CtdlLogPrintf(CTDL_DEBUG, "network_process_buffer() processing %ld bytes\n", size); + 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) ) { - CtdlLogPrintf(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; } @@ -1537,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); - CtdlLogPrintf(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 { - CtdlLogPrintf(CTDL_ERR, "%s: %s\n", filename, strerror(errno)); + syslog(LOG_ERR, "%s: %s\n", filename, strerror(errno)); } free(sermsg.ser); CtdlFreeMessage(msg); @@ -1600,7 +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); - CtdlLogPrintf(CTDL_DEBUG, "Bouncing message due to invalid recipient address.\n"); + syslog(LOG_DEBUG, "Bouncing message due to invalid recipient address.\n"); return; } strcpy(target_room, ""); /* no target room if mail */ @@ -1669,12 +1782,12 @@ void network_process_file(char *filename) { fp = fopen(filename, "rb"); if (fp == NULL) { - CtdlLogPrintf(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); - CtdlLogPrintf(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 */ @@ -1717,11 +1830,11 @@ void network_do_spoolin(void) { */ if (stat(ctdl_netin_dir, &statbuf)) return; if (statbuf.st_mtime == last_spoolin_mtime) { - CtdlLogPrintf(CTDL_DEBUG, "network: nothing in inbound queue\n"); + syslog(LOG_DEBUG, "network: nothing in inbound queue\n"); return; } last_spoolin_mtime = statbuf.st_mtime; - CtdlLogPrintf(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. @@ -1732,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); } } @@ -1744,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[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; @@ -1760,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); @@ -1783,49 +1946,69 @@ void network_purge_spoolout(void) { * receive network spool from the remote system */ void receive_spool(int *sock, char *remote_nodename) { - size_t siz; - long download_len = 0L; - long bytes_received = 0L; - long bytes_copied = 0L; + 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; - CtdlLogPrintf(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) { - CtdlLogPrintf(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) { - /** + /* * If shutting down we can exit here and unlink the temp file. * this shouldn't loose us any messages. */ - if (CtdlThreadCheckStop()) + if (server_shutting_down) { fclose(fp); unlink(tempfilename); return; } - snprintf(buf, sizeof buf, "READ %ld|%ld", - bytes_received, - ((download_len - bytes_received > IGNET_PACKET_SIZE) - ? IGNET_PACKET_SIZE : (download_len - bytes_received))); + 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); @@ -1836,71 +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 (CtdlThreadCheckStop()) + + /* 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) { - CtdlLogPrintf(CTDL_NOTICE, "Received %ld octets from <%s>\n", download_len, remote_nodename); - } - CtdlLogPrintf(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; - } - siz = 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); } @@ -1920,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; - CtdlLogPrintf(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) { - CtdlLogPrintf(CTDL_CRIT, "cannot open upload file locally: %s\n", - strerror(errno)); + syslog(LOG_CRIT, "cannot open %s: %s\n", sfname, strerror(errno)); } return; } @@ -1941,8 +2109,8 @@ 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 (CtdlThreadCheckStop()) + /* Exit if shutting down */ + if (server_shutting_down) { close(fd); return; @@ -1959,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; } @@ -1974,20 +2141,21 @@ void transmit_spool(int *sock, char *remote_nodename) ABORTUPL: close(fd); - /** Last chance for shutdown exit */ - if(CtdlThreadCheckStop()) + + /* 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; - CtdlLogPrintf(CTDL_NOTICE, "Sent %ld octets to <%s>\n", - bytes_written, remote_nodename); - CtdlLogPrintf(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') { - CtdlLogPrintf(CTDL_DEBUG, "Removing <%s>\n", sfname); + syslog(LOG_DEBUG, "Removing <%s>\n", sfname); unlink(sfname); } } @@ -2006,24 +2174,24 @@ void network_poll_node(char *node, char *secret, char *host, char *port) { if (network_talking_to(node, NTT_CHECK)) return; network_talking_to(node, NTT_ADD); - CtdlLogPrintf(CTDL_DEBUG, "network: polling <%s>\n", node); - CtdlLogPrintf(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) { - CtdlLogPrintf(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; } - CtdlLogPrintf(CTDL_DEBUG, "Connected!\n"); - CCC->sReadBuf = NewStrBuf(); + syslog(LOG_DEBUG, "Connected!\n"); + CCC->SBuf.Buf = NewStrBuf(); CCC->sMigrateBuf = NewStrBuf(); - CCC->sPos = NULL; + CCC->SBuf.ReadWritePointer = NULL; /* Read the server greeting */ if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail; - CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); + 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); @@ -2033,30 +2201,30 @@ void network_poll_node(char *node, char *secret, char *host, char *port) { "Connected to node \"%s\" but I was expecting to connect to node \"%s\".", connected_to, node ); - CtdlLogPrintf(CTDL_ERR, "%s\n", err_buf); + 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); - CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf); + syslog(LOG_DEBUG, "<%s\n", buf); if (sock_puts(&sock, buf) <0) goto bail; if (sock_getln(&sock, buf, sizeof buf) < 0) goto bail; - CtdlLogPrintf(CTDL_DEBUG, ">%s\n", buf); + syslog(LOG_DEBUG, ">%s\n", buf); if (buf[0] != '2') { goto bail; } /* At this point we are authenticated. */ - if (!CtdlThreadCheckStop()) + if (!server_shutting_down) receive_spool(&sock, node); - if (!CtdlThreadCheckStop()) + if (!server_shutting_down) transmit_spool(&sock, node); } sock_puts(&sock, "QUIT"); bail: - FreeStrBuf(&CCC->sReadBuf); + FreeStrBuf(&CCC->SBuf.Buf); FreeStrBuf(&CCC->sMigrateBuf); if (sock != -1) sock_close(sock); @@ -2081,13 +2249,13 @@ void network_poll_other_citadel_nodes(int full_poll) { char spoolfile[256]; if (working_ignetcfg == NULL) { - CtdlLogPrintf(CTDL_DEBUG, "network: no neighbor nodes are configured - 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); @@ -2233,7 +2397,7 @@ void *network_do_queue(void *args) { } /* If there is anything in the inbound queue, process it */ - if (!CtdlThreadCheckStop()) { + if (!server_shutting_down) { network_do_spoolin(); } @@ -2244,28 +2408,15 @@ void *network_do_queue(void *args) { free_filter_list(filterlist); filterlist = NULL; - network_purge_spoolout(); + network_consolidate_spoolout(); - CtdlLogPrintf(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; - - /* Reschedule this task to happen again periodically, unless the thread system indicates - * that the server is shutting down. - */ - if (!CtdlThreadCheckStop()) { - CtdlThreadSchedule("IGnet Network", CTDLTHREAD_BIGSTACK, - network_do_queue, NULL, time(NULL) + 60 - ); - } - else { - CtdlLogPrintf(CTDL_DEBUG, "network: Task STOPPED.\n"); - } - return NULL; } @@ -2287,12 +2438,6 @@ void cmd_netp(char *cmdbuf) extract_token(node, cmdbuf, 0, '|', sizeof node); extract_token(pass, cmdbuf, 1, '|', sizeof pass); - if (doing_queue) { - CtdlLogPrintf(CTDL_WARNING, "Network node <%s> refused - spooling\n", 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); @@ -2302,7 +2447,7 @@ void cmd_netp(char *cmdbuf) "An unknown Citadel server called \"%s\" attempted to connect from %s [%s].\n", node, CC->cs_host, CC->cs_addr ); - CtdlLogPrintf(CTDL_WARNING, err_buf); + syslog(LOG_WARNING, "%s", err_buf); cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED); CtdlAideMessage(err_buf, "IGNet Networking."); return; @@ -2313,21 +2458,21 @@ void cmd_netp(char *cmdbuf) "A Citadel server at %s [%s] failed to authenticate as network node \"%s\".\n", CC->cs_host, CC->cs_addr, node ); - CtdlLogPrintf(CTDL_WARNING, err_buf); + 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)) { - CtdlLogPrintf(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); - CtdlLogPrintf(CTDL_NOTICE, "Network node <%s> logged in from %s [%s]\n", + 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); @@ -2353,11 +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"); - 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"; }