ua_util.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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_plugin_network.h"
  11. size_t
  12. UA_readNumber(u8 *buf, size_t buflen, u32 *number) {
  13. UA_assert(buf);
  14. UA_assert(number);
  15. u32 n = 0;
  16. size_t progress = 0;
  17. /* read numbers until the end or a non-number character appears */
  18. while(progress < buflen) {
  19. u8 c = buf[progress];
  20. if(c < '0' || c > '9')
  21. break;
  22. n = (n*10) + (u32)(c-'0');
  23. ++progress;
  24. }
  25. *number = n;
  26. return progress;
  27. }
  28. UA_StatusCode
  29. UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname,
  30. u16 *outPort, UA_String *outPath) {
  31. /* Url must begin with "opc.tcp://" or opc.udp:// (if pubsub enabled) */
  32. if(endpointUrl->length < 11) {
  33. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  34. } else if (strncmp((char*)endpointUrl->data, "opc.tcp://", 10) != 0) {
  35. #ifdef UA_ENABLE_PUBSUB
  36. if (strncmp((char*)endpointUrl->data, "opc.udp://", 10) != 0) {
  37. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  38. }
  39. #else
  40. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  41. #endif
  42. }
  43. /* Where does the hostname end? */
  44. size_t curr = 10;
  45. if(endpointUrl->data[curr] == '[') {
  46. /* IPv6: opc.tcp://[2001:0db8:85a3::8a2e:0370:7334]:1234/path */
  47. for(; curr < endpointUrl->length; ++curr) {
  48. if(endpointUrl->data[curr] == ']')
  49. break;
  50. }
  51. if(curr == endpointUrl->length)
  52. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  53. curr++;
  54. } else {
  55. /* IPv4 or hostname: opc.tcp://something.something:1234/path */
  56. for(; curr < endpointUrl->length; ++curr) {
  57. if(endpointUrl->data[curr] == ':' || endpointUrl->data[curr] == '/')
  58. break;
  59. }
  60. }
  61. /* Set the hostname */
  62. outHostname->data = &endpointUrl->data[10];
  63. outHostname->length = curr - 10;
  64. if(curr == endpointUrl->length)
  65. return UA_STATUSCODE_GOOD;
  66. /* Set the port */
  67. if(endpointUrl->data[curr] == ':') {
  68. if(++curr == endpointUrl->length)
  69. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  70. u32 largeNum;
  71. size_t progress = UA_readNumber(&endpointUrl->data[curr], endpointUrl->length - curr, &largeNum);
  72. if(progress == 0 || largeNum > 65535)
  73. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  74. /* Test if the end of a valid port was reached */
  75. curr += progress;
  76. if(curr == endpointUrl->length || endpointUrl->data[curr] == '/')
  77. *outPort = (u16)largeNum;
  78. if(curr == endpointUrl->length)
  79. return UA_STATUSCODE_GOOD;
  80. }
  81. /* Set the path */
  82. UA_assert(curr < endpointUrl->length);
  83. if(endpointUrl->data[curr] != '/')
  84. return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
  85. if(++curr == endpointUrl->length)
  86. return UA_STATUSCODE_GOOD;
  87. outPath->data = &endpointUrl->data[curr];
  88. outPath->length = endpointUrl->length - curr;
  89. /* Remove trailing slash from the path */
  90. if(endpointUrl->data[endpointUrl->length - 1] == '/')
  91. outPath->length--;
  92. return UA_STATUSCODE_GOOD;
  93. }