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

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