/** * Attach meta information to supplied message block, returning a possibly * new message block to use. */ static pmsg_t * mq_udp_attach_metadata(pmsg_t *mb, const gnet_host_t *to) { pmsg_t *result; if (pmsg_is_extended(mb)) { struct mq_udp_info_extended *mi; WALLOC(mi); gnet_host_copy(&mi->to, to); result = mb; /* * Replace original free routine with the new one, saving the original * metadata and its free routine in the new metadata for later * transparent dispatching at free time. */ mi->orig_free = pmsg_replace_ext(mb, mq_udp_pmsg_free_extended, mi, &mi->orig_arg); } else { struct mq_udp_info *mi; WALLOC(mi); gnet_host_copy(&mi->to, to); result = pmsg_clone_extend(mb, mq_udp_pmsg_free, mi); pmsg_free(mb); } g_assert(pmsg_is_extended(result)); return result; }
/** * Free routine for plain metadata. */ static void mq_udp_pmsg_free(pmsg_t *mb, void *arg) { struct mq_udp_info *mi = arg; g_assert(pmsg_is_extended(mb)); WFREE(mi); }
/** * Free routine for extended metadata, invoking the original free routine * on the original metadata. */ static void mq_udp_pmsg_free_extended(pmsg_t *mb, void *arg) { struct mq_udp_info_extended *mi = arg; g_assert(pmsg_is_extended(mb)); if (mi->orig_free) (*mi->orig_free)(mb, mi->orig_arg); WFREE(mi); }
/** * Free routine for the extended message blocks we send to the UDP layer. */ static void g2_qh2_pmsg_free(pmsg_t *mb, void *arg) { struct g2_qh2_pmsg_info *pmi = arg; gnutella_node_t *n; g2_qh2_pmsg_info_check(pmi); g_assert(pmsg_is_extended(mb)); if (pmsg_was_sent(mb)) goto done; /* * Message was unsent, probably because the UDP address in the /Q2 was * wrong for some reason. * * If we're still connected to the hub which passed us this /Q2, then * we can relay back the /QH2 to the hub and it will hopefully be able * to deliver it back to the querying node. */ n = node_by_id(pmi->hub_id); if (NULL == n) { if (GNET_PROPERTY(g2_debug) > 1) { g_debug("%s(): could not send %s, relaying hub is gone, dropping.", G_STRFUNC, g2_msg_infostr_mb(mb)); } gnet_stats_inc_general(GNR_UDP_G2_HITS_UNDELIVERED); goto done; } else { pmsg_t *nmb; if (GNET_PROPERTY(g2_debug) > 1) { g_debug("%s(): could not send %s, giving back to %s for relaying", G_STRFUNC, g2_msg_infostr_mb(mb), node_infostr(n)); } nmb = pmsg_clone_plain(mb); pmsg_clear_reliable(nmb); g2_node_send(n, nmb); gnet_stats_inc_general(GNR_UDP_G2_HITS_REROUTED_TO_HUB); } done: nid_unref(pmi->hub_id); pmi->magic = 0; WFREE(pmi); }
/** * Shallow cloning of message, result is referencing the same data. * * This is not the same thing as pmsg_ref() because here a new message block * is created (albeit the data are shared with the original message). */ pmsg_t * pmsg_clone(pmsg_t *mb) { if (pmsg_is_extended(mb)) { return pmsg_clone_ext(cast_to_pmsg_ext(mb)); } else { pmsg_t *nmb; pmsg_check_consistency(mb); WALLOC(nmb); *nmb = *mb; /* Struct copy */ nmb->m_refcnt = 1; pdata_addref(nmb->m_data); return nmb; } }
/** * Free routine for a query message. */ static void sq_pmsg_free(pmsg_t *mb, void *arg) { struct smsg_info *smi = arg; g_assert(pmsg_is_extended(mb)); /* * If we're still in leaf mode, let the search know that we sent a * query for it to the specified node ID. */ if (settings_is_leaf()) search_notify_sent(smi->shandle, smi->node_id); nid_unref(smi->node_id); WFREE(smi); }
/** * Free routine for query hit message. */ static void dh_pmsg_free(pmsg_t *mb, void *arg) { struct dh_pmsg_info *pmi = arg; const struct guid *muid; dqhit_t *dh; g_assert(pmsg_is_extended(mb)); muid = gnutella_header_get_muid(pmsg_start(mb)); dh = dh_locate(muid); if (dh == NULL) goto cleanup; /* * It can happen that an initial query hit comes and is queued for * transmission, but the node is so clogged we don't actually send * it before the entry expires in our tracking tables. When we later * get the ACK that it was sent, we can therefore get obsolete data. * Hence we're very careful updating the stats, and we can't assert * that we're tracking everything correctly. * --RAM, 2004-09-04 */ if (pmsg_was_sent(mb)) dh->hits_sent += pmi->hits; if (dh->msg_queued == 0) /* We did not expect this ACK */ goto cleanup; dh->msg_queued--; if (dh->hits_queued >= pmi->hits) dh->hits_queued -= pmi->hits; /* FALL THROUGH */ cleanup: WFREE(pmi); }
/** * Free all message blocks, and decrease ref count on all data buffers. * * If the message block is referenced by more than one place, simply * decrease its reference count. No freeing occurs and the free routine * is therefore not invoked. */ void pmsg_free(pmsg_t *mb) { pdata_t *db = mb->m_data; pmsg_check_consistency(mb); g_assert(mb->m_refcnt != 0); /* * Don't free anything if refcnt != 1. */ if (mb->m_refcnt > 1U) { mb->m_refcnt--; return; } /* * Invoke free routine on extended message block. */ if (pmsg_is_extended(mb)) { pmsg_ext_t *emb = cast_to_pmsg_ext(mb); if (emb->m_free) (*emb->m_free)(mb, emb->m_arg); WFREE0(emb); } else { WFREE0(mb); } /* * Unref buffer data only after possible free routine was * invoked, since it may cause a free, preventing access to * memory from within the free routine. */ pdata_unref(db); }
/** * Free routine for our extended message blocks. */ static void revent_pmsg_free(pmsg_t *mb, void *arg) { struct revent_pmsg_info *pmi = arg; struct revent_ops *ops; void *obj; pmi_check(pmi); g_assert(pmsg_is_extended(mb)); ops = pmi->ops; /* * It is possible that whilst the message was in the message queue, * the operation was terminated. Therefore, we need to ensure that the * recorded user is still alive. */ obj = (*ops->is_alive)(pmi->rid); if (NULL == obj) { if (*ops->debug > 2) g_debug("DHT %s[%s] late UDP message %s", ops->name, nid_to_string(&pmi->rid), pmsg_was_sent(mb) ? "sending" : "dropping"); goto cleanup; } /* * Signal message freeing, so that user structure can decrement the * amount of pending messsages if necessary. */ if (ops->freeing_msg) (*ops->freeing_msg)(obj); /* * If the RPC callback triggered before the UDP message queue could * process the message on the way out, then we don't need to do anything * as the RPC is already dead and has been processed as such... */ if (pmi->rpc_done) goto cleanup; pmi->rpi->pmi = NULL; /* Break x-ref as message was processed */ if (pmsg_was_sent(mb)) { knode_t *kn = pmi->kn; /* * Message was successfully sent from the queue. */ kn->last_sent = tm_time(); if (ops->msg_sent) (*ops->msg_sent)(obj, mb); if (*ops->debug > 4) g_debug("DHT %s[%s] sent %s (%d bytes) to %s, RTT=%u", ops->name, nid_to_string(&pmi->rid), kmsg_infostr(pmsg_phys_base(mb)), pmsg_written_size(mb), knode_to_string(kn), kn->rtt); } else { knode_t *kn = pmi->kn; guid_t *muid; if (*ops->debug > 2) g_debug("DHT %s[%s] message %s%u to %s dropped by UDP queue", ops->name, nid_to_string(&pmi->rid), ops->udata_name, pmi->rpi->udata, knode_to_string(kn)); /* * Message was not sent and dropped by the queue. */ if (ops->msg_dropped) (*ops->msg_dropped)(obj, kn, mb); /* * Cancel the RPC, since the message was never sent out... * The MUID is at the start of the message. */ g_assert(pmsg_written_size(mb) > GUID_RAW_SIZE); muid = cast_to_guid_ptr(pmsg_phys_base(mb)); dht_rpc_cancel(muid); if (ops->rpc_cancelled) (*ops->rpc_cancelled)(obj, pmi->rpi->udata); revent_rpi_free(pmi->rpi); /* Cancel does not invoke RPC callback */ } cleanup: revent_pmi_free(pmi); }