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