modules/sv/server.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- log_print
- counter_add
- counter_state
- counter_wait
- radix_init
- SV_sleep
- SV_signal_thread
- SV_do_child
- main_loop
- SV_concurrent_server
- SV_start
- SV_shutdown
1 /***************************************
2 $Revision: 1.54 $
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 heavy rewrite by Andrei Robachevsky, Marek Bukowy
10
11 +html+ <DL COMPACT>
12 +html+ <DT>Online References:
13 +html+ <DD><UL>
14 +html+ <LI>Based on <A HREF="http://iii.ripe.net/dbase/coding/new.code/progress/ottrey/code/java/src/DBServer.java">DBServer.java</A>
15 +html+ </UL>
16 +html+ </DL>
17
18 ******************/ /******************
19 Modification History:
20 ottrey (02/03/1999) Created.
21 ottrey (08/03/1999) Modified.
22 joao (22/06/1999) Modified.
23 ******************/ /******************
24 Copyright (c) 1999 RIPE NCC
25
26 All Rights Reserved
27
28 Permission to use, copy, modify, and distribute this software and its
29 documentation for any purpose and without fee is hereby granted,
30 provided that the above copyright notice appear in all copies and that
31 both that copyright notice and this permission notice appear in
32 supporting documentation, and that the name of the author not be
33 used in advertising or publicity pertaining to distribution of the
34 software without specific, written prior permission.
35
36 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
37 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
38 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
39 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
40 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
41 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
42 ***************************************/
43
44 #include <ctype.h>
45
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <sys/wait.h>
49 #include <sys/socket.h>
50 #include <netinet/in.h>
51
52 #include "thread.h"
53 #include "rxroutines.h"
54 #include "sk.h"
55 /*
56 #include "objects.h"
57 */
58 #include "constants.h"
59
60 #include "ca_configFns.h"
61 #include "ca_dictionary.h"
62 #include "ca_macros.h"
63 #include "ca_srcAttribs.h"
64
65 #include "mysql_driver.h"
66 #include "access_control.h"
67 #include "ud.h"
68 #include "ud_tr.h"
69 #include "server.h"
70
71 #include "rp.h"
72 #include "memwrap.h"
73
74 #include "ta.h"
75
76 #include "protocol_whois.h"
77 #include "protocol_mirror.h"
78 #include "protocol_config.h"
79
80 /*+ String sizes +*/
81 #define STR_S 63
82 #define STR_M 255
83 #define STR_L 1023
84 #define STR_XL 4095
85 #define STR_XXL 16383
86
87 /* Storage for descriptors of the read side of the pipe */
88 int sv_lockfd[MAX_LOCKS];
89
90 /* Listening sockets */
91 int SV_whois_sock;
92 int SV_config_sock;
93 int SV_mirror_sock;
94
95 /* each updatable source has its own update thread and its own socket */
96 #define MAX_SOURCES 100
97 int SV_update_sock[MAX_SOURCES];
98
99
100 /*+ Server starting time +*/
101 time_t SV_starttime;
102
103 /* Logging results */
104 static void log_print(const char *arg) {
/* [<][>][^][v][top][bottom][index][help] */
105
106 printf(arg);
107
108 } /* log_print() */
109
110
111 /* counters - by marek */
112 typedef struct {
113 int count;
114 pthread_mutex_t lock; /*+ Mutex lock.Used for synchronizing changes.+*/
115 pthread_cond_t cond; /*+ condition variable +*/
116 } svr_counter_t;
117
118
119 /* structure passed to every running server */
120 typedef struct {
121 void (*function)(int);
122 int conn_sock;
123 int accept_sock;
124 int limit; /* limit for the number of concurrent connections */
125 svr_counter_t *counter; /* number of active clients */
126 char *name;
127 } svr_args;
128
129
130 /*++++++++++++++++++++++++++++++++++++++
131 function to operate on the counter structures -
132 takes the increment (can be negative), changes the value
133 using the locks and everything,
134
135 int
136 counter_add returns the new value.
137
138 svr_counter_t *cst counter structure
139
140 int incval increment value (can be negative)
141
142 Author:
143 marek
144 ++++++++++++++++++++++++++++++++++++++*/
145 static
146 int
147 counter_add( svr_counter_t *cst, int incval )
/* [<][>][^][v][top][bottom][index][help] */
148 {
149 int newval;
150
151 /* add under mutex */
152 pthread_mutex_lock( &(cst->lock) );
153 cst->count += incval;
154 newval = cst->count;
155 pthread_mutex_unlock(&(cst->lock) );
156
157 /* now - signal the change of value to the waiting thread */
158 pthread_cond_signal( &(cst->cond) );
159
160 return newval;
161 }
162
163
164 /*++++++++++++++++++++++++++++++++++++++
165
166 int
167 counter_state returns the current value of a counter
168
169 svr_counter_t *cst counter
170
171 Author:
172 marek
173
174 ++++++++++++++++++++++++++++++++++++++*/
175 static
176 int
177 counter_state( svr_counter_t *cst )
/* [<][>][^][v][top][bottom][index][help] */
178 {
179 return counter_add( cst, 0 );
180 }
181
182
183 /*++++++++++++++++++++++++++++++++++++++
184 waits until the counter is in the range [0-limit].
185 unless the limit is 0, in which case the check is disabled.
186
187 int counter_wait returns the new value of the counter after wait
188
189 svr_counter_t *cst counter
190
191 int limit limit / range, or 0 to disable the check
192
193 Author:
194 marek
195 ++++++++++++++++++++++++++++++++++++++*/
196 static
197 int counter_wait(svr_counter_t *cst, int limit )
/* [<][>][^][v][top][bottom][index][help] */
198 {
199 int newval;
200
201 pthread_mutex_lock( &(cst->lock) );
202
203 if( limit != 0 ) {
204 while( cst->count >= limit ) {
205 pthread_cond_wait( &(cst->cond), &(cst->lock));
206 }
207 }
208
209 newval = cst->count;
210 pthread_mutex_unlock(&(cst->lock) );
211
212 return newval;
213 }
214
215 /*++++++++++++++++++++++++++++++++++++++
216
217 Loading the radix tree. Started as a separate thread.
218
219 Author:
220 marek
221 ++++++++++++++++++++++++++++++++++++++*/
222 void radix_init(void){
/* [<][>][^][v][top][bottom][index][help] */
223 int i;
224 ca_dbSource_t *source_hdl;
225
226 wr_log_set(0);
227 /* this needs to be done in two loops,
228 because the trees must be created asap (first loop)
229 and then locked until they are populated in the second loop
230 */
231
232 TH_init_read_write_lockw(&rx_forest_rwlock);
233
234 for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){
235 dieif( RP_init_trees( source_hdl ) != RP_OK );
236 }
237
238 for(i=0; (source_hdl = ca_get_SourceHandleByPosition(i))!=NULL ; i++){
239 dieif( RP_sql_load_reg( source_hdl ) != RP_OK );
240 }
241
242 wr_log_set(0); /* switch on/off the memory leak detector */
243 /* pthread_mutex_unlock( &radix_initializing_lock ); */
244
245 pthread_exit((void *)0);
246 }
247
248
249 /************************************************************
250 * int SV_sleep() *
251 * *
252 * sleeps till shutdown request comes *
253 * but at most <delay> seconds *
254 * *
255 * Returns: *
256 * 1 - timeout *
257 * 0 - shutdown *
258 * *
259 ************************************************************/
260
261 int SV_sleep(int delay)
/* [<][>][^][v][top][bottom][index][help] */
262 {
263 int do_server;
264 int elapsed_time=0;
265
266 while((do_server=CO_get_do_server()) && (elapsed_time<delay))
267 {
268 sleep(TIME_SLICE);
269 elapsed_time+=TIME_SLICE;
270 }
271 if(elapsed_time<delay)return(1); else return(0);
272 }
273
274 /*++++++++++++++++++++++++++++++++++++++
275
276 Handle signals.
277
278 Changes the flags:
279 do_nrtm
280 do_update
281 do_whoisd
282
283 More:
284 +html+ <PRE>
285 Author:
286 andrei
287 +html+ </PRE>
288 ++++++++++++++++++++++++++++++++++++++*/
289 void *SV_signal_thread() {
/* [<][>][^][v][top][bottom][index][help] */
290 char print_buf[STR_M];
291 sigset_t sset;
292 int sigReceived;
293 int do_update;
294
295 sigemptyset(&sset);
296 /* SIGTERM and SIGINT are used to shutdown the server */
297 /* SIGUSR1 is used to pause/resume updates - rarely used as we have PC command */
298 sigaddset(&sset, SIGTERM);
299 sigaddset(&sset, SIGINT);
300 sigaddset(&sset, SIGUSR1);
301 /* This is a bit confusing, but is needed */
302 /* For more information on signal handling in */
303 /* threads see for example "Multithreading Programming */
304 /* Techniques" by Shashi Prasad, ISBN 0-07-912250-7, pp. 94-101 */
305
306 /* XXX If one needs to handle more signals, don't forget to */
307 /* block them in other threads in install_signal_handler() in whois_rip.c */
308 pthread_sigmask(SIG_BLOCK, &sset, NULL);
309
310 for(;;)
311 {
312 #ifdef HAVE_THR_SIGWAIT
313 _thr_sigwait(&sset, &sigReceived);
314 #else
315 sigwait(&sset, &sigReceived);
316 #endif
317 sprintf(print_buf, "Signal received [%d]\n", sigReceived);
318 log_print(print_buf); strcpy(print_buf, "");
319 /* fprintf(stderr, "Signal received [%d]\n", sigReceived); */
320 switch (sigReceived)
321 {
322 case SIGINT:
323 case SIGTERM:
324 /* SIGINT and SIGTERM stop all servers */
325 SV_shutdown();
326 pthread_exit((void *)0);
327 break;
328
329 case SIGUSR1:
330 /* SIGUSR1 will switch the updates on and off */
331 do_update=CO_get_do_update();
332 if(do_update)do_update=0; else do_update=1;
333 sprintf(print_buf, "%d", do_update);
334 CO_set_const("UD.do_update", print_buf);
335 if(do_update)
336 sprintf(print_buf, "Starting updates\n");
337 else
338 sprintf(print_buf, "Stopping updates\n");
339 log_print(print_buf); strcpy(print_buf, "");
340 /* fprintf(stderr, "Stopping updates (SIGTERM received)\n"); */
341 break;
342 }
343 }
344 } /* SV_signal_thread() */
345
346
347 /* SV_do_child() */
348 /*++++++++++++++++++++++++++++++++++++++
349
350 Handle whois/config/mirror connections. Takes a pointer to the
351 service description structure, containing a connected socket, limit
352 of active threads, pointer to the counter of them. Does not stop to
353 obey the limits, assumes this to be checked and assumes that it is
354 already counted. Decrements the counter on exit.
355
356 Precondition: the counter must be incremented before this function is called.
357
358 void *SV_do_child Actually, does not return anything useful. Just NULL.
359
360 void *varg service description structure.
361
362 Author:
363 marek
364 ++++++++++++++++++++++++++++++++++++++*/
365 void *SV_do_child(void *varg)
/* [<][>][^][v][top][bottom][index][help] */
366 {
367 svr_args *args = (svr_args *) varg;
368 int sock = args->conn_sock;
369 int curclients;
370
371 ER_dbg_va(FAC_TH, ASP_TH_NEW,
372 ": Child thread [%d]: Socket number = %d",
373 args->name, pthread_self(), sock);
374
375 curclients = counter_state( args->counter ); /* already added */
376 ER_dbg_va(FAC_TH, ASP_TH_NEW,
377 "%s threads++ = %d", args->name, curclients);
378
379 TA_add(sock, args->name);
380
381 args->function(sock);
382
383 /* TA_delete must come first - otherwise the server would crash
384 when trying to report address of a closed socket */
385 TA_delete();
386 close(sock);
387
388 /* update the global thread counter. */
389 curclients = counter_add( args->counter, -1);
390 ER_dbg_va(FAC_TH, ASP_TH_NEW,
391 "%s threads-- = %d", args->name, curclients);
392
393 free(args);
394
395 return NULL; /* exit the thread */
396 } /* SV_do_child */
397
398
399 /* main_loop() */
400 /*++++++++++++++++++++++++++++++++++++++
401
402 Waits for an incoming connection on the and spawns a new thread to
403 handle it. Takes a pointer to the service description structure
404 containing the number of the listening socket, limit of active
405 threads, pointer to the counter of them, and the function to call
406 with a connected socket. Increments the counter before starting
407 a client thread to run SV_do_child().
408
409 void *arg pointer to the service description structure.
410
411 More:
412 +html+ <PRE>
413 Author:
414 ottrey
415 joao
416 andrei (do_server)
417 marek (rewritten/simplified/added limits)
418 +html+ </PRE>
419 ++++++++++++++++++++++++++++++++++++++*/
420 static void *main_loop(void *arg) {
/* [<][>][^][v][top][bottom][index][help] */
421 svr_args *argset = (svr_args *)arg;
422 svr_args *argcopy;
423 char loopname[32];
424 int children;
425 char chnum[16];
426
427 snprintf(loopname, 32, "s-%s", argset->name);
428
429 TA_add(0, loopname);
430
431 while( CO_get_do_server() != 0 ) {
432 /* check the number of clients, do not proceed until it's below limit */
433 children = counter_wait( argset->counter, argset->limit );
434 snprintf(chnum, 16, "%d", children);
435 TA_setactivity(chnum); /* display the current number of children */
436
437 /* wait for new connections */
438 argset->conn_sock = SK_accept_connection(argset->accept_sock);
439 if(argset->conn_sock == -1) {
440 break;
441 }
442
443 ER_dbg_va(FAC_TH, ASP_TH_NEW, "%s: starting a new child thread",
444 loopname);
445 TA_increment();
446 /* incrementing argset->counter here - to avoid race condition and
447 ensure a _more_correct_ value of current clients also for unlimited
448 or infrequent connections. Does not really matter otherwise.
449
450 NOTE: this architecture implies that higher values can be
451 displayed for infrequent threads, because there's no way
452 to change it when threads are exiting while this thread is
453 blocked in call to accept(). If this call was in the child thread,
454 the number would be an underestimation instead. I prefer over-e.
455 */
456 counter_add( argset->counter, 1);
457
458 /* Start a new thread. will decrement counter when exiting */
459
460 /* now. There's a race condition - argset must be copied in SV_do_child
461 and can be reused here only afterwards. To avoid it, we make a copy
462 and expect SV_do_child to free it after use.
463 Caveat: the counter remains where it was, we just copy the pointer.
464 */
465 argcopy = malloc( sizeof(svr_args) );
466 memcpy( argcopy, argset, sizeof(svr_args) );
467 TH_create( SV_do_child, (void *)argcopy );
468 }
469
470 TA_delete();
471 ER_dbg_va(FAC_TH, ASP_TH_NEW, "Exiting from the main loop");
472
473 pthread_exit((void *)0);
474 return NULL; /* stupid compilers. */
475 } /* main_loop() */
476
477 /* SV_concurrent_server() */
478 /*++++++++++++++++++++++++++++++++++++++
479
480 This is the routine that creates the main threads.
481
482 int sock The socket to connect to.
483
484 int limit Limit of active clients (0 == no limit)
485
486 void * do_function The function to call for each type of service
487
488 More:
489 +html+ <PRE>
490 Author:
491 ottrey
492 joao
493 marek
494 +html+ </PRE>
495 ++++++++++++++++++++++++++++++++++++++*/
496 static
497 void SV_concurrent_server(int sock, int limit, char *name,
/* [<][>][^][v][top][bottom][index][help] */
498 void do_function(int))
499 {
500 svr_args *args;
501
502 dieif( wr_calloc((void **)&args, 1, sizeof(svr_args)) != UT_OK);
503
504 args->accept_sock=sock;
505 args->limit=limit;
506 args->name=name;
507 args->function=do_function;
508
509 dieif( wr_calloc((void **)&(args->counter),1,sizeof(svr_counter_t)) != UT_OK);
510 pthread_mutex_init( &(args->counter->lock), NULL );
511 pthread_cond_init( &(args->counter->cond), NULL );
512 args->counter->count = 0;
513
514
515 /* Start a new thread. */
516
517 TH_create(main_loop, (void *)args);
518
519 } /* SV_concurrent_server() */
520
521 /* SV_start() */
522 /*++++++++++++++++++++++++++++++++++++++
523
524 Start the server.
525
526 More:
527 +html+ <PRE>
528 Authors:
529 ottrey
530 joao
531 +html+ </PRE>
532 +html+ Starts up the server.
533 +html+ <OL>
534 +html+ <LI> Create sockets on the necessary ports (whois, config and mirror)
535 +html+ <LI> Start new threads for each service.
536 +html+ </OL>
537 +html+ <A HREF=".DBrc">.properties</A>
538
539 ++++++++++++++++++++++++++++++++++++++*/
540 void SV_start() {
/* [<][>][^][v][top][bottom][index][help] */
541 int whois_port = -1;
542 int config_port = -1;
543 int mirror_port = -1;
544 int update_port = -1;
545 int update_mode = 0;
546 int fdes[2];
547 struct timeval tval;
548 char starttime[128];
549 ca_dbSource_t *source_hdl;
550 char *source_name;
551 int source;
552 char *db_host, *db_name, *db_user, *db_passwd;
553 int db_port;
554 SQ_connection_t *db_connection;
555
556 /* Store the starting time */
557 gettimeofday(&tval, NULL);
558 SV_starttime = tval.tv_sec;/* seconds since Jan. 1, 1970 */
559
560 /* Log the starting time */
561 ctime_r(&SV_starttime, starttime);
562 ER_inf_va(FAC_SV, 0xFFFFFF, "Server is started %s", starttime);
563
564
565
566
567 /* Create interrupt pipe */
568 /* Writing to this pipe will cause sleeping threads */
569 /* to wake up */
570 fprintf(stderr, "Creating an interrupt pipe\n");
571 if(pipe(fdes)==-1) {
572 printf("Cannot open interrupt pipe\n");
573 exit(-1);
574 }
575 /* Save the pipe descriptors in sv_lock array */
576 sv_lockfd[WLOCK_SHTDOWN]=fdes[0];
577 sv_lockfd[LOCK_SHTDOWN]=fdes[1];
578
579 /* Initialise modules */
580 SK_init();
581
582 /* Initialise the access control list. */
583 AC_build();
584 AC_acc_load();
585 /* explicitly start the decay thread */
586 TH_create((void *(*)(void *))AC_decay, NULL);
587
588
589
590 /* Get port information for each service */
591 whois_port = ca_get_svwhois_port;
592 ER_inf_va(FAC_SV, ASP_SV_PORT, "whois port is %d", whois_port);
593 /* ER_dbg_va(FAC_SV, ASP_SV_PORT, "whois port is %d", whois_port); */
594
595 config_port = ca_get_svconfig_port;
596 ER_inf_va(FAC_SV, ASP_SV_PORT, "config port is %d", config_port);
597 /* ER_dbg_va(FAC_SV, ASP_SV_PORT, "config port is %d", config_port); */
598
599
600 mirror_port = ca_get_svmirror_port;
601 ER_inf_va(FAC_SV, ASP_SV_PORT, "mirror port is %d", mirror_port);
602 /* ER_dbg_va(FAC_SV, ASP_SV_PORT, "mirror port is %d", mirror_port);*/
603
604
605 /* 6. Create a socket on the necessary ports/addresses and bind to them. */
606 /* whois socket */
607 SV_whois_sock = SK_getsock(SOCK_STREAM, whois_port, 128, INADDR_ANY);
608 /* Currently binds to INADDR_ANY. Will need to get specific address */
609 /* SV_whois_sock = SK_getsock(SOCK_STREAM,whois_port,whois_addr); */
610 /* config interface socket */
611 SV_config_sock = SK_getsock(SOCK_STREAM, config_port, 5, INADDR_ANY);
612 /* nrt socket */
613 SV_mirror_sock = SK_getsock(SOCK_STREAM,mirror_port, 5, INADDR_ANY);
614
615 /* Check every Database and create sockets */
616 /* we need first to create and bind all of them */
617 /* so that in case of failure we do not start any */
618 /* update thread */
619 fprintf(stderr, "Check the DB\n");
620 for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){
621 /* check for crash and recover if needed */
622 /* make a connection to a database */
623 db_host = ca_get_srcdbmachine(source_hdl);
624 db_port = ca_get_srcdbport(source_hdl);
625 db_name = ca_get_srcdbname(source_hdl);
626 db_user = ca_get_srcdbuser(source_hdl);
627 db_passwd = ca_get_srcdbpassword(source_hdl);
628 db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd);
629 /* now check TR record */
630 TR_recover(db_connection);
631 /* free resources */
632 SQ_close_connection(db_connection);
633 free(db_host);
634 free(db_name);
635 free(db_user);
636 free(db_passwd);
637
638 update_mode = ca_get_srcmode(source_hdl);
639 if(IS_UPDATE(update_mode)) {
640 /* update_port = SK_atoport(CO_get_update_port(), "tcp"); */
641 update_port = ca_get_srcupdateport(source_hdl);
642 printf("XXX htons(update_port)=%d\n", update_port);
643 /* XXX ask AMRM to change the name of the function */
644
645 SV_update_sock[source] = SK_getsock(SOCK_STREAM, update_port, 5, INADDR_ANY);
646 }
647 else SV_update_sock[source] = 0;
648 }
649 SV_update_sock[source+1]=-1; /* end of socket array */
650
651 /* Initialise the radix tree (separate thread[s])
652 already can allow socket connections, because the trees will
653 be created locked, and will be unlocked when loaded */
654
655 /* pthread_mutex_lock( &radix_initializing_lock ); */
656 TH_create((void *(*)(void *))radix_init, NULL);
657 /* pthread_mutex_lock( &radix_initializing_lock ); */
658
659
660 /* Now.... accept() calls block until they get a connection
661 so to listen on more than one port we need more
662 than one thread */
663
664 /* Create master thread for whois threads */
665 SV_concurrent_server(SV_whois_sock, 64, "whois", PW_interact);
666 /* Create master thread for config threads */
667 SV_concurrent_server(SV_config_sock, 0, "config", PC_interact);
668 /* Create master thread for mirror threads */
669 SV_concurrent_server(SV_mirror_sock, 0, "mirror", PM_interact);
670
671 /* Walk through the sources and */
672 /* run update thread for every source with CANUPD == 'y' */
673
674 for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){
675 update_mode = ca_get_srcmode(source_hdl);
676 source_name= ca_get_srcname(source_hdl);
677
678 if(IS_UPDATE(update_mode)) {
679 /* run RIPupdate thread */
680 fprintf(stderr,"Source [%s] Mode UPDATE [port=%d]\n", source_name, ca_get_srcupdateport(source_hdl));
681 ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode UPDATE [port=%d]", source_name, ca_get_srcupdateport(source_hdl));
682 TH_create((void *(*)(void *))UD_do_updates, (void *)source);
683 }
684 else if(IS_NRTM_CLNT(update_mode)){
685 /* start NRTM client */
686 fprintf(stderr,"Source [%s] Mode NRTM\n", source_name);
687 ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode NRTM", source_name);
688 TH_create((void *(*)(void *))UD_do_nrtm, (void *)source);
689 }
690 else {
691 fprintf(stderr,"Source [%s] Mode STATIC\n", source_name);
692 ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode STATIC", source_name);
693 }
694 free(source_name); /* because ca_* functions return copies */
695 }
696
697 pthread_exit(NULL);
698
699 } /* SV_start() */
700
701 /* SV_shutdown() */
702 /*++++++++++++++++++++++++++++++++++++++
703
704 Shutdown the server.
705
706 More:
707 +html+ <PRE>
708 Authors:
709 andrei
710 +html+ </PRE>
711 +html+ Stops the server.
712 +html+ <OL>
713 +html+ <LI> Close listening sockets (whois, config, mirror and updates)
714 +html+ <LI> Stop all threads by triggering do_server variable.
715 +html+ </OL>
716 +html+ <A HREF=".DBrc">.properties</A>
717
718 ++++++++++++++++++++++++++++++++++++++*/
719 void SV_shutdown() {
/* [<][>][^][v][top][bottom][index][help] */
720 char print_buf[STR_M];
721 int source;
722 time_t shutdowntime;
723 struct timeval tval;
724 char shuttime[100];
725
726 sprintf(print_buf, "%d", 0);
727 /* Stop updates */
728 CO_set_const("UD.do_update", print_buf);
729 /* Stop all servers */
730 CO_set_const("SV.do_server", print_buf);
731 sprintf(print_buf, "Stopping all servers\n");
732 fprintf(stderr, print_buf);
733 /*log_print(print_buf); */
734 strcpy(print_buf, "");
735
736 /* Store the shutdown time */
737 gettimeofday(&tval, NULL);
738 shutdowntime = tval.tv_sec;/* seconds since Jan. 1, 1970 */
739
740 /* Log the starting time */
741 ctime_r(&shutdowntime, shuttime);
742 ER_inf_va(FAC_SV, 0xFFFFFF, "Server shutdown %s", shuttime);
743
744
745
746 /* Wake up all sleeping threads */
747 fprintf(stderr, "Going to wake sleeping threads up\n");
748 write(sv_lockfd[WLOCK_SHTDOWN], " ", 1);
749
750 /* CLose all listening sockets, so accept call exits */
751 close(SV_whois_sock);
752 close(SV_config_sock);
753 close(SV_mirror_sock);
754 for (source=0; SV_update_sock[source]!=-1; source++)
755 if(SV_update_sock[source]!=0)close(SV_update_sock[source]);
756
757
758 } /* SV_shutdown() */