1 | /*************************************** 2 | $Revision: 1.58 $ 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 | /* Listening sockets */ 88 | int SV_whois_sock; 89 | int SV_config_sock; 90 | int SV_mirror_sock; 91 | 92 | /* each updatable source has its own update thread and its own socket */ 93 | #define MAX_SOURCES 100 94 | int SV_update_sock[MAX_SOURCES]; 95 | 96 | 97 | 98 | /*+ Server starting time +*/ 99 | time_t SV_starttime; 100 | /* the filename where we store the PID of the server */ 101 | char *SV_pidfile; 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 | * 0 - timeout * 257 | * 1 - 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(do_server)return(0); else return(1); 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 | int SV_start(char *pidfile) { 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 pid_fd; 547 | int nwrite; 548 | struct timeval tval; 549 | char starttime[128]; 550 | char server_pid[16]; 551 | ca_dbSource_t *source_hdl; 552 | char *source_name; 553 | int source; 554 | char *db_host, *db_name, *db_user, *db_passwd; 555 | int db_port; 556 | SQ_connection_t *db_connection; 557 | 558 | /* Store the starting time */ 559 | gettimeofday(&tval, NULL); 560 | SV_starttime = tval.tv_sec;/* seconds since Jan. 1, 1970 */ 561 | 562 | /* Log the starting time */ 563 | ctime_r(&SV_starttime, starttime); 564 | ER_inf_va(FAC_SV, 0xFFFFFF, "Server is started %s", starttime); 565 | 566 | /* Store the PID of the process */ 567 | SV_pidfile = pidfile; 568 | /* create the file read-writable by the process owner */ 569 | if((pid_fd=open(SV_pidfile, O_CREAT | O_TRUNC | O_WRONLY, 0600))==-1) { 570 | ER_perror(FAC_SV, 1, "cannot open pid file %s", SV_pidfile); 571 | return(-1); 572 | } 573 | sprintf(server_pid, "%d", (int)getpid()); 574 | nwrite=write(pid_fd, server_pid, strlen(server_pid) ); 575 | close(pid_fd); 576 | if(nwrite != strlen(server_pid)) { 577 | ER_perror(FAC_SV, 1, "cannot write to pid file %s", SV_pidfile); 578 | return(-1); 579 | } 580 | 581 | 582 | /* Initialise modules */ 583 | SK_init(); 584 | PW_init(); 585 | 586 | /* Initialise the access control list. */ 587 | AC_build(); 588 | AC_acc_load(); 589 | /* explicitly start the decay thread */ 590 | TH_create((void *(*)(void *))AC_decay, NULL); 591 | 592 | 593 | 594 | /* Get port information for each service */ 595 | whois_port = ca_get_svwhois_port; 596 | ER_inf_va(FAC_SV, ASP_SV_PORT, "whois port is %d", whois_port); 597 | /* ER_dbg_va(FAC_SV, ASP_SV_PORT, "whois port is %d", whois_port); */ 598 | 599 | config_port = ca_get_svconfig_port; 600 | ER_inf_va(FAC_SV, ASP_SV_PORT, "config port is %d", config_port); 601 | /* ER_dbg_va(FAC_SV, ASP_SV_PORT, "config port is %d", config_port); */ 602 | 603 | 604 | mirror_port = ca_get_svmirror_port; 605 | ER_inf_va(FAC_SV, ASP_SV_PORT, "mirror port is %d", mirror_port); 606 | /* ER_dbg_va(FAC_SV, ASP_SV_PORT, "mirror port is %d", mirror_port);*/ 607 | 608 | 609 | /* 6. Create a socket on the necessary ports/addresses and bind to them. */ 610 | /* whois socket */ 611 | SV_whois_sock = SK_getsock(SOCK_STREAM, whois_port, 128, INADDR_ANY); 612 | /* Currently binds to INADDR_ANY. Will need to get specific address */ 613 | /* SV_whois_sock = SK_getsock(SOCK_STREAM,whois_port,whois_addr); */ 614 | /* config interface socket */ 615 | SV_config_sock = SK_getsock(SOCK_STREAM, config_port, 5, INADDR_ANY); 616 | /* nrt socket */ 617 | SV_mirror_sock = SK_getsock(SOCK_STREAM,mirror_port, 128, INADDR_ANY); 618 | 619 | /* Check every Database and create sockets */ 620 | /* we need first to create and bind all of them */ 621 | /* so that in case of failure we do not start any */ 622 | /* update thread */ 623 | fprintf(stderr, "Check the DB\n"); 624 | for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){ 625 | /* check for crash and recover if needed */ 626 | /* make a connection to a database */ 627 | db_host = ca_get_srcdbmachine(source_hdl); 628 | db_port = ca_get_srcdbport(source_hdl); 629 | db_name = ca_get_srcdbname(source_hdl); 630 | db_user = ca_get_srcdbuser(source_hdl); 631 | db_passwd = ca_get_srcdbpassword(source_hdl); 632 | db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd); 633 | /* now check TR record */ 634 | TR_recover(db_connection); 635 | /* free resources */ 636 | SQ_close_connection(db_connection); 637 | free(db_host); 638 | free(db_name); 639 | free(db_user); 640 | free(db_passwd); 641 | 642 | update_mode = ca_get_srcmode(source_hdl); 643 | if(IS_UPDATE(update_mode)) { 644 | /* update_port = SK_atoport(CO_get_update_port(), "tcp"); */ 645 | update_port = ca_get_srcupdateport(source_hdl); 646 | printf("XXX htons(update_port)=%d\n", update_port); 647 | /* XXX ask AMRM to change the name of the function */ 648 | 649 | SV_update_sock[source] = SK_getsock(SOCK_STREAM, update_port, 128, INADDR_ANY); 650 | } 651 | else SV_update_sock[source] = 0; 652 | } 653 | SV_update_sock[source+1]=-1; /* end of socket array */ 654 | 655 | /* Initialise the radix tree (separate thread[s]) 656 | already can allow socket connections, because the trees will 657 | be created locked, and will be unlocked when loaded */ 658 | 659 | /* pthread_mutex_lock( &radix_initializing_lock ); */ 660 | TH_create((void *(*)(void *))radix_init, NULL); 661 | /* pthread_mutex_lock( &radix_initializing_lock ); */ 662 | 663 | 664 | /* Now.... accept() calls block until they get a connection 665 | so to listen on more than one port we need more 666 | than one thread */ 667 | 668 | /* Create master thread for whois threads */ 669 | SV_concurrent_server(SV_whois_sock, 64, "whois", PW_interact); 670 | /* Create master thread for config threads */ 671 | SV_concurrent_server(SV_config_sock, 0, "config", PC_interact); 672 | /* Create master thread for mirror threads */ 673 | SV_concurrent_server(SV_mirror_sock, 0, "mirror", PM_interact); 674 | 675 | /* Walk through the sources and */ 676 | /* run update thread for every source with CANUPD == 'y' */ 677 | 678 | for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){ 679 | update_mode = ca_get_srcmode(source_hdl); 680 | source_name= ca_get_srcname(source_hdl); 681 | 682 | if(IS_UPDATE(update_mode)) { 683 | /* run RIPupdate thread */ 684 | fprintf(stderr,"Source [%s] Mode UPDATE [port=%d]\n", source_name, ca_get_srcupdateport(source_hdl)); 685 | ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode UPDATE [port=%d]", source_name, ca_get_srcupdateport(source_hdl)); 686 | TH_create((void *(*)(void *))UD_do_updates, (void *)source); 687 | } 688 | else if(IS_NRTM_CLNT(update_mode)){ 689 | /* start NRTM client */ 690 | fprintf(stderr,"Source [%s] Mode NRTM\n", source_name); 691 | ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode NRTM", source_name); 692 | TH_create((void *(*)(void *))UD_do_nrtm, (void *)source); 693 | } 694 | else { 695 | fprintf(stderr,"Source [%s] Mode STATIC\n", source_name); 696 | ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode STATIC", source_name); 697 | } 698 | free(source_name); /* because ca_* functions return copies */ 699 | } 700 | /* terminate the thread */ 701 | /* XXX not return becase then we terminate the whole process */ 702 | pthread_exit(NULL); 703 | return(1); /* we will never reach this point */ 704 | } /* SV_start() */ 705 | 706 | /* SV_shutdown() */ 707 | /*++++++++++++++++++++++++++++++++++++++ 708 | 709 | Shutdown the server. 710 | 711 | More: 712 | +html+ <PRE> 713 | Authors: 714 | andrei 715 | +html+ </PRE> 716 | +html+ Stops the server. 717 | +html+ <OL> 718 | +html+ <LI> Close listening sockets (whois, config, mirror and updates) 719 | +html+ <LI> Stop all threads by triggering do_server variable. 720 | +html+ </OL> 721 | +html+ <A HREF=".DBrc">.properties</A> 722 | 723 | ++++++++++++++++++++++++++++++++++++++*/ 724 | void SV_shutdown() { 725 | char print_buf[STR_M]; 726 | int source; 727 | time_t shutdowntime; 728 | struct timeval tval; 729 | char shuttime[100]; 730 | 731 | sprintf(print_buf, "%d", 0); 732 | /* Stop updates */ 733 | CO_set_const("UD.do_update", print_buf); 734 | /* Stop all servers */ 735 | CO_set_const("SV.do_server", print_buf); 736 | sprintf(print_buf, "Stopping all servers\n"); 737 | fprintf(stderr, print_buf); 738 | /*log_print(print_buf); */ 739 | strcpy(print_buf, ""); 740 | 741 | /* wait for all updates to complete */ 742 | /* XXX may be changed with blocking interface for stop updates */ 743 | sleep(5); 744 | 745 | /* Store the shutdown time */ 746 | gettimeofday(&tval, NULL); 747 | shutdowntime = tval.tv_sec;/* seconds since Jan. 1, 1970 */ 748 | 749 | /* Log the sshutdown time */ 750 | ctime_r(&shutdowntime, shuttime); 751 | ER_inf_va(FAC_SV, 0xFFFFFF, "Server shutdown %s", shuttime); 752 | 753 | 754 | 755 | /* Wake up all sleeping threads */ 756 | fprintf(stderr, "Going to wake sleeping threads up\n"); 757 | 758 | /* Delete the pid file to indicate normal shutdown */ 759 | if(unlink(SV_pidfile)==-1) { 760 | ER_perror(FAC_SV, 1, "cannot delete pid file %s:", SV_pidfile); 761 | } 762 | 763 | 764 | /* CLose all listening sockets, so accept call exits */ 765 | close(SV_whois_sock); 766 | close(SV_config_sock); 767 | close(SV_mirror_sock); 768 | for (source=0; SV_update_sock[source]!=-1; source++) 769 | if(SV_update_sock[source]!=0)close(SV_update_sock[source]); 770 | 771 | 772 | } /* SV_shutdown() */