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  | }