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