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) {
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){
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) {
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() {
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() {
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) {
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() {
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 *)) {
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) {
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) {
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) {
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) {
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) {
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 | }