1 /*
2  *	binkleyforce -- unix FTN mailer project
3  *
4  *	Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
5  *
6  *	This program is free software; you can redistribute it and/or modify
7  *	it under the terms of the GNU General Public License as published by
8  *	the Free Software Foundation; either version 2 of the License, or
9  *	(at your option) any later version.
10  *
11  *	$Id: daemon.c,v 1.1.1.1 2004/09/09 09:52:37 kstepanenkov Exp $
12  */
13 
14 #include "includes.h"
15 #include "confread.h"
16 #include "logger.h"
17 #include "util.h"
18 #include "nodelist.h"
19 #include "io.h"
20 #include "session.h"
21 #include "outbound.h"
22 #include "daemon.h"
23 
24 /*
25  * Maxumum number of simultaneously running clients
26  */
27 int max_tcpip = 0;
28 int max_modem = 0;
29 
30 /*
31  * Current number of running clients
32  */
33 int tcpip_clients = 0;
34 int modem_clients = 0;
35 
36 /*
37  * Write queue/demon status to the log every XX seconds
38  */
39 #define DAEMON_ALIVE_TIMER 1200
40 
41 /*
42  * Time to sleep than all queues are in "DQ_Idle" state
43  */
44 #define DAEMON_IDLE_SLEEP 5
45 
46 /*
47  * Table of handled signals
48  */
49 struct {
50 	int signum;
51 	DM_State state;
52 	bool wait;
53 } daemon_signals[] = {
54 	{ SIGHUP,      DM_Restart,       FALSE },
55 	{ SIGINT,      DM_Shutdown,      FALSE },
56 	{ SIGTERM,     DM_Shutdown,      FALSE },
57 	{ SIGUSR1,     DM_Usr1,          FALSE },
58 	{ SIGUSR2,     DM_Usr2,          FALSE },
59 	{ 0,           0,                FALSE }
60 };
61 
62 /*
63  * Systems queue (with all adresses, flavors, etc.)
64  */
65 s_sysqueue daemon_sys_queue;
66 
67 /*
68  * Outgoing calls queues
69  */
70 s_daemon_queue daemon_queues[] = {
71 	{ &daemon_sys_queue, -1, 0, FALSE, DQ_Idle }, /* Modem */
72 	{ &daemon_sys_queue, -1, 0, TRUE,  DQ_Idle }, /* IP */
73 	{ NULL,              -1, 0, FALSE, DQ_Idle }
74 };
75 
76 /*
77  * Positions of the certain queues in the 'daemon_queues' array
78  */
79 #define MODEM_QUEUE 0
80 #define TCPIP_QUEUE 1
81 
daemon_sighandler_chld(int sig)82 static RETSIGTYPE daemon_sighandler_chld(int sig)
83 {
84 	int old_errno = errno;
85 	int rc, status;
86 	pid_t pid;
87 
88 	while( (pid = waitpid(-1, &status, WNOHANG)) > 0 )
89 	{
90 		rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
91 		if( daemon_branch_exit(pid, rc) == -1 )
92 			bf_log("wait got unexpected pid %d", (int)pid);
93 	}
94 
95 	signal(SIGCHLD, daemon_sighandler_chld);
96 	errno = old_errno;
97 }
98 
daemon_sighandler(int signum)99 static RETSIGTYPE daemon_sighandler(int signum)
100 {
101 	int i;
102 
103 	for( i = 0; daemon_signals[i].signum; i++ )
104 		if( daemon_signals[i].signum == signum )
105 		{
106 			daemon_signals[i].wait = TRUE;
107 			return;
108 		}
109 
110 	bf_log("daemon got unexpected signal %d", signum);
111 }
112 
daemon_sysentry_init(s_sysentry * sysent)113 static int daemon_sysentry_init(s_sysentry *sysent)
114 {
115 	s_override *p;
116 	char msg[64] = "";
117 	char abuf[BF_MAXADDRSTR+1];
118 
119 	/* Read calls/sessions statistic from sts file */
120 	(void)session_stat_get(&sysent->stat, &sysent->node.addr);
121 
122 	/* Lookup node in nodelist */
123 	(void)nodelist_lookup(&sysent->node, sysent->node.addr);
124 
125 	/* Set overrides */
126 	if( (p = conf_override(cf_override, sysent->node.addr)) )
127 	{
128 		sysent->overrides = p;
129 		sysent->lineptr = NULL;
130 		sysent->line = 0;
131 	}
132 
133 	if( sysent->node.keyword == KEYWORD_HOLD )
134 	{
135 		strcpy(msg, "hold by nodelist");
136 		sysent->stat.undialable = TRUE;
137 	}
138 	else if( sysent->node.keyword == KEYWORD_DOWN )
139 	{
140 		strcpy(msg, "down by nodelist");
141 		sysent->stat.undialable = TRUE;
142 	}
143 	else if( sysent->stat.undialable )
144 		strcpy(msg, "undialable");
145 	else if( sysent->stat.hold_until )
146 	{
147 		int holdtime = sysent->stat.hold_until - time(0);
148 
149 		if( holdtime > 0 )
150 			sprintf(msg, "calls holded for %d seconds", holdtime);
151 		else
152 			strcpy(msg, "calls holded");
153 	}
154 	else if( sysent->stat.hold_freqs )
155 	{
156 		int holdtime = sysent->stat.hold_freqs - time(0);
157 
158 		if( holdtime > 0 )
159 			sprintf(msg, "freqs holded for %d seconds", holdtime);
160 		else
161 			strcpy(msg, "freqs holded");
162 	}
163 
164 	if( msg && *msg )
165 		bf_log("QUEUE: add %s (%s)", ftn_addrstr(abuf, sysent->node.addr), msg);
166 	else
167 		bf_log("QUEUE: add %s", ftn_addrstr(abuf, sysent->node.addr));
168 
169 	return 0;
170 }
171 
daemon_sysentry_deinit(s_sysentry * sysent)172 static int daemon_sysentry_deinit(s_sysentry *sysent)
173 {
174 	char abuf[BF_MAXADDRSTR+1];
175 
176 	bf_log("QUEUE: remove %s", ftn_addrstr(abuf, sysent->node.addr));
177 
178 	return 0;
179 }
180 
daemon_node_cancall_line(const s_node * node,const s_override * ovrd)181 static bool daemon_node_cancall_line(const s_node *node, const s_override *ovrd)
182 {
183 	bool good_phone = FALSE;
184 	bool good_host = FALSE;
185 	bool good_time = FALSE;
186 	time_t unixtime = time(NULL);
187 	struct tm *now = localtime(&unixtime);
188 
189 	/*
190 	 * Check phone number
191 	 */
192 	if( ovrd && ovrd->sPhone && *ovrd->sPhone )
193 	{
194 		 if( modem_isgood_phone(ovrd->sPhone) )
195 			good_phone = TRUE;
196 	}
197 	else if( node && node->phone && *node->phone )
198 	{
199 		 if( modem_isgood_phone(node->phone) )
200 			good_phone = TRUE;
201 	}
202 
203 	/*
204 	 * Check host name (IP address)
205 	 */
206 	if( ovrd && ovrd->sIpaddr && *ovrd->sIpaddr )
207 	{
208 		if( tcpip_isgood_host(ovrd->sIpaddr) )
209 			good_host = TRUE;
210 	}
211 
212 	/*
213 	 * Check work time
214 	 */
215 	if( ovrd && timevec_isdefined(&ovrd->worktime) )
216 	{
217 		if( timevec_isnow(&ovrd->worktime, now) )
218 			good_time = TRUE;
219 	}
220 	else if( ovrd && ovrd->sFlags && !nodelist_checkflag(ovrd->sFlags, "CM") )
221 	{
222 		/*
223 		 * It is not an error. We check CM flag only
224 		 * if the work time was not specified in the override
225 		 */
226 		good_time = TRUE;
227 	}
228 	else if( node && timevec_isdefined(&node->worktime) )
229 	{
230 		if( timevec_isnow(&node->worktime, now) )
231 			good_time = TRUE;
232 	}
233 
234 	if( good_time )
235 	{
236 		if( good_host )
237 			return 2;
238 		else if( good_phone )
239 			return 1;
240 	}
241 
242 	return 0;
243 }
244 
245 enum { UNHOLD_CALLS, UNHOLD_FREQS };
246 
daemon_unhold_system(s_sysentry * syst,int mode)247 static void daemon_unhold_system(s_sysentry *syst, int mode)
248 {
249 	char abuf[BF_MAXADDRSTR+1];
250 	s_sess_stat stat_diff;
251 
252 	memset(&stat_diff, '\0', sizeof(s_sess_stat));
253 
254 	/*
255 	 * Reset try counters to the TRIES_RESET value
256 	 */
257 	session_stat_reset_counters(&stat_diff);
258 
259 	if( mode == UNHOLD_FREQS )
260 		stat_diff.hold_freqs = HOLD_RESET;
261 	else
262 		stat_diff.hold_until = HOLD_RESET;
263 
264 	/*
265 	 * Write new statistic to the sts file
266 	 */
267 	if( session_stat_apply_diff(syst->node.addr, stat_diff) == -1 )
268 	{
269 		bf_log("cannot write statistic for address %s",
270 				ftn_addrstr(abuf, syst->node.addr));
271 	}
272 
273 	/*
274 	 * Read new statistic from sts file, ignore errors
275 	 */
276 	(void)session_stat_get(&syst->stat, &syst->node.addr);
277 }
278 
daemon_node_cancall(s_sysentry * syst,bool ign_wtime,bool tcpip)279 static bool daemon_node_cancall(s_sysentry *syst, bool ign_wtime, bool tcpip)
280 {
281 	char abuf[BF_MAXADDRSTR+1];
282 	const s_override *ptrl, *lastptr;
283 	int line;
284 	int rc;
285 
286 	/* Is this system allready active in an another queue? Skip. */
287 	if( syst->busy )
288 		return FALSE;
289 
290 	/* Check for undialable flag */
291 	if( syst->stat.undialable )
292 		return FALSE;
293 
294 	if( daemon_branch_exist(syst->node.addr) )
295 		return FALSE;
296 
297 	/* Check for netmail presence, when MAILONLY */
298 	if( conf_options(cf_options) & OPTIONS_MAILONLY )
299 		if ( !( syst->types & TYPE_NETMAIL ) )
300 			return FALSE;
301 
302 	/* Check system hold status */
303 	if( syst->stat.hold_until > 0 )
304 	{
305 		if( time(0) > syst->stat.hold_until )
306 		{
307 			bf_log("unholding %s", ftn_addrstr(abuf, syst->node.addr));
308 			daemon_unhold_system(syst, UNHOLD_CALLS);
309 		}
310 		else
311 			return FALSE;
312 	}
313 
314 	/* Check freq hold status */
315 	if( syst->stat.hold_freqs > 0 )
316 	{
317 		if( time(0) > syst->stat.hold_freqs )
318 		{
319 			bf_log("unholding freqs for %s", ftn_addrstr(abuf, syst->node.addr));
320 			daemon_unhold_system(syst, UNHOLD_FREQS);
321 		}
322 		else if( !syst->flavors && (syst->types & TYPE_REQUEST) )
323 			return FALSE;
324 	}
325 
326 	/* Make checks for all lines */
327 	if( syst->overrides )
328 	{
329 		if( syst->lineptr && syst->lineptr->hidden )
330 		{
331 			line = syst->line + 1;
332 			/* Check lines after current */
333 			for( ptrl = syst->lineptr->hidden; ptrl; ptrl = ptrl->hidden )
334 			{
335 				if( (rc = daemon_node_cancall_line(NULL, ptrl))
336 				 && (rc == (tcpip ? 2 : 1)) )
337 				{
338 					syst->line = line;
339 					syst->lineptr = ptrl;
340 					syst->tcpip = (rc == 2) ? TRUE : FALSE;
341 					return TRUE;
342 				}
343 				line++;
344 			}
345 		}
346 
347 		if( syst->lineptr == NULL )
348 			{ lastptr = NULL; syst->line = 0; }
349 		else
350 			{ lastptr = syst->lineptr->hidden; }
351 
352 		line = 0;
353 		/* Check lines before current */
354 		for( ptrl = syst->overrides; ptrl && ptrl != lastptr; ptrl = ptrl->hidden )
355 		{
356 			if( (rc = daemon_node_cancall_line(line ? NULL : &syst->node, ptrl))
357 			 && (rc == (tcpip ? 2 : 1)) )
358 			{
359 				syst->line = line;
360 				syst->lineptr = ptrl;
361 				syst->tcpip = (rc == 2) ? TRUE : FALSE;
362 				return TRUE;
363 			}
364 			line++;
365 		}
366 	}
367 	else /* Node without overriden parameters */
368 	{
369 		syst->line = line = 0;
370 		return daemon_node_cancall_line(&syst->node, NULL);
371 	}
372 
373 	return FALSE;
374 }
375 
daemon_getnext(const s_sysqueue * q,int current,bool tcpip)376 static int daemon_getnext(const s_sysqueue *q, int current, bool tcpip)
377 {
378 	int i;
379 	int normal = -1;
380 
381 	if( current < 0 )
382 		current = 0;
383 
384 	/* Check systems AFTER the current */
385 	for( i = current + 1; i < q->sysnum; i++ )
386 	{
387 		if( q->systab[i].flavors & FLAVOR_IMMED ) {
388 			if( daemon_node_cancall(&q->systab[i], TRUE, tcpip) )
389 				return i;
390 		} else if( q->systab[i].flavors & FLAVOR_CRASH ) {
391 			if( daemon_node_cancall(&q->systab[i], FALSE, tcpip) )
392 				return i;
393 		} else if( q->systab[i].flavors & FLAVOR_DIRECT
394 		        || q->systab[i].flavors & FLAVOR_NORMAL ) {
395 			if( normal == -1 && daemon_node_cancall(&q->systab[i], FALSE, tcpip) )
396 				normal = i;
397 		}
398 	}
399 
400 	/* Check systems BEFORE the current */
401 	for( i = 0; (i < current + 1) && (i < q->sysnum); i++ )
402 	{
403 		if( q->systab[i].flavors & FLAVOR_IMMED ) {
404 			if( daemon_node_cancall(&q->systab[i], TRUE, tcpip) )
405 				return i;
406 		} else if( q->systab[i].flavors & FLAVOR_CRASH ) {
407 			if( daemon_node_cancall(&q->systab[i], FALSE, tcpip) )
408 				return i;
409 		} else if( q->systab[i].flavors & FLAVOR_DIRECT
410 		        || q->systab[i].flavors & FLAVOR_NORMAL ) {
411 			if( normal == -1 && daemon_node_cancall(&q->systab[i], FALSE, tcpip) )
412 				normal = i;
413 		}
414 	}
415 
416 	return normal;
417 }
418 
daemon_getnext2(const s_sysqueue * q,int current,bool tcpip)419 static int daemon_getnext2(const s_sysqueue *q, int current, bool tcpip)
420 {
421 	int next;
422 
423 	/* Unlock previous system if available */
424 	if( current >= 0 )
425 		q->systab[current].busy = FALSE;
426 
427 	next = daemon_getnext(q, current, tcpip);
428 
429 	/* Lock new system */
430 	if( next >= 0 )
431 		q->systab[next].busy = TRUE;
432 
433 	return next;
434 }
435 
daemon_do_tries_action(s_sysqueue * q,int pos,s_tries * act,const char * msg)436 static void daemon_do_tries_action(s_sysqueue *q, int pos, s_tries *act, const char *msg)
437 {
438 	s_sess_stat stat_diff;
439 	char abuf[BF_MAXADDRSTR+1];
440 
441 	memset(&stat_diff, '\0', sizeof(s_sess_stat));
442 
443 	if( act->action == TRIES_ACTION_UNDIALABLE )
444 	{
445 		bf_log("set %s undialable: %s",
446 			ftn_addrstr(abuf, q->systab[pos].node.addr), msg);
447 		stat_diff.undialable = TRUE;
448 	}
449 	else if( act->action == TRIES_ACTION_HOLDSYSTEM )
450 	{
451 		bf_log("hold %s for %d seconds: %s",
452 			ftn_addrstr(abuf, q->systab[pos].node.addr), act->arg, msg);
453 		stat_diff.hold_until = time(NULL) + act->arg;
454 	}
455 	else if( act->action == TRIES_ACTION_HOLDALL )
456 	{
457 		bf_log("hold all systems for %d seconds: %s", act->arg, msg);
458 		q->holduntil = time(NULL) + act->arg;
459 	}
460 
461 	/*
462 	 * Write new statistic to the sts file
463 	 */
464 	if( session_stat_apply_diff(q->systab[pos].node.addr, stat_diff) == -1 )
465 	{
466 		bf_log("cannot write statistic for address %s",
467 				ftn_addrstr(abuf, q->systab[pos].node.addr));
468 	}
469 
470 	/*
471 	 * Read new statistic from sts file, ignore errors
472 	 */
473 	(void)session_stat_get(&q->systab[pos].stat,
474 			&q->systab[pos].node.addr);
475 }
476 
daemon_process_rc(s_sysqueue * q,s_faddr addr,int rc)477 static void daemon_process_rc(s_sysqueue *q, s_faddr addr, int rc)
478 {
479 	int i;
480 	s_tries *maxtries        = NULL;
481 	s_tries *maxtries_noansw = NULL;
482 	s_tries *maxtries_noconn = NULL;
483 	s_tries *maxtries_nodial = NULL;
484 	s_tries *maxtries_hshake = NULL;
485 	s_tries *maxtries_sessns = NULL;
486 	char abuf[BF_MAXADDRSTR+1];
487 
488 	for( i = 0; i < q->sysnum; i++ )
489 		if( ftn_addrcomp(q->systab[i].node.addr, addr) == 0 )
490 			break;
491 
492 	if( i < q->sysnum )
493 	{
494 		/* Set last call finish time */
495 		q->systab[i].lastcall = time(0);
496 
497 		/* Temporary set `state' structure to
498 		   make dynamical configuration work! */
499 		state.valid  = TRUE;
500 		state.node   = q->systab[i].node;
501 		state.listed = q->systab[i].node.listed;
502 
503 		maxtries        = conf_tries(cf_maxtries);
504 		maxtries_noansw = conf_tries(cf_maxtries_noansw);
505 		maxtries_noconn = conf_tries(cf_maxtries_noconn);
506 		maxtries_nodial = conf_tries(cf_maxtries_nodial);
507 		maxtries_hshake = conf_tries(cf_maxtries_hshake);
508 		maxtries_sessns = conf_tries(cf_maxtries_sessions);
509 
510 		/* Reset `state' structure */
511 		init_state(&state);
512 
513 		/* Update statistic, ignore errors */
514 		session_stat_get(&q->systab[i].stat, &addr);
515 
516 		bf_log("%s: rc = %d [%d/%d/%d/%d/%d/%d]",
517 			ftn_addrstr(abuf, addr), rc,
518 			q->systab[i].stat.tries,
519 			q->systab[i].stat.tries_noansw,
520 			q->systab[i].stat.tries_noconn,
521 			q->systab[i].stat.tries_nodial,
522 			q->systab[i].stat.tries_hshake,
523 			q->systab[i].stat.tries_sessns);
524 
525 		DEB((D_DAEMON, "daemon_process_rc: address %s: [%d/%d/%d/%d/%d/%d]",
526 			ftn_addrstr(abuf, addr),
527 			q->systab[i].stat.tries,
528 			q->systab[i].stat.tries_noansw,
529 			q->systab[i].stat.tries_noconn,
530 			q->systab[i].stat.tries_nodial,
531 			q->systab[i].stat.tries_hshake,
532 			q->systab[i].stat.tries_sessns));
533 
534 		if( maxtries && q->systab[i].stat.tries >= maxtries->tries )
535 		{
536 			daemon_do_tries_action(q, i, maxtries, "reached maximal tries count");
537 		}
538 		else if( maxtries_noansw && q->systab[i].stat.tries_noansw >= maxtries_noansw->tries )
539 		{
540 			daemon_do_tries_action(q, i, maxtries_noansw, "reached maximal no answers count");
541 		}
542 		else if( maxtries_noconn && q->systab[i].stat.tries_noconn >= maxtries_noconn->tries )
543 		{
544 			daemon_do_tries_action(q, i, maxtries_noconn, "reached maximal connect failures count");
545 		}
546 		else if( maxtries_nodial && q->systab[i].stat.tries_nodial >= maxtries_nodial->tries )
547 		{
548 			daemon_do_tries_action(q, i, maxtries_nodial, "reached maximal no dialtone count");
549 		}
550 		else if( maxtries_hshake && q->systab[i].stat.tries_hshake >= maxtries_hshake->tries )
551 		{
552 			daemon_do_tries_action(q, i, maxtries_hshake, "reached maximal handshake failures count");
553 		}
554 		else if( maxtries_sessns && q->systab[i].stat.tries_sessns >= maxtries_sessns->tries )
555 		{
556 			daemon_do_tries_action(q, i, maxtries_sessns, "reached maximal session failures count");
557 		}
558 	}
559 	else
560 	{
561 		/* No entry in the systems queue
562 		 * TODO: load statistic and check tries? */
563 		bf_log("%s: rc = %d",
564 			ftn_addrstr(abuf, addr), rc);
565 		DEB((D_DAEMON, "daemon_process_rc: address %s: [%d/%d/%d/%d/%d]",
566 			ftn_addrstr(abuf, addr)));
567 	}
568 }
569 
daemon_alive_message(s_sysqueue * q)570 static void daemon_alive_message(s_sysqueue *q)
571 {
572 	int i, holded_num = 0;
573 
574 	for( i = 0; i < q->sysnum; i++ )
575 		if( q->systab[i].stat.hold_until
576 		 || q->systab[i].stat.hold_freqs )
577 			holded_num++;
578 
579 	bf_log("still alive (%d systems, %d holded, %d branches)",
580 		q->sysnum, holded_num, daemon_branch_number());
581 }
582 
daemon_queue_do(s_daemon_queue * dq)583 static void daemon_queue_do(s_daemon_queue *dq)
584 {
585 	bool select_next_address = FALSE;
586 	s_sysqueue *q = dq->q;
587 #ifdef DEBUG
588 	char abuf[BF_MAXADDRSTR+1];
589 #endif
590 
591 	if( dq->current >= 0 )
592 	{
593 		if( (q->systab[dq->current].lastcall == 0)
594 		 || (q->systab[dq->current].lastcall + dq->circle < time(0)) )
595 		{
596 			if( !daemon_branch_exist(q->systab[dq->current].node.addr) )
597 			{
598 				DEB((D_DAEMON, "daemon_queue: calling %s",
599 					ftn_addrstr(abuf, q->systab[dq->current].node.addr)));
600 				if( !daemon_call(&q->systab[dq->current]) )
601 					select_next_address = TRUE;
602 			}
603 			else
604 				select_next_address = TRUE;
605 		}
606 	}
607 	else
608 		select_next_address = TRUE;
609 
610 	if( select_next_address )
611 	{
612 		int next = daemon_getnext2(q, dq->current, dq->tcpip);
613 		DEB((D_DAEMON, "daemon_queue: next = %d, current = %d",
614 			next, dq->current));
615 
616 		if( next >= 0 )
617 		{
618 			dq->current = next;
619 
620 			/*
621 			 * Temporary set `state' structure to
622 			 * make dynamical configuration work!
623 			 */
624 			state.valid  = TRUE;
625 			state.node   = q->systab[dq->current].node;
626 			state.listed = q->systab[dq->current].node.listed;
627 			state.inet   = dq->tcpip;
628 
629 			if( (q->systab[dq->current].flavors & FLAVOR_IMMED) )
630 				dq->circle = conf_number(cf_daemon_circle_immed);
631 			else if( (q->systab[dq->current].flavors & FLAVOR_CRASH) )
632 				dq->circle = conf_number(cf_daemon_circle_crash);
633 			else if( (q->systab[dq->current].flavors & FLAVOR_DIRECT) )
634 				dq->circle = conf_number(cf_daemon_circle_direct);
635 			else
636 				dq->circle = conf_number(cf_daemon_circle_normal);
637 
638 			init_state(&state);
639 		}
640 		else
641 			dq->current = -1;
642 	}
643 }
644 
daemon_queues_update_current(s_daemon_queue dqs[],int pos)645 void daemon_queues_update_current(s_daemon_queue dqs[], int pos)
646 {
647 	int i;
648 
649 	for( i = 0; dqs[i].q; i++ )
650 	{
651 		if( dqs[i].current < 0 )
652 			continue;
653 
654 		if( dqs[i].current == pos )
655 			dqs[i].current = -1;
656 		else if( dqs[i].current > pos )
657 			dqs[i].current--;
658 	}
659 }
660 
daemon_rescan_sysqueue(s_sysqueue * q,s_daemon_queue dqs[])661 int daemon_rescan_sysqueue(s_sysqueue *q, s_daemon_queue dqs[])
662 {
663 	int i;
664 	s_outbound_callback_data ocb;
665 
666 	out_reset_sysqueue(q);
667 
668 	memset(&ocb, '\0', sizeof(s_outbound_callback_data));
669 	ocb.callback = out_handle_sysqueue;
670 	ocb.dest = (void *)q;
671 	if( out_scan(&ocb, NULL) )
672 	{
673 		bf_log("error scanning outbound");
674 		return -1;
675 	}
676 
677 	/*
678 	 * Remove empty entries from sysqueue (e.g. the mail was
679 	 * removed by the sysop or by an another program)
680 	 */
681 	for( i = 0; i < q->sysnum; i++ )
682 		if( !q->systab[i].types && !q->systab[i].flavors )
683 		{
684 			out_remove_from_sysqueue(q, i);
685 			daemon_queues_update_current(dqs, i);
686 		}
687 
688 #ifdef DEBUG
689 	log_sysqueue(q);
690 #endif
691 
692 	return 0;
693 }
694 
daemon_remove_waiting_branches(s_sysqueue * q,s_daemon_queue dqs[])695 int daemon_remove_waiting_branches(s_sysqueue *q, s_daemon_queue dqs[])
696 {
697 	int i;
698 	int j;
699 	s_daemon_branch *bptr;
700 #ifdef DEBUG
701 	char abuf[BF_MAXADDRSTR+1];
702 #endif
703 
704 	while( (i = daemon_branch_get_first_waiting()) >= 0 )
705 	{
706 		bptr = daemon_branch_get_pointer(i);
707 		if( !bptr )
708 		{
709 			bf_log("internal error: cannot get branch pointer!");
710 			return -1;
711 		}
712 
713 		DEB((D_DAEMON, "daemon: process branch information for %s, rc = %d",
714 			ftn_addrstr(abuf, bptr->addr), bptr->rc));
715 
716 		if( bptr->tcpip )
717 			--tcpip_clients;
718 		else
719 			--modem_clients;
720 
721 		daemon_process_rc(q, bptr->addr, bptr->rc);
722 
723 		if( bptr->rc == BFERR_NOERROR )
724 		{
725 			/* Remove system from queue */
726 			for( j = 0; j < q->sysnum; j++ )
727 				if( !ftn_addrcomp(bptr->addr, q->systab[j].node.addr) )
728 				{
729 					out_remove_from_sysqueue(q, j);
730 					daemon_queues_update_current(dqs, j);
731 				}
732 		}
733 
734 		/* Hold modem line for some time */
735 		if( !bptr->tcpip && bptr->portname )
736 		{
737 			daemon_line_hold(bptr->portname,
738 				conf_number(cf_daemon_circle_modem));
739 		}
740 
741 		/* Remove branch entry */
742 		daemon_branch_remove(i);
743 	}
744 
745 	return 0;
746 }
747 
748 #define	PIDFILE_CREATE	1
749 #define PIDFILE_DELETE	2
750 #define PIDFILE_TERMINATE 3
751 
daemon_pidfile(int cmd)752 int daemon_pidfile(int cmd)
753 {
754 	char *pidfile	    = conf_string(cf_daemon_pid_file);
755 	pid_t hispid, mypid = getpid();
756 	FILE *pf;
757 	struct stat sb;
758 
759 	if (pidfile == NULL)
760 		return 0;
761 
762 	switch (cmd) {
763 		case PIDFILE_CREATE:
764 			if (stat(pidfile, &sb) == 0) {
765 				pf = fopen(pidfile, "r");
766 				if (pf == NULL) {
767 					bf_log("daemon_pidfile: cannot open %s for reading", pidfile);
768 					return (-1);
769 				}
770 
771 				fscanf(pf, "%d", &hispid);
772 				fclose(pf);
773 
774 				if (hispid != 0) {
775 					if (hispid == mypid)
776 						return 0;
777 					if (kill(hispid, 0) == 0) {
778 						bf_log("daemon_pidfile: another daemon exist. pid=%d", hispid);
779 						return (-1);
780 					}
781 					if (errno != ESRCH) {
782 						bf_log("daemon_pidfile: error sending signal. pid=%d, errno=%d", hispid, errno);
783 						return (-1);
784 					}
785 				}
786 			} else if (errno != ENOENT) {
787 				bf_log("daemon_pidfile: error stat(%s). errno=%d", pidfile, errno);
788 				return (-1);
789 			}
790 
791 			pf = fopen(pidfile, "w");
792 			if (pf == NULL) {
793 				bf_log("daemon_pidfile: cannot open %s for writing", pidfile);
794 				return (-1);
795 			}
796 
797 			fprintf(pf, "%d", mypid);
798 			fclose(pf);
799 			break;
800 
801 		case PIDFILE_DELETE:
802 			if (stat(pidfile, &sb) == 0) {
803 				pf = fopen(pidfile, "r");
804 				if (pf == NULL) {
805 					bf_log("daemon_pidfile: cannot open %s for reading", pidfile);
806 					return (-1);
807 				}
808 
809 				fscanf(pf, "%d", &hispid);
810 				fclose(pf);
811 
812 				if ((hispid == 0) || (hispid == mypid)) {
813 					unlink(pidfile);
814 					return 0;
815 				} else {
816 					bf_log("daemon_pidfile: oops! mypid=%d, hispid=%d", mypid, hispid);
817 					return (-1);
818 				}
819 			} else {
820 				bf_log("daemon_pidfile: error stat(%s). errno=%d", pidfile, errno);
821 				return (-1);
822 			}
823 			break;
824 
825 		case PIDFILE_TERMINATE:
826 			if (stat(pidfile, &sb) == 0) {
827 				pf = fopen(pidfile, "r");
828 				if (pf == NULL) {
829 					bf_log("daemon_pidfile: cannot open %s for reading", pidfile);
830 					return (-1);
831 				}
832 
833 				fscanf(pf, "%d", &hispid);
834 				fclose(pf);
835 				unlink(pidfile);
836 
837 				if (hispid != 0)
838 					kill(hispid, 15);
839 
840 			} else {
841 				bf_log("daemon_pidfile: error stat(%s). errno=%d", pidfile, errno);
842 				return (-1);
843 			}
844 			break;
845 
846 		default:
847 			bf_log("daemon_pidfile: undefined cmd = %d", cmd);
848 			return (-1);
849 	}
850 
851 	return 0;
852 }
853 
daemon_run(const char * confname,const char * incname,bool quit)854 int daemon_run(const char *confname, const char *incname, bool quit)
855 {
856 	DM_State dmstate    = DM_Start;
857 	time_t timer_rescan = 0;
858 	time_t timer_alive  = 0;
859 	bool started        = FALSE;
860 	int circle_rescan   = 0;
861 	int rc              = 0;
862 	int i;
863 
864 	if ( quit ) {
865 		daemon_pidfile(PIDFILE_TERMINATE);
866 		exit(0);
867 	}
868 
869 	/* Initialisation */
870 	memset(&daemon_sys_queue, '\0', sizeof(s_sysqueue));
871 
872 	/* Install signal handlers */
873 	signal(SIGCHLD, daemon_sighandler_chld);
874 	signal(SIGINT,  daemon_sighandler);
875 	signal(SIGTERM, daemon_sighandler);
876 	signal(SIGHUP,  daemon_sighandler);
877 	signal(SIGUSR1, daemon_sighandler);
878 	signal(SIGUSR2, daemon_sighandler);
879 
880 	while(1)
881 	{
882 		switch(dmstate) {
883 		case DM_Start:
884 			DEB((D_DAEMON, "daemon: entering state DM_Start"));
885 
886 			if (daemon_pidfile(PIDFILE_CREATE) == -1)
887 				exit(0);
888 
889 			circle_rescan = conf_number(cf_daemon_circle_rescan);
890 			max_tcpip     = conf_number(cf_daemon_maxclients_tcpip);
891 			max_modem     = conf_number(cf_daemon_maxclients_modem);
892 
893 			/* Set default values */
894 			if( !circle_rescan ) circle_rescan = 60;
895 
896 			/* Disable counting of files/mail size */
897 			sysqueue_dont_count_sizes = TRUE;
898 
899 			/* Setup sysqueue scanner callbacks */
900 			sysqueue_add_callback = daemon_sysentry_init;
901 			sysqueue_rem_callback = daemon_sysentry_deinit;
902 
903 			/* Reopen log and debug files */
904 			if( log_isopened() )
905 				log_close();
906 #ifdef DEBUG
907 			if( debug_isopened() )
908 				debug_close();
909 #endif
910 			if( log_open(log_getfilename(LOG_FILE_DAEMON), NULL, NULL) )
911 			{
912 				bf_log("can't continue without logging");
913 				return BFERR_FATALERROR;
914 			}
915 
916 #ifdef DEBUG
917 			(void)debug_setfilename(log_getfilename(LOG_FILE_DEBUG));
918 #endif
919 
920 			bf_log("%sstarting daemon (%s)",
921 				started ? "re" : "", BF_VERSION);
922 
923 			started = TRUE;
924 			dmstate = DM_ProcessQueues;
925 			break;
926 
927 		case DM_Restart:
928 			DEB((D_DAEMON, "daemon: entering state DM_Restart"));
929 
930 			/* Release memory */
931 			deinit_sysqueue(&daemon_sys_queue);
932 			deinit_conf();
933 
934 			/* Reset queues */
935 			daemon_queues[MODEM_QUEUE].current =
936 				daemon_queues[TCPIP_QUEUE].current = -1;
937 			daemon_queues[MODEM_QUEUE].circle =
938 				daemon_queues[TCPIP_QUEUE].circle = 0;
939 			daemon_queues[MODEM_QUEUE].state =
940 				daemon_queues[TCPIP_QUEUE].state = DQ_Idle;
941 
942 			/* Read primary config file */
943 			if( confname && *confname )
944 				rc = conf_readconf(confname, 0);
945 			else
946 				rc = conf_readconf(conf_getconfname(), 0);
947 
948 			if( rc )
949 				return(BFERR_FATALERROR);
950 
951 			/* Read additional config file (manual include) */
952 			if( incname && *incname && conf_readconf(incname, 1) )
953 				bf_log("cannot read additional config (ignore)");
954 
955 			dmstate = DM_Start;
956 			break;
957 
958 		case DM_ProcessQueues:
959 			DEB((D_DAEMON, "daemon: entering state DM_ProcessQueues"));
960 
961 			/*
962 			 * Handle received signals
963 			 */
964 			for( i = 0; daemon_signals[i].signum; i++ )
965 				if( daemon_signals[i].wait )
966 					break;
967 
968 			if( daemon_signals[i].signum )
969 			{
970 				daemon_signals[i].wait = FALSE;
971 				dmstate = daemon_signals[i].state;
972 				break;
973 			}
974 
975 			/*
976 			 * Process finished branches
977 			 */
978 			(void)daemon_remove_waiting_branches(&daemon_sys_queue,
979 					daemon_queues);
980 
981 			/*
982 			 * Check rescan timer
983 			 */
984 			if( !timer_running(timer_rescan) || timer_expired(timer_rescan) )
985 			{
986 				(void)daemon_rescan_sysqueue(&daemon_sys_queue,
987 						daemon_queues);
988 				timer_set(&timer_rescan, circle_rescan);
989 			}
990 
991 			/*
992 			 * Check alive timer
993 			 */
994 			if( !timer_running(timer_alive) || timer_expired(timer_alive) )
995 			{
996 				daemon_alive_message(&daemon_sys_queue);
997 				timer_set(&timer_alive, DAEMON_ALIVE_TIMER);
998 			}
999 
1000 			if( max_modem > 0 )
1001 				daemon_queue_do(&daemon_queues[MODEM_QUEUE]);
1002 			if( max_tcpip > 0 )
1003 				daemon_queue_do(&daemon_queues[TCPIP_QUEUE]);
1004 
1005 			(void)sleep(DAEMON_IDLE_SLEEP);
1006 			break;
1007 
1008 		case DM_Usr1:
1009 			DEB((D_DAEMON, "daemon: entering state DM_Usr1"));
1010 
1011 			bf_log("signal USR1 has no effect now. Have any ideas?");
1012 			dmstate = DM_ProcessQueues;
1013 
1014 			break;
1015 
1016 		case DM_Usr2:
1017 			DEB((D_DAEMON, "daemon: entering state DM_Usr2"));
1018 
1019 			bf_log("signal USR2 has no effect now. Have any ideas?");
1020 			dmstate = DM_ProcessQueues;
1021 
1022 			break;
1023 
1024 		case DM_Shutdown:
1025 			DEB((D_DAEMON, "daemon: entering state DM_Shutdown"));
1026 
1027 			bf_log("stopping daemon");
1028 			daemon_pidfile(PIDFILE_DELETE);
1029 
1030 			/* Release memory */
1031 			deinit_sysqueue(&daemon_sys_queue);
1032 			daemon_branch_deinit();
1033 			daemon_lines_deinit();
1034 			deinit_conf();
1035 
1036 			exit(0);
1037 		}
1038 	}
1039 }
1040 
1041