Example #1
0
qdr_auto_link_t *qdr_route_add_auto_link_CT(qdr_core_t          *core,
                                            qd_iterator_t       *name,
                                            qd_parsed_field_t   *addr_field,
                                            qd_direction_t       dir,
                                            int                  phase,
                                            qd_parsed_field_t   *container_field,
                                            qd_parsed_field_t   *connection_field,
                                            qd_parsed_field_t   *external_addr)
{
    qdr_auto_link_t *al = new_qdr_auto_link_t();

    //
    // Set up the auto_link structure
    //
    ZERO(al);
    al->identity      = qdr_identifier(core);
    al->name          = name ? (char*) qd_iterator_copy(name) : 0;
    al->dir           = dir;
    al->phase         = phase;
    al->state         = QDR_AUTO_LINK_STATE_INACTIVE;
    al->external_addr = external_addr ? (char*) qd_iterator_copy(qd_parse_raw(external_addr)) : 0;

    //
    // Find or create an address for the auto_link destination
    //
    qd_iterator_t *iter = qd_parse_raw(addr_field);
    qd_iterator_reset_view(iter, ITER_VIEW_ADDRESS_HASH);
    qd_iterator_annotate_phase(iter, (char) phase + '0');

    qd_hash_retrieve(core->addr_hash, iter, (void*) &al->addr);
    if (!al->addr) {
        al->addr = qdr_address_CT(core, qdr_treatment_for_address_CT(core, 0, iter, 0, 0));
        DEQ_INSERT_TAIL(core->addrs, al->addr);
        qd_hash_insert(core->addr_hash, iter, al->addr, &al->addr->hash_handle);
    }

    al->addr->ref_count++;

    //
    // Find or create a connection identifier structure for this auto_link
    //
    if (container_field || connection_field) {
        al->conn_id = qdr_route_declare_id_CT(core, qd_parse_raw(container_field), qd_parse_raw(connection_field));
        DEQ_INSERT_TAIL_N(REF, al->conn_id->auto_link_refs, al);
        qdr_connection_ref_t * cref = DEQ_HEAD(al->conn_id->connection_refs);
        while (cref) {
            qdr_auto_link_activate_CT(core, al, cref->conn);
            cref = DEQ_NEXT(cref);
        }
    }

    //
    // Add the auto_link to the core list
    //
    DEQ_INSERT_TAIL(core->auto_links, al);

    return al;
}
Example #2
0
qdr_link_route_t *qdr_route_add_link_route_CT(qdr_core_t             *core,
                                              qd_iterator_t          *name,
                                              qd_parsed_field_t      *prefix_field,
                                              qd_parsed_field_t      *container_field,
                                              qd_parsed_field_t      *connection_field,
                                              qd_address_treatment_t  treatment,
                                              qd_direction_t          dir)
{
    qdr_link_route_t *lr = new_qdr_link_route_t();

    //
    // Set up the link_route structure
    //
    ZERO(lr);
    lr->identity  = qdr_identifier(core);
    lr->name      = name ? (char*) qd_iterator_copy(name) : 0;
    lr->dir       = dir;
    lr->treatment = treatment;

    //
    // Find or create an address for link-attach routing
    //
    qd_iterator_t *iter = qd_parse_raw(prefix_field);
    qd_iterator_reset_view(iter, ITER_VIEW_ADDRESS_HASH);
    qd_iterator_annotate_prefix(iter, dir == QD_INCOMING ? 'C' : 'D');

    qd_hash_retrieve(core->addr_hash, iter, (void*) &lr->addr);
    if (!lr->addr) {
        lr->addr = qdr_address_CT(core, treatment);
        DEQ_INSERT_TAIL(core->addrs, lr->addr);
        qd_hash_insert(core->addr_hash, iter, lr->addr, &lr->addr->hash_handle);
    }

    lr->addr->ref_count++;

    //
    // Find or create a connection identifier structure for this link route
    //
    if (container_field || connection_field) {
        lr->conn_id = qdr_route_declare_id_CT(core, qd_parse_raw(container_field), qd_parse_raw(connection_field));
        DEQ_INSERT_TAIL_N(REF, lr->conn_id->link_route_refs, lr);
        qdr_connection_ref_t * cref = DEQ_HEAD(lr->conn_id->connection_refs);
        while (cref) {
            qdr_link_route_activate_CT(core, lr, cref->conn);
            cref = DEQ_NEXT(cref);
        }
    }

    //
    // Add the link route to the core list
    //
    DEQ_INSERT_TAIL(core->link_routes, lr);

    return lr;
}
static const char *qdra_link_route_treatment_CT(qd_parsed_field_t *field, qd_address_treatment_t *trt)
{
    if (field) {
        qd_field_iterator_t *iter = qd_parse_raw(field);
        if (qd_field_iterator_equal(iter, (unsigned char*) "linkBalanced")) {
            *trt = QD_TREATMENT_LINK_BALANCED;
            return 0;
        }
        return "Invalid value for 'distribution'";
    }

    *trt = QD_TREATMENT_LINK_BALANCED;
    return 0;
}
static const char *qdra_auto_link_direction_CT(qd_parsed_field_t *field, qd_direction_t *dir)
{
    if (field) {
        qd_field_iterator_t *iter = qd_parse_raw(field);
        if (qd_field_iterator_equal(iter, (unsigned char*) "in")) {
            *dir = QD_INCOMING;
            return 0;
        } else if (qd_field_iterator_equal(iter, (unsigned char*) "out")) {
            *dir = QD_OUTGOING;
            return 0;
        }
        return "Invalid value for 'dir'";
    }
    return "Missing value for 'dir'";
}
Example #5
0
static void qdr_agent_set_columns(qdr_query_t *query,
                                  qd_parsed_field_t *attribute_names,
                                  const char *qdr_columns[],
                                  int column_count)
{
    if (!attribute_names ||
        (qd_parse_tag(attribute_names) != QD_AMQP_LIST8 &&
         qd_parse_tag(attribute_names) != QD_AMQP_LIST32) ||
        qd_parse_sub_count(attribute_names) == 0 ||
        qd_parse_sub_count(attribute_names) >= QDR_AGENT_MAX_COLUMNS) {
        //
        // Either the attribute_names field is absent, it's not a list, or it's an empty list.
        // In this case, we will include all available attributes.
        //
        int i;
        for (i = 0; i < column_count; i++)
            query->columns[i] = i;
        query->columns[i] = -1;
        assert(i < QDR_AGENT_MAX_COLUMNS);
        return;
    }

    //
    // We have a valid, non-empty attribute list.  Set the columns appropriately.
    //
    uint32_t count = qd_parse_sub_count(attribute_names);
    uint32_t idx;

    for (idx = 0; idx < count; idx++) {
        qd_parsed_field_t *name = qd_parse_sub_value(attribute_names, idx);
        if (!name || (qd_parse_tag(name) != QD_AMQP_STR8_UTF8 && qd_parse_tag(name) != QD_AMQP_STR32_UTF8))
            query->columns[idx] = QDR_AGENT_COLUMN_NULL;
        else {
            int j = 0;
            while (qdr_columns[j]) {
                qd_field_iterator_t *iter = qd_parse_raw(name);
                if (qd_field_iterator_equal(iter, (const unsigned char*) qdr_columns[j])) {
                    query->columns[idx] = j;
                    break;
                }
                j+=1;
            }
        }
    }
    query->columns[idx+1] = -1;
}
Example #6
0
qd_parsed_field_t *qd_parse_value_by_key(qd_parsed_field_t *field, const char *key)
{
    uint32_t count = qd_parse_sub_count(field);

    for (uint32_t idx = 0; idx < count; idx++) {
        qd_parsed_field_t *sub  = qd_parse_sub_key(field, idx);
        if (!sub)
            return 0;

        qd_iterator_t *iter = qd_parse_raw(sub);
        if (!iter)
            return 0;

        if (qd_iterator_equal(iter, (const unsigned char*) key)) {
            return qd_parse_sub_value(field, idx);
        }
    }

    return 0;
}
Example #7
0
qd_bitmask_t *qd_tracemask_create(qd_tracemask_t *tm, qd_parsed_field_t *tracelist)
{
    qd_bitmask_t *bm  = qd_bitmask(0);
    int           idx = 0;

    assert(qd_parse_is_list(tracelist));

    sys_rwlock_rdlock(tm->lock);
    qd_parsed_field_t *item   = qd_parse_sub_value(tracelist, idx);
    qdtm_router_t     *router = 0;
    while (item) {
        qd_field_iterator_t *iter = qd_parse_raw(item);
        qd_address_iterator_reset_view(iter, ITER_VIEW_NODE_HASH);
        qd_hash_retrieve(tm->hash, iter, (void*) &router);
        if (router && router->link_maskbit >= 0)
            qd_bitmask_set_bit(bm, router->link_maskbit);
        idx++;
        item = qd_parse_sub_value(tracelist, idx);
    }
    sys_rwlock_unlock(tm->lock);
    return bm;
}
Example #8
0
static PyObject *parsed_to_py_string(qd_parsed_field_t *field)
{
    switch (qd_parse_tag(field)) {
      case QD_AMQP_VBIN8:
      case QD_AMQP_VBIN32:
      case QD_AMQP_STR8_UTF8:
      case QD_AMQP_STR32_UTF8:
      case QD_AMQP_SYM8:
      case QD_AMQP_SYM32:
        break;
      default:
        Py_RETURN_NONE;
    }

#define SHORT_BUF 1024
    uint8_t short_buf[SHORT_BUF];
    PyObject *result;
    qd_field_iterator_t *raw = qd_parse_raw(field);
    qd_field_iterator_reset(raw);
    uint32_t length = qd_field_iterator_remaining(raw);
    uint8_t *buffer = short_buf;
    uint8_t *ptr;
    int alloc = 0;

    if (length > SHORT_BUF) {
        alloc = 1;
        buffer = (uint8_t*) malloc(length);
    }

    ptr = buffer;
    while (!qd_field_iterator_end(raw))
        *(ptr++) = qd_field_iterator_octet(raw);
    result = PyString_FromStringAndSize((char*) buffer, ptr - buffer);
    if (alloc)
        free(buffer);

    return result;
}
Example #9
0
const char *qd_parse_annotations_v1(
    bool                   strip_anno_in,
    qd_iterator_t         *ma_iter_in,
    qd_parsed_field_t    **ma_ingress,
    qd_parsed_field_t    **ma_phase,
    qd_parsed_field_t    **ma_to_override,
    qd_parsed_field_t    **ma_trace,
    qd_iterator_pointer_t *blob_pointer,
    uint32_t              *blob_item_count)
{
    // Do full parse
    qd_iterator_reset(ma_iter_in);

    qd_parsed_turbo_list_t annos;
    uint32_t               user_entries;
    uint32_t               user_bytes;
    const char * parse_error = qd_parse_turbo(ma_iter_in, &annos, &user_entries, &user_bytes);
    if (parse_error) {
        return parse_error;
    }

    qd_parsed_turbo_t *anno;
    if (!strip_anno_in) {
        anno = DEQ_HEAD(annos);
        while (anno) {
            qd_iterator_t *key_iter =
                qd_iterator_buffer(anno->bufptr.buffer,
                                anno->bufptr.cursor - qd_buffer_base(anno->bufptr.buffer),
                                anno->size,
                                ITER_VIEW_ALL);
            assert(key_iter);

            qd_parsed_field_t *key_field = qd_parse(key_iter);
            assert(key_field);

            qd_iterator_t *iter = qd_parse_raw(key_field);
            assert(iter);

            qd_parsed_turbo_t *anno_val = DEQ_NEXT(anno);
            assert(anno_val);

            qd_iterator_t *val_iter =
                qd_iterator_buffer(anno_val->bufptr.buffer,
                                anno_val->bufptr.cursor - qd_buffer_base(anno_val->bufptr.buffer),
                                anno_val->size,
                                ITER_VIEW_ALL);
            assert(val_iter);

            qd_parsed_field_t *val_field = qd_parse(val_iter);
            assert(val_field);

            // Hoist the key name out of the buffers into a normal char array
            char key_name[QD_MA_MAX_KEY_LEN + 1];
            (void)qd_iterator_strncpy(iter, key_name, QD_MA_MAX_KEY_LEN + 1);

            // transfer ownership of the extracted value to the message
            if        (!strcmp(key_name, QD_MA_TRACE)) {
                *ma_trace = val_field;
            } else if (!strcmp(key_name, QD_MA_INGRESS)) {
                *ma_ingress = val_field;
            } else if (!strcmp(key_name, QD_MA_TO)) {
                *ma_to_override = val_field;
            } else if (!strcmp(key_name, QD_MA_PHASE)) {
                *ma_phase = val_field;
            } else {
                // TODO: this key had the QD_MA_PREFIX but it does not match
                //       one of the actual fields. 
                qd_parse_free(val_field);
            }

            qd_iterator_free(key_iter);
            qd_parse_free(key_field);
            qd_iterator_free(val_iter);
            // val_field is usually handed over to message_private and is freed 

            anno = DEQ_NEXT(anno_val);
        }
    }

    anno = DEQ_HEAD(annos);
    while (anno) {
        DEQ_REMOVE_HEAD(annos);
        free_qd_parsed_turbo_t(anno);
        anno = DEQ_HEAD(annos);
    }

    // Adjust size of user annotation blob by the size of the router
    // annotations
    blob_pointer->remaining = user_bytes;
    assert(blob_pointer->remaining >= 0);

    *blob_item_count = user_entries;
    assert(*blob_item_count >= 0);
    return 0;
}
Example #10
0
static char *test_map(void *context)
{
    static char error[1000];
    const char *data =
        "\xd1\x00\x00\x00\x2d\x00\x00\x00\x06"    // map32, 6 items
        "\xa3\x05\x66irst\xa1\x0evalue_of_first"  // (23) "first":"value_of_first"
        "\xa3\x06second\x52\x20"                  // (10) "second":32
        "\xa3\x05third\x41";                      // (8)  "third":true
    int data_len = 50;

    qd_iterator_t     *data_iter = qd_iterator_binary(data, data_len, ITER_VIEW_ALL);
    qd_parsed_field_t *field     = qd_parse(data_iter);

    if (!qd_parse_ok(field)) {
        snprintf(error, 1000, "Parse failed: %s", qd_parse_error(field));
        qd_iterator_free(data_iter);
        qd_parse_free(field);
        return error;
    }

    if (!qd_parse_is_map(field)) {
        qd_iterator_free(data_iter);
        qd_parse_free(field);
        return "Expected field to be a map";
    }

    uint32_t count = qd_parse_sub_count(field);
    if (count != 3) {
        snprintf(error, 1000, "Expected sub-count==3, got %"PRIu32, count);
        qd_iterator_free(data_iter);
        qd_parse_free(field);
        return error;
    }

    qd_parsed_field_t *key_field  = qd_parse_sub_key(field, 0);
    qd_iterator_t     *key_iter   = qd_parse_raw(key_field);
    qd_iterator_t     *typed_iter = qd_parse_typed(key_field);
    if (!qd_iterator_equal(key_iter, (unsigned char*) "first")) {
        unsigned char     *result   = qd_iterator_copy(key_iter);
        snprintf(error, 1000, "First key: expected 'first', got '%s'", result);
        free (result);
        return error;
    }

    if (!qd_iterator_equal(typed_iter, (unsigned char*) "\xa3\x05\x66irst"))
        return "Incorrect typed iterator on first-key";

    qd_parsed_field_t *val_field = qd_parse_sub_value(field, 0);
    qd_iterator_t     *val_iter  = qd_parse_raw(val_field);
    typed_iter = qd_parse_typed(val_field);
    if (!qd_iterator_equal(val_iter, (unsigned char*) "value_of_first")) {
        unsigned char     *result   = qd_iterator_copy(val_iter);
        snprintf(error, 1000, "First value: expected 'value_of_first', got '%s'", result);
        free (result);
        return error;
    }

    if (!qd_iterator_equal(typed_iter, (unsigned char*) "\xa1\x0evalue_of_first"))
        return "Incorrect typed iterator on first-key";

    key_field = qd_parse_sub_key(field, 1);
    key_iter  = qd_parse_raw(key_field);
    if (!qd_iterator_equal(key_iter, (unsigned char*) "second")) {
        unsigned char     *result   = qd_iterator_copy(key_iter);
        snprintf(error, 1000, "Second key: expected 'second', got '%s'", result);
        free (result);
        return error;
    }

    val_field = qd_parse_sub_value(field, 1);
    if (qd_parse_as_uint(val_field) != 32) {
        snprintf(error, 1000, "Second value: expected 32, got %"PRIu32, qd_parse_as_uint(val_field));
        return error;
    }

    key_field = qd_parse_sub_key(field, 2);
    key_iter  = qd_parse_raw(key_field);
    if (!qd_iterator_equal(key_iter, (unsigned char*) "third")) {
        unsigned char     *result   = qd_iterator_copy(key_iter);
        snprintf(error, 1000, "Third key: expected 'third', got '%s'", result);
        free (result);
        return error;
    }

    val_field = qd_parse_sub_value(field, 2);
    if (!qd_parse_as_bool(val_field)) {
        snprintf(error, 1000, "Third value: expected true");
        return error;
    }

    qd_iterator_free(data_iter);
    qd_parse_free(field);
    return 0;
}
Example #11
0
/**
 * Checks the content of the message to see if this can be handled by the C-management agent. If this agent cannot handle it, it will be
 * forwarded to the Python agent.
 */
