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