const char * bitzi_fj_to_string(bitzi_fj_t fj) { STATIC_ASSERT(NUM_BITZI_FJ == G_N_ELEMENTS(bitzi_fj_table)); g_assert(UNSIGNED(fj) < G_N_ELEMENTS(bitzi_fj_table)); return Q_(bitzi_fj_table[UNSIGNED(fj)]); }
/** * Compare two characters. */ static int charcmp(char a, char b) { return a == b ? 0 : UNSIGNED(a) < UNSIGNED(b) ? -1 : +1; }
/** * Get the type of message intuited from the start of a G2 packet. * * @param start start of message * @param len amount of consecutive bytes we have so far * * @return the message type if we can intuit it, G2_MSG_MAX otherwise. */ enum g2_msg g2_msg_type(const void *start, size_t len) { const char *name; size_t namelen; bool known; void *val; int type; g2_msg_init(); name = g2_frame_name(start, len, &namelen); if (NULL == name) return G2_MSG_MAX; known = patricia_lookup_extended_k(g2_msg_pt, name, namelen*8, NULL, &val); if (!known) return G2_MSG_MAX; type = pointer_to_int(val); g_assert((uint) type < UNSIGNED(G2_MSG_MAX)); return type; }
void gnet_stats_count_flowc(const void *head, bool head_only) { uint t; uint16 size = gmsg_size(head) + GTA_HEADER_SIZE; uint8 function = gnutella_header_get_function(head); uint8 ttl = gnutella_header_get_ttl(head); uint8 hops = gnutella_header_get_hops(head); g_assert(thread_is_main()); if (GNET_PROPERTY(node_debug) > 3) g_debug("FLOWC function=%d ttl=%d hops=%d", function, ttl, hops); /* * Adjust for Kademlia messages. */ if (GTA_MSG_DHT == function && size >= KDA_HEADER_SIZE && !head_only) { uint8 opcode = kademlia_header_get_function(head); if (UNSIGNED(opcode + MSG_DHT_BASE) < G_N_ELEMENTS(stats_lut)) { t = stats_lut[opcode + MSG_DHT_BASE]; } else { t = stats_lut[function]; /* Invalid opcode? */ } hops = 0; ttl = 0; } else { t = stats_lut[function]; } gnet_stats_flowc_internal(t, function, ttl, hops, size); }
/** * Write data to stream. * * @param os the output stream * @param data start of data to write * @param len length of data to write * * @return size of data written, -1 on error. */ ssize_t ostream_write(ostream_t *os, const void *data, size_t len) { ssize_t w = (ssize_t) -1; ostream_check(os); len = MIN(len, MAX_INT_VAL(ssize_t)); switch (os->type) { case OSTREAM_T_FILE: { size_t n = fwrite(data, len, 1, os->u.f); w = (0 == n) ? -1 : (ssize_t) len; } break; case OSTREAM_T_FD: w = write(os->u.fd, data, len); break; case OSTREAM_T_MEM: pmsg_slist_append(os->u.sl, data, len); w = len; break; case OSTREAM_T_PMSG: w = pmsg_write(os->u.mb, data, len); w = (len == UNSIGNED(w)) ? w : -1; break; case OSTREAM_T_MAX: g_assert_not_reached(); } if (-1 == w) os->ioerr = TRUE; return w; }
/** * Grab random data from file and feed them to the specified routine. * * @param path pathname where random data are expected * @param rfd random filling routine to feed data * @param len amount of random bytes to read * * @return the amount of bytes fed if OK, a short count or -1 on error, * with errno set. */ ssize_t frand_restore(const char *path, feed_fn_t rfd, size_t len) { char buf[256]; int fd; ssize_t bytes_read = 0; fd = file_open_missing(path, O_RDONLY); if (-1 == fd) return -1; while (len != 0) { size_t n = MIN(len, sizeof buf); ssize_t r; r = read(fd, buf, n); if (-1 == r) break; bytes_read += r; (*rfd)(buf, r); if (UNSIGNED(r) != n) break; len -= n; } ZERO(buf); /* Leave no memory trail */ close(fd); return bytes_read; }
/** * Use specified random filler to create a file full of random bytes. * * @param path pathname where random data should be generated * @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_save(const char *path, randfill_fn_t rfn, size_t len) { char buf[256]; int fd; ssize_t written = 0; fd = file_create(path, O_WRONLY, S_IRUSR | S_IWUSR); if (-1 == fd) return -1; while (len != 0) { size_t n = MIN(len, sizeof buf); ssize_t w; (*rfn)(buf, n); w = write(fd, buf, n); if (-1 == w) break; written += w; if (UNSIGNED(w) != n) break; len -= n; } ZERO(buf); /* Leave no memory trail */ close(fd); return written; }
void bdump(int datf) { int i; unsigned char dat[DBM_BBLKSIZ]; filestat_t buf; unsigned long b; unsigned long used = 0; unsigned long total; if (-1 == fstat(datf, &buf)) return; for (b = 0; b < UNSIGNED(buf.st_size); b += DBM_BBLKSIZ * DBM_BBLKSIZ * 8) { if ((fileoffset_t) -1 == lseek(datf, b, SEEK_SET)) oops("seek failed: offset %lu", b); if (-1 == read(datf, dat, sizeof dat)) oops("read failed: offset %lu", b); for (i = 0; i < DBM_BBLKSIZ; i++) used += bits_set(dat[i]); } total = buf.st_size / DBM_BBLKSIZ; if (buf.st_size % DBM_BBLKSIZ) total++; printf("%lu blocks used / %lu total (%.2f%% used)\n", used, total, used * 100.0 / (total ? total : 1)); }
/** * @return key decimation factor for expiration */ double keys_decimation_factor(const kuid_t *key) { size_t common; int delta; uint8 frontier; common = kuid_common_prefix(get_our_kuid(), key); /* * The furthest frontier is important because it determines whether * we need to apply timing decimation on published keys. * Relying solely on the exploration of our subtree is not enough * since there can be some aberration in the vincinity of our KUID. * * Correct it with the theoretical furthest bit value, determined * from the estimated DHT size, putting the frontier as further away * as possible. */ frontier = MIN(kball.furthest_bits, kball.theoretical_bits); /* * If key falls within our k-ball, no decimation. */ if (common >= frontier || !kball.seeded) return 1.0; delta = kball.furthest_bits - common; g_assert(delta > 0 && UNSIGNED(delta) < G_N_ELEMENTS(decimation_factor)); return decimation_factor[delta]; }
/** * Retry publishing after some delay. * * @param pe the entry to publish * @param delay delay in seconds * @param msg if non-NULL, logging message explaining the delay */ static void publisher_retry(struct publisher_entry *pe, int delay, const char *msg) { struct pubdata *pd; publisher_check(pe); g_assert(NULL == pe->publish_ev); g_assert(delay > 0); pd = get_pubdata(pe->sha1); if (pd != NULL) { pd->next_enqueue = time_advance(tm_time(), UNSIGNED(delay)); dbmw_write(db_pubdata, pe->sha1, pd, sizeof *pd); } pe->publish_ev = cq_insert(publish_cq, delay * 1000, handle_entry, pe); pe->last_delayed = tm_time(); if (GNET_PROPERTY(publisher_debug) > 3) { shared_file_t *sf = shared_file_by_sha1(pe->sha1); g_debug("PUBLISHER will retry SHA-1 %s %s\"%s\" in %s: %s", sha1_to_string(pe->sha1), (sf && sf != SHARE_REBUILDING && shared_file_is_partial(sf)) ? "partial " : "", (sf && sf != SHARE_REBUILDING) ? shared_file_name_nfc(sf) : "", compact_time(delay), msg != NULL ? msg : "<no reason>"); shared_file_unref(&sf); } }
void gnet_stats_count_sent(const gnutella_node_t *n, uint8 type, const void *base, uint32 size) { uint t = stats_lut[type]; gnet_stats_t *stats; uint8 hops; g_assert(t != MSG_UNKNOWN); g_assert(thread_is_main()); g_assert(!NODE_TALKS_G2(n)); stats = NODE_USES_UDP(n) ? &gnet_udp_stats : &gnet_tcp_stats; /* * Adjust for Kademlia messages. */ if (GTA_MSG_DHT == type && size >= KDA_HEADER_SIZE) { uint8 opcode = kademlia_header_get_function(base); if (UNSIGNED(opcode + MSG_DHT_BASE) < G_N_ELEMENTS(stats_lut)) { t = stats_lut[opcode + MSG_DHT_BASE]; } hops = 0; } else { hops = gnutella_header_get_hops(base); } gnet_stats_count_sent_internal(n, t, hops, size, stats); }
/** * Write new value in-place for the pair at index ``i'' on the page. * * @return 0 if OK, -1 on error with errno set. */ int replpair(DBM *db, char *pag, int i, datum val) { unsigned koff; unsigned voff; unsigned short *ino = (unsigned short *) pag; g_assert(UNSIGNED(i) + 1 <= ino[0]); voff = offset(ino[i + 1]); #ifdef BIGDATA if (is_big(ino[i + 1])) return big_replace(db, pag + voff, val.dptr, val.dsize); #else (void) db; /* Parameter unused if no BIGDATA */ #endif koff = offset(ino[i]); g_assert(koff - voff == val.dsize); memcpy(pag + voff, val.dptr, val.dsize); return 0; }
/** * Convert a message type to a symbolic name. * * @param type the G2 message type * * @return the message symbolic name if we can intuit it, "UNKNOWN" otherwise. */ const char * g2_msg_type_name(const enum g2_msg type) { if G_UNLIKELY((uint) type >= UNSIGNED(G2_MSG_MAX)) return "UNKNOWN"; return g2_msg_symbolic_names[type]; }
/** * Initialize internal state for our incremental zlib stream. * * @param zs the zlib stream structure to initialize * @param data input data to process; if NULL, will be incrementally given * @param len length of data to process (if data not NULL) or estimation * @param dest where processed data should go, or NULL if allocated * @param destlen length of supplied output buffer, if dest != NULL */ static void zlib_stream_init(zlib_stream_t *zs, const void *data, size_t len, void *dest, size_t destlen) { z_streamp z; g_assert(size_is_non_negative(len)); g_assert(size_is_non_negative(destlen)); zs->in = data; zs->inlen = data ? len : 0; zs->inlen_total = zs->inlen; /* * When deflating zlib requires normally 0.1% more + 12 bytes, we use * 0.5% to be safe. * * When inflating, assume we'll double the input at least. */ if (NULL == dest) { /* Processed data go to a dynamically allocated buffer */ if (!zs->allocated) { if (data == NULL && len == 0) len = 512; if (ZLIB_DEFLATER_MAGIC == zs->magic) { zs->outlen = (len * 1.005 + 12.0); g_assert(zs->outlen > len); g_assert(zs->outlen - len >= 12); } else { zs->outlen = UNSIGNED(len) * 2; } zs->out = halloc(zs->outlen); zs->allocated = TRUE; } } else { /* Processed data go to a supplied buffer, not-resizable */ if (zs->allocated) hfree(zs->out); zs->out = dest; zs->outlen = destlen; zs->allocated = FALSE; } /* * Initialize Z stream. */ z = zs->z; g_assert(z != NULL); /* Stream not closed yet */ z->next_out = zs->out; z->avail_out = zs->outlen; z->next_in = deconstify_pointer(zs->in); z->avail_in = 0; /* Will be set by zlib_xxx_step() */ }
/** * Callback function for inputevt_add(). This function pipes the query to * the server using the pipe in non-blocking mode, partial writes are handled * appropriately. In case of an unrecoverable error the query pipe will be * closed and the blocking adns_fallback() will be invoked. */ static void adns_query_callback(void *data, int dest, inputevt_cond_t condition) { adns_async_write_t *remain = data; g_assert(NULL != remain); g_assert(NULL != remain->buf); g_assert(remain->pos < remain->size); g_assert(dest == adns_query_fd); g_assert(0 != adns_query_event_id); if (condition & INPUT_EVENT_EXCEPTION) { g_warning("%s: write exception", G_STRFUNC); goto abort; } while (remain->pos < remain->size) { ssize_t ret; size_t n; n = remain->size - remain->pos; ret = write(dest, &remain->buf[remain->pos], n); if (0 == ret) { errno = ECONNRESET; ret = (ssize_t) -1; } /* FALL THROUGH */ if ((ssize_t) -1 == ret) { if (!is_temporary_error(errno)) goto error; return; } g_assert(ret > 0); g_assert(UNSIGNED(ret) <= n); remain->pos += (size_t) ret; } g_assert(remain->pos == remain->size); inputevt_remove(&adns_query_event_id); goto done; error: g_warning("%s: write() failed: %m", G_STRFUNC); abort: g_warning("%s: removed myself", G_STRFUNC); inputevt_remove(&adns_query_event_id); fd_close(&adns_query_fd); g_warning("%s: using fallback", G_STRFUNC); adns_fallback(&remain->req); done: adns_async_write_free(remain); return; }
static inline void tls_log_function(int level, const char *text) { if (GNET_PROPERTY(tls_debug) > UNSIGNED(level)) { char *str = h_strdup(text); strchomp(str, 0); g_debug("TLS(%d): %s", level, str); hfree(str); } }
/** * @return human-readable error string for given error code. */ const char * iprange_strerror(iprange_err_t errnum) { STATIC_ASSERT(IPR_ERROR_COUNT == G_N_ELEMENTS(iprange_errstr)); if (UNSIGNED(errnum) >= G_N_ELEMENTS(iprange_errstr)) return "Invalid error code"; return iprange_errstr[errnum]; }
static inline ALWAYS_INLINE void PIO_LOCK(int fd) { ONCE_FLAG_RUN(pio_inited, pio_init_once); g_assert(fd >= 0); g_assert(UNSIGNED(fd) < pio_capacity); spinlock(&pio_locks[fd]); }
/** * @return human-readable error string corresponding to error code `errnum'. */ const char * tok_strerror(tok_error_t errnum) { STATIC_ASSERT(G_N_ELEMENTS(tok_errstr) == TOK_MAX_ERROR); if (UNSIGNED(errnum) >= G_N_ELEMENTS(tok_errstr)) return "Invalid error code"; return tok_errstr[errnum]; }
void gnet_stats_count_dropped(gnutella_node_t *n, msg_drop_reason_t reason) { uint32 size; uint type; gnet_stats_t *stats; g_assert(UNSIGNED(reason) < MSG_DROP_REASON_COUNT); g_assert(thread_is_main()); stats = NODE_USES_UDP(n) ? &gnet_udp_stats : &gnet_tcp_stats; if (NODE_TALKS_G2(n)) { int f = g2_msg_type(n->data, n->size); if (f != G2_MSG_MAX) { f += MSG_G2_BASE; } else { f = G_N_ELEMENTS(stats_lut) - 1; /* Last, holds MSG_UNKNOWN */ } type = stats_lut[f]; size = n->size; } else { type = stats_lut[gnutella_header_get_function(&n->header)]; size = n->size + sizeof(n->header); } entropy_harvest_small( VARLEN(n->addr), VARLEN(n->port), VARLEN(reason), VARLEN(type), VARLEN(size), NULL); DROP_STATS(stats, type, size); node_inc_rxdrop(n); switch (reason) { case MSG_DROP_HOSTILE_IP: n->n_hostile++; break; case MSG_DROP_SPAM: n->n_spam++; break; case MSG_DROP_EVIL: n->n_evil++; break; default: ; } if (NODE_TALKS_G2(n)) { if (GNET_PROPERTY(log_dropped_g2)) { g2_msg_log_dropped_data(n->data, n->size, "from %s: %s", node_infostr(n), gnet_stats_drop_reason_to_string(reason)); } } else { if (GNET_PROPERTY(log_dropped_gnutella)) { gmsg_log_split_dropped(&n->header, n->data, n->size, "from %s: %s", node_infostr(n), gnet_stats_drop_reason_to_string(reason)); } } }
static inline ALWAYS_INLINE void THREAD_LOCK(int fd) { if G_UNLIKELY(!pio_inited) pio_init(); g_assert(fd >= 0); g_assert(UNSIGNED(fd) < pio_capacity); spinlock_hidden(&pio_locks[fd]); }
/** * Sets the state of the browse host context to ``state'' and resets the * data block variables. */ static inline void browse_host_next_state(struct browse_host_upload *bh, enum bh_state state) { g_assert(NULL != bh); g_assert(UNSIGNED(state) < NUM_BH_STATES); bh->w_buf = NULL; bh->w_buf_size = 0; bh->b_data = NULL; bh->b_size = 0; bh->b_offset = 0; bh->state = state; }
/** * Account for dropped Kademlia message of specified opcode from node ``n''. */ void gnet_dht_stats_count_dropped(gnutella_node_t *n, kda_msg_t opcode, msg_drop_reason_t reason) { uint32 size; uint type; gnet_stats_t *stats; g_assert(UNSIGNED(reason) < MSG_DROP_REASON_COUNT); g_assert(opcode <= KDA_MSG_MAX_ID); g_assert(UNSIGNED(opcode + MSG_DHT_BASE) < G_N_ELEMENTS(stats_lut)); g_assert(thread_is_main()); size = n->size + sizeof(n->header); type = stats_lut[opcode + MSG_DHT_BASE]; stats = NODE_USES_UDP(n) ? &gnet_udp_stats : &gnet_tcp_stats; entropy_harvest_small( VARLEN(n->addr), VARLEN(n->port), VARLEN(reason), VARLEN(type), VARLEN(size), NULL); DROP_STATS(stats, type, size); node_inc_rxdrop(n); }
static void on_notebook_downloads_info_switch_page(GtkNotebook *unused_notebook, GtkNotebookPage *unused_page, int page_num, void *unused_udata) { (void) unused_notebook; (void) unused_page; (void) unused_udata; g_return_if_fail(UNSIGNED(page_num) < NUM_DOWNLOADS_INFO_NB_PAGES); entropy_harvest_single(VARLEN(page_num)); notebook_downloads_info_current_page = page_num; gui_prop_set_guint32_val(PROP_DOWNLOADS_INFO_NOTEBOOK_TAB, page_num); }
/** * Write NUL-terminated string. * * If (size_t) -1 is given as length, then it is computed via strlen(), in * which case the string buffer must be NUL-terminated. Otherwise, the value * is taken to be the pre-computed string length. * * The string is written as: <ule64(length)><bytes>, no trailing NUL. */ void pmsg_write_string(pmsg_t *mb, const char *str, size_t length) { size_t len; g_assert(pmsg_is_writable(mb)); /* Not shared, or would corrupt data */ len = (size_t) -1 == length ? strlen(str) : length; g_assert(UNSIGNED(pmsg_available(mb)) >= len + 10); /* Need ule64 length */ pmsg_write_ule64(mb, (uint64) len); if (len != 0) { pmsg_write(mb, str, len); } }
/** * Write NUL-terminated string, up to `n' characters or the first seen NUL * in the buffer, whichever comes first. * * The string is written as: <ule64(length)><bytes>, no trailing NUL. */ void pmsg_write_fixed_string(pmsg_t *mb, const char *str, size_t n) { size_t len; g_assert(pmsg_is_writable(mb)); /* Not shared, or would corrupt data */ g_assert(UNSIGNED(pmsg_available(mb)) >= n + 10); /* Need ule64 length */ len = strlen(str); len = MIN(n, len); pmsg_write_ule64(mb, (uint64) len); if (len != 0) { pmsg_write(mb, str, len); } }
/** * Write I/O vector. * * @return amount of bytes written, or -1 on error. */ static ssize_t tx_deflate_writev(txdrv_t *tx, iovec_t *iov, int iovcnt) { struct attr *attr = tx->opaque; int sent = 0; if (tx_deflate_debugging(9)) { g_debug("TX %s: (%s) (buffer #%d, nagle %s, unflushed %zu) [%c%c]", G_STRFUNC, gnet_host_to_string(&tx->host), attr->fill_idx, (attr->flags & DF_NAGLE) ? "on" : "off", attr->unflushed, (attr->flags & DF_FLOWC) ? 'C' : '-', (attr->flags & DF_FLUSH) ? 'f' : '-'); } while (iovcnt-- > 0) { int ret; /* * If we're flow controlled or shut down, stop sending. */ if (attr->flags & (DF_FLOWC|DF_SHUTDOWN)) break; ret = deflate_add(tx, iovec_base(iov), iovec_len(iov)); if (-1 == ret) return -1; sent += ret; if (UNSIGNED(ret) < iovec_len(iov)) { /* Could not write all, flow-controlled */ break; } iov++; } if (tx_deflate_debugging(9)) { g_debug("TX %s: (%s) sent %lu bytes (buffer #%d, nagle %s, " "unflushed %zu) [%c%c]", G_STRFUNC, gnet_host_to_string(&tx->host), (ulong) sent, attr->fill_idx, (attr->flags & DF_NAGLE) ? "on" : "off", attr->unflushed, (attr->flags & DF_FLOWC) ? 'C' : '-', (attr->flags & DF_FLUSH) ? 'f' : '-'); } return sent; }
/** * Write NUL-terminated string, up to `n' characters or the first seen NUL * in the buffer, whichever comes first. * * The string is written as: <ule64(length)><bytes>, no trailing NUL. */ void pmsg_write_fixed_string(pmsg_t *mb, const char *str, size_t n) { size_t len; g_assert(pmsg_is_writable(mb)); /* Not shared, or would corrupt data */ g_assert(UNSIGNED(pmsg_available(mb)) >= n + 10); /* Need ule64 length */ g_assert_log(size_is_non_negative(n), "%s(): n=%zd", G_STRFUNC, n); len = vstrlen(str); len = MIN(n, len); pmsg_write_ule64(mb, (uint64) len); if (len != 0) { pmsg_write(mb, str, len); } }
/** * Create new message holding serialized tree. * * @param t the tree to serialize * @param prio priority of the message * @param freecb if non-NULL, the free routine to attach to message * @param arg additional argument for the free routine * * @return a message containing the serialized tree. */ static pmsg_t * g2_build_pmsg_prio(const g2_tree_t *t, int prio, pmsg_free_t freecb, void *arg) { size_t len; pmsg_t *mb; len = g2_frame_serialize(t, NULL, 0); if (NULL == freecb) mb = pmsg_new(prio, NULL, len); else mb = pmsg_new_extend(prio, NULL, len, freecb, arg); g2_frame_serialize(t, pmsg_start(mb), len); pmsg_seek(mb, len); g_assert(UNSIGNED(pmsg_size(mb)) == len); return mb; }
/** * Write NUL-terminated string. * * If (size_t) -1 is given as length, then it is computed via strlen(), in * which case the string buffer must be NUL-terminated. Otherwise, the value * is taken to be the pre-computed string length. * * The string is written as: <ule64(length)><bytes>, no trailing NUL. */ void pmsg_write_string(pmsg_t *mb, const char *str, size_t length) { size_t len; g_assert(pmsg_is_writable(mb)); /* Not shared, or would corrupt data */ g_assert_log(size_is_non_negative(length) || (size_t) -1 == length, "%s(): length=%zd", G_STRFUNC, length); len = (size_t) -1 == length ? strlen(str) : length; g_assert(UNSIGNED(pmsg_available(mb)) >= len + 10); /* Need ule64 length */ pmsg_write_ule64(mb, (uint64) len); if (len != 0) { pmsg_write(mb, str, len); } }