Source File sv/server.c

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