1    | /***************************************
2    |   $Revision: 1.62 $
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) {
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;
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;
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 )
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 ) 
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 )
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)
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)
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)
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() {
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)
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) {
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,
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) {
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  |   /* explicitly start the decay thread */
595  |   TH_create((void *(*)(void *))AC_decay, NULL);
596  | 
597  | 
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() {
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() */