modules/sv/server.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. log_print
  2. counter_add
  3. counter_state
  4. counter_wait
  5. radix_init
  6. radix_load
  7. SV_sleep
  8. SV_signal_thread
  9. SV_do_child
  10. main_loop
  11. SV_concurrent_server
  12. SV_start
  13. SV_shutdown

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

/* [<][>][^][v][top][bottom][index][help] */