ua_util.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * Copyright 2014, 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
  6. * Copyright 2014 (c) Florian Palm
  7. * Copyright 2017 (c) Stefan Profanter, fortiss GmbH
  8. */
  9. #include "ua_types_generated_handling.h"
  10. #include "ua_util.h"
  11. #include "ua_util_internal.h"
  12. #include "base64.h"
  13. size_t
  14. UA_readNumberWithBase(const UA_Byte *buf, size_t buflen, UA_UInt32 *number, UA_Byte base) {
  15. UA_assert(buf);
  16. UA_assert(number);
  17. u32 n = 0;
  18. size_t progress = 0;
  19. /* read numbers until the end or a non-number character appears */
  20. while(progress < buflen) {
  21. u8 c = buf[progress];
  22. if(c >= '0' && c <= '9' && c <= '0' + (base-1))
  23. n = (n * base) + c - '0';
  24. else if(base > 9 && c >= 'a' && c <= 'z' && c <= 'a' + (base-11))
  25. n = (n * base) + c-'a' + 10;
  26. else if(base > 9 && c >= 'A' && c <= 'Z' && c <= 'A' + (base-11))
  27. n = (n * base) + c-'A' + 10;
  28. else
  29. break;
  30. ++progress;
  31. }
  32. *number = n;
  33. return progress;
  34. }
  35. size_t
  36. UA_readNumber(UA_Byte *buf, size_t buflen, UA_UInt32 *number)
  37. {
  38. return UA_readNumberWithBase(buf, buflen, number, 10);
  39. }
  40. UA_StatusCode
  41. UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname,
  42. u16 *outPort, UA_String *outPath) {
  43. /* Url must begin with "opc.tcp://" or opc.udp:// (if pubsub enabled) */
  44. if(endpointUrl->length < 11) {
  45. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  46. }
  47. if (strncmp((char*)endpointUrl->data, "opc.tcp://", 10) != 0) {
  48. #ifdef UA_ENABLE_PUBSUB
  49. if (strncmp((char*)endpointUrl->data, "opc.udp://", 10) != 0 &&
  50. strncmp((char*)endpointUrl->data, "opc.mqtt://", 11) != 0) {
  51. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  52. }
  53. #else
  54. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  55. #endif
  56. }
  57. /* Where does the hostname end? */
  58. size_t curr = 10;
  59. if(endpointUrl->data[curr] == '[') {
  60. /* IPv6: opc.tcp://[2001:0db8:85a3::8a2e:0370:7334]:1234/path */
  61. for(; curr < endpointUrl->length; ++curr) {
  62. if(endpointUrl->data[curr] == ']')
  63. break;
  64. }
  65. if(curr == endpointUrl->length)
  66. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  67. curr++;
  68. } else {
  69. /* IPv4 or hostname: opc.tcp://something.something:1234/path */
  70. for(; curr < endpointUrl->length; ++curr) {
  71. if(endpointUrl->data[curr] == ':' || endpointUrl->data[curr] == '/')
  72. break;
  73. }
  74. }
  75. /* Set the hostname */
  76. outHostname->data = &endpointUrl->data[10];
  77. outHostname->length = curr - 10;
  78. if(curr == endpointUrl->length)
  79. return UA_STATUSCODE_GOOD;
  80. /* Set the port */
  81. if(endpointUrl->data[curr] == ':') {
  82. if(++curr == endpointUrl->length)
  83. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  84. u32 largeNum;
  85. size_t progress = UA_readNumber(&endpointUrl->data[curr], endpointUrl->length - curr, &largeNum);
  86. if(progress == 0 || largeNum > 65535)
  87. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  88. /* Test if the end of a valid port was reached */
  89. curr += progress;
  90. if(curr == endpointUrl->length || endpointUrl->data[curr] == '/')
  91. *outPort = (u16)largeNum;
  92. if(curr == endpointUrl->length)
  93. return UA_STATUSCODE_GOOD;
  94. }
  95. /* Set the path */
  96. UA_assert(curr < endpointUrl->length);
  97. if(endpointUrl->data[curr] != '/')
  98. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  99. if(++curr == endpointUrl->length)
  100. return UA_STATUSCODE_GOOD;
  101. outPath->data = &endpointUrl->data[curr];
  102. outPath->length = endpointUrl->length - curr;
  103. /* Remove trailing slash from the path */
  104. if(endpointUrl->data[endpointUrl->length - 1] == '/')
  105. outPath->length--;
  106. return UA_STATUSCODE_GOOD;
  107. }
  108. UA_StatusCode
  109. UA_parseEndpointUrlEthernet(const UA_String *endpointUrl, UA_String *target,
  110. UA_UInt16 *vid, UA_Byte *pcp) {
  111. /* Url must begin with "opc.eth://" */
  112. if(endpointUrl->length < 11) {
  113. return UA_STATUSCODE_BADINTERNALERROR;
  114. }
  115. if(strncmp((char*) endpointUrl->data, "opc.eth://", 10) != 0) {
  116. return UA_STATUSCODE_BADINTERNALERROR;
  117. }
  118. /* Where does the host address end? */
  119. size_t curr = 10;
  120. for(; curr < endpointUrl->length; ++curr) {
  121. if(endpointUrl->data[curr] == ':') {
  122. break;
  123. }
  124. }
  125. /* set host address */
  126. target->data = &endpointUrl->data[10];
  127. target->length = curr - 10;
  128. if(curr == endpointUrl->length) {
  129. return UA_STATUSCODE_GOOD;
  130. }
  131. /* Set VLAN */
  132. u32 value = 0;
  133. curr++; /* skip ':' */
  134. size_t progress = UA_readNumber(&endpointUrl->data[curr],
  135. endpointUrl->length - curr, &value);
  136. if(progress == 0 || value > 4096) {
  137. return UA_STATUSCODE_BADINTERNALERROR;
  138. }
  139. curr += progress;
  140. if(curr == endpointUrl->length || endpointUrl->data[curr] == '.') {
  141. *vid = (UA_UInt16) value;
  142. }
  143. if(curr == endpointUrl->length) {
  144. return UA_STATUSCODE_GOOD;
  145. }
  146. /* Set priority */
  147. if(endpointUrl->data[curr] != '.') {
  148. return UA_STATUSCODE_BADINTERNALERROR;
  149. }
  150. curr++; /* skip '.' */
  151. progress = UA_readNumber(&endpointUrl->data[curr],
  152. endpointUrl->length - curr, &value);
  153. if(progress == 0 || value > 7) {
  154. return UA_STATUSCODE_BADINTERNALERROR;
  155. }
  156. curr += progress;
  157. if(curr != endpointUrl->length) {
  158. return UA_STATUSCODE_BADINTERNALERROR;
  159. }
  160. *pcp = (UA_Byte) value;
  161. return UA_STATUSCODE_GOOD;
  162. }
  163. UA_StatusCode UA_ByteString_toBase64String(const UA_ByteString *byteString, UA_String *str) {
  164. if (str->length != 0) {
  165. UA_free(str->data);
  166. str->data = NULL;
  167. str->length = 0;
  168. }
  169. if (byteString == NULL || byteString->data == NULL)
  170. return UA_STATUSCODE_GOOD;
  171. if (byteString == str)
  172. return UA_STATUSCODE_BADINVALIDARGUMENT;
  173. int resSize = 0;
  174. str->data = (UA_Byte*)UA_base64(byteString->data, (int)byteString->length, &resSize);
  175. str->length = (size_t) resSize;
  176. if (str->data == NULL)
  177. return UA_STATUSCODE_BADOUTOFMEMORY;
  178. return UA_STATUSCODE_GOOD;
  179. }
  180. UA_StatusCode
  181. UA_NodeId_toString(const UA_NodeId *nodeId, UA_String *nodeIdStr) {
  182. if (nodeIdStr->length != 0) {
  183. UA_free(nodeIdStr->data);
  184. nodeIdStr->data = NULL;
  185. nodeIdStr->length = 0;
  186. }
  187. if (nodeId == NULL)
  188. return UA_STATUSCODE_GOOD;
  189. char *nsStr = NULL;
  190. long snprintfLen = 0;
  191. size_t nsLen = 0;
  192. if (nodeId->namespaceIndex != 0) {
  193. nsStr = (char*)UA_malloc(9+1); // strlen("ns=XXXXX;") = 9 + Nullbyte
  194. snprintfLen = UA_snprintf(nsStr, 10, "ns=%d;", nodeId->namespaceIndex);
  195. if (snprintfLen < 0 || snprintfLen >= 10) {
  196. UA_free(nsStr);
  197. return UA_STATUSCODE_BADINTERNALERROR;
  198. }
  199. nsLen = (size_t)(snprintfLen);
  200. }
  201. UA_ByteString byteStr = UA_BYTESTRING_NULL;
  202. switch (nodeId->identifierType) {
  203. case UA_NODEIDTYPE_NUMERIC:
  204. /* ns (2 byte, 65535) = 5 chars, numeric (4 byte, 4294967295) = 10 chars, delim = 1 , nullbyte = 1-> 17 chars */
  205. nodeIdStr->length = nsLen + 2 + 10 + 1;
  206. nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
  207. if (nodeIdStr->data == NULL) {
  208. nodeIdStr->length = 0;
  209. UA_free(nsStr);
  210. return UA_STATUSCODE_BADOUTOFMEMORY;
  211. }
  212. snprintfLen =UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "%si=%lu",
  213. nsLen > 0 ? nsStr : "",
  214. (unsigned long )nodeId->identifier.numeric);
  215. break;
  216. case UA_NODEIDTYPE_STRING:
  217. /* ns (16bit) = 5 chars, strlen + nullbyte */
  218. nodeIdStr->length = nsLen + 2 + nodeId->identifier.string.length + 1;
  219. nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
  220. if (nodeIdStr->data == NULL) {
  221. nodeIdStr->length = 0;
  222. UA_free(nsStr);
  223. return UA_STATUSCODE_BADOUTOFMEMORY;
  224. }
  225. snprintfLen =UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "%ss=%.*s",
  226. nsLen > 0 ? nsStr : "",
  227. (int)nodeId->identifier.string.length, nodeId->identifier.string.data);
  228. break;
  229. case UA_NODEIDTYPE_GUID:
  230. /* ns (16bit) = 5 chars + strlen(A123456C-0ABC-1A2B-815F-687212AAEE1B)=36 + nullbyte */
  231. nodeIdStr->length = nsLen + 2 + 36 + 1;
  232. nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
  233. if (nodeIdStr->data == NULL) {
  234. nodeIdStr->length = 0;
  235. UA_free(nsStr);
  236. return UA_STATUSCODE_BADOUTOFMEMORY;
  237. }
  238. snprintfLen = UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "%sg=" UA_PRINTF_GUID_FORMAT,
  239. nsLen > 0 ? nsStr : "",
  240. UA_PRINTF_GUID_DATA(nodeId->identifier.guid));
  241. break;
  242. case UA_NODEIDTYPE_BYTESTRING:
  243. UA_ByteString_toBase64String(&nodeId->identifier.byteString, &byteStr);
  244. /* ns (16bit) = 5 chars + LEN + nullbyte */
  245. nodeIdStr->length = nsLen + 2 + byteStr.length + 1;
  246. nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
  247. if (nodeIdStr->data == NULL) {
  248. nodeIdStr->length = 0;
  249. UA_String_deleteMembers(&byteStr);
  250. UA_free(nsStr);
  251. return UA_STATUSCODE_BADOUTOFMEMORY;
  252. }
  253. snprintfLen = UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "%sb=%.*s",
  254. nsLen > 0 ? nsStr : "",
  255. (int)byteStr.length, byteStr.data);
  256. UA_String_deleteMembers(&byteStr);
  257. break;
  258. }
  259. UA_free(nsStr);
  260. if (snprintfLen < 0 || snprintfLen >= (long) nodeIdStr->length) {
  261. UA_free(nodeIdStr->data);
  262. nodeIdStr->data = NULL;
  263. nodeIdStr->length = 0;
  264. return UA_STATUSCODE_BADINTERNALERROR;
  265. }
  266. nodeIdStr->length = (size_t)snprintfLen;
  267. return UA_STATUSCODE_GOOD;
  268. }