Source File modules/sv/server.c

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