Source File modules/sv/server.c

    1    | /***************************************
    2    |   $Revision: 1.50 $
    3    |
    4    |   Example code: A server for a client to connect to.
    5    |
    6    |   Status: NOT REVUED, NOT TESTED
    7    |
    8    |   Authors:       Chris Ottrey, Joao Damas,
    9    |                  heavy rewrite by Andrei Robachevsky, Marek Bukowy
    10   |
    11   |   +html+ <DL COMPACT>
    12   |   +html+ <DT>Online References:
    13   |   +html+ <DD><UL>
    14   |   +html+   <LI>Based on <A HREF="http://iii.ripe.net/dbase/coding/new.code/progress/ottrey/code/java/src/DBServer.java">DBServer.java</A>
    15   |   +html+ </UL>
    16   |   +html+ </DL>
    17   |
    18   |   ******************/ /******************
    19   |   Modification History:
    20   |         ottrey (02/03/1999) Created.
    21   |         ottrey (08/03/1999) Modified.
    22   |         joao   (22/06/1999) Modified.
    23   |   ******************/ /******************
    24   |   Copyright (c) 1999                              RIPE NCC
    25   |
    26   |   All Rights Reserved
    27   |
    28   |   Permission to use, copy, modify, and distribute this software and its
    29   |   documentation for any purpose and without fee is hereby granted,
    30   |   provided that the above copyright notice appear in all copies and that
    31   |   both that copyright notice and this permission notice appear in
    32   |   supporting documentation, and that the name of the author not be
    33   |   used in advertising or publicity pertaining to distribution of the
    34   |   software without specific, written prior permission.
    35   |
    36   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    37   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
    38   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    39   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    40   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    41   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    42   |  ***************************************/
    43   |
    44   | #include <ctype.h>
    45   |
    46   | #include <sys/types.h>
    47   | #include <sys/stat.h>
    48   | #include <sys/wait.h>
    49   | #include <sys/socket.h>
    50   | #include <netinet/in.h>
    51   |
    52   | #include "thread.h"
    53   | #include "rxroutines.h"
    54   | #include "sk.h"
    55   | /*
    56   | #include "objects.h"
    57   | */
    58   | #include "constants.h"
    59   |
    60   | #include "ca_configFns.h"
    61   | #include "ca_dictionary.h"
    62   | #include "ca_macros.h"
    63   | #include "ca_srcAttribs.h"
    64   |
    65   | #include "mysql_driver.h"
    66   | #include "access_control.h"
    67   | #include "ud.h"
    68   | #include "server.h"
    69   |
    70   | #include "rp.h"
    71   | #include "memwrap.h"
    72   |
    73   | #include "ta.h"
    74   |
    75   | #include "protocol_whois.h"
    76   | #include "protocol_mirror.h"
    77   | #include "protocol_config.h"
    78   |
    79   | /*+ String sizes +*/
    80   | #define STR_S   63
    81   | #define STR_M   255
    82   | #define STR_L   1023
    83   | #define STR_XL  4095
    84   | #define STR_XXL 16383
    85   |
    86   | /* Storage for descriptors of the read side of the pipe */
    87   | int sv_lockfd[MAX_LOCKS];
    88   |
    89   | /* Listening sockets */
    90   | int SV_whois_sock;
    91   | int SV_config_sock;
    92   | int SV_mirror_sock;
    93   |
    94   | /* each updatable source has its own update thread and its own socket */
    95   | #define MAX_SOURCES 100
    96   | int SV_update_sock[MAX_SOURCES];
    97   |
    98   |
    99   | /*+ Server starting time +*/
    100  | time_t SV_starttime;
    101  |
    102  | /* Logging results */
    103  | static void log_print(const char *arg) {
    104  |
    105  |   printf(arg);
    106  |
    107  | } /* log_print() */
    108  |
    109  |
    110  | /* counters - by marek */
    111  | typedef struct {
    112  |   int count;
    113  |   pthread_mutex_t lock; /*+ Mutex lock.Used for synchronizing changes.+*/
    114  |   pthread_cond_t  cond; /*+ condition variable +*/
    115  | } svr_counter_t;
    116  |
    117  |
    118  | /* structure passed to every running server */
    119  | typedef struct {
    120  |   void (*function)(int);
    121  |   int conn_sock;
    122  |   int accept_sock;
    123  |   int limit;         /* limit for the number of concurrent connections */
    124  |   svr_counter_t *counter; /* number of active clients */
    125  |   char *name;
    126  | } svr_args;
    127  |
    128  |
    129  | /*++++++++++++++++++++++++++++++++++++++
    130  |   function to operate on the counter structures -
    131  |   takes the increment (can be negative), changes the value
    132  |   using the locks and everything,
    133  |
    134  |   int
    135  |   counter_add            returns the new value.
    136  |
    137  |   svr_counter_t *cst     counter structure
    138  |
    139  |   int incval             increment value (can be negative)
    140  |
    141  |   Author:
    142  |     marek
    143  |   ++++++++++++++++++++++++++++++++++++++*/
    144  | static
    145  | int
    146  | counter_add( svr_counter_t *cst, int incval )
    147  | {
    148  |     int newval;
    149  |
    150  |     /* add under mutex */
    151  |     pthread_mutex_lock( &(cst->lock) );
    152  |     cst->count += incval;
    153  |     newval = cst->count;
    154  |     pthread_mutex_unlock(&(cst->lock) );
    155  |
    156  |     /* now - signal the change of value to the waiting thread */
    157  |     pthread_cond_signal( &(cst->cond) );
    158  |
    159  |     return newval;
    160  | }
    161  |
    162  |
    163  | /*++++++++++++++++++++++++++++++++++++++
    164  |
    165  |   int
    166  |   counter_state         returns the current value of a counter
    167  |
    168  |   svr_counter_t *cst    counter
    169  |
    170  |   Author:
    171  |     marek
    172  |
    173  |   ++++++++++++++++++++++++++++++++++++++*/
    174  | static
    175  | int
    176  | counter_state( svr_counter_t *cst )
    177  | {
    178  |   return counter_add( cst, 0 );
    179  | }
    180  |
    181  |
    182  | /*++++++++++++++++++++++++++++++++++++++
    183  |   waits until the counter is in the range [0-limit].
    184  |   unless the limit is 0, in which case the check is disabled.
    185  |
    186  |   int counter_wait      returns the new value of the counter after wait
    187  |
    188  |   svr_counter_t *cst    counter
    189  |
    190  |   int limit             limit / range, or 0 to disable the check
    191  |
    192  |   Author:
    193  |     marek
    194  |   ++++++++++++++++++++++++++++++++++++++*/
    195  | static
    196  | int counter_wait(svr_counter_t *cst, int limit )
    197  | {
    198  |   int newval;
    199  |
    200  |   pthread_mutex_lock( &(cst->lock) );
    201  |
    202  |   if( limit != 0 ) {
    203  |     while( cst->count >= limit ) {
    204  |       pthread_cond_wait( &(cst->cond), &(cst->lock));
    205  |     }
    206  |   }
    207  |
    208  |   newval = cst->count;
    209  |   pthread_mutex_unlock(&(cst->lock) );
    210  |
    211  |   return newval;
    212  | }
    213  |
    214  | /*++++++++++++++++++++++++++++++++++++++
    215  |
    216  |   Loading the radix tree. Started as a separate thread.
    217  |
    218  |   Author:
    219  |     marek
    220  |   ++++++++++++++++++++++++++++++++++++++*/
    221  | void radix_init(void){
    222  |   int i;
    223  |   ca_dbSource_t *source_hdl;
    224  |
    225  |   wr_log_set(0);
    226  |   /* this needs to be done in two loops,
    227  |      because the trees must be created asap (first loop)
    228  |      and then locked until they are populated in the second loop
    229  |   */
    230  |
    231  |   for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){
    232  |     dieif( RP_init_trees( source_hdl ) != RP_OK );
    233  |   }
    234  |
    235  |   for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){
    236  |     dieif( RP_sql_load_reg( source_hdl ) != RP_OK );
    237  |   }
    238  |
    239  |   wr_log_set(0); /* switch on/off the memory leak detector */
    240  | /*  pthread_mutex_unlock( &radix_initializing_lock );  */
    241  |
    242  |   pthread_exit((void *)0);
    243  | }
    244  |
    245  |
    246  | /************************************************************
    247  | *  int SV_sleep()                                           *
    248  | *                                                           *
    249  | * sleeps till shutdown request comes                        *
    250  | * but at most <delay> seconds                               *
    251  | *                                                           *
    252  | * Returns:                                                  *
    253  | * 1 - timeout                                               *
    254  | * 0 - shutdown                                              *
    255  | *                                                           *
    256  | ************************************************************/
    257  |
    258  | int SV_sleep(int delay)
    259  | {
    260  |  int do_server;
    261  |  int elapsed_time=0;
    262  |
    263  |  while((do_server=CO_get_do_server()) && (elapsed_time<delay))
    264  |  {
    265  |   sleep(TIME_SLICE);
    266  |   elapsed_time+=TIME_SLICE;
    267  |  }
    268  |  if(elapsed_time<delay)return(1); else return(0);
    269  | }
    270  |
    271  | /*++++++++++++++++++++++++++++++++++++++
    272  |
    273  |   Handle signals.
    274  |
    275  |   Changes the flags:
    276  |   	do_nrtm
    277  |   	do_update
    278  |   	do_whoisd
    279  |
    280  |   More:
    281  |   +html+ <PRE>
    282  |   Author:
    283  |         andrei
    284  |   +html+ </PRE>
    285  |   ++++++++++++++++++++++++++++++++++++++*/
    286  | void *SV_signal_thread() {
    287  | char print_buf[STR_M];
    288  | sigset_t sset;
    289  | int sigReceived;
    290  | int do_update;
    291  |
    292  | 	sigemptyset(&sset);
    293  | 	sigaddset(&sset, SIGTERM);
    294  | 	sigaddset(&sset, SIGINT);
    295  | 	sigaddset(&sset, SIGUSR1);
    296  | 	/* This is a bit confusing, but is needed */
    297  | 	/* For more information on signal handling in */
    298  | 	/* threads see for example "Multithreading Programming */
    299  | 	/* Techniques" by Shashi Prasad, ISBN 0-07-912250-7, pp. 94-101 */
    300  | 	pthread_sigmask(SIG_BLOCK, &sset, NULL);
    301  | 	/*	fprintf(stderr, "Signal handler installed\n");*/
    302  |
    303  | 	for(;;)
    304  | 	{
    305  | 	 sigwait(&sset, &sigReceived);
    306  | 	 sprintf(print_buf, "Signal received [%d]\n", sigReceived);
    307  | 	 log_print(print_buf); strcpy(print_buf, "");
    308  | 	 /*	 fprintf(stderr, "Signal received [%d]\n", sigReceived); */
    309  | 	 switch (sigReceived)
    310  | 	 {
    311  | 	   case SIGINT:
    312  | 	   /* SIGINT stops all servers */
    313  | 	        SV_shutdown();
    314  |                 pthread_exit((void *)0);
    315  |   	        break;
    316  |
    317  |   	   case SIGTERM:
    318  |   	   /* SIGTERM will switch the updates on and off */
    319  |   	        do_update=CO_get_do_update();
    320  |   	        if(do_update)do_update=0; else do_update=1;
    321  |   	   	sprintf(print_buf, "%d", do_update);
    322  | 		CO_set_const("UD.do_update", print_buf);
    323  | 		if(do_update)
    324  | 		  sprintf(print_buf, "Starting updates\n");
    325  | 		else
    326  | 		  sprintf(print_buf, "Stopping updates\n");
    327  | 		log_print(print_buf); strcpy(print_buf, "");
    328  | 		/*		fprintf(stderr, "Stopping updates (SIGTERM received)\n"); */
    329  |   	   	break;
    330  |   	 }
    331  |   	}
    332  | } /* SV_signal_thread() */
    333  |
    334  |
    335  | /* SV_do_child() */
    336  | /*++++++++++++++++++++++++++++++++++++++
    337  |
    338  |   Handle whois/config/mirror connections. Takes a pointer to the
    339  |   service description structure, containing a connected socket, limit
    340  |   of active threads, pointer to the counter of them. Does not stop to
    341  |   obey the limits, assumes this to be checked and assumes that it is
    342  |   already counted.  Decrements the counter on exit.
    343  |
    344  |   Precondition: the counter must be incremented before this function is called.
    345  |
    346  |   void *SV_do_child     Actually, does not return anything useful. Just NULL.
    347  |
    348  |   void *varg            service description structure.
    349  |
    350  |   Author:
    351  |     marek
    352  |   ++++++++++++++++++++++++++++++++++++++*/
    353  | void *SV_do_child(void *varg)
    354  | {
    355  |   svr_args *args = (svr_args *) varg;
    356  |   int sock = args->conn_sock;
    357  |   int curclients;
    358  |
    359  |   ER_dbg_va(FAC_TH, ASP_TH_NEW,
    360  | 	    ": Child thread [%d]: Socket number = %d",
    361  | 	    args->name, pthread_self(), sock);
    362  |
    363  |   curclients = counter_state( args->counter ); /* already added */
    364  |   ER_dbg_va(FAC_TH, ASP_TH_NEW,
    365  | 	    "%s threads++ = %d", args->name, curclients);
    366  |
    367  |   TA_add(sock, args->name);
    368  |
    369  |   args->function(sock);
    370  |
    371  |   /* TA_delete must come first - otherwise the server would crash
    372  |      when trying to report address of a closed socket */
    373  |   TA_delete();
    374  |   close(sock);
    375  |
    376  |   /* update the global thread counter. */
    377  |   curclients = counter_add( args->counter, -1);
    378  |   ER_dbg_va(FAC_TH, ASP_TH_NEW,
    379  | 	    "%s threads-- = %d", args->name, curclients);
    380  |
    381  |   free(args);
    382  |
    383  |   return NULL; /* exit the thread */
    384  | } /* SV_do_child */
    385  |
    386  |
    387  | /* main_loop() */
    388  | /*++++++++++++++++++++++++++++++++++++++
    389  |
    390  |   Waits for an incoming connection on the and spawns a new thread to
    391  |   handle it.  Takes a pointer to the service description structure
    392  |   containing the number of the listening socket, limit of active
    393  |   threads, pointer to the counter of them, and the function to call
    394  |   with a connected socket.  Increments the counter before starting
    395  |   a client thread to run SV_do_child().
    396  |
    397  |   void *arg      pointer to the service description structure.
    398  |
    399  |   More:
    400  |   +html+ <PRE>
    401  |   Author:
    402  |         ottrey
    403  | 	joao
    404  | 	andrei (do_server)
    405  | 	marek (rewritten/simplified/added limits)
    406  |   +html+ </PRE>
    407  |   ++++++++++++++++++++++++++++++++++++++*/
    408  | static void  *main_loop(void *arg) {
    409  |   svr_args *argset = (svr_args *)arg;
    410  |   svr_args *argcopy;
    411  |   char loopname[32];
    412  |   int children;
    413  |   char chnum[16];
    414  |
    415  |   snprintf(loopname, 32, "s-%s", argset->name);
    416  |
    417  |   TA_add(0, loopname);
    418  |
    419  |   while( CO_get_do_server() != 0 ) {
    420  |     /* check the number of clients, do not proceed until it's below limit */
    421  |     children = counter_wait( argset->counter, argset->limit );
    422  |     snprintf(chnum, 16, "%d", children);
    423  |     TA_setactivity(chnum); /* display the current number of children */
    424  |
    425  |     /* wait for new connections */
    426  |     argset->conn_sock = SK_accept_connection(argset->accept_sock);
    427  |     if(argset->conn_sock == -1) {
    428  |       break;
    429  |     }
    430  |
    431  |     ER_dbg_va(FAC_TH, ASP_TH_NEW, "%s: starting a new child thread",
    432  | 	      loopname);
    433  |     TA_increment();
    434  |     /* incrementing argset->counter here - to avoid race condition and
    435  |        ensure a _more_correct_ value of current clients also for unlimited
    436  |        or infrequent connections. Does not really matter otherwise.
    437  |
    438  |        NOTE: this architecture implies that higher values can be
    439  |        displayed for infrequent threads, because there's no way
    440  |        to change it when threads are exiting while this thread is
    441  |        blocked in call to accept(). If this call was in the child thread,
    442  |        the number would be an underestimation instead. I prefer over-e.
    443  |     */
    444  |     counter_add( argset->counter, 1);
    445  |
    446  |     /* Start a new thread. will decrement counter when exiting */
    447  |
    448  |     /* now. There's a race condition - argset must be copied in SV_do_child
    449  |        and can be reused here only afterwards. To avoid it, we make a copy
    450  |        and expect SV_do_child to free it after use.
    451  |        Caveat: the counter remains where it was, we just copy the pointer.
    452  |     */
    453  |     argcopy = malloc( sizeof(svr_args) );
    454  |     memcpy( argcopy, argset, sizeof(svr_args) );
    455  |     TH_create( SV_do_child, (void *)argcopy );
    456  |   }
    457  |
    458  |   TA_delete();
    459  |   ER_dbg_va(FAC_TH, ASP_TH_NEW, "Exiting from the main loop");
    460  |
    461  |   pthread_exit((void *)0);
    462  |   return NULL; /* stupid compilers. */
    463  | } /* main_loop() */
    464  |
    465  | /* SV_concurrent_server() */
    466  | /*++++++++++++++++++++++++++++++++++++++
    467  |
    468  |   This is the routine that creates the main threads.
    469  |
    470  |   int     sock        The socket to connect to.
    471  |
    472  |   int     limit       Limit of active clients (0 == no limit)
    473  |
    474  |   void *  do_function The function to call for each type of service
    475  |
    476  |   More:
    477  |   +html+ <PRE>
    478  |   Author:
    479  |         ottrey
    480  | 	joao
    481  | 	marek
    482  |   +html+ </PRE>
    483  |   ++++++++++++++++++++++++++++++++++++++*/
    484  | static
    485  | void SV_concurrent_server(int sock, int limit,  char *name,
    486  | 			  void do_function(int))
    487  | {
    488  |   svr_args *args;
    489  |
    490  |   dieif( wr_calloc((void **)&args, 1, sizeof(svr_args)) != UT_OK);
    491  |
    492  |   args->accept_sock=sock;
    493  |   args->limit=limit;
    494  |   args->name=name;
    495  |   args->function=do_function;
    496  |
    497  |   dieif( wr_calloc((void **)&(args->counter),1,sizeof(svr_counter_t)) != UT_OK);
    498  |   pthread_mutex_init( &(args->counter->lock), NULL );
    499  |   pthread_cond_init(  &(args->counter->cond), NULL );
    500  |   args->counter->count = 0;
    501  |
    502  |
    503  |   /* Start a new thread. */
    504  |
    505  |   TH_create(main_loop, (void *)args);
    506  |
    507  | } /* SV_concurrent_server() */
    508  |
    509  | /* SV_start() */
    510  | /*++++++++++++++++++++++++++++++++++++++
    511  |
    512  |   Start the server.
    513  |
    514  |   More:
    515  |   +html+ <PRE>
    516  |   Authors:
    517  |         ottrey
    518  |         joao
    519  |   +html+ </PRE>
    520  |   +html+ Starts up the server.
    521  |   +html+ <OL>
    522  |   +html+   <LI> Create sockets on the necessary ports (whois, config and mirror)
    523  |   +html+   <LI> Start new threads for each service.
    524  |   +html+ </OL>
    525  |   +html+ <A HREF=".DBrc">.properties</A>
    526  |
    527  |   ++++++++++++++++++++++++++++++++++++++*/
    528  | void SV_start() {
    529  |   int whois_port = -1;
    530  |   int config_port = -1;
    531  |   int mirror_port = -1;
    532  |   int update_port = -1;
    533  |   int update_mode = 0;
    534  |   int fdes[2];
    535  |   struct timeval tval;
    536  |   ca_dbSource_t *source_hdl;
    537  |   char *source_name;
    538  |   int source;
    539  |   char *db_host, *db_name, *db_user, *db_passwd;
    540  |   int db_port;
    541  |   SQ_connection_t *db_connection;
    542  |
    543  |   /* Store the starting time */
    544  |   gettimeofday(&tval, NULL);
    545  |   SV_starttime = tval.tv_sec;/* seconds since Jan. 1, 1970 */
    546  |
    547  |   /* Create interrupt pipe */
    548  |   /* Writing to this pipe will cause sleeping threads */
    549  |   /* to wake up */
    550  |   fprintf(stderr, "Creating an interrupt pipe\n");
    551  |   if(pipe(fdes)==-1) {
    552  |    printf("Cannot open interrupt pipe\n");
    553  |    exit(-1);
    554  |   }
    555  |   /* Save the pipe descriptors in sv_lock array */
    556  |   sv_lockfd[WLOCK_SHTDOWN]=fdes[0];
    557  |   sv_lockfd[LOCK_SHTDOWN]=fdes[1];
    558  |
    559  |   /* Initialise modules */
    560  |   SK_init();
    561  |
    562  |   /* Initialise the access control list. */
    563  |   AC_build();
    564  |   AC_acc_load();
    565  |   /* explicitly start the decay thread */
    566  |   TH_create((void *(*)(void *))AC_decay, NULL);
    567  |
    568  |
    569  |
    570  |   /* Get port information for each service */
    571  |   whois_port  = ca_get_svwhois_port;
    572  |   ER_dbg_va(FAC_SV, ASP_SV_PORT, "whois port is %d", whois_port);
    573  |
    574  |   config_port = ca_get_svconfig_port;
    575  |   ER_dbg_va(FAC_SV, ASP_SV_PORT, "config port is %d", config_port);
    576  |
    577  |   mirror_port = ca_get_svmirror_port;
    578  |   ER_dbg_va(FAC_SV, ASP_SV_PORT, "mirror port is %d", mirror_port);
    579  |
    580  |
    581  |   /* 6. Create a socket on the necessary ports/addresses and bind to them. */
    582  |   /* whois socket */
    583  |   SV_whois_sock = SK_getsock(SOCK_STREAM, whois_port, 128, INADDR_ANY);
    584  | /* Currently binds to INADDR_ANY. Will need to get specific address */
    585  | /*  SV_whois_sock = SK_getsock(SOCK_STREAM,whois_port,whois_addr); */
    586  |   /* config interface socket */
    587  |   SV_config_sock = SK_getsock(SOCK_STREAM, config_port, 5, INADDR_ANY);
    588  |   /* nrt socket */
    589  |   SV_mirror_sock = SK_getsock(SOCK_STREAM,mirror_port, 5, INADDR_ANY);
    590  |
    591  |   /* Check every Database and create sockets */
    592  |   /* we need first to create and bind all of them */
    593  |   /* so that in case of failure we do not start any */
    594  |   /* update thread */
    595  |   fprintf(stderr, "Check the DB\n");
    596  |   for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){
    597  |      /* check for crash and recover if needed */
    598  |      /* make a connection to a database */
    599  |      db_host = ca_get_srcdbmachine(source_hdl);
    600  |      db_port = ca_get_srcdbport(source_hdl);
    601  |      db_name = ca_get_srcdbname(source_hdl);
    602  |      db_user = ca_get_srcdbuser(source_hdl);
    603  |      db_passwd = ca_get_srcdbpassword(source_hdl);
    604  |      db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd);
    605  |      /* now check TR record */
    606  |      TR_recover(db_connection);
    607  |      /* free resources */
    608  |      SQ_close_connection(db_connection);
    609  |      free(db_host);
    610  |      free(db_name);
    611  |      free(db_user);
    612  |      free(db_passwd);
    613  |
    614  |      update_mode = ca_get_srcmode(source_hdl);
    615  |      if(IS_UPDATE(update_mode)) {
    616  |        /* update_port = SK_atoport(CO_get_update_port(), "tcp"); */
    617  |        update_port = ca_get_srcupdateport(source_hdl);
    618  |        printf("XXX htons(update_port)=%d\n", update_port);
    619  |        /* XXX ask AMRM to change the name of the function */
    620  |
    621  |        SV_update_sock[source] = SK_getsock(SOCK_STREAM, update_port, 5, INADDR_ANY);
    622  |      }
    623  |      else SV_update_sock[source] = 0;
    624  |   }
    625  |   SV_update_sock[source+1]=-1; /* end of socket array */
    626  |
    627  |    /* Initialise the radix tree (separate thread[s])
    628  |      already can allow socket connections, because the trees will
    629  |      be created locked, and will be unlocked when loaded */
    630  |
    631  | /*   pthread_mutex_lock( &radix_initializing_lock );  */
    632  |   TH_create((void *(*)(void *))radix_init, NULL);
    633  | /*  pthread_mutex_lock( &radix_initializing_lock );  */
    634  |
    635  |
    636  |   /* Now.... accept() calls block until they get a connection
    637  |      so to listen on more than one port we need more
    638  |      than one thread */
    639  |
    640  |   /* Create master thread for whois threads */
    641  |   SV_concurrent_server(SV_whois_sock, 64, "whois", PW_interact);
    642  |
    643  |   /* Create master thread for config threads */
    644  |   SV_concurrent_server(SV_config_sock, 0, "config", PC_interact);
    645  |   /* Create master thread for mirror threads */
    646  |   SV_concurrent_server(SV_mirror_sock, 0, "mirror", PM_interact);
    647  |
    648  |   /* Walk through the sources and */
    649  |   /* run update thread for every source with CANUPD == 'y' */
    650  |
    651  |    for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){
    652  |      update_mode = ca_get_srcmode(source_hdl);
    653  |      source_name= ca_get_srcname(source_hdl);
    654  |
    655  |      if(IS_UPDATE(update_mode)) {
    656  |      /* run RIPupdate thread */
    657  |        fprintf(stderr,"Source [%s] Mode UPDATE\n", source_name);
    658  |        TH_create((void *(*)(void *))UD_do_updates, (void *)source);
    659  |      }
    660  |      else if(IS_NRTM_CLNT(update_mode)){
    661  |        /* start NRTM client */
    662  |        fprintf(stderr,"Source [%s] Mode NRTM\n", source_name);
    663  |        TH_create((void *(*)(void *))UD_do_nrtm, (void *)source);
    664  |      }
    665  |      else fprintf(stderr,"Source [%s] Mode STATIC\n", source_name);
    666  |      free(source_name); /* because ca_* functions return copies */
    667  |    }
    668  |
    669  |   pthread_exit(NULL);
    670  |
    671  | } /* SV_start() */
    672  |
    673  | /* SV_shutdown() */
    674  | /*++++++++++++++++++++++++++++++++++++++
    675  |
    676  |   Shutdown the server.
    677  |
    678  |   More:
    679  |   +html+ <PRE>
    680  |   Authors:
    681  |         andrei
    682  |   +html+ </PRE>
    683  |   +html+ Stops the server.
    684  |   +html+ <OL>
    685  |   +html+   <LI> Close listening sockets (whois, config, mirror and updates)
    686  |   +html+   <LI> Stop all threads by triggering do_server variable.
    687  |   +html+ </OL>
    688  |   +html+ <A HREF=".DBrc">.properties</A>
    689  |
    690  |   ++++++++++++++++++++++++++++++++++++++*/
    691  | void SV_shutdown() {
    692  | char print_buf[STR_M];
    693  | int source;
    694  |
    695  |  sprintf(print_buf, "%d", 0);
    696  |  /* Stop updates */
    697  |  CO_set_const("UD.do_update", print_buf);
    698  |  /* Stop all servers */
    699  |  CO_set_const("SV.do_server", print_buf);
    700  |  sprintf(print_buf, "Stopping all servers\n");
    701  |  fprintf(stderr, print_buf);
    702  |  /*log_print(print_buf); */
    703  |  strcpy(print_buf, "");
    704  |
    705  |  /* Wake up all sleeping threads */
    706  |  fprintf(stderr, "Going to wake sleeping threads up\n");
    707  |  write(sv_lockfd[WLOCK_SHTDOWN], " ", 1);
    708  |
    709  |  /* CLose all listening sockets, so accept call exits */
    710  |  close(SV_whois_sock);
    711  |  close(SV_config_sock);
    712  |  close(SV_mirror_sock);
    713  |  for (source=0; SV_update_sock[source]!=-1; source++)
    714  | 	 if(SV_update_sock[source]!=0)close(SV_update_sock[source]);
    715  |
    716  |
    717  | } /* SV_shutdown() */