aboutsummaryrefslogtreecommitdiff
path: root/components/service/locator/service_name.c
diff options
context:
space:
mode:
Diffstat (limited to 'components/service/locator/service_name.c')
-rw-r--r--components/service/locator/service_name.c196
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;
+}