void ConnectionContext::setCapacity(boost::shared_ptr<ReceiverContext> receiver, uint32_t capacity) { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); receiver->setCapacity(capacity); pn_link_flow((pn_link_t*) receiver->receiver, receiver->getCapacity()); wakeupDriver(); }
void receiver::add_credit(uint32_t credit) { link_context &ctx = link_context::get(pn_object()); if (ctx.draining) ctx.pending_credit += credit; else pn_link_flow(pn_object(), credit); }
bool Incoming::doWork() { uint32_t c = getCredit(); bool issue = window < c; if (issue) { pn_link_flow(link, c - window); window = c; } return issue; }
static pn_event_type_t message_stream_handler(test_handler_t *th, pn_event_t *e) { struct message_stream_context *ctx = (struct message_stream_context*)th->context; switch (pn_event_type(e)) { case PN_CONNECTION_BOUND: pn_transport_set_max_frame(pn_event_transport(e), FRAME); return PN_EVENT_NONE; case PN_SESSION_INIT: pn_session_set_incoming_capacity(pn_event_session(e), FRAME); /* Single frame incoming */ pn_session_set_outgoing_window(pn_event_session(e), 1); /* Single frame outgoing */ return PN_EVENT_NONE; case PN_LINK_REMOTE_OPEN: common_handler(th, e); if (pn_link_is_receiver(pn_event_link(e))) { pn_link_flow(pn_event_link(e), 1); } else { ctx->sender = pn_event_link(e); } return PN_EVENT_NONE; case PN_LINK_FLOW: /* Start a delivery */ if (pn_link_is_sender(pn_event_link(e)) && !ctx->dlv) { ctx->dlv = pn_delivery(pn_event_link(e), pn_dtag("x", 1)); } return PN_LINK_FLOW; case PN_CONNECTION_WAKE: { /* Send a chunk */ ssize_t remains = ctx->size - ctx->sent; ssize_t n = (CHUNK < remains) ? CHUNK : remains; TEST_CHECK(th->t, n == pn_link_send(ctx->sender, ctx->send_buf.start + ctx->sent, n)); ctx->sent += n; if (ctx->sent == ctx->size) { TEST_CHECK(th->t, pn_link_advance(ctx->sender)); } return PN_CONNECTION_WAKE; } case PN_DELIVERY: { /* Receive a delivery - smaller than a chunk? */ pn_delivery_t *dlv = pn_event_delivery(e); if (pn_delivery_readable(dlv)) { ssize_t n = pn_delivery_pending(dlv); rwbytes_ensure(&ctx->recv_buf, ctx->received + n); TEST_ASSERT(n == pn_link_recv(pn_event_link(e), ctx->recv_buf.start + ctx->received, n)); ctx->received += n; } ctx->complete = !pn_delivery_partial(dlv); return PN_DELIVERY; } default: return common_handler(th, e); } }
static void CORE_link_flow(void *context, qdr_link_t *link, int credit) { 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) pn_link_flow(plink, credit); }
bool ConnectionContext::fetch(boost::shared_ptr<SessionContext> ssn, boost::shared_ptr<ReceiverContext> lnk, qpid::messaging::Message& message, qpid::messaging::Duration timeout) { { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); if (!lnk->capacity) { pn_link_flow(lnk->receiver, 1); wakeupDriver(); } } if (get(ssn, lnk, message, timeout)) { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); if (lnk->capacity) { pn_link_flow(lnk->receiver, 1);//TODO: is this the right approach? wakeupDriver(); } return true; } else { { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); pn_link_drain(lnk->receiver, 0); wakeupDriver(); while (pn_link_credit(lnk->receiver) && !pn_link_queued(lnk->receiver)) { QPID_LOG(debug, "Waiting for message or for credit to be drained: credit=" << pn_link_credit(lnk->receiver) << ", queued=" << pn_link_queued(lnk->receiver)); wait(); } if (lnk->capacity && pn_link_queued(lnk->receiver) == 0) { pn_link_flow(lnk->receiver, lnk->capacity); } } if (get(ssn, lnk, message, qpid::messaging::Duration::IMMEDIATE)) { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); if (lnk->capacity) { pn_link_flow(lnk->receiver, 1); wakeupDriver(); } return true; } else { return false; } } }
void ConnectionContext::attach(pn_session_t* /*session*/, pn_link_t* link, int credit) { qpid::sys::ScopedLock<qpid::sys::Monitor> l(lock); QPID_LOG(debug, "Attaching link " << link << ", state=" << pn_link_state(link)); pn_link_open(link); QPID_LOG(debug, "Link attached " << link << ", state=" << pn_link_state(link)); if (credit) pn_link_flow(link, credit); wakeupDriver(); while (pn_link_state(link) & PN_REMOTE_UNINIT) { QPID_LOG(debug, "waiting for confirmation of link attach for " << link << ", state=" << pn_link_state(link)); wait(); } }
static void do_receive(pn_delivery_t *pnd) { pn_link_t *pn_link = pn_delivery_link(pnd); qd_link_t *link = (qd_link_t*) pn_link_get_context(pn_link); if (link) { qd_node_t *node = link->node; if (node) { node->ntype->rx_handler(node->context, link, pnd); return; } } // // Reject the delivery if we couldn't find a node to handle it // pn_link_advance(pn_link); pn_link_flow(pn_link, 1); pn_delivery_update(pnd, PN_REJECTED); pn_delivery_settle(pnd); }
/** * New Incoming Link Handler */ static int router_incoming_link_handler(void* context, dx_link_t *link) { dx_router_t *router = (dx_router_t*) context; dx_link_item_t *item = new_dx_link_item_t(); pn_link_t *pn_link = dx_link_pn(link); if (item) { DEQ_ITEM_INIT(item); item->link = link; sys_mutex_lock(router->lock); DEQ_INSERT_TAIL(router->in_links, item); sys_mutex_unlock(router->lock); pn_terminus_copy(pn_link_source(pn_link), pn_link_remote_source(pn_link)); pn_terminus_copy(pn_link_target(pn_link), pn_link_remote_target(pn_link)); pn_link_flow(pn_link, 8); pn_link_open(pn_link); } else { pn_link_close(pn_link); } return 0; }
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(); } } }
void connection_dispatch(pn_handler_t *h, pn_event_t *event, pn_event_type_t type) { connection_context_t *cc = connection_context(h); bool replying = cc->global->opts->reply; switch (type) { case PN_LINK_REMOTE_OPEN: { pn_link_t *link = pn_event_link(event); if (pn_link_is_receiver(link)) { check(cc->recv_link == NULL, "Multiple incomming links on one connection"); cc->recv_link = link; pn_connection_t *conn = pn_event_connection(event); pn_list_add(cc->global->active_connections, conn); if (cc->global->shutting_down) { pn_connection_close(conn); break; } if (replying) { // Set up a reply link and defer granting credit to the incoming link pn_connection_t *conn = pn_session_connection(pn_link_session(link)); pn_session_t *ssn = pn_session(conn); pn_session_open(ssn); char name[100]; // prefer a multiplatform uuid generator sprintf(name, "reply_sender_%d", cc->connection_id); cc->reply_link = pn_sender(ssn, name); pn_link_open(cc->reply_link); } else { pn_flowcontroller_t *fc = pn_flowcontroller(1024); pn_handler_add(h, fc); pn_decref(fc); } } } break; case PN_LINK_FLOW: { if (replying) { pn_link_t *reply_link = pn_event_link(event); // pn_flowcontroller handles the non-reply case check(reply_link == cc->reply_link, "internal error"); // Grant the sender as much credit as just given to us for replies int delta = pn_link_credit(reply_link) - pn_link_credit(cc->recv_link); if (delta > 0) pn_link_flow(cc->recv_link, delta); } } break; case PN_DELIVERY: { pn_link_t *recv_link = pn_event_link(event); pn_delivery_t *dlv = pn_event_delivery(event); if (pn_link_is_receiver(recv_link) && !pn_delivery_partial(dlv)) { if (cc->global->received == 0) statistics_start(cc->global->stats); size_t encoded_size = pn_delivery_pending(dlv); cc->global->encoded_data = ensure_buffer(cc->global->encoded_data, encoded_size, &cc->global->encoded_data_size); check(cc->global->encoded_data, "decoding buffer realloc failure"); ssize_t n = pn_link_recv(recv_link, cc->global->encoded_data, encoded_size); check(n == (ssize_t) encoded_size, "message data read fail"); pn_message_t *msg = cc->global->message; int err = pn_message_decode(msg, cc->global->encoded_data, n); check(err == 0, "message decode error"); cc->global->received++; pn_delivery_settle(dlv); statistics_msg_received(cc->global->stats, msg); if (replying) { const char *reply_addr = pn_message_get_reply_to(msg); if (reply_addr) { pn_link_t *rl = cc->reply_link; check(pn_link_credit(rl) > 0, "message received without corresponding reply credit"); LOG("Replying to: %s\n", reply_addr ); pn_message_set_address(msg, reply_addr); pn_message_set_creation_time(msg, msgr_now()); char tag[8]; void *ptr = &tag; *((uint64_t *) ptr) = cc->global->sent; pn_delivery_t *dlv = pn_delivery(rl, pn_dtag(tag, 8)); size_t size = cc->global->encoded_data_size; int err = pn_message_encode(msg, cc->global->encoded_data, &size); check(err == 0, "message encoding error"); pn_link_send(rl, cc->global->encoded_data, size); pn_delivery_settle(dlv); cc->global->sent++; } } } if (cc->global->received >= cc->global->opts->msg_count) { global_shutdown(cc->global); } } break; case PN_CONNECTION_UNBOUND: { pn_connection_t *conn = pn_event_connection(event); pn_list_remove(cc->global->active_connections, conn); pn_connection_release(conn); } break; default: break; } }
/** * Inbound Delivery Handler */ static void router_rx_handler(void* context, dx_link_t *link, pn_delivery_t *delivery) { dx_router_t *router = (dx_router_t*) context; pn_link_t *pn_link = pn_delivery_link(delivery); dx_message_t *msg; int valid_message = 0; // // Receive the message into a local representation. If the returned message // pointer is NULL, we have not yet received a complete message. // sys_mutex_lock(router->lock); msg = dx_message_receive(delivery); sys_mutex_unlock(router->lock); if (!msg) return; // // Validate the message through the Properties section // valid_message = dx_message_check(msg, DX_DEPTH_PROPERTIES); pn_link_advance(pn_link); pn_link_flow(pn_link, 1); if (valid_message) { dx_field_iterator_t *iter = dx_message_field_iterator(msg, DX_FIELD_TO); dx_router_link_t *rlink; if (iter) { dx_field_iterator_reset(iter, ITER_VIEW_NO_HOST); sys_mutex_lock(router->lock); int result = hash_retrieve(router->out_hash, iter, (void*) &rlink); dx_field_iterator_free(iter); if (result == 0) { // // To field is valid and contains a known destination. Enqueue on // the output fifo for the next-hop-to-destination. // pn_link_t* pn_outlink = dx_link_pn(rlink->link); DEQ_INSERT_TAIL(rlink->out_fifo, msg); pn_link_offered(pn_outlink, DEQ_SIZE(rlink->out_fifo)); dx_link_activate(rlink->link); } else { // // To field contains an unknown address. Release the message. // pn_delivery_update(delivery, PN_RELEASED); pn_delivery_settle(delivery); } sys_mutex_unlock(router->lock); } } else { // // Message is invalid. Reject the message. // pn_delivery_update(delivery, PN_REJECTED); pn_delivery_settle(delivery); pn_delivery_set_context(delivery, 0); dx_free_message(msg); } }
int main ( int argc, char ** argv ) { char info[1000]; int expected = (argc > 1) ? atoi(argv[1]) : 100000; int received = 0; int size = 32; int msg_size = 50; bool done = false; int initial_credit = 500, new_credit = 250, low_credit_limit = 250; char const * host = "0.0.0.0"; char const * port = "5672"; bool sasl_done = false; pn_driver_t * driver; pn_listener_t * listener; pn_connector_t * connector; pn_connection_t * connection; pn_session_t * session; pn_link_t * link; pn_delivery_t * delivery; char * message_data = (char *) malloc ( MY_BUF_SIZE ); int message_data_capacity = MY_BUF_SIZE; fprintf ( stderr, "drecv expecting %d messages.\n", expected ); driver = pn_driver ( ); if ( ! pn_listener(driver, host, port, 0) ) { fprintf ( stderr, "listener creation failed.\n" ); exit ( 1 ); } while ( ! done) { pn_driver_wait ( driver, -1 ); if ( (listener = pn_driver_listener(driver)) ) pn_listener_accept( listener ); if ( (connector = pn_driver_connector(driver)) ) { pn_connector_process ( connector ); if ( ! sasl_done ) if( ! (sasl_done = get_sasl_over_with(connector) )) continue; connection = pn_connector_connection ( connector ); /*========================================================= Open everything that is ready on the other side but not here. =========================================================*/ pn_state_t hes_ready_im_not = PN_LOCAL_UNINIT | PN_REMOTE_ACTIVE; if (pn_connection_state(connection) == hes_ready_im_not) pn_connection_open( connection); for ( session = pn_session_head(connection, hes_ready_im_not); session; session = pn_session_next(session, hes_ready_im_not) ) pn_session_open(session); for ( link = pn_link_head(connection, hes_ready_im_not); link; link = pn_link_next(link, hes_ready_im_not) ) { pn_terminus_copy(pn_link_source(link), pn_link_remote_source(link)); pn_terminus_copy(pn_link_target(link), pn_link_remote_target(link)); pn_link_open ( link ); if ( pn_link_is_receiver(link) ) pn_link_flow ( link, initial_credit ); } /*========================================================== Get all available deliveries. ==========================================================*/ for ( delivery = pn_work_head ( connection ); delivery; delivery = pn_work_next ( delivery ) ) { if ( pn_delivery_readable(delivery) ) { link = pn_delivery_link ( delivery ); while ( PN_EOS != pn_link_recv(link, message_data, MY_BUF_SIZE) ) ; pn_link_advance ( link ); pn_delivery_update ( delivery, PN_ACCEPTED ); pn_delivery_settle ( delivery ); if ( ++ received >= expected ) { sprintf ( info, "received %d messages", received ); print_timestamp ( stderr, info ); done = true; } // a progress report for long tests. if ( ! (received % 5000000) ) fprintf ( stderr, "received: %d\n", received ); if ( pn_link_credit(link) <= low_credit_limit ) pn_link_flow ( link, new_credit ); } else { // TODO // Why am I getting writables? // And what to do with them? } } /*=============================================================== Shut down everything that the other side has closed. ===============================================================*/ pn_state_t active_here_closed_there = PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED; if ( pn_connection_state(connection) == active_here_closed_there ) pn_connection_close ( connection ); for ( session = pn_session_head(connection, active_here_closed_there); session; session = pn_session_next(session, active_here_closed_there) ) pn_session_close ( session ); for ( link = pn_link_head(connection, active_here_closed_there); link; link = pn_link_next(link, active_here_closed_there) ) pn_link_close ( link ); if ( pn_connector_closed(connector) ) { pn_connection_free ( pn_connector_connection(connector) ); pn_connector_free ( connector ); done = true; } else pn_connector_process(connector); } } pn_driver_free(driver); return 0; }
/** * Inbound Delivery Handler */ static void AMQP_rx_handler(void* context, qd_link_t *link, pn_delivery_t *pnd) { qd_router_t *router = (qd_router_t*) context; pn_link_t *pn_link = qd_link_pn(link); qdr_link_t *rlink = (qdr_link_t*) qd_link_get_context(link); qdr_delivery_t *delivery = 0; qd_message_t *msg; // // Receive the message into a local representation. If the returned message // pointer is NULL, we have not yet received a complete message. // // Note: In the link-routing case, consider cutting the message through. There's // no reason to wait for the whole message to be received before starting to // send it. // msg = qd_message_receive(pnd); if (!msg) return; // // Consume the delivery. // pn_link_advance(pn_link); // // If there's no router link, free the message and finish. It's likely that the link // is closing. // if (!rlink) { qd_message_free(msg); return; } // // Handle the link-routed case // if (qdr_link_is_routed(rlink)) { pn_delivery_tag_t dtag = pn_delivery_tag(pnd); delivery = qdr_link_deliver_to_routed_link(rlink, msg, pn_delivery_settled(pnd), (uint8_t*) dtag.start, dtag.size); if (delivery) { if (pn_delivery_settled(pnd)) pn_delivery_settle(pnd); else { pn_delivery_set_context(pnd, delivery); qdr_delivery_set_context(delivery, pnd); qdr_delivery_incref(delivery); } } return; } // // Determine if the incoming link is anonymous. If the link is addressed, // there are some optimizations we can take advantage of. // bool anonymous_link = qdr_link_is_anonymous(rlink); // // Determine if the user of this connection is allowed to proxy the // user_id of messages. A message user_id is proxied when the // property value differs from the authenticated user name of the connection. // If the user is not allowed to proxy the user_id then the message user_id // must be blank or it must be equal to the connection user name. // bool check_user = false; qd_connection_t *conn = qd_link_connection(link); if (conn->policy_settings) check_user = !conn->policy_settings->allowUserIdProxy; // // Validate the content of the delivery as an AMQP message. This is done partially, only // to validate that we can find the fields we need to route the message. // // If the link is anonymous, we must validate through the message properties to find the // 'to' field. If the link is not anonymous, we don't need the 'to' field as we will be // using the address from the link target. // qd_message_depth_t validation_depth = (anonymous_link || check_user) ? QD_DEPTH_PROPERTIES : QD_DEPTH_MESSAGE_ANNOTATIONS; bool valid_message = qd_message_check(msg, validation_depth); if (valid_message) { if (check_user) { // This connection must not allow proxied user_id qd_iterator_t *userid_iter = qd_message_field_iterator(msg, QD_FIELD_USER_ID); if (userid_iter) { // The user_id property has been specified if (qd_iterator_remaining(userid_iter) > 0) { // user_id property in message is not blank if (!qd_iterator_equal(userid_iter, (const unsigned char *)conn->user_id)) { // This message is rejected: attempted user proxy is disallowed qd_log(router->log_source, QD_LOG_DEBUG, "Message rejected due to user_id proxy violation. User:%s", conn->user_id); pn_link_flow(pn_link, 1); pn_delivery_update(pnd, PN_REJECTED); pn_delivery_settle(pnd); qd_message_free(msg); qd_iterator_free(userid_iter); return; } } qd_iterator_free(userid_iter); } } qd_parsed_field_t *in_ma = qd_message_message_annotations(msg); qd_bitmask_t *link_exclusions; bool strip = qdr_link_strip_annotations_in(rlink); qd_iterator_t *ingress_iter = router_annotate_message(router, in_ma, msg, &link_exclusions, strip); if (anonymous_link) { qd_iterator_t *addr_iter = 0; int phase = 0; // // If the message has delivery annotations, get the to-override field from the annotations. // if (in_ma) { qd_parsed_field_t *ma_to = qd_parse_value_by_key(in_ma, QD_MA_TO); if (ma_to) { addr_iter = qd_iterator_dup(qd_parse_raw(ma_to)); phase = qd_message_get_phase_annotation(msg); } } // // Still no destination address? Use the TO field from the message properties. // if (!addr_iter) addr_iter = qd_message_field_iterator(msg, QD_FIELD_TO); if (addr_iter) { qd_iterator_reset_view(addr_iter, ITER_VIEW_ADDRESS_HASH); if (phase > 0) qd_iterator_annotate_phase(addr_iter, '0' + (char) phase); delivery = qdr_link_deliver_to(rlink, msg, ingress_iter, addr_iter, pn_delivery_settled(pnd), link_exclusions); } } else { const char *term_addr = pn_terminus_get_address(qd_link_remote_target(link)); if (!term_addr) term_addr = pn_terminus_get_address(qd_link_source(link)); if (term_addr) { qd_composed_field_t *to_override = qd_compose_subfield(0); qd_compose_insert_string(to_override, term_addr); qd_message_set_to_override_annotation(msg, to_override); int phase = qdr_link_phase(rlink); if (phase != 0) qd_message_set_phase_annotation(msg, phase); } delivery = qdr_link_deliver(rlink, msg, ingress_iter, pn_delivery_settled(pnd), link_exclusions); } if (delivery) { if (pn_delivery_settled(pnd)) pn_delivery_settle(pnd); else { pn_delivery_set_context(pnd, delivery); qdr_delivery_set_context(delivery, pnd); qdr_delivery_incref(delivery); } } else { // // The message is now and will always be unroutable because there is no address. // pn_link_flow(pn_link, 1); pn_delivery_update(pnd, PN_REJECTED); pn_delivery_settle(pnd); qd_message_free(msg); } // // Rules for delivering messages: // // For addressed (non-anonymous) links: // to-override must be set (done in the core?) // uses qdr_link_deliver to hand over to the core // // For anonymous links: // If there's a to-override in the annotations, use that address // Or, use the 'to' field in the message properties // } else { // // Message is invalid. Reject the message and don't involve the router core. // pn_link_flow(pn_link, 1); pn_delivery_update(pnd, PN_REJECTED); pn_delivery_settle(pnd); qd_message_free(msg); } }