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