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);
}
Exemple #2
0
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);
}
Exemple #4
0
/** 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);
    }
}