ua_connection.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #include "ua_util.h"
  2. #include "ua_connection_internal.h"
  3. #include "ua_types_encoding_binary.h"
  4. #include "ua_types_generated_encoding_binary.h"
  5. #include "ua_securechannel.h"
  6. // max message size is 64k
  7. const UA_ConnectionConfig UA_ConnectionConfig_standard =
  8. {.protocolVersion = 0, .sendBufferSize = 65535, .recvBufferSize = 65535,
  9. .maxMessageSize = 1048576, .maxChunkCount = 16};
  10. void UA_Connection_init(UA_Connection *connection) {
  11. connection->state = UA_CONNECTION_CLOSED;
  12. connection->localConf = UA_ConnectionConfig_standard;
  13. connection->remoteConf = UA_ConnectionConfig_standard;
  14. connection->channel = NULL;
  15. connection->sockfd = 0;
  16. connection->handle = NULL;
  17. UA_ByteString_init(&connection->incompleteMessage);
  18. connection->send = NULL;
  19. connection->recv = NULL;
  20. connection->close = NULL;
  21. connection->getSendBuffer = NULL;
  22. connection->releaseSendBuffer = NULL;
  23. connection->releaseRecvBuffer = NULL;
  24. }
  25. void UA_Connection_deleteMembers(UA_Connection *connection) {
  26. UA_ByteString_deleteMembers(&connection->incompleteMessage);
  27. }
  28. UA_StatusCode
  29. UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RESTRICT message,
  30. UA_Boolean * UA_RESTRICT realloced) {
  31. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  32. /* We have a stored an incomplete chunk. Concat the received message to the end.
  33. * After this block, connection->incompleteMessage is always empty. */
  34. if(connection->incompleteMessage.length > 0) {
  35. size_t length = connection->incompleteMessage.length + message->length;
  36. UA_Byte *data = UA_realloc(connection->incompleteMessage.data, length);
  37. if(!data) {
  38. retval = UA_STATUSCODE_BADOUTOFMEMORY;
  39. goto cleanup;
  40. }
  41. memcpy(&data[connection->incompleteMessage.length], message->data, length);
  42. connection->releaseRecvBuffer(connection, message);
  43. message->data = data;
  44. message->length += length;
  45. *realloced = true;
  46. connection->incompleteMessage = UA_BYTESTRING_NULL;
  47. }
  48. /* Loop over the chunks in the received buffer */
  49. size_t complete_until = 0; /* the received complete chunks end at this point */
  50. UA_Boolean garbage_end = false; /* garbage after the last complete message */
  51. while(message->length - complete_until >= 8) {
  52. /* Check the message type */
  53. UA_UInt32 msgtype = (UA_UInt32)message->data[complete_until] +
  54. ((UA_UInt32)message->data[complete_until+1] << 8) +
  55. ((UA_UInt32)message->data[complete_until+2] << 16);
  56. if(msgtype != ('M' + ('S' << 8) + ('G' << 16)) &&
  57. msgtype != ('O' + ('P' << 8) + ('N' << 16)) &&
  58. msgtype != ('H' + ('E' << 8) + ('L' << 16)) &&
  59. msgtype != ('A' + ('C' << 8) + ('K' << 16)) &&
  60. msgtype != ('C' + ('L' << 8) + ('O' << 16))) {
  61. garbage_end = true; /* the message type is not recognized */
  62. break;
  63. }
  64. /* Decode the length of the chunk */
  65. UA_UInt32 chunk_length = 0;
  66. size_t length_pos = complete_until + 4;
  67. UA_StatusCode decode_retval = UA_UInt32_decodeBinary(message, &length_pos, &chunk_length);
  68. /* The message size is not allowed. Throw the remaining bytestring away */
  69. if(decode_retval != UA_STATUSCODE_GOOD || chunk_length < 16 || chunk_length > connection->localConf.recvBufferSize) {
  70. garbage_end = true;
  71. break;
  72. }
  73. /* The chunk is okay but incomplete. Store the end. */
  74. if(chunk_length + complete_until > message->length)
  75. break;
  76. complete_until += chunk_length; /* Go to the next chunk */
  77. }
  78. /* Separate incomplete chunks */
  79. if(complete_until != message->length) {
  80. /* Garbage after the last good chunk. No need to keep a buffer */
  81. if(garbage_end) {
  82. if(complete_until == 0)
  83. goto cleanup; /* All garbage, only happens on messages from the network layer */
  84. message->length = complete_until;
  85. return UA_STATUSCODE_GOOD;
  86. }
  87. /* No good chunk, only an incomplete one */
  88. if(complete_until == 0) {
  89. if(!*realloced) {
  90. retval = UA_ByteString_allocBuffer(&connection->incompleteMessage, message->length);
  91. if(retval != UA_STATUSCODE_GOOD)
  92. goto cleanup;
  93. memcpy(connection->incompleteMessage.data, message->data, message->length);
  94. connection->releaseRecvBuffer(connection, message);
  95. *realloced = true;
  96. } else {
  97. connection->incompleteMessage = *message;
  98. *message = UA_BYTESTRING_NULL;
  99. }
  100. return UA_STATUSCODE_GOOD;
  101. }
  102. /* At least one good chunk and an incomplete one */
  103. size_t incomplete_length = message->length - complete_until;
  104. retval = UA_ByteString_allocBuffer(&connection->incompleteMessage, incomplete_length);
  105. if(retval != UA_STATUSCODE_GOOD)
  106. goto cleanup;
  107. memcpy(&connection->incompleteMessage.data, &message->data[complete_until], incomplete_length);
  108. message->length = complete_until;
  109. }
  110. return UA_STATUSCODE_GOOD;
  111. cleanup:
  112. if(!*realloced)
  113. connection->releaseRecvBuffer(connection, message);
  114. UA_ByteString_deleteMembers(&connection->incompleteMessage);
  115. return retval;
  116. }
  117. #if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
  118. #pragma GCC diagnostic push
  119. #pragma GCC diagnostic ignored "-Wextra"
  120. #pragma GCC diagnostic ignored "-Wcast-qual"
  121. #pragma GCC diagnostic ignored "-Wunused-value"
  122. #endif
  123. void UA_Connection_detachSecureChannel(UA_Connection *connection) {
  124. #ifdef UA_ENABLE_MULTITHREADING
  125. UA_SecureChannel *channel = connection->channel;
  126. if(channel)
  127. uatomic_cmpxchg(&channel->connection, connection, NULL);
  128. uatomic_set(&connection->channel, NULL);
  129. #else
  130. if(connection->channel)
  131. connection->channel->connection = NULL;
  132. connection->channel = NULL;
  133. #endif
  134. }
  135. void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) {
  136. #ifdef UA_ENABLE_MULTITHREADING
  137. if(uatomic_cmpxchg(&channel->connection, NULL, connection) == NULL)
  138. uatomic_set((void**)&connection->channel, (void*)channel);
  139. #else
  140. if(channel->connection != NULL)
  141. return;
  142. channel->connection = connection;
  143. connection->channel = channel;
  144. #endif
  145. }
  146. #if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
  147. #pragma GCC diagnostic pop
  148. #endif