ua_util.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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_util.h"
  10. #include "ua_util_internal.h"
  11. #include "ua_plugin_network.h"
  12. #include "base64.h"
  13. size_t
  14. UA_readNumber(u8 *buf, size_t buflen, u32 *number) {
  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')
  23. break;
  24. n = (n*10) + (u32)(c-'0');
  25. ++progress;
  26. }
  27. *number = n;
  28. return progress;
  29. }
  30. UA_StatusCode
  31. UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname,
  32. u16 *outPort, UA_String *outPath) {
  33. /* Url must begin with "opc.tcp://" or opc.udp:// (if pubsub enabled) */
  34. if(endpointUrl->length < 11) {
  35. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  36. } else if (strncmp((char*)endpointUrl->data, "opc.tcp://", 10) != 0) {
  37. #ifdef UA_ENABLE_PUBSUB
  38. if (strncmp((char*)endpointUrl->data, "opc.udp://", 10) != 0) {
  39. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  40. }
  41. #else
  42. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  43. #endif
  44. }
  45. /* Where does the hostname end? */
  46. size_t curr = 10;
  47. if(endpointUrl->data[curr] == '[') {
  48. /* IPv6: opc.tcp://[2001:0db8:85a3::8a2e:0370:7334]:1234/path */
  49. for(; curr < endpointUrl->length; ++curr) {
  50. if(endpointUrl->data[curr] == ']')
  51. break;
  52. }
  53. if(curr == endpointUrl->length)
  54. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  55. curr++;
  56. } else {
  57. /* IPv4 or hostname: opc.tcp://something.something:1234/path */
  58. for(; curr < endpointUrl->length; ++curr) {
  59. if(endpointUrl->data[curr] == ':' || endpointUrl->data[curr] == '/')
  60. break;
  61. }
  62. }
  63. /* Set the hostname */
  64. outHostname->data = &endpointUrl->data[10];
  65. outHostname->length = curr - 10;
  66. if(curr == endpointUrl->length)
  67. return UA_STATUSCODE_GOOD;
  68. /* Set the port */
  69. if(endpointUrl->data[curr] == ':') {
  70. if(++curr == endpointUrl->length)
  71. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  72. u32 largeNum;
  73. size_t progress = UA_readNumber(&endpointUrl->data[curr], endpointUrl->length - curr, &largeNum);
  74. if(progress == 0 || largeNum > 65535)
  75. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  76. /* Test if the end of a valid port was reached */
  77. curr += progress;
  78. if(curr == endpointUrl->length || endpointUrl->data[curr] == '/')
  79. *outPort = (u16)largeNum;
  80. if(curr == endpointUrl->length)
  81. return UA_STATUSCODE_GOOD;
  82. }
  83. /* Set the path */
  84. UA_assert(curr < endpointUrl->length);
  85. if(endpointUrl->data[curr] != '/')
  86. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  87. if(++curr == endpointUrl->length)
  88. return UA_STATUSCODE_GOOD;
  89. outPath->data = &endpointUrl->data[curr];
  90. outPath->length = endpointUrl->length - curr;
  91. /* Remove trailing slash from the path */
  92. if(endpointUrl->data[endpointUrl->length - 1] == '/')
  93. outPath->length--;
  94. return UA_STATUSCODE_GOOD;
  95. }
  96. UA_StatusCode UA_ByteString_toBase64String(const UA_ByteString *byteString, UA_String *str) {
  97. if (str->length != 0) {
  98. UA_free(str->data);
  99. str->data = NULL;
  100. str->length = 0;
  101. }
  102. if (byteString == NULL || byteString->data == NULL)
  103. return UA_STATUSCODE_GOOD;
  104. if (byteString == str)
  105. return UA_STATUSCODE_BADINVALIDARGUMENT;
  106. int resSize = 0;
  107. str->data = (UA_Byte*)UA_base64(byteString->data, (int)byteString->length, &resSize);
  108. str->length = (size_t) resSize;
  109. if (str->data == NULL)
  110. return UA_STATUSCODE_BADOUTOFMEMORY;
  111. return UA_STATUSCODE_GOOD;
  112. }
  113. UA_StatusCode
  114. UA_NodeId_toString(const UA_NodeId *nodeId, UA_String *nodeIdStr) {
  115. if (nodeIdStr->length != 0) {
  116. UA_free(nodeIdStr->data);
  117. nodeIdStr->data = NULL;
  118. nodeIdStr->length = 0;
  119. }
  120. if (nodeId == NULL)
  121. return UA_STATUSCODE_GOOD;
  122. UA_ByteString byteStr = UA_BYTESTRING_NULL;
  123. switch (nodeId->identifierType) {
  124. /* for all the lengths below we add the constant for: */
  125. /* strlen("ns=XXXXXX;i=")=11 */
  126. case UA_NODEIDTYPE_NUMERIC:
  127. /* ns (2 byte, 65535) = 5 chars, numeric (4 byte, 4294967295) = 10 chars, delim = 1 , nullbyte = 1-> 17 chars */
  128. nodeIdStr->length = 11 + 10 + 1;
  129. nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
  130. if (nodeIdStr->data == NULL)
  131. return UA_STATUSCODE_BADOUTOFMEMORY;
  132. UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;i=%lu",
  133. nodeId->namespaceIndex, (unsigned long )nodeId->identifier.numeric);
  134. break;
  135. case UA_NODEIDTYPE_STRING:
  136. /* ns (16bit) = 5 chars, strlen + nullbyte */
  137. nodeIdStr->length = 11 + nodeId->identifier.string.length + 1;
  138. nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
  139. if (nodeIdStr->data == NULL)
  140. return UA_STATUSCODE_BADOUTOFMEMORY;
  141. UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;s=%.*s", nodeId->namespaceIndex,
  142. (int)nodeId->identifier.string.length, nodeId->identifier.string.data);
  143. break;
  144. case UA_NODEIDTYPE_GUID:
  145. /* ns (16bit) = 5 chars + strlen(A123456C-0ABC-1A2B-815F-687212AAEE1B)=36 + nullbyte */
  146. nodeIdStr->length = 11 + 36 + 1;
  147. nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
  148. if (nodeIdStr->data == NULL)
  149. return UA_STATUSCODE_BADOUTOFMEMORY;
  150. UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;g=" UA_PRINTF_GUID_FORMAT,
  151. nodeId->namespaceIndex, UA_PRINTF_GUID_DATA(nodeId->identifier.guid));
  152. break;
  153. case UA_NODEIDTYPE_BYTESTRING:
  154. UA_ByteString_toBase64String(&nodeId->identifier.byteString, &byteStr);
  155. /* ns (16bit) = 5 chars + LEN + nullbyte */
  156. nodeIdStr->length = 11 + byteStr.length + 1;
  157. nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
  158. if (nodeIdStr->data == NULL)
  159. return UA_STATUSCODE_BADOUTOFMEMORY;
  160. UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;b=%.*s", nodeId->namespaceIndex, (int)byteStr.length, byteStr.data);
  161. UA_String_deleteMembers(&byteStr);
  162. break;
  163. }
  164. return UA_STATUSCODE_GOOD;
  165. }