void qdra_link_update_CT(qdr_core_t *core, qd_field_iterator_t *name, qd_field_iterator_t *identity, qdr_query_t *query, qd_parsed_field_t *in_body) { // If the request was successful then the statusCode MUST contain 200 (OK) and the body of the message // MUST contain a map containing the actual attributes of the entity updated. These MAY differ from those // requested. // A map containing attributes that are not applicable for the entity being created, or invalid values for a // given attribute, MUST result in a failure response with a statusCode of 400 (Bad Request). if (qd_parse_is_map(in_body)) { // The absence of an attribute name implies that the entity should retain its existing value. // If the map contains a key-value pair where the value is null then the updated entity should have no value // for that attribute, removing any previous value. qd_parsed_field_t *admin_state = qd_parse_value_by_key(in_body, qdr_link_columns[QDR_LINK_ADMIN_STATE]); if (admin_state) { //admin state is the only field that can be updated via the update management request //qd_field_iterator_t *adm_state = qd_parse_raw(admin_state); if (identity) { qdr_link_t *link = qdr_link_find_by_identity(core, identity); // TODO - set the adm_state on the link qdra_link_update_set_status(core, query, link); } else if (name) { qdr_link_t *link = qdr_link_find_by_name(core, name); // TODO - set the adm_state on the link qdra_link_update_set_status(core, query, link); } else { qdra_link_set_bad_request(query); } } else qdra_link_set_bad_request(query); } else query->status = QD_AMQP_BAD_REQUEST; // // Enqueue the response. // qdr_agent_enqueue_response_CT(core, query); }
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); }
void qdra_config_auto_link_create_CT(qdr_core_t *core, qd_field_iterator_t *name, qdr_query_t *query, qd_parsed_field_t *in_body) { while (true) { // // Ensure there isn't a duplicate name and that the body is a map // qdr_auto_link_t *al = DEQ_HEAD(core->auto_links); while (al) { if (name && al->name && qd_field_iterator_equal(name, (const unsigned char*) al->name)) break; al = DEQ_NEXT(al); } if (!!al) { query->status = QD_AMQP_BAD_REQUEST; query->status.description = "Name conflicts with an existing entity"; qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description); break; } if (!qd_parse_is_map(in_body)) { query->status = QD_AMQP_BAD_REQUEST; query->status.description = "Body of request must be a map"; qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description); break; } // // Extract the fields from the request // qd_parsed_field_t *addr_field = qd_parse_value_by_key(in_body, qdr_config_auto_link_columns[QDR_CONFIG_AUTO_LINK_ADDR]); qd_parsed_field_t *dir_field = qd_parse_value_by_key(in_body, qdr_config_auto_link_columns[QDR_CONFIG_AUTO_LINK_DIR]); qd_parsed_field_t *phase_field = qd_parse_value_by_key(in_body, qdr_config_auto_link_columns[QDR_CONFIG_AUTO_LINK_PHASE]); qd_parsed_field_t *connection_field = qd_parse_value_by_key(in_body, qdr_config_auto_link_columns[QDR_CONFIG_AUTO_LINK_CONNECTION]); qd_parsed_field_t *container_field = qd_parse_value_by_key(in_body, qdr_config_auto_link_columns[QDR_CONFIG_AUTO_LINK_CONTAINER_ID]); // // Addr and dir fields are mandatory. Fail if they're not both here. // if (!addr_field || !dir_field) { query->status = QD_AMQP_BAD_REQUEST; query->status.description = "addr and dir fields are mandatory"; qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description); break; } qd_direction_t dir; const char *error = qdra_auto_link_direction_CT(dir_field, &dir); if (error) { query->status = QD_AMQP_BAD_REQUEST; query->status.description = error; qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description); break; } // // Use the specified phase if present. Otherwise default based on the direction: // Phase 0 for outgoing links and phase 1 for incoming links. // int phase = phase_field ? qd_parse_as_int(phase_field) : (dir == QD_OUTGOING ? 0 : 1); // // Validate the phase // if (phase < 0 || phase > 9) { query->status = QD_AMQP_BAD_REQUEST; query->status.description = "autoLink phase must be between 0 and 9"; qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s", CONFIG_AUTOLINK_TYPE, query->status.description); break; } // // The request is good. Create the entity. // bool is_container = !!container_field; qd_parsed_field_t *in_use_conn = is_container ? container_field : connection_field; al = qdr_route_add_auto_link_CT(core, name, addr_field, dir, phase, in_use_conn, is_container); // // Compose the result map for the response. // if (query->body) { qd_compose_start_map(query->body); for (int col = 0; col < QDR_CONFIG_AUTO_LINK_COLUMN_COUNT; col++) qdr_config_auto_link_insert_column_CT(al, col, query->body, true); qd_compose_end_map(query->body); } query->status = QD_AMQP_CREATED; break; } // // Enqueue the response if there is a body. If there is no body, this is a management // operation created internally by the configuration file parser. // if (query->body) { // // If there was an error in processing the create, insert a NULL value into the body. // if (query->status.status / 100 > 2) qd_compose_insert_null(query->body); qdr_agent_enqueue_response_CT(core, query); } else { if (query->status.status / 100 > 2) qd_log(core->log, QD_LOG_ERROR, "Error configuring linkRoute: %s", query->status.description); qdr_query_free(query); } }
void qdra_conn_link_route_create_CT(qdr_core_t *core, qd_iterator_t *name, qdr_query_t *query, qd_parsed_field_t *in_body) { char *pattern = NULL; query->status = QD_AMQP_BAD_REQUEST; // fail if creating via a configuration file if (query->in_conn == 0) { query->status.description = "Can only create via management CREATE"; goto exit; } // find the associated connection qdr_connection_t *conn = _find_conn_CT(core, query->in_conn); if (!conn) { query->status.description = "Parent connection no longer exists"; goto exit; } // fail if forbidden by policy if (!conn->policy_allow_dynamic_link_routes) { query->status = QD_AMQP_FORBIDDEN; goto exit; } if (!qd_parse_is_map(in_body)) { query->status.description = "Body of request must be a map"; goto exit; } // // Extract the fields from the request // qd_parsed_field_t *pattern_field = qd_parse_value_by_key(in_body, qdr_conn_link_route_columns[QDR_CONN_LINK_ROUTE_PATTERN]); qd_parsed_field_t *dir_field = qd_parse_value_by_key(in_body, qdr_conn_link_route_columns[QDR_CONN_LINK_ROUTE_DIRECTION]); if (!pattern_field) { query->status.description = "Pattern field is required"; goto exit; } const char *error = NULL; pattern = qdra_config_address_validate_pattern_CT(pattern_field, false, &error); if (!pattern) { query->status.description = error; goto exit; } qd_direction_t dir; error = qdra_link_route_direction_CT(dir_field, &dir); if (error) { query->status.description = error; goto exit; } qdr_link_route_t *lr = qdr_route_add_conn_route_CT(core, conn, name, pattern, dir); if (!lr) { query->status.description = "creation failed"; goto exit; } query->status = QD_AMQP_CREATED; _write_as_map_CT(query, lr); exit: free(pattern); if (query->status.status != QD_AMQP_CREATED.status) { qd_log(core->agent_log, QD_LOG_ERROR, "Error performing CREATE of %s: %s", CONN_LINK_ROUTE_TYPE, query->status.description); qd_compose_insert_null(query->body); // no body map } qdr_agent_enqueue_response_CT(core, query); }
void qdra_config_link_route_create_CT(qdr_core_t *core, qd_field_iterator_t *name, qdr_query_t *query, qd_parsed_field_t *in_body) { while (true) { // // Ensure there isn't a duplicate name and that the body is a map // qdr_link_route_t *lr = DEQ_HEAD(core->link_routes); while (lr) { if (name && lr->name && qd_field_iterator_equal(name, (const unsigned char*) lr->name)) break; lr = DEQ_NEXT(lr); } if (!!lr) { query->status = QD_AMQP_BAD_REQUEST; query->status.description = "Name conflicts with an existing entity"; break; } if (!qd_parse_is_map(in_body)) { query->status = QD_AMQP_BAD_REQUEST; break; } // // Extract the fields from the request // qd_parsed_field_t *prefix_field = qd_parse_value_by_key(in_body, qdr_config_link_route_columns[QDR_CONFIG_LINK_ROUTE_PREFIX]); qd_parsed_field_t *distrib_field = qd_parse_value_by_key(in_body, qdr_config_link_route_columns[QDR_CONFIG_LINK_ROUTE_DISTRIBUTION]); qd_parsed_field_t *connection_field = qd_parse_value_by_key(in_body, qdr_config_link_route_columns[QDR_CONFIG_LINK_ROUTE_CONNECTION]); qd_parsed_field_t *container_field = qd_parse_value_by_key(in_body, qdr_config_link_route_columns[QDR_CONFIG_LINK_ROUTE_CONTAINER_ID]); qd_parsed_field_t *dir_field = qd_parse_value_by_key(in_body, qdr_config_link_route_columns[QDR_CONFIG_LINK_ROUTE_DIR]); // // Prefix and dir fields are mandatory. Fail if they're not both here. // if (!prefix_field || !dir_field) { query->status = QD_AMQP_BAD_REQUEST; break; } qd_direction_t dir; const char *error = qdra_link_route_direction_CT(dir_field, &dir); if (error) { query->status = QD_AMQP_BAD_REQUEST; query->status.description = error; break; } qd_address_treatment_t trt; error = qdra_link_route_treatment_CT(distrib_field, &trt); if (error) { query->status = QD_AMQP_BAD_REQUEST; query->status.description = error; break; } // // The request is good. Create the entity. // bool is_container = !!container_field; qd_parsed_field_t *in_use_conn = is_container ? container_field : connection_field; lr = qdr_route_add_link_route_CT(core, name, prefix_field, in_use_conn, is_container, trt, dir); // // Compose the result map for the response. // if (query->body) { qd_compose_start_map(query->body); for (int col = 0; col < QDR_CONFIG_LINK_ROUTE_COLUMN_COUNT; col++) qdr_config_link_route_insert_column_CT(lr, col, query->body, true); qd_compose_end_map(query->body); } query->status = QD_AMQP_CREATED; break; } // // Enqueue the response if there is a body. If there is no body, this is a management // operation created internally by the configuration file parser. // if (query->body) { // // If there was an error in processing the create, insert a NULL value into the body. // if (query->status.status / 100 > 2) qd_compose_insert_null(query->body); qdr_agent_enqueue_response_CT(core, query); } else { if (query->status.status / 100 > 2) qd_log(core->log, QD_LOG_ERROR, "Error configuring linkRoute: %s", query->status.description); qdr_query_free(query); } }
/** * 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; }
/** * 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); } }