Source File modules/sv/server.c

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