qdr_address_t *qdr_add_local_address_CT(qdr_core_t *core, char aclass, const char *address, qd_address_treatment_t treatment) { char addr_string[1000]; qdr_address_t *addr = 0; qd_iterator_t *iter = 0; snprintf(addr_string, sizeof(addr_string), "%c%s", aclass, address); iter = qd_iterator_string(addr_string, ITER_VIEW_ALL); qd_hash_retrieve(core->addr_hash, iter, (void**) &addr); if (!addr) { addr = qdr_address_CT(core, treatment); if (addr) { qd_hash_insert(core->addr_hash, iter, addr, &addr->hash_handle); DEQ_INSERT_TAIL(core->addrs, addr); addr->block_deletion = true; addr->local = (aclass == 'L'); } } qd_iterator_free(iter); return addr; }
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_parser_fixed_scalars(void *context) { int idx = 0; qd_iterator_t *field = NULL; qd_parsed_field_t *parsed = NULL; static char error[1024]; error[0] = 0; while (fs_vectors[idx].data) { field = qd_iterator_binary(fs_vectors[idx].data, fs_vectors[idx].length, ITER_VIEW_ALL); parsed = qd_parse(field); qd_iterator_t *typed_iter = qd_parse_typed(parsed); int length = qd_iterator_length(typed_iter); if (length != fs_vectors[idx].length) { strcpy(error, "Length of typed iterator does not match actual length"); break; } if (!qd_parse_ok(parsed)) { strcpy(error, "Unexpected Parse Error"); break; } if (qd_parse_tag(parsed) != fs_vectors[idx].expected_tag) { sprintf(error, "(%d) Tag: Expected %02x, Got %02x", idx, fs_vectors[idx].expected_tag, qd_parse_tag(parsed)); break; } if (fs_vectors[idx].check_uint && qd_parse_as_uint(parsed) != fs_vectors[idx].expected_ulong) { sprintf(error, "(%d) UINT: Expected %"PRIx64", Got %"PRIx32, idx, fs_vectors[idx].expected_ulong, qd_parse_as_uint(parsed)); break; } if (fs_vectors[idx].check_ulong && qd_parse_as_ulong(parsed) != fs_vectors[idx].expected_ulong) { sprintf(error, "(%d) ULONG: Expected %"PRIx64", Got %"PRIx64, idx, fs_vectors[idx].expected_ulong, qd_parse_as_ulong(parsed)); break; } if (fs_vectors[idx].check_int && qd_parse_as_int(parsed) != fs_vectors[idx].expected_long) { sprintf(error, "(%d) INT: Expected %"PRIx64", Got %"PRIx32, idx, fs_vectors[idx].expected_long, qd_parse_as_int(parsed)); break; } if (fs_vectors[idx].check_long && qd_parse_as_long(parsed) != fs_vectors[idx].expected_long) { sprintf(error, "(%d) LONG: Expected %"PRIx64", Got %"PRIx64, idx, fs_vectors[idx].expected_long, qd_parse_as_long(parsed)); break; } idx++; qd_iterator_free(field); field = 0; qd_parse_free(parsed); parsed = 0; } qd_iterator_free(field); qd_parse_free(parsed); return *error ? error : 0; }
static char *test_tracemask(void *context) { qd_bitmask_t *bm = NULL; qd_tracemask_t *tm = qd_tracemask(); qd_buffer_list_t list; static char error[1024]; error[0] = 0; qd_iterator_set_address(false, "0", "ROUTER"); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.A", 0); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.B", 1); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.C", 2); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.D", 3); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.E", 4); qd_tracemask_add_router(tm, "amqp:/_topo/0/Router.F", 5); qd_tracemask_set_link(tm, 0, 4); qd_tracemask_set_link(tm, 3, 10); qd_tracemask_set_link(tm, 4, 3); qd_tracemask_set_link(tm, 5, 2); qd_composed_field_t *comp = qd_compose_subfield(0); qd_compose_start_list(comp); qd_compose_insert_string(comp, "0/Router.A"); qd_compose_insert_string(comp, "0/Router.D"); qd_compose_insert_string(comp, "0/Router.E"); qd_compose_end_list(comp); DEQ_INIT(list); qd_compose_take_buffers(comp, &list); qd_compose_free(comp); int length = 0; qd_buffer_t *buf = DEQ_HEAD(list); while (buf) { length += qd_buffer_size(buf); buf = DEQ_NEXT(buf); } qd_iterator_t *iter = qd_iterator_buffer(DEQ_HEAD(list), 0, length, ITER_VIEW_ALL); qd_parsed_field_t *pf = qd_parse(iter); qd_iterator_free(iter); int ingress = -1; bm = qd_tracemask_create(tm, pf, &ingress); if (qd_bitmask_cardinality(bm) != 3) { sprintf(error, "Expected cardinality of 3, got %d", qd_bitmask_cardinality(bm)); goto cleanup; } if (ingress != 0) { sprintf(error, "(A) Expected ingress index of 0, got %d", ingress); goto cleanup; } int total = 0; int bit, c; for (QD_BITMASK_EACH(bm, bit, c)) { total += bit; } if (total != 17) { sprintf(error, "Expected total bit value of 17, got %d", total); goto cleanup; } qd_bitmask_free(bm); bm = 0; qd_tracemask_del_router(tm, 3); qd_tracemask_remove_link(tm, 0); ingress = -1; bm = qd_tracemask_create(tm, pf, &ingress); qd_parse_free(pf); pf = 0; if (qd_bitmask_cardinality(bm) != 1) { sprintf(error, "Expected cardinality of 1, got %d", qd_bitmask_cardinality(bm)); goto cleanup; } if (ingress != 0) { sprintf(error, "(B) Expected ingress index of 0, got %d", ingress); goto cleanup; } total = 0; for (QD_BITMASK_EACH(bm, bit, c)) { total += bit; } if (total != 3) { sprintf(error, "Expected total bit value of 3, got %d", total); // fallthrough } cleanup: qd_parse_free(pf); qd_tracemask_free(tm); qd_bitmask_free(bm); for (qd_buffer_t *buf = DEQ_HEAD(list); buf; buf = DEQ_HEAD(list)) { DEQ_REMOVE_HEAD(list); qd_buffer_free(buf); } return *error ? error : 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; }
static char *test_integer_conversion(void *context) { const struct fs_vector_t { const char *data; int length; uint8_t parse_as; bool expect_fail; int64_t expected_int; uint64_t expected_uint; } fs_vectors[] = { // can successfully convert 64 bit values that are valid in the 32bit range {"\x80\x00\x00\x00\x00\xff\xff\xff\xff", 9, QD_AMQP_UINT, false, 0, UINT32_MAX}, {"\x80\x00\x00\x00\x00\x00\x00\x00\x00", 9, QD_AMQP_UINT, false, 0, 0}, {"\x80\x00\x00\x00\x00\x00\x00\x00\x01", 9, QD_AMQP_UINT, false, 0, 1}, {"\x81\x00\x00\x00\x00\x7f\xff\xff\xff", 9, QD_AMQP_INT, false, INT32_MAX, 0}, {"\x81\xFF\xFF\xFF\xFF\x80\x00\x00\x00", 9, QD_AMQP_INT, false, INT32_MIN, 0}, {"\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9, QD_AMQP_INT, false, -1, 0}, // signed/unsigned conversions {"\x70\x7F\xFF\xFF\xFF", 5, QD_AMQP_INT, false, INT32_MAX, 0}, {"\x71\x7F\xFF\xFF\xFF", 5, QD_AMQP_UINT, false, 0, INT32_MAX}, {"\x80\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9, QD_AMQP_LONG, false, INT64_MAX, 0}, {"\x81\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9, QD_AMQP_ULONG, false,0, INT64_MAX}, {"\x50\x7F", 2, QD_AMQP_INT, false, INT8_MAX, 0}, {"\x60\x7F\xFF", 3, QD_AMQP_INT, false, INT16_MAX, 0}, {"\x53\x7F", 2, QD_AMQP_INT, false, INT8_MAX, 0}, {"\x55\x7F", 2, QD_AMQP_UINT, false, 0, INT8_MAX}, {"\x51\x7F", 2, QD_AMQP_UINT, false, 0, INT8_MAX}, {"\x61\x7F\xFF", 3, QD_AMQP_UINT, false, 0, INT16_MAX}, // strings {"\xa1\x02 1", 4, QD_AMQP_UINT, false, 0, 1}, {"\xa1\x02-1", 4, QD_AMQP_INT, false, -1, 0}, {"\xa1\x14" "18446744073709551615", 22, QD_AMQP_ULONG,false, 0, UINT64_MAX}, {"\xa1\x14" "-9223372036854775808", 22, QD_AMQP_LONG, false, INT64_MIN, 0}, {"\xa1\x13" "9223372036854775807", 21, QD_AMQP_LONG, false, INT64_MAX, 0}, {"\xa3\x13" "9223372036854775807", 21, QD_AMQP_LONG, false, INT64_MAX, 0}, // cannot convert 64 bit values that are outside the 32bit range as int32 {"\x80\x00\x00\x00\x01\x00\x00\x00\x00", 9, QD_AMQP_UINT, true, 0, 0}, {"\x81\x00\x00\x00\x00\x80\x00\x00\x00", 9, QD_AMQP_INT, true, 0, 0}, {"\x81\xFF\xFF\xFF\xFF\x7F\xFF\xFF\xFF", 9, QD_AMQP_INT, true, 0, 0}, // bad signed/unsigned conversions {"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 9, QD_AMQP_LONG, true, 0, 0}, {"\x81\x80\x00\x00\x00\x00\x00\x00\x00", 9, QD_AMQP_ULONG, true, 0, 0}, {"\x70\x80\x00\x00\x00", 5, QD_AMQP_LONG, true, 0, 0}, {"\x71\x80\x00\x00\x00", 5, QD_AMQP_ULONG, true, 0, 0}, {"\x55\x80", 2, QD_AMQP_UINT, true, 0, 0}, {"\x51\x80", 2, QD_AMQP_UINT, true, 0, 0}, {"\x54\x80", 2, QD_AMQP_UINT, true, 0, 0}, {"\x61\x80\x00", 3, QD_AMQP_UINT, true, 0, 0}, {"\x53\x80", 2, QD_AMQP_INT, true, 0, 0}, {"\x52\x80", 2, QD_AMQP_INT, true, 0, 0}, {"\x50\x80", 2, QD_AMQP_LONG, true, 0, 0}, {"\x60\x80", 2, QD_AMQP_LONG, true, 0, 0}, {NULL}, }; char *error = NULL; for (int i = 0; fs_vectors[i].data && !error; ++i) { qd_iterator_t *data_iter = qd_iterator_binary(fs_vectors[i].data, fs_vectors[i].length, ITER_VIEW_ALL); qd_parsed_field_t *field = qd_parse(data_iter); if (!qd_parse_ok(field)) { error = "unexpected parse error"; qd_iterator_free(data_iter); qd_parse_free(field); break; } bool equal = false; switch (fs_vectors[i].parse_as) { case QD_AMQP_UINT: { uint32_t tmp = qd_parse_as_uint(field); equal = (tmp == fs_vectors[i].expected_uint); break; } case QD_AMQP_ULONG: { uint64_t tmp = qd_parse_as_ulong(field); equal = (tmp == fs_vectors[i].expected_uint); break; } case QD_AMQP_INT: { int32_t tmp = qd_parse_as_int(field); equal = (tmp == fs_vectors[i].expected_int); break; } case QD_AMQP_LONG: { int64_t tmp = qd_parse_as_long(field); equal = (tmp == fs_vectors[i].expected_int); break; } } if (!qd_parse_ok(field)) { if (!fs_vectors[i].expect_fail) { error = "unexpected conversion/parse error"; } } else if (fs_vectors[i].expect_fail) { error = "Conversion did not fail as expected"; } else if (!equal) { error = "unexpected converted value"; } qd_iterator_free(data_iter); qd_parse_free(field); } return error; }
static char* test_view_address_hash(void *context) { struct {const char *addr; const char *view;} cases[] = { {"amqp:/_local/my-addr/sub", "Lmy-addr/sub"}, {"amqp:/_local/my-addr", "Lmy-addr"}, {"amqp:/_topo/area/router/local/sub", "Aarea"}, {"amqp:/_topo/my-area/router/local/sub", "Rrouter"}, {"amqp:/_topo/my-area/my-router/local/sub", "Llocal/sub"}, {"amqp:/_topo/area/all/local/sub", "Aarea"}, {"amqp:/_topo/my-area/all/local/sub", "Tlocal/sub"}, {"amqp:/_topo/all/all/local/sub", "Tlocal/sub"}, {"amqp://host:port/_local/my-addr", "Lmy-addr"}, {"_topo/area/router/my-addr", "Aarea"}, {"_topo/my-area/router/my-addr", "Rrouter"}, {"_topo/my-area/my-router/my-addr", "Lmy-addr"}, {"_topo/my-area/router", "Rrouter"}, {"amqp:/mobile", "M1mobile"}, {"mobile", "M1mobile"}, {"/mobile", "M1mobile"}, // Re-run the above tests to make sure trailing dots are ignored. {"amqp:/_local/my-addr/sub.", "Lmy-addr/sub"}, {"amqp:/_local/my-addr.", "Lmy-addr"}, {"amqp:/_topo/area/router/local/sub.", "Aarea"}, {"amqp:/_topo/my-area/router/local/sub.", "Rrouter"}, {"amqp:/_topo/my-area/my-router/local/sub.", "Llocal/sub"}, {"amqp:/_topo/area/all/local/sub.", "Aarea"}, {"amqp:/_topo/my-area/all/local/sub.", "Tlocal/sub"}, {"amqp:/_topo/all/all/local/sub.", "Tlocal/sub"}, {"amqp://host:port/_local/my-addr.", "Lmy-addr"}, {"_topo/area/router/my-addr.", "Aarea"}, {"_topo/my-area/router/my-addr.", "Rrouter"}, {"_topo/my-area/my-router/my-addr.", "Lmy-addr"}, {"_topo/my-area/router.", "Rrouter"}, {"_topo/my-area/router:", "Rrouter:"}, {0, 0} }; int idx; for (idx = 0; cases[idx].addr; idx++) { qd_iterator_t *iter = qd_iterator_string(cases[idx].addr, ITER_VIEW_ADDRESS_HASH); char *ret = view_address_hash(context, iter, cases[idx].addr, cases[idx].view); qd_iterator_free(iter); if (ret) return ret; } for (idx = 0; cases[idx].addr; idx++) { qd_buffer_list_t chain; DEQ_INIT(chain); build_buffer_chain(&chain, cases[idx].addr, 3); qd_iterator_t *iter = qd_iterator_buffer(DEQ_HEAD(chain), 0, strlen(cases[idx].addr), ITER_VIEW_ADDRESS_HASH); char *ret = view_address_hash(context, iter, cases[idx].addr, cases[idx].view); release_buffer_chain(&chain); if (ret) return ret; } 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); } }