1 /*
2 * Alarm Pinger (c) 2002 Jacek Konieczny <jajcus@pld.org.pl>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
16 * USA
17 *
18 * $Id: apinger.c,v 1.40 2003/03/26 11:24:59 cvs-jajcus Exp $
19 */
20
21 #include "config.h"
22 #include "apinger.h"
23
24 #include <stdio.h>
25 #ifdef HAVE_STDLIB_H
26 # include <stdlib.h>
27 #endif
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31 #ifdef HAVE_STRING_H
32 # include <string.h>
33 #endif
34 #ifdef HAVE_SYS_WAIT_H
35 # include <sys/wait.h>
36 #endif
37 #ifdef HAVE_SYS_POLL_H
38 # include <sys/poll.h>
39 #endif
40 #ifdef HAVE_ARPA_INET_H
41 # include <arpa/inet.h>
42 #endif
43
44 #include "debug.h"
45 #include "tv_macros.h"
46 #include "rrd.h"
47
48 #ifdef HAVE_ASSERT_H
49 # include <assert.h>
50 #else
51 # define assert(cond)
52 #endif
53
54 #define MIN(a,b) (((a)<(b))?(a):(b))
55
56 struct delayed_report {
57 int on;
58 char *msgid;
59 char *lastmsgid;
60 struct alarm_cfg *a;
61 struct target t;
62 struct timeval timestamp;
63 struct delayed_report *next;
64 };
65
66 struct delayed_report *delayed_reports=NULL;
67
68 struct timeval operation_started;
69
70
is_alarm_on(struct target * t,struct alarm_cfg * a)71 int is_alarm_on(struct target *t,struct alarm_cfg *a){
72 struct active_alarm_list *al;
73
74 for(al=t->active_alarms;al;al=al->next)
75 if (al->alarm==a)
76 return 1;
77 return 0;
78 }
79
80 static char msgid_buf[1024];
81 static char hostnamebuf[256]="-";
82
gen_msgid(struct target * t,char * suff)83 char *gen_msgid(struct target *t,char *suff){
84 struct timeval cur_time;
85
86 gettimeofday(&cur_time,NULL);
87
88 gethostname(hostnamebuf,sizeof(hostnamebuf));
89 sprintf(msgid_buf,"<%p.%li.%s@%s>",
90 t,(long int)(cur_time.tv_usec/1000+cur_time.tv_sec*1000),
91 suff,hostnamebuf);
92 return strdup(msgid_buf);
93 }
94
alarm_on(struct target * t,struct alarm_cfg * a)95 char *alarm_on(struct target *t,struct alarm_cfg *a){
96 struct active_alarm_list *al;
97 struct timeval cur_time,tv;
98
99 gettimeofday(&cur_time,NULL);
100 al=NEW(struct active_alarm_list,1);
101 al->next=t->active_alarms;
102 al->alarm=a;
103 al->msgid=gen_msgid(t,"on");
104 al->num_repeats=0;
105 if (a->repeat_interval){
106 tv.tv_sec=a->repeat_interval/1000;
107 tv.tv_usec=(a->repeat_interval%1000)*1000;
108 timeradd(&cur_time,&tv,&al->next_repeat);
109 }
110 t->active_alarms=al;
111 return strdup(al->msgid);
112 }
113
alarm_off(struct target * t,struct alarm_cfg * a)114 char *alarm_off(struct target *t,struct alarm_cfg *a){
115 struct active_alarm_list *al,*pa,*na;
116 char *msgid;
117
118 pa=NULL;
119 for(al=t->active_alarms;al;al=na){
120 na=al->next;
121 if (al->alarm==a){
122 if (pa!=NULL)
123 pa->next=na;
124 else
125 t->active_alarms=na;
126 msgid=al->msgid;
127 free(al);
128 return msgid;
129 }
130 else pa=al;
131 }
132 logit("Alarm '%s' not found in '%s'",a->name,t->name);
133 return NULL;
134 }
135
136 static char *macros_buf=NULL;
137 static int macros_buf_l=0;
subst_macros(const char * string,struct target * t,struct alarm_cfg * a,int on)138 const char * subst_macros(const char *string,struct target *t,struct alarm_cfg *a,int on){
139 char *p;
140 int nmacros=0;
141 int i,sl,l,n;
142 char **values;
143 char ps[16],pr[16],al[16],ad[16],ts[100];
144 time_t tim;
145
146 if (string==NULL || string[0]=='\000') return "";
147 for(i=0;string[i]!='\000';i++){
148 if (string[i]!='%') continue;
149 nmacros++;
150 i++;
151 if (string[i]=='\000') break;
152 }
153 if (nmacros==0) return string;
154 values=NEW(char *,(nmacros+1));
155 assert(values!=NULL);
156 l=sl=strlen(string);
157 n=0;
158 for(i=0;i<sl;i++){
159 if (string[i]!='%') continue;
160 i++;
161 switch(string[i]){
162 case 't':
163 values[n]=t->name;
164 break;
165 case 'T':
166 values[n]=t->description;
167 break;
168 case 'a':
169 if (a)
170 values[n]=a->name;
171 else
172 values[n]="?";
173 break;
174 case 'A':
175 if (a)
176 switch(a->type){
177 case AL_DOWN:
178 values[n]="down";
179 break;
180 case AL_LOSS:
181 values[n]="loss";
182 break;
183 case AL_DELAY:
184 values[n]="delay";
185 break;
186 default:
187 values[n]="unknown";
188 break;
189 }
190 else
191 values[n]="?";
192 break;
193 case 'r':
194 switch(on){
195 case -1:
196 values[n]="alarm canceled (config reload)";
197 break;
198 case 0:
199 values[n]="alarm canceled";
200 break;
201 default:
202 values[n]="ALARM";
203 break;
204 }
205 break;
206 case 'p':
207 sprintf(ps,"%i",t->last_sent);
208 values[n]=ps;
209 break;
210 case 'P':
211 sprintf(pr,"%i",t->received);
212 values[n]=pr;
213 break;
214 case 'l':
215 if (AVG_LOSS_KNOWN(t)){
216 sprintf(al,"%0.1f%%",AVG_LOSS(t));
217 values[n]=al;
218 }
219 else values[n]="n/a";
220 break;
221 case 'd':
222 if (AVG_DELAY_KNOWN(t)){
223 sprintf(ad,"%0.3fms",AVG_DELAY(t));
224 values[n]=ad;
225 }
226 else values[n]="n/a";
227 break;
228 case 's':
229 tim=time(NULL);
230 strftime(ts,100,config->timestamp_format,localtime(&tim));
231 values[n]=ts;
232 break;
233 case '%':
234 values[n]="%";
235 break;
236 default:
237 values[n]="";
238 break;
239 }
240 l+=strlen(values[n])-1;
241 n++;
242 }
243 values[n]=NULL;
244 l+=2;
245 if (macros_buf == NULL){
246 macros_buf=NEW(char,l);
247 macros_buf_l=l;
248 }else if (macros_buf_l < l){
249 macros_buf=(char *)realloc(macros_buf,l);
250 macros_buf_l=l;
251 }
252 assert(macros_buf!=NULL);
253 p=macros_buf;
254 n=0;
255 for(i=0;i<sl;i++){
256 if (string[i]!='%'){
257 *p++=string[i];
258 continue;
259 }
260 strcpy(p,values[n]);
261 p+=strlen(values[n]);
262 n++;
263 i++;
264 }
265 free(values);
266 *p='\000';
267 return macros_buf;
268 }
269
write_report(FILE * f,struct target * t,struct alarm_cfg * a,int on)270 void write_report(FILE *f,struct target *t,struct alarm_cfg *a,int on){
271 time_t tm;
272
273 tm=time(NULL);
274 fprintf(f,"%s",ctime(&tm));
275 if (on)
276 fprintf(f,"ALARM went off: %s\n",a->name);
277 else
278 fprintf(f,"alarm canceled: %s\n",a->name);
279 fprintf(f,"Target: %s\n",t->name);
280 fprintf(f,"Description: %s\n",t->description);
281 fprintf(f,"Probes sent: %i\n",t->last_sent+1);
282 fprintf(f,"Replies received: %i\n",t->received);
283 fprintf(f,"Last reply received: #%i %s",t->last_received,
284 ctime(&t->last_received_tv.tv_sec));
285 if (AVG_DELAY_KNOWN(t)){
286 fprintf(f,"Recent avg. delay: %4.3fms\n",AVG_DELAY(t));
287 }
288 if (AVG_LOSS_KNOWN(t)){
289 fprintf(f,"Recent avg. packet loss: %5.1f%%\n",AVG_LOSS(t));
290 }
291 }
292
make_reports(struct target * t,struct alarm_cfg * a,int on,char * thisid,char * lastid)293 void make_reports(struct target *t,struct alarm_cfg *a,int on,char* thisid,char* lastid){
294 FILE *p;
295 char buf[1024];
296 char *mailto,*mailfrom,*mailenvfrom;
297 int ret;
298 const char *command;
299
300 mailto=a->mailto;
301 mailenvfrom=a->mailenvfrom;
302 if (mailenvfrom!=NULL && strpbrk(mailenvfrom,"\\'")!=0)
303 mailenvfrom=NULL;
304 mailfrom=a->mailfrom;
305 if (mailto){
306 if (mailenvfrom){
307 snprintf(buf,1024,"%s -f'%s'",config->mailer,mailenvfrom);
308 }
309 else{
310 snprintf(buf,1024,"%s",config->mailer);
311 }
312 debug("Popening: %s",buf);
313 p=popen(buf,"w");
314 if (!p){
315 myperror("Couldn't send mail, popen:");
316 return;
317 }
318 fprintf(p,"Subject: %s\n",subst_macros(a->mailsubject,t,a,on));
319 fprintf(p,"To: %s\n",subst_macros(mailto,t,a,on));
320 if (mailfrom) {
321 fprintf(p,"From: %s\n",subst_macros(mailfrom,t,a,on));
322 }
323 if (thisid!=NULL)
324 fprintf(p,"Message-Id: %s\n",thisid);
325 if (lastid!=NULL && lastid[0]!='\000')
326 fprintf(p,"References: %s\n",lastid);
327
328 fprintf(p,"\n");
329 write_report(p,t,a,on);
330 ret=pclose(p);
331 if (!WIFEXITED(ret)){
332 logit("Error while sending mail.\n");
333 logit("sendmail terminated abnormally.\n");
334 }
335 else if (WEXITSTATUS(ret)!=0){
336 logit("Error while sending mail.\n");
337 logit("sendmail exited with status: %i\n",WEXITSTATUS(ret));
338 }
339 }
340 if (on>0) command=a->pipe_on;
341 else command=a->pipe_off;
342 if (command){
343 command=subst_macros(command,t,a,on);
344 debug("Popening: %s",command);
345 p=popen(command,"w");
346 if (!p){
347 logit("Couldn't pipe report through %s",command);
348 myperror("popen");
349 }
350 else {
351 write_report(p,t,a,on);
352 ret=pclose(p);
353 if (!WIFEXITED(ret)){
354 logit("Error while piping report.");
355 logit("command (%s) terminated abnormally.",command);
356 }
357 else if (WEXITSTATUS(ret)!=0){
358 logit("Error while piping report.");
359 logit("command (%s) exited with status: %i",command,WEXITSTATUS(ret));
360 }
361 }
362 }
363 if (on>0) command=a->command_on;
364 else command=a->command_off;
365 if (command){
366 command=subst_macros(command,t,a,on);
367 debug("Starting: %s",command);
368 ret=system(command);
369 if (!WIFEXITED(ret)){
370 logit("Error while starting command.");
371 logit("command (%s) terminated abnormally.",command);
372 }
373 else if (WEXITSTATUS(ret)!=0){
374 logit("Error while starting command.");
375 logit("command (%s) exited with status: %i",command,WEXITSTATUS(ret));
376 }
377 }
378 }
379
make_delayed_reports(void)380 void make_delayed_reports(void){
381 struct alarm_cfg *alarm;
382 struct target target;
383 int on;
384 char *msgid,*references;
385 struct delayed_report *dr,*pdr,*ndr;
386 int names_len,descriptions_len,references_len;
387 char *names,*descriptions;
388
389
390 if (delayed_reports==NULL) return;
391 on=delayed_reports->on;
392 msgid=strdup(delayed_reports->msgid);
393 alarm=delayed_reports->a;
394 target=delayed_reports->t;
395 names_len=descriptions_len=references_len=0;
396 for(dr=delayed_reports;dr;dr=dr->next){
397 if (dr->a==alarm && dr->on==on){
398 names_len+=strlen(dr->t.name)+1;
399 descriptions_len+=strlen(dr->t.description)+1;
400 if (dr->lastmsgid){
401 references_len+=strlen(dr->lastmsgid)+1;
402 }
403 }
404 }
405
406 names=NEW(char,names_len+1);
407 names[0]='\000';
408 descriptions=NEW(char,descriptions_len+1);
409 descriptions[0]='\000';
410 references=NEW(char,references_len+1);
411 references[0]='\000';
412
413 pdr=NULL;
414 for(dr=delayed_reports;dr;dr=ndr){
415 ndr=dr->next;
416 if (dr->a==alarm && dr->on==on){
417 if (on){
418 struct active_alarm_list *al;
419 struct target *t;
420 for(t=targets;t;t=t->next){
421 if (strcmp(dr->t.name,t->name)) continue;
422 for(al=t->active_alarms;al;al=al->next){
423 if (al->alarm==alarm){
424 if (al->msgid!=NULL) free(al->msgid);
425 al->msgid=strdup(msgid);
426 }
427 }
428 break;
429 }
430 }
431 if (names[0]!='\000') strcat(names,",");
432 strcat(names,dr->t.name);
433 if (descriptions[0]!='\000') strcat(descriptions,",");
434 strcat(descriptions,dr->t.description);
435 if (dr->lastmsgid){
436 if (references[0]!='\000') strcat(references," ");
437 strcat(references,dr->lastmsgid);
438 }
439 if (pdr!=NULL)
440 pdr->next=ndr;
441 else
442 delayed_reports=ndr;
443 free(dr->msgid);
444 free(dr->lastmsgid);
445 free(dr);
446 }
447 else pdr=dr;
448 }
449
450 target.name=names;
451 target.description=descriptions;
452
453 make_reports(&target,alarm,on,msgid,references);
454
455 free(msgid);
456 free(names);
457 free(descriptions);
458 free(references);
459 }
460
toggle_alarm(struct target * t,struct alarm_cfg * a,int on)461 void toggle_alarm(struct target *t,struct alarm_cfg *a,int on){
462 char *thisid=NULL,*lastid=NULL;
463 struct delayed_report *dr,*tdr;
464
465 if (on>0){
466 logit("ALARM: %s(%s) *** %s ***",t->description,t->name,a->name);
467 thisid=alarm_on(t,a);
468 }
469 else{
470 lastid=alarm_off(t,a);
471 thisid=gen_msgid(t,"off");
472 if (on==0)
473 logit("alarm canceled: %s(%s) *** %s ***",t->description,t->name,a->name);
474 else
475 logit("alarm canceled (config reload): %s(%s) *** %s ***",t->description,t->name,a->name);
476 }
477
478 if (a->combine_interval>0){
479 for(tdr=delayed_reports;tdr!=NULL && tdr->next!=NULL;tdr=tdr->next){
480 if (strcmp(tdr->t.name,t->name)==0 && tdr->a==a && tdr->on==on) return;
481 }
482 if (tdr!=NULL && strcmp(tdr->t.name,t->name)==0 && tdr->a==a && tdr->on==on) return;
483 dr=NEW(struct delayed_report,1);
484 assert(dr!=NULL);
485 dr->t=*t;
486 dr->a=a;
487 dr->msgid=strdup(thisid);
488 if (lastid) dr->lastmsgid=strdup(lastid);
489 else dr->lastmsgid=NULL;
490 dr->on=on;
491 gettimeofday(&dr->timestamp,NULL);
492 dr->next=NULL;
493 if (tdr==NULL)
494 delayed_reports=dr;
495 else
496 tdr->next=dr;
497 }
498 else make_reports(t,a,on,thisid,lastid);
499 free(thisid);
500 free(lastid);
501 }
502
503 /* if a time came for the next event schedule next one in given interval and return 1 */
scheduled_event(struct timeval * next_event,struct timeval * cur_time,int interval)504 int scheduled_event(struct timeval *next_event,struct timeval *cur_time,int interval){
505 struct timeval ct,tv;
506 int ret;
507
508 if (cur_time==NULL){
509 gettimeofday(&ct,NULL);
510 cur_time=&ct;
511 }
512 if (!timerisset(next_event) || timercmp(next_event,cur_time,<)){
513 if (!timerisset(next_event)){
514 *next_event=*cur_time;
515 }
516 tv.tv_sec=interval/1000;
517 tv.tv_usec=(interval%1000)*1000;
518 timeradd(cur_time,&tv,next_event);
519 ret=1;
520 }
521 else {
522 ret=0;
523 }
524 if (!timerisset(&next_probe) || timercmp(next_event,&next_probe,<))
525 next_probe=*next_event;
526 return ret;
527 }
528
send_probe(struct target * t)529 void send_probe(struct target *t){
530 int i,i1;
531 char buf[100];
532 int seq;
533
534 seq=++t->last_sent;
535 debug("Sending ping #%i to %s (%s)",seq,t->description,t->name);
536 strftime(buf,100,"%b %d %H:%M:%S",localtime(&t->next_probe.tv_sec));
537 debug("Next one scheduled for %s",buf);
538 if (t->addr.addr.sa_family==AF_INET) send_icmp_probe(t,seq);
539 #ifdef HAVE_IPV6
540 else if (t->addr.addr.sa_family==AF_INET6) send_icmp6_probe(t,seq);
541 #endif
542
543 i=t->last_sent%(t->config->avg_loss_delay_samples+t->config->avg_loss_samples);
544 if (t->last_sent>t->config->avg_loss_delay_samples+t->config->avg_loss_samples){
545 if (!t->queue[i]) t->recently_lost--;
546 }
547 t->queue[i]=0;
548
549 if (t->last_sent>t->config->avg_loss_delay_samples){
550 i1=(t->last_sent-t->config->avg_loss_delay_samples)
551 %(t->config->avg_loss_delay_samples+t->config->avg_loss_samples);
552 if (!t->queue[i1]) t->recently_lost++;
553 debug("Recently lost packets: %i",t->recently_lost);
554 }
555
556 t->upsent++;
557 }
558
559
analyze_reply(struct timeval time_recv,int icmp_seq,struct trace_info * ti)560 void analyze_reply(struct timeval time_recv,int icmp_seq,struct trace_info *ti){
561 struct target *t;
562 struct timeval tv;
563 double delay,avg_delay,avg_loss;
564 double tmp;
565 int i;
566 int previous_received;
567 struct alarm_list *al;
568 struct active_alarm_list *aal,*paa,*naa;
569 struct alarm_cfg *a;
570
571 if (icmp_seq!=(ti->seq%65536)){
572 debug("Sequence number mismatch.");
573 return;
574 }
575
576 for(t=targets;t!=NULL;t=t->next){
577 if (t==ti->target_id) break;
578 }
579 if (t==NULL){
580 logit("Couldn't match any target to the echo reply.\n");
581 return;
582 }
583 previous_received=t->last_received;
584 if (ti->seq>t->last_received) t->last_received=ti->seq;
585 t->last_received_tv=time_recv;
586 timersub(&time_recv,&ti->timestamp,&tv);
587 delay=tv.tv_sec*1000.0+((double)tv.tv_usec)/1000.0;
588 debug("#%i from %s(%s) delay: %4.3fms",ti->seq,t->description,t->name,delay);
589 if (t->received>t->config->avg_delay_samples)
590 tmp=t->rbuf[t->received%t->config->avg_delay_samples];
591 else
592 tmp=0;
593 t->rbuf[t->received%t->config->avg_delay_samples]=delay;
594 t->delay_sum+=delay-tmp;
595 t->received++;
596
597 avg_delay=AVG_DELAY(t);
598 debug("(avg: %4.3fms)",avg_delay);
599
600 i=ti->seq%(t->config->avg_loss_delay_samples+t->config->avg_loss_samples);
601 if (!t->queue[i] && ti->seq<=t->last_sent-t->config->avg_loss_delay_samples)
602 t->recently_lost--;
603 t->queue[i]=1;
604
605 if (AVG_LOSS_KNOWN(t)){
606 avg_loss=AVG_LOSS(t);
607 }else
608 avg_loss=0;
609
610 debug("(avg. loss: %5.1f%%)",avg_loss);
611
612 paa=NULL;
613 for(aal=t->active_alarms;aal;aal=naa){
614 naa=aal->next;
615 a=aal->alarm;
616 if (a->type==AL_DOWN){
617 t->upsent=0;
618 avg_loss=0;
619 }
620 if ((a->type==AL_DOWN)
621 || (a->type==AL_DELAY && avg_delay<a->p.lh.low)
622 || (a->type==AL_LOSS && avg_loss<a->p.lh.low) ){
623 toggle_alarm(t,a,0);
624 }
625 }
626
627 for(al=t->config->alarms;al;al=al->next){
628 a=al->alarm;
629 if (is_alarm_on(t,a)) continue;
630 switch(a->type){
631 case AL_DELAY:
632 if (AVG_DELAY_KNOWN(t) && avg_delay>a->p.lh.high )
633 toggle_alarm(t,a,1);
634 break;
635 case AL_LOSS:
636 if ( avg_loss > a->p.lh.high )
637 toggle_alarm(t,a,1);
638 break;
639 default:
640 break;
641 }
642 }
643 }
644
configure_targets(void)645 void configure_targets(void){
646 struct target *t,*pt,*nt;
647 struct target_cfg *tc;
648 struct active_alarm_list *al,*nal;
649 union addr addr;
650 int r;
651 int l;
652
653 /* delete all not configured targets */
654 pt=NULL;
655 for(t=targets;t;t=nt){
656 for(tc=config->targets;tc;tc=tc->next)
657 if (strcmp(tc->name,t->name)==0)
658 break;
659 nt=t->next;
660 if (tc==NULL){
661 if (pt==NULL)
662 targets=t;
663 else
664 pt->next=nt;
665 for(al=t->active_alarms;al;al=nal){
666 nal=al->next;
667 free(al);
668 }
669 free(t->queue);
670 free(t->rbuf);
671 free(t->name);
672 free(t->description);
673 free(t);
674 }
675 else pt=t;
676 }
677
678 /* Update target configuration */
679 for(tc=config->targets;tc;tc=tc->next){
680 for(t=targets;t;t=t->next)
681 if (!strcmp(t->name,tc->name))
682 break;
683 if (t==NULL) { /* new target */
684 memset(&addr,0,sizeof(addr));
685 r=inet_pton(AF_INET,tc->name,&addr.addr4.sin_addr);
686 if (r){
687 if (icmp_sock<0){
688 logit("Sorry, IPv4 is not available\n");
689 logit("Ignoring target %s\n",tc->name);
690 continue;
691 }
692 addr.addr.sa_family=AF_INET;
693 }else{
694 #ifdef HAVE_IPV6
695 r=inet_pton(AF_INET6,tc->name,&addr.addr6.sin6_addr);
696 if (r==0){
697 #endif
698 logit("Bad host address: %s\n",tc->name);
699 logit("Ignoring target %s\n",tc->name);
700 continue;
701 #ifdef HAVE_IPV6
702 }
703 if (icmp6_sock<0){
704 logit("Sorry, IPv6 is not available\n");
705 logit("Ignoring target %s\n",tc->name);
706 continue;
707 }
708 addr.addr.sa_family=AF_INET6;
709 #endif
710 }
711 t=NEW(struct target,1);
712 memset(t,0,sizeof(struct target));
713 t->name=strdup(tc->name);
714 t->description=strdup(tc->description);
715 t->addr=addr;
716 t->next=targets;
717 targets=t;
718 }
719 t->config=tc;
720 l=tc->avg_loss_delay_samples+tc->avg_loss_samples;
721 if (t->queue)
722 t->queue=(char *)realloc(t->queue,l);
723 else
724 t->queue=NEW(char,l);
725 assert(t->queue!=NULL);
726 memset(t->queue,0,l);
727 /* t->recently_lost=tc->avg_loss_samples; */
728 l=tc->avg_delay_samples;
729 if (t->rbuf)
730 t->rbuf=(double *)realloc(t->rbuf,l);
731 else
732 t->rbuf=NEW(double,l);
733 assert(t->rbuf!=NULL);
734 memset(t->rbuf,0,l);
735 }
736 if (targets==NULL){
737 logit("No usable targets found, exiting");
738 exit(1);
739 }
740 gettimeofday(&operation_started,NULL);
741 if (config->rrd_interval)
742 rrd_create();
743 }
744
free_targets(void)745 void free_targets(void){
746 struct target *t,*nt;
747 struct active_alarm_list *al,*nal;
748
749 /* delete all not configured targets */
750 for(t=targets;t;t=nt){
751 nt=t->next;
752 for(al=t->active_alarms;al;al=nal){
753 nal=al->next;
754 free(al);
755 }
756 free(t->queue);
757 free(t->rbuf);
758 free(t->name);
759 free(t->description);
760 free(t);
761 }
762 }
763
764
reload_config(void)765 void reload_config(void){
766 struct target *t;
767 struct active_alarm_list *al,*an;
768 struct alarm_cfg *a;
769 int r;
770
771 while(delayed_reports!=NULL) make_delayed_reports();
772 for(t=targets;t;t=t->next)
773 for(al=t->active_alarms;al;al=an){
774 an=al->next;
775 a=al->alarm;
776 toggle_alarm(t,a,-1);
777 }
778 r=load_config(config_file);
779 if (r==0) configure_targets();
780 }
781
write_status(void)782 void write_status(void){
783 FILE *f;
784 struct target *t;
785 struct active_alarm_list *al;
786 struct alarm_cfg *a;
787 time_t tm;
788 int i,qp,really_lost;
789 char *buf1,*buf2;
790 int err=0;
791
792 if (config->status_file==NULL) return;
793
794 f=fopen(config->status_file,"w");
795 if (f==NULL){
796 logit("Couldn't open status file");
797 myperror(config->status_file);
798 return;
799 }
800 tm=time(NULL);
801 fprintf(f,"%s\n",ctime(&tm));
802 for(t=targets;t;t=t->next){
803 fprintf(f,"Target: %s\n",t->name);
804 fprintf(f,"Description: %s\n",t->description);
805 fprintf(f,"Last reply received: #%i %s",t->last_received,
806 ctime(&t->last_received_tv.tv_sec));
807 fprintf(f,"Average delay: %0.3fms\n",AVG_DELAY(t));
808 if (AVG_LOSS_KNOWN(t)){
809 fprintf(f,"Average packet loss: %0.1f%%\n",AVG_LOSS(t));
810 }
811 fprintf(f,"Active alarms:");
812 if (t->active_alarms){
813 for(al=t->active_alarms;al;al=al->next){
814 a=al->alarm;
815 fprintf(f," \"%s\"",a->name);
816 }
817 fprintf(f,"\n");
818 }
819 else fprintf(f," None\n");
820
821 buf1=NEW(char,t->config->avg_loss_delay_samples+1);
822 buf2=NEW(char,t->config->avg_loss_samples+1);
823 i=t->last_sent%(t->config->avg_loss_delay_samples+t->config->avg_loss_samples);
824 for(i=0;i<t->config->avg_loss_delay_samples;i++){
825 if (i>=t->last_sent){
826 buf1[t->config->avg_loss_delay_samples-i-1]='-';
827 continue;
828 }
829 qp=(t->last_sent-i)%(t->config->avg_loss_delay_samples+
830 t->config->avg_loss_samples);
831 if (t->queue[qp])
832 buf1[t->config->avg_loss_delay_samples-i-1]='#';
833 else
834 buf1[t->config->avg_loss_delay_samples-i-1]='.';
835 }
836 buf1[i]=0;
837 really_lost=0;
838 for(i=0;i<t->config->avg_loss_samples;i++){
839 if (i>=t->last_sent-t->config->avg_loss_delay_samples){
840 buf2[t->config->avg_loss_samples-i-1]='-';
841 continue;
842 }
843 qp=(t->last_sent-i-t->config->avg_loss_delay_samples)
844 %(t->config->avg_loss_delay_samples+t->config->avg_loss_samples);
845 if (t->queue[qp])
846 buf2[t->config->avg_loss_samples-i-1]='#';
847 else{
848 buf2[t->config->avg_loss_samples-i-1]='.';
849 really_lost++;
850 }
851 }
852 buf2[i]=0;
853 fprintf(f,"Received packets buffer: %s %s\n",buf2,buf1);
854 if (t->recently_lost!=really_lost){
855 fprintf(f," lost packet count mismatch (%i!=%i)!\n",t->recently_lost,really_lost);
856 logit("%s: Lost packet count mismatch (%i!=%i)!",t->name,t->recently_lost,really_lost);
857 logit("%s: Received packets buffer: %s %s\n",t->name,buf2,buf1);
858 err=1;
859 }
860 free(buf1);
861 free(buf2);
862
863 fprintf(f,"\n");
864 }
865 fclose(f);
866 if (err) abort();
867 }
868
869 #ifdef FORKED_RECEIVER
870 int receiver_pipe=0;
871
pipe_reply(struct timeval time_recv,int icmp_seq,struct trace_info * ti)872 void pipe_reply(struct timeval time_recv,int icmp_seq,struct trace_info *ti){
873 struct piped_info pi;
874
875 pi.recv_timestamp=time_recv;
876 pi.icmp_seq=icmp_seq;
877 pi.ti=*ti;
878 write(receiver_pipe,&pi,sizeof(pi));
879 }
880
receiver_loop(void)881 void receiver_loop(void){
882 struct pollfd pfd[2];
883 int npfd=0;
884 int i;
885
886 signal(SIGTERM,SIG_DFL);
887 signal(SIGINT,SIG_DFL);
888 signal(SIGHUP,SIG_DFL);
889 signal(SIGUSR1,SIG_DFL);
890 signal(SIGPIPE,SIG_DFL);
891
892 if (icmp_sock){
893 pfd[npfd].events=POLLIN|POLLERR|POLLHUP|POLLNVAL;
894 pfd[npfd].revents=0;
895 pfd[npfd++].fd=icmp_sock;
896 }
897 if (icmp6_sock){
898 pfd[npfd].events=POLLIN|POLLERR|POLLHUP|POLLNVAL;
899 pfd[npfd++].fd=icmp6_sock;
900 pfd[npfd].revents=0;
901 }
902 while(1){
903 poll(pfd,npfd,-1);
904 for(i=0;i<npfd;i++){
905 if (!pfd[i].revents&POLLIN) continue;
906 if (pfd[i].fd==icmp_sock) recv_icmp();
907 else if (pfd[i].fd==icmp6_sock) recv_icmp6();
908 pfd[i].revents=0;
909 }
910 };
911 }
912 #endif
913
main_loop(void)914 void main_loop(void){
915 struct target *t;
916 struct timeval cur_time,next_status={0,0},tv,next_report={0,0},next_rrd_update={0,0};
917 struct pollfd pfd[2];
918 int timeout;
919 int npfd=0;
920 int i;
921 char buf[100];
922 int downtime;
923 struct alarm_list *al,*nal;
924 struct active_alarm_list *aal;
925 struct alarm_cfg *a;
926 #ifdef FORKED_RECEIVER
927 int recv_pipe[2];
928 int pid,r;
929 struct piped_info pi;
930 #endif
931
932 configure_targets();
933 #ifdef FORKED_RECEIVER
934 r=pipe(recv_pipe);
935 if (r){
936 myperror("pipe");
937 exit(1);
938 }
939 pid=fork();
940 if (pid==-1){
941 myperror("pipe");
942 exit(1);
943 }
944 else if (pid==0){
945 close(recv_pipe[0]);
946 receiver_pipe=recv_pipe[1];
947 receiver_loop();
948 exit(0);
949 }
950 close(recv_pipe[1]);
951 pfd[npfd].events=POLLIN|POLLERR|POLLHUP|POLLNVAL;
952 pfd[npfd].revents=0;
953 pfd[npfd++].fd=recv_pipe[0];
954 #else
955 if (icmp_sock){
956 pfd[npfd].events=POLLIN|POLLERR|POLLHUP|POLLNVAL;
957 pfd[npfd].revents=0;
958 pfd[npfd++].fd=icmp_sock;
959 }
960 if (icmp6_sock){
961 pfd[npfd].events=POLLIN|POLLERR|POLLHUP|POLLNVAL;
962 pfd[npfd++].fd=icmp6_sock;
963 pfd[npfd].revents=0;
964 }
965 #endif
966 if (config->status_interval){
967 gettimeofday(&cur_time,NULL);
968 tv.tv_sec=config->status_interval/1000;
969 tv.tv_usec=(config->status_interval%1000)*1000;
970 timeradd(&cur_time,&tv,&next_status);
971 }
972 while(!interrupted_by){
973 gettimeofday(&cur_time,NULL);
974 if ( !timercmp(&next_probe,&cur_time,>) )
975 timerclear(&next_probe);
976 for(t=targets;t;t=t->next){
977 for(al=t->config->alarms;al;al=nal){
978 a=al->alarm;
979 nal=al->next;
980 if (a->type!=AL_DOWN || is_alarm_on(t,a)) continue;
981 if (timerisset(&t->last_received_tv)){
982 timersub(&cur_time,&t->last_received_tv,&tv);
983 }
984 else {
985 timersub(&cur_time,&operation_started,&tv);
986 }
987 downtime=tv.tv_sec*1000+tv.tv_usec/1000;
988 if ( downtime > a->p.val)
989 toggle_alarm(t,a,1);
990 }
991 if (scheduled_event(&(t->next_probe),&cur_time,t->config->interval)){
992 send_probe(t);
993 }
994 for(aal=t->active_alarms;aal;aal=aal->next){
995 char *msgid;
996 char buf[100];
997 a=aal->alarm;
998 if (a->repeat_interval<=0)
999 continue;
1000 if (!scheduled_event(&aal->next_repeat,&cur_time,a->repeat_interval))
1001 continue;
1002 if (a->repeat_max && aal->num_repeats>=a->repeat_max)
1003 continue;
1004 aal->num_repeats++;
1005 debug("Repeating reports...");
1006 sprintf(buf,"%i",aal->num_repeats);
1007 msgid=gen_msgid(t,buf);
1008 make_reports(t,a,1,msgid,aal->msgid);
1009 free(msgid);
1010 }
1011 }
1012 if (config->status_interval){
1013 if (scheduled_event(&next_status,&cur_time,config->status_interval)){
1014 if (config->status_file) write_status();
1015 status_request=0;
1016 }
1017 }
1018 if (config->rrd_interval){
1019 if (scheduled_event(&next_rrd_update,&cur_time,config->rrd_interval)){
1020 rrd_update();
1021 }
1022 }
1023 if (delayed_reports){
1024 if (timerisset(&next_report) && timercmp(&next_report,&cur_time,<)){
1025 make_delayed_reports();
1026 timerclear(&next_report);
1027 }
1028 }
1029 if (delayed_reports){
1030 if (!timerisset(&next_report)){
1031 tv.tv_sec=delayed_reports->a->combine_interval/1000;
1032 tv.tv_usec=(delayed_reports->a->combine_interval%1000)*1000;
1033 timeradd(&delayed_reports->timestamp,&tv,&next_report);
1034 }
1035 if (!timerisset(&next_probe) || timercmp(&next_report,&next_probe,<))
1036 next_probe=next_report;
1037 }
1038 strftime(buf,100,"%b %d %H:%M:%S",localtime(&next_probe.tv_sec));
1039 debug("Next event scheduled for %s",buf);
1040 gettimeofday(&cur_time,NULL);
1041 if (timercmp(&next_probe,&cur_time,<)){
1042 timeout=0;
1043 }
1044 else{
1045 timersub(&next_probe,&cur_time,&tv);
1046 timeout=tv.tv_usec/1000+tv.tv_sec*1000;
1047 }
1048 debug("Polling, timeout: %5.3fs",((double)timeout)/1000);
1049 poll(pfd,npfd,timeout);
1050 for(i=0;i<npfd;i++){
1051 if (!pfd[i].revents&POLLIN) continue;
1052 #ifdef FORKED_RECEIVER
1053 if (pfd[i].fd==recv_pipe[0]){
1054 r=read(recv_pipe[0],&pi,sizeof(pi));
1055 if (r==sizeof(pi))
1056 analyze_reply(pi.recv_timestamp,pi.icmp_seq,&pi.ti);
1057 }
1058 #else
1059 if (pfd[i].fd==icmp_sock) recv_icmp();
1060 else if (pfd[i].fd==icmp6_sock) recv_icmp6();
1061 #endif
1062 pfd[i].revents=0;
1063 }
1064 if (status_request){
1065 status_request=0;
1066 if (config->status_file){
1067 logit("SIGUSR1 received, writting status.");
1068 write_status();
1069 }
1070 }
1071 if (reload_request){
1072 reload_request=0;
1073 logit("SIGHUP received, reloading configuration.");
1074 reload_config();
1075 }
1076 }
1077 #ifdef FORKED_RECEIVER
1078 kill(pid,SIGTERM);
1079 #endif
1080 while(delayed_reports!=NULL) make_delayed_reports();
1081 free_targets();
1082 if (macros_buf!=NULL) free(macros_buf);
1083 }
1084
1085