/** * Flush current /QH2. * * Depending how the QH2 builder is configured, this either sends the message * to the target node or invokes a processing callback. */ static void g2_build_qh2_flush(struct g2_qh2_builder *ctx) { pmsg_t *mb; g_assert(ctx != NULL); g_assert(ctx->t != NULL); g_assert((ctx->n != NULL) ^ (ctx->cb != NULL)); /* * Restore the order of children in the root packet to be the order we * used when we added the nodes, since we prepend new children. */ g2_tree_reverse_children(ctx->t); /* * If sending over UDP, ask for reliable delivery of the query hit. * To be able to monitor the fate of the message, we asssociate a free * routine to it. */ if (ctx->to_udp) { struct g2_qh2_pmsg_info *pmi; WALLOC0(pmi); pmi->magic = G2_QH2_PMI_MAGIC; pmi->hub_id = nid_ref(NODE_ID(ctx->hub)); mb = g2_build_pmsg_extended(ctx->t, g2_qh2_pmsg_free, pmi); pmsg_mark_reliable(mb); } else { mb = g2_build_pmsg(ctx->t); } if (GNET_PROPERTY(g2_debug) > 3) { g_debug("%s(): flushing the following hit for " "Q2 #%s to %s%s (%d bytes):", G_STRFUNC, guid_hex_str(ctx->muid), NULL == ctx->n ? stacktrace_function_name(ctx->cb) : node_infostr(ctx->n), NULL == ctx->n ? "()" : "", pmsg_size(mb)); g2_tfmt_tree_dump(ctx->t, stderr, G2FMT_O_PAYLOAD | G2FMT_O_PAYLEN); } if (ctx->n != NULL) g2_node_send(ctx->n, mb); else (*ctx->cb)(mb, ctx->arg); ctx->messages++; ctx->current_size = 0; g2_tree_free_null(&ctx->t); }
/** * Send a datagram to the specified node, made of `len' bytes from `buf', * forming a valid Gnutella message, with a "control" priority. */ void udp_ctrl_send_msg(const gnutella_node_t *n, const void *buf, int len) { pmsg_t *mb; g_assert(NODE_IS_UDP(n)); g_return_if_fail(n->outq); mb = gmsg_to_ctrl_pmsg(buf, len); if (NODE_CAN_SR_UDP(n)) pmsg_mark_reliable(mb); /* Send reliably if node supports it */ mq_udp_node_putq(n->outq, mb, n); }
/** * Send a message to specified UDP node. * * It is up to the caller to clone the message if needed, otherwise the * node's queue becomes the sole owner of the message and will pmsg_free() it. */ void udp_send_mb(const gnutella_node_t *n, pmsg_t *mb) { if (NULL == n || NULL == n->outq) { pmsg_free(mb); /* emit warnings */ g_return_if_fail(n); g_return_if_fail(n->outq); g_assert_not_reached(); } g_assert(NODE_IS_UDP(n)); if (NODE_CAN_SR_UDP(n)) pmsg_mark_reliable(mb); /* Send reliably if node supports it */ mq_udp_node_putq(n->outq, mb, n); }
/** * Send a datagram to the specified node, made of `len' bytes from `buf', * forming a valid Gnutella message. */ void udp_send_msg(const gnutella_node_t *n, const void *buf, int len) { pmsg_t *mb; g_assert(NODE_IS_UDP(n)); g_return_if_fail(n->outq); /* * If message is directed to a UDP node that can do semi-reliable UDP, * then turn on reliability on the message. */ mb = gmsg_to_pmsg(buf, len); if (NODE_CAN_SR_UDP(n)) pmsg_mark_reliable(mb); mq_udp_node_putq(n->outq, mb, n); }
/** * Route query hits from one node to the other. */ void dh_route(gnutella_node_t *src, gnutella_node_t *dest, int count) { pmsg_t *mb; struct dh_pmsg_info *pmi; const struct guid *muid; dqhit_t *dh; mqueue_t *mq; g_assert( gnutella_header_get_function(&src->header) == GTA_MSG_SEARCH_RESULTS); g_assert(count >= 0); if (!NODE_IS_WRITABLE(dest)) goto drop_shutdown; muid = gnutella_header_get_muid(&src->header); dh = dh_locate(muid); g_assert(dh != NULL); /* Must have called dh_got_results() first! */ if (GNET_PROPERTY(dh_debug) > 19) { g_debug("DH #%s got %d hit%s: " "msg=%u, hits_recv=%u, hits_sent=%u, hits_queued=%u", guid_hex_str(muid), count, plural(count), dh->msg_recv, dh->hits_recv, dh->hits_sent, dh->hits_queued); } mq = dest->outq; /* * Can we forward the message? */ switch (dh_can_forward(dh, mq, FALSE)) { case DH_DROP_FC: goto drop_flow_control; case DH_DROP_THROTTLE: goto drop_throttle; case DH_DROP_TRANSIENT: goto drop_transient; case DH_FORWARD: default: break; } /* * Allow message through. */ WALLOC(pmi); pmi->hits = count; dh->hits_queued += count; dh->msg_queued++; g_assert(dh->hits_queued >= UNSIGNED(count)); /* * Magic: we create an extended version of a pmsg_t that contains a * free routine, which will be invoked when the message queue frees * the message. * * This enables us to track how much results we already queued/sent. */ if (NODE_IS_UDP(dest)) { gnet_host_t to; pmsg_t *mbe; gnet_host_set(&to, dest->addr, dest->port); /* * With GUESS we may route back a query hit to an UDP node. */ if (GNET_PROPERTY(guess_server_debug) > 19) { g_debug("GUESS sending %d hit%s (%s) for #%s to %s", count, plural(count), NODE_CAN_SR_UDP(dest) ? "reliably" : NODE_CAN_INFLATE(dest) ? "possibly deflated" : "uncompressed", guid_hex_str(muid), node_infostr(dest)); } /* * Attempt to compress query hit if the destination supports it. * * If we're going to send the hit using semi-reliable UDP, there's * no need to compress beforehand, since the transport layer will * attempt its own compression anyway. */ if (!NODE_CAN_SR_UDP(dest) && NODE_CAN_INFLATE(dest)) { mb = gmsg_split_to_deflated_pmsg(&src->header, src->data, src->size + GTA_HEADER_SIZE); if (gnutella_header_get_ttl(pmsg_start(mb)) & GTA_UDP_DEFLATED) gnet_stats_inc_general(GNR_UDP_TX_COMPRESSED); } else { mb = gmsg_split_to_pmsg(&src->header, src->data, src->size + GTA_HEADER_SIZE); } mbe = pmsg_clone_extend(mb, dh_pmsg_free, pmi); pmsg_free(mb); if (NODE_CAN_SR_UDP(dest)) pmsg_mark_reliable(mbe); mq_udp_putq(mq, mbe, &to); } else { mb = gmsg_split_to_pmsg_extend(&src->header, src->data, src->size + GTA_HEADER_SIZE, dh_pmsg_free, pmi); mq_tcp_putq(mq, mb, src); if (GNET_PROPERTY(dh_debug) > 19) { g_debug("DH enqueued %d hit%s for #%s to %s", count, plural(count), guid_hex_str(muid), node_infostr(dest)); } } return; drop_shutdown: gnet_stats_count_dropped(src, MSG_DROP_SHUTDOWN); return; drop_flow_control: gnet_stats_count_dropped(src, MSG_DROP_FLOW_CONTROL); gnet_stats_count_flowc(&src->header, TRUE); return; drop_throttle: gnet_stats_count_dropped(src, MSG_DROP_THROTTLE); return; drop_transient: gnet_stats_count_dropped(src, MSG_DROP_TRANSIENT); return; }