modules/sv/server.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. log_print
  2. radix_init
  3. main_loop
  4. SV_start
  5. SV_shutdown
  6. SV_sleep
  7. SV_signal_thread
  8. SV_concurrent_server
  9. SV_do_whois
  10. SV_do_mirror
  11. SV_do_config
  12. SV_watchdog
  13. do_watchdog

   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) {
     /* [<][>][^][v][top][bottom][index][help] */
 121 
 122   printf(arg);
 123 
 124 } /* log_print() */
 125 
 126 
 127 void radix_init(void){
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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() {
     /* [<][>][^][v][top][bottom][index][help] */
 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() {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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() {
     /* [<][>][^][v][top][bottom][index][help] */
 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 *)) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) { 
     /* [<][>][^][v][top][bottom][index][help] */
 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) { 
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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 }  

/* [<][>][^][v][top][bottom][index][help] */