/** * Updates the horizon statistics in the statusbar. * * This is an event-driven callback called from the HSEP code * using the event listener framework. In addition to taking into account * the HSEP information, the number of established non-HSEP nodes and * their library size (if provided) are added to the values displayed. */ void gnet_stats_gui_horizon_update(hsep_triple *table, guint32 triples) { const guint32 hops = 4U; /* must be <= HSEP_N_MAX */ guint64 val; hsep_triple other; if (triples <= hops) /* should not happen */ return; g_assert((gint32) triples > 0); guc_hsep_get_non_hsep_triple(&other); /* * Update the 3 labels in the statusbar with the horizon values for a * distance of 'hops' hops. */ val = table[hops][HSEP_IDX_NODES] + other[HSEP_IDX_NODES]; gtk_label_printf(GTK_LABEL( gui_main_window_lookup("label_statusbar_horizon_node_count")), "%s %s", uint64_to_string(val), NG_("node", "nodes", val)); val = table[hops][HSEP_IDX_FILES] + other[HSEP_IDX_FILES]; gtk_label_printf(GTK_LABEL( gui_main_window_lookup("label_statusbar_horizon_file_count")), "%s %s", uint64_to_string(val), NG_("file", "files", val)); val = table[hops][HSEP_IDX_KIB] + other[HSEP_IDX_KIB]; gtk_label_printf(GTK_LABEL( gui_main_window_lookup("label_statusbar_horizon_kb_count")), "%s", short_kb_size(val, show_metric_units())); }
/** * @returns a static string of the cell contents of the given row and column. * * @attention * NB: The static buffers for each column are disjunct. */ const char * hsep_get_static_str(int row, int column) { const char *ret = NULL; hsep_triple hsep_table[G_N_ELEMENTS(hsep_global_table)]; hsep_triple other[1]; uint64 v; hsep_get_global_table(hsep_table, G_N_ELEMENTS(hsep_table)); hsep_get_non_hsep_triple(other); switch (column) { case HSEP_IDX_NODES: { static char buf[UINT64_DEC_BUFLEN]; v = hsep_table[row][HSEP_IDX_NODES] + other[0][HSEP_IDX_NODES]; uint64_to_string_buf(v, buf, sizeof buf); ret = buf; } break; case HSEP_IDX_FILES: { static char buf[UINT64_DEC_BUFLEN]; v = hsep_table[row][HSEP_IDX_FILES] + other[0][HSEP_IDX_FILES]; uint64_to_string_buf(v, buf, sizeof buf); ret = buf; } break; case HSEP_IDX_KIB: { static char buf[UINT64_DEC_BUFLEN]; /* Make a copy because concurrent usage of short_kb_size() * could be hard to discover. */ v = hsep_table[row][HSEP_IDX_KIB] + other[0][HSEP_IDX_KIB]; g_strlcpy(buf, short_kb_size(v, GNET_PROPERTY(display_metric_units)), sizeof buf); ret = buf; } break; } g_assert(ret != NULL); return ret; }
/** * Writes the browse host data of the context ``ctx'' to the buffer * ``dest''. This must be called multiple times to retrieve the complete * data until zero is returned i.e., the end of file is reached. * * This routine deals with HTML data generation. * * @param ctx an initialized browse host context. * @param dest the destination buffer. * @param size the amount of bytes ``dest'' can hold. * * @return -1 on failure, zero at the end-of-file condition or if size * was zero. On success, the amount of bytes copied to ``dest'' * is returned. */ static ssize_t browse_host_read_html(struct special_upload *ctx, void *const dest, size_t size) { static const char header[] = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\r\n" "<html>\r\n" "<head>\r\n" "<title>Browse Host</title>\r\n" "</head>\r\n" "<body>\r\n"; static const char trailer[] = "</ul>\r\n</body>\r\n</html>\r\n"; struct browse_host_upload *bh = cast_to_browse_host_upload(ctx); char *p = dest; g_assert(NULL != bh); g_assert(NULL != dest); g_assert(size <= INT_MAX); g_assert(UNSIGNED(bh->state) < NUM_BH_STATES); g_assert(bh->b_size <= INT_MAX); g_assert(bh->b_offset <= bh->b_size); do { switch (bh->state) { case BH_STATE_HEADER: if (!bh->b_data) { bh->b_data = header; bh->b_size = CONST_STRLEN(header); } p += browse_host_read_data(bh, p, &size); if (bh->b_size == bh->b_offset) browse_host_next_state(bh, BH_STATE_LIBRARY_INFO); break; case BH_STATE_LIBRARY_INFO: if (!bh->b_data) { bh->w_buf_size = w_concat_strings(&bh->w_buf, "<h1>", product_get_name(), "</h1>\r\n" "<h3>", version_get_string(), " sharing ", uint64_to_string(shared_files_scanned()), " file", shared_files_scanned() == 1 ? "" : "s", " ", short_kb_size(shared_kbytes_scanned(), GNET_PROPERTY(display_metric_units)), " total</h3>\r\n" "<ul>\r\n", (void *) 0); bh->b_data = bh->w_buf; bh->b_size = bh->w_buf_size - 1; /* minus trailing NUL */ bh->b_offset = 0; } p += browse_host_read_data(bh, p, &size); if (bh->b_size == bh->b_offset) browse_host_next_state(bh, BH_STATE_FILES); break; case BH_STATE_TRAILER: if (!bh->b_data) { bh->b_data = trailer; bh->b_size = CONST_STRLEN(trailer); } p += browse_host_read_data(bh, p, &size); if (bh->b_size == bh->b_offset) browse_host_next_state(bh, BH_STATE_EOF); break; case BH_STATE_FILES: if (bh->b_data && bh->b_size == bh->b_offset) { g_assert(bh->w_buf == bh->b_data); wfree(bh->w_buf, bh->w_buf_size); bh->w_buf = NULL; bh->w_buf_size = 0; bh->b_data = NULL; } if (!bh->b_data) { const shared_file_t *sf; bh->file_index++; sf = shared_file_sorted(bh->file_index); if (!sf) { if (bh->file_index > shared_files_scanned()) browse_host_next_state(bh, BH_STATE_TRAILER); /* Skip holes in the file_index table */ } else if (SHARE_REBUILDING == sf) { browse_host_next_state(bh, BH_STATE_REBUILDING); } else { const char * const name_nfc = shared_file_name_nfc(sf); const filesize_t file_size = shared_file_size(sf); size_t html_size; char *html_name; { const char *dir; char *name; dir = shared_file_relative_path(sf); if (dir) { name = h_strconcat(dir, "/", name_nfc, (void *) 0); } else { name = deconstify_char(name_nfc); } html_size = 1 + html_escape(name, NULL, 0); html_name = walloc(html_size); html_escape(name, html_name, html_size); if (name != name_nfc) { HFREE_NULL(name); } } if (sha1_hash_available(sf)) { const struct sha1 *sha1 = shared_file_sha1(sf); bh->w_buf_size = w_concat_strings(&bh->w_buf, "<li><a href=\"/uri-res/N2R?urn:sha1:", sha1_base32(sha1), "\">", html_name, "</a> [", short_html_size(file_size, GNET_PROPERTY(display_metric_units)), "]</li>\r\n", (void *) 0); } else { char *escaped; escaped = url_escape(name_nfc); bh->w_buf_size = w_concat_strings(&bh->w_buf, "<li><a href=\"/get/", uint32_to_string(shared_file_index(sf)), "/", escaped, "\">", html_name, "</a>" " [", short_html_size(file_size, GNET_PROPERTY(display_metric_units)), "]</li>\r\n", (void *) 0); if (escaped != name_nfc) { HFREE_NULL(escaped); } } wfree(html_name, html_size); bh->b_data = bh->w_buf; bh->b_size = bh->w_buf_size - 1; /* minus trailing NUL */ bh->b_offset = 0; } } if (bh->b_data) p += browse_host_read_data(bh, p, &size); break; case BH_STATE_REBUILDING: if (!bh->b_data) { static const char msg[] = "<li>" "<b>" "The library is currently being rebuild. Please, " "try again in a moment." "</b>" "</li>"; bh->b_data = msg; bh->b_size = CONST_STRLEN(msg); } p += browse_host_read_data(bh, p, &size); if (bh->b_size == bh->b_offset) browse_host_next_state(bh, BH_STATE_TRAILER); break; case BH_STATE_EOF: return p - cast_to_char_ptr(dest); case NUM_BH_STATES: g_assert_not_reached(); } } while (size > 0); return p - cast_to_char_ptr(dest); }
/** * Displays assorted status information */ enum shell_reply shell_exec_status(struct gnutella_shell *sh, int argc, const char *argv[]) { const char *cur; const option_t options[] = { { "i", &cur }, }; int parsed; char buf[2048]; time_t now; shell_check(sh); g_assert(argv); g_assert(argc > 0); parsed = shell_options_parse(sh, argv, options, G_N_ELEMENTS(options)); if (parsed < 0) return REPLY_ERROR; argv += parsed; /* args[0] is first command argument */ argc -= parsed; /* counts only command arguments now */ now = tm_time(); /* Leading flags */ { char flags[47]; const char *fw; const char *fd; const char *pmp; const char *dht; /* * The flags are displayed as followed: * * UMP port mapping configured via UPnP * NMP port mapping configured via NAT-PMP * pmp port mapping available (UPnP or NAT-PMP), un-configured * CLK clock, GTKG expired * !FD or FD red or yellow bombs for fd shortage * STL upload stalls * gUL/yUL/rUL green, yellow or red upload early stalling levels * CPU cpu overloaded * MOV file moving * SHA SHA-1 rebuilding or verifying * TTH TTH rebuilding or verifying * LIB library rescan * :FW or FW indicates whether hole punching is possible * udp or UDP indicates UDP firewalling (lowercased for hole punching) * TCP indicates TCP-firewalled * - the happy face: no firewall * sDH/lDH/bDH seeded, own KUID looking or bootstrapping DHT * A or P active or passive DHT mode * UP or LF ultrapeer or leaf mode */ pmp = (GNET_PROPERTY(upnp_possible) || GNET_PROPERTY(natpmp_possible)) ? "pmp " : empty; if ( (GNET_PROPERTY(enable_upnp) || GNET_PROPERTY(enable_natpmp)) && GNET_PROPERTY(port_mapping_successful) ) { pmp = GNET_PROPERTY(enable_natpmp) ? "NMP " : "UMP "; } if (dht_enabled()) { dht = empty; switch ((enum dht_bootsteps) GNET_PROPERTY(dht_boot_status)) { case DHT_BOOT_NONE: case DHT_BOOT_SHUTDOWN: break; case DHT_BOOT_SEEDED: dht = "sDH "; break; case DHT_BOOT_OWN: dht = "lDH "; break; case DHT_BOOT_COMPLETING: dht = "bDH "; break; case DHT_BOOT_COMPLETED: dht = dht_is_active() ? "A " : "P "; break; case DHT_BOOT_MAX_VALUE: g_assert_not_reached(); } } else { dht = empty; } if (GNET_PROPERTY(is_firewalled) && GNET_PROPERTY(is_udp_firewalled)) { fw = GNET_PROPERTY(recv_solicited_udp) ? ":FW " : "FW "; } else if (GNET_PROPERTY(is_firewalled)) { fw = "TCP "; } else if (GNET_PROPERTY(is_udp_firewalled)) { fw = GNET_PROPERTY(recv_solicited_udp) ? "udp " : "UDP "; } else { fw = "- "; } if (GNET_PROPERTY(file_descriptor_runout)) { fd = "!FD "; } else if (GNET_PROPERTY(file_descriptor_shortage)) { fd = "FD "; } else { fd = empty; } gm_snprintf(flags, sizeof flags, "<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>", pmp, GNET_PROPERTY(download_queue_frozen) ? "DFZ " : empty, GNET_PROPERTY(ancient_version) ? "CLK " : empty, fd, GNET_PROPERTY(uploads_stalling) ? "STL " : empty, GNET_PROPERTY(uploads_bw_ignore_stolen) ? "gUL " : empty, GNET_PROPERTY(uploads_bw_uniform) ? "yUL " : empty, GNET_PROPERTY(uploads_bw_no_stealing) ? "rUL " : empty, GNET_PROPERTY(overloaded_cpu) ? "CPU " : empty, GNET_PROPERTY(file_moving) ? "MOV " : empty, (GNET_PROPERTY(sha1_rebuilding) || GNET_PROPERTY(sha1_verifying)) ? "SHA " : empty, (GNET_PROPERTY(tth_rebuilding) || GNET_PROPERTY(tth_verifying)) ? "TTH " : empty, GNET_PROPERTY(library_rebuilding) ? "LIB " : empty, fw, dht, settings_is_ultra() ? "UP" : "LF"); gm_snprintf(buf, sizeof buf, "+%s+\n" "| %-18s%51s |\n" "|%s|\n", dashes, "Status", flags, equals); shell_write(sh, buf); } /* General status */ { const char *blackout; short_string_t leaf_switch; short_string_t ultra_check; leaf_switch = timestamp_get_string( GNET_PROPERTY(node_last_ultra_leaf_switch)); ultra_check = timestamp_get_string( GNET_PROPERTY(node_last_ultra_check)); if (GNET_PROPERTY(is_firewalled) && GNET_PROPERTY(is_udp_firewalled)) { blackout = GNET_PROPERTY(recv_solicited_udp) ? "TCP,udp" : "TCP,UDP"; } else if (GNET_PROPERTY(is_firewalled)) { blackout = "TCP"; } else if (GNET_PROPERTY(is_udp_firewalled)) { blackout = GNET_PROPERTY(recv_solicited_udp) ? "udp" : "UDP"; } else { blackout = "None"; } gm_snprintf(buf, sizeof buf, "| Mode: %-9s Last Switch: %-19s%2s|\n" "| Uptime: %-9s Last Check: %-19s%2s|\n" "| Port: %-9u Blackout: %-7s%14s|\n" "|%s|\n", GNET_PROPERTY(online_mode) ? node_peermode_to_string(GNET_PROPERTY(current_peermode)) : "offline", GNET_PROPERTY(node_last_ultra_leaf_switch) ? leaf_switch.str : "never", space, short_time(delta_time(now, GNET_PROPERTY(start_stamp))), GNET_PROPERTY(node_last_ultra_check) ? ultra_check.str : "never", space, socket_listen_port(), blackout, space, equals); shell_write(sh, buf); } /* IPv4 info */ switch (GNET_PROPERTY(network_protocol)) { case NET_USE_BOTH: case NET_USE_IPV4: gm_snprintf(buf, sizeof buf, "| IPv4: %-44s Since: %-12s|\n", host_addr_to_string(listen_addr()), short_time(delta_time(now, GNET_PROPERTY(current_ip_stamp)))); shell_write(sh, buf); } /* IPv6 info */ switch (GNET_PROPERTY(network_protocol)) { case NET_USE_BOTH: gm_snprintf(buf, sizeof buf, "|%s|\n", dashes); shell_write(sh, buf); /* FALL THROUGH */ case NET_USE_IPV6: gm_snprintf(buf, sizeof buf, "| IPv6: %-44s Since: %-12s|\n", host_addr_to_string(listen_addr6()), short_time(delta_time(now, GNET_PROPERTY(current_ip6_stamp)))); shell_write(sh, buf); } /* Node counts */ gm_snprintf(buf, sizeof buf, "|%s|\n" "| Peers: %-7u Ultra %4u/%-7u Leaf %4u/%-6u Legacy %4u/%-4u |\n" "| Downloads %4u/%-4u Uploads %4u/%-7u Browse %4u/%-4u |\n" "|%s|\n", equals, GNET_PROPERTY(node_ultra_count) + GNET_PROPERTY(node_leaf_count) + GNET_PROPERTY(node_normal_count), GNET_PROPERTY(node_ultra_count), settings_is_ultra() ? GNET_PROPERTY(max_connections) : GNET_PROPERTY(max_ultrapeers), GNET_PROPERTY(node_leaf_count), GNET_PROPERTY(max_leaves), GNET_PROPERTY(node_normal_count), GNET_PROPERTY(normal_connections), GNET_PROPERTY(dl_active_count), GNET_PROPERTY(dl_running_count), GNET_PROPERTY(ul_running), GNET_PROPERTY(ul_registered), GNET_PROPERTY(html_browse_served) + GNET_PROPERTY(qhits_browse_served), GNET_PROPERTY(html_browse_count) + GNET_PROPERTY(qhits_browse_count), equals); shell_write(sh, buf); /* Bandwidths */ { const bool metric = GNET_PROPERTY(display_metric_units); short_string_t gnet_in, http_in, leaf_in, gnet_out, http_out, leaf_out; short_string_t dht_in, dht_out; gnet_bw_stats_t bw_stats, bw2_stats; const char *bwtype = cur ? "(cur)" : "(avg)"; gnet_get_bw_stats(BW_GNET_IN, &bw_stats); gnet_get_bw_stats(BW_GNET_UDP_IN, &bw2_stats); gnet_in = short_rate_get_string( cur ? bw_stats.current + bw2_stats.current : bw_stats.average + bw2_stats.average, metric); gnet_get_bw_stats(BW_GNET_OUT, &bw_stats); gnet_get_bw_stats(BW_GNET_UDP_OUT, &bw2_stats); gnet_out = short_rate_get_string( cur ? bw_stats.current + bw2_stats.current : bw_stats.average + bw2_stats.average, metric); gnet_get_bw_stats(BW_HTTP_IN, &bw_stats); http_in = short_rate_get_string( cur ? bw_stats.current : bw_stats.average, metric); gnet_get_bw_stats(BW_HTTP_OUT, &bw_stats); http_out = short_rate_get_string( cur ? bw_stats.current : bw_stats.average, metric); gnet_get_bw_stats(BW_LEAF_IN, &bw_stats); leaf_in = short_rate_get_string( cur ? bw_stats.current : bw_stats.average, metric); gnet_get_bw_stats(BW_LEAF_OUT, &bw_stats); leaf_out = short_rate_get_string( cur ? bw_stats.current : bw_stats.average, metric); gnet_get_bw_stats(BW_DHT_IN, &bw_stats); dht_in = short_rate_get_string( cur ? bw_stats.current : bw_stats.average, metric); gnet_get_bw_stats(BW_DHT_OUT, &bw_stats); dht_out = short_rate_get_string( cur ? bw_stats.current : bw_stats.average, metric); gm_snprintf(buf, sizeof buf, "| %-70s|\n" "|%71s|\n" "| %5s In: %13s %13s %13s %13s |\n" "| %5s Out: %13s %13s %13s %13s |\n", "Bandwidth:" " Gnutella Leaf HTTP DHT", dashes, bwtype, gnet_in.str, leaf_in.str, http_in.str, dht_in.str, bwtype, gnet_out.str, leaf_out.str, http_out.str, dht_out.str); shell_write(sh, buf); } { char line[128]; bool metric = GNET_PROPERTY(display_metric_units); gm_snprintf(buf, sizeof buf, "|%s|\n", equals); shell_write(sh, buf); concat_strings(line, sizeof line, "Shares ", uint64_to_string(shared_files_scanned()), " file", shared_files_scanned() == 1 ? "" : "s", " ", short_kb_size(shared_kbytes_scanned(), metric), " total", (void *) 0); gm_snprintf(buf, sizeof buf, "| %-35s Up: %-11s Down: %-11s |\n", line, short_byte_size(GNET_PROPERTY(ul_byte_count), metric), short_byte_size2(GNET_PROPERTY(dl_byte_count), metric)); shell_write(sh, buf); gm_snprintf(buf, sizeof buf, "+%s+\n", dashes); shell_write(sh, buf); } return REPLY_READY; }
static void print_hsep_table(struct gnutella_shell *sh, hsep_triple *table, int triples, hsep_triple *non_hsep_ptr) { static hsep_triple empty_non_hsep; const char *hops_str = _("Hops"); const char *nodes_str = _("Nodes"); const char *files_str = _("Files"); const char *size_str = _("Size"); hsep_triple non_hsep, *t; char buf[200]; size_t maxlen[4]; size_t i; if (!non_hsep_ptr) { non_hsep_ptr = &empty_non_hsep; } memcpy(non_hsep, non_hsep_ptr, sizeof non_hsep); t = &table[1]; /* * Determine maximum width of each column. */ maxlen[0] = strlen(hops_str); /* length of Hops */ maxlen[1] = strlen(nodes_str); /* length of Nodes */ maxlen[2] = strlen(files_str); /* length of Files */ maxlen[3] = strlen(size_str); /* length of Size */ for (i = 0; i < UNSIGNED(triples) * 4; i++) { size_t n; unsigned m = i % 4; switch (m) { case 0: n = strlen(uint64_to_string(i / 4 + 1)); break; case 1: case 2: case 3: { unsigned j = 0; switch (m) { case 1: j = HSEP_IDX_NODES; break; case 2: j = HSEP_IDX_FILES; break; case 3: j = HSEP_IDX_KIB; break; } n = strlen(uint64_to_string(t[i][j] + non_hsep[j])); } break; default: n = 0; g_assert_not_reached(); } if (n > maxlen[m]) maxlen[m] = n; } str_bprintf(buf, sizeof buf, "%*s %*s %*s %*s\n", (int) maxlen[0], hops_str, (int) maxlen[1], nodes_str, (int) maxlen[2], files_str, (int) maxlen[3], size_str); shell_write(sh, buf); for (i = maxlen[0] + maxlen[1] + maxlen[2] + maxlen[3] + 6; i > 0; i--) shell_write(sh, "-"); shell_write(sh, "\n"); t = &table[1]; for (i = 0; i < UNSIGNED(triples); i++) { const char *s1, *s2, *s3; s1 = uint64_to_string(t[i][HSEP_IDX_NODES] + non_hsep[HSEP_IDX_NODES]); s2 = uint64_to_string2(t[i][HSEP_IDX_FILES] + non_hsep[HSEP_IDX_FILES]); s3 = short_kb_size(t[i][HSEP_IDX_KIB] + non_hsep[HSEP_IDX_KIB], GNET_PROPERTY(display_metric_units)); str_bprintf(buf, sizeof buf, "%*u %*s %*s %*s\n", (int) maxlen[0], (unsigned) (i + 1), (int) maxlen[1], s1, (int) maxlen[2], s2, (int) maxlen[3], s3); shell_write(sh, buf); } }