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) {
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 )
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 ) 
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 )
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){
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)
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() {
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)
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) {
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,
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() {
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() {
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() */