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