Back to index

citadel  8.12
Classes | Defines | Typedefs | Functions | Variables
serv_network.c File Reference
#include "sysdep.h"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <signal.h>
#include <pwd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <time.h>
#include <sys/wait.h>
#include <string.h>
#include <limits.h>
#include <libcitadel.h>
#include "citadel.h"
#include "server.h"
#include "citserver.h"
#include "support.h"
#include "config.h"
#include "user_ops.h"
#include "database.h"
#include "msgbase.h"
#include "internet_addressing.h"
#include "serv_network.h"
#include "clientsocket.h"
#include "file_ops.h"
#include "citadel_dirs.h"
#include "threads.h"
#include "snprintf.h"
#include "context.h"
#include "netconfig.h"
#include "netspool.h"
#include "netmail.h"
#include "ctdl_module.h"

Go to the source code of this file.

Classes

struct  __roomlists

Defines

#define EXP   259200 /* three days */

Typedefs

typedef struct __roomlists roomlists

Functions

uint32_t hashlittle (const void *key, size_t length, uint32_t initval)
int GetNetworkedRoomNumbers (const char *DirName, HashList *DirList)
int network_usetable (struct CtdlMessage *msg)
int network_sync_to (char *target_node, long len)
void cmd_nsyn (char *argbuf)
void network_queue_interesting_rooms (struct ctdlroom *qrbuf, void *data)
void network_queue_room (struct ctdlroom *qrbuf, void *data)
void destroy_network_queue_room (RoomProcList *rplist)
void destroy_network_queue_room_locked (void)
void network_bounce (struct CtdlMessage *msg, char *reason)
void network_do_queue (void)
int network_room_handler (struct ctdlroom *room)
int network_talking_to (const char *nodename, long len, int operation)
void cleanup_nttlist (void)
void network_logout_hook (void)
void network_cleanup_function (void)
void SetNTTDebugEnabled (const int n)
void SetNetQDebugEnabled (const int n)
 CTDL_MODULE_INIT (network)

Variables

int NetQDebugEnabled = 0
struct RoomProcListrplist = NULL
int NTTDebugEnabled = 0
static HashList * nttlist = NULL

Class Documentation

struct __roomlists

Definition at line 101 of file serv_network.c.

Collaboration diagram for __roomlists:
Class Members
HashList * RoomsInterestedIn
RoomProcList * rplist

Define Documentation

#define EXP   259200 /* three days */

Definition at line 34 of file serv_network.c.


Typedef Documentation

typedef struct __roomlists roomlists

Function Documentation

void cleanup_nttlist ( void  )

Definition at line 701 of file serv_network.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void cmd_nsyn ( char *  argbuf)

