You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/kppp/pppstats.cpp

347 lines
7.7 KiB

/*
*
* $Id$
*
* History:
*
* Bernd Wuebben, wuebben@math.cornell.edu:
*
* Much of this is taken from the pppd sources in particular
* /pppstat/pppstat.c, and modified to suit the needs of kppp.
*
*
* Here the original history of pppstat.c:
*
* perkins@cps.msu.edu: Added compression statistics and alternate
* display. 11/94
*
* Brad Parker (brad@cayman.com) 6/92
*
* from the original "slstats" by Van Jaconson
*
* Copyright (c) 1989 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
* - Initial distribution.
*/
#include <config.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#ifdef __DragonFly__
#include <net/ppp_layer/ppp_defs.h>
#else
#include <net/ppp_defs.h>
#endif
#include "config.h"
#include "pppstats.h"
#ifndef STREAMS
#if defined(__linux__) && defined(__powerpc__) \
&& (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
/* kludge alert! */
#undef __GLIBC__
#endif
#include <sys/socket.h> /* *BSD, Linux, NeXT, Ultrix etc. */
#ifndef HAVE_NET_IF_PPP_H
#ifdef HAVE_LINUX_IF_PPP_H
#include <linux/if.h>
#ifndef aligned_u64
#define aligned_u64 unsigned long long __attribute__((aligned(8)))
#endif
#include <linux/if_ppp.h>
#elif defined(__DragonFly__)
#include <net/if.h>
#include <net/ppp/if_ppp.h>
#endif
#else
#include <net/if.h>
#include <net/if_ppp.h>
#endif
#else /* STREAMS */
#include <sys/socket.h>
#include <sys/stropts.h> /* SVR4, Solaris 2, SunOS 4, OSF/1, etc. */
#include <net/ppp_defs.h>
#include <net/pppio.h>
#include <net/if.h>
#include <sys/sockio.h>
#endif /* STREAMS */
#include <tqtimer.h>
#include <kdebug.h>
PPPStats::PPPStats()
{
clear();
timer = new TQTimer;
connect(timer, TQT_SIGNAL(timeout()), TQT_SLOT(timerClick()));
}
PPPStats::~PPPStats() {
stop();
delete timer;
}
void PPPStats::clear()
{
ibytes = 0;
ipackets = 0;
ibytes_last = 0;
obytes_last = 0;
compressedin = 0;
uncompressedin = 0;
errorin = 0;
obytes = 0;
opackets = 0;
compressed = 0;
packetsunc = 0;
packetsoutunc = 0;
iotqStatus = BytesNone;
}
void PPPStats::timerClick() {
enum IOtqStatus newtqStatus;
doStats();
if((ibytes != ibytes_last) && (obytes != obytes_last))
newtqStatus = BytesBoth;
else if(ibytes != ibytes_last)
newtqStatus = BytesIn;
else if(obytes != obytes_last)
newtqStatus = BytesOut;
else
newtqStatus = BytesNone;
if(newtqStatus != iotqStatus)
emit statsChanged(iotqStatus = newtqStatus);
ibytes_last = ibytes;
obytes_last = obytes;
}
void PPPStats::setUnit(int u) {
unit = u;
sprintf(unitName, "ppp%d", unit);
}
void PPPStats::start() {
timer->start(PPP_STATS_INTERVAL);
}
void PPPStats::stop() {
emit statsChanged(BytesNone);
timer->stop();
}
bool PPPStats::ifIsUp() {
bool is_up;
struct ifreq ifr;
#if defined(__svr4__ )
usleep(1000000); // Needed for Solaris ?!
#endif
#ifdef STREAMS
if ((t = open("/dev/ppp", O_RDONLY)) < 0) {
perror("pppstats: Couldn't open /dev/ppp: ");
return false;
}
if (!strioctl(t, PPPIO_ATTACH, (char*)&unit, sizeof(int), 0)) {
fprintf(stderr, "pppstats: ppp%d is not available\n", unit);
::close(t);
return false;
}
// TODO: close t somewhere again
#endif
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("Couldn't create IP socket");
return false;
}
strlcpy(ifr.ifr_name, unitName, sizeof(ifr.ifr_name));
if(ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
if (errno)
fprintf(stderr, "Couldn't find interface %s: %s\n",
unitName, strerror(errno));
::close(s);
s = 0;
return 0;
}
if ((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING)) {
is_up = true;
kdDebug(5002) << "Interface is up" << endl;
}
else{
is_up = false;
::close(s);
s = 0;
kdDebug(5002) << "Interface is down" << endl;
}
return is_up;
}
bool PPPStats::initStats() {
struct sockaddr_in *sinp;
struct ifreq ifr;
clear();
strlcpy(ifr.ifr_name, unitName, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
}
sinp = (struct sockaddr_in*)&ifr.ifr_addr;
if(sinp->sin_addr.s_addr)
local_ip_address = inet_ntoa(sinp->sin_addr);
else
local_ip_address = "";
kdDebug(5002) << "Local IP: " << local_ip_address << endl;
(void) ioctl(s, SIOCGIFDSTADDR, &ifr);
sinp = (struct sockaddr_in*)&ifr.ifr_dstaddr;
if(sinp->sin_addr.s_addr)
remote_ip_address = inet_ntoa(sinp->sin_addr);
else
remote_ip_address = "";
kdDebug(5002) << "Remote IP: " << remote_ip_address << endl;
return true;
}
bool PPPStats::doStats() {
struct ppp_stats cur;
if(! get_ppp_stats(&cur)){
return false;
}
// "in" "pack" "comp" "uncomp" "err"
// IN PACK VJCOMP VJUNC VJERR
ibytes = cur.p.ppp_ibytes; // bytes received
ipackets = cur.p.ppp_ipackets; // packets recieved
compressedin = cur.vj.vjs_compressedin; // inbound compressed packets
uncompressedin = cur.vj.vjs_uncompressedin; // inbound uncompressed packets
errorin = cur.vj.vjs_errorin; //receive errors
// "out" "pack" "comp" "uncomp" "ip"
// OUT PACK JCOMP VJUNC NON-VJ
obytes = cur.p.ppp_obytes; // raw bytes sent
opackets = cur.p.ppp_opackets; // packets sent
compressed = cur.vj.vjs_compressed; //outbound compressed packets
// outbound packets - outbound compressed packets
packetsunc = cur.vj.vjs_packets - cur.vj.vjs_compressed;
// packets sent - oubount compressed
packetsoutunc = cur.p.ppp_opackets - cur.vj.vjs_packets;
return true;
}
#ifndef STREAMS
bool PPPStats::get_ppp_stats(struct ppp_stats *curp){
struct ifpppstatsreq req;
if(s==0)
return false;
#ifdef __linux__
req.stats_ptr = (caddr_t) &req.stats;
sprintf(req.ifr__name, "ppp%d", unit);
#else
sprintf(req.ifr_name, "ppp%d", unit);
#endif
if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
if (errno == ENOTTY)
fprintf(stderr, "pppstats: kernel support missing\n");
else
perror("ioctl(SIOCGPPPSTATS)");
return false;
}
*curp = req.stats;
return true;
}
#else /* STREAMS */
bool PPPStats::get_ppp_stats( struct ppp_stats *curp){
if (!strioctl(t, PPPIO_GETSTAT, (char*)curp, 0, sizeof(*curp))) {
if (errno == EINVAL)
fprintf(stderr, "pppstats: kernel support missing\n");
else
perror("pppstats: Couldn't get statistics");
return false;
}
return true;
}
bool PPPStats::strioctl(int fd, int cmd, char* ptr, int ilen, int olen){
struct strioctl str;
str.ic_cmd = cmd;
str.ic_timout = 0;
str.ic_len = ilen;
str.ic_dp = ptr;
if (ioctl(fd, I_STR, &str) == -1)
return false;
if (str.ic_len != olen)
fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
olen, str.ic_len, cmd);
return true;
}
#endif /* STREAMS */
#include "pppstats.moc"