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