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