diff options
Diffstat (limited to 'utils/open-isns/query.c')
-rw-r--r-- | utils/open-isns/query.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/utils/open-isns/query.c b/utils/open-isns/query.c new file mode 100644 index 0000000..b2cfbc9 --- /dev/null +++ b/utils/open-isns/query.c @@ -0,0 +1,238 @@ +/* + * Handle iSNS Device Attribute Query + * + * Copyright (C) 2007 Olaf Kirch <olaf.kirch@oracle.com> + */ + +#include <stdlib.h> +#include <string.h> +#include "isns.h" +#include "attrs.h" +#include "message.h" +#include "security.h" +#include "objects.h" +#include "db.h" +#include "util.h" + +/* + * Create a query, and set the source name + */ +static isns_simple_t * +__isns_create_query(isns_source_t *source, const isns_attr_list_t *key) +{ + return isns_simple_create(ISNS_DEVICE_ATTRIBUTE_QUERY, source, key); +} + +isns_simple_t * +isns_create_query(isns_client_t *clnt, const isns_attr_list_t *key) +{ + return __isns_create_query(clnt->ic_source, key); +} + +isns_simple_t * +isns_create_query2(isns_client_t *clnt, const isns_attr_list_t *key, isns_source_t *source) +{ + return __isns_create_query(source?: clnt->ic_source, key); +} + +int +isns_query_request_attr_tag(isns_simple_t *qry, uint32_t tag) +{ + isns_attr_list_append_nil(&qry->is_operating_attrs, tag); + return ISNS_SUCCESS; +} + +int +isns_query_request_attr(isns_simple_t *qry, isns_attr_t *attr) +{ + if (!ISNS_ATTR_IS_NIL(attr)) { + isns_error("Query operating attribute must be NIL\n"); + return ISNS_INVALID_QUERY; + } + isns_attr_list_append_attr(&qry->is_operating_attrs, attr); + return ISNS_SUCCESS; +} + +static unsigned int +isns_query_get_requested_types(const isns_attr_list_t *attrs) +{ + unsigned int i, mask = 0; + + for (i = 0; i < attrs->ial_count; ++i) { + uint32_t tag = attrs->ial_data[i]->ia_tag_id; + isns_object_template_t *tmpl; + + tmpl = isns_object_template_find(tag); + /* Ignore unknown tags */ + if (tmpl == NULL) + continue; + + mask |= 1 << tmpl->iot_handle; + } + return mask; +} + +/* + * Get the list of objects matching this query + */ +static int +isns_query_get_objects(isns_simple_t *qry, isns_db_t *db, isns_object_list_t *result) +{ + isns_scope_t *scope = NULL; + isns_object_list_t matching = ISNS_OBJECT_LIST_INIT; + isns_attr_list_t *keys = &qry->is_message_attrs; + isns_object_template_t *query_type = NULL; + unsigned int i, qry_mask = 0; + int status; + + /* 5.6.5.2 + * If multiple attributes are used as the Message Key, then they + * MUST all be from the same object type (e.g., IP address and + * TCP/UDP Port are attributes of the Portal object type). + */ + for (i = 0; i < keys->ial_count; ++i) { + isns_object_template_t *tmpl; + uint32_t tag = keys->ial_data[i]->ia_tag_id; + + tmpl = isns_object_template_for_tag(tag); + if (tmpl == NULL) + return ISNS_ATTRIBUTE_NOT_IMPLEMENTED; + if (query_type == NULL) + query_type = tmpl; + else if (tmpl != query_type) + return ISNS_INVALID_QUERY; + } + + /* + * 5.6.5.2 + * An empty Message Key field indicates the query is scoped to + * the entire database accessible by the source Node. + */ + if (keys->ial_count == 0) { + query_type = &isns_entity_template; + keys = NULL; + } + + /* Policy: check whether the client is allowed to + * query this type of object. */ + if (!isns_policy_validate_object_type(qry->is_policy, + query_type, qry->is_function)) + return ISNS_SOURCE_UNAUTHORIZED; + + /* No scope means that the source is not part of + * any discovery domain, and there's no default DD. + * Just return an empty reply. */ + scope = isns_scope_for_call(db, qry); + if (scope == NULL) + return ISNS_SUCCESS; + + status = isns_scope_gang_lookup(scope, query_type, keys, &matching); + if (status != ISNS_SUCCESS) + goto out; + + /* Extract the mask of requested objects */ + qry_mask = isns_query_get_requested_types(&qry->is_operating_attrs); + + /* + * 5.6.5.2 + * The DevAttrQry response message returns attributes of objects + * listed in the Operating Attributes that are related to the + * Message Key of the original DevAttrQry message. + */ + for (i = 0; i < matching.iol_count; ++i) { + isns_object_t *obj = matching.iol_data[i]; + + if (!isns_policy_validate_object_access(qry->is_policy, + qry->is_source, obj, + qry->is_function)) + continue; + + if (obj->ie_container) + isns_object_list_append(result, obj->ie_container); + isns_object_list_append(result, obj); + isns_scope_get_related(scope, obj, qry_mask, result); + } + +out: + isns_object_list_destroy(&matching); + isns_scope_release(scope); + return status; +} + +/* + * Create a Query Response + */ +static isns_simple_t * +isns_create_query_response(isns_server_t *srv, + const isns_simple_t *qry, const isns_object_list_t *objects) +{ + const isns_attr_list_t *req_attrs = NULL; + isns_simple_t *resp; + unsigned int i; + + resp = __isns_create_query(srv->is_source, &qry->is_message_attrs); + + /* + * 5.7.5.2. + * If no Operating Attributes are included in the original + * query, then all Operating Attributes SHALL be returned + * in the response. + */ + if (qry->is_operating_attrs.ial_count != 0) + req_attrs = &qry->is_operating_attrs; + + for (i = 0; i < objects->iol_count; ++i) { + isns_object_t *obj = objects->iol_data[i]; + + if (obj->ie_rebuild) + obj->ie_rebuild(obj, srv->is_db); + isns_object_get_attrlist(obj, + &resp->is_operating_attrs, + req_attrs); + } + return resp; +} + +int +isns_process_query(isns_server_t *srv, isns_simple_t *call, isns_simple_t **result) +{ + isns_object_list_t objects = ISNS_OBJECT_LIST_INIT; + isns_simple_t *reply = NULL; + isns_db_t *db = srv->is_db; + int status; + + /* Get the objects matching the query */ + status = isns_query_get_objects(call, db, &objects); + if (status != ISNS_SUCCESS) + goto done; + + /* Success: build the response */ + reply = isns_create_query_response(srv, call, &objects); + if (reply == NULL) { + status = ISNS_INTERNAL_ERROR; + goto done; + } + + /* There's nothing in the spec that tells us what to + * return if the query matches no object. + */ + if (objects.iol_count == 0) { + status = ISNS_NO_SUCH_ENTRY; + goto done; + } + +done: + isns_object_list_destroy(&objects); + *result = reply; + return status; +} + +/* + * Parse the list of objects in a query response + */ +int +isns_query_response_get_objects(isns_simple_t *qry, + isns_object_list_t *result) +{ + return isns_simple_response_get_objects(qry, result); +} |