Source File modules/sv/server.c

    1    | /***************************************
    2    |   $Revision: 1.58 $
    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 "ud_tr.h"
    69   | #include "server.h"
    70   |
    71   | #include "rp.h"
    72   | #include "memwrap.h"
    73   |
    74   | #include "ta.h"
    75   |
    76   | #include "protocol_whois.h"
    77   | #include "protocol_mirror.h"
    78   | #include "protocol_config.h"
    79   |
    80   | /*+ String sizes +*/
    81   | #define STR_S   63
    82   | #define STR_M   255
    83   | #define STR_L   1023
    84   | #define STR_XL  4095
    85   | #define STR_XXL 16383
    86   |
    87   | /* Listening sockets */
    88   | int SV_whois_sock;
    89   | int SV_config_sock;
    90   | int SV_mirror_sock;
    91   |
    92   | /* each updatable source has its own update thread and its own socket */
    93   | #define MAX_SOURCES 100
    94   | int SV_update_sock[MAX_SOURCES];
    95   |
    96   |
    97   |
    98   | /*+ Server starting time +*/
    99   | time_t SV_starttime;
    100  | /* the filename where we store the PID of the server */
    101  | char *SV_pidfile;
    102  |
    103  | /* Logging results */
    104  | static void log_print(const char *arg) {
    105  |
    106  |   printf(arg);
    107  |
    108  | } /* log_print() */
    109  |
    110  |
    111  | /* counters - by marek */
    112  | typedef struct {
    113  |   int count;
    114  |   pthread_mutex_t lock; /*+ Mutex lock.Used for synchronizing changes.+*/
    115  |   pthread_cond_t  cond; /*+ condition variable +*/
    116  | } svr_counter_t;
    117  |
    118  |
    119  | /* structure passed to every running server */
    120  | typedef struct {
    121  |   void (*function)(int);
    122  |   int conn_sock;
    123  |   int accept_sock;
    124  |   int limit;         /* limit for the number of concurrent connections */
    125  |   svr_counter_t *counter; /* number of active clients */
    126  |   char *name;
    127  | } svr_args;
    128  |
    129  |
    130  | /*++++++++++++++++++++++++++++++++++++++
    131  |   function to operate on the counter structures -
    132  |   takes the increment (can be negative), changes the value
    133  |   using the locks and everything,
    134  |
    135  |   int
    136  |   counter_add            returns the new value.
    137  |
    138  |   svr_counter_t *cst     counter structure
    139  |
    140  |   int incval             increment value (can be negative)
    141  |
    142  |   Author:
    143  |     marek
    144  |   ++++++++++++++++++++++++++++++++++++++*/
    145  | static
    146  | int
    147  | counter_add( svr_counter_t *cst, int incval )
    148  | {
    149  |     int newval;
    150  |
    151  |     /* add under mutex */
    152  |     pthread_mutex_lock( &(cst->lock) );
    153  |     cst->count += incval;
    154  |     newval = cst->count;
    155  |     pthread_mutex_unlock(&(cst->lock) );
    156  |
    157  |     /* now - signal the change of value to the waiting thread */
    158  |     pthread_cond_signal( &(cst->cond) );
    159  |
    160  |     return newval;
    161  | }
    162  |
    163  |
    164  | /*++++++++++++++++++++++++++++++++++++++
    165  |
    166  |   int
    167  |   counter_state         returns the current value of a counter
    168  |
    169  |   svr_counter_t *cst    counter
    170  |
    171  |   Author:
    172  |     marek
    173  |
    174  |   ++++++++++++++++++++++++++++++++++++++*/
    175  | static
    176  | int
    177  | counter_state( svr_counter_t *cst )
    178  | {
    179  |   return counter_add( cst, 0 );
    180  | }
    181  |
    182  |
    183  | /*++++++++++++++++++++++++++++++++++++++
    184  |   waits until the counter is in the range [0-limit].
    185  |   unless the limit is 0, in which case the check is disabled.
    186  |
    187  |   int counter_wait      returns the new value of the counter after wait
    188  |
    189  |   svr_counter_t *cst    counter
    190  |
    191  |   int limit             limit / range, or 0 to disable the check
    192  |
    193  |   Author:
    194  |     marek
    195  |   ++++++++++++++++++++++++++++++++++++++*/
    196  | static
    197  | int counter_wait(svr_counter_t *cst, int limit )
    198  | {
    199  |   int newval;
    200  |
    201  |   pthread_mutex_lock( &(cst->lock) );
    202  |
    203  |   if( limit != 0 ) {
    204  |     while( cst->count >= limit ) {
    205  |       pthread_cond_wait( &(cst->cond), &(cst->lock));
    206  |     }
    207  |   }
    208  |
    209  |   newval = cst->count;
    210  |   pthread_mutex_unlock(&(cst->lock) );
    211  |
    212  |   return newval;
    213  | }
    214  |
    215  | /*++++++++++++++++++++++++++++++++++++++
    216  |
    217  |   Loading the radix tree. Started as a separate thread.
    218  |
    219  |   Author:
    220  |     marek
    221  |   ++++++++++++++++++++++++++++++++++++++*/
    222  | void radix_init(void){
    223  |   int i;
    224  |   ca_dbSource_t *source_hdl;
    225  |
    226  |   wr_log_set(0);
    227  |   /* this needs to be done in two loops,
    228  |      because the trees must be created asap (first loop)
    229  |      and then locked until they are populated in the second loop
    230  |   */
    231  |
    232  |   TH_init_read_write_lockw(&rx_forest_rwlock);
    233  |
    234  |   for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){
    235  |     dieif( RP_init_trees( source_hdl ) != RP_OK );
    236  |   }
    237  |
    238  |   for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){
    239  |     dieif( RP_sql_load_reg( source_hdl ) != RP_OK );
    240  |   }
    241  |
    242  |   wr_log_set(0); /* switch on/off the memory leak detector */
    243  | /*  pthread_mutex_unlock( &radix_initializing_lock );  */
    244  |
    245  |   pthread_exit((void *)0);
    246  | }
    247  |
    248  |
    249  | /************************************************************
    250  | *  int SV_sleep()                                           *
    251  | *                                                           *
    252  | * sleeps till shutdown request comes                        *
    253  | * but at most <delay> seconds                               *
    254  | *                                                           *
    255  | * Returns:                                                  *
    256  | * 0 - timeout                                               *
    257  | * 1 - shutdown                                              *
    258  | *                                                           *
    259  | ************************************************************/
    260  |
    261  | int SV_sleep(int delay)
    262  | {
    263  |  int do_server;
    264  |  int elapsed_time=0;
    265  |
    266  |  while((do_server=CO_get_do_server()) && (elapsed_time<delay))
    267  |  {
    268  |   sleep(TIME_SLICE);
    269  |   elapsed_time+=TIME_SLICE;
    270  |  }
    271  |  if(do_server)return(0); else return(1);
    272  | }
    273  |
    274  | /*++++++++++++++++++++++++++++++++++++++
    275  |
    276  |   Handle signals.
    277  |
    278  |   Changes the flags:
    279  |   	do_nrtm
    280  |   	do_update
    281  |   	do_whoisd
    282  |
    283  |   More:
    284  |   +html+ <PRE>
    285  |   Author:
    286  |         andrei
    287  |   +html+ </PRE>
    288  |   ++++++++++++++++++++++++++++++++++++++*/
    289  | void *SV_signal_thread() {
    290  | char print_buf[STR_M];
    291  | sigset_t sset;
    292  | int sigReceived;
    293  | int do_update;
    294  |
    295  | 	sigemptyset(&sset);
    296  | 	/* SIGTERM and SIGINT are used to shutdown the server */
    297  | 	/* SIGUSR1 is used to pause/resume updates - rarely used as we have PC command */
    298  | 	sigaddset(&sset, SIGTERM);
    299  | 	sigaddset(&sset, SIGINT);
    300  | 	sigaddset(&sset, SIGUSR1);
    301  | 	/* This is a bit confusing, but is needed */
    302  | 	/* For more information on signal handling in */
    303  | 	/* threads see for example "Multithreading Programming */
    304  | 	/* Techniques" by Shashi Prasad, ISBN 0-07-912250-7, pp. 94-101 */
    305  |
    306  | 	/* XXX If one needs to handle more signals, don't forget to */
    307  | 	/* block them in other threads in install_signal_handler() in whois_rip.c */
    308  | 	pthread_sigmask(SIG_BLOCK, &sset, NULL);
    309  |
    310  | 	for(;;)
    311  | 	{
    312  | #ifdef HAVE_THR_SIGWAIT
    313  |          _thr_sigwait(&sset, &sigReceived);
    314  | #else
    315  |          sigwait(&sset, &sigReceived);
    316  | #endif
    317  | 	 sprintf(print_buf, "Signal received [%d]\n", sigReceived);
    318  | 	 log_print(print_buf); strcpy(print_buf, "");
    319  | 	 /*	 fprintf(stderr, "Signal received [%d]\n", sigReceived); */
    320  | 	 switch (sigReceived)
    321  | 	 {
    322  | 	   case SIGINT:
    323  | 	   case SIGTERM:
    324  | 	   /* SIGINT and SIGTERM stop all servers */
    325  | 	        SV_shutdown();
    326  |                 pthread_exit((void *)0);
    327  |   	        break;
    328  |
    329  |   	   case SIGUSR1:
    330  |   	   /* SIGUSR1 will switch the updates on and off */
    331  |   	        do_update=CO_get_do_update();
    332  |   	        if(do_update)do_update=0; else do_update=1;
    333  |   	   	sprintf(print_buf, "%d", do_update);
    334  | 		CO_set_const("UD.do_update", print_buf);
    335  | 		if(do_update)
    336  | 		  sprintf(print_buf, "Starting updates\n");
    337  | 		else
    338  | 		  sprintf(print_buf, "Stopping updates\n");
    339  | 		log_print(print_buf); strcpy(print_buf, "");
    340  | 		/*		fprintf(stderr, "Stopping updates (SIGTERM received)\n"); */
    341  |   	   	break;
    342  |   	 }
    343  |   	}
    344  | } /* SV_signal_thread() */
    345  |
    346  |
    347  | /* SV_do_child() */
    348  | /*++++++++++++++++++++++++++++++++++++++
    349  |
    350  |   Handle whois/config/mirror connections. Takes a pointer to the
    351  |   service description structure, containing a connected socket, limit
    352  |   of active threads, pointer to the counter of them. Does not stop to
    353  |   obey the limits, assumes this to be checked and assumes that it is
    354  |   already counted.  Decrements the counter on exit.
    355  |
    356  |   Precondition: the counter must be incremented before this function is called.
    357  |
    358  |   void *SV_do_child     Actually, does not return anything useful. Just NULL.
    359  |
    360  |   void *varg            service description structure.
    361  |
    362  |   Author:
    363  |     marek
    364  |   ++++++++++++++++++++++++++++++++++++++*/
    365  | void *SV_do_child(void *varg)
    366  | {
    367  |   svr_args *args = (svr_args *) varg;
    368  |   int sock = args->conn_sock;
    369  |   int curclients;
    370  |
    371  |   ER_dbg_va(FAC_TH, ASP_TH_NEW,
    372  | 	    ": Child thread [%d]: Socket number = %d",
    373  | 	    args->name, pthread_self(), sock);
    374  |
    375  |   curclients = counter_state( args->counter ); /* already added */
    376  |   ER_dbg_va(FAC_TH, ASP_TH_NEW,
    377  | 	    "%s threads++ = %d", args->name, curclients);
    378  |
    379  |   TA_add(sock, args->name);
    380  |
    381  |   args->function(sock);
    382  |
    383  |   /* TA_delete must come first - otherwise the server would crash
    384  |      when trying to report address of a closed socket */
    385  |   TA_delete();
    386  |   close(sock);
    387  |
    388  |   /* update the global thread counter. */
    389  |   curclients = counter_add( args->counter, -1);
    390  |   ER_dbg_va(FAC_TH, ASP_TH_NEW,
    391  | 	    "%s threads-- = %d", args->name, curclients);
    392  |
    393  |   free(args);
    394  |
    395  |   return NULL; /* exit the thread */
    396  | } /* SV_do_child */
    397  |
    398  |
    399  | /* main_loop() */
    400  | /*++++++++++++++++++++++++++++++++++++++
    401  |
    402  |   Waits for an incoming connection on the and spawns a new thread to
    403  |   handle it.  Takes a pointer to the service description structure
    404  |   containing the number of the listening socket, limit of active
    405  |   threads, pointer to the counter of them, and the function to call
    406  |   with a connected socket.  Increments the counter before starting
    407  |   a client thread to run SV_do_child().
    408  |
    409  |   void *arg      pointer to the service description structure.
    410  |
    411  |   More:
    412  |   +html+ <PRE>
    413  |   Author:
    414  |         ottrey
    415  | 	joao
    416  | 	andrei (do_server)
    417  | 	marek (rewritten/simplified/added limits)
    418  |   +html+ </PRE>
    419  |   ++++++++++++++++++++++++++++++++++++++*/
    420  | static void  *main_loop(void *arg) {
    421  |   svr_args *argset = (svr_args *)arg;
    422  |   svr_args *argcopy;
    423  |   char loopname[32];
    424  |   int children;
    425  |   char chnum[16];
    426  |
    427  |   snprintf(loopname, 32, "s-%s", argset->name);
    428  |
    429  |   TA_add(0, loopname);
    430  |
    431  |   while( CO_get_do_server() != 0 ) {
    432  |     /* check the number of clients, do not proceed until it's below limit */
    433  |     children = counter_wait( argset->counter, argset->limit );
    434  |     snprintf(chnum, 16, "%d", children);
    435  |     TA_setactivity(chnum); /* display the current number of children */
    436  |
    437  |     /* wait for new connections */
    438  |     argset->conn_sock = SK_accept_connection(argset->accept_sock);
    439  |     if(argset->conn_sock == -1) {
    440  |       break;
    441  |     }
    442  |
    443  |     ER_dbg_va(FAC_TH, ASP_TH_NEW, "%s: starting a new child thread",
    444  | 	      loopname);
    445  |     TA_increment();
    446  |     /* incrementing argset->counter here - to avoid race condition and
    447  |        ensure a _more_correct_ value of current clients also for unlimited
    448  |        or infrequent connections. Does not really matter otherwise.
    449  |
    450  |        NOTE: this architecture implies that higher values can be
    451  |        displayed for infrequent threads, because there's no way
    452  |        to change it when threads are exiting while this thread is
    453  |        blocked in call to accept(). If this call was in the child thread,
    454  |        the number would be an underestimation instead. I prefer over-e.
    455  |     */
    456  |     counter_add( argset->counter, 1);
    457  |
    458  |     /* Start a new thread. will decrement counter when exiting */
    459  |
    460  |     /* now. There's a race condition - argset must be copied in SV_do_child
    461  |        and can be reused here only afterwards. To avoid it, we make a copy
    462  |        and expect SV_do_child to free it after use.
    463  |        Caveat: the counter remains where it was, we just copy the pointer.
    464  |     */
    465  |     argcopy = malloc( sizeof(svr_args) );
    466  |     memcpy( argcopy, argset, sizeof(svr_args) );
    467  |     TH_create( SV_do_child, (void *)argcopy );
    468  |   }
    469  |
    470  |   TA_delete();
    471  |   ER_dbg_va(FAC_TH, ASP_TH_NEW, "Exiting from the main loop");
    472  |
    473  |   pthread_exit((void *)0);
    474  |   return NULL; /* stupid compilers. */
    475  | } /* main_loop() */
    476  |
    477  | /* SV_concurrent_server() */
    478  | /*++++++++++++++++++++++++++++++++++++++
    479  |
    480  |   This is the routine that creates the main threads.
    481  |
    482  |   int     sock        The socket to connect to.
    483  |
    484  |   int     limit       Limit of active clients (0 == no limit)
    485  |
    486  |   void *  do_function The function to call for each type of service
    487  |
    488  |   More:
    489  |   +html+ <PRE>
    490  |   Author:
    491  |         ottrey
    492  | 	joao
    493  | 	marek
    494  |   +html+ </PRE>
    495  |   ++++++++++++++++++++++++++++++++++++++*/
    496  | static
    497  | void SV_concurrent_server(int sock, int limit,  char *name,
    498  | 			  void do_function(int))
    499  | {
    500  |   svr_args *args;
    501  |
    502  |   dieif( wr_calloc((void **)&args, 1, sizeof(svr_args)) != UT_OK);
    503  |
    504  |   args->accept_sock=sock;
    505  |   args->limit=limit;
    506  |   args->name=name;
    507  |   args->function=do_function;
    508  |
    509  |   dieif( wr_calloc((void **)&(args->counter),1,sizeof(svr_counter_t)) != UT_OK);
    510  |   pthread_mutex_init( &(args->counter->lock), NULL );
    511  |   pthread_cond_init(  &(args->counter->cond), NULL );
    512  |   args->counter->count = 0;
    513  |
    514  |
    515  |   /* Start a new thread. */
    516  |
    517  |   TH_create(main_loop, (void *)args);
    518  |
    519  | } /* SV_concurrent_server() */
    520  |
    521  | /* SV_start() */
    522  | /*++++++++++++++++++++++++++++++++++++++
    523  |
    524  |   Start the server.
    525  |
    526  |   More:
    527  |   +html+ <PRE>
    528  |   Authors:
    529  |         ottrey
    530  |         joao
    531  |   +html+ </PRE>
    532  |   +html+ Starts up the server.
    533  |   +html+ <OL>
    534  |   +html+   <LI> Create sockets on the necessary ports (whois, config and mirror)
    535  |   +html+   <LI> Start new threads for each service.
    536  |   +html+ </OL>
    537  |   +html+ <A HREF=".DBrc">.properties</A>
    538  |
    539  |   ++++++++++++++++++++++++++++++++++++++*/
    540  | int SV_start(char *pidfile) {
    541  |   int whois_port = -1;
    542  |   int config_port = -1;
    543  |   int mirror_port = -1;
    544  |   int update_port = -1;
    545  |   int update_mode = 0;
    546  |   int pid_fd;
    547  |   int nwrite;
    548  |   struct timeval tval;
    549  |   char starttime[128];
    550  |   char server_pid[16];
    551  |   ca_dbSource_t *source_hdl;
    552  |   char *source_name;
    553  |   int source;
    554  |   char *db_host, *db_name, *db_user, *db_passwd;
    555  |   int db_port;
    556  |   SQ_connection_t *db_connection;
    557  |
    558  |   /* Store the starting time */
    559  |   gettimeofday(&tval, NULL);
    560  |   SV_starttime = tval.tv_sec;/* seconds since Jan. 1, 1970 */
    561  |
    562  |   /* Log the starting time */
    563  |   ctime_r(&SV_starttime, starttime);
    564  |   ER_inf_va(FAC_SV, 0xFFFFFF, "Server is started %s", starttime);
    565  |
    566  |   /* Store the PID of the process */
    567  |   SV_pidfile = pidfile;
    568  |   /* create the file read-writable by the process owner */
    569  |   if((pid_fd=open(SV_pidfile,  O_CREAT | O_TRUNC | O_WRONLY, 0600))==-1) {
    570  |       ER_perror(FAC_SV, 1, "cannot open pid file %s", SV_pidfile);
    571  |       return(-1);
    572  |   }
    573  |   sprintf(server_pid, "%d", (int)getpid());
    574  |   nwrite=write(pid_fd, server_pid, strlen(server_pid) );
    575  |   close(pid_fd);
    576  |   if(nwrite != strlen(server_pid)) {
    577  |       ER_perror(FAC_SV, 1, "cannot write to pid file %s", SV_pidfile);
    578  |       return(-1);
    579  |   }
    580  |
    581  |
    582  |   /* Initialise modules */
    583  |   SK_init();
    584  |   PW_init();
    585  |
    586  |   /* Initialise the access control list. */
    587  |   AC_build();
    588  |   AC_acc_load();
    589  |   /* explicitly start the decay thread */
    590  |   TH_create((void *(*)(void *))AC_decay, NULL);
    591  |
    592  |
    593  |
    594  |   /* Get port information for each service */
    595  |   whois_port  = ca_get_svwhois_port;
    596  |   ER_inf_va(FAC_SV, ASP_SV_PORT, "whois port is %d", whois_port);
    597  | /*  ER_dbg_va(FAC_SV, ASP_SV_PORT, "whois port is %d", whois_port); */
    598  |
    599  |   config_port = ca_get_svconfig_port;
    600  |   ER_inf_va(FAC_SV, ASP_SV_PORT, "config port is %d", config_port);
    601  | /*  ER_dbg_va(FAC_SV, ASP_SV_PORT, "config port is %d", config_port); */
    602  |
    603  |
    604  |   mirror_port = ca_get_svmirror_port;
    605  |   ER_inf_va(FAC_SV, ASP_SV_PORT, "mirror port is %d", mirror_port);
    606  | /*  ER_dbg_va(FAC_SV, ASP_SV_PORT, "mirror port is %d", mirror_port);*/
    607  |
    608  |
    609  |   /* 6. Create a socket on the necessary ports/addresses and bind to them. */
    610  |   /* whois socket */
    611  |   SV_whois_sock = SK_getsock(SOCK_STREAM, whois_port, 128, INADDR_ANY);
    612  | /* Currently binds to INADDR_ANY. Will need to get specific address */
    613  | /*  SV_whois_sock = SK_getsock(SOCK_STREAM,whois_port,whois_addr); */
    614  |   /* config interface socket */
    615  |   SV_config_sock = SK_getsock(SOCK_STREAM, config_port, 5, INADDR_ANY);
    616  |   /* nrt socket */
    617  |   SV_mirror_sock = SK_getsock(SOCK_STREAM,mirror_port, 128, INADDR_ANY);
    618  |
    619  |   /* Check every Database and create sockets */
    620  |   /* we need first to create and bind all of them */
    621  |   /* so that in case of failure we do not start any */
    622  |   /* update thread */
    623  |   fprintf(stderr, "Check the DB\n");
    624  |   for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){
    625  |      /* check for crash and recover if needed */
    626  |      /* make a connection to a database */
    627  |      db_host = ca_get_srcdbmachine(source_hdl);
    628  |      db_port = ca_get_srcdbport(source_hdl);
    629  |      db_name = ca_get_srcdbname(source_hdl);
    630  |      db_user = ca_get_srcdbuser(source_hdl);
    631  |      db_passwd = ca_get_srcdbpassword(source_hdl);
    632  |      db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd);
    633  |      /* now check TR record */
    634  |      TR_recover(db_connection);
    635  |      /* free resources */
    636  |      SQ_close_connection(db_connection);
    637  |      free(db_host);
    638  |      free(db_name);
    639  |      free(db_user);
    640  |      free(db_passwd);
    641  |
    642  |      update_mode = ca_get_srcmode(source_hdl);
    643  |      if(IS_UPDATE(update_mode)) {
    644  |        /* update_port = SK_atoport(CO_get_update_port(), "tcp"); */
    645  |        update_port = ca_get_srcupdateport(source_hdl);
    646  |        printf("XXX htons(update_port)=%d\n", update_port);
    647  |        /* XXX ask AMRM to change the name of the function */
    648  |
    649  |        SV_update_sock[source] = SK_getsock(SOCK_STREAM, update_port, 128, INADDR_ANY);
    650  |      }
    651  |      else SV_update_sock[source] = 0;
    652  |   }
    653  |   SV_update_sock[source+1]=-1; /* end of socket array */
    654  |
    655  |    /* Initialise the radix tree (separate thread[s])
    656  |      already can allow socket connections, because the trees will
    657  |      be created locked, and will be unlocked when loaded */
    658  |
    659  | /*   pthread_mutex_lock( &radix_initializing_lock );  */
    660  |   TH_create((void *(*)(void *))radix_init, NULL);
    661  | /*  pthread_mutex_lock( &radix_initializing_lock );  */
    662  |
    663  |
    664  |   /* Now.... accept() calls block until they get a connection
    665  |      so to listen on more than one port we need more
    666  |      than one thread */
    667  |
    668  |   /* Create master thread for whois threads */
    669  |   SV_concurrent_server(SV_whois_sock, 64, "whois", PW_interact);
    670  |   /* Create master thread for config threads */
    671  |   SV_concurrent_server(SV_config_sock, 0, "config", PC_interact);
    672  |   /* Create master thread for mirror threads */
    673  |   SV_concurrent_server(SV_mirror_sock, 0, "mirror", PM_interact);
    674  |
    675  |   /* Walk through the sources and */
    676  |   /* run update thread for every source with CANUPD == 'y' */
    677  |
    678  |    for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){
    679  |      update_mode = ca_get_srcmode(source_hdl);
    680  |      source_name= ca_get_srcname(source_hdl);
    681  |
    682  |      if(IS_UPDATE(update_mode)) {
    683  |      /* run RIPupdate thread */
    684  |        fprintf(stderr,"Source [%s] Mode UPDATE [port=%d]\n", source_name, ca_get_srcupdateport(source_hdl));
    685  |        ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode UPDATE [port=%d]", source_name, ca_get_srcupdateport(source_hdl));
    686  |        TH_create((void *(*)(void *))UD_do_updates, (void *)source);
    687  |      }
    688  |      else if(IS_NRTM_CLNT(update_mode)){
    689  |        /* start NRTM client */
    690  |        fprintf(stderr,"Source [%s] Mode NRTM\n", source_name);
    691  |        ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode NRTM", source_name);
    692  |        TH_create((void *(*)(void *))UD_do_nrtm, (void *)source);
    693  |      }
    694  |      else {
    695  | 	     fprintf(stderr,"Source [%s] Mode STATIC\n", source_name);
    696  | 	     ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode STATIC", source_name);
    697  |      }
    698  |      free(source_name); /* because ca_* functions return copies */
    699  |    }
    700  |   /* terminate the thread */
    701  |   /* XXX not return becase then we terminate the whole process */
    702  |   pthread_exit(NULL);
    703  |   return(1); /* we will never reach this point */
    704  | } /* SV_start() */
    705  |
    706  | /* SV_shutdown() */
    707  | /*++++++++++++++++++++++++++++++++++++++
    708  |
    709  |   Shutdown the server.
    710  |
    711  |   More:
    712  |   +html+ <PRE>
    713  |   Authors:
    714  |         andrei
    715  |   +html+ </PRE>
    716  |   +html+ Stops the server.
    717  |   +html+ <OL>
    718  |   +html+   <LI> Close listening sockets (whois, config, mirror and updates)
    719  |   +html+   <LI> Stop all threads by triggering do_server variable.
    720  |   +html+ </OL>
    721  |   +html+ <A HREF=".DBrc">.properties</A>
    722  |
    723  |   ++++++++++++++++++++++++++++++++++++++*/
    724  | void SV_shutdown() {
    725  | char print_buf[STR_M];
    726  | int source;
    727  | time_t shutdowntime;
    728  | struct timeval tval;
    729  | char shuttime[100];
    730  |
    731  |  sprintf(print_buf, "%d", 0);
    732  |  /* Stop updates */
    733  |  CO_set_const("UD.do_update", print_buf);
    734  |  /* Stop all servers */
    735  |  CO_set_const("SV.do_server", print_buf);
    736  |  sprintf(print_buf, "Stopping all servers\n");
    737  |  fprintf(stderr, print_buf);
    738  |  /*log_print(print_buf); */
    739  |  strcpy(print_buf, "");
    740  |
    741  |  /* wait for all updates to complete */
    742  |  /* XXX may be changed with blocking interface for stop updates */
    743  |  sleep(5);
    744  |
    745  |  /* Store the shutdown time */
    746  |   gettimeofday(&tval, NULL);
    747  |   shutdowntime = tval.tv_sec;/* seconds since Jan. 1, 1970 */
    748  |
    749  |   /* Log the sshutdown time */
    750  |   ctime_r(&shutdowntime, shuttime);
    751  |   ER_inf_va(FAC_SV, 0xFFFFFF, "Server shutdown %s", shuttime);
    752  |
    753  |
    754  |
    755  |  /* Wake up all sleeping threads */
    756  |  fprintf(stderr, "Going to wake sleeping threads up\n");
    757  |
    758  |  /* Delete the pid file to indicate normal shutdown */
    759  |  if(unlink(SV_pidfile)==-1) {
    760  |       ER_perror(FAC_SV, 1, "cannot delete pid file %s:", SV_pidfile);
    761  |  }
    762  |
    763  |
    764  |  /* CLose all listening sockets, so accept call exits */
    765  |  close(SV_whois_sock);
    766  |  close(SV_config_sock);
    767  |  close(SV_mirror_sock);
    768  |  for (source=0; SV_update_sock[source]!=-1; source++)
    769  | 	 if(SV_update_sock[source]!=0)close(SV_update_sock[source]);
    770  |
    771  |
    772  | } /* SV_shutdown() */