1 | /*************************************** 2 | $Revision: 1.63 $ 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 | AC_persistence_init(); 595 | /* explicitly start the decay & persistence threads */ 596 | TH_create((void *(*)(void *))AC_decay, NULL); 597 | TH_create((void *(*)(void *))AC_persistence_daemon, NULL); 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() */