diff options
Diffstat (limited to 'components/service/locator/service_name.c')
-rw-r--r-- | components/service/locator/service_name.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/components/service/locator/service_name.c b/components/service/locator/service_name.c new file mode 100644 index 000000000..878b84bec --- /dev/null +++ b/components/service/locator/service_name.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <string.h> +#include <stdio.h> +#include "service_name.h" + +/* + * Structure to hold result of parsing the service name. Sets + * indices and length of the following fields. Lengths are set to zero + * if field is not present. + */ +struct sn_parsed_fields +{ + size_t authority_pos; + size_t authority_len; + size_t service_pos; + size_t service_len; + size_t version_pos; + size_t version_len; + size_t instance_pos; + size_t instance_len; +}; + +/* + * Find the lengthof the current field, up to the specified separator or end + * of the service name. + */ +static size_t field_len(const char *sn, size_t from, size_t len, char separator) +{ + size_t field_len = 0; + size_t pos = from; + + while (pos < len) { + + if (sn[pos] == separator) break; + + ++pos; + ++field_len; + } + + return field_len; +} + +/* + * Find the next field in the service name after the specified separator from the + * specified position. + */ +static bool find_next(const char *sn, size_t from, size_t len, char separator, size_t *next) +{ + bool found = false; + size_t pos = from; + + while (pos < len) { + + if (sn[pos] == separator) { + *next = pos + 1; + found = (*next < len); + break; + } + + ++pos; + } + + return found; +} + +/* + * Parse the service name. Returns true if is a legal service + * name and mandatory fields are present; + */ +static bool sn_parse(const char *sn, struct sn_parsed_fields *fields) +{ + size_t sn_len = strlen(sn); + size_t field_pos = 0; + + fields->authority_pos = 0; + fields->authority_len = 0; + fields->service_pos = 0; + fields->service_len = 0; + fields->version_pos = 0; + fields->version_len = 0; + fields->instance_pos = 0; + fields->instance_len = 0; + + /* Absorb urn: if present */ + if (memcmp("urn", &sn[field_pos], strlen("urn")) == 0) { + if (!find_next(sn, field_pos, sn_len, ':', &field_pos)) return false; + } + + /* Check it is a service name */ + if (memcmp("sn", &sn[field_pos], strlen("sn")) != 0) { + /* Not a service name */ + return false; + } + + /* Expect the authority field */ + if (find_next(sn, field_pos, sn_len, ':', &field_pos)) { + fields->authority_pos = field_pos; + fields->authority_len = field_len(sn, field_pos, sn_len, ':'); + } + else { + /* Missing mandatory authority field */ + return false; + } + + /* Expect the service field */ + if (find_next(sn, field_pos, sn_len, ':', &field_pos)) { + fields->service_pos = field_pos; + fields->service_len = field_len(sn, field_pos, sn_len, ':'); + + /* Check for the optional version */ + if (find_next(sn, field_pos, field_pos + fields->service_len, '.', &field_pos)) { + fields->version_pos = field_pos; + fields->version_len = field_len(sn, field_pos, sn_len, ':'); + } + } + else { + /* Missing mandatory service field */ + return false; + } + + /* Check for optional instance */ + if (find_next(sn, field_pos, sn_len, ':', &field_pos)) { + fields->instance_pos = field_pos; + fields->instance_len = sn_len - field_pos; + } + + return true; +} + +bool sn_is_valid(const char *sn) +{ + struct sn_parsed_fields fields; + return sn_parse(sn, &fields); +} + +bool sn_check_authority(const char *sn, const char *auth) +{ + bool matched = false; + struct sn_parsed_fields fields; + + if (sn_parse(sn, &fields) && fields.authority_len) { + + matched = (memcmp(auth, &sn[fields.authority_pos], strlen(auth)) == 0); + } + + return matched; +} + +bool sn_check_service(const char *sn, const char *service) +{ + bool matched = false; + struct sn_parsed_fields fields; + + if (sn_parse(sn, &fields) && fields.service_len) { + + matched = (memcmp(service, &sn[fields.service_pos], strlen(service)) == 0); + } + + return matched; +} + +unsigned int sn_get_service_instance(const char *sn) +{ + unsigned int instance = 0; + + struct sn_parsed_fields fields; + + if (sn_parse(sn, &fields) && fields.instance_len) { + + sscanf(&sn[fields.instance_pos], "%d", &instance); + } + + return instance; +} + +size_t sn_read_service(const char *sn, char *buf, size_t buf_len) +{ + size_t field_len = 0; + + memset(buf, 0, buf_len); + struct sn_parsed_fields fields; + + if (sn_parse(sn, &fields) && fields.service_len && (fields.service_len < buf_len)) { + + field_len = fields.service_len; + memcpy(buf, &sn[fields.service_pos], field_len); + buf[field_len] = '\0'; + } + + return field_len; +} |