diff --git a/src/conky.cc b/src/conky.cc index ae505f37..8370936d 100644 --- a/src/conky.cc +++ b/src/conky.cc @@ -281,7 +281,7 @@ static void print_version(void) #endif /* BUILD_MYSQL */ #ifdef BUILD_WEATHER_METAR << _(" * Weather (METAR)\n") -#endif /* BUILD_WEATHER_METAR */ +#endif /* BUILD_WEATHER_METAR */ #ifdef BUILD_WEATHER_XOAP << _(" * Weather (XOAP)\n") #endif /* BUILD_WEATHER_XOAP */ @@ -2007,7 +2007,7 @@ static void clear_text(int exposures) /* there is some extra space for borders and outlines */ int border_total = get_border_total(); - XClearArea(display, window.window, text_start_x - border_total, + XClearArea(display, window.window, text_start_x - border_total, text_start_y - border_total, text_width + 2*border_total, text_height + 2*border_total, exposures ? True : 0); } @@ -2142,7 +2142,7 @@ static void main_loop(void) XFreePixmap(display, window.back_buffer); window.back_buffer = XCreatePixmap(display, window.window, window.width, window.height, DefaultDepth(display, screen)); - + if (window.back_buffer != None) { window.drawable = window.back_buffer; } else { @@ -2721,7 +2721,7 @@ void load_config_file() l.replace(-2); if(l.type(-1) != lua::TSTRING) throw conky::error(_("missing text block in configuration")); - + /* Remove \\-\n. */ l.gsub(l.tocstring(-1), "\\\n", ""); l.replace(-2); @@ -2878,6 +2878,7 @@ void set_current_config() { void initialisation(int argc, char **argv) { struct sigaction act, oact; + clear_net_stats(); set_default_configurations(); set_current_config(); @@ -3063,7 +3064,6 @@ int main(int argc, char **argv) argc_copy = argc; argv_copy = argv; g_signal_pending = 0; - clear_net_stats(); #ifdef BUILD_CURL struct curl_global_initializer { diff --git a/src/linux.cc b/src/linux.cc index 3b814947..0550e38b 100644 --- a/src/linux.cc +++ b/src/linux.cc @@ -367,10 +367,24 @@ void print_gateway_ip(struct text_object *obj, char *p, int p_max_size) snprintf(p, p_max_size, "%s", gw_info.ip); } + +/** + * Parses information from /proc/net/dev and stores them in ??? + * + * For the output format of /proc/net/dev @see http://linux.die.net/man/5/proc + * + * @return always returns 0. May change in the future, e.g. returning non zero + * if some error happened + **/ int update_net_stats(void) { FILE *net_dev_fp; static int rep = 0; + /* variably to notify the parts averaging the download speed, that this + * is the first call ever to this function. This variable can't be used + * to decide if this is the first time an interface was parsed as there + * are many interfaces, which can be activated and deactivated at arbitrary + * times */ static char first = 1; // FIXME: arbitrary size chosen to keep code simple. @@ -394,12 +408,15 @@ int update_net_stats(void) return 0; } - /* open file and ignore first two lines */ + /* open file /proc/net/dev. If not something went wrong, clear all + * network statistics */ if (!(net_dev_fp = open_file("/proc/net/dev", &rep))) { clear_net_stats(); return 0; } - + /* ignore first two header lines in file /proc/net/dev. If somethings + * goes wrong, e.g. end of file reached, quit. + * (Why isn't clear_net_stats called for this case ??? */ if (!fgets(buf, 255, net_dev_fp) || /* garbage */ !fgets(buf, 255, net_dev_fp)) { /* garbage (field names) */ fclose(net_dev_fp); @@ -413,48 +430,68 @@ int update_net_stats(void) char temp_addr[18]; long long r, t, last_recv, last_trans; + /* quit only after all non-header lines from /proc/net/dev parsed */ if (fgets(buf, 255, net_dev_fp) == NULL) { break; } p = buf; - while (isspace((int) *p)) { + /* change char * p to first non-space character, which is the beginning + * of the interface name */ + while (*p != '\0' && isspace((int) *p)) { p++; } s = p; - while (*p && *p != ':') { + /* increment p until the end of the interface name has been reached */ + while (*p != '\0' && *p != ':') { p++; } if (*p == '\0') { continue; } + /* replace ':' with '\0' in output of /proc/net/dev */ *p = '\0'; p++; + /* get pointer to interface statistics with the interface name in s */ ns = get_net_stat(s, NULL, NULL); ns->up = 1; memset(&(ns->addr.sa_data), 0, 14); memset(ns->addrs, 0, 17 * MAX_NET_INTERFACES + 1); /* Up to 17 chars per ip, max MAX_NET_INTERFACES interfaces. Nasty memory usage... */ - last_recv = ns->recv; - last_trans = ns->trans; - /* bytes packets errs drop fifo frame compressed multicast|bytes ... */ sscanf(p, "%lld %*d %*d %*d %*d %*d %*d %*d %lld", &r, &t); - /* if recv or trans is less than last time, an overflow happened */ + /* if the interface is parsed the first time, then set recv and trans + * to currently received, meaning the change in network traffic is 0 */ + if (ns->last_read_recv == -1) { + ns->recv = r; + first = 1; + } + if (ns->last_read_trans == -1) { + ns->trans = t; + first = 1; + } + /* move current traffic statistic to last thereby obsoleting the + * current statistic */ + last_recv = ns->recv; + last_trans = ns->trans; + + /* If recv or trans is less than last time, an overflow happened. + * In that case set the last traffic to the current one, don't set + * it to 0, else a spike in the download and upload speed will occur! */ if (r < ns->last_read_recv) { - last_recv = 0; + last_recv = r; } else { ns->recv += (r - ns->last_read_recv); } ns->last_read_recv = r; if (t < ns->last_read_trans) { - last_trans = 0; + last_trans = t; } else { ns->trans += (t - ns->last_read_trans); } @@ -490,19 +527,19 @@ int update_net_stats(void) close((long) i); free(conf.ifc_buf); - /*** end ip addr patch ***/ if (!first) { - /* calculate speeds */ - ns->net_rec[0] = (ns->recv - last_recv) / delta; + /* calculate instantenous speeds */ + ns->net_rec [0] = (ns->recv - last_recv ) / delta; ns->net_trans[0] = (ns->trans - last_trans) / delta; } curtmp1 = 0; curtmp2 = 0; - // get an average + /* get an average over the last speed samples */ int samples = net_avg_samples.get(*state); + /* is OpenMP actually useful here? How large is samples? > 1000 ? */ #ifdef HAVE_OPENMP #pragma omp parallel for reduction(+:curtmp1, curtmp2) schedule(dynamic,10) #endif /* HAVE_OPENMP */ diff --git a/src/net_stat.cc b/src/net_stat.cc index 85446ef9..ec53586a 100644 --- a/src/net_stat.cc +++ b/src/net_stat.cc @@ -58,9 +58,19 @@ conky::lua_traits::Map conky::lua_traits:: static conky::simple_config_setting if_up_strictness("if_up_strictness", IFUP_UP, true); - +/** + * global array of structs containing network statistics for each interface + **/ struct net_stat netstats[MAX_NET_INTERFACES]; +/** + * Returns pointer to specified interface in netstats array. + * If not found then add the specified interface to the array. + * The added interface will have all its members initialized to 0, + * because clear_net_stats() is called from main() in conky.cc! + * + * @param[in] dev device / interface name. Silently ignores char * == NULL + **/ struct net_stat *get_net_stat(const char *dev, void *free_at_crash1, void *free_at_crash2) { unsigned int i; @@ -80,6 +90,10 @@ struct net_stat *get_net_stat(const char *dev, void *free_at_crash1, void *free_ for (i = 0; i < MAX_NET_INTERFACES; i++) { if (netstats[i].dev == 0) { netstats[i].dev = strndup(dev, text_buffer_size.get(*state)); + /* initialize last_read_recv and last_read_trans to -1 denoting + * that they were never read before */ + netstats[i].last_read_recv = -1; + netstats[i].last_read_trans = -1; return &netstats[i]; } } @@ -415,6 +429,11 @@ double wireless_link_barval(struct text_object *obj) } #endif /* BUILD_WLAN */ + +/** + * Clears the global array of net_stat structs which contains networks + * statistics for every interface. + **/ void clear_net_stats(void) { #ifdef BUILD_IPV6 diff --git a/src/net_stat.h b/src/net_stat.h index cde1af31..a57875bc 100644 --- a/src/net_stat.h +++ b/src/net_stat.h @@ -43,30 +43,43 @@ struct v6addr { #endif /* BUILD_IPV6 */ struct net_stat { - char *dev; - int up; - long long last_read_recv, last_read_trans; - long long recv, trans; - double recv_speed, trans_speed; - struct sockaddr addr; + /* interface name, e.g. wlan0, eth0, ... */ + char *dev; + /* set to 1, if interface is up */ + int up; + /* network traffic read on last call in order to calculate how much + * was received or transmitted since the last call. contains -1 if + * it was never read before. in bytes */ + long long last_read_recv, last_read_trans; + /* total received and transmitted data statistics in bytes */ + long long recv, trans; + /* averaged network speed in bytes / second */ + double recv_speed, trans_speed; + /* struct with at least the member sa_data which is a const * containing + * the socket address. + * @see http://pubs.opengroup.org/onlinepubs/7908799/xns/syssocket.h.html */ + struct sockaddr addr; #ifdef BUILD_IPV6 - struct v6addr *v6addrs; + struct v6addr *v6addrs; bool v6show_nm; bool v6show_sc; #endif /* BUILD_IPV6 */ #if defined(__linux__) - char addrs[17 * MAX_NET_INTERFACES + 1]; + char addrs[17 * MAX_NET_INTERFACES + 1]; #endif /* __linux__ */ - double net_rec[15], net_trans[15]; - // wireless extensions - char essid[32]; - int channel; - char freq[16]; - char bitrate[16]; - char mode[16]; - int link_qual; - int link_qual_max; - char ap[18]; + /* network speeds between two conky calls in bytes per second. + * An average over these samples is calculated in recv_speed and + * trans_speed */ + double net_rec[15], net_trans[15]; + // wireless extensions + char essid[32]; + int channel; + char freq[16]; + char bitrate[16]; + char mode[16]; + int link_qual; + int link_qual_max; + char ap[18]; }; extern struct net_stat netstats[];