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