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