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.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) {
/* [<][>][^][v][top][bottom][index][help] */
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){
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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() {
/* [<][>][^][v][top][bottom][index][help] */
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() {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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() {
/* [<][>][^][v][top][bottom][index][help] */
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 *)) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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 }