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