ua_connection.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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 = 65536, .recvBufferSize = 65536,
  9. .maxMessageSize = 65536, .maxChunkCount = 1};
  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->close = NULL;
  20. connection->recv = 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_ByteString *current = message;
  32. *realloced = false;
  33. if(connection->incompleteMessage.length > 0) {
  34. /* concat the existing incomplete message with the new message */
  35. UA_Byte *data = UA_realloc(connection->incompleteMessage.data,
  36. connection->incompleteMessage.length + message->length);
  37. if(!data) {
  38. /* not enough memory */
  39. UA_ByteString_deleteMembers(&connection->incompleteMessage);
  40. connection->releaseRecvBuffer(connection, message);
  41. return UA_STATUSCODE_BADOUTOFMEMORY;
  42. }
  43. memcpy(&data[connection->incompleteMessage.length], message->data, message->length);
  44. connection->incompleteMessage.data = data;
  45. connection->incompleteMessage.length += message->length;
  46. connection->releaseRecvBuffer(connection, message);
  47. current = &connection->incompleteMessage;
  48. *realloced = true;
  49. }
  50. /* the while loop sets pos to the first element after the last complete message. if a message
  51. contains garbage, the buffer length is set to contain only the "good" messages before. */
  52. size_t pos = 0;
  53. size_t delete_at = current->length-1; // garbled message after this point
  54. while(current->length - pos >= 16) {
  55. UA_UInt32 msgtype = (UA_UInt32)current->data[pos] +
  56. ((UA_UInt32)current->data[pos+1] << 8) +
  57. ((UA_UInt32)current->data[pos+2] << 16);
  58. if(msgtype != ('M' + ('S' << 8) + ('G' << 16)) &&
  59. msgtype != ('O' + ('P' << 8) + ('N' << 16)) &&
  60. msgtype != ('H' + ('E' << 8) + ('L' << 16)) &&
  61. msgtype != ('A' + ('C' << 8) + ('K' << 16)) &&
  62. msgtype != ('C' + ('L' << 8) + ('O' << 16))) {
  63. /* the message type is not recognized */
  64. delete_at = pos; // throw the remaining message away
  65. break;
  66. }
  67. UA_UInt32 length = 0;
  68. size_t length_pos = pos + 4;
  69. UA_StatusCode retval = UA_UInt32_decodeBinary(current, &length_pos, &length);
  70. if(retval != UA_STATUSCODE_GOOD || length < 16 || length > connection->localConf.recvBufferSize) {
  71. /* the message size is not allowed. throw the remaining bytestring away */
  72. delete_at = pos;
  73. break;
  74. }
  75. if(length + pos > current->length)
  76. break; /* the message is incomplete. keep the beginning */
  77. pos += length;
  78. }
  79. /* throw the message away */
  80. if(delete_at == 0) {
  81. if(!*realloced) {
  82. connection->releaseRecvBuffer(connection, message);
  83. *realloced = true;
  84. } else
  85. UA_ByteString_deleteMembers(current);
  86. return UA_STATUSCODE_GOOD;
  87. }
  88. /* no complete message at all */
  89. if(pos == 0) {
  90. if(!*realloced) {
  91. /* store the buffer in the connection */
  92. UA_ByteString_copy(current, &connection->incompleteMessage);
  93. connection->releaseRecvBuffer(connection, message);
  94. *realloced = true;
  95. }
  96. return UA_STATUSCODE_GOOD;
  97. }
  98. /* there remains an incomplete message at the end */
  99. if(current->length != pos) {
  100. UA_Byte *data = UA_malloc(current->length - pos);
  101. if(!data) {
  102. UA_ByteString_deleteMembers(&connection->incompleteMessage);
  103. if(!*realloced) {
  104. connection->releaseRecvBuffer(connection, message);
  105. *realloced = true;
  106. }
  107. return UA_STATUSCODE_BADOUTOFMEMORY;
  108. }
  109. size_t newlength = current->length - pos;
  110. memcpy(data, &current->data[pos], newlength);
  111. current->length = pos;
  112. if(*realloced)
  113. *message = *current;
  114. connection->incompleteMessage.data = data;
  115. connection->incompleteMessage.length = newlength;
  116. return UA_STATUSCODE_GOOD;
  117. }
  118. if(current == &connection->incompleteMessage) {
  119. *message = *current;
  120. connection->incompleteMessage = UA_BYTESTRING_NULL;
  121. }
  122. return UA_STATUSCODE_GOOD;
  123. }
  124. #if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
  125. #pragma GCC diagnostic push
  126. #pragma GCC diagnostic ignored "-Wextra"
  127. #pragma GCC diagnostic ignored "-Wcast-qual"
  128. #pragma GCC diagnostic ignored "-Wunused-value"
  129. #endif
  130. void UA_Connection_detachSecureChannel(UA_Connection *connection) {
  131. #ifdef UA_ENABLE_MULTITHREADING
  132. UA_SecureChannel *channel = connection->channel;
  133. if(channel)
  134. uatomic_cmpxchg(&channel->connection, connection, NULL);
  135. uatomic_set(&connection->channel, NULL);
  136. #else
  137. if(connection->channel)
  138. connection->channel->connection = NULL;
  139. connection->channel = NULL;
  140. #endif
  141. }
  142. void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) {
  143. #ifdef UA_ENABLE_MULTITHREADING
  144. if(uatomic_cmpxchg(&channel->connection, NULL, connection) == NULL)
  145. uatomic_set((void**)&connection->channel, (void*)channel);
  146. #else
  147. if(channel->connection != NULL)
  148. return;
  149. channel->connection = connection;
  150. connection->channel = channel;
  151. #endif
  152. }
  153. #if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
  154. #pragma GCC diagnostic pop
  155. #endif