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