ua_connection.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #include "ua_util.h"
  2. #include "ua_connection.h"
  3. #include "ua_types_encoding_binary.h"
  4. #include "ua_securechannel.h"
  5. // max message size is 64k
  6. const UA_ConnectionConfig UA_ConnectionConfig_standard =
  7. {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize = 65536,
  8. .maxMessageSize = 65536, .maxChunkCount = 1};
  9. void UA_Connection_init(UA_Connection *connection) {
  10. connection->state = UA_CONNECTION_CLOSED;
  11. connection->localConf = UA_ConnectionConfig_standard;
  12. connection->remoteConf = UA_ConnectionConfig_standard;
  13. connection->channel = UA_NULL;
  14. connection->sockfd = 0;
  15. connection->handle = UA_NULL;
  16. UA_ByteString_init(&connection->incompleteMessage);
  17. connection->send = UA_NULL;
  18. connection->close = UA_NULL;
  19. connection->recv = UA_NULL;
  20. connection->getSendBuffer = UA_NULL;
  21. connection->releaseSendBuffer = UA_NULL;
  22. connection->releaseRecvBuffer = UA_NULL;
  23. }
  24. void UA_Connection_deleteMembers(UA_Connection *connection) {
  25. UA_ByteString_deleteMembers(&connection->incompleteMessage);
  26. }
  27. UA_Job UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString received) {
  28. UA_Job job = (UA_Job){.type = UA_JOBTYPE_NOTHING};
  29. if(received.length == -1)
  30. return job;
  31. UA_ByteString current;
  32. if(connection->incompleteMessage.length <= 0)
  33. current = received;
  34. else {
  35. /* concat the existing incomplete message with the new message */
  36. current.data = UA_realloc(connection->incompleteMessage.data,
  37. connection->incompleteMessage.length + received.length);
  38. if(!current.data) {
  39. /* not enough memory */
  40. UA_ByteString_deleteMembers(&connection->incompleteMessage);
  41. connection->releaseRecvBuffer(connection, &received);
  42. return job;
  43. }
  44. UA_memcpy(current.data + connection->incompleteMessage.length, received.data, received.length);
  45. current.length = connection->incompleteMessage.length + received.length;
  46. connection->releaseRecvBuffer(connection, &received);
  47. UA_ByteString_init(&connection->incompleteMessage);
  48. }
  49. /* the while loop sets pos to the first element after the last complete message. if a message
  50. contains garbage, the buffer length is set to contain only the "good" messages before. */
  51. size_t pos = 0;
  52. while(current.length - pos >= 16) {
  53. UA_UInt32 msgtype = current.data[pos] + (current.data[pos+1] << 8) + (current.data[pos+2] << 16);
  54. if(msgtype != ('M' + ('S' << 8) + ('G' << 16)) &&
  55. msgtype != ('O' + ('P' << 8) + ('N' << 16)) &&
  56. msgtype != ('H' + ('E' << 8) + ('L' << 16)) &&
  57. msgtype != ('A' + ('C' << 8) + ('K' << 16)) &&
  58. msgtype != ('C' + ('L' << 8) + ('O' << 16))) {
  59. /* the message type is not recognized. throw the remaining bytestring away */
  60. current.length = pos;
  61. break;
  62. }
  63. UA_Int32 length = 0;
  64. size_t length_pos = pos + 4;
  65. UA_StatusCode retval = UA_Int32_decodeBinary(&current, &length_pos, &length);
  66. if(retval != UA_STATUSCODE_GOOD || length < 16 ||
  67. length > (UA_Int32)connection->localConf.maxMessageSize) {
  68. /* the message size is not allowed. throw the remaining bytestring away */
  69. current.length = pos;
  70. break;
  71. }
  72. if(length + (UA_Int32)pos > current.length)
  73. break; /* the message is incomplete. keep the beginning */
  74. pos += length;
  75. }
  76. if(current.length == 0) {
  77. /* throw everything away */
  78. if(current.data == received.data)
  79. connection->releaseRecvBuffer(connection, &received);
  80. else
  81. UA_ByteString_deleteMembers(&current);
  82. return job;
  83. }
  84. if(pos == 0) {
  85. /* no complete message in current */
  86. if(current.data == received.data) {
  87. /* copy the data into the connection */
  88. UA_ByteString_copy(&current, &connection->incompleteMessage);
  89. connection->releaseRecvBuffer(connection, &received);
  90. } else {
  91. /* the data is already copied off the network stack */
  92. connection->incompleteMessage = current;
  93. }
  94. return job;
  95. }
  96. if(current.length != (UA_Int32)pos) {
  97. /* there is an incomplete message at the end of current */
  98. connection->incompleteMessage.data = UA_malloc(current.length - pos);
  99. if(connection->incompleteMessage.data) {
  100. UA_memcpy(connection->incompleteMessage.data, &current.data[pos], current.length - pos);
  101. connection->incompleteMessage.length = current.length - pos;
  102. }
  103. current.length = pos;
  104. }
  105. job.job.binaryMessage.message = current;
  106. job.job.binaryMessage.connection = connection;
  107. if(current.data == received.data)
  108. job.type = UA_JOBTYPE_BINARYMESSAGE_NETWORKLAYER;
  109. else
  110. job.type = UA_JOBTYPE_BINARYMESSAGE_ALLOCATED;
  111. return job;
  112. }
  113. void UA_Connection_detachSecureChannel(UA_Connection *connection) {
  114. #ifdef UA_MULTITHREADING
  115. UA_SecureChannel *channel = connection->channel;
  116. if(channel)
  117. uatomic_cmpxchg(&channel->connection, connection, UA_NULL);
  118. uatomic_set(&connection->channel, UA_NULL);
  119. #else
  120. if(connection->channel)
  121. connection->channel->connection = UA_NULL;
  122. connection->channel = UA_NULL;
  123. #endif
  124. }
  125. void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) {
  126. #ifdef UA_MULTITHREADING
  127. if(uatomic_cmpxchg(&channel->connection, UA_NULL, connection) == UA_NULL)
  128. uatomic_set(&connection->channel, channel);
  129. #else
  130. if(channel->connection != UA_NULL)
  131. return;
  132. channel->connection = connection;
  133. connection->channel = channel;
  134. #endif
  135. }