/* backend.c
*
* 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Netspeed Applet was writen by Jörgen Scheibengruber <mfcn@gmx.de>
*/
#include <config.h>
#include <glibtop/netlist.h>
#include <glibtop/netload.h>
#include <net/if_media.h>
#include "backend.h"
/* Check for all available devices. This really should be
* portable for at least all plattforms using the gnu c lib
*/
GList*
get_available_devices(void)
{
glibtop_netlist buf;
char **devices, **dev, *prev = "";
GList *device_glist = NULL;
devices = glibtop_get_netlist(&buf);
/* TODO: I assume that duplicates follow each other. Can I do so? */
for(dev = devices; *dev; ++dev) {
if (strcmp(prev, *dev) == 0) continue;
device_glist = g_list_append(device_glist, g_strdup(*dev));
prev = *dev;
}
g_strfreev(devices);
return device_glist;
}
const gchar*
get_default_route(void)
{
FILE *fp;
static char device[50];
fp = fopen("/proc/net/route", "r");
if (fp == NULL) return NULL;
while (!feof(fp)) {
char buffer[1024];
unsigned int ip, gw, flags, ref, use, metric, mask, mtu, window, irtt;
int retval;
fgets(buffer, 1024, fp);
retval = sscanf(buffer, "%49s %x %x %x %d %d %d %x %d %d %d",
device, &ip, &gw, &flags, &ref, &use, &metric, &mask, &mtu, &window, &irtt);
if (retval != 11) continue;
if (gw == 0) {
fclose(fp);
return device;
}
}
fclose(fp);
return NULL;
}
void
free_devices_list(GList *list)
{
g_list_foreach(list, (GFunc)g_free, NULL);
g_list_free(list);
}
/* Frees a DevInfo struct and all the stuff it contains
*/
void
free_device_info(DevInfo *devinfo)
{
g_free(devinfo->name);
g_free(devinfo->ip);
g_free(devinfo->netmask);
g_free(devinfo->ptpip);
g_free(devinfo->hwaddr);
g_free(devinfo->ipv6);
}
static char*
format_ipv4(guint32 ip)
{
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &ip, str, sizeof str);
return g_strdup(str);
}
static char*
format_ipv6(const guint8 ip[16])
{
char str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, ip, str, sizeof str);
return g_strdup(str);
}
/* TODO:
these stuff are not portable because of ioctl
*/
static void
get_additional_info(DevInfo *devinfo)
{
int fd = -1;
struct ifreq request = {};
g_strlcpy(request.ifr_name, devinfo->name, sizeof request.ifr_name);
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
goto out;
if (ioctl(fd, SIOCGIFFLAGS, &request) == -1)
goto out;
/* Check if the device is a ptp and if this is the
* case, get the ptp-ip */
devinfo->ptpip = NULL;
if (request.ifr_flags & IFF_POINTOPOINT) {
if (ioctl(fd, SIOCGIFDSTADDR, &request) >= 0) {
struct sockaddr_in* addr;
addr = (struct sockaddr_in*)&request.ifr_dstaddr;
devinfo->ptpip = format_ipv4(addr->sin_addr.s_addr);
}
}
if (devinfo->type == DEV_UNKNOWN) {
struct ifmediareq ifmr;
memset(&ifmr, 0, sizeof(ifmr));
g_strlcpy(ifmr.ifm_name, devinfo->name, sizeof(ifmr.ifm_name));
if (ioctl(fd, SIOCGIFMEDIA, &ifmr) >= 0) {
switch (IFM_TYPE(ifmr.ifm_current)) {
case IFM_ETHER: devinfo->type = DEV_ETHERNET; break;
case IFM_IEEE80211: devinfo->type = DEV_WIRELESS; break;
}
}
}
out:
if(fd != -1)
close(fd);
}
DevInfo
get_device_info(const char *device)
{
glibtop_netload netload;
DevInfo devinfo = {0};
guint8 *hw;
g_assert(device);
devinfo.name = g_strdup(device);
devinfo.type = DEV_UNKNOWN;
glibtop_get_netload(&netload, device);
devinfo.tx = netload.bytes_out;
devinfo.rx = netload.bytes_in;
devinfo.up = (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_UP) ? TRUE : FALSE);
devinfo.running = (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_RUNNING) ? TRUE : FALSE);
devinfo.ip = format_ipv4(netload.address);
devinfo.netmask = format_ipv4(netload.subnet);
devinfo.ipv6 = format_ipv6(netload.address6);
hw = netload.hwaddress;
devinfo.hwaddr = g_strdup_printf(
"%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
hw[0], hw[1], hw[2], hw[3],
hw[4], hw[5], hw[6], hw[7]);
/* stolen from gnome-applets/multiload/linux-proc.c */
if(netload.if_flags & (1L << GLIBTOP_IF_FLAGS_LOOPBACK)) {
devinfo.type = DEV_LO;
}
else if(netload.if_flags & (1L << GLIBTOP_IF_FLAGS_POINTOPOINT)) {
if (g_str_has_prefix(device, "plip")) {
devinfo.type = DEV_PLIP;
}
else if (g_str_has_prefix(device, "sl")) {
devinfo.type = DEV_SLIP;
}
else {
devinfo.type = DEV_PPP;
}
}
get_additional_info(&devinfo);
return devinfo;
}
gboolean
compare_device_info(const DevInfo *a, const DevInfo *b)
{
g_assert(a && b);
g_assert(a->name && b->name);
if (!g_str_equal(a->name, b->name)) return TRUE;
if (a->ip && b->ip) {
if (!g_str_equal(a->ip, b->ip)) return TRUE;
} else {
if (a->ip || b->ip) return TRUE;
}
/* Ignore hwaddr, ptpip and netmask... I think this is ok */
if (a->up != b->up) return TRUE;
if (a->running != b->running) return TRUE;
return FALSE;
}
syntax highlighted by Code2HTML, v. 0.9.1