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