Back to index

citadel  8.12
Classes | Typedefs | Functions
netspool.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  maplist
struct  SpoolControl

Typedefs

typedef struct maplist
typedef struct SpoolControl

Functions

void network_spoolout_room (RoomProcList *room_to_spool, HashList *working_ignetcfg, HashList *the_netmap)
void network_do_spoolin (HashList *working_ignetcfg, HashList *the_netmap, int *netmap_changed)
void network_consolidate_spoolout (HashList *working_ignetcfg, HashList *the_netmap)
void free_spoolcontrol_struct (SpoolControl **scc)
int writenfree_spoolcontrol_file (SpoolControl **scc, char *filename)
int read_spoolcontrol_file (SpoolControl **scc, char *filename)
int is_recipient (SpoolControl *sc, const char *Name)

Class Documentation

struct maplist

Definition at line 32 of file netspool.h.

Collaboration diagram for maplist:
Class Members
struct maplist * next
char remote_nodename
char remote_roomname
struct SpoolControl

Definition at line 41 of file netspool.h.

Collaboration diagram for SpoolControl:
Class Members
FILE * digestfp
namelist * digestrecps
maplist * ignet_push_shares
long lastsent
namelist * listrecps
char * misc
int num_msgs_spooled
namelist * participates
HashList * the_netmap
HashList * working_ignetcfg

Typedef Documentation

typedef struct maplist

Definition at line 30 of file netspool.h.

typedef struct SpoolControl

Definition at line 39 of file netspool.h.


Function Documentation

Definition at line 189 of file serv_netspool.c.

{
       SpoolControl *sc;
       namelist *nptr = NULL;
       maplist *mptr = NULL;

       sc = *scc;
       while (sc->listrecps != NULL) {
              nptr = sc->listrecps->next;
              free(sc->listrecps);
              sc->listrecps = nptr;
       }
       /* Do the same for digestrecps */
       while (sc->digestrecps != NULL) {
              nptr = sc->digestrecps->next;
              free(sc->digestrecps);
              sc->digestrecps = nptr;
       }
       /* Do the same for participates */
       while (sc->participates != NULL) {
              nptr = sc->participates->next;
              free(sc->participates);
              sc->participates = nptr;
       }
       while (sc->ignet_push_shares != NULL) {
              mptr = sc->ignet_push_shares->next;
              free(sc->ignet_push_shares);
              sc->ignet_push_shares = mptr;
       }
       free(sc->misc);
       free(sc);
       *scc=NULL;
}

Here is the caller graph for this function:

int is_recipient ( SpoolControl sc,
const char *  Name 
)

Definition at line 321 of file serv_netspool.c.

{
       namelist *nptr;
       size_t len;

       len = strlen(Name);
       nptr = sc->listrecps;
       while (nptr != NULL) {
              if (strncmp(Name, nptr->name, len)==0)
                     return 1;
              nptr = nptr->next;
       }
       /* Do the same for digestrecps */
       nptr = sc->digestrecps;
       while (nptr != NULL) {
              if (strncmp(Name, nptr->name, len)==0)
                     return 1;
              nptr = nptr->next;
       }
       /* Do the same for participates */
       nptr = sc->participates;
       while (nptr != NULL) {
              if (strncmp(Name, nptr->name, len)==0)
                     return 1;
              nptr = nptr->next;
       }
       return 0;
}

Here is the caller graph for this function:

void network_consolidate_spoolout ( HashList *  working_ignetcfg,
HashList *  the_netmap 
)

Definition at line 751 of file serv_netspool.c.

