1 | /*************************************** 2 | $Revision: 1.36 $ 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 | 10 | +html+ <DL COMPACT> 11 | +html+ <DT>Online References: 12 | +html+ <DD><UL> 13 | +html+ <LI>Based on <A HREF="http://iii.ripe.net/dbase/coding/new.code/progress/ottrey/code/java/src/DBServer.java">DBServer.java</A> 14 | +html+ </UL> 15 | +html+ </DL> 16 | 17 | ******************/ /****************** 18 | Modification History: 19 | ottrey (02/03/1999) Created. 20 | ottrey (08/03/1999) Modified. 21 | joao (22/06/1999) Modified. 22 | ******************/ /****************** 23 | Copyright (c) 1999 RIPE NCC 24 | 25 | All Rights Reserved 26 | 27 | Permission to use, copy, modify, and distribute this software and its 28 | documentation for any purpose and without fee is hereby granted, 29 | provided that the above copyright notice appear in all copies and that 30 | both that copyright notice and this permission notice appear in 31 | supporting documentation, and that the name of the author not be 32 | used in advertising or publicity pertaining to distribution of the 33 | software without specific, written prior permission. 34 | 35 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 36 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 37 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 38 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 39 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 40 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 41 | ***************************************/ 42 | #include <sys/socket.h> 43 | #include <netinet/in.h> 44 | 45 | #include <sys/wait.h> 46 | #include <ctype.h> 47 | 48 | #include <sys/types.h> 49 | #include <sys/stat.h> 50 | 51 | #include "thread.h" 52 | #include "rxroutines.h" 53 | #include "socket.h" 54 | /* 55 | #include "objects.h" 56 | */ 57 | #include "constants.h" 58 | 59 | #include "ca_configFns.h" 60 | #include "ca_dictSyms.h" 61 | #include "ca_macros.h" 62 | #include "ca_srcAttribs.h" 63 | 64 | #include "mysql_driver.h" 65 | #include "access_control.h" 66 | #include "ud.h" 67 | #include "server.h" 68 | 69 | #include "rp.h" 70 | #include "memwrap.h" 71 | 72 | #include "ta.h" 73 | 74 | #define RIPE_REG 17 75 | 76 | /*+ String sizes +*/ 77 | #define STR_S 63 78 | #define STR_M 255 79 | #define STR_L 1023 80 | #define STR_XL 4095 81 | #define STR_XXL 16383 82 | 83 | 84 | /* Storage for descriptors of the read side of the pipe */ 85 | int sv_lockfd[MAX_LOCKS]; 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 | /*+ Mutex lock. Used for synchronizing changes. +*/ 97 | pthread_mutex_t Whois_thread_count_lock; 98 | pthread_mutex_t Config_thread_count_lock; 99 | pthread_mutex_t Mirror_thread_count_lock; 100 | 101 | /*+ The number of threads. +*/ 102 | int Whois_thread_count; 103 | int Config_thread_count; 104 | int Mirror_thread_count; 105 | 106 | 107 | /*+ Server starting time +*/ 108 | time_t SV_starttime; 109 | 110 | /* pthread_mutex_t radix_initializing_lock; */ 111 | /* XXX this is a workaround of a problem with mysql - it prevents the 112 | update/nrtm threads from starting before the radix tree is loaded. 113 | 114 | Apparently, even LOCK TABLES doesn't prevent the program from locking up 115 | */ 116 | 117 | static void do_watchdog(void *arg); 118 | 119 | /* Logging results */ 120 | static void log_print(const char *arg) { 121 | FILE *logf; 122 | 123 | if (CO_get_thread_logging() == 1) { 124 | if (strcmp(CO_get_thread_logfile(), "stdout") == 0) { 125 | printf(arg); 126 | } 127 | else { 128 | logf = fopen(CO_get_thread_logfile(), "a"); 129 | fprintf(logf, arg); 130 | fclose(logf); 131 | } 132 | } 133 | 134 | } /* log_print() */ 135 | 136 | 137 | void radix_init(void){ 138 | int i; 139 | ca_dbSource_t *source_hdl; 140 | 141 | wr_log_set(0); 142 | /* this needs to be done in two loops, 143 | because the trees must be created asap (first loop) 144 | and then locked until they are populated in the second loop 145 | */ 146 | 147 | for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){ 148 | dieif( RP_init_trees( source_hdl ) != RP_OK ); 149 | } 150 | 151 | for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){ 152 | dieif( RP_sql_load_reg( source_hdl ) != RP_OK ); 153 | } 154 | 155 | #if 0 156 | { 157 | er_path_t erlogstr; 158 | 159 | erlogstr.fdes = stdout; 160 | erlogstr.asp = 0xffff0000; 161 | erlogstr.fac = 0; /* FAC_QI; */ 162 | erlogstr.sev = ER_SEV_D; 163 | erlogstr.mode = ER_M_SEVCHAR | ER_M_FACSYMB | ER_M_TEXTLONG; 164 | 165 | ER_setpath(& erlogstr); 166 | } 167 | #endif 168 | wr_log_set(0); /* switch on/off the memory leak detector */ 169 | /* pthread_mutex_unlock( &radix_initializing_lock ); */ 170 | 171 | pthread_exit((void *)0); 172 | } 173 | 174 | /* main_loop() */ 175 | /*++++++++++++++++++++++++++++++++++++++ 176 | 177 | Waits for an incoming connection on the and spawns a new thread to handle it. 178 | 179 | void *arg Pointer to a struct containing the socket to talk to the client and 180 | the function to call depending on the incoming connection. 181 | 182 | More: 183 | +html+ <PRE> 184 | Author: 185 | ottrey 186 | joao 187 | andrei (do_server) 188 | +html+ </PRE> 189 | ++++++++++++++++++++++++++++++++++++++*/ 190 | static void *main_loop(void *arg) { 191 | th_args *args = (th_args *)arg; 192 | int connected_socket; 193 | int do_server; 194 | 195 | while(do_server=CO_get_do_server()) { 196 | 197 | connected_socket = SK_accept_connection(args->sock); 198 | if(connected_socket==-1) break; 199 | 200 | 201 | ER_dbg_va(FAC_TH, ASP_TH_NEW, "Starting a new thread"); 202 | 203 | /* Start a new thread. */ 204 | 205 | 206 | TH_create((void *(*)(void *))(args->function), (void *)connected_socket); 207 | // 208 | // pthread_attr_init(&attr); /* initialize attr with default attributes */ 209 | // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 210 | // pthread_create(&tid, &attr, (void *(*)(void *))(args->function), (void *)connected_socket); 211 | } 212 | 213 | ER_dbg_va(FAC_TH, ASP_TH_NEW, "Exiting from the main loop"); 214 | 215 | } /* main_loop() */ 216 | 217 | 218 | /* SV_start() */ 219 | /*++++++++++++++++++++++++++++++++++++++ 220 | 221 | Start the server. 222 | 223 | More: 224 | +html+ <PRE> 225 | Authors: 226 | ottrey 227 | joao 228 | +html+ </PRE> 229 | +html+ Starts up the server. 230 | +html+ <OL> 231 | +html+ <LI> Create sockets on the necessary ports (whois, config and mirror) 232 | +html+ <LI> Start new threads for each service. 233 | +html+ </OL> 234 | +html+ <A HREF=".DBrc">.properties</A> 235 | 236 | ++++++++++++++++++++++++++++++++++++++*/ 237 | void SV_start() { 238 | /* Make listening sockets global variables */ 239 | /* int whois_sock,config_sock,mirror_sock,update_sock; */ 240 | /* uint32_t whois_addr,sock_addr,mirror_addr; */ 241 | int whois_port = -1; 242 | int config_port = -1; 243 | int mirror_port = -1; 244 | int update_port = -1; 245 | int update_mode = 0; 246 | sigset_t sset; 247 | int fdes[2]; 248 | struct timeval tval; 249 | ca_dbSource_t *source_hdl; 250 | char *source_name; 251 | int source; 252 | 253 | /* Store the starting time */ 254 | gettimeofday(&tval, NULL); 255 | SV_starttime = tval.tv_sec;/* seconds since Jan. 1, 1970 */ 256 | 257 | /* Create interrupt pipe */ 258 | /* Writing to this pipe will cause sleeping threads */ 259 | /* to wake up */ 260 | fprintf(stderr, "Creating an interrupt pipe\n"); 261 | if(pipe(fdes)==-1) { 262 | printf("Cannot open interrupt pipe\n"); 263 | exit(-1); 264 | } 265 | /* Save the pipe descriptors in sv_lock array */ 266 | sv_lockfd[WLOCK_SHTDOWN]=fdes[0]; 267 | sv_lockfd[LOCK_SHTDOWN]=fdes[1]; 268 | 269 | 270 | /* Initialise the access control list. */ 271 | AC_build(); 272 | AC_acc_load(); 273 | /* explicitly start the decay thread */ 274 | TH_create((void *(*)(void *))AC_decay, NULL); 275 | 276 | /* Initialise the radix tree (separate thread[s]) 277 | already can allow socket connections, because the trees will 278 | be created locked, and will be unlocked when loaded */ 279 | 280 | /* pthread_mutex_lock( &radix_initializing_lock ); */ 281 | TH_create((void *(*)(void *))radix_init, NULL); 282 | /* pthread_mutex_lock( &radix_initializing_lock ); */ 283 | 284 | 285 | /* XXX I have no idea how this is working!! It's wrong! - ottrey 30/7/99 */ 286 | /* Get port information for each service */ 287 | whois_port = SK_atoport(CO_get_whois_port(), "tcp"); 288 | printf("XXX htons(whois_port)=%d\n", htons(whois_port)); 289 | if(whois_port == -1) { 290 | printf("Invalid service/port: %d\n", htons(whois_port)); 291 | exit(-1); 292 | } 293 | 294 | /* XXX I have no idea how this is working!! It's wrong! - ottrey 30/7/99 */ 295 | config_port = SK_atoport(CO_get_config_port(), "tcp"); 296 | printf("XXX htons(config_port)=%d\n", htons(config_port)); 297 | if(config_port == -1) { 298 | printf("Invalid service/port: %d\n", htons(config_port)); 299 | exit(-1); 300 | } 301 | mirror_port = SK_atoport(CO_get_mirror_port(), "tcp"); 302 | printf("XXX htons(mirror_port)=%d\n", htons(mirror_port)); 303 | if(mirror_port == -1) { 304 | printf("Invalid service/port: %d\n", mirror_port); 305 | exit(-1); 306 | } 307 | 308 | /* XXX I have no idea how this is working!! It's wrong! - ottrey 30/7/99 */ 309 | /* update_port = SK_atoport(CO_get_update_port(), "tcp"); */ 310 | /* printf("XXX htons(update_port)=%d\n", htons(update_port)); */ 311 | /* if(update_port == -1) { */ 312 | /* printf("Invalid service/port: %d\n", htons(update_port)); */ 313 | /* exit(-1); */ 314 | /* } */ 315 | 316 | 317 | 318 | /* 6. Create a socket on the necessary ports/addresses and bind to them. */ 319 | /* whois socket */ 320 | SV_whois_sock = SK_getsock(SOCK_STREAM, whois_port, INADDR_ANY); 321 | /* Currently binds to INADDR_ANY. Will need to get specific address */ 322 | /* SV_whois_sock = SK_getsock(SOCK_STREAM,whois_port,whois_addr); */ 323 | /* config interface socket */ 324 | SV_config_sock = SK_getsock(SOCK_STREAM, config_port, INADDR_ANY); 325 | /* nrt socket */ 326 | SV_mirror_sock = SK_getsock(SOCK_STREAM,mirror_port,INADDR_ANY); 327 | 328 | 329 | 330 | /* update interface socket */ 331 | /* we need first to create and bind all of them */ 332 | /* so that in case of failure we do not start any */ 333 | /* update thread */ 334 | for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){ 335 | update_mode = ca_get_srcmode(source_hdl); 336 | if(IS_UPDATE(update_mode)) { 337 | /* update_port = SK_atoport(CO_get_update_port(), "tcp"); */ 338 | update_port = htons(ca_get_srcupdateport(source_hdl)); 339 | printf("XXX htons(update_port)=%d\n", htons(update_port)); 340 | /* XXX ask AMRM to change the name of the function */ 341 | 342 | SV_update_sock[source] = SK_getsock(SOCK_STREAM, update_port, INADDR_ANY); 343 | } 344 | else SV_update_sock[source] = 0; 345 | } 346 | SV_update_sock[source+1]=-1; /* end of socket array */ 347 | 348 | /* Now.... accept() calls block until they get a connection 349 | so to listen on more than one port we need more 350 | than one thread */ 351 | 352 | /* Create master thread for whois threads */ 353 | SV_concurrent_server(SV_whois_sock, SV_do_whois); 354 | 355 | /* Create master thread for config threads */ 356 | SV_concurrent_server(SV_config_sock, SV_do_config); 357 | /* Create master thread for mirror threads */ 358 | SV_concurrent_server(SV_mirror_sock, SV_do_mirror); 359 | 360 | /* Walk through the sources and */ 361 | /* run update thread for every source with CANUPD == 'y' */ 362 | 363 | for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){ 364 | update_mode = ca_get_srcmode(source_hdl); 365 | source_name= ca_get_srcname(source_hdl); 366 | 367 | if(IS_UPDATE(update_mode)) { 368 | /* run RIPupdate thread */ 369 | fprintf(stderr,"Source [%s] Mode UPDATE\n", source_name); 370 | TH_create((void *(*)(void *))UD_do_updates, (void *)source); 371 | } 372 | else { 373 | /* start NRTM client */ 374 | fprintf(stderr,"Source [%s] Mode NRTM\n", source_name); 375 | TH_create((void *(*)(void *))UD_do_nrtm, (void *)source); 376 | } 377 | free(source_name); /* because ca_* functions return copies */ 378 | } 379 | 380 | 381 | 382 | /* XXX Is this needed? */ 383 | pthread_exit(NULL); 384 | 385 | } /* SV_start() */ 386 | 387 | /* SV_shutdown() */ 388 | /*++++++++++++++++++++++++++++++++++++++ 389 | 390 | Shutdown the server. 391 | 392 | More: 393 | +html+ <PRE> 394 | Authors: 395 | andrei 396 | +html+ </PRE> 397 | +html+ Stops the server. 398 | +html+ <OL> 399 | +html+ <LI> Close listening sockets (whois, config, mirror and updates) 400 | +html+ <LI> Stop all threads by triggering do_server variable. 401 | +html+ </OL> 402 | +html+ <A HREF=".DBrc">.properties</A> 403 | 404 | ++++++++++++++++++++++++++++++++++++++*/ 405 | void SV_shutdown() { 406 | char print_buf[STR_M]; 407 | int source; 408 | 409 | sprintf(print_buf, "%d", 0); 410 | /* Stop updates */ 411 | CO_set_const("UD.do_update", print_buf); 412 | /* Stop all servers */ 413 | CO_set_const("SV.do_server", print_buf); 414 | sprintf(print_buf, "Stopping all servers\n"); 415 | fprintf(stderr, print_buf); 416 | /*log_print(print_buf); */ 417 | strcpy(print_buf, ""); 418 | 419 | /* Wake up all sleeping threads */ 420 | fprintf(stderr, "Going to wake sleeping threads up\n"); 421 | write(sv_lockfd[WLOCK_SHTDOWN], " ", 1); 422 | 423 | /* CLose all listening sockets, so accept call exits */ 424 | close(SV_whois_sock); 425 | close(SV_config_sock); 426 | close(SV_mirror_sock); 427 | for (source=0; SV_update_sock[source]!=-1; source++) 428 | if(SV_update_sock[source]!=0)close(SV_update_sock[source]); 429 | 430 | 431 | } /* SV_shutdown() */ 432 | 433 | 434 | /* SV_sleep() */ 435 | /*++++++++++++++++++++++++++++++++++++++ 436 | 437 | Sleep and wake up on special events. 438 | 439 | More: 440 | +html+ <PRE> 441 | Authors: 442 | andrei 443 | +html+ </PRE> 444 | +html+ Sleeps timeout but wakes up when an envent occures. 445 | 446 | ++++++++++++++++++++++++++++++++++++++*/ 447 | int SV_sleep(int lock, int sleeptime) { 448 | struct timeval timeout; 449 | struct stat st; 450 | fd_set set; 451 | 452 | if (fstat(sv_lockfd[lock], &st) ==-1) { 453 | fprintf(stderr, "Error stat-ing the lock file\n"); 454 | return(-1); 455 | } 456 | 457 | timeout.tv_sec=sleeptime; 458 | timeout.tv_usec=0; 459 | 460 | FD_ZERO(&set); 461 | FD_SET(sv_lockfd[lock], &set); 462 | 463 | fprintf(stderr, "Going to sleep\n"); 464 | select(sv_lockfd[lock]+1, &set, NULL, NULL, &timeout); 465 | 466 | fprintf(stderr, "Select returned\n"); 467 | 468 | return(0); 469 | } 470 | 471 | /*++++++++++++++++++++++++++++++++++++++ 472 | 473 | Handle signals. 474 | 475 | Changes the flags: 476 | do_nrtm 477 | do_update 478 | do_whoisd 479 | 480 | More: 481 | +html+ <PRE> 482 | Author: 483 | andrei 484 | +html+ </PRE> 485 | ++++++++++++++++++++++++++++++++++++++*/ 486 | void *SV_signal_thread() { 487 | char print_buf[STR_M]; 488 | sigset_t sset; 489 | int sigReceived; 490 | int do_update; 491 | 492 | sigemptyset(&sset); 493 | sigaddset(&sset, SIGTERM); 494 | sigaddset(&sset, SIGINT); 495 | sigaddset(&sset, SIGUSR1); 496 | /* This is a bit confusing, but is needed */ 497 | /* For more information on signal handling in */ 498 | /* threads see for example "Multithreading Programming */ 499 | /* Techniques" by Shashi Prasad, ISBN 0-07-912250-7, pp. 94-101 */ 500 | pthread_sigmask(SIG_BLOCK, &sset, NULL); 501 | /* fprintf(stderr, "Signal handler installed\n");*/ 502 | 503 | for(;;) 504 | { 505 | sigwait(&sset, &sigReceived); 506 | sprintf(print_buf, "Signal received [%d]\n", sigReceived); 507 | log_print(print_buf); strcpy(print_buf, ""); 508 | /* fprintf(stderr, "Signal received [%d]\n", sigReceived); */ 509 | switch (sigReceived) 510 | { 511 | case SIGINT: 512 | /* SIGINT stops all servers */ 513 | SV_shutdown(); 514 | pthread_exit((void *)0); 515 | break; 516 | 517 | case SIGTERM: 518 | /* SIGTERM will switch the updates on and off */ 519 | do_update=CO_get_do_update(); 520 | if(do_update)do_update=0; else do_update=1; 521 | sprintf(print_buf, "%d", do_update); 522 | CO_set_const("UD.do_update", print_buf); 523 | if(do_update) 524 | sprintf(print_buf, "Starting updates\n"); 525 | else 526 | sprintf(print_buf, "Stopping updates\n"); 527 | log_print(print_buf); strcpy(print_buf, ""); 528 | /* fprintf(stderr, "Stopping updates (SIGTERM received)\n"); */ 529 | break; 530 | } 531 | } 532 | } /* SV_signal_thread() */ 533 | 534 | /* SV_concurrent_server() */ 535 | /*++++++++++++++++++++++++++++++++++++++ 536 | 537 | This is the routine that creates the main threads. 538 | 539 | int sock The socket to connect to. 540 | void * do_function The function to call for each type of service 541 | 542 | More: 543 | +html+ <PRE> 544 | Author: 545 | ottrey 546 | joao 547 | +html+ </PRE> 548 | ++++++++++++++++++++++++++++++++++++++*/ 549 | void SV_concurrent_server(int sock, void *do_function(void *)) { 550 | th_args *args; 551 | pthread_t tid; 552 | pthread_attr_t attr; 553 | 554 | dieif( wr_calloc((void **)&args,1,sizeof(th_args)) != UT_OK); 555 | 556 | args->function=(void *)do_function; 557 | args->sock=sock; 558 | 559 | /* pthread_mutex_init(&Whois_thread_count_lock,NULL); */ 560 | 561 | /* Start a new thread. */ 562 | 563 | TH_create(main_loop, (void *)args); 564 | 565 | 566 | /* Start a new thread. */ 567 | // pthread_attr_init(&attr); /* initialize attr with default attributes */ 568 | // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 569 | // pthread_create(&tid, &attr, main_thread, (void *)args); 570 | 571 | } /* TH_run() */ 572 | 573 | /* SV_do_whois() */ 574 | /*++++++++++++++++++++++++++++++++++++++ 575 | 576 | Handle whois connections. 577 | 578 | void *arg The socket to connect to. (It has to be passed in this way for this thread routine.) 579 | 580 | More: 581 | +html+ <PRE> 582 | Author: 583 | joao 584 | +html+ </PRE> 585 | ++++++++++++++++++++++++++++++++++++++*/ 586 | void *SV_do_whois(void *arg) { 587 | int sock = (int)arg; 588 | 589 | ER_dbg_va(FAC_TH, ASP_TH_NEW, 590 | "Whois: Child thread [%d]: Socket number = %d", 591 | pthread_self(), sock); 592 | 593 | /* Use a mutex to update the global whois thread counter. */ 594 | pthread_mutex_lock(&Whois_thread_count_lock); 595 | Whois_thread_count++; 596 | ER_dbg_va(FAC_TH, ASP_TH_NEW, 597 | "Whois_thread_count++=%d", Whois_thread_count); 598 | 599 | pthread_mutex_unlock(&Whois_thread_count_lock); 600 | 601 | TA_add(sock, "whois"); 602 | PW_interact(sock); 603 | TA_delete(); 604 | 605 | /* Use a mutex to update the global whois thread counter. */ 606 | pthread_mutex_lock(&Whois_thread_count_lock); 607 | Whois_thread_count--; 608 | ER_dbg_va(FAC_TH, ASP_TH_NEW, 609 | "Whois_thread_count--=%d", Whois_thread_count); 610 | pthread_mutex_unlock(&Whois_thread_count_lock); 611 | 612 | pthread_exit((void *)0); 613 | 614 | } /* SV_do_whois() */ 615 | 616 | /* SV_do_mirror() */ 617 | /*++++++++++++++++++++++++++++++++++++++ 618 | 619 | Handle NRTM connections. 620 | 621 | void *arg The socket to connect to. (It has to be passed in this way for this thread routine.) 622 | 623 | More: 624 | +html+ <PRE> 625 | Author: 626 | joao 627 | +html+ </PRE> 628 | ++++++++++++++++++++++++++++++++++++++*/ 629 | void *SV_do_mirror(void *arg) { 630 | int sock = (int)arg; 631 | char print_buf[STR_M]; 632 | 633 | sprintf(print_buf, "NRTM: Child thread [%d]: Socket number = %d\n", pthread_self(), sock); log_print(print_buf); strcpy(print_buf, ""); 634 | 635 | /* Use a mutex to update the global mirror thread counter. */ 636 | pthread_mutex_lock(&Mirror_thread_count_lock); 637 | Mirror_thread_count++; 638 | sprintf(print_buf, "Mirror_thread_count++=%d\n", Mirror_thread_count); log_print(print_buf); strcpy(print_buf, ""); 639 | pthread_mutex_unlock(&Mirror_thread_count_lock); 640 | 641 | TA_add(sock, "mirror"); 642 | PM_interact(sock); 643 | TA_delete(); 644 | 645 | /* Use a mutex to update the global mirror thread counter. */ 646 | pthread_mutex_lock(&Mirror_thread_count_lock); 647 | Mirror_thread_count--; 648 | sprintf(print_buf, "Mirror_thread_count--=%d\n", Mirror_thread_count); log_print(print_buf); strcpy(print_buf, ""); 649 | pthread_mutex_unlock(&Mirror_thread_count_lock); 650 | 651 | pthread_exit((void *)0); 652 | 653 | } /* SV_do_mirror() */ 654 | 655 | /* SV_do_config() */ 656 | /*++++++++++++++++++++++++++++++++++++++ 657 | 658 | Handle config connections. 659 | 660 | void *arg The socket to connect to. (It has to be passed in this way for this 661 | thread routine.) 662 | 663 | More: 664 | +html+ <PRE> 665 | Author: 666 | joao 667 | +html+ </PRE> 668 | ++++++++++++++++++++++++++++++++++++++*/ 669 | void *SV_do_config(void *arg) { 670 | int sock = (int)arg; 671 | char print_buf[STR_M]; 672 | 673 | sprintf(print_buf, "Config: Child thread [%d]: Socket number = %d\n", pthread_self(), sock); log_print(print_buf); strcpy(print_buf, ""); 674 | 675 | /* 676 | printf("Hi there, there is nothing to configure yet\nBye..... :-)\n"); 677 | fflush(NULL); 678 | 679 | SK_close(sock); 680 | */ 681 | TA_add(sock, "config"); 682 | PC_interact(sock); 683 | TA_delete(); 684 | 685 | pthread_exit((void *)0); 686 | 687 | } /* SV_do_config() */ 688 | 689 | 690 | /*++++++++++++++++++++++++++++++++++++++ 691 | 692 | This is the routine that creates a watchdog thread. 693 | 694 | The watchdog will cancel (pthread_cancel()) the calling thread in case the 695 | socket is closed by the client (its read-half is closed). The calling 696 | thread should make necessaruy preparations when calling the watchdog: 697 | 698 | - the socket should be connected 699 | - cancellation points and cleanup routines should be defined 700 | 701 | In case the connection is closed by the calling thread itself, the 702 | watchdog just exits and no action against the calling thread is performed. 703 | 704 | wd_args - a pointer to wd_args_t structure containing 705 | data about socket and thread ID 706 | 707 | More: 708 | +html+ <PRE> 709 | Author: 710 | ottrey 711 | joao 712 | andrei 713 | +html+ </PRE> 714 | ++++++++++++++++++++++++++++++++++++++*/ 715 | 716 | void SV_watchdog(wd_args_t *wd_args) { 717 | pthread_t tid; 718 | pthread_attr_t attr; 719 | 720 | /* Start a new thread. */ 721 | TH_create((void *(*)(void *))do_watchdog, (void *)wd_args); 722 | 723 | // pthread_attr_init(&attr); /* initialize attr with default attributes */ 724 | // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 725 | // pthread_create(&tid, &attr, (void *(*)(void *))do_watchdog, (void *)wd_args); 726 | 727 | } 728 | 729 | 730 | /*++++++++++++++++++++++++++++++++++++++ 731 | 732 | The watchdog thread itself 733 | 734 | The watchdog thread makes select() on the connected socket waiting until it 735 | becomes readable. If this happens as a result of some input, it'll simply 736 | dump it. Otherwise, this indicates that the client has closed the 737 | connection. In this case watchdog will cancel (pthread_cancel()) the whois 738 | thread (which in its turn will kill (mysql_kill()) mysql thread as part of 739 | its cleanup routine). 740 | 741 | More: 742 | +html+ <PRE> 743 | Author: 744 | andrei 745 | +html+ </PRE> 746 | ++++++++++++++++++++++++++++++++++++++*/ 747 | static void do_watchdog(void *arg) { 748 | wd_args_t *wd_args = (wd_args_t *)arg; 749 | int socket; 750 | pthread_t tid; 751 | int nready; 752 | int n; 753 | fd_set rset; 754 | char buff[STR_S]; 755 | 756 | socket = wd_args->connected_socket; 757 | tid = wd_args->tid; 758 | 759 | 760 | FD_ZERO(&rset); 761 | FD_SET(socket, &rset); 762 | 763 | while ((nready=select(socket+1, &rset, NULL, NULL, NULL))!=-1) { 764 | 765 | /* There was some input or client half of connection was closed */ 766 | /* Check for the latter */ 767 | if (( n=read(socket, buff, sizeof(buff))) == 0) { 768 | /* Connection was closed by client */ 769 | /* Now send a cancellation request to the whois thread. */ 770 | /* mysql thread will be terminated by thread cleanup routine */ 771 | 772 | /* The only possible error is ESRCH, so we do not care about */ 773 | pthread_cancel(tid); 774 | 775 | /* Exit the watchdog thread, passing NULL as we don't expect pthread_join() */ 776 | pthread_exit(NULL); 777 | } 778 | 779 | /* Otherwise dump input and continue */ 780 | } 781 | 782 | /* the only reason that we are here is that the socket has been */ 783 | /* closed by the whois thread and not valid. Just exit the watchdog, */ 784 | /* passing NULL as we don't expect pthread_join() */ 785 | pthread_exit(NULL); 786 | 787 | }