/* * Copyright (c) 1998 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. */ /********** monitor.c **********/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nefu.h" #include "ll.h" void machine_dns_lookup( void ) { struct machine *m; struct machine **i; struct hostent *hp; struct test *t; i = &machines_no_dns; while ( *i != NULL ) { m = *i; if (( hp = gethostbyname( m->m_name )) != NULL ) { if ( hp->h_addr_list[ 1 ] != NULL ) { if ( m->m_dns_status != MACHINE_MULT_IPS ) { m->m_dns_status = MACHINE_MULT_IPS; dns_event++; } i = &((*i)->m_next_dns); } else { *i = (*i)->m_next_dns; dns_event++; m->m_dns_status = 0; m->m_next_dns = NULL; memcpy( &(m->m_sin.sin_addr.s_addr), hp->h_addr_list[ 0 ], (unsigned int)hp->h_length ); t = m->m_test; t->t_status = T_UP; t->t_sin.sin_addr.s_addr = m->m_sin.sin_addr.s_addr; t = t->t_child; while (( t != NULL ) && ( t->t_machine == m )) { t->t_status = T_UP; t->t_sin.sin_addr.s_addr = m->m_sin.sin_addr.s_addr; t = t->t_peer; } } } else { if ( m->m_dns_status != MACHINE_NO_DNS ) { m->m_dns_status = MACHINE_NO_DNS; dns_event++; } i = &((*i)->m_next_dns); } } } /* UP, t, NULL, NULL * DOWN, t, first, NULL * MAYBE t, first, NULL * MAYBE t, bounce, first */ void test_update( int stat, struct test *t, struct report *now, struct report *prev ) { if ( report( stat, t, now, prev ) < 0 ) { syslog( LOG_ERR, "update: report failed: %m" ); abort(); } if ( t->t_report != NULL ) { report_free( t->t_report ); t->t_report = NULL; } if ( stat != T_UP ) { t->t_report = now; if ( t->t_status == T_UP ) { t->t_pass_down = t->t_tested - 1; } } t->t_status = stat; } void monitor_network( struct schedule *s ) { struct report *r; struct report *b; struct test *t; struct test *path; int route; int result; int sl; struct timeval tv_done; struct timeval tv_pass; struct timeval tv_slept; struct timeval tv_test; struct timeval tv_path; tv_slept.tv_sec = 0; tv_slept.tv_usec = 0; reports = NULL; if ( time_start( &tv_pass ) != 0 ) { syslog( LOG_ERR, "time_start: %m" ); abort(); } /* always log the results of the first pass to history */ s->s_event = 1; for ( ;; ) { schedule( s ); if (( t = s->s_test ) == NULL ) { /* make sure that we wait enough between passes */ tv_done = tv_pass; if ( time_end( &tv_done ) != 0 ) { syslog( LOG_ERR, "time_end: %m" ); abort(); } if (( sl = s->s_tv_pass_minimum.tv_sec - tv_done.tv_sec ) > 0 ) { sleep( sl ); tv_slept.tv_sec += sl; } if (( sl = s->s_tv_pass_minimum.tv_usec - tv_done.tv_usec ) > 0 ) { usleep( sl ); tv_slept.tv_usec += sl; } /* positive report time */ if ( time_end( &tv_pass ) != 0 ) { syslog( LOG_ERR, "time_end: %m" ); abort(); } s->s_tv_pass = tv_pass; tv_slept.tv_sec += ( tv_slept.tv_usec / 1000000 ); tv_slept.tv_usec = ( tv_slept.tv_usec % 1000000 ); syslog( LOG_DEBUG, "pass %ld: %ld.%.6ld %lu.%.6lu", s->s_pass, tv_pass.tv_sec, tv_pass.tv_usec, tv_slept.tv_sec, tv_slept.tv_usec ); /* if there was an event, update history */ if ( s->s_event > 0 ) { if ( history_update( s ) != 0 ) { abort(); } s->s_event = 0; } tv_slept.tv_sec = 0; tv_slept.tv_usec = 0; if ( time_start( &tv_pass ) != 0 ) { syslog( LOG_ERR, "time_start: %m" ); abort(); } if ( publish( s ) != 0 ) { abort(); } /* check for dns every so many passes*/ if (( dns_pass > 0 ) && (( s->s_pass % dns_pass ) == 0 )) { if ( machines_no_dns != NULL ) { dns_event = 0; machine_dns_lookup(); if ( dns_event != 0 ) { s->s_event = 1; } } } /* only suppress the first pass reports */ nefu_suppress_reports = 0; } else { /* if test is up get time */ if (( t->t_status & T_DOWN_MASK ) == 0 ) { if ( time_start( &t->t_time_down ) != 0 ) { syslog( LOG_ERR, "time_start: %m" ); abort(); } } if (( r = report_create()) == NULL ) { syslog( LOG_ERR, "report_create: %m" ); abort(); } t->t_tested = s->s_pass; if ( time_start( &tv_test ) != 0 ) { syslog( LOG_ERR, "time_start: %m" ); abort(); } syslog( LOG_DEBUG, "START TEST %s", t->t_full_name ); switch ( (*t->t_test)( t, r )) { case T_UP: report_free( r ); if ( t->t_status != T_UP ) { test_update( T_UP, t, NULL, NULL ); s->s_event = 1; if ( publish( s ) != 0 ) { abort(); } } for ( path = s->s_tail; path != NULL; path = path->t_route_prev ) { if ( path->t_status != T_UP ) { test_update( T_UP, path, NULL, NULL ); s->s_event = 1; if ( publish( s ) != 0 ) { abort(); } } else { break; } } break; case T_DOWN: switch ( t->t_status ) { case T_DOWN: if ( report_compare( t->t_report, r ) != 0 ) { test_update( T_DOWN, t, r, NULL ); s->s_event = 1; if ( publish( s ) != 0 ) { abort(); } } else { report_free( r ); } break; case T_UP: case T_MAYBE_DOWN: test_update( T_DOWN, t, r, NULL ); s->s_event = 1; if ( publish( s ) != 0 ) { abort(); } } break; case T_MAYBE_DOWN: switch ( t->t_status ) { case T_MAYBE_DOWN: if ( report_compare( t->t_report, r ) == 0 ) { report_free( r ); break; } /* else "fall through" */ case T_DOWN: case T_UP: /* b check */ route = 1; /* assume its fine for now */ for ( path = s->s_head; path != NULL; path = path->t_route_next ) { /* skip all dependencies that don't have DNS */ if ( path->t_status == T_NO_DNS ) { continue; } /* get time before entering test, as should be up */ if ( time_start( &path->t_time_down ) != 0 ) { syslog( LOG_ERR, "time_start: %m" ); abort(); } if (( b = report_create()) == NULL ) { syslog( LOG_ERR, "report_create: %m" ); abort(); } path->t_tested = s->s_pass; if ( time_start( &tv_path ) != 0 ) { syslog( LOG_ERR, "time_start: %m" ); abort(); } syslog( LOG_DEBUG, "START PATH %s: %lu seconds", path->t_full_name, tv_path.tv_sec ); if (( result = (*path->t_test)( path, b )) != T_UP ) { test_update( result, path, b, NULL ); s->s_event = 1; if ( publish( s ) != 0 ) { abort(); } /* reschedule */ while ( s->s_tail != path ) { pop_route( s ); } pop_route( s ); s->s_test = path; /* set route down */ route = 0; break; } else { path->t_status = T_UP; report_free( b ); } if ( time_end( &tv_path ) != 0 ) { syslog( LOG_ERR, "time_end: %m" ); abort(); } syslog( LOG_DEBUG, "FINISHED PATH %s: %lu seconds", path->t_full_name, tv_path.tv_sec ); } if ( route == 0 ) { report_free( r ); } else { if (( b = report_create()) == NULL ) { syslog( LOG_ERR, "report_create: %m" ); abort(); } if ( time_start( &tv_path ) != 0 ) { syslog( LOG_ERR, "time_start: %m" ); abort(); } syslog( LOG_DEBUG, "START PATH %s", t->t_full_name ); switch( result = (*t->t_test)( t, b )) { case T_MAYBE_DOWN: if ( report_compare( b, r ) != 0 ) { test_update( T_MAYBE_DOWN, t, b, r ); s->s_event = 1; report_free( r ); if ( publish( s ) != 0 ) { abort(); } } else { test_update( T_MAYBE_DOWN, t, r, NULL ); s->s_event = 1; report_free( b ); if ( publish( s ) != 0 ) { abort(); } } break; case T_DOWN: case T_UP: if ( report( R_BOUNCE, t, r, NULL ) < 0 ) { syslog( LOG_ERR, "monitor: report failed: %m" ); abort(); } report_free( r ); if ( t->t_status != result ) { test_update( result, t, b, NULL ); s->s_event = 1; if ( publish( s ) != 0 ) { abort(); } } else { report_free( b ); } break; default : syslog( LOG_ERR, "monitor: result %d", result ); abort(); } if ( time_end( &tv_path ) != 0 ) { syslog( LOG_ERR, "time_end: %m" ); abort(); } syslog( LOG_DEBUG, "FINISHED PATH %s: %lu seconds", t->t_full_name, tv_path.tv_sec ); } } } if ( time_end( &tv_test ) != 0 ) { syslog( LOG_ERR, "time_end: %m" ); abort(); } syslog( LOG_DEBUG, "FINISHED TEST %s: %lu seconds", t->t_full_name, tv_test.tv_sec ); if ( s->s_tv_service_minimum.tv_sec > 0 ) { sleep( s->s_tv_service_minimum.tv_sec ); tv_slept.tv_sec += s->s_tv_service_minimum.tv_sec; } if ( s->s_tv_service_minimum.tv_usec > 0 ) { usleep( s->s_tv_service_minimum.tv_usec ); tv_slept.tv_usec += s->s_tv_service_minimum.tv_usec; } } } }