## 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] */