## modules/sv/server.c

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

## DEFINITIONS

This source file includes following functions.

1. log_print
2. svr_counter_t
3. svr_args
4. counter_add
5. counter_state
6. counter_wait
7. radix_init
8. radix_load
9. SV_sleep
10. SV_signal_thread
11. SV_do_child
12. main_loop
13. SV_concurrent_server
14. SV_start
15. SV_shutdown

       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) {
         /* [<][>][^][v][top][bottom][index][help] */
      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;
         /* [<][>][^][v][top][bottom][index][help] */
      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;
         /* [<][>][^][v][top][bottom][index][help] */
     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 )
         /* [<][>][^][v][top][bottom][index][help] */
     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 )
         /* [<][>][^][v][top][bottom][index][help] */
     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 )
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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() {
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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,
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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() {
         /* [<][>][^][v][top][bottom][index][help] */
     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() */

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