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; }
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'"; }
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; }
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; }
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; }
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; }
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; }
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; }
/** * 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; }
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; }
/** * 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); } }