static GtkTreeModel * create_searches_model(void) { static GType columns[c_sl_num]; GtkListStore *store; guint i; STATIC_ASSERT(c_sl_num == N_ITEMS(columns)); #define SET(c, x) case (c): columns[i] = (x); break for (i = 0; i < N_ITEMS(columns); i++) { switch (i) { SET(c_sl_name, G_TYPE_STRING); SET(c_sl_hit, G_TYPE_INT); SET(c_sl_new, G_TYPE_INT); SET(c_sl_fg, GDK_TYPE_COLOR); SET(c_sl_bg, GDK_TYPE_COLOR); SET(c_sl_sch, G_TYPE_POINTER); default: g_assert_not_reached(); } } #undef SET store = gtk_list_store_newv(N_ITEMS(columns), columns); return GTK_TREE_MODEL(store); }
static void add_list_columns(GtkTreeView *tv) { static const struct { const gchar * const title; const gint id; const gfloat align; } columns[] = { { N_("Search"), c_sl_name, 0.0 }, { N_("Hits"), c_sl_hit, 1.0 }, { N_("New"), c_sl_new, 1.0 } }; guint i; STATIC_ASSERT(SEARCH_LIST_VISIBLE_COLUMNS == N_ITEMS(columns)); for (i = 0; i < N_ITEMS(columns); i++) { GtkTreeViewColumn *column; column = add_column(tv, _(columns[i].title), columns[i].id, columns[i].align, NULL, c_sl_fg, c_sl_bg); gtk_tree_view_column_set_sort_column_id(column, columns[i].id); column_sort_tristate_register(column, on_search_list_column_clicked, NULL); } tree_view_restore_widths(tv, PROP_SEARCH_LIST_COL_WIDTHS); }
/** * Build the PATRICIA that maps a message name string into our internal * message ID. */ static void g2_msg_build_map(void) { uint i; STATIC_ASSERT(G2_MSG_MAX == N_ITEMS(g2_msg_english_names)); STATIC_ASSERT(G2_MSG_MAX == N_ITEMS(g2_msg_symbolic_names)); g_assert(NULL == g2_msg_pt); /* * We must be prepared to handle all the possible packet names, not just * the ones we know. Therefore, the PATRICIA key size is computed to be * able to handle the maximum architected size. */ g2_msg_pt = patricia_create(G2_FRAME_NAME_LEN_MAX * 8); /* Size in bits */ for (i = 0; i < N_ITEMS(g2_msg_symbolic_names); i++) { const char *key = g2_msg_symbolic_names[i]; size_t len = strlen(key); patricia_insert_k(g2_msg_pt, key, len * 8, int_to_pointer(i)); } }
/** * Invoked each time a new bandwidth timeslice begins. */ static void udp_sched_begin(void *data, int source, inputevt_cond_t cond) { udp_sched_t *us = data; unsigned i; udp_sched_check(us); udp_sched_log(4, "%p: starting, %zu bytes buffered", us, us->buffered); udp_sched_log(5, "%p: messages queued: " "data=%zu, control=%zu, urgent=%zu, highest=%zu", us, eslist_count(&us->lifo[PMSG_P_DATA]), eslist_count(&us->lifo[PMSG_P_CONTROL]), eslist_count(&us->lifo[PMSG_P_URGENT]), eslist_count(&us->lifo[PMSG_P_HIGHEST])); /* * Expire old traffic that we could not send. */ for (i = 0; i < N_ITEMS(us->lifo); i++) { eslist_foreach_remove(&us->lifo[i], udp_tx_desc_expired, us); } /* * Schedule pending traffic in LIFO order (starting from head), * processing the highest priority queue first. */ us->used_all = FALSE; do { udp_sched_seen_clear(us); for (i = N_ITEMS(us->lifo); i != 0 && !us->used_all; i--) { udp_sched_process(us, &us->lifo[i-1]); } udp_sched_tx_release(us); /* May re-queue traffic */ udp_sched_log(5, "%p: loop tail: %zu bytes buffered, b/w %s", us, us->buffered, us->used_all ? "gone" : "available"); } while (!us->used_all && us->buffered != 0); /* * If we did not use all the bandwidth yet and we flow-controlled * upper layers, service them. */ if (!us->used_all && us->flow_controlled) { struct udp_service_ctx ctx; us->flow_controlled = FALSE; ctx.fd = source; ctx.cond = cond; udp_sched_service(us, &ctx); } udp_sched_log(4, "%p: done (b/w %s, %zu bytes buffered%s)", us, us->used_all ? "gone" : "available", us->buffered, us->flow_controlled ? ", flow-controlled" : ""); }
/** * Extract the URN from a /Q2/URN and populate the search request info * if it is a SHA1 (or bitprint, which contains a SHA1). */ static void g2_node_extract_urn(const g2_tree_t *t, search_request_info_t *sri) { const char *p; size_t paylen; uint i; /* * If we have more SHA1s already than we can hold, stop. */ if (sri->exv_sha1cnt == N_ITEMS(sri->exv_sha1)) return; p = g2_tree_node_payload(t, &paylen); if (NULL == p) return; /* * We can only search by SHA1, hence we're only interested by URNs * that contain a SHA1. */ if (paylen < SHA1_RAW_SIZE) return; /* Cannot contain a SHA1 */ /* * Since we know there are at least SHA1_RAW_SIZE bytes in the payload, * we can use clamp_memcmp() to see whether we have a known prefix. */ for (i = 0; i < N_ITEMS(g2_q2_urn); i++) { const char *prefix = g2_q2_urn[i]; size_t len = vstrlen(prefix) + 1; /* Wants trailing NUL as well */ if (0 == clamp_memcmp(prefix, len, p, paylen)) { p += len; paylen -= len; g_assert(size_is_positive(paylen)); if (paylen >= SHA1_RAW_SIZE) { uint idx = sri->exv_sha1cnt++; g_assert(idx < N_ITEMS(sri->exv_sha1)); memcpy(&sri->exv_sha1[idx].sha1, p, SHA1_RAW_SIZE); } break; } } }
static void fi_gui_details_treeview_init(void) { static const struct { const char *title; gfloat xalign; gboolean editable; } tab[] = { { "ID", 1.0, FALSE }, { "Item", 1.0, FALSE }, { "Value", 0.0, TRUE }, }; GtkTreeView *tv; GtkTreeModel *model; unsigned i; tv = GTK_TREE_VIEW(gui_main_window_lookup("treeview_download_details")); g_return_if_fail(tv); treeview_download_details = tv; model = GTK_TREE_MODEL(gtk_list_store_new(N_ITEMS(tab), G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING)); gtk_tree_view_set_model(tv, model); g_object_unref(model); for (i = 0; i < N_ITEMS(tab); i++) { GtkTreeViewColumn *column; GtkCellRenderer *renderer; renderer = create_text_cell_renderer(tab[i].xalign); g_object_set(G_OBJECT(renderer), "editable", tab[i].editable, NULL_PTR); gui_signal_connect(renderer, "edited", on_cell_edited, tv); column = gtk_tree_view_column_new_with_attributes(tab[i].title, renderer, "text", i, NULL_PTR); g_object_set(column, "visible", i > 0 ? TRUE : FALSE, "min-width", 1, "resizable", TRUE, "sizing", 1 == i ? GTK_TREE_VIEW_COLUMN_AUTOSIZE : GTK_TREE_VIEW_COLUMN_FIXED, NULL_PTR); gtk_tree_view_append_column(tv, column); } drag_attach_text(GTK_WIDGET(tv), download_details_get_text); }
/** * Returns the MIME content type string. */ const char * mime_type_to_string(enum mime_type type) { static const char *names[] = { #define MIME_TYPE(id, name) name, #include "mime_types.h" #undef MIME_TYPE }; size_t i; STATIC_ASSERT(MIME_TYPE_NUM == N_ITEMS(names)); i = (size_t) type < N_ITEMS(names) ? type : MIME_TYPE_APPLICATION_OCTET_STREAM; return names[i]; }
/** * Loads the geo-ip.txt into memory. * * Choosing the first file we find among the several places we look at, * typically: * * -# ~/.gtk-gnutella/geo-ip.txt * -# /usr/share/gtk-gnutella/geo-ip.txt * -# /home/src/gtk-gnutella/geo-ip.txt * * The selected file will then be monitored and a reloading will occur * shortly after a modification. */ static void gip_retrieve(unsigned n) { FILE *f; int idx; char *filename; file_path_t fp[4]; unsigned length; length = settings_file_path_load(fp, gip_source[n].file, SFP_DFLT); g_assert(length <= N_ITEMS(fp)); f = file_config_open_read_norename_chosen( gip_source[n].what, fp, length, &idx); if (NULL == f) return; filename = make_pathname(fp[idx].dir, fp[idx].name); watcher_register(filename, gip_changed, uint_to_pointer(n)); HFREE_NULL(filename); gip_load(f, n); fclose(f); }
/** * Initializations. */ void G_COLD uhc_init(void) { uint i; g_return_if_fail(NULL == uhc_list); uhc_list = hash_list_new(uhc_hash, uhc_equal); for (i = 0; i < N_ITEMS(boot_hosts); i++) { const char *host, *ep, *uhc; uint16 port; uhc = boot_hosts[i].uhc; /* Some consistency checks */ uhc_get_host_port(uhc, &host, &port); g_assert(NULL != host); g_assert(0 != port); ep = is_strprefix(uhc, host); g_assert(NULL != ep); g_assert(':' == ep[0]); uhc_list_append(uhc); } hash_list_shuffle(uhc_list); }
static uint32 parse_named_entity(const struct array entity) { size_t i, len; char name[16 + 2]; if (entity.size >= N_ITEMS(name) - 2) goto error; len = 0; name[len++] = '&'; for (i = 0; i < entity.size; i++) { const unsigned char c = entity.data[i]; if (!is_ascii_alnum(c)) goto error; name[len++] = c; } name[len++] = ';'; name[len] = '\0'; return html_decode_entity(name, NULL); error: return -1; }
/** * Destroys the UDP TX scheduler, which must no longer be attached to anything. */ void udp_sched_free(udp_sched_t *us) { udp_sched_check(us); unsigned i; /* * TX stacks are asynchronously collected, so we need to force collection * now to make sure nobody references us any longer. */ tx_collect(); g_assert(0 == hash_list_length(us->stacks)); for (i = 0; i < N_ITEMS(us->lifo); i++) { udp_sched_drop_all(us, &us->lifo[i]); } udp_sched_tx_release(us); udp_sched_seen_clear(us); pool_free(us->txpool); hset_free_null(&us->seen); hash_list_free(&us->stacks); udp_sched_clear_sockets(us); us->magic = 0; WFREE(us); }
void HintsInit(void) { Window win; AtomListIntern(atoms_misc_names, N_ITEMS(atoms_misc_names), atoms_misc); win = XCreateSimpleWindow(disp, WinGetXwin(VROOT), -200, -200, 5, 5, 0, 0, 0); ICCCM_Init(); MWM_SetInfo(); #if ENABLE_GNOME GNOME_SetHints(win); #endif EWMH_Init(win); ecore_x_window_prop_string_set(WinGetXwin(VROOT), E16_ATOM_VERSION, e_wm_version); if (Mode.wm.window) { HintsSetWindowName(VROOT, "Enlightenment"); HintsSetWindowClass(VROOT, "Virtual-Root", "Enlightenment"); } Mode.root.ext_pmap = HintsGetRootPixmap(VROOT); Mode.root.ext_pmap_valid = EDrawableCheck(Mode.root.ext_pmap, 0); }
/** * @return human-readable error string corresponding to error code `errnum'. */ const char * header_strerror(uint errnum) { if (errnum >= N_ITEMS(error_str)) return "Invalid error code"; return error_str[errnum]; }
/** * Initialize the DHT publisher. */ void G_COLD publisher_init(void) { size_t i; dbstore_kv_t kv = { SHA1_RAW_SIZE, NULL, sizeof(struct pubdata), 0 }; dbstore_packing_t packing = { serialize_pubdata, deserialize_pubdata, NULL }; publish_cq = cq_main_submake("publisher", PUBLISHER_CALLOUT); publisher_sha1 = hikset_create( offsetof(struct publisher_entry, sha1), HASH_KEY_FIXED, SHA1_RAW_SIZE); db_pubdata = dbstore_open(db_pubdata_what, settings_dht_db_dir(), db_pubdata_base, kv, packing, PUBLISH_DB_CACHE_SIZE, sha1_hash, sha1_eq, GNET_PROPERTY(dht_storage_in_memory)); cq_periodic_add(publish_cq, PUBLISH_SYNC_PERIOD, publisher_sync, NULL); for (i = 0; i < N_ITEMS(inverse_decimation); i++) { double n = i + 1.0; double v = log(n / KDA_K); inverse_decimation[i] = 1.0 / (1.0 + v * v); if (GNET_PROPERTY(publisher_debug) > 4) { g_debug("PUBLISHER inverse_decimation[%zu] = %g", i, inverse_decimation[i]); } } for (i = 0; i < N_ITEMS(inverse_decimation); i++) { if (inverse_decimation[i] >= PUBLISH_MIN_DECIMATION) { publisher_minimum = i + 1; break; } } g_assert(publisher_minimum > 0); if (GNET_PROPERTY(publisher_debug)) { g_debug("PUBLISHER minimum amount of nodes we accept: %u", publisher_minimum); } publisher_trim_pubdata(); }
static enum html_attr parse_attribute(const struct array attr) { static const struct { const char *name; enum html_attr attr; } tab[] = { #define D(x) { #x, HTML_ATTR_ ## x, } D(ALT), D(HEIGHT), D(HREF), D(LANG), D(NAME), D(SRC), D(TARGET), D(WIDTH), #undef D }; size_t i, len; char name[32]; STATIC_ASSERT(N_ITEMS(tab) == NUM_HTML_ATTR - 1); len = 0; for (i = 0; i < attr.size; i++) { const unsigned char c = attr.data[i]; if (N_ITEMS(name) == len || !is_ascii_alpha(c)) break; name[len] = ascii_toupper(c); len++; } if (len > 0 && len < N_ITEMS(name)) { name[len] = '\0'; for (i = 0; i < N_ITEMS(tab); i++) { if (0 == strcmp(name, tab[i].name)) return tab[i].attr; } g_warning("%s(): unknown attribute: \"%s\"", G_STRFUNC, name); } return HTML_ATTR_UNKNOWN; }
/** * Use specified random filler to merge randomness into existing file content. * * @param path pathname where random data should be merged * @param rfn random number buffer-filling routine to use * @param len amount of random bytes to generate * * @return the amount of bytes generated if OK, a short count or -1 on error, * with errno set. */ ssize_t frand_merge(const char *path, randfill_fn_t rfn, size_t len) { char buf[256], data[256]; int fd; ssize_t written = 0; fileoffset_t pos = 0; fd = file_create(path, O_RDWR, S_IRUSR | S_IWUSR); if (-1 == fd) return -1; STATIC_ASSERT(N_ITEMS(buf) == N_ITEMS(data)); STATIC_ASSERT(N_ITEMS(buf) == sizeof buf); while (len != 0) { size_t i, n = MIN(len, sizeof buf); ssize_t r, w; (*rfn)(buf, n); r = read(fd, data, n); if (-1 == r) break; for (i = 0; i < n; i++) buf[i] ^= data[i]; r = lseek(fd, pos, SEEK_SET); if (-1 == r) break; w = write(fd, buf, n); if (-1 == w) break; written += w; if (UNSIGNED(w) != n) break; len -= n; pos += n; } ZERO(buf); /* Leave no memory trail */ close(fd); return written; }
static void hsep_sanity_check(void) { const pslist_t *sl; hsep_triple sum[N_ITEMS(hsep_global_table)]; unsigned int i, j; ZERO(&sum); g_assert(1 == hsep_own[HSEP_IDX_NODES]); /* * Iterate over all HSEP-capable nodes, and for each triple index * sum up all the connections' triple values. */ PSLIST_FOREACH(node_all_gnet_nodes(), sl) { gnutella_node_t *n = sl->data; /* also consider unestablished connections here */ if (!(n->attrs & NODE_A_CAN_HSEP)) continue; g_assert(0 == n->hsep->table[0][HSEP_IDX_NODES]); /* check nodes */ g_assert(0 == n->hsep->table[0][HSEP_IDX_FILES]); /* check files */ g_assert(0 == n->hsep->table[0][HSEP_IDX_KIB]); /* check KiB */ g_assert(1 == n->hsep->table[1][HSEP_IDX_NODES]); /* check nodes */ /* check if values are monotonously increasing (skip first) */ g_assert( hsep_check_monotony(cast_to_pointer(n->hsep->table[1]), N_ITEMS(n->hsep->table[1]) - 1) ); /* sum up the values */ for (i = 0; i < N_ITEMS(sum); i++) { for (j = 0; j < N_ITEMS(sum[0]); j++) sum[i][j] += n->hsep->table[i][j]; } }
void hcache_gui_init(void) { GtkTreeModel *model; gint n; STATIC_ASSERT(N_ITEMS(hcache_col_labels) == HCACHE_STATS_VISIBLE_COLUMNS); treeview_hcache = GTK_TREE_VIEW(gui_main_window_lookup("treeview_hcache")); model = GTK_TREE_MODEL(gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT)); for (n = 0; n < HCACHE_MAX; n++) { GtkTreeIter iter; if (n == HCACHE_NONE) continue; gtk_list_store_append(GTK_LIST_STORE(model), &iter); gtk_list_store_set(GTK_LIST_STORE(model), &iter, c_hcs_name, get_hcache_name(n), c_hcs_host_count, 0, c_hcs_hits, 0, c_hcs_misses, 0, (-1)); } for (n = 0; (guint) n < N_ITEMS(hcache_col_labels); n++) { add_column(treeview_hcache, n, (gfloat) (n != 0), _(hcache_col_labels[n].text)); } gtk_tree_view_set_model(treeview_hcache, model); tree_view_restore_widths(treeview_hcache, PROP_HCACHE_COL_WIDTHS); g_object_unref(model); tree_view_set_fixed_height_mode(treeview_hcache, TRUE); main_gui_add_timer(hcache_gui_timer); }
static const struct shell_cmd_help * shell_cmd_lookup(const char *argv0) { size_t i; g_return_val_if_fail(argv0, NULL); for (i = 0; i < N_ITEMS(commands); i++) { if (0 == ascii_strcasecmp(commands[i].name, argv0)) return &commands[i]; } return NULL; }
/** * @return b/w per second configured for the attached b/w scheduler. */ static uint64 udp_sched_bw_per_second(const udp_sched_t *us) { uint i; for (i = 0; i < N_ITEMS(us->bio); i++) { const bio_source_t *bio = us->bio[i]; if (bio != NULL) return bio_bw_per_second(bio); } return 0; /* No known I/O source, no bandwidth available */ }
/** * Initializations. */ void G_COLD ghc_init(void) { uint i; g_return_if_fail(NULL == ghc_list); ghc_list = list_new(); for (i = 0; i < N_ITEMS(boot_url); i++) { struct ghc *ghc; ghc = ghc_new(boot_url[i]); ghc_list_add(ghc); } }
/** * Clear the socket-related information in the UDP scheduler. */ static void udp_sched_clear_sockets(udp_sched_t *us) { uint i; for (i = 0; i < N_ITEMS(us->bio); i++) { bio_source_t *bio = us->bio[i]; if (bio != NULL) { bsched_source_remove(bio); us->bio[i] = NULL; } } }
/** * Initialize web cache. */ void gwc_init(void) { uint i; gwc_known_url = hset_create(HASH_KEY_STRING, 0); gwc_failed_url = hset_create(HASH_KEY_STRING, 0); gwc_retrieve(); if (0 == hset_count(gwc_known_url)) { for (i = 0; i < N_ITEMS(boot_url) && boot_url[i]; i++) gwc_add(boot_url[i]); } }
static void hsep_fire_global_table_changed(time_t now) { /* store global table change time */ hsep_last_global_table_change = now; /* do nothing if we don't have any listeners */ if (event_subscriber_active(hsep_global_table_changed_event)) { hsep_triple table[N_ITEMS(hsep_global_table)]; /* * Make a copy of the global HSEP table and give that * copy and the number of included triples to the * listeners. */ hsep_get_global_table(table, N_ITEMS(table)); event_trigger(hsep_global_table_changed_event, T_NORMAL(hsep_global_listener_t, (table, N_ITEMS(table)))); } }
enum shell_reply shell_exec_help(struct gnutella_shell *sh, int argc, const char *argv[]) { shell_check(sh); g_assert(argv); g_assert(argc > 0); shell_write(sh, "100~\n"); if (argc > 1) { shell_write(sh, shell_cmd_get_help(argc - 1, &argv[1])); } else { size_t i; shell_write(sh, "Use \"help <cmd>\" for additional help about a command.\n"); shell_write(sh, "The following commands are available:\n"); for (i = 0; i < N_ITEMS(commands); i++) { const char *name = commands[i].name; if (NULL == name || '\0' == name[0]) continue; shell_write(sh, name); { size_t len = strlen(name); char pad[10]; if (len < sizeof pad) { memset(pad, ' ', sizeof pad); pad[sizeof pad - len] = '\0'; shell_write(sh, pad); } } { const char *summary = shell_cmd_get_summary(name); if (summary) { shell_write(sh, " - "); shell_write(sh, summary); } } shell_write(sh, "\n"); } } shell_write(sh, ".\n"); return REPLY_READY; }
static void update_sensitivity(gboolean sensitive) { static const struct { const gchar *name; } items[] = { { "popup_nodes_disconnect" }, { "popup_nodes_browse_host" }, }; guint i; for (i = 0; i < N_ITEMS(items); i++) { gtk_widget_set_sensitive(gui_popup_nodes_lookup(items[i].name), sensitive); } gtk_widget_set_sensitive( gui_main_window_lookup("button_nodes_disconnect"), sensitive); }
/** * Initialize the MIME table. */ void G_COLD mime_type_init(void) { size_t i; /* * Ensure the MIME table is sorted. */ for (i = 0; i < N_ITEMS(mime_type_map); i++) { enum mime_type ret; ret = mime_type_from_extension(mime_type_map[i].extension); if (ret != mime_type_map[i].type) { g_error("mime_type_map[] is not sorted!"); } } }
static bool hsep_check_monotony(hsep_triple *table, unsigned int triples) { bool error = FALSE; uint i, j; g_assert(table); for (i = 1; i < triples; i++) { /* if any triple is not >= the previous one, error will be TRUE */ for (j = 0; j < N_ITEMS(table[0]); j++) error |= table[i - 1][j] > table[i][j]; if (error) break; } return !error; }
static inline bool ipv4_addr_is_routable(uint32 ip) { static const struct { const uint32 addr, mask; } net[] = { { 0x00000000UL, 0xff000000UL }, /* 0.0.0.0/8 "This" Network */ { 0xe0000000UL, 0xe0000000UL }, /* 224.0.0.0/4 Multicast + Reserved */ { 0x7f000000UL, 0xff000000UL }, /* 127.0.0.0/8 Loopback */ { 0xc0000200UL, 0xffffff00UL }, /* 192.0.2.0/24 Test-Net [RFC 3330] */ { 0xc0586300UL, 0xffffff00UL }, /* 192.88.99.0/24 6to4 [RFC 3068] */ { 0xc6120000UL, 0xfffe0000UL }, /* 198.18.0.0/15 [RFC 2544] */ }; uint i; for (i = 0; i < N_ITEMS(net); i++) { if ((ip & net[i].mask) == net[i].addr) return FALSE; } return TRUE; }
/** * Creates a new UDP TX scheduling layer. * * The layer can be attached to multiple TX layers, which will then share * the same bandwidth limitation. This is given by the "bws" parameter. * * The sockets are dynamically fetched, since the application can disable * them and recreate them depending on dynamic user reconfiguration. * * @param bws the bandwidth scheduler used for output * @param get_socket callback to get the UDP socket to write to * * @return a new scheduler. */ udp_sched_t * udp_sched_make( bsched_bws_t bws, udp_sched_socket_cb_t get_socket) { udp_sched_t *us; unsigned i; WALLOC0(us); us->magic = UDP_SCHED_MAGIC; us->txpool = pool_create("UDP TX descriptors", sizeof(struct udp_tx_desc), udp_tx_desc_alloc, udp_tx_desc_free, NULL); us->get_socket = get_socket; us->bws = bws; udp_sched_update_sockets(us); for (i = 0; i < N_ITEMS(us->lifo); i++) { eslist_init(&us->lifo[i], offsetof(struct udp_tx_desc, lnk)); } eslist_init(&us->tx_released, offsetof(struct udp_tx_desc, lnk)); us->seen = hset_create_any(gnet_host_hash, gnet_host_hash2, gnet_host_equal); us->stacks = hash_list_new(udp_tx_stack_hash, udp_tx_stack_eq); return us; }