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