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

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