Definition at line 286 of file serv_network.c.

                            {
       int num_spooled;
       long len;
       char target_node[256];

       if (CtdlAccessCheck(ac_aide)) return;

       len = extract_token(target_node, argbuf, 0, '|', sizeof target_node);
       num_spooled = network_sync_to(target_node, len);
       if (num_spooled >= 0) {
              cprintf("%d Spooled %d messages.\n", CIT_OK, num_spooled);
       }
       else {
              cprintf("%d No such room/node share exists.\n",
                     ERROR + ROOM_NOT_FOUND);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

CTDL_MODULE_INIT ( network  )

Definition at line 374 of file serv_network.c.

{
       struct RoomProcList *cur, *p;

       cur = rplist;
       while (cur != NULL)
       {
              p = cur->next;
              free (cur);
              cur = p;             
       }
}

Here is the caller graph for this function:

Definition at line 387 of file serv_network.c.

Here is the call graph for this function:

Here is the caller graph for this function:

int GetNetworkedRoomNumbers ( const char *  DirName,
HashList *  DirList 
)

Definition at line 112 of file serv_network.c.

{
       DIR *filedir = NULL;
       struct dirent *d;
       struct dirent *filedir_entry;
       long RoomNR;
       long Count = 0;
              
       filedir = opendir (DirName);
       if (filedir == NULL) {
              return 0;
       }

       d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1);
       if (d == NULL) {
              return 0;
       }

       while ((readdir_r(filedir, d, &filedir_entry) == 0) &&
              (filedir_entry != NULL))
       {
              RoomNR = atol(filedir_entry->d_name);
              if (RoomNR != 0) {
                     Count++;
                     Put(DirList, LKEY(RoomNR), &Count, reference_free_handler);
              }
       }
       free(d);
       closedir(filedir);
       return Count;
}

Here is the caller graph for this function:

uint32_t hashlittle ( const void *  key,
size_t  length,
uint32_t  initval 
)

Here is the caller graph for this function:

void network_bounce ( struct CtdlMessage msg,
char *  reason 
)

Definition at line 399 of file serv_network.c.

{
       struct CitContext *CCC = CC;
       char *oldpath = NULL;
       char buf[SIZ];
       char bouncesource[SIZ];
       char recipient[SIZ];
       struct recptypes *valid = NULL;
       char force_room[ROOMNAMELEN];
       static int serialnum = 0;
       size_t size;

       QNM_syslog(LOG_DEBUG, "entering network_bounce()\n");

       if (msg == NULL) return;

       snprintf(bouncesource, sizeof bouncesource, "%s@%s", BOUNCESOURCE, config.c_nodename);

       /* 
        * Give it a fresh message ID
        */
       if (msg->cm_fields['I'] != NULL) {
              free(msg->cm_fields['I']);
       }
       snprintf(buf, sizeof buf, "%ld.%04lx.%04x@%s",
              (long)time(NULL), (long)getpid(), ++serialnum, config.c_fqdn);
       msg->cm_fields['I'] = strdup(buf);

       /*
        * FIXME ... right now we're just sending a bounce; we really want to
        * include the text of the bounced message.
        */
       if (msg->cm_fields['M'] != NULL) {
              free(msg->cm_fields['M']);
       }
       msg->cm_fields['M'] = strdup(reason);
       msg->cm_format_type = 0;

       /*
        * Turn the message around
        */
       if (msg->cm_fields['R'] == NULL) {
              free(msg->cm_fields['R']);
       }

       if (msg->cm_fields['D'] == NULL) {
              free(msg->cm_fields['D']);
       }

       snprintf(recipient, sizeof recipient, "%s@%s",
              msg->cm_fields['A'], msg->cm_fields['N']);

       if (msg->cm_fields['A'] == NULL) {
              free(msg->cm_fields['A']);
       }

       if (msg->cm_fields['N'] == NULL) {
              free(msg->cm_fields['N']);
       }

       if (msg->cm_fields['U'] == NULL) {
              free(msg->cm_fields['U']);
       }

       msg->cm_fields['A'] = strdup(BOUNCESOURCE);
       msg->cm_fields['N'] = strdup(config.c_nodename);
       msg->cm_fields['U'] = strdup("Delivery Status Notification (Failure)");

       /* prepend our node to the path */
       if (msg->cm_fields['P'] != NULL) {
              oldpath = msg->cm_fields['P'];
              msg->cm_fields['P'] = NULL;
       }
       else {
              oldpath = strdup("unknown_user");
       }
       size = strlen(oldpath) + SIZ;
       msg->cm_fields['P'] = malloc(size);
       snprintf(msg->cm_fields['P'], size, "%s!%s", config.c_nodename, oldpath);
       free(oldpath);

       /* Now submit the message */
       valid = validate_recipients(recipient, NULL, 0);
       if (valid != NULL) if (valid->num_error != 0) {
              free_recipients(valid);
              valid = NULL;
       }
       if ( (valid == NULL) || (!strcasecmp(recipient, bouncesource)) ) {
              strcpy(force_room, config.c_aideroom);
       }
       else {
              strcpy(force_room, "");
       }
       if ( (valid == NULL) && IsEmptyStr(force_room) ) {
              strcpy(force_room, config.c_aideroom);
       }
       CtdlSubmitMsg(msg, valid, force_room, 0);

       /* Clean up */
       if (valid != NULL) free_recipients(valid);
       CtdlFreeMessage(msg);
       QNM_syslog(LOG_DEBUG, "leaving network_bounce()\n");
}

Here is the call graph for this function:

Here is the caller graph for this function:

void network_cleanup_function ( void  )

Definition at line 722 of file serv_network.c.

{
       struct CitContext *CCC = CC;

       if (!IsEmptyStr(CCC->net_node)) {
              network_talking_to(CCC->net_node, strlen(CCC->net_node), NTT_REMOVE);
              CCC->net_node[0] = '\0';
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void network_do_queue ( void  )

Definition at line 514 of file serv_network.c.

{
       struct CitContext *CCC = CC;
       static int doing_queue = 0;
       static time_t last_run = 0L;
       int full_processing = 1;
       HashList *working_ignetcfg;
       HashList *the_netmap = NULL;
       int netmap_changed = 0;
       roomlists RL;

       /*
        * Run the full set of processing tasks no more frequently
        * than once every n seconds
        */
       if ( (time(NULL) - last_run) < config.c_net_freq ) {
              full_processing = 0;
              syslog(LOG_DEBUG, "Network full processing in %ld seconds.\n",
                     config.c_net_freq - (time(NULL)- last_run)
              );
       }

       /*
        * This is a simple concurrency check to make sure only one queue run
        * is done at a time.  We could do this with a mutex, but since we
        * don't really require extremely fine granularity here, we'll do it
        * with a static variable instead.
        */
       if (doing_queue) {
              return;
       }
       doing_queue = 1;

       become_session(&networker_spool_CC);
       begin_critical_section(S_RPLIST);
       RL.rplist = rplist;
       rplist = NULL;
       end_critical_section(S_RPLIST);

       RL.RoomsInterestedIn = NewHash(1, lFlathash);
       if (full_processing &&
           (GetNetworkedRoomNumbers(ctdl_netcfg_dir, RL.RoomsInterestedIn)==0))
       {
              doing_queue = 0;
              DeleteHash(&RL.RoomsInterestedIn);
              if (RL.rplist == NULL)
                     return;
       }
       /* Load the IGnet Configuration into memory */
       working_ignetcfg = load_ignetcfg();

       /*
        * Load the network map and filter list into memory.
        */
       if (!server_shutting_down)
              the_netmap = read_network_map();
       if (!server_shutting_down)
              load_network_filter_list();

       /* 
        * Go ahead and run the queue
        */
       if (full_processing && !server_shutting_down) {
              QNM_syslog(LOG_DEBUG, "network: loading outbound queue");
              CtdlForEachRoom(network_queue_interesting_rooms, &RL);
       }

       if ((RL.rplist != NULL) && (!server_shutting_down)) {
              RoomProcList *ptr, *cmp;
              ptr = RL.rplist;
              QNM_syslog(LOG_DEBUG, "network: running outbound queue");
              while (ptr != NULL && !server_shutting_down) {
                     
                     cmp = ptr->next;

                     while (cmp != NULL) {
                            if ((cmp->namelen > 0) &&
                                (cmp->key == ptr->key) &&
                                (cmp->namelen == ptr->namelen) &&
                                (strcmp(cmp->lcname, ptr->lcname) == 0))
                            {
                                   cmp->namelen = 0;
                            }
                            cmp = cmp->next;
                     }

                     if (ptr->namelen > 0) {
                            network_spoolout_room(ptr, 
                                                working_ignetcfg,
                                                the_netmap);
                     }
                     ptr = ptr->next;
              }
       }

       /* If there is anything in the inbound queue, process it */
       if (!server_shutting_down) {
              network_do_spoolin(working_ignetcfg, 
                               the_netmap,
                               &netmap_changed);
       }

       /* Free the filter list in memory */
       free_netfilter_list();

       /* Save the network map back to disk */
       if (netmap_changed) {
              StrBuf *MapStr = SerializeNetworkMap(the_netmap);
              CtdlPutSysConfig(IGNETMAP, SmashStrBuf(&MapStr));
       }

       /* combine singe message files into one spool entry per remote node. */
       network_consolidate_spoolout(working_ignetcfg, the_netmap);

       /* shut down. */

       DeleteHash(&the_netmap);

       DeleteHash(&working_ignetcfg);

       QNM_syslog(LOG_DEBUG, "network: queue run completed");

       if (full_processing) {
              last_run = time(NULL);
       }
       DeleteHash(&RL.RoomsInterestedIn);
       destroy_network_queue_room(RL.rplist);
       doing_queue = 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void network_logout_hook ( void  )

Definition at line 710 of file serv_network.c.

{
       CitContext *CCC = MyContext();

       /*
        * If we were talking to a network node, we're not anymore...
        */
       if (!IsEmptyStr(CCC->net_node)) {
              network_talking_to(CCC->net_node, strlen(CCC->net_node), NTT_REMOVE);
              CCC->net_node[0] = '\0';
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void network_queue_interesting_rooms ( struct ctdlroom qrbuf,
void *  data 
)

Definition at line 309 of file serv_network.c.

                                                                         {
       int i;
       struct RoomProcList *ptr;
       long QRNum = qrbuf->QRnumber;
       void *v;
       roomlists *RP = (roomlists*) data;

       if (!GetHash(RP->RoomsInterestedIn, LKEY(QRNum), &v))
              return;

       ptr = (struct RoomProcList *) malloc(sizeof (struct RoomProcList));
       if (ptr == NULL) return;

       ptr->namelen = strlen(qrbuf->QRname);
       if (ptr->namelen > ROOMNAMELEN)
              ptr->namelen = ROOMNAMELEN - 1;

       memcpy (ptr->name, qrbuf->QRname, ptr->namelen);
       ptr->name[ptr->namelen] = '\0';
       ptr->QRNum = qrbuf->QRnumber;

       for (i = 0; i < ptr->namelen; i++)
       {
              ptr->lcname[i] = tolower(ptr->name[i]);
       }

       ptr->lcname[ptr->namelen] = '\0';
       ptr->key = hashlittle(ptr->lcname, ptr->namelen, 9872345);
       ptr->next = RP->rplist;
       RP->rplist = ptr;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void network_queue_room ( struct ctdlroom qrbuf,
void *  data 
)

Definition at line 344 of file serv_network.c.

                                                            {
       int i;
       struct RoomProcList *ptr;

       if (qrbuf->QRdefaultview == VIEW_QUEUE)
              return;
       ptr = (struct RoomProcList *) malloc(sizeof (struct RoomProcList));
       if (ptr == NULL) return;

       ptr->namelen = strlen(qrbuf->QRname);
       if (ptr->namelen > ROOMNAMELEN)
              ptr->namelen = ROOMNAMELEN - 1;

       memcpy (ptr->name, qrbuf->QRname, ptr->namelen);
       ptr->name[ptr->namelen] = '\0';
       ptr->QRNum = qrbuf->QRnumber;

       for (i = 0; i < ptr->namelen; i++)
       {
              ptr->lcname[i] = tolower(ptr->name[i]);
       }
       ptr->lcname[ptr->namelen] = '\0';
       ptr->key = hashlittle(ptr->lcname, ptr->namelen, 9872345);

       begin_critical_section(S_RPLIST);
       ptr->next = rplist;
       rplist = ptr;
       end_critical_section(S_RPLIST);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int network_room_handler ( struct ctdlroom room)

Definition at line 647 of file serv_network.c.

{
       network_queue_room(room, NULL);
       return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int network_sync_to ( char *  target_node,
long  len 
)

Definition at line 211 of file serv_network.c.

{
       struct CitContext *CCC = CC;
       SpoolControl sc;
       int num_spooled = 0;
       int found_node = 0;
       char buf[256];
       char sc_type[256];
       char sc_node[256];
       char sc_room[256];
       char filename[PATH_MAX];
       FILE *fp;

       /* Grab the configuration line we're looking for */
       assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
       begin_critical_section(S_NETCONFIGS);
       fp = fopen(filename, "r");
       if (fp == NULL) {
              end_critical_section(S_NETCONFIGS);
              return(-1);
       }
       while (fgets(buf, sizeof buf, fp) != NULL)
       {
              buf[strlen(buf)-1] = 0;

              extract_token(sc_type, buf, 0, '|', sizeof sc_type);
              if (strcasecmp(sc_type, "ignet_push_share"))
                     continue;

              extract_token(sc_node, buf, 1, '|', sizeof sc_node);
              if (strcasecmp(sc_node, target_node))
                     continue;

              extract_token(sc_room, buf, 2, '|', sizeof sc_room);
              found_node = 1;
                     
              /* Concise syntax because we don't need a full linked-list */
              memset(&sc, 0, sizeof(SpoolControl));
              sc.ignet_push_shares = (maplist *)
                     malloc(sizeof(maplist));
              sc.ignet_push_shares->next = NULL;
              safestrncpy(sc.ignet_push_shares->remote_nodename,
                         sc_node,
                         sizeof sc.ignet_push_shares->remote_nodename);
              safestrncpy(sc.ignet_push_shares->remote_roomname,
                         sc_room,
                         sizeof sc.ignet_push_shares->remote_roomname);
       }
       fclose(fp);
       end_critical_section(S_NETCONFIGS);

       if (!found_node) return(-1);

       sc.working_ignetcfg = load_ignetcfg();
       sc.the_netmap = read_network_map();

       /* Send ALL messages */
       num_spooled = CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
              network_spool_msg, &sc);

       /* Concise cleanup because we know there's only one node in the sc */
       free(sc.ignet_push_shares);

       DeleteHash(&sc.working_ignetcfg);
       DeleteHash(&sc.the_netmap);

       QN_syslog(LOG_NOTICE, "Synchronized %d messages to <%s>\n",
                num_spooled, target_node);
       return(num_spooled);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int network_talking_to ( const char *  nodename,
long  len,
int  operation 
)

Definition at line 659 of file serv_network.c.

                                                                      {

       int retval = 0;
       HashPos *Pos = NULL;
       void *vdata;

       begin_critical_section(S_NTTLIST);

       switch(operation) {

              case NTT_ADD:
                     if (nttlist == NULL) 
                            nttlist = NewHash(1, NULL);
                     Put(nttlist, nodename, len, NewStrBufPlain(nodename, len), HFreeStrBuf);
                     if (NTTDebugEnabled) syslog(LOG_DEBUG, "nttlist: added <%s>\n", nodename);
                     break;
              case NTT_REMOVE:
                     if ((nttlist == NULL) ||
                         (GetCount(nttlist) == 0))
                            break;
                     Pos = GetNewHashPos(nttlist, 1);
                     if (GetHashPosFromKey (nttlist, nodename, len, Pos))
                            DeleteEntryFromHash(nttlist, Pos);
                     DeleteHashPos(&Pos);
                     if (NTTDebugEnabled) syslog(LOG_DEBUG, "nttlist: removed <%s>\n", nodename);

                     break;

              case NTT_CHECK:
                     if ((nttlist == NULL) ||
                         (GetCount(nttlist) == 0))
                            break;
                     if (GetHash(nttlist, nodename, len, &vdata))
                            retval ++;
                     if (NTTDebugEnabled) syslog(LOG_DEBUG, "nttlist: have [%d] <%s>\n", retval, nodename);
                     break;
       }

       end_critical_section(S_NTTLIST);
       return(retval);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int network_usetable ( struct CtdlMessage msg)

Definition at line 153 of file serv_network.c.

{
       struct CitContext *CCC = CC;
       char msgid[SIZ];
       struct cdbdata *cdbut;
       struct UseTable ut;

       /* Bail out if we can't generate a message ID */
       if (msg == NULL) {
              return(0);
       }
       if (msg->cm_fields['I'] == NULL) {
              return(0);
       }
       if (IsEmptyStr(msg->cm_fields['I'])) {
              return(0);
       }

       /* Generate the message ID */
       strcpy(msgid, msg->cm_fields['I']);
       if (haschar(msgid, '@') == 0) {
              strcat(msgid, "@");
              if (msg->cm_fields['N'] != NULL) {
                     strcat(msgid, msg->cm_fields['N']);
              }
              else {
                     return(0);
              }
       }

       cdbut = cdb_fetch(CDB_USETABLE, msgid, strlen(msgid));
       if (cdbut != NULL) {
              cdb_free(cdbut);
              QN_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) );
       return(0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void SetNetQDebugEnabled ( const int  n)

Definition at line 740 of file serv_network.c.

Here is the caller graph for this function:

void SetNTTDebugEnabled ( const int  n)

Definition at line 736 of file serv_network.c.

Here is the caller graph for this function:


Variable Documentation

Definition at line 95 of file serv_network.c.

int NTTDebugEnabled = 0

Definition at line 653 of file serv_network.c.

HashList* nttlist = NULL [static]

Definition at line 658 of file serv_network.c.

struct RoomProcList* rplist = NULL

Definition at line 110 of file serv_network.c.