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