{
       struct CitContext *CCC = CC;
       IOBuffer IOB;
       FDIOBuffer FDIO;
        int d_namelen;
       DIR *dp;
       struct dirent *d;
       struct dirent *filedir_entry;
       const char *pch;
       char spooloutfilename[PATH_MAX];
       char filename[PATH_MAX];
       const StrBuf *nexthop;
       StrBuf *NextHop;
       int i;
       int nFailed = 0;

       /* Step 1: consolidate files in the outbound queue into one file per neighbor node */
       d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1);
       if (d == NULL)       return;

       dp = opendir(ctdl_netout_dir);
       if (dp == NULL) {
              free(d);
              return;
       }

       NextHop = NewStrBuf();
       memset(&IOB, 0, sizeof(IOBuffer));
       memset(&FDIO, 0, sizeof(FDIOBuffer));
       FDIO.IOB = &IOB;

       while ((readdir_r(dp, d, &filedir_entry) == 0) &&
              (filedir_entry != NULL))
       {
#ifdef _DIRENT_HAVE_D_NAMELEN
              d_namelen = filedir_entry->d_namelen;
#else

#ifndef DT_UNKNOWN
#define DT_UNKNOWN     0
#define DT_DIR         4
#define DT_REG         8
#define DT_LNK         10

#define IFTODT(mode)   (((mode) & 0170000) >> 12)
#define DTTOIF(dirtype)        ((dirtype) << 12)
#endif
              d_namelen = strlen(filedir_entry->d_name);
#endif
              if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
                     continue; /* Ignore backup files... */

              if ((d_namelen == 1) && 
                  (filedir_entry->d_name[0] == '.'))
                     continue;

              if ((d_namelen == 2) && 
                  (filedir_entry->d_name[0] == '.') &&
                  (filedir_entry->d_name[1] == '.'))
                     continue;

              pch = strchr(filedir_entry->d_name, '@');
              if (pch == NULL)
                     continue;

              snprintf(filename, 
                      sizeof filename,
                      "%s/%s",
                      ctdl_netout_dir,
                      filedir_entry->d_name);

              StrBufPlain(NextHop,
                         filedir_entry->d_name,
                         pch - filedir_entry->d_name);

              snprintf(spooloutfilename,
                      sizeof spooloutfilename,
                      "%s/%s",
                      ctdl_netout_dir,
                      ChrPtr(NextHop));

              QN_syslog(LOG_DEBUG, "Consolidate %s to %s\n", filename, ChrPtr(NextHop));
              if (network_talking_to(SKEY(NextHop), NTT_CHECK)) {
                     nFailed++;
                     QN_syslog(LOG_DEBUG,
                              "Currently online with %s - skipping for now\n",
                              ChrPtr(NextHop)
                            );
              }
              else {
                     size_t dsize;
                     size_t fsize;
                     int fd;
                     const char *err = NULL;
                     network_talking_to(SKEY(NextHop), NTT_ADD);

                     IOB.fd = open(filename, O_RDONLY);
                     if (IOB.fd == -1) {
                            nFailed++;
                            QN_syslog(LOG_ERR,
                                     "failed to open %s for reading due to %s; skipping.\n",
                                     filename, strerror(errno)
                                   );
                            network_talking_to(SKEY(NextHop), NTT_REMOVE);
                            continue;                          
                     }
                     
                     fd = open(spooloutfilename,
                              O_EXCL|O_CREAT|O_NONBLOCK|O_WRONLY, 
                              S_IRUSR|S_IWUSR);
                     if (fd == -1)
                     {
                            fd = open(spooloutfilename,
                                     O_EXCL|O_NONBLOCK|O_WRONLY, 
                                     S_IRUSR | S_IWUSR);
                     }
                     if (fd == -1) {
                            nFailed++;
                            QN_syslog(LOG_ERR,
                                     "failed to open %s for reading due to %s; skipping.\n",
                                     spooloutfilename, strerror(errno)
                                   );
                            close(IOB.fd);
                            network_talking_to(SKEY(NextHop), NTT_REMOVE);
                            continue;
                     }
                     dsize = lseek(fd, 0, SEEK_END);
                     fsize = lseek(IOB.fd, 0, SEEK_END);
                     
                     FDIOBufferInit(&FDIO, &IOB, fd, fsize + dsize);
                     FDIO.ChunkSendRemain = fsize;
                     FDIO.TotalSentAlready = dsize;
                     err = NULL;
                     do {} while ((FileMoveChunked(&FDIO, &err) > 0) && (err == NULL));
                     if (err == NULL) {
                            unlink(filename);
                     }
                     else {
                            nFailed++;
                            QN_syslog(LOG_ERR,
                                     "failed to append to %s [%s]; rolling back..\n",
                                     spooloutfilename, strerror(errno)
                                   );
                            /* whoops partial append?? truncate spooloutfilename again! */
                            ftruncate(fd, dsize);
                     }
                     FDIOBufferDelete(&FDIO);
                     close(IOB.fd);
                     close(fd);
                     network_talking_to(SKEY(NextHop), NTT_REMOVE);
              }
       }
       closedir(dp);

       if (nFailed > 0) {
              FreeStrBuf(&NextHop);
              QN_syslog(LOG_INFO,
                       "skipping Spoolcleanup because of %d files unprocessed.\n",
                       nFailed
                     );

              return;
       }

       /* 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) {
              FreeStrBuf(&NextHop);
              free(d);
              return;
       }

       while ((readdir_r(dp, d, &filedir_entry) == 0) &&
              (filedir_entry != NULL))
       {
#ifdef _DIRENT_HAVE_D_NAMELEN
              d_namelen = filedir_entry->d_namelen;
              d_type = filedir_entry->d_type;
#else

#ifndef DT_UNKNOWN
#define DT_UNKNOWN     0
#define DT_DIR         4
#define DT_REG         8
#define DT_LNK         10

#define IFTODT(mode)   (((mode) & 0170000) >> 12)
#define DTTOIF(dirtype)        ((dirtype) << 12)
#endif
              d_namelen = strlen(filedir_entry->d_name);
#endif
              if ((d_namelen == 1) && 
                  (filedir_entry->d_name[0] == '.'))
                     continue;

              if ((d_namelen == 2) && 
                  (filedir_entry->d_name[0] == '.') &&
                  (filedir_entry->d_name[1] == '.'))
                     continue;

              pch = strchr(filedir_entry->d_name, '@');
              if (pch == NULL) /* no @ in name? consolidated file. */
                     continue;

              StrBufPlain(NextHop,
                         filedir_entry->d_name,
                         pch - filedir_entry->d_name);

              snprintf(filename, 
                     sizeof filename,
                     "%s/%s",
                     ctdl_netout_dir,
                     filedir_entry->d_name
              );

              i = is_valid_node(&nexthop,
                              NULL,
                              NextHop,
                              working_ignetcfg,
                              the_netmap);
       
              if ( (i != 0) || (StrLength(nexthop) > 0) ) {
                     unlink(filename);
              }
       }
       FreeStrBuf(&NextHop);
       free(d);
       closedir(dp);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void network_do_spoolin ( HashList *  working_ignetcfg,
HashList *  the_netmap,
int *  netmap_changed 
)

