/** * Called when a delivery is writable */ void OutgoingFromRelay::handle(pn_delivery_t* delivery) { void* context = pn_delivery_get_context(delivery); BufferedTransfer* transfer = reinterpret_cast<BufferedTransfer*>(context); assert(transfer); if (pn_delivery_writable(delivery)) { if (transfer->write(link)) { outgoingMessageSent(); QPID_LOG(debug, "Sent relayed message " << name << " [" << relay.get() << "]"); } else { QPID_LOG(error, "Failed to send relayed message " << name << " [" << relay.get() << "]"); } } if (pn_delivery_updated(delivery)) { uint64_t d = transfer->updated(); switch (d) { case PN_ACCEPTED: outgoingMessageAccepted(); break; case PN_REJECTED: case PN_RELEASED://TODO: not quite true... case PN_MODIFIED://TODO: not quite true... outgoingMessageRejected(); break; default: QPID_LOG(warning, "Unhandled disposition: " << d); } } }
/** * Delivery Disposition Handler */ static void router_disp_handler(void* context, dx_link_t *link, pn_delivery_t *delivery) { pn_link_t *pn_link = pn_delivery_link(delivery); if (pn_link_is_sender(pn_link)) { pn_disposition_t disp = pn_delivery_remote_state(delivery); dx_message_t *msg = pn_delivery_get_context(delivery); pn_delivery_t *activate = 0; if (msg) { assert(delivery == dx_message_out_delivery(msg)); if (disp != 0) { activate = dx_message_in_delivery(msg); pn_delivery_update(activate, disp); // TODO - handling of the data accompanying RECEIVED/MODIFIED } if (pn_delivery_settled(delivery)) { // // Downstream delivery has been settled. Propagate the settlement // upstream. // activate = dx_message_in_delivery(msg); pn_delivery_settle(activate); pn_delivery_settle(delivery); dx_free_message(msg); } if (activate) { // // Activate the upstream/incoming link so that the settlement will // get pushed out. // dx_link_t *act_link = (dx_link_t*) pn_link_get_context(pn_delivery_link(activate)); dx_link_activate(act_link); } return; } } pn_delivery_settle(delivery); }
/** * Delivery Disposition Handler */ static void AMQP_disposition_handler(void* context, qd_link_t *link, pn_delivery_t *pnd) { qd_router_t *router = (qd_router_t*) context; qdr_delivery_t *delivery = (qdr_delivery_t*) pn_delivery_get_context(pnd); bool give_reference = false; // // It's important to not do any processing without a qdr_delivery. When pre-settled // multi-frame deliveries arrive, it's possible for the settlement to register before // the whole message arrives. Such premature settlement indications must be ignored. // if (!delivery) return; // // If the delivery is settled, remove the linkage between the PN and QDR deliveries. // if (pn_delivery_settled(pnd)) { pn_delivery_set_context(pnd, 0); qdr_delivery_set_context(delivery, 0); // // Don't decref the delivery here. Rather, we will _give_ the reference to the core. // give_reference = true; } // // Update the disposition of the delivery // qdr_delivery_update_disposition(router->router_core, delivery, pn_delivery_remote_state(pnd), pn_delivery_settled(pnd), give_reference); // // If settled, close out the delivery // if (pn_delivery_settled(pnd)) pn_delivery_settle(pnd); }
qd_message_t *qd_message_receive(pn_delivery_t *delivery) { pn_link_t *link = pn_delivery_link(delivery); ssize_t rc; qd_buffer_t *buf; qd_message_pvt_t *msg = (qd_message_pvt_t*) pn_delivery_get_context(delivery); // // If there is no message associated with the delivery, this is the first time // we've received anything on this delivery. Allocate a message descriptor and // link it and the delivery together. // if (!msg) { msg = (qd_message_pvt_t*) qd_message(); pn_delivery_set_context(delivery, (void*) msg); } // // Get a reference to the tail buffer on the message. This is the buffer into which // we will store incoming message data. If there is no buffer in the message, allocate // an empty one and add it to the message. // buf = DEQ_TAIL(msg->content->buffers); if (!buf) { buf = qd_buffer(); DEQ_INSERT_TAIL(msg->content->buffers, buf); } while (1) { // // Try to receive enough data to fill the remaining space in the tail buffer. // rc = pn_link_recv(link, (char*) qd_buffer_cursor(buf), qd_buffer_capacity(buf)); // // If we receive PN_EOS, we have come to the end of the message. // if (rc == PN_EOS) { // // If the last buffer in the list is empty, remove it and free it. This // will only happen if the size of the message content is an exact multiple // of the buffer size. // if (qd_buffer_size(buf) == 0) { DEQ_REMOVE_TAIL(msg->content->buffers); qd_buffer_free(buf); } pn_delivery_set_context(delivery, 0); char repr[qd_message_repr_len()]; qd_log(log_source, QD_LOG_TRACE, "Received %s on link %s", qd_message_repr((qd_message_t*)msg, repr, sizeof(repr)), pn_link_name(link)); return (qd_message_t*) msg; } if (rc > 0) { // // We have received a positive number of bytes for the message. Advance // the cursor in the buffer. // qd_buffer_insert(buf, rc); // // If the buffer is full, allocate a new empty buffer and append it to the // tail of the message's list. // if (qd_buffer_capacity(buf) == 0) { buf = qd_buffer(); DEQ_INSERT_TAIL(msg->content->buffers, buf); } } else // // We received zero bytes, and no PN_EOS. This means that we've received // all of the data available up to this point, but it does not constitute // the entire message. We'll be back later to finish it up. // break; } return 0; }