blob: 878b84bec3f67a4d99d37634cc9033d42512fdc3 [file] [log] [blame]
Julian Hall8cff2b82020-11-23 18:12:17 +01001/*
2 * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <string.h>
8#include <stdio.h>
9#include "service_name.h"
10
11/*
12 * Structure to hold result of parsing the service name. Sets
13 * indices and length of the following fields. Lengths are set to zero
14 * if field is not present.
15 */
16struct sn_parsed_fields
17{
18 size_t authority_pos;
19 size_t authority_len;
20 size_t service_pos;
21 size_t service_len;
22 size_t version_pos;
23 size_t version_len;
24 size_t instance_pos;
25 size_t instance_len;
26};
27
28/*
29 * Find the lengthof the current field, up to the specified separator or end
30 * of the service name.
31 */
32static size_t field_len(const char *sn, size_t from, size_t len, char separator)
33{
34 size_t field_len = 0;
35 size_t pos = from;
36
37 while (pos < len) {
38
39 if (sn[pos] == separator) break;
40
41 ++pos;
42 ++field_len;
43 }
44
45 return field_len;
46}
47
48/*
49 * Find the next field in the service name after the specified separator from the
50 * specified position.
51 */
52static bool find_next(const char *sn, size_t from, size_t len, char separator, size_t *next)
53{
54 bool found = false;
55 size_t pos = from;
56
57 while (pos < len) {
58
59 if (sn[pos] == separator) {
60 *next = pos + 1;
61 found = (*next < len);
62 break;
63 }
64
65 ++pos;
66 }
67
68 return found;
69}
70
71/*
72 * Parse the service name. Returns true if is a legal service
73 * name and mandatory fields are present;
74 */
75static bool sn_parse(const char *sn, struct sn_parsed_fields *fields)
76{
77 size_t sn_len = strlen(sn);
78 size_t field_pos = 0;
79
80 fields->authority_pos = 0;
81 fields->authority_len = 0;
82 fields->service_pos = 0;
83 fields->service_len = 0;
84 fields->version_pos = 0;
85 fields->version_len = 0;
86 fields->instance_pos = 0;
87 fields->instance_len = 0;
88
89 /* Absorb urn: if present */
90 if (memcmp("urn", &sn[field_pos], strlen("urn")) == 0) {
91 if (!find_next(sn, field_pos, sn_len, ':', &field_pos)) return false;
92 }
93
94 /* Check it is a service name */
95 if (memcmp("sn", &sn[field_pos], strlen("sn")) != 0) {
96 /* Not a service name */
97 return false;
98 }
99
100 /* Expect the authority field */
101 if (find_next(sn, field_pos, sn_len, ':', &field_pos)) {
102 fields->authority_pos = field_pos;
103 fields->authority_len = field_len(sn, field_pos, sn_len, ':');
104 }
105 else {
106 /* Missing mandatory authority field */
107 return false;
108 }
109
110 /* Expect the service field */
111 if (find_next(sn, field_pos, sn_len, ':', &field_pos)) {
112 fields->service_pos = field_pos;
113 fields->service_len = field_len(sn, field_pos, sn_len, ':');
114
115 /* Check for the optional version */
116 if (find_next(sn, field_pos, field_pos + fields->service_len, '.', &field_pos)) {
117 fields->version_pos = field_pos;
118 fields->version_len = field_len(sn, field_pos, sn_len, ':');
119 }
120 }
121 else {
122 /* Missing mandatory service field */
123 return false;
124 }
125
126 /* Check for optional instance */
127 if (find_next(sn, field_pos, sn_len, ':', &field_pos)) {
128 fields->instance_pos = field_pos;
129 fields->instance_len = sn_len - field_pos;
130 }
131
132 return true;
133}
134
135bool sn_is_valid(const char *sn)
136{
137 struct sn_parsed_fields fields;
138 return sn_parse(sn, &fields);
139}
140
141bool sn_check_authority(const char *sn, const char *auth)
142{
143 bool matched = false;
144 struct sn_parsed_fields fields;
145
146 if (sn_parse(sn, &fields) && fields.authority_len) {
147
148 matched = (memcmp(auth, &sn[fields.authority_pos], strlen(auth)) == 0);
149 }
150
151 return matched;
152}
153
154bool sn_check_service(const char *sn, const char *service)
155{
156 bool matched = false;
157 struct sn_parsed_fields fields;
158
159 if (sn_parse(sn, &fields) && fields.service_len) {
160
161 matched = (memcmp(service, &sn[fields.service_pos], strlen(service)) == 0);
162 }
163
164 return matched;
165}
166
167unsigned int sn_get_service_instance(const char *sn)
168{
169 unsigned int instance = 0;
170
171 struct sn_parsed_fields fields;
172
173 if (sn_parse(sn, &fields) && fields.instance_len) {
174
175 sscanf(&sn[fields.instance_pos], "%d", &instance);
176 }
177
178 return instance;
179}
180
181size_t sn_read_service(const char *sn, char *buf, size_t buf_len)
182{
183 size_t field_len = 0;
184
185 memset(buf, 0, buf_len);
186 struct sn_parsed_fields fields;
187
188 if (sn_parse(sn, &fields) && fields.service_len && (fields.service_len < buf_len)) {
189
190 field_len = fields.service_len;
191 memcpy(buf, &sn[fields.service_pos], field_len);
192 buf[field_len] = '\0';
193 }
194
195 return field_len;
196}