1 | /*************************************** 2 | $Revision: 1.44 $ 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 "sk.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 | 122 | printf(arg); 123 | 124 | } /* log_print() */ 125 | 126 | 127 | void radix_init(void){ 128 | int i; 129 | ca_dbSource_t *source_hdl; 130 | 131 | wr_log_set(0); 132 | /* this needs to be done in two loops, 133 | because the trees must be created asap (first loop) 134 | and then locked until they are populated in the second loop 135 | */ 136 | 137 | for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){ 138 | dieif( RP_init_trees( source_hdl ) != RP_OK ); 139 | } 140 | 141 | for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){ 142 | dieif( RP_sql_load_reg( source_hdl ) != RP_OK ); 143 | } 144 | 145 | wr_log_set(0); /* switch on/off the memory leak detector */ 146 | /* pthread_mutex_unlock( &radix_initializing_lock ); */ 147 | 148 | pthread_exit((void *)0); 149 | } 150 | 151 | /* main_loop() */ 152 | /*++++++++++++++++++++++++++++++++++++++ 153 | 154 | Waits for an incoming connection on the and spawns a new thread to handle it. 155 | 156 | void *arg Pointer to a struct containing the socket to talk to the client and 157 | the function to call depending on the incoming connection. 158 | 159 | More: 160 | +html+ <PRE> 161 | Author: 162 | ottrey 163 | joao 164 | andrei (do_server) 165 | +html+ </PRE> 166 | ++++++++++++++++++++++++++++++++++++++*/ 167 | static void *main_loop(void *arg) { 168 | th_args *args = (th_args *)arg; 169 | int connected_socket; 170 | int do_server; 171 | 172 | while(do_server=CO_get_do_server()) { 173 | 174 | connected_socket = SK_accept_connection(args->sock); 175 | if(connected_socket==-1) break; 176 | 177 | 178 | ER_dbg_va(FAC_TH, ASP_TH_NEW, "Starting a new thread"); 179 | 180 | /* Start a new thread. */ 181 | 182 | 183 | TH_create((void *(*)(void *))(args->function), (void *)connected_socket); 184 | // 185 | // pthread_attr_init(&attr); /* initialize attr with default attributes */ 186 | // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 187 | // pthread_create(&tid, &attr, (void *(*)(void *))(args->function), (void *)connected_socket); 188 | } 189 | 190 | ER_dbg_va(FAC_TH, ASP_TH_NEW, "Exiting from the main loop"); 191 | 192 | } /* main_loop() */ 193 | 194 | 195 | /* SV_start() */ 196 | /*++++++++++++++++++++++++++++++++++++++ 197 | 198 | Start the server. 199 | 200 | More: 201 | +html+ <PRE> 202 | Authors: 203 | ottrey 204 | joao 205 | +html+ </PRE> 206 | +html+ Starts up the server. 207 | +html+ <OL> 208 | +html+ <LI> Create sockets on the necessary ports (whois, config and mirror) 209 | +html+ <LI> Start new threads for each service. 210 | +html+ </OL> 211 | +html+ <A HREF=".DBrc">.properties</A> 212 | 213 | ++++++++++++++++++++++++++++++++++++++*/ 214 | void SV_start() { 215 | /* Make listening sockets global variables */ 216 | /* int whois_sock,config_sock,mirror_sock,update_sock; */ 217 | /* uint32_t whois_addr,sock_addr,mirror_addr; */ 218 | int whois_port = -1; 219 | int config_port = -1; 220 | int mirror_port = -1; 221 | int update_port = -1; 222 | int update_mode = 0; 223 | sigset_t sset; 224 | int fdes[2]; 225 | struct timeval tval; 226 | ca_dbSource_t *source_hdl; 227 | char *source_name; 228 | int source; 229 | char *db_host, *db_name, *db_user, *db_passwd; 230 | int db_port; 231 | SQ_connection_t *db_connection; 232 | 233 | /* Store the starting time */ 234 | gettimeofday(&tval, NULL); 235 | SV_starttime = tval.tv_sec;/* seconds since Jan. 1, 1970 */ 236 | 237 | /* Create interrupt pipe */ 238 | /* Writing to this pipe will cause sleeping threads */ 239 | /* to wake up */ 240 | fprintf(stderr, "Creating an interrupt pipe\n"); 241 | if(pipe(fdes)==-1) { 242 | printf("Cannot open interrupt pipe\n"); 243 | exit(-1); 244 | } 245 | /* Save the pipe descriptors in sv_lock array */ 246 | sv_lockfd[WLOCK_SHTDOWN]=fdes[0]; 247 | sv_lockfd[LOCK_SHTDOWN]=fdes[1]; 248 | 249 | /* Initialise modules */ 250 | SK_init(); 251 | 252 | /* Initialise the access control list. */ 253 | AC_build(); 254 | AC_acc_load(); 255 | /* explicitly start the decay thread */ 256 | TH_create((void *(*)(void *))AC_decay, NULL); 257 | 258 | 259 | 260 | /* Get port information for each service */ 261 | whois_port = htons(ca_get_svwhois_port); 262 | ER_dbg_va(FAC_SV, ASP_SV_PORT, "whois port is %d", ca_get_svwhois_port); 263 | 264 | config_port = htons(ca_get_svconfig_port); 265 | ER_dbg_va(FAC_SV, ASP_SV_PORT, "config port is %d", ca_get_svconfig_port); 266 | 267 | mirror_port = htons(ca_get_svmirror_port); 268 | ER_dbg_va(FAC_SV, ASP_SV_PORT, "mirror port is %d", ca_get_svmirror_port); 269 | 270 | 271 | /* 6. Create a socket on the necessary ports/addresses and bind to them. */ 272 | /* whois socket */ 273 | SV_whois_sock = SK_getsock(SOCK_STREAM, whois_port, INADDR_ANY); 274 | /* Currently binds to INADDR_ANY. Will need to get specific address */ 275 | /* SV_whois_sock = SK_getsock(SOCK_STREAM,whois_port,whois_addr); */ 276 | /* config interface socket */ 277 | SV_config_sock = SK_getsock(SOCK_STREAM, config_port, INADDR_ANY); 278 | /* nrt socket */ 279 | SV_mirror_sock = SK_getsock(SOCK_STREAM,mirror_port,INADDR_ANY); 280 | 281 | /* Check every Database and create sockets */ 282 | /* we need first to create and bind all of them */ 283 | /* so that in case of failure we do not start any */ 284 | /* update thread */ 285 | fprintf(stderr, "Check the DB\n"); 286 | for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){ 287 | /* check for crash and recover if needed */ 288 | /* make a connection to a database */ 289 | db_host = ca_get_srcdbmachine(source_hdl); 290 | db_port = ca_get_srcdbport(source_hdl); 291 | db_name = ca_get_srcdbname(source_hdl); 292 | db_user = ca_get_srcdbuser(source_hdl); 293 | db_passwd = ca_get_srcdbpassword(source_hdl); 294 | db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd); 295 | /* now check TR record */ 296 | TR_recover(db_connection); 297 | /* free resources */ 298 | SQ_close_connection(db_connection); 299 | free(db_host); 300 | free(db_name); 301 | free(db_user); 302 | free(db_passwd); 303 | 304 | update_mode = ca_get_srcmode(source_hdl); 305 | if(IS_UPDATE(update_mode)) { 306 | /* update_port = SK_atoport(CO_get_update_port(), "tcp"); */ 307 | update_port = htons(ca_get_srcupdateport(source_hdl)); 308 | printf("XXX htons(update_port)=%d\n", htons(update_port)); 309 | /* XXX ask AMRM to change the name of the function */ 310 | 311 | SV_update_sock[source] = SK_getsock(SOCK_STREAM, update_port, INADDR_ANY); 312 | } 313 | else SV_update_sock[source] = 0; 314 | } 315 | SV_update_sock[source+1]=-1; /* end of socket array */ 316 | 317 | /* Initialise the radix tree (separate thread[s]) 318 | already can allow socket connections, because the trees will 319 | be created locked, and will be unlocked when loaded */ 320 | 321 | /* pthread_mutex_lock( &radix_initializing_lock ); */ 322 | TH_create((void *(*)(void *))radix_init, NULL); 323 | /* pthread_mutex_lock( &radix_initializing_lock ); */ 324 | 325 | 326 | /* Now.... accept() calls block until they get a connection 327 | so to listen on more than one port we need more 328 | than one thread */ 329 | 330 | /* Create master thread for whois threads */ 331 | SV_concurrent_server(SV_whois_sock, SV_do_whois); 332 | 333 | /* Create master thread for config threads */ 334 | SV_concurrent_server(SV_config_sock, SV_do_config); 335 | /* Create master thread for mirror threads */ 336 | SV_concurrent_server(SV_mirror_sock, SV_do_mirror); 337 | 338 | /* Walk through the sources and */ 339 | /* run update thread for every source with CANUPD == 'y' */ 340 | 341 | for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){ 342 | update_mode = ca_get_srcmode(source_hdl); 343 | source_name= ca_get_srcname(source_hdl); 344 | 345 | if(IS_UPDATE(update_mode)) { 346 | /* run RIPupdate thread */ 347 | fprintf(stderr,"Source [%s] Mode UPDATE\n", source_name); 348 | TH_create((void *(*)(void *))UD_do_updates, (void *)source); 349 | } 350 | else if(IS_NRTM_CLNT(update_mode)){ 351 | /* start NRTM client */ 352 | fprintf(stderr,"Source [%s] Mode NRTM\n", source_name); 353 | TH_create((void *(*)(void *))UD_do_nrtm, (void *)source); 354 | } 355 | else fprintf(stderr,"Source [%s] Mode STATIC\n", source_name); 356 | free(source_name); /* because ca_* functions return copies */ 357 | } 358 | 359 | pthread_exit(NULL); 360 | 361 | } /* SV_start() */ 362 | 363 | /* SV_shutdown() */ 364 | /*++++++++++++++++++++++++++++++++++++++ 365 | 366 | Shutdown the server. 367 | 368 | More: 369 | +html+ <PRE> 370 | Authors: 371 | andrei 372 | +html+ </PRE> 373 | +html+ Stops the server. 374 | +html+ <OL> 375 | +html+ <LI> Close listening sockets (whois, config, mirror and updates) 376 | +html+ <LI> Stop all threads by triggering do_server variable. 377 | +html+ </OL> 378 | +html+ <A HREF=".DBrc">.properties</A> 379 | 380 | ++++++++++++++++++++++++++++++++++++++*/ 381 | void SV_shutdown() { 382 | char print_buf[STR_M]; 383 | int source; 384 | 385 | sprintf(print_buf, "%d", 0); 386 | /* Stop updates */ 387 | CO_set_const("UD.do_update", print_buf); 388 | /* Stop all servers */ 389 | CO_set_const("SV.do_server", print_buf); 390 | sprintf(print_buf, "Stopping all servers\n"); 391 | fprintf(stderr, print_buf); 392 | /*log_print(print_buf); */ 393 | strcpy(print_buf, ""); 394 | 395 | /* Wake up all sleeping threads */ 396 | fprintf(stderr, "Going to wake sleeping threads up\n"); 397 | write(sv_lockfd[WLOCK_SHTDOWN], " ", 1); 398 | 399 | /* CLose all listening sockets, so accept call exits */ 400 | close(SV_whois_sock); 401 | close(SV_config_sock); 402 | close(SV_mirror_sock); 403 | for (source=0; SV_update_sock[source]!=-1; source++) 404 | if(SV_update_sock[source]!=0)close(SV_update_sock[source]); 405 | 406 | 407 | } /* SV_shutdown() */ 408 | 409 | /************************************************************ 410 | * int SV_sleep() * 411 | * * 412 | * sleeps till shutdown request comes * 413 | * but at most <delay> seconds * 414 | * * 415 | * Returns: * 416 | * 1 - timeout * 417 | * 0 - shutdown * 418 | * * 419 | ************************************************************/ 420 | 421 | int SV_sleep(int delay) 422 | { 423 | int do_server; 424 | int elapsed_time=0; 425 | 426 | while((do_server=CO_get_do_server()) && (elapsed_time<delay)) 427 | { 428 | sleep(TIME_SLICE); 429 | elapsed_time+=TIME_SLICE; 430 | } 431 | if(elapsed_time<delay)return(1); else return(0); 432 | } 433 | 434 | /*++++++++++++++++++++++++++++++++++++++ 435 | 436 | Handle signals. 437 | 438 | Changes the flags: 439 | do_nrtm 440 | do_update 441 | do_whoisd 442 | 443 | More: 444 | +html+ <PRE> 445 | Author: 446 | andrei 447 | +html+ </PRE> 448 | ++++++++++++++++++++++++++++++++++++++*/ 449 | void *SV_signal_thread() { 450 | char print_buf[STR_M]; 451 | sigset_t sset; 452 | int sigReceived; 453 | int do_update; 454 | 455 | sigemptyset(&sset); 456 | sigaddset(&sset, SIGTERM); 457 | sigaddset(&sset, SIGINT); 458 | sigaddset(&sset, SIGUSR1); 459 | /* This is a bit confusing, but is needed */ 460 | /* For more information on signal handling in */ 461 | /* threads see for example "Multithreading Programming */ 462 | /* Techniques" by Shashi Prasad, ISBN 0-07-912250-7, pp. 94-101 */ 463 | pthread_sigmask(SIG_BLOCK, &sset, NULL); 464 | /* fprintf(stderr, "Signal handler installed\n");*/ 465 | 466 | for(;;) 467 | { 468 | sigwait(&sset, &sigReceived); 469 | sprintf(print_buf, "Signal received [%d]\n", sigReceived); 470 | log_print(print_buf); strcpy(print_buf, ""); 471 | /* fprintf(stderr, "Signal received [%d]\n", sigReceived); */ 472 | switch (sigReceived) 473 | { 474 | case SIGINT: 475 | /* SIGINT stops all servers */ 476 | SV_shutdown(); 477 | pthread_exit((void *)0); 478 | break; 479 | 480 | case SIGTERM: 481 | /* SIGTERM will switch the updates on and off */ 482 | do_update=CO_get_do_update(); 483 | if(do_update)do_update=0; else do_update=1; 484 | sprintf(print_buf, "%d", do_update); 485 | CO_set_const("UD.do_update", print_buf); 486 | if(do_update) 487 | sprintf(print_buf, "Starting updates\n"); 488 | else 489 | sprintf(print_buf, "Stopping updates\n"); 490 | log_print(print_buf); strcpy(print_buf, ""); 491 | /* fprintf(stderr, "Stopping updates (SIGTERM received)\n"); */ 492 | break; 493 | } 494 | } 495 | } /* SV_signal_thread() */ 496 | 497 | /* SV_concurrent_server() */ 498 | /*++++++++++++++++++++++++++++++++++++++ 499 | 500 | This is the routine that creates the main threads. 501 | 502 | int sock The socket to connect to. 503 | void * do_function The function to call for each type of service 504 | 505 | More: 506 | +html+ <PRE> 507 | Author: 508 | ottrey 509 | joao 510 | +html+ </PRE> 511 | ++++++++++++++++++++++++++++++++++++++*/ 512 | void SV_concurrent_server(int sock, void *do_function(void *)) { 513 | th_args *args; 514 | pthread_t tid; 515 | pthread_attr_t attr; 516 | 517 | dieif( wr_calloc((void **)&args,1,sizeof(th_args)) != UT_OK); 518 | 519 | args->function=(void *)do_function; 520 | args->sock=sock; 521 | 522 | /* pthread_mutex_init(&Whois_thread_count_lock,NULL); */ 523 | 524 | /* Start a new thread. */ 525 | 526 | TH_create(main_loop, (void *)args); 527 | 528 | 529 | /* Start a new thread. */ 530 | // pthread_attr_init(&attr); /* initialize attr with default attributes */ 531 | // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 532 | // pthread_create(&tid, &attr, main_thread, (void *)args); 533 | 534 | } /* TH_run() */ 535 | 536 | /* SV_do_whois() */ 537 | /*++++++++++++++++++++++++++++++++++++++ 538 | 539 | Handle whois connections. 540 | 541 | void *arg The socket to connect to. (It has to be passed in this way for this thread routine.) 542 | 543 | More: 544 | +html+ <PRE> 545 | Author: 546 | joao 547 | +html+ </PRE> 548 | ++++++++++++++++++++++++++++++++++++++*/ 549 | void *SV_do_whois(void *arg) { 550 | int sock = (int)arg; 551 | 552 | ER_dbg_va(FAC_TH, ASP_TH_NEW, 553 | "Whois: Child thread [%d]: Socket number = %d", 554 | pthread_self(), sock); 555 | 556 | /* Use a mutex to update the global whois thread counter. */ 557 | pthread_mutex_lock(&Whois_thread_count_lock); 558 | Whois_thread_count++; 559 | ER_dbg_va(FAC_TH, ASP_TH_NEW, 560 | "Whois_thread_count++=%d", Whois_thread_count); 561 | 562 | pthread_mutex_unlock(&Whois_thread_count_lock); 563 | 564 | TA_add(sock, "whois"); 565 | PW_interact(sock); 566 | close(sock); 567 | TA_delete(); 568 | 569 | /* Use a mutex to update the global whois thread counter. */ 570 | pthread_mutex_lock(&Whois_thread_count_lock); 571 | Whois_thread_count--; 572 | ER_dbg_va(FAC_TH, ASP_TH_NEW, 573 | "Whois_thread_count--=%d", Whois_thread_count); 574 | pthread_mutex_unlock(&Whois_thread_count_lock); 575 | 576 | pthread_exit((void *)0); 577 | 578 | } /* SV_do_whois() */ 579 | 580 | /* SV_do_mirror() */ 581 | /*++++++++++++++++++++++++++++++++++++++ 582 | 583 | Handle NRTM connections. 584 | 585 | void *arg The socket to connect to. (It has to be passed in this way for this thread routine.) 586 | 587 | More: 588 | +html+ <PRE> 589 | Author: 590 | joao 591 | +html+ </PRE> 592 | ++++++++++++++++++++++++++++++++++++++*/ 593 | void *SV_do_mirror(void *arg) { 594 | int sock = (int)arg; 595 | char print_buf[STR_M]; 596 | 597 | sprintf(print_buf, "NRTM: Child thread [%d]: Socket number = %d\n", pthread_self(), sock); log_print(print_buf); strcpy(print_buf, ""); 598 | 599 | /* Use a mutex to update the global mirror thread counter. */ 600 | pthread_mutex_lock(&Mirror_thread_count_lock); 601 | Mirror_thread_count++; 602 | sprintf(print_buf, "Mirror_thread_count++=%d\n", Mirror_thread_count); log_print(print_buf); strcpy(print_buf, ""); 603 | pthread_mutex_unlock(&Mirror_thread_count_lock); 604 | 605 | TA_add(sock, "mirror"); 606 | PM_interact(sock); 607 | TA_delete(); 608 | 609 | /* Use a mutex to update the global mirror thread counter. */ 610 | pthread_mutex_lock(&Mirror_thread_count_lock); 611 | Mirror_thread_count--; 612 | sprintf(print_buf, "Mirror_thread_count--=%d\n", Mirror_thread_count); log_print(print_buf); strcpy(print_buf, ""); 613 | pthread_mutex_unlock(&Mirror_thread_count_lock); 614 | 615 | pthread_exit((void *)0); 616 | 617 | } /* SV_do_mirror() */ 618 | 619 | /* SV_do_config() */ 620 | /*++++++++++++++++++++++++++++++++++++++ 621 | 622 | Handle config connections. 623 | 624 | void *arg The socket to connect to. (It has to be passed in this way for this 625 | thread routine.) 626 | 627 | More: 628 | +html+ <PRE> 629 | Author: 630 | joao 631 | +html+ </PRE> 632 | ++++++++++++++++++++++++++++++++++++++*/ 633 | void *SV_do_config(void *arg) { 634 | int sock = (int)arg; 635 | char print_buf[STR_M]; 636 | 637 | sprintf(print_buf, "Config: Child thread [%d]: Socket number = %d\n", pthread_self(), sock); log_print(print_buf); strcpy(print_buf, ""); 638 | 639 | /* 640 | printf("Hi there, there is nothing to configure yet\nBye..... :-)\n"); 641 | fflush(NULL); 642 | 643 | SK_close(sock); 644 | */ 645 | TA_add(sock, "config"); 646 | PC_interact(sock); 647 | TA_delete(); 648 | 649 | pthread_exit((void *)0); 650 | 651 | } /* SV_do_config() */ 652 | 653 | 654 | /*++++++++++++++++++++++++++++++++++++++ 655 | 656 | This is the routine that creates a watchdog thread. 657 | 658 | The watchdog will cancel (pthread_cancel()) the calling thread in case the 659 | socket is closed by the client (its read-half is closed). The calling 660 | thread should make necessaruy preparations when calling the watchdog: 661 | 662 | - the socket should be connected 663 | - cancellation points and cleanup routines should be defined 664 | 665 | In case the connection is closed by the calling thread itself, the 666 | watchdog just exits and no action against the calling thread is performed. 667 | 668 | wd_args - a pointer to wd_args_t structure containing 669 | data about socket and thread ID 670 | 671 | More: 672 | +html+ <PRE> 673 | Author: 674 | ottrey 675 | joao 676 | andrei 677 | +html+ </PRE> 678 | ++++++++++++++++++++++++++++++++++++++*/ 679 | 680 | void SV_watchdog(wd_args_t *wd_args) { 681 | pthread_t tid; 682 | pthread_attr_t attr; 683 | 684 | /* Start a new thread. */ 685 | TH_create((void *(*)(void *))do_watchdog, (void *)wd_args); 686 | 687 | // pthread_attr_init(&attr); /* initialize attr with default attributes */ 688 | // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 689 | // pthread_create(&tid, &attr, (void *(*)(void *))do_watchdog, (void *)wd_args); 690 | 691 | } 692 | 693 | 694 | /*++++++++++++++++++++++++++++++++++++++ 695 | 696 | The watchdog thread itself 697 | 698 | The watchdog thread makes select() on the connected socket waiting until it 699 | becomes readable. If this happens as a result of some input, it'll simply 700 | dump it. Otherwise, this indicates that the client has closed the 701 | connection. In this case watchdog will cancel (pthread_cancel()) the whois 702 | thread (which in its turn will kill (mysql_kill()) mysql thread as part of 703 | its cleanup routine). 704 | 705 | More: 706 | +html+ <PRE> 707 | Author: 708 | andrei 709 | +html+ </PRE> 710 | ++++++++++++++++++++++++++++++++++++++*/ 711 | static void do_watchdog(void *arg) { 712 | wd_args_t *wd_args = (wd_args_t *)arg; 713 | int socket; 714 | pthread_t tid; 715 | int nready; 716 | int n; 717 | fd_set rset; 718 | char buff[STR_S]; 719 | 720 | socket = wd_args->connected_socket; 721 | tid = wd_args->tid; 722 | 723 | 724 | FD_ZERO(&rset); 725 | FD_SET(socket, &rset); 726 | 727 | while ((nready=select(socket+1, &rset, NULL, NULL, NULL))!=-1) { 728 | 729 | /* There was some input or client half of connection was closed */ 730 | /* Check for the latter */ 731 | if (( n=read(socket, buff, sizeof(buff))) == 0) { 732 | /* Connection was closed by client */ 733 | /* Now send a cancellation request to the whois thread. */ 734 | /* mysql thread will be terminated by thread cleanup routine */ 735 | 736 | /* The only possible error is ESRCH, so we do not care about */ 737 | pthread_cancel(tid); 738 | 739 | /* Exit the watchdog thread, passing NULL as we don't expect pthread_join() */ 740 | pthread_exit(NULL); 741 | } 742 | 743 | /* Otherwise dump input and continue */ 744 | } 745 | 746 | /* the only reason that we are here is that the socket has been */ 747 | /* closed by the whois thread and not valid. Just exit the watchdog, */ 748 | /* passing NULL as we don't expect pthread_join() */ 749 | pthread_exit(NULL); 750 | 751 | }