static bool qd_can_handle_request(qd_parsed_field_t           *properties_fld,
                                  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,
                                  int                         *count,
                                  int                         *offset)
{
    // The must be a property field and that property field should be a AMQP map. This is true for QUERY but I need
    // to check if it true for CREATE, UPDATE and DELETE
    if (properties_fld == 0 || !qd_parse_is_map(properties_fld))
        return false;

    //
    // Only certain entity types can be handled by this agent.
    // 'entityType': 'org.apache.qpid.dispatch.router.address
    // 'entityType': 'org.apache.qpid.dispatch.router.link'
    // TODO - Add more entity types here. The above is not a complete list.

    qd_parsed_field_t *parsed_field = qd_parse_value_by_key(properties_fld, IDENTITY);
    if (parsed_field!=0) {
        *identity_iter = qd_parse_raw(parsed_field);
    }
    parsed_field = qd_parse_value_by_key(properties_fld, NAME);
    if (parsed_field!=0) {
        *name_iter = qd_parse_raw(parsed_field);
    }

    parsed_field = qd_parse_value_by_key(properties_fld, ENTITY);

    if (parsed_field == 0) { // Sometimes there is no 'entityType' but 'type' might be available.
        parsed_field = qd_parse_value_by_key(properties_fld, TYPE);
        if (parsed_field == 0)
            return false;
    }

    if (qd_field_iterator_equal(qd_parse_raw(parsed_field), address_entity_type))
        *entity_type = QD_ROUTER_ADDRESS;
    else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), link_entity_type))
        *entity_type = QD_ROUTER_LINK;
    else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), config_address_entity_type))
        *entity_type = QD_ROUTER_CONFIG_ADDRESS;
    else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), link_route_entity_type))
        *entity_type = QD_ROUTER_CONFIG_LINK_ROUTE;
    else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), auto_link_entity_type))
        *entity_type = QD_ROUTER_CONFIG_AUTO_LINK;
    else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), console_entity_type))
        *entity_type = QD_ROUTER_FORBIDDEN;
    else
        return false;


    parsed_field = qd_parse_value_by_key(properties_fld, OPERATION);

    if (parsed_field == 0)
        return false;

    if (qd_field_iterator_equal(qd_parse_raw(parsed_field), MANAGEMENT_QUERY))
        (*operation_type) = QD_ROUTER_OPERATION_QUERY;
    else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), MANAGEMENT_CREATE))
        (*operation_type) = QD_ROUTER_OPERATION_CREATE;
    else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), MANAGEMENT_READ))
        (*operation_type) = QD_ROUTER_OPERATION_READ;
    else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), MANAGEMENT_UPDATE))
        (*operation_type) = QD_ROUTER_OPERATION_UPDATE;
    else if (qd_field_iterator_equal(qd_parse_raw(parsed_field), MANAGEMENT_DELETE))
        (*operation_type) = QD_ROUTER_OPERATION_DELETE;
    else
        // This is an unknown operation type. cannot be handled, return false.
        return false;

    // Obtain the count and offset.
    parsed_field = qd_parse_value_by_key(properties_fld, COUNT);
    if (parsed_field)
        (*count) = qd_parse_as_int(parsed_field);
    else
        (*count) = -1;

    parsed_field = qd_parse_value_by_key(properties_fld, OFFSET);
    if (parsed_field)
        (*offset) = qd_parse_as_int(parsed_field);
    else
        (*offset) = 0;

    return true;
}
Example #12
0
static qd_iterator_t *router_annotate_message(qd_router_t       *router,
                                              qd_parsed_field_t *in_ma,
                                              qd_message_t      *msg,
                                              qd_bitmask_t     **link_exclusions,
                                              bool               strip_inbound_annotations)
{
    qd_iterator_t *ingress_iter = 0;

    qd_parsed_field_t *trace   = 0;
    qd_parsed_field_t *ingress = 0;
    qd_parsed_field_t *to      = 0;
    qd_parsed_field_t *phase   = 0;

    *link_exclusions = 0;

    if (in_ma && !strip_inbound_annotations) {
        uint32_t count = qd_parse_sub_count(in_ma);
        bool done = false;

        for (uint32_t idx = 0; idx < count && !done; idx++) {
            qd_parsed_field_t *sub  = qd_parse_sub_key(in_ma, idx);
            if (!sub)
                continue;
            qd_iterator_t *iter = qd_parse_raw(sub);
            if (!iter)
                continue;

            if        (qd_iterator_equal(iter, (unsigned char*) QD_MA_TRACE)) {
                trace = qd_parse_sub_value(in_ma, idx);
            } else if (qd_iterator_equal(iter, (unsigned char*) QD_MA_INGRESS)) {
                ingress = qd_parse_sub_value(in_ma, idx);
            } else if (qd_iterator_equal(iter, (unsigned char*) QD_MA_TO)) {
                to = qd_parse_sub_value(in_ma, idx);
            } else if (qd_iterator_equal(iter, (unsigned char*) QD_MA_PHASE)) {
                phase = qd_parse_sub_value(in_ma, idx);
            }
            done = trace && ingress && to && phase;
        }
    }

    //
    // QD_MA_TRACE:
    // If there is a trace field, append this router's ID to the trace.
    // If the router ID is already in the trace the msg has looped.
    //
    qd_composed_field_t *trace_field = qd_compose_subfield(0);
    qd_compose_start_list(trace_field);
    if (trace) {
        if (qd_parse_is_list(trace)) {
            //
            // Create a link-exclusion map for the items in the trace.  This map will
            // contain a one-bit for each link that leads to a neighbor router that
            // the message has already passed through.
            //
            *link_exclusions = qd_tracemask_create(router->tracemask, trace);

            //
            // Append this router's ID to the trace.
            //
            uint32_t idx = 0;
            qd_parsed_field_t *trace_item = qd_parse_sub_value(trace, idx);
            while (trace_item) {
                qd_iterator_t *iter = qd_parse_raw(trace_item);
                qd_iterator_reset_view(iter, ITER_VIEW_ALL);
                qd_compose_insert_string_iterator(trace_field, iter);
                idx++;
                trace_item = qd_parse_sub_value(trace, idx);
            }
        }
    }

    qd_compose_insert_string(trace_field, node_id);
    qd_compose_end_list(trace_field);
    qd_message_set_trace_annotation(msg, trace_field);

    //
    // QD_MA_TO:
    // Preserve the existing value.
    //
    if (to) {
        qd_composed_field_t *to_field = qd_compose_subfield(0);
        qd_compose_insert_string_iterator(to_field, qd_parse_raw(to));
        qd_message_set_to_override_annotation(msg, to_field);
    }

    //
    // QD_MA_PHASE:
    // Preserve the existing value.
    //
    if (phase) {
        int phase_val = qd_parse_as_int(phase);
        qd_message_set_phase_annotation(msg, phase_val);
    }

    //
    // QD_MA_INGRESS:
    // If there is no ingress field, annotate the ingress as
    // this router else keep the original field.
    //
    qd_composed_field_t *ingress_field = qd_compose_subfield(0);
    if (ingress && qd_parse_is_scalar(ingress)) {
        ingress_iter = qd_parse_raw(ingress);
        qd_compose_insert_string_iterator(ingress_field, ingress_iter);
    } else
        qd_compose_insert_string(ingress_field, node_id);
    qd_message_set_ingress_annotation(msg, ingress_field);

    //
    // Return the iterator to the ingress field _if_ it was present.
    // If we added the ingress, return NULL.
    //
    return ingress_iter;
}
Example #13
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);
    }
}