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