// pppload - A PPP Load Monitor
// Copyright (C) 1996  Sean Vyain
// svyain@mail.tds.net
// smvyain@softart.com
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

extern "C" {
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <linux/ppp_defs.h>
}

#include "PPPStats.H"
#include "Options.H"

typedef struct
{
  struct ppp_stats  stats;
} DclPPPInfo;

PPPStats::PPPStats()
: _rxTotal( 0 ), _txTotal( 0 ), _isUp( true ), _retryId( -1 )
{
	if ((_s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("couldn't create IP socket");
        exit(1);
    }

	startTimer( options->interval() * 1000 );
}

void PPPStats::timerEvent( QTimerEvent* e )
{
	if ( e->timerId() == _retryId )
	{
		system( (const char*)options->cmd() );
	}
	
	DclPPPInfo        PPPInfo[1];
	struct ifreq      ifreq;
	struct ppp_stats* PPPStat;
	struct ppp_stats  LastPPPStat[1];
	
	memset (& ifreq, 0, sizeof (ifreq));
	sprintf (ifreq.ifr_ifrn.ifrn_name, "ppp%d", options->link());
	
	ifreq.ifr_ifru.ifru_data = (caddr_t) PPPInfo;
	PPPStat = & PPPInfo->stats;
	memset (LastPPPStat, 0, sizeof (LastPPPStat));
	
	if ( (ioctl (_s, SIOCDEVPRIVATE, (caddr_t) & ifreq) < 0) ||
		( _isUp && ( PPPStat->p.ppp_ibytes < _rxTotal ) ) ||
		( !_isUp && ( PPPStat->p.ppp_ibytes == 0 ) )
		) {
		if ( _isUp ) {
			_isUp = false;
			emit linkDown();
			if ( options->cmd().length() ) {
				_retryId = startTimer( options->retry() * 1000 );
				system( (const char*)options->cmd() );
			}
		}
		PPPStat->p.ppp_ibytes = 0;
		PPPStat->p.ppp_obytes = 0;
	} else if ( !_isUp ) {
		_isUp = true;
		killTimer( _retryId );
		_retryId = -1;
	}

	unsigned int rxDelta = PPPStat->p.ppp_ibytes - _rxTotal;
	unsigned int txDelta = PPPStat->p.ppp_obytes - _txTotal;
	_rxTotal = PPPStat->p.ppp_ibytes;
	_txTotal = PPPStat->p.ppp_obytes;
	if ( rxDelta == _rxTotal ) rxDelta = 0;
	if ( txDelta == _txTotal ) txDelta = 0;
	emit changeStats( rxDelta, txDelta, _rxTotal, _txTotal );
}
