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