ua_connection.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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, 2016-2017 (c) Florian Palm
  7. * Copyright 2015-2016 (c) Sten Grüner
  8. * Copyright 2015 (c) Oleksiy Vasylyev
  9. * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
  10. * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
  11. */
  12. #include "ua_util_internal.h"
  13. #include "ua_connection_internal.h"
  14. #include "ua_types_encoding_binary.h"
  15. #include "ua_types_generated_encoding_binary.h"
  16. #include "ua_types_generated_handling.h"
  17. #include "ua_transport_generated_encoding_binary.h"
  18. #include "ua_securechannel.h"
  19. void UA_Connection_deleteMembers(UA_Connection *connection) {
  20. UA_ByteString_deleteMembers(&connection->incompleteMessage);
  21. }
  22. /* Hides somme errors before sending them to a client according to the
  23. * standard. */
  24. static void
  25. hideErrors(UA_TcpErrorMessage *const error) {
  26. switch(error->error) {
  27. case UA_STATUSCODE_BADCERTIFICATEUNTRUSTED:
  28. error->error = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  29. error->reason = UA_STRING_NULL;
  30. break;
  31. // TODO: Check if these are all cases that need to be covered.
  32. default:
  33. break;
  34. }
  35. }
  36. void
  37. UA_Connection_sendError(UA_Connection *connection, UA_TcpErrorMessage *error) {
  38. hideErrors(error);
  39. UA_TcpMessageHeader header;
  40. header.messageTypeAndChunkType = UA_MESSAGETYPE_ERR + UA_CHUNKTYPE_FINAL;
  41. // Header + ErrorMessage (error + reasonLength_field + length)
  42. header.messageSize = 8 + (4 + 4 + (UA_UInt32)error->reason.length);
  43. /* Get the send buffer from the network layer */
  44. UA_ByteString msg = UA_BYTESTRING_NULL;
  45. UA_StatusCode retval = connection->getSendBuffer(connection, header.messageSize, &msg);
  46. if(retval != UA_STATUSCODE_GOOD)
  47. return;
  48. /* Encode and send the response */
  49. UA_Byte *bufPos = msg.data;
  50. const UA_Byte *bufEnd = &msg.data[msg.length];
  51. UA_TcpMessageHeader_encodeBinary(&header, &bufPos, bufEnd);
  52. UA_TcpErrorMessage_encodeBinary(error, &bufPos, bufEnd);
  53. msg.length = header.messageSize;
  54. connection->send(connection, &msg);
  55. }
  56. static UA_StatusCode
  57. prependIncompleteChunk(UA_Connection *connection, UA_ByteString *message) {
  58. /* Allocate the new message buffer */
  59. size_t length = connection->incompleteMessage.length + message->length;
  60. UA_Byte *data = (UA_Byte*)UA_realloc(connection->incompleteMessage.data, length);
  61. if(!data) {
  62. UA_ByteString_deleteMembers(&connection->incompleteMessage);
  63. return UA_STATUSCODE_BADOUTOFMEMORY;
  64. }
  65. /* Copy / release the current message buffer */
  66. memcpy(&data[connection->incompleteMessage.length], message->data, message->length);
  67. message->length = length;
  68. message->data = data;
  69. connection->incompleteMessage = UA_BYTESTRING_NULL;
  70. return UA_STATUSCODE_GOOD;
  71. }
  72. static UA_StatusCode
  73. bufferIncompleteChunk(UA_Connection *connection, const UA_Byte *pos, size_t length) {
  74. UA_assert(length > 0);
  75. UA_StatusCode retval = UA_ByteString_allocBuffer(&connection->incompleteMessage, length);
  76. if(retval != UA_STATUSCODE_GOOD)
  77. return retval;
  78. memcpy(connection->incompleteMessage.data, pos, length);
  79. return UA_STATUSCODE_GOOD;
  80. }
  81. static UA_StatusCode
  82. processChunk(UA_Connection *connection, void *application,
  83. UA_Connection_processChunk processCallback,
  84. const UA_Byte **posp, const UA_Byte *end, UA_Boolean *done) {
  85. const UA_Byte *pos = *posp;
  86. const size_t length = (uintptr_t)end - (uintptr_t)pos;
  87. /* At least 8 byte needed for the header. Wait for the next chunk. */
  88. if(length < 8) {
  89. if(length > 0)
  90. bufferIncompleteChunk(connection, pos, length);
  91. *done = true;
  92. return UA_STATUSCODE_GOOD;
  93. }
  94. /* Check the message type */
  95. UA_MessageType msgtype = (UA_MessageType)
  96. ((UA_UInt32)pos[0] + ((UA_UInt32)pos[1] << 8) + ((UA_UInt32)pos[2] << 16));
  97. if(msgtype != UA_MESSAGETYPE_MSG && msgtype != UA_MESSAGETYPE_ERR &&
  98. msgtype != UA_MESSAGETYPE_OPN && msgtype != UA_MESSAGETYPE_HEL &&
  99. msgtype != UA_MESSAGETYPE_ACK && msgtype != UA_MESSAGETYPE_CLO) {
  100. /* The message type is not recognized */
  101. return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
  102. }
  103. UA_Byte isFinal = pos[3];
  104. if(isFinal != 'C' && isFinal != 'F' && isFinal != 'A') {
  105. /* The message type is not recognized */
  106. return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
  107. }
  108. UA_UInt32 chunk_length = 0;
  109. UA_ByteString temp = { 8, (UA_Byte*)(uintptr_t)pos }; /* At least 8 byte left */
  110. size_t temp_offset = 4;
  111. /* Decoding the UInt32 cannot fail */
  112. UA_UInt32_decodeBinary(&temp, &temp_offset, &chunk_length);
  113. /* The message size is not allowed */
  114. if(chunk_length < 16 || chunk_length > connection->localConf.recvBufferSize)
  115. return UA_STATUSCODE_BADTCPMESSAGETOOLARGE;
  116. /* Wait for the next packet to process the complete chunk */
  117. if(chunk_length > length) {
  118. bufferIncompleteChunk(connection, pos, length);
  119. *done = true;
  120. return UA_STATUSCODE_GOOD;
  121. }
  122. /* Process the chunk; forward the position pointer */
  123. temp.length = chunk_length;
  124. *posp += chunk_length;
  125. *done = false;
  126. return processCallback(application, connection, &temp);
  127. }
  128. UA_StatusCode
  129. UA_Connection_processChunks(UA_Connection *connection, void *application,
  130. UA_Connection_processChunk processCallback,
  131. const UA_ByteString *packet) {
  132. /* If we have stored an incomplete chunk, prefix to the received message.
  133. * After this block, connection->incompleteMessage is always empty. The
  134. * message and the buffer is released if allocating the memory fails. */
  135. UA_Boolean realloced = false;
  136. UA_ByteString message = *packet;
  137. UA_StatusCode retval;
  138. if(connection->incompleteMessage.length > 0) {
  139. retval = prependIncompleteChunk(connection, &message);
  140. if(retval != UA_STATUSCODE_GOOD)
  141. return retval;
  142. realloced = true;
  143. }
  144. /* Loop over the received chunks. pos is increased with each chunk. */
  145. const UA_Byte *pos = message.data;
  146. const UA_Byte *end = &message.data[message.length];
  147. UA_Boolean done = true;
  148. do {
  149. retval = processChunk(connection, application, processCallback,
  150. &pos, end, &done);
  151. } while(!done && retval == UA_STATUSCODE_GOOD);
  152. if(realloced)
  153. UA_ByteString_deleteMembers(&message);
  154. return retval;
  155. }
  156. /* In order to know whether a chunk was processed, we insert an redirection into
  157. * the callback. */
  158. struct completeChunkTrampolineData {
  159. UA_Boolean called;
  160. void *application;
  161. UA_Connection_processChunk processCallback;
  162. };
  163. static UA_StatusCode
  164. completeChunkTrampoline(void *application, UA_Connection *connection,
  165. UA_ByteString *chunk) {
  166. struct completeChunkTrampolineData *data =
  167. (struct completeChunkTrampolineData*)application;
  168. data->called = true;
  169. return data->processCallback(data->application, connection, chunk);
  170. }
  171. UA_StatusCode
  172. UA_Connection_receiveChunksBlocking(UA_Connection *connection, void *application,
  173. UA_Connection_processChunk processCallback,
  174. UA_UInt32 timeout) {
  175. UA_DateTime now = UA_DateTime_nowMonotonic();
  176. UA_DateTime maxDate = now + (timeout * UA_DATETIME_MSEC);
  177. struct completeChunkTrampolineData data;
  178. data.called = false;
  179. data.application = application;
  180. data.processCallback = processCallback;
  181. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  182. while(true) {
  183. /* Listen for messages to arrive */
  184. UA_ByteString packet = UA_BYTESTRING_NULL;
  185. retval = connection->recv(connection, &packet, timeout);
  186. if(retval != UA_STATUSCODE_GOOD)
  187. break;
  188. /* Try to process one complete chunk */
  189. retval = UA_Connection_processChunks(connection, &data,
  190. completeChunkTrampoline, &packet);
  191. connection->releaseRecvBuffer(connection, &packet);
  192. if(data.called)
  193. break;
  194. /* We received a message. But the chunk is incomplete. Compute the
  195. * remaining timeout. */
  196. now = UA_DateTime_nowMonotonic();
  197. /* >= avoid timeout to be set to 0 */
  198. if(now >= maxDate)
  199. return UA_STATUSCODE_GOODNONCRITICALTIMEOUT;
  200. /* round always to upper value to avoid timeout to be set to 0
  201. * if(maxDate - now) < (UA_DATETIME_MSEC/2) */
  202. timeout = (UA_UInt32)(((maxDate - now) + (UA_DATETIME_MSEC - 1)) / UA_DATETIME_MSEC);
  203. }
  204. return retval;
  205. }
  206. UA_StatusCode
  207. UA_Connection_receiveChunksNonBlocking(UA_Connection *connection, void *application,
  208. UA_Connection_processChunk processCallback) {
  209. struct completeChunkTrampolineData data;
  210. data.called = false;
  211. data.application = application;
  212. data.processCallback = processCallback;
  213. /* Listen for messages to arrive */
  214. UA_ByteString packet = UA_BYTESTRING_NULL;
  215. UA_StatusCode retval = connection->recv(connection, &packet, 1);
  216. if((retval != UA_STATUSCODE_GOOD) && (retval != UA_STATUSCODE_GOODNONCRITICALTIMEOUT))
  217. return retval;
  218. /* Try to process one complete chunk */
  219. retval = UA_Connection_processChunks(connection, &data, completeChunkTrampoline, &packet);
  220. connection->releaseRecvBuffer(connection, &packet);
  221. return retval;
  222. }
  223. void UA_Connection_detachSecureChannel(UA_Connection *connection) {
  224. UA_SecureChannel *channel = connection->channel;
  225. if(channel)
  226. /* only replace when the channel points to this connection */
  227. UA_atomic_cmpxchg((void**)&channel->connection, connection, NULL);
  228. UA_atomic_xchg((void**)&connection->channel, NULL);
  229. }
  230. // TODO: Return an error code
  231. void
  232. UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) {
  233. if(UA_atomic_cmpxchg((void**)&channel->connection, NULL, connection) == NULL)
  234. UA_atomic_xchg((void**)&connection->channel, (void*)channel);
  235. }