From 77a1a6a43d61af9bc882e75880213a60a183f69c Mon Sep 17 00:00:00 2001 From: Martin Baulig Date: Mon, 24 Jan 2000 01:42:32 +0000 Subject: [PATCH] `address' and `subnet' are now arrays of GLIBTOP_IFADDR_LEN u_int8_t 2000-01-24 Martin Baulig * include/glibtop/netinfo.h (glibtop_netinfo): `address' and `subnet' are now arrays of GLIBTOP_IFADDR_LEN u_int8_t values. (glibtop_get_netinfo): `transport' is now `u_int64_t' and not `unsigned' to make it work with `GLIBTOP_TRANSPORT_ALL'. * include/glibtop/limits.h (GLIBTOP_IFADDR_LEN): New constant. This is the length of a network interface address in bytes. --- ChangeLog | 10 +++ features.def | 2 +- include/glibtop/limits.h | 3 + include/glibtop/netinfo.h | 16 ++-- sysdeps/linux/netinfo.c | 156 ++++++++++++++++++++++++++++++++++++-- 5 files changed, 170 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6f2caccc..deebd067 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2000-01-24 Martin Baulig + + * include/glibtop/netinfo.h (glibtop_netinfo): `address' and + `subnet' are now arrays of GLIBTOP_IFADDR_LEN u_int8_t values. + (glibtop_get_netinfo): `transport' is now `u_int64_t' and not + `unsigned' to make it work with `GLIBTOP_TRANSPORT_ALL'. + + * include/glibtop/limits.h (GLIBTOP_IFADDR_LEN): New constant. + This is the length of a network interface address in bytes. + 2000-01-24 Martin Baulig * libgtop-sysdeps.m4 (GNOME_LIBGTOP_TYPES_PRIVATE): New macro. diff --git a/features.def b/features.def index 9202d5bd..cfab348d 100644 --- a/features.def +++ b/features.def @@ -19,6 +19,6 @@ array(glibtop_map_entry)|proc_map|array|pid_t(pid) array(glibtop_mountentry)|@mountlist|array|int(all_fs) retval|@fsusage|ulong(blocks,bfree,bavail,files,ffree)|string(mount_dir) array(glibtop_interface)|interface_names|array|ulong(interface,number,instance,strategy) -retval|netinfo|ulong(if_flags,transport,mtu,subnet,address)|string(interface):unsigned(transport) +retval|netinfo|ulong(if_flags,transport,mtu,subnet[GLIBTOP_IFADDR_LEN],address[GLIBTOP_IFADDR_LEN])|string(interface):ulong(transport) retval|netload|ulong(packets_in,packets_out,packets_total,bytes_in,bytes_out,bytes_total,errors_in,errors_out,errors_total,collisions)|string(interface):unsigned(transport,protocol) retval|ppp|ulong(state,bytes_in,bytes_out)|ushort(device,use_isdn):string(lockfile) diff --git a/include/glibtop/limits.h b/include/glibtop/limits.h index 45ab0206..9596ea3b 100644 --- a/include/glibtop/limits.h +++ b/include/glibtop/limits.h @@ -42,6 +42,9 @@ BEGIN_LIBGTOP_DECLS /* Maximum length of a network interface name. */ #define GLIBTOP_INTERFACE_LEN 32 +/* Length of a network interface address in bytes. */ +#define GLIBTOP_IFADDR_LEN 16 + /* This is ((u_int64_t)-1) */ #define GLIBTOP_UNLIMITED (~(u_int64_t)0) diff --git a/include/glibtop/netinfo.h b/include/glibtop/netinfo.h index 4800746a..2ca45913 100644 --- a/include/glibtop/netinfo.h +++ b/include/glibtop/netinfo.h @@ -46,11 +46,11 @@ typedef struct _glibtop_netinfo glibtop_netinfo; struct _glibtop_netinfo { u_int64_t flags, - if_flags, /* GLIBTOP_NETINFO_IF_FLAGS */ - transport, /* GLIBTOP_NETINFO_TRANSPORT */ - mtu, /* GLIBTOP_NETINFO_MTU */ - subnet, /* GLIBTOP_NETINFO_SUBNET */ - address; /* GLIBTOP_NETINFO_ADDRESS */ + if_flags, /* GLIBTOP_NETINFO_IF_FLAGS */ + transport, /* GLIBTOP_NETINFO_TRANSPORT */ + mtu; /* GLIBTOP_NETINFO_MTU */ + u_int8_t subnet [GLIBTOP_IFADDR_LEN],/* GLIBTOP_NETINFO_SUBNET */ + address [GLIBTOP_IFADDR_LEN]; /* GLIBTOP_NETINFO_ADDRESS */ }; #define glibtop_get_netinfo(netinfo,interface,transport) glibtop_get_netinfo_l(glibtop_global_server, netinfo, interface, transport) @@ -61,14 +61,14 @@ struct _glibtop_netinfo #define glibtop_get_netinfo_r glibtop_get_netinfo_s #endif -int glibtop_get_netinfo_l (glibtop *server, glibtop_netinfo *buf, const char *interface, unsigned transport); +int glibtop_get_netinfo_l (glibtop *server, glibtop_netinfo *buf, const char *interface, u_int64_t transport); #if GLIBTOP_SUID_NETINFO int glibtop_init_netinfo_p (glibtop *server); -int glibtop_get_netinfo_p (glibtop *server, glibtop_netinfo *buf, const char *interface, unsigned transport); +int glibtop_get_netinfo_p (glibtop *server, glibtop_netinfo *buf, const char *interface, u_int64_t transport); #else int glibtop_init_netinfo_s (glibtop *server); -int glibtop_get_netinfo_s (glibtop *server, glibtop_netinfo *buf, const char *interface, unsigned transport); +int glibtop_get_netinfo_s (glibtop *server, glibtop_netinfo *buf, const char *interface, u_int64_t transport); #endif #ifdef GLIBTOP_NAMES diff --git a/sysdeps/linux/netinfo.c b/sysdeps/linux/netinfo.c index db7593ae..58175f1f 100644 --- a/sysdeps/linux/netinfo.c +++ b/sysdeps/linux/netinfo.c @@ -31,6 +31,18 @@ #include #include +#include + +#ifndef HAVE_AFINET +#define HAVE_AFINET 1 +#endif + +#ifndef HAVE_AFINET6 +#define HAVE_AFINET6 1 +#endif + +#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6" + #if !defined (_LIBC) && defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 /* GNU LibC */ #include @@ -50,6 +62,7 @@ #endif static const unsigned long _glibtop_sysdeps_netinfo = +(1L << GLIBTOP_NETINFO_TRANSPORT) + (1L << GLIBTOP_NETINFO_IF_FLAGS) + (1L << GLIBTOP_NETINFO_ADDRESS) + (1L << GLIBTOP_NETINFO_SUBNET) + @@ -65,21 +78,22 @@ glibtop_init_netinfo_s (glibtop *server) return 0; } -/* Provides network statistics. */ +#ifdef HAVE_AFINET -int -glibtop_get_netinfo_s (glibtop *server, glibtop_netinfo *buf, - const char *interface, unsigned transport) +static int +_netinfo_ipv4 (glibtop *server, glibtop_netinfo *buf, + const char *interface) { int skfd; - memset (buf, 0, sizeof (glibtop_netinfo)); - skfd = socket (AF_INET, SOCK_DGRAM, 0); if (skfd) { struct ifreq ifr; unsigned flags; + buf->transport = GLIBTOP_TRANSPORT_IPV4; + buf->flags |= (1L << GLIBTOP_NETINFO_TRANSPORT); + strcpy (ifr.ifr_name, interface); if (!ioctl (skfd, SIOCGIFFLAGS, &ifr)) { buf->flags |= (1L << GLIBTOP_NETINFO_IF_FLAGS); @@ -121,7 +135,7 @@ glibtop_get_netinfo_s (glibtop *server, glibtop_netinfo *buf, if (!ioctl (skfd, SIOCGIFADDR, &ifr)) { struct sockaddr_in addr = *(struct sockaddr_in *) &ifr.ifr_addr; - buf->address = addr.sin_addr.s_addr; + memcpy (&buf->address, &addr.sin_addr.s_addr, 4); buf->flags |= (1L << GLIBTOP_NETINFO_ADDRESS); } @@ -129,7 +143,7 @@ glibtop_get_netinfo_s (glibtop *server, glibtop_netinfo *buf, if (!ioctl (skfd, SIOCGIFNETMASK, &ifr)) { struct sockaddr_in addr = *(struct sockaddr_in *) &ifr.ifr_addr; - buf->subnet = addr.sin_addr.s_addr; + memcpy (&buf->subnet, &addr.sin_addr.s_addr, 4); buf->flags |= (1L << GLIBTOP_NETINFO_SUBNET); } @@ -144,3 +158,129 @@ glibtop_get_netinfo_s (glibtop *server, glibtop_netinfo *buf, return 0; } + +#endif /* HAVE_AFINET */ + +#ifdef HAVE_AFINET6 + +static int +_parse_ipv6_address (const char *addr_string, u_int8_t *dest) +{ + int i; + + if (strlen (addr_string) != 32) + return -1; + + for (i = 0; i < 8; i++) { + char c1, c2; + int d1, d2; + + c1 = tolower (addr_string [(i<<1)]); + c2 = tolower (addr_string [(i<<1)+1]); + + if ((c1 >= '0') && (c1 <= '9')) + d1 = c1-'0'; + else if ((c1 >= 'a') && (c1 <= 'f')) + d1 = c1-'a'+10; + else + return -1; + + if ((c2 >= '0') && (c2 <= '9')) + d2 = c2-'0'; + else if ((c2 >= 'a') && (c2 <= 'f')) + d2 = c2-'a'+10; + else + return -1; + + dest [i] = (d1 << 4) + d2; + } + + return 0; +} + +static int +_netinfo_ipv6 (glibtop *server, glibtop_netinfo *buf, + const char *interface) +{ + FILE *f; + char addr6[40], devname[20]; + struct sockaddr_in6 sap; + int plen, scope, dad_status, if_idx; + extern struct aftype inet6_aftype; + + if ((f = fopen (_PATH_PROCNET_IFINET6, "r")) != NULL) { + while (fscanf (f, "%64s %02x %02x %02x %02x %20s\n", + addr6, &if_idx, &plen, &scope, &dad_status, + devname) != EOF) { + if (strcmp (devname, interface)) + continue; + + if (!_parse_ipv6_address (addr6, buf->address)) + buf->flags |= (1L << GLIBTOP_NETINFO_ADDRESS); + + break; + } + } + + return 0; +} + +#endif /* HAVE_AFINET6 */ + +/* Provides network statistics. */ + +int +glibtop_get_netinfo_s (glibtop *server, glibtop_netinfo *buf, + const char *interface, u_int64_t transport) +{ + memset (buf, 0, sizeof (glibtop_netinfo)); + + if (strlen (interface) >= GLIBTOP_INTERFACE_LEN) + return -1; + + /* Assume IPv4 is the standard until IPv6 becomes more popular. */ + if (transport == GLIBTOP_TRANSPORT_DEFAULT) + transport = GLIBTOP_TRANSPORT_ALL; + + /* Get information about all possible transport methods. */ + if (transport == GLIBTOP_TRANSPORT_ALL) { + char buffer [BUFSIZ]; + struct stat statb; + + /* We may get a little speed improvement when we use sysctl () + * directly, but the following piece of code seems very stable + * and reliable to me. + * + * The first stat() on "/proc/sys/net" is done to find out whether + * the kernel has sysctl support. + * + * January 23, 1999 + * Martin + */ + + if (!stat ("/proc/sys/net", &statb) && S_ISDIR (statb.st_mode)) { + buf->flags |= (1L << GLIBTOP_NETINFO_TRANSPORT); + + sprintf (buffer, "/proc/sys/net/ipv4/conf/%s", interface); + if (!stat (buffer, &statb) && S_ISDIR (statb.st_mode)) + buf->transport |= GLIBTOP_TRANSPORT_IPV4; + + sprintf (buffer, "/proc/sys/net/ipv6/conf/%s", interface); + if (!stat (buffer, &statb) && S_ISDIR (statb.st_mode)) + buf->transport |= GLIBTOP_TRANSPORT_IPV6; + } + } + + switch (transport) { +#ifdef HAVE_AFINET + case GLIBTOP_TRANSPORT_IPV4: + return _netinfo_ipv4 (server, buf, interface); +#endif /* HAVE_AFINET */ +#ifdef HAVE_AFINET6 + case GLIBTOP_TRANSPORT_IPV6: + return _netinfo_ipv6 (server, buf, interface); +#endif /* HAVE_AFINET6 */ + } + + return 0; +}