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.58 $
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 /* 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
97
98 /*+ Server starting time +*/
99 time_t SV_starttime;
100 /* the filename where we store the PID of the server */
101 char *SV_pidfile;
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 * 0 - timeout *
257 * 1 - 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(do_server)return(0); else return(1);
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 int SV_start(char *pidfile) {
/* [<][>][^][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 pid_fd;
547 int nwrite;
548 struct timeval tval;
549 char starttime[128];
550 char server_pid[16];
551 ca_dbSource_t *source_hdl;
552 char *source_name;
553 int source;
554 char *db_host, *db_name, *db_user, *db_passwd;
555 int db_port;
556 SQ_connection_t *db_connection;
557
558 /* Store the starting time */
559 gettimeofday(&tval, NULL);
560 SV_starttime = tval.tv_sec;/* seconds since Jan. 1, 1970 */
561
562 /* Log the starting time */
563 ctime_r(&SV_starttime, starttime);
564 ER_inf_va(FAC_SV, 0xFFFFFF, "Server is started %s", starttime);
565
566 /* Store the PID of the process */
567 SV_pidfile = pidfile;
568 /* create the file read-writable by the process owner */
569 if((pid_fd=open(SV_pidfile, O_CREAT | O_TRUNC | O_WRONLY, 0600))==-1) {
570 ER_perror(FAC_SV, 1, "cannot open pid file %s", SV_pidfile);
571 return(-1);
572 }
573 sprintf(server_pid, "%d", (int)getpid());
574 nwrite=write(pid_fd, server_pid, strlen(server_pid) );
575 close(pid_fd);
576 if(nwrite != strlen(server_pid)) {
577 ER_perror(FAC_SV, 1, "cannot write to pid file %s", SV_pidfile);
578 return(-1);
579 }
580
581
582 /* Initialise modules */
583 SK_init();
584 PW_init();
585
586 /* Initialise the access control list. */
587 AC_build();
588 AC_acc_load();
589 /* explicitly start the decay thread */
590 TH_create((void *(*)(void *))AC_decay, NULL);
591
592
593
594 /* Get port information for each service */
595 whois_port = ca_get_svwhois_port;
596 ER_inf_va(FAC_SV, ASP_SV_PORT, "whois port is %d", whois_port);
597 /* ER_dbg_va(FAC_SV, ASP_SV_PORT, "whois port is %d", whois_port); */
598
599 config_port = ca_get_svconfig_port;
600 ER_inf_va(FAC_SV, ASP_SV_PORT, "config port is %d", config_port);
601 /* ER_dbg_va(FAC_SV, ASP_SV_PORT, "config port is %d", config_port); */
602
603
604 mirror_port = ca_get_svmirror_port;
605 ER_inf_va(FAC_SV, ASP_SV_PORT, "mirror port is %d", mirror_port);
606 /* ER_dbg_va(FAC_SV, ASP_SV_PORT, "mirror port is %d", mirror_port);*/
607
608
609 /* 6. Create a socket on the necessary ports/addresses and bind to them. */
610 /* whois socket */
611 SV_whois_sock = SK_getsock(SOCK_STREAM, whois_port, 128, INADDR_ANY);
612 /* Currently binds to INADDR_ANY. Will need to get specific address */
613 /* SV_whois_sock = SK_getsock(SOCK_STREAM,whois_port,whois_addr); */
614 /* config interface socket */
615 SV_config_sock = SK_getsock(SOCK_STREAM, config_port, 5, INADDR_ANY);
616 /* nrt socket */
617 SV_mirror_sock = SK_getsock(SOCK_STREAM,mirror_port, 128, INADDR_ANY);
618
619 /* Check every Database and create sockets */
620 /* we need first to create and bind all of them */
621 /* so that in case of failure we do not start any */
622 /* update thread */
623 fprintf(stderr, "Check the DB\n");
624 for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){
625 /* check for crash and recover if needed */
626 /* make a connection to a database */
627 db_host = ca_get_srcdbmachine(source_hdl);
628 db_port = ca_get_srcdbport(source_hdl);
629 db_name = ca_get_srcdbname(source_hdl);
630 db_user = ca_get_srcdbuser(source_hdl);
631 db_passwd = ca_get_srcdbpassword(source_hdl);
632 db_connection=SQ_get_connection(db_host, db_port, db_name, db_user, db_passwd);
633 /* now check TR record */
634 TR_recover(db_connection);
635 /* free resources */
636 SQ_close_connection(db_connection);
637 free(db_host);
638 free(db_name);
639 free(db_user);
640 free(db_passwd);
641
642 update_mode = ca_get_srcmode(source_hdl);
643 if(IS_UPDATE(update_mode)) {
644 /* update_port = SK_atoport(CO_get_update_port(), "tcp"); */
645 update_port = ca_get_srcupdateport(source_hdl);
646 printf("XXX htons(update_port)=%d\n", update_port);
647 /* XXX ask AMRM to change the name of the function */
648
649 SV_update_sock[source] = SK_getsock(SOCK_STREAM, update_port, 128, INADDR_ANY);
650 }
651 else SV_update_sock[source] = 0;
652 }
653 SV_update_sock[source+1]=-1; /* end of socket array */
654
655 /* Initialise the radix tree (separate thread[s])
656 already can allow socket connections, because the trees will
657 be created locked, and will be unlocked when loaded */
658
659 /* pthread_mutex_lock( &radix_initializing_lock ); */
660 TH_create((void *(*)(void *))radix_init, NULL);
661 /* pthread_mutex_lock( &radix_initializing_lock ); */
662
663
664 /* Now.... accept() calls block until they get a connection
665 so to listen on more than one port we need more
666 than one thread */
667
668 /* Create master thread for whois threads */
669 SV_concurrent_server(SV_whois_sock, 64, "whois", PW_interact);
670 /* Create master thread for config threads */
671 SV_concurrent_server(SV_config_sock, 0, "config", PC_interact);
672 /* Create master thread for mirror threads */
673 SV_concurrent_server(SV_mirror_sock, 0, "mirror", PM_interact);
674
675 /* Walk through the sources and */
676 /* run update thread for every source with CANUPD == 'y' */
677
678 for(source=0; (source_hdl = ca_get_SourceHandleByPosition(source))!=NULL ; source++){
679 update_mode = ca_get_srcmode(source_hdl);
680 source_name= ca_get_srcname(source_hdl);
681
682 if(IS_UPDATE(update_mode)) {
683 /* run RIPupdate thread */
684 fprintf(stderr,"Source [%s] Mode UPDATE [port=%d]\n", source_name, ca_get_srcupdateport(source_hdl));
685 ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode UPDATE [port=%d]", source_name, ca_get_srcupdateport(source_hdl));
686 TH_create((void *(*)(void *))UD_do_updates, (void *)source);
687 }
688 else if(IS_NRTM_CLNT(update_mode)){
689 /* start NRTM client */
690 fprintf(stderr,"Source [%s] Mode NRTM\n", source_name);
691 ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode NRTM", source_name);
692 TH_create((void *(*)(void *))UD_do_nrtm, (void *)source);
693 }
694 else {
695 fprintf(stderr,"Source [%s] Mode STATIC\n", source_name);
696 ER_inf_va(FAC_SV, 0xFFFFFF, "Source [%s] Mode STATIC", source_name);
697 }
698 free(source_name); /* because ca_* functions return copies */
699 }
700 /* terminate the thread */
701 /* XXX not return becase then we terminate the whole process */
702 pthread_exit(NULL);
703 return(1); /* we will never reach this point */
704 } /* SV_start() */
705
706 /* SV_shutdown() */
707 /*++++++++++++++++++++++++++++++++++++++
708
709 Shutdown the server.
710
711 More:
712 +html+ <PRE>
713 Authors:
714 andrei
715 +html+ </PRE>
716 +html+ Stops the server.
717 +html+ <OL>
718 +html+ <LI> Close listening sockets (whois, config, mirror and updates)
719 +html+ <LI> Stop all threads by triggering do_server variable.
720 +html+ </OL>
721 +html+ <A HREF=".DBrc">.properties</A>
722
723 ++++++++++++++++++++++++++++++++++++++*/
724 void SV_shutdown() {
/* [<][>][^][v][top][bottom][index][help] */
725 char print_buf[STR_M];
726 int source;
727 time_t shutdowntime;
728 struct timeval tval;
729 char shuttime[100];
730
731 sprintf(print_buf, "%d", 0);
732 /* Stop updates */
733 CO_set_const("UD.do_update", print_buf);
734 /* Stop all servers */
735 CO_set_const("SV.do_server", print_buf);
736 sprintf(print_buf, "Stopping all servers\n");
737 fprintf(stderr, print_buf);
738 /*log_print(print_buf); */
739 strcpy(print_buf, "");
740
741 /* wait for all updates to complete */
742 /* XXX may be changed with blocking interface for stop updates */
743 sleep(5);
744
745 /* Store the shutdown time */
746 gettimeofday(&tval, NULL);
747 shutdowntime = tval.tv_sec;/* seconds since Jan. 1, 1970 */
748
749 /* Log the sshutdown time */
750 ctime_r(&shutdowntime, shuttime);
751 ER_inf_va(FAC_SV, 0xFFFFFF, "Server shutdown %s", shuttime);
752
753
754
755 /* Wake up all sleeping threads */
756 fprintf(stderr, "Going to wake sleeping threads up\n");
757
758 /* Delete the pid file to indicate normal shutdown */
759 if(unlink(SV_pidfile)==-1) {
760 ER_perror(FAC_SV, 1, "cannot delete pid file %s:", SV_pidfile);
761 }
762
763
764 /* CLose all listening sockets, so accept call exits */
765 close(SV_whois_sock);
766 close(SV_config_sock);
767 close(SV_mirror_sock);
768 for (source=0; SV_update_sock[source]!=-1; source++)
769 if(SV_update_sock[source]!=0)close(SV_update_sock[source]);
770
771
772 } /* SV_shutdown() */