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