Definition at line 702 of file serv_netspool.c.

{
       struct CitContext *CCC = CC;
       DIR *dp;
       struct dirent *d;
       struct stat statbuf;
       char filename[PATH_MAX];
       static time_t last_spoolin_mtime = 0L;

       /*
        * Check the spoolin directory's modification time.  If it hasn't
        * been touched, we don't need to scan it.
        */
       if (stat(ctdl_netin_dir, &statbuf)) return;
       if (statbuf.st_mtime == last_spoolin_mtime) {
              QNM_syslog(LOG_DEBUG, "network: nothing in inbound queue\n");
              return;
       }
       last_spoolin_mtime = statbuf.st_mtime;
       QNM_syslog(LOG_DEBUG, "network: processing inbound queue\n");

       /*
        * Ok, there's something interesting in there, so scan it.
        */
       dp = opendir(ctdl_netin_dir);
       if (dp == NULL) return;

       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
                     );
                     network_process_file(filename,
                                        working_ignetcfg,
                                        the_netmap,
                                        netmap_changed);
              }
       }

       closedir(dp);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void network_spoolout_room ( RoomProcList room_to_spool,
HashList *  working_ignetcfg,
HashList *  the_netmap 
)

Definition at line 354 of file serv_netspool.c.

{
       char buf[SIZ];
       char filename[PATH_MAX];
       SpoolControl *sc;
       int i;

       /*
        * If the room doesn't exist, don't try to perform its networking tasks.
        * 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 (CtdlGetRoom(&CC->room, room_to_spool->name) != 0) {
              syslog(LOG_CRIT, "ERROR: cannot load <%s>\n", room_to_spool->name);
              return;
       }

       assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
       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);

       sc->working_ignetcfg = working_ignetcfg;
       sc->the_netmap = the_netmap;

       /* If there are digest recipients, we have to build a digest */
       if (sc->digestrecps != NULL) {
              sc->digestfp = tmpfile();
              fprintf(sc->digestfp, "Content-type: text/plain\n\n");
       }

       /* Do something useful */
       CtdlForEachMessage(MSGS_GT, sc->lastsent, NULL, NULL, NULL,
              network_spool_msg, sc);

       /* If we wrote a digest, deliver it and then close it */
       snprintf(buf, sizeof buf, "room_%s@%s",
              CC->room.QRname, config.c_fqdn);
       for (i=0; buf[i]; ++i) {
              buf[i] = tolower(buf[i]);
              if (isspace(buf[i])) buf[i] = '_';
       }
       if (sc->digestfp != NULL) {
              fprintf(sc->digestfp,       " -----------------------------------"
                                   "------------------------------------"
                                   "-------\n"
                                   "You are subscribed to the '%s' "
                                   "list.\n"
                                   "To post to the list: %s\n",
                                   CC->room.QRname, buf
              );
              network_deliver_digest(sc); /* deliver and close */
       }

       /* Now rewrite the config file */
       writenfree_spoolcontrol_file(&sc, filename);
       end_critical_section(S_NETCONFIGS);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int read_spoolcontrol_file ( SpoolControl **  scc,
char *  filename 
)

Definition at line 98 of file serv_netspool.c.

{
       FILE *fp;
       char instr[SIZ];
       char buf[SIZ];
       char nodename[256];
       char roomname[ROOMNAMELEN];
       size_t miscsize = 0;
       size_t linesize = 0;
       int skipthisline = 0;
       namelist *nptr = NULL;
       maplist *mptr = NULL;
       SpoolControl *sc;

       fp = fopen(filename, "r");
       if (fp == NULL) {
              return 0;
       }
       sc = malloc(sizeof(SpoolControl));
       memset(sc, 0, sizeof(SpoolControl));
       *scc = sc;

       while (fgets(buf, sizeof buf, fp) != NULL) {
              buf[strlen(buf)-1] = 0;

              extract_token(instr, buf, 0, '|', sizeof instr);
              if (!strcasecmp(instr, strof(lastsent))) {
                     sc->lastsent = extract_long(buf, 1);
              }
              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, 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, 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, strof(ignet_push_share))) {
                     extract_token(nodename, buf, 1, '|', sizeof nodename);
                     extract_token(roomname, buf, 2, '|', sizeof roomname);
                     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
                      * be subscribe/unsubscribe pendings with expired
                      * timestamps.
                      */
                     skipthisline = 0;
                     if (!strncasecmp(buf, strof(subpending)"|", 11)) {
                            if (time(NULL) - extract_long(buf, 4) > EXP) {
                                   skipthisline = 1;
                            }
                     }
                     if (!strncasecmp(buf, strof(unsubpending)"|", 13)) {
                            if (time(NULL) - extract_long(buf, 3) > EXP) {
                                   skipthisline = 1;
                            }
                     }

                     if (skipthisline == 0) {
                            linesize = strlen(buf);
                            sc->misc = realloc(sc->misc,
                                   (miscsize + linesize + 2) );
                            sprintf(&sc->misc[miscsize], "%s\n", buf);
                            miscsize = miscsize + linesize + 1;
                     }
              }


       }
       fclose(fp);
       return 1;
}

Here is the caller graph for this function:

int writenfree_spoolcontrol_file ( SpoolControl **  scc,
char *  filename 
)

Definition at line 223 of file serv_netspool.c.

{
       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;
       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 {
              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) {
                  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) {
                     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) {
                     StrBufAppendPrintf(Cfg, "participate|%s\n", sc->participates->name);
                     nptr = sc->participates->next;
                     free(sc->participates);
                     sc->participates = nptr;
              }
              while (sc->ignet_push_shares != NULL) {
                     StrBufAppendPrintf(Cfg, "ignet_push_share|%s", sc->ignet_push_shares->remote_nodename);
                     if (!IsEmptyStr(sc->ignet_push_shares->remote_roomname)) {
                            StrBufAppendPrintf(Cfg, "|%s", sc->ignet_push_shares->remote_roomname);
                     }
                     StrBufAppendPrintf(Cfg, "\n");
                     mptr = sc->ignet_push_shares->next;
                     free(sc->ignet_push_shares);
                     sc->ignet_push_shares = mptr;
              }
              if (sc->misc != NULL) {
                     StrBufAppendBufPlain(Cfg, sc->misc, -1, 0);
              }
              free(sc->misc);

              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;
       }
       return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function: