static void qd_io_rx_handler(void *context, qd_message_t *msg, int link_id) { IoAdapter *self = (IoAdapter*) context; // // Parse the message through the body and exit if the message is not well formed. // if (!qd_message_check(msg, QD_DEPTH_BODY)) return; // This is called from non-python threads so we need to acquire the GIL to use python APIS. qd_python_lock_state_t lock_state = qd_python_lock(); PyObject *py_msg = PyObject_CallFunction(message_type, NULL); if (!py_msg) { qd_error_py(); qd_python_unlock(lock_state); return; } iter_to_py_attr(qd_message_field_iterator(msg, QD_FIELD_TO), py_iter_copy, py_msg, "address"); iter_to_py_attr(qd_message_field_iterator(msg, QD_FIELD_REPLY_TO), py_iter_copy, py_msg, "reply_to"); // Note: correlation ID requires _typed() iter_to_py_attr(qd_message_field_iterator_typed(msg, QD_FIELD_CORRELATION_ID), py_iter_parse, py_msg, "correlation_id"); iter_to_py_attr(qd_message_field_iterator(msg, QD_FIELD_APPLICATION_PROPERTIES), py_iter_parse, py_msg, "properties"); iter_to_py_attr(qd_message_field_iterator(msg, QD_FIELD_BODY), py_iter_parse, py_msg, "body"); PyObject *value = PyObject_CallFunction(self->handler, "Ol", py_msg, link_id); Py_DECREF(py_msg); Py_XDECREF(value); qd_error_py(); qd_python_unlock(lock_state); }
qd_parsed_field_t *qd_message_message_annotations(qd_message_t *in_msg) { qd_message_pvt_t *msg = (qd_message_pvt_t*) in_msg; qd_message_content_t *content = msg->content; if (content->parsed_message_annotations) return content->parsed_message_annotations; qd_field_iterator_t *ma = qd_message_field_iterator(in_msg, QD_FIELD_MESSAGE_ANNOTATION); if (ma == 0) return 0; content->parsed_message_annotations = qd_parse(ma); if (content->parsed_message_annotations == 0 || !qd_parse_ok(content->parsed_message_annotations) || !qd_parse_is_map(content->parsed_message_annotations)) { qd_field_iterator_free(ma); qd_parse_free(content->parsed_message_annotations); content->parsed_message_annotations = 0; return 0; } qd_field_iterator_free(ma); return content->parsed_message_annotations; }
static void qd_core_agent_create_handler(qdr_core_t *core, qd_message_t *msg, qd_router_entity_type_t entity_type, qd_router_operation_type_t operation_type, qd_field_iterator_t *name_iter) { // // Add the Body // qd_composed_field_t *out_body = qd_compose(QD_PERFORMATIVE_BODY_AMQP_VALUE, 0); // Set the callback function. qdr_manage_handler(core, qd_manage_response_handler); // Call local function that creates and returns a qd_management_context_t containing the values passed in. qd_management_context_t *ctx = qd_management_context(qd_message(), msg, out_body, 0, core, operation_type, 0); qd_field_iterator_t *body_iter = qd_message_field_iterator(msg, QD_FIELD_BODY); qd_parsed_field_t *in_body = qd_parse(body_iter); qdr_manage_create(core, ctx, entity_type, name_iter, in_body, out_body); qd_field_iterator_free(body_iter); }
/** Copy a message field for use in log messages. Output in buffer. */ static void copy_field(qd_message_t *msg, int field, int max, char *pre, char *post, char **begin, char *end) { qd_field_iterator_t* iter = qd_message_field_iterator(msg, field); if (iter) { aprintf(begin, end, "%s", pre); qd_field_iterator_reset(iter); for (int j = 0; !qd_field_iterator_end(iter) && j < max; ++j) { char byte = qd_field_iterator_octet(iter); quote(&byte, 1, begin, end); } aprintf(begin, end, "%s", post); qd_field_iterator_free(iter); } }
/** * * Handler for the management agent. * */ void qdr_management_agent_on_message(void *context, qd_message_t *msg, int unused_link_id, int unused_cost) { qdr_core_t *core = (qdr_core_t*) context; qd_field_iterator_t *app_properties_iter = qd_message_field_iterator(msg, QD_FIELD_APPLICATION_PROPERTIES); qd_router_entity_type_t entity_type = 0; qd_router_operation_type_t operation_type = 0; qd_field_iterator_t *identity_iter = 0; qd_field_iterator_t *name_iter = 0; int32_t count = 0; int32_t offset = 0; qd_parsed_field_t *properties_fld = qd_parse(app_properties_iter); if (qd_can_handle_request(properties_fld, &entity_type, &operation_type, &identity_iter, &name_iter, &count, &offset)) { switch (operation_type) { case QD_ROUTER_OPERATION_QUERY: qd_core_agent_query_handler(core, entity_type, operation_type, msg, &count, &offset); break; case QD_ROUTER_OPERATION_CREATE: qd_core_agent_create_handler(core, msg, entity_type, operation_type, name_iter); break; case QD_ROUTER_OPERATION_READ: qd_core_agent_read_handler(core, msg, entity_type, operation_type, identity_iter, name_iter); break; case QD_ROUTER_OPERATION_UPDATE: qd_core_agent_update_handler(core, msg, entity_type, operation_type, identity_iter, name_iter); break; case QD_ROUTER_OPERATION_DELETE: qd_core_agent_delete_handler(core, msg, entity_type, operation_type, identity_iter, name_iter); break; } } else { // // The C management agent is not going to handle this request. Forward it off to Python. // qdr_send_to2(core, msg, MANAGEMENT_INTERNAL, false, false); } qd_field_iterator_free(app_properties_iter); qd_parse_free(properties_fld); }
static void qd_core_agent_query_handler(qdr_core_t *core, qd_router_entity_type_t entity_type, qd_router_operation_type_t operation_type, qd_message_t *msg, int *count, int *offset) { // // Add the Body. // qd_composed_field_t *field = qd_compose(QD_PERFORMATIVE_BODY_AMQP_VALUE, 0); // Start a map in the body. Look for the end map in the callback function, qd_manage_response_handler. qd_compose_start_map(field); //add a "attributeNames" key qd_compose_insert_string(field, ATTRIBUTE_NAMES); // Call local function that creates and returns a local qd_management_context_t object containing the values passed in. qd_management_context_t *ctx = qd_management_context(qd_message(), msg, field, 0, core, operation_type, (*count)); // Grab the attribute names from the incoming message body. The attribute names will be used later on in the response. qd_parsed_field_t *attribute_names_parsed_field = 0; qd_field_iterator_t *body_iter = qd_message_field_iterator(msg, QD_FIELD_BODY); qd_parsed_field_t *body = qd_parse(body_iter); if (body != 0 && qd_parse_is_map(body)) { attribute_names_parsed_field = qd_parse_value_by_key(body, ATTRIBUTE_NAMES); } // Set the callback function. qdr_manage_handler(core, qd_manage_response_handler); ctx->query = qdr_manage_query(core, ctx, entity_type, attribute_names_parsed_field, field); //Add the attribute names qdr_query_add_attribute_names(ctx->query); //this adds a list of attribute names like ["attribute1", "attribute2", "attribute3", "attribute4",] qd_compose_insert_string(field, results); //add a "results" key qd_compose_start_list(field); //start the list for results qdr_query_get_first(ctx->query, (*offset)); qd_field_iterator_free(body_iter); qd_parse_free(body); }
static void qd_set_properties(qd_message_t *msg, qd_field_iterator_t **reply_to, qd_composed_field_t **fld) { qd_field_iterator_t *correlation_id = qd_message_field_iterator_typed(msg, QD_FIELD_CORRELATION_ID); // Grab the reply_to field from the incoming message. This is the address we will send the response to. *reply_to = qd_message_field_iterator(msg, QD_FIELD_REPLY_TO); *fld = qd_compose(QD_PERFORMATIVE_PROPERTIES, 0); qd_compose_start_list(*fld); qd_compose_insert_null(*fld); // message-id qd_compose_insert_null(*fld); // user-id qd_compose_insert_string_iterator(*fld, *reply_to); // to qd_compose_insert_null(*fld); // subject qd_compose_insert_null(*fld); qd_compose_insert_typed_iterator(*fld, correlation_id); qd_compose_end_list(*fld); qd_field_iterator_free(correlation_id); }
static void qd_core_agent_update_handler(qdr_core_t *core, qd_message_t *msg, qd_router_entity_type_t entity_type, qd_router_operation_type_t operation_type, qd_field_iterator_t *identity_iter, qd_field_iterator_t *name_iter) { qd_composed_field_t *out_body = qd_compose(QD_PERFORMATIVE_BODY_AMQP_VALUE, 0); // Set the callback function. qdr_manage_handler(core, qd_manage_response_handler); qd_management_context_t *ctx = qd_management_context(qd_message(), msg, out_body, 0, core, operation_type, 0); qd_field_iterator_t *iter = qd_message_field_iterator(msg, QD_FIELD_BODY); qd_parsed_field_t *in_body= qd_parse(iter); qd_field_iterator_free(iter); qdr_manage_update(core, ctx, entity_type, name_iter, identity_iter, in_body, out_body); }
/** * 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); } }