modules/sv/server.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- log_print
- counter_add
- counter_state
- counter_wait
- radix_init
- radix_load
- SV_sleep
- SV_signal_thread
- SV_do_child
- main_loop
- SV_concurrent_server
- SV_start
- SV_shutdown
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) {
/* [<][>][^][v][top][bottom][index][help] */
81
82 printf(arg);
83
84 } /* log_print() */
85
86
87 /* counters - by marek */
88 typedef struct {
89 int count;
90 pthread_mutex_t lock; /*+ Mutex lock.Used for synchronizing changes.+*/
91 pthread_cond_t cond; /*+ condition variable +*/
92 } svr_counter_t;
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 )
/* [<][>][^][v][top][bottom][index][help] */
124 {
125 int newval;
126
127 /* add under mutex */
128 pthread_mutex_lock( &(cst->lock) );
129 cst->count += incval;
130 newval = cst->count;
131 pthread_mutex_unlock(&(cst->lock) );
132
133 /* now - signal the change of value to the waiting thread */
134 pthread_cond_signal( &(cst->cond) );
135
136 return newval;
137 }
138
139
140 /*++++++++++++++++++++++++++++++++++++++
141
142 int
143 counter_state returns the current value of a counter
144
145 svr_counter_t *cst counter
146
147 Author:
148 marek
149
150 ++++++++++++++++++++++++++++++++++++++*/
151 static
152 int
153 counter_state( svr_counter_t *cst )
/* [<][>][^][v][top][bottom][index][help] */
154 {
155 return counter_add( cst, 0 );
156 }
157
158
159 /*++++++++++++++++++++++++++++++++++++++
160 waits until the counter is in the range [0-limit].
161 unless the limit is 0, in which case the check is disabled.
162
163 int counter_wait returns the new value of the counter after wait
164
165 svr_counter_t *cst counter
166
167 int limit limit / range, or 0 to disable the check
168
169 Author:
170 marek
171 ++++++++++++++++++++++++++++++++++++++*/
172 static
173 int counter_wait(svr_counter_t *cst, int limit )
/* [<][>][^][v][top][bottom][index][help] */
174 {
175 int newval;
176
177 pthread_mutex_lock( &(cst->lock) );
178
179 if( limit != 0 ) {
180 while( cst->count >= limit ) {
181 pthread_cond_wait( &(cst->cond), &(cst->lock));
182 }
183 }
184
185 newval = cst->count;
186 pthread_mutex_unlock(&(cst->lock) );
187
188 return newval;
189 }
190
191 /*++++++++++++++++++++++++++++++++++++++
192
193 Initialize the radix tree - all trees are added to the forest in
194 a locked state. As each tree finishes loading (from radix_load()),
195 it is unlocked.
196
197 ++++++++++++++++++++++++++++++++++++++*/
198 static void
199 radix_init(void)
/* [<][>][^][v][top][bottom][index][help] */
200 {
201 int i;
202 ca_dbSource_t *source_hdl;
203
204 TH_init_read_write_lockw(&rx_forest_rwlock);
205 for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){
206 dieif( RP_init_trees( source_hdl ) != RP_OK );
207 }
208 }
209
210 /*++++++++++++++++++++++++++++++++++++++
211
212 Load the radix tree - all trees are initialized from the appropriate
213 SQL tables. As each tree finishes loading (from radix_load()), it is
214 unlocked. They must be created by the radix_init() function.
215
216 ++++++++++++++++++++++++++++++++++++++*/
217 static void
218 radix_load(void)
/* [<][>][^][v][top][bottom][index][help] */
219 {
220 int i;
221 ca_dbSource_t *source_hdl;
222
223 for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){
224 dieif( RP_sql_load_reg( source_hdl ) != RP_OK );
225 }
226 }
227
228
229 /************************************************************
230 * int SV_sleep() *
231 * *
232 * sleeps till shutdown request comes *
233 * but at most <delay> seconds *
234 * *
235 * Returns: *
236 * 0 - timeout *
237 * 1 - shutdown *
238 * *
239 ************************************************************/
240
241 int SV_sleep(int delay)
/* [<][>][^][v][top][bottom][index][help] */
242 {
243 int do_server;
244 int elapsed_time=0;
245
246 while((do_server=CO_get_do_server()) && (elapsed_time<delay))
247 {
248 sleep(TIME_SLICE);
249 elapsed_time+=TIME_SLICE;
250 }
251 if(do_server)return(0); else return(1);
252 }
253
254 /*++++++++++++++++++++++++++++++++++++++
255
256 Handle signals.
257
258 Changes the flags:
259 do_nrtm
260 do_update
261 do_whoisd
262
263 More:
264 +html+ <PRE>
265 Author:
266 andrei
267 +html+ </PRE>
268 ++++++++++++++++++++++++++++++++++++++*/
269 void *SV_signal_thread() {
/* [<][>][^][v][top][bottom][index][help] */
270 char print_buf[STR_M];
271 sigset_t sset;
272 int sigReceived;
273 int do_update;
274
275 sigemptyset(&sset);
276 /* SIGTERM and SIGINT are used to shutdown the server */
277 /* SIGUSR1 is used to pause/resume updates - rarely used as we have PC command */
278 sigaddset(&sset, SIGTERM);
279 sigaddset(&sset, SIGINT);
280 sigaddset(&sset, SIGUSR1);
281 /* This is a bit confusing, but is needed */
282 /* For more information on signal handling in */
283 /* threads see for example "Multithreading Programming */
284 /* Techniques" by Shashi Prasad, ISBN 0-07-912250-7, pp. 94-101 */
285
286 /* XXX If one needs to handle more signals, don't forget to */
287 /* block them in other threads in install_signal_handler() in whois_rip.c */
288 pthread_sigmask(SIG_BLOCK, &sset, NULL);
289
290 for(;;)
291 {
292 #ifdef HAVE_THR_SIGWAIT
293 _thr_sigwait(&sset, &sigReceived);
294 #else
295 sigwait(&sset, &sigReceived);
296 #endif
297 sprintf(print_buf, "Signal received [%d]\n", sigReceived);
298 log_print(print_buf); strcpy(print_buf, "");
299 /* fprintf(stderr, "Signal received [%d]\n", sigReceived); */
300 switch (sigReceived)
301 {
302 case SIGINT:
303 case SIGTERM:
304 /* SIGINT and SIGTERM stop all servers */
305 SV_shutdown();
306 pthread_exit((void *)0);
307 break;
308
309 case SIGUSR1:
310 /* SIGUSR1 will switch the updates on and off */
311 do_update=CO_get_do_update();
312 if(do_update)do_update=0; else do_update=1;
313 sprintf(print_buf, "%d", do_update);
314 CO_set_const("UD.do_update", print_buf);
315 if(do_update)
316 sprintf(print_buf, "Starting updates\n");
317 else
318 sprintf(print_buf, "Stopping updates\n");
319 log_print(print_buf); strcpy(print_buf, "");
320 /* fprintf(stderr, "Stopping updates (SIGTERM received)\n"); */
321 break;
322 }
323 }
324 } /* SV_signal_thread() */
325
326
327 /* SV_do_child() */
328 /*++++++++++++++++++++++++++++++++++++++
329
330 Handle whois/config/mirror connections. Takes a pointer to the
331 service description structure, containing a connected socket, limit
332 of active threads, pointer to the counter of them. Does not stop to
333 obey the limits, assumes this to be checked and assumes that it is
334 already counted. Decrements the counter on exit.
335
336 Precondition: the counter must be incremented before this function is called.
337
338 void *SV_do_child Actually, does not return anything useful. Just NULL.
339
340 void *varg service description structure.
341
342 Author:
343 marek
344 ++++++++++++++++++++++++++++++++++++++*/
345 void *SV_do_child(void *varg)
/* [<][>][^][v][top][bottom][index][help] */
346 {
347 svr_args *args = (svr_args *) varg;
348 int sock = args->conn_sock;
349 int curclients;
350
351 ER_dbg_va(FAC_TH, ASP_TH_NEW,
352 ": Child thread [%d]: Socket number = %d",
353 args->name, pthread_self(), sock);
354
355 curclients = counter_state( args->counter ); /* already added */
356 ER_dbg_va(FAC_TH, ASP_TH_NEW,
357 "%s threads++ = %d", args->name, curclients);
358
359 TA_add(sock, args->name);
360
361 args->function(sock);
362
363 /* TA_delete must come first - otherwise the server would crash
364 when trying to report address of a closed socket */
365 TA_delete();
366 close(sock);
367
368 /* update the global thread counter. */
369 curclients = counter_add( args->counter, -1);
370 ER_dbg_va(FAC_TH, ASP_TH_NEW,
371 "%s threads-- = %d", args->name, curclients);
372
373 UT_free(args);
374
375 return NULL; /* exit the thread */
376 } /* SV_do_child */
377
378
379 /* main_loop() */
380 /*++++++++++++++++++++++++++++++++++++++
381
382 Waits for an incoming connection on the and spawns a new thread to
383 handle it. Takes a pointer to the service description structure
384 containing the number of the listening socket, limit of active
385 threads, pointer to the counter of them, and the function to call
386 with a connected socket. Increments the counter before starting
387 a client thread to run SV_do_child().
388
389 void *arg pointer to the service description structure.
390
391 More:
392 +html+ <PRE>
393 Author:
394 ottrey
395 joao
396 andrei (do_server)
397 marek (rewritten/simplified/added limits)
398 +html+ </PRE>
399 ++++++++++++++++++++++++++++++++++++++*/
400 static void *main_loop(void *arg) {
/* [<][>][^][v][top][bottom][index][help] */
401 svr_args *argset = (svr_args *)arg;
402 svr_args *argcopy;
403 char loopname[32];
404 int children;
405 char chnum[16];
406 struct pollfd pfd[2];
407
408 snprintf(loopname, 32, "s-%s", argset->name);
409
410 TA_add(0, loopname);
411
412 pfd[0].fd = argset->accept_sock;
413 pfd[0].events = POLLIN;
414 pfd[1].fd = SV_shutdown_recv_fd;
415 pfd[1].events = POLLIN;
416
417 while( CO_get_do_server() != 0 ) {
418 /* check the number of clients, do not proceed until it's below limit */
419 children = counter_wait( argset->counter, argset->limit );
420 snprintf(chnum, 16, "%d", children);
421 TA_setactivity(chnum); /* display the current number of children */
422
423 /* check for input */
424 if (poll(pfd, 2, -1) == -1) {
425 ER_perror(FAC_SV, 1, "%s got error %d on poll; %s", argset->name,
426 errno, strerror(errno));
427 continue;
428 }
429
430 /* see if we're shutting down */
431 if (pfd[1].revents != 0) break;
432
433 /* wait for new connections */
434 argset->conn_sock = SK_accept_connection(argset->accept_sock);
435 if(argset->conn_sock == -1) {
436 break;
437 }
438
439 ER_dbg_va(FAC_TH, ASP_TH_NEW, "%s: starting a new child thread",
440 loopname);
441 TA_increment();
442 /* incrementing argset->counter here - to avoid race condition and
443 ensure a _more_correct_ value of current clients also for unlimited
444 or infrequent connections. Does not really matter otherwise.
445
446 NOTE: this architecture implies that higher values can be
447 displayed for infrequent threads, because there's no way
448 to change it when threads are exiting while this thread is
449 blocked in call to accept(). If this call was in the child thread,
450 the number would be an underestimation instead. I prefer over-e.
451 */
452 counter_add( argset->counter, 1);
453
454 /* Start a new thread. will decrement counter when exiting */
455
456 /* now. There's a race condition - argset must be copied in SV_do_child
457 and can be reused here only afterwards. To avoid it, we make a copy
458 and expect SV_do_child to free it after use.
459 Caveat: the counter remains where it was, we just copy the pointer.
460 */
461 argcopy = UT_malloc( sizeof(svr_args) );
462 memcpy( argcopy, argset, sizeof(svr_args) );
463 TH_create( SV_do_child, (void *)argcopy );
464 }
465
466 TA_delete();
467 ER_dbg_va(FAC_TH, ASP_TH_NEW, "Exiting from the main loop");
468
469 return NULL;
470 } /* main_loop() */
471
472 /* SV_concurrent_server() */
473 /*++++++++++++++++++++++++++++++++++++++
474
475 This is the routine that creates the main threads.
476
477 int sock The socket to connect to.
478
479 int limit Limit of active clients (0 == no limit)
480
481 void * do_function The function to call for each type of service
482
483 More:
484 +html+ <PRE>
485 Author:
486 ottrey
487 joao
488 marek
489 +html+ </PRE>
490 ++++++++++++++++++++++++++++++++++++++*/
491 static
492 void SV_concurrent_server(int sock, int limit, char *name,
/* [<][>][^][v][top][bottom][index][help] */
493 void do_function(int))
494 {
495 svr_args *args;
496
497 args = (svr_args *)UT_calloc(1, sizeof(svr_args));
498
499 args->accept_sock=sock;
500 args->limit=limit;
501 args->name=name;
502 args->function=do_function;
503 args->counter = (svr_counter_t *)UT_calloc(1, sizeof(svr_counter_t));
504
505 pthread_mutex_init( &(args->counter->lock), NULL );
506 pthread_cond_init( &(args->counter->cond), NULL );
507 args->counter->count = 0;
508
509
510 /* Start a new thread. */
511
512 TH_create(main_loop, (void *)args);
513
514 } /* SV_concurrent_server() */
515
516 /* SV_start() */
517 /*++++++++++++++++++++++++++++++++++++++
518
519 Start the server.
520
521 More:
522 +html+ <PRE>
523 Authors:
524 ottrey
525 joao
526 +html+ </PRE>
527 +html+ Starts up the server.
528 +html+ <OL>
529 +html+ <LI> Create sockets on the necessary ports (whois, config and mirror)
530 +html+ <LI> Start new threads for each service.
531 +html+ </OL>
532 +html+ <A HREF=".DBrc">.properties</A>
533
534 ++++++++++++++++++++++++++++++++++++++*/
535 int SV_start(char *pidfile) {
/* [<][>][^][v][top][bottom][index][help] */
536 int whois_port = -1;
537 int config_port = -1;
538 int mirror_port = -1;
539 int update_port = -1;
540 int update_mode = 0;
541 int pid_fd;
542 int nwrite;
543 struct timeval tval;
544 char starttime[128];
545 char server_pid[16];
546 ca_dbSource_t *source_hdl;
547 char *source_name;
548 int source;
549 char *db_host, *db_name, *db_user, *db_passwd;
550 int db_port;
551 SQ_connection_t *db_connection;
552 int shutdown_pipe[2];
553
554 /* Store the starting time */
555 gettimeofday(&tval, NULL);
556 SV_starttime = tval.tv_sec;/* seconds since Jan. 1, 1970 */
557
558 /* Log the starting time */
559 ctime_r(&SV_starttime, starttime);
560 ER_inf_va(FAC_SV, 0xFFFFFF, "Server is started %s", starttime);
561
562 /* Create our shutdown pipe */
563 if (pipe(shutdown_pipe) != 0) {
564 ER_perror(FAC_SV, 1,
565 "error %d creating shutdown pipe; %s", errno, strerror(errno));
566 return(-1);
567 }
568 SV_shutdown_send_fd = shutdown_pipe[1];
569 SV_shutdown_recv_fd = shutdown_pipe[0];
570
571 /* Store the PID of the process */
572 SV_pidfile = pidfile;
573 /* create the file read-writable by the process owner */
574 if((pid_fd=open(SV_pidfile, O_CREAT | O_TRUNC | O_WRONLY, 0600))==-1) {
575 ER_perror(FAC_SV, 1, "cannot open pid file %s", SV_pidfile);
576 return(-1);
577 }
578 sprintf(server_pid, "%d", (int)getpid());
579 nwrite=write(pid_fd, server_pid, strlen(server_pid) );
580 close(pid_fd);
581 if(nwrite != strlen(server_pid)) {
582 ER_perror(FAC_SV, 1, "cannot write to pid file %s", SV_pidfile);
583 return(-1);
584 }
585
586
587 /* Initialise modules */
588 SK_init();
589 PW_init();
590
591 /* Initialise the access control list. */
592 AC_build();
593 AC_acc_load();
594 /* 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() {
/* [<][>][^][v][top][bottom][index][help] */
730 char print_buf[STR_M];
731 int source;
732 time_t shutdowntime;
733 struct timeval tval;
734 char shuttime[100];
735
736 sprintf(print_buf, "%d", 0);
737 /* Stop updates */
738 CO_set_const("UD.do_update", print_buf);
739 /* Stop all servers */
740 CO_set_const("SV.do_server", print_buf);
741 sprintf(print_buf, "Stopping all servers\n");
742 fprintf(stderr, print_buf);
743 /*log_print(print_buf); */
744 strcpy(print_buf, "");
745
746 /* wait for all updates to complete */
747 /* XXX may be changed with blocking interface for stop updates */
748 sleep(5);
749
750 /* Store the shutdown time */
751 gettimeofday(&tval, NULL);
752 shutdowntime = tval.tv_sec;/* seconds since Jan. 1, 1970 */
753
754 /* Log the sshutdown time */
755 ctime_r(&shutdowntime, shuttime);
756 ER_inf_va(FAC_SV, 0xFFFFFF, "Server shutdown %s", shuttime);
757
758
759
760 /* Wake up all sleeping threads */
761 fprintf(stderr, "Going to wake sleeping threads up\n");
762
763 /* Delete the pid file to indicate normal shutdown */
764 if(unlink(SV_pidfile)==-1) {
765 ER_perror(FAC_SV, 1, "cannot delete pid file %s:", SV_pidfile);
766 }
767
768 /* write to shutdown pipe */
769 if (write(SV_shutdown_send_fd, "", 1) != 1) {
770 ER_perror(FAC_SV, 1, "error %d writing to shutdown pipe; %s",
771 errno, strerror(errno));
772 }
773
774
775 /* don't do this, it's not polite ;) */
776 #if 0
777 /* CLose all listening sockets, so accept call exits */
778 close(SV_whois_sock);
779 close(SV_config_sock);
780 close(SV_mirror_sock);
781 for (source=0; SV_update_sock[source]!=-1; source++)
782 if(SV_update_sock[source]!=0)close(SV_update_sock[source]);
783 #endif /* 0 */
784
785 } /* SV_shutdown() */