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

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