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