## 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. SV_sleep
7. SV_signal_thread
8. SV_do_child
9. main_loop
10. SV_concurrent_server
11. SV_start
12. SV_shutdown

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

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