/src/S2OPC/src/Common/helpers/sopc_helper_uri.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Licensed to Systerel under one or more contributor license |
3 | | * agreements. See the NOTICE file distributed with this work |
4 | | * for additional information regarding copyright ownership. |
5 | | * Systerel licenses this file to you under the Apache |
6 | | * License, Version 2.0 (the "License"); you may not use this |
7 | | * file except in compliance with the License. You may obtain |
8 | | * a copy of the License at |
9 | | * |
10 | | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | | * |
12 | | * Unless required by applicable law or agreed to in writing, |
13 | | * software distributed under the License is distributed on an |
14 | | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
15 | | * KIND, either express or implied. See the License for the |
16 | | * specific language governing permissions and limitations |
17 | | * under the License. |
18 | | */ |
19 | | |
20 | | #include <stddef.h> |
21 | | #include <string.h> |
22 | | |
23 | | #include "sopc_assert.h" |
24 | | #include "sopc_helper_string.h" |
25 | | #include "sopc_helper_uri.h" |
26 | | #include "sopc_mem_alloc.h" |
27 | | |
28 | 251 | #define URI_PREFIX_SEP "://" |
29 | 5.05k | #define URI_HOSTNAME_SEP ":" |
30 | 155 | #define URI_PORT_SEP "/" |
31 | | |
32 | 16.6k | #define URI_OPEN_BRACKET '[' |
33 | 12.0k | #define URI_CLOSE_BRACKET ']' |
34 | | |
35 | 153 | #define TCPUA_PREFIX ((const char*) "opc.tcp") |
36 | 152 | #define UDPUA_PREFIX ((const char*) "opc.udp") |
37 | 151 | #define ETHUA_PREFIX ((const char*) "opc.eth") |
38 | 150 | #define MQTTUA_PREFIX ((const char*) "MqttUa") |
39 | | |
40 | | /** |
41 | | * Match prefix with SOPC existing prefix set the type with a SOPC_UriType and return true otherwise return false |
42 | | */ |
43 | | static SOPC_ReturnStatus getUriTypeFromEnum(char** prefix, SOPC_UriType* type); |
44 | | |
45 | | /** |
46 | | * Extract Hostname from given URI |
47 | | * Must take a *pCursor which strictly start at the beginning of the sequence and a hostname with *hostname pointing to |
48 | | * NULL. |
49 | | * In case of failure parameters are not modified |
50 | | */ |
51 | | static SOPC_ReturnStatus getUriHostname(const char** ppCursor, char** ppHostname); |
52 | | |
53 | | /** |
54 | | * Extract prefix or port from given URI depending on sep_match |
55 | | * Must take a *pCursor which strictly start at the beginning of the sequence and a port or prefix with *port or *prefix |
56 | | * pointing to NULL. |
57 | | * uriSwitch specify if we are looking for a port or a prefix. |
58 | | * In case of failure parameters are not modified |
59 | | */ |
60 | | static SOPC_ReturnStatus getUriPrefixOrPort(const char** ppCursor, |
61 | | char** ppFind, |
62 | | const char* sep_match, |
63 | | SOPC_UriSwitch uriSwitch); |
64 | | |
65 | | static SOPC_ReturnStatus getUriHostname(const char** ppCursor, char** ppHostname) |
66 | 247 | { |
67 | 247 | if (NULL == ppCursor || NULL == *ppCursor || NULL == ppHostname || NULL != *ppHostname) |
68 | 0 | { |
69 | 0 | return (SOPC_STATUS_INVALID_PARAMETERS); |
70 | 0 | } |
71 | | |
72 | 247 | const char* start = *ppCursor; |
73 | 247 | const char* pCursor = *ppCursor; |
74 | 247 | SOPC_ReturnStatus res = SOPC_STATUS_OK; |
75 | 247 | bool match = false; |
76 | 247 | char* resStr = NULL; |
77 | 247 | size_t len = 0; |
78 | 247 | size_t NbBracketOpen = 0; |
79 | | |
80 | 17.0k | while (!match && res == SOPC_STATUS_OK) |
81 | 16.8k | { |
82 | 16.8k | if (0 == NbBracketOpen) |
83 | 4.90k | { |
84 | 4.90k | match = strchr(URI_HOSTNAME_SEP, *pCursor) != NULL; |
85 | 4.90k | } |
86 | 16.8k | if (!match) |
87 | 16.6k | { |
88 | 16.6k | if (*pCursor == URI_OPEN_BRACKET) |
89 | 9.49k | { |
90 | 9.49k | ++start; |
91 | 9.49k | ++NbBracketOpen; |
92 | 9.49k | } |
93 | 16.6k | if (NbBracketOpen > 0 && URI_CLOSE_BRACKET == *pCursor) |
94 | 201 | { |
95 | 201 | --len; |
96 | 201 | --NbBracketOpen; |
97 | 201 | } |
98 | 16.4k | else |
99 | 16.4k | { |
100 | 16.4k | ++len; |
101 | 16.4k | } |
102 | 16.6k | ++pCursor; |
103 | 16.6k | } |
104 | 16.8k | if ('\0' == *pCursor) |
105 | 90 | { |
106 | 90 | res = SOPC_STATUS_INVALID_PARAMETERS; |
107 | 90 | } |
108 | 16.8k | } |
109 | 247 | if (NbBracketOpen > 0 || 0 == len) |
110 | 56 | { |
111 | 56 | res = SOPC_STATUS_INVALID_PARAMETERS; |
112 | 56 | } |
113 | 247 | if (SOPC_STATUS_OK == res) |
114 | 155 | { |
115 | 155 | resStr = SOPC_Calloc(len + 1, sizeof(char)); |
116 | 155 | if (NULL == resStr) |
117 | 0 | { |
118 | 0 | res = SOPC_STATUS_OUT_OF_MEMORY; |
119 | 0 | } |
120 | 155 | } |
121 | 247 | if (SOPC_STATUS_OK == res) |
122 | 155 | { |
123 | 155 | resStr = strncpy(resStr, start, len); |
124 | 155 | *ppHostname = resStr; |
125 | 155 | pCursor += strlen(URI_HOSTNAME_SEP); |
126 | 155 | *ppCursor = pCursor; |
127 | 155 | } |
128 | 247 | return (res); |
129 | 247 | } |
130 | | |
131 | | static SOPC_ReturnStatus getUriPrefixOrPort(const char** ppCursor, |
132 | | char** ppFind, |
133 | | const char* sep_match, |
134 | | SOPC_UriSwitch uriSwitch) |
135 | 406 | { |
136 | 406 | if (NULL == ppCursor || NULL == *ppCursor || NULL == ppFind || NULL != *ppFind || NULL == sep_match) |
137 | 0 | { |
138 | 0 | return (SOPC_STATUS_INVALID_PARAMETERS); |
139 | 0 | } |
140 | | |
141 | 406 | const char* start = *ppCursor; |
142 | 406 | const char* pCursor = *ppCursor; |
143 | 406 | SOPC_ReturnStatus res = SOPC_STATUS_OK; |
144 | 406 | char* resStr = NULL; |
145 | 406 | size_t len = 0; |
146 | | |
147 | 406 | pCursor = strstr(start, sep_match); |
148 | 406 | if (SOPC_URI_PREFIX == uriSwitch) |
149 | 251 | { |
150 | 251 | if (NULL == pCursor) |
151 | 3 | { |
152 | 3 | res = SOPC_STATUS_INVALID_PARAMETERS; |
153 | 3 | } |
154 | 251 | } |
155 | 155 | else if (SOPC_URI_PORT == uriSwitch) |
156 | 155 | { |
157 | 155 | if (NULL == pCursor) |
158 | 153 | { |
159 | 153 | pCursor = start + strlen(start); |
160 | 153 | } |
161 | 155 | } |
162 | 0 | else |
163 | 0 | { |
164 | 0 | SOPC_ASSERT(false && "Unknown uriSwitch"); |
165 | 0 | } |
166 | | |
167 | 406 | if (SOPC_STATUS_OK == res) |
168 | 403 | { |
169 | 403 | if (pCursor > start) |
170 | 400 | { |
171 | 400 | len = (size_t)(pCursor - start); |
172 | 400 | } |
173 | 3 | else |
174 | 3 | { |
175 | 3 | res = SOPC_STATUS_INVALID_PARAMETERS; |
176 | 3 | } |
177 | 403 | } |
178 | | |
179 | 406 | if (SOPC_STATUS_OK == res) |
180 | 400 | { |
181 | 400 | resStr = SOPC_Calloc(len + 1, sizeof(char)); |
182 | 400 | if (NULL == resStr) |
183 | 0 | { |
184 | 0 | res = SOPC_STATUS_OUT_OF_MEMORY; |
185 | 0 | } |
186 | 400 | } |
187 | | |
188 | 406 | if (SOPC_STATUS_OK == res) |
189 | 400 | { |
190 | 400 | resStr = strncpy(resStr, start, len); |
191 | 400 | pCursor += strlen(sep_match); |
192 | 400 | *ppFind = resStr; |
193 | 400 | *ppCursor = pCursor; |
194 | 400 | } |
195 | 406 | return (res); |
196 | 406 | } |
197 | | |
198 | | static SOPC_ReturnStatus getUriTypeFromEnum(char** prefix, SOPC_UriType* type) |
199 | 153 | { |
200 | 153 | if (strncmp(*prefix, TCPUA_PREFIX, (strlen(*prefix) + 1)) == 0) |
201 | 1 | { |
202 | 1 | *type = SOPC_URI_TCPUA; |
203 | 1 | return (SOPC_STATUS_OK); |
204 | 1 | } |
205 | 152 | else if (strncmp(*prefix, UDPUA_PREFIX, (strlen(*prefix) + 1)) == 0) |
206 | 1 | { |
207 | 1 | *type = SOPC_URI_UDPUA; |
208 | 1 | return (SOPC_STATUS_OK); |
209 | 1 | } |
210 | 151 | else if (strncmp(*prefix, ETHUA_PREFIX, (strlen(*prefix) + 1)) == 0) |
211 | 1 | { |
212 | 1 | *type = SOPC_URI_ETHUA; |
213 | 1 | return (SOPC_STATUS_OK); |
214 | 1 | } |
215 | 150 | else if (strncmp(*prefix, MQTTUA_PREFIX, (strlen(*prefix) + 1)) == 0) |
216 | 1 | { |
217 | 1 | *type = SOPC_URI_MQTTUA; |
218 | 1 | return (SOPC_STATUS_OK); |
219 | 1 | } |
220 | 149 | return (SOPC_STATUS_INVALID_PARAMETERS); |
221 | 153 | } |
222 | | |
223 | | SOPC_ReturnStatus SOPC_Helper_URI_SplitUri(const char* uri, SOPC_UriType* type, char** hostname, char** port) |
224 | 273 | { |
225 | 273 | if (NULL == uri || NULL == hostname || NULL == port || NULL != *port || NULL != *hostname) |
226 | 0 | { |
227 | 0 | return (SOPC_STATUS_INVALID_PARAMETERS); |
228 | 0 | } |
229 | 273 | if (strlen(uri) + 4 > TCP_UA_MAX_URL_LENGTH) // Encoded value shall be less than 4096 byte |
230 | 22 | { |
231 | 22 | return (SOPC_STATUS_INVALID_PARAMETERS); |
232 | 22 | } |
233 | | |
234 | | /* *pCursor is a tmp copy to the uri. its purpose is to run through the URI |
235 | | * Its pos must be at the beginning of each sequence and must be strictly after the last separator found */ |
236 | 251 | const char* pCursor = uri; |
237 | 251 | char* prefix = NULL; |
238 | 251 | SOPC_ReturnStatus result = SOPC_STATUS_OK; |
239 | | |
240 | 251 | if (SOPC_STATUS_OK == result) |
241 | 251 | { |
242 | 251 | result = getUriPrefixOrPort(&pCursor, &prefix, URI_PREFIX_SEP, SOPC_URI_PREFIX); |
243 | 251 | } |
244 | 251 | if (SOPC_STATUS_OK == result) |
245 | 247 | { |
246 | 247 | result = getUriHostname(&pCursor, hostname); |
247 | 247 | } |
248 | 251 | if (SOPC_STATUS_OK == result) |
249 | 155 | { |
250 | 155 | result = getUriPrefixOrPort(&pCursor, port, URI_PORT_SEP, SOPC_URI_PORT); |
251 | 155 | } |
252 | 251 | if (SOPC_STATUS_OK == result) |
253 | 153 | { |
254 | 153 | result = getUriTypeFromEnum(&prefix, type); |
255 | 153 | } |
256 | 251 | SOPC_Free(prefix); |
257 | 251 | if (SOPC_STATUS_OK != result) |
258 | 247 | { |
259 | 247 | SOPC_Free(*hostname); |
260 | 247 | SOPC_Free(*port); |
261 | 247 | *hostname = NULL; |
262 | 247 | *port = NULL; |
263 | 247 | } |
264 | 251 | return (result); |
265 | 273 | } |