static void CORE_link_drain(void *context, qdr_link_t *link, bool mode) { qd_link_t *qlink = (qd_link_t*) qdr_link_get_context(link); if (!qlink) return; pn_link_t *plink = qd_link_pn(qlink); if (plink) { if (pn_link_is_receiver(plink)) pn_link_set_drain(plink, mode); } }
void receiver::drain() { link_context &ctx = link_context::get(pn_object()); if (ctx.draining) throw proton::error("drain already in progress"); else { ctx.draining = true; if (credit() > 0) pn_link_set_drain(pn_object(), true); else { // Drain is already complete. No state to communicate over the wire. // Create dummy flow event where "drain finish" can be detected. pn_connection_t *pnc = pn_session_connection(pn_link_session(pn_object())); connection_context& cctx = connection_context::get(pnc); // connection_engine collector is per connection. Reactor collector is global. pn_collector_t *coll = cctx.collector; if (!coll) coll = pn_reactor_collector(pn_object_reactor(pnc)); pn_collector_put(coll, PN_OBJECT, pn_object(), PN_LINK_FLOW); } } }
void messaging_adapter::on_delivery(proton_event &pe) { pn_event_t *cevent = pe.pn_event(); pn_link_t *lnk = pn_event_link(cevent); pn_delivery_t *dlv = pn_event_delivery(cevent); link_context& lctx = link_context::get(lnk); if (pn_link_is_receiver(lnk)) { delivery d(make_wrapper<delivery>(dlv)); if (!pn_delivery_partial(dlv) && pn_delivery_readable(dlv)) { // generate on_message pn_connection_t *pnc = pn_session_connection(pn_link_session(lnk)); connection_context& ctx = connection_context::get(pnc); // Reusable per-connection message. // Avoid expensive heap malloc/free overhead. // See PROTON-998 class message &msg(ctx.event_message); msg.decode(d); if (pn_link_state(lnk) & PN_LOCAL_CLOSED) { if (lctx.auto_accept) d.release(); } else { delegate_.on_message(d, msg); if (lctx.auto_accept && !d.settled()) d.accept(); if (lctx.draining && !pn_link_credit(lnk)) { lctx.draining = false; receiver r(make_wrapper<receiver>(lnk)); delegate_.on_receiver_drain_finish(r); } } } else if (pn_delivery_updated(dlv) && d.settled()) { delegate_.on_delivery_settle(d); } if (lctx.draining && pn_link_credit(lnk) == 0) { lctx.draining = false; pn_link_set_drain(lnk, false); receiver r(make_wrapper<receiver>(lnk)); delegate_.on_receiver_drain_finish(r); if (lctx.pending_credit) { pn_link_flow(lnk, lctx.pending_credit); lctx.pending_credit = 0; } } credit_topup(lnk); } else { tracker t(make_wrapper<tracker>(dlv)); // sender if (pn_delivery_updated(dlv)) { uint64_t rstate = pn_delivery_remote_state(dlv); if (rstate == PN_ACCEPTED) { delegate_.on_tracker_accept(t); } else if (rstate == PN_REJECTED) { delegate_.on_tracker_reject(t); } else if (rstate == PN_RELEASED || rstate == PN_MODIFIED) { delegate_.on_tracker_release(t); } if (t.settled()) { delegate_.on_tracker_settle(t); } if (lctx.auto_settle) t.settle(); } } }