A small memory footprint AMQP implimentation

Dependents:   iothub_client_sample_amqp remote_monitoring simplesample_amqp

Committer:
AzureIoTClient
Date:
Fri Jun 30 10:41:22 2017 -0700
Revision:
28:add19eb7defa
Parent:
25:1101516ee67d
Child:
30:0407b2db334c
1.1.18

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Azure.IoT Build 0:6ae2f7bca550 1 // Copyright (c) Microsoft. All rights reserved.
Azure.IoT Build 0:6ae2f7bca550 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
Azure.IoT Build 0:6ae2f7bca550 3
Azure.IoT Build 0:6ae2f7bca550 4 #include <stdlib.h>
Azure.IoT Build 0:6ae2f7bca550 5 #include <string.h>
Azure.IoT Build 0:6ae2f7bca550 6
AzureIoTClient 19:000ab4e6a2c1 7 #include "azure_c_shared_utility/optimize_size.h"
AzureIoTClient 21:f9c433d8e6ca 8 #include "azure_c_shared_utility/gballoc.h"
Azure.IoT Build 0:6ae2f7bca550 9 #include "azure_c_shared_utility/xio.h"
Azure.IoT Build 0:6ae2f7bca550 10 #include "azure_c_shared_utility/xlogging.h"
Azure.IoT Build 0:6ae2f7bca550 11 #include "azure_c_shared_utility/tickcounter.h"
Azure.IoT Build 0:6ae2f7bca550 12
Azure.IoT Build 0:6ae2f7bca550 13 #include "azure_uamqp_c/connection.h"
Azure.IoT Build 0:6ae2f7bca550 14 #include "azure_uamqp_c/frame_codec.h"
Azure.IoT Build 0:6ae2f7bca550 15 #include "azure_uamqp_c/amqp_frame_codec.h"
Azure.IoT Build 0:6ae2f7bca550 16 #include "azure_uamqp_c/amqp_definitions.h"
Azure.IoT Build 0:6ae2f7bca550 17 #include "azure_uamqp_c/amqpvalue_to_string.h"
Azure.IoT Build 0:6ae2f7bca550 18
Azure.IoT Build 0:6ae2f7bca550 19 /* Requirements satisfied by the virtue of implementing the ISO:*/
Azure.IoT Build 0:6ae2f7bca550 20 /* Codes_SRS_CONNECTION_01_088: [Any data appearing beyond the protocol header MUST match the version indicated by the protocol header.] */
Azure.IoT Build 0:6ae2f7bca550 21 /* Codes_SRS_CONNECTION_01_015: [Implementations SHOULD NOT expect to be able to reuse open TCP sockets after close performatives have been exchanged.] */
Azure.IoT Build 0:6ae2f7bca550 22
AzureIoTClient 16:22a72cf8e416 23 /* Codes_SRS_CONNECTION_01_087: [The protocol header consists of the upper case ASCII letters "AMQP" followed by a protocol id of zero, followed by three unsigned bytes representing the major, minor, and revision of the protocol version (currently 1 (MAJOR), 0 (MINOR), 0 (REVISION)). In total this is an 8-octet sequence] */
Azure.IoT Build 0:6ae2f7bca550 24 static const unsigned char amqp_header[] = { 'A', 'M', 'Q', 'P', 0, 1, 0, 0 };
Azure.IoT Build 0:6ae2f7bca550 25
Azure.IoT Build 0:6ae2f7bca550 26 typedef enum RECEIVE_FRAME_STATE_TAG
Azure.IoT Build 0:6ae2f7bca550 27 {
AzureIoTClient 4:98007eb79fa8 28 RECEIVE_FRAME_STATE_FRAME_SIZE,
AzureIoTClient 4:98007eb79fa8 29 RECEIVE_FRAME_STATE_FRAME_DATA
Azure.IoT Build 0:6ae2f7bca550 30 } RECEIVE_FRAME_STATE;
Azure.IoT Build 0:6ae2f7bca550 31
Azure.IoT Build 0:6ae2f7bca550 32 typedef struct ENDPOINT_INSTANCE_TAG
Azure.IoT Build 0:6ae2f7bca550 33 {
AzureIoTClient 4:98007eb79fa8 34 uint16_t incoming_channel;
AzureIoTClient 4:98007eb79fa8 35 uint16_t outgoing_channel;
AzureIoTClient 4:98007eb79fa8 36 ON_ENDPOINT_FRAME_RECEIVED on_endpoint_frame_received;
AzureIoTClient 4:98007eb79fa8 37 ON_CONNECTION_STATE_CHANGED on_connection_state_changed;
AzureIoTClient 4:98007eb79fa8 38 void* callback_context;
AzureIoTClient 4:98007eb79fa8 39 CONNECTION_HANDLE connection;
Azure.IoT Build 0:6ae2f7bca550 40 } ENDPOINT_INSTANCE;
Azure.IoT Build 0:6ae2f7bca550 41
Azure.IoT Build 0:6ae2f7bca550 42 typedef struct CONNECTION_INSTANCE_TAG
Azure.IoT Build 0:6ae2f7bca550 43 {
AzureIoTClient 4:98007eb79fa8 44 XIO_HANDLE io;
AzureIoTClient 4:98007eb79fa8 45 size_t header_bytes_received;
AzureIoTClient 4:98007eb79fa8 46 CONNECTION_STATE connection_state;
AzureIoTClient 4:98007eb79fa8 47 FRAME_CODEC_HANDLE frame_codec;
AzureIoTClient 4:98007eb79fa8 48 AMQP_FRAME_CODEC_HANDLE amqp_frame_codec;
AzureIoTClient 4:98007eb79fa8 49 ENDPOINT_INSTANCE** endpoints;
AzureIoTClient 4:98007eb79fa8 50 uint32_t endpoint_count;
AzureIoTClient 4:98007eb79fa8 51 char* host_name;
AzureIoTClient 4:98007eb79fa8 52 char* container_id;
AzureIoTClient 4:98007eb79fa8 53 TICK_COUNTER_HANDLE tick_counter;
AzureIoTClient 4:98007eb79fa8 54 uint32_t remote_max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 55
AzureIoTClient 4:98007eb79fa8 56 ON_SEND_COMPLETE on_send_complete;
AzureIoTClient 4:98007eb79fa8 57 void* on_send_complete_callback_context;
Azure.IoT Build 0:6ae2f7bca550 58
AzureIoTClient 4:98007eb79fa8 59 ON_NEW_ENDPOINT on_new_endpoint;
AzureIoTClient 4:98007eb79fa8 60 void* on_new_endpoint_callback_context;
Azure.IoT Build 0:6ae2f7bca550 61
Azure.IoT Build 0:6ae2f7bca550 62 ON_CONNECTION_STATE_CHANGED on_connection_state_changed;
Azure.IoT Build 0:6ae2f7bca550 63 void* on_connection_state_changed_callback_context;
Azure.IoT Build 0:6ae2f7bca550 64 ON_IO_ERROR on_io_error;
Azure.IoT Build 0:6ae2f7bca550 65 void* on_io_error_callback_context;
Azure.IoT Build 0:6ae2f7bca550 66
AzureIoTClient 4:98007eb79fa8 67 /* options */
AzureIoTClient 4:98007eb79fa8 68 uint32_t max_frame_size;
AzureIoTClient 4:98007eb79fa8 69 uint16_t channel_max;
AzureIoTClient 4:98007eb79fa8 70 milliseconds idle_timeout;
AzureIoTClient 4:98007eb79fa8 71 milliseconds remote_idle_timeout;
Azure.IoT.Build 14:0b0e28c75ded 72 tickcounter_ms_t last_frame_received_time;
Azure.IoT.Build 14:0b0e28c75ded 73 tickcounter_ms_t last_frame_sent_time;
Azure.IoT Build 0:6ae2f7bca550 74
AzureIoTClient 4:98007eb79fa8 75 unsigned int is_underlying_io_open : 1;
AzureIoTClient 4:98007eb79fa8 76 unsigned int idle_timeout_specified : 1;
AzureIoTClient 4:98007eb79fa8 77 unsigned int is_remote_frame_received : 1;
AzureIoTClient 4:98007eb79fa8 78 unsigned int is_trace_on : 1;
Azure.IoT Build 0:6ae2f7bca550 79 } CONNECTION_INSTANCE;
Azure.IoT Build 0:6ae2f7bca550 80
Azure.IoT Build 0:6ae2f7bca550 81 /* Codes_SRS_CONNECTION_01_258: [on_connection_state_changed shall be invoked whenever the connection state changes.]*/
AzureIoTClient 24:2c59c2d43ebf 82 static void connection_set_state(CONNECTION_HANDLE connection, CONNECTION_STATE connection_state)
Azure.IoT Build 0:6ae2f7bca550 83 {
AzureIoTClient 4:98007eb79fa8 84 uint64_t i;
Azure.IoT Build 0:6ae2f7bca550 85
AzureIoTClient 24:2c59c2d43ebf 86 CONNECTION_STATE previous_state = connection->connection_state;
AzureIoTClient 24:2c59c2d43ebf 87 connection->connection_state = connection_state;
Azure.IoT Build 0:6ae2f7bca550 88
Azure.IoT Build 0:6ae2f7bca550 89 /* Codes_SRS_CONNECTION_22_001: [If a connection state changed occurs and a callback is registered the callback shall be called.] */
AzureIoTClient 24:2c59c2d43ebf 90 if (connection->on_connection_state_changed)
Azure.IoT Build 0:6ae2f7bca550 91 {
AzureIoTClient 24:2c59c2d43ebf 92 connection->on_connection_state_changed(connection->on_connection_state_changed_callback_context, connection_state, previous_state);
Azure.IoT Build 0:6ae2f7bca550 93 }
Azure.IoT Build 0:6ae2f7bca550 94
AzureIoTClient 16:22a72cf8e416 95 /* Codes_SRS_CONNECTION_01_260: [Each endpoint's on_connection_state_changed shall be called.] */
AzureIoTClient 24:2c59c2d43ebf 96 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 97 {
AzureIoTClient 4:98007eb79fa8 98 /* Codes_SRS_CONNECTION_01_259: [The callback_context passed in connection_create_endpoint.] */
AzureIoTClient 24:2c59c2d43ebf 99 connection->endpoints[i]->on_connection_state_changed(connection->endpoints[i]->callback_context, connection_state, previous_state);
AzureIoTClient 4:98007eb79fa8 100 }
Azure.IoT Build 0:6ae2f7bca550 101 }
Azure.IoT Build 0:6ae2f7bca550 102
AzureIoTClient 24:2c59c2d43ebf 103 static int send_header(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 104 {
AzureIoTClient 4:98007eb79fa8 105 int result;
Azure.IoT Build 0:6ae2f7bca550 106
AzureIoTClient 16:22a72cf8e416 107 /* Codes_SRS_CONNECTION_01_093: [_ When the client opens a new socket connection to a server, it MUST send a protocol header with the client's preferred protocol version.] */
AzureIoTClient 4:98007eb79fa8 108 /* Codes_SRS_CONNECTION_01_104: [Sending the protocol header shall be done by using xio_send.] */
AzureIoTClient 24:2c59c2d43ebf 109 if (xio_send(connection->io, amqp_header, sizeof(amqp_header), NULL, NULL) != 0)
AzureIoTClient 4:98007eb79fa8 110 {
AzureIoTClient 4:98007eb79fa8 111 /* Codes_SRS_CONNECTION_01_106: [When sending the protocol header fails, the connection shall be immediately closed.] */
AzureIoTClient 28:add19eb7defa 112 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 113 {
AzureIoTClient 28:add19eb7defa 114 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 115 }
Azure.IoT Build 0:6ae2f7bca550 116
AzureIoTClient 4:98007eb79fa8 117 /* Codes_SRS_CONNECTION_01_057: [END In this state it is illegal for either endpoint to write anything more onto the connection. The connection can be safely closed and discarded.] */
AzureIoTClient 24:2c59c2d43ebf 118 connection_set_state(connection, CONNECTION_STATE_END);
Azure.IoT Build 0:6ae2f7bca550 119
AzureIoTClient 4:98007eb79fa8 120 /* Codes_SRS_CONNECTION_01_105: [When xio_send fails, connection_dowork shall return a non-zero value.] */
AzureIoTClient 19:000ab4e6a2c1 121 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 122 }
AzureIoTClient 4:98007eb79fa8 123 else
AzureIoTClient 4:98007eb79fa8 124 {
AzureIoTClient 24:2c59c2d43ebf 125 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 126 {
AzureIoTClient 16:22a72cf8e416 127 LOG(AZ_LOG_TRACE, LOG_LINE, "-> Header (AMQP 0.1.0.0)");
AzureIoTClient 4:98007eb79fa8 128 }
Azure.IoT Build 0:6ae2f7bca550 129
AzureIoTClient 4:98007eb79fa8 130 /* Codes_SRS_CONNECTION_01_041: [HDR SENT In this state the connection header has been sent to the peer but no connection header has been received.] */
AzureIoTClient 24:2c59c2d43ebf 131 connection_set_state(connection, CONNECTION_STATE_HDR_SENT);
AzureIoTClient 4:98007eb79fa8 132 result = 0;
AzureIoTClient 4:98007eb79fa8 133 }
Azure.IoT Build 0:6ae2f7bca550 134
AzureIoTClient 4:98007eb79fa8 135 return result;
Azure.IoT Build 0:6ae2f7bca550 136 }
Azure.IoT Build 0:6ae2f7bca550 137
Azure.IoT Build 0:6ae2f7bca550 138 static const char* get_frame_type_as_string(AMQP_VALUE descriptor)
Azure.IoT Build 0:6ae2f7bca550 139 {
AzureIoTClient 4:98007eb79fa8 140 const char* result;
Azure.IoT Build 0:6ae2f7bca550 141
AzureIoTClient 4:98007eb79fa8 142 if (is_open_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 143 {
AzureIoTClient 4:98007eb79fa8 144 result = "[OPEN]";
AzureIoTClient 4:98007eb79fa8 145 }
AzureIoTClient 4:98007eb79fa8 146 else if (is_begin_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 147 {
AzureIoTClient 4:98007eb79fa8 148 result = "[BEGIN]";
AzureIoTClient 4:98007eb79fa8 149 }
AzureIoTClient 4:98007eb79fa8 150 else if (is_attach_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 151 {
AzureIoTClient 4:98007eb79fa8 152 result = "[ATTACH]";
AzureIoTClient 4:98007eb79fa8 153 }
AzureIoTClient 4:98007eb79fa8 154 else if (is_flow_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 155 {
AzureIoTClient 4:98007eb79fa8 156 result = "[FLOW]";
AzureIoTClient 4:98007eb79fa8 157 }
AzureIoTClient 4:98007eb79fa8 158 else if (is_disposition_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 159 {
AzureIoTClient 4:98007eb79fa8 160 result = "[DISPOSITION]";
AzureIoTClient 4:98007eb79fa8 161 }
AzureIoTClient 4:98007eb79fa8 162 else if (is_transfer_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 163 {
AzureIoTClient 4:98007eb79fa8 164 result = "[TRANSFER]";
AzureIoTClient 4:98007eb79fa8 165 }
AzureIoTClient 4:98007eb79fa8 166 else if (is_detach_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 167 {
AzureIoTClient 4:98007eb79fa8 168 result = "[DETACH]";
AzureIoTClient 4:98007eb79fa8 169 }
AzureIoTClient 4:98007eb79fa8 170 else if (is_end_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 171 {
AzureIoTClient 4:98007eb79fa8 172 result = "[END]";
AzureIoTClient 4:98007eb79fa8 173 }
AzureIoTClient 4:98007eb79fa8 174 else if (is_close_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 175 {
AzureIoTClient 4:98007eb79fa8 176 result = "[CLOSE]";
AzureIoTClient 4:98007eb79fa8 177 }
AzureIoTClient 4:98007eb79fa8 178 else
AzureIoTClient 4:98007eb79fa8 179 {
AzureIoTClient 4:98007eb79fa8 180 result = "[Unknown]";
AzureIoTClient 4:98007eb79fa8 181 }
Azure.IoT Build 0:6ae2f7bca550 182
AzureIoTClient 4:98007eb79fa8 183 return result;
Azure.IoT Build 0:6ae2f7bca550 184 }
Azure.IoT Build 0:6ae2f7bca550 185
Azure.IoT Build 5:ae49385aff34 186 static void log_incoming_frame(AMQP_VALUE performative)
Azure.IoT Build 0:6ae2f7bca550 187 {
AzureIoTClient 9:c22db038556c 188 #ifdef NO_LOGGING
AzureIoTClient 9:c22db038556c 189 UNUSED(performative);
AzureIoTClient 9:c22db038556c 190 #else
AzureIoTClient 4:98007eb79fa8 191 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
AzureIoTClient 28:add19eb7defa 192 if (descriptor == NULL)
AzureIoTClient 28:add19eb7defa 193 {
AzureIoTClient 28:add19eb7defa 194 LogError("Error getting performative descriptor");
AzureIoTClient 28:add19eb7defa 195 }
AzureIoTClient 28:add19eb7defa 196 else
AzureIoTClient 28:add19eb7defa 197 {
AzureIoTClient 28:add19eb7defa 198 char* performative_as_string;
AzureIoTClient 16:22a72cf8e416 199 LOG(AZ_LOG_TRACE, 0, "<- ");
AzureIoTClient 16:22a72cf8e416 200 LOG(AZ_LOG_TRACE, 0, (char*)get_frame_type_as_string(descriptor));
AzureIoTClient 25:1101516ee67d 201 performative_as_string = NULL;
AzureIoTClient 16:22a72cf8e416 202 LOG(AZ_LOG_TRACE, LOG_LINE, (performative_as_string = amqpvalue_to_string(performative)));
AzureIoTClient 4:98007eb79fa8 203 if (performative_as_string != NULL)
AzureIoTClient 4:98007eb79fa8 204 {
AzureIoTClient 21:f9c433d8e6ca 205 free(performative_as_string);
AzureIoTClient 4:98007eb79fa8 206 }
AzureIoTClient 4:98007eb79fa8 207 }
AzureIoTClient 9:c22db038556c 208 #endif
Azure.IoT Build 0:6ae2f7bca550 209 }
Azure.IoT Build 0:6ae2f7bca550 210
Azure.IoT Build 5:ae49385aff34 211 static void log_outgoing_frame(AMQP_VALUE performative)
Azure.IoT Build 0:6ae2f7bca550 212 {
AzureIoTClient 9:c22db038556c 213 #ifdef NO_LOGGING
AzureIoTClient 9:c22db038556c 214 UNUSED(performative);
AzureIoTClient 9:c22db038556c 215 #else
AzureIoTClient 4:98007eb79fa8 216 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
AzureIoTClient 28:add19eb7defa 217 if (descriptor == NULL)
AzureIoTClient 28:add19eb7defa 218 {
AzureIoTClient 28:add19eb7defa 219 LogError("Error getting performative descriptor");
AzureIoTClient 28:add19eb7defa 220 }
AzureIoTClient 28:add19eb7defa 221 else
AzureIoTClient 28:add19eb7defa 222 {
AzureIoTClient 28:add19eb7defa 223 char* performative_as_string;
AzureIoTClient 28:add19eb7defa 224 LOG(AZ_LOG_TRACE, 0, "-> ");
AzureIoTClient 16:22a72cf8e416 225 LOG(AZ_LOG_TRACE, 0, (char*)get_frame_type_as_string(descriptor));
AzureIoTClient 25:1101516ee67d 226 performative_as_string = NULL;
AzureIoTClient 16:22a72cf8e416 227 LOG(AZ_LOG_TRACE, LOG_LINE, (performative_as_string = amqpvalue_to_string(performative)));
AzureIoTClient 4:98007eb79fa8 228 if (performative_as_string != NULL)
AzureIoTClient 4:98007eb79fa8 229 {
AzureIoTClient 21:f9c433d8e6ca 230 free(performative_as_string);
AzureIoTClient 4:98007eb79fa8 231 }
AzureIoTClient 4:98007eb79fa8 232 }
AzureIoTClient 9:c22db038556c 233 #endif
Azure.IoT Build 0:6ae2f7bca550 234 }
Azure.IoT Build 0:6ae2f7bca550 235
Azure.IoT Build 0:6ae2f7bca550 236 static void on_bytes_encoded(void* context, const unsigned char* bytes, size_t length, bool encode_complete)
Azure.IoT Build 0:6ae2f7bca550 237 {
AzureIoTClient 24:2c59c2d43ebf 238 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
AzureIoTClient 24:2c59c2d43ebf 239 if (xio_send(connection->io, bytes, length, encode_complete ? connection->on_send_complete : NULL, connection->on_send_complete_callback_context) != 0)
AzureIoTClient 4:98007eb79fa8 240 {
AzureIoTClient 28:add19eb7defa 241 LogError("Cannot send encoded bytes");
AzureIoTClient 24:2c59c2d43ebf 242
AzureIoTClient 28:add19eb7defa 243 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 244 {
AzureIoTClient 28:add19eb7defa 245 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 246 }
AzureIoTClient 24:2c59c2d43ebf 247
AzureIoTClient 24:2c59c2d43ebf 248 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 249 }
Azure.IoT Build 0:6ae2f7bca550 250 }
Azure.IoT Build 0:6ae2f7bca550 251
AzureIoTClient 24:2c59c2d43ebf 252 static int send_open_frame(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 253 {
AzureIoTClient 4:98007eb79fa8 254 int result;
Azure.IoT Build 0:6ae2f7bca550 255
AzureIoTClient 4:98007eb79fa8 256 /* Codes_SRS_CONNECTION_01_151: [The connection max_frame_size setting shall be passed down to the frame_codec when the Open frame is sent.] */
AzureIoTClient 24:2c59c2d43ebf 257 if (frame_codec_set_max_frame_size(connection->frame_codec, connection->max_frame_size) != 0)
AzureIoTClient 4:98007eb79fa8 258 {
AzureIoTClient 28:add19eb7defa 259 LogError("Cannot set max frame size");
AzureIoTClient 24:2c59c2d43ebf 260
AzureIoTClient 4:98007eb79fa8 261 /* Codes_SRS_CONNECTION_01_207: [If frame_codec_set_max_frame_size fails the connection shall be closed and the state set to END.] */
AzureIoTClient 28:add19eb7defa 262 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 263 {
AzureIoTClient 28:add19eb7defa 264 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 265 }
AzureIoTClient 24:2c59c2d43ebf 266
AzureIoTClient 28:add19eb7defa 267 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 268 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 269 }
AzureIoTClient 4:98007eb79fa8 270 else
AzureIoTClient 4:98007eb79fa8 271 {
AzureIoTClient 4:98007eb79fa8 272 /* Codes_SRS_CONNECTION_01_134: [The container id field shall be filled with the container id specified in connection_create.] */
AzureIoTClient 24:2c59c2d43ebf 273 OPEN_HANDLE open_performative = open_create(connection->container_id);
AzureIoTClient 4:98007eb79fa8 274 if (open_performative == NULL)
AzureIoTClient 4:98007eb79fa8 275 {
AzureIoTClient 28:add19eb7defa 276 LogError("Cannot create OPEN performative");
AzureIoTClient 28:add19eb7defa 277
AzureIoTClient 28:add19eb7defa 278 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 279 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 280 {
AzureIoTClient 28:add19eb7defa 281 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 282 }
AzureIoTClient 24:2c59c2d43ebf 283
AzureIoTClient 28:add19eb7defa 284 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 285 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 286 }
AzureIoTClient 4:98007eb79fa8 287 else
AzureIoTClient 4:98007eb79fa8 288 {
AzureIoTClient 4:98007eb79fa8 289 /* Codes_SRS_CONNECTION_01_137: [The max_frame_size connection setting shall be set in the open frame by using open_set_max_frame_size.] */
AzureIoTClient 24:2c59c2d43ebf 290 if (open_set_max_frame_size(open_performative, connection->max_frame_size) != 0)
AzureIoTClient 4:98007eb79fa8 291 {
AzureIoTClient 28:add19eb7defa 292 LogError("Cannot set max frame size");
AzureIoTClient 24:2c59c2d43ebf 293
AzureIoTClient 28:add19eb7defa 294 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 295 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 296 {
AzureIoTClient 28:add19eb7defa 297 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 298 }
AzureIoTClient 24:2c59c2d43ebf 299
AzureIoTClient 28:add19eb7defa 300 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 301 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 302 }
AzureIoTClient 4:98007eb79fa8 303 /* Codes_SRS_CONNECTION_01_139: [The channel_max connection setting shall be set in the open frame by using open_set_channel_max.] */
AzureIoTClient 24:2c59c2d43ebf 304 else if (open_set_channel_max(open_performative, connection->channel_max) != 0)
AzureIoTClient 4:98007eb79fa8 305 {
AzureIoTClient 28:add19eb7defa 306 LogError("Cannot set max channel");
AzureIoTClient 24:2c59c2d43ebf 307
AzureIoTClient 28:add19eb7defa 308 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 309 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 310 {
AzureIoTClient 28:add19eb7defa 311 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 312 }
AzureIoTClient 24:2c59c2d43ebf 313
AzureIoTClient 28:add19eb7defa 314 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 315 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 316 }
AzureIoTClient 4:98007eb79fa8 317 /* Codes_SRS_CONNECTION_01_142: [If no idle_timeout value has been specified, no value shall be stamped in the open frame (no call to open_set_idle_time_out shall be made).] */
AzureIoTClient 24:2c59c2d43ebf 318 else if ((connection->idle_timeout_specified) &&
AzureIoTClient 4:98007eb79fa8 319 /* Codes_SRS_CONNECTION_01_141: [If idle_timeout has been specified by a call to connection_set_idle_timeout, then that value shall be stamped in the open frame.] */
AzureIoTClient 24:2c59c2d43ebf 320 (open_set_idle_time_out(open_performative, connection->idle_timeout) != 0))
AzureIoTClient 4:98007eb79fa8 321 {
AzureIoTClient 4:98007eb79fa8 322 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 323 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 324 {
AzureIoTClient 28:add19eb7defa 325 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 326 }
AzureIoTClient 24:2c59c2d43ebf 327
AzureIoTClient 28:add19eb7defa 328 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 329 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 330 }
AzureIoTClient 4:98007eb79fa8 331 /* Codes_SRS_CONNECTION_01_136: [If no hostname value has been specified, no value shall be stamped in the open frame (no call to open_set_hostname shall be made).] */
AzureIoTClient 24:2c59c2d43ebf 332 else if ((connection->host_name != NULL) &&
AzureIoTClient 4:98007eb79fa8 333 /* Codes_SRS_CONNECTION_01_135: [If hostname has been specified by a call to connection_set_hostname, then that value shall be stamped in the open frame.] */
AzureIoTClient 24:2c59c2d43ebf 334 (open_set_hostname(open_performative, connection->host_name) != 0))
AzureIoTClient 4:98007eb79fa8 335 {
AzureIoTClient 28:add19eb7defa 336 LogError("Cannot set hostname");
AzureIoTClient 24:2c59c2d43ebf 337
AzureIoTClient 28:add19eb7defa 338 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 339 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 340 {
AzureIoTClient 28:add19eb7defa 341 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 342 }
AzureIoTClient 24:2c59c2d43ebf 343
AzureIoTClient 28:add19eb7defa 344 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 345 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 346 }
AzureIoTClient 4:98007eb79fa8 347 else
AzureIoTClient 4:98007eb79fa8 348 {
AzureIoTClient 4:98007eb79fa8 349 AMQP_VALUE open_performative_value = amqpvalue_create_open(open_performative);
AzureIoTClient 4:98007eb79fa8 350 if (open_performative_value == NULL)
AzureIoTClient 4:98007eb79fa8 351 {
AzureIoTClient 28:add19eb7defa 352 LogError("Cannot create OPEN AMQP value");
AzureIoTClient 24:2c59c2d43ebf 353
AzureIoTClient 28:add19eb7defa 354 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 355 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 356 {
AzureIoTClient 28:add19eb7defa 357 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 358 }
AzureIoTClient 24:2c59c2d43ebf 359
AzureIoTClient 28:add19eb7defa 360 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 361 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 362 }
AzureIoTClient 4:98007eb79fa8 363 else
AzureIoTClient 4:98007eb79fa8 364 {
AzureIoTClient 4:98007eb79fa8 365 /* Codes_SRS_CONNECTION_01_002: [Each AMQP connection begins with an exchange of capabilities and limitations, including the maximum frame size.] */
AzureIoTClient 4:98007eb79fa8 366 /* Codes_SRS_CONNECTION_01_004: [After establishing or accepting a TCP connection and sending the protocol header, each peer MUST send an open frame before sending any other frames.] */
AzureIoTClient 4:98007eb79fa8 367 /* Codes_SRS_CONNECTION_01_005: [The open frame describes the capabilities and limits of that peer.] */
AzureIoTClient 4:98007eb79fa8 368 /* Codes_SRS_CONNECTION_01_205: [Sending the AMQP OPEN frame shall be done by calling amqp_frame_codec_begin_encode_frame with channel number 0, the actual performative payload and 0 as payload_size.] */
AzureIoTClient 4:98007eb79fa8 369 /* Codes_SRS_CONNECTION_01_006: [The open frame can only be sent on channel 0.] */
AzureIoTClient 28:add19eb7defa 370 connection->on_send_complete = NULL;
AzureIoTClient 28:add19eb7defa 371 connection->on_send_complete_callback_context = NULL;
AzureIoTClient 24:2c59c2d43ebf 372 if (amqp_frame_codec_encode_frame(connection->amqp_frame_codec, 0, open_performative_value, NULL, 0, on_bytes_encoded, connection) != 0)
AzureIoTClient 4:98007eb79fa8 373 {
AzureIoTClient 28:add19eb7defa 374 LogError("amqp_frame_codec_encode_frame failed");
AzureIoTClient 24:2c59c2d43ebf 375
AzureIoTClient 28:add19eb7defa 376 /* Codes_SRS_CONNECTION_01_206: [If sending the frame fails, the connection shall be closed and state set to END.] */
AzureIoTClient 28:add19eb7defa 377 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 378 {
AzureIoTClient 28:add19eb7defa 379 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 380 }
AzureIoTClient 24:2c59c2d43ebf 381
AzureIoTClient 28:add19eb7defa 382 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 383 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 384 }
AzureIoTClient 4:98007eb79fa8 385 else
AzureIoTClient 4:98007eb79fa8 386 {
AzureIoTClient 24:2c59c2d43ebf 387 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 388 {
Azure.IoT Build 5:ae49385aff34 389 log_outgoing_frame(open_performative_value);
AzureIoTClient 4:98007eb79fa8 390 }
Azure.IoT Build 0:6ae2f7bca550 391
AzureIoTClient 4:98007eb79fa8 392 /* Codes_SRS_CONNECTION_01_046: [OPEN SENT In this state the connection headers have been exchanged. An open frame has been sent to the peer but no open frame has yet been received.] */
AzureIoTClient 24:2c59c2d43ebf 393 connection_set_state(connection, CONNECTION_STATE_OPEN_SENT);
AzureIoTClient 4:98007eb79fa8 394 result = 0;
AzureIoTClient 4:98007eb79fa8 395 }
Azure.IoT Build 0:6ae2f7bca550 396
AzureIoTClient 4:98007eb79fa8 397 amqpvalue_destroy(open_performative_value);
AzureIoTClient 4:98007eb79fa8 398 }
AzureIoTClient 4:98007eb79fa8 399 }
Azure.IoT Build 0:6ae2f7bca550 400
AzureIoTClient 4:98007eb79fa8 401 open_destroy(open_performative);
AzureIoTClient 4:98007eb79fa8 402 }
AzureIoTClient 4:98007eb79fa8 403 }
Azure.IoT Build 0:6ae2f7bca550 404
AzureIoTClient 4:98007eb79fa8 405 return result;
Azure.IoT Build 0:6ae2f7bca550 406 }
Azure.IoT Build 0:6ae2f7bca550 407
AzureIoTClient 24:2c59c2d43ebf 408 static int send_close_frame(CONNECTION_HANDLE connection, ERROR_HANDLE error_handle)
Azure.IoT Build 0:6ae2f7bca550 409 {
AzureIoTClient 4:98007eb79fa8 410 int result;
AzureIoTClient 4:98007eb79fa8 411 CLOSE_HANDLE close_performative;
Azure.IoT Build 0:6ae2f7bca550 412
AzureIoTClient 4:98007eb79fa8 413 /* Codes_SRS_CONNECTION_01_217: [The CLOSE frame shall be constructed by using close_create.] */
AzureIoTClient 4:98007eb79fa8 414 close_performative = close_create();
AzureIoTClient 4:98007eb79fa8 415 if (close_performative == NULL)
AzureIoTClient 4:98007eb79fa8 416 {
AzureIoTClient 28:add19eb7defa 417 LogError("Cannot create close performative");
AzureIoTClient 28:add19eb7defa 418 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 419 }
AzureIoTClient 4:98007eb79fa8 420 else
AzureIoTClient 4:98007eb79fa8 421 {
AzureIoTClient 4:98007eb79fa8 422 if ((error_handle != NULL) &&
AzureIoTClient 4:98007eb79fa8 423 /* Codes_SRS_CONNECTION_01_238: [If set, this field indicates that the connection is being closed due to an error condition.] */
AzureIoTClient 4:98007eb79fa8 424 (close_set_error(close_performative, error_handle) != 0))
AzureIoTClient 4:98007eb79fa8 425 {
AzureIoTClient 28:add19eb7defa 426 LogError("Cannot set error on CLOSE");
AzureIoTClient 28:add19eb7defa 427 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 428 }
AzureIoTClient 4:98007eb79fa8 429 else
AzureIoTClient 4:98007eb79fa8 430 {
AzureIoTClient 4:98007eb79fa8 431 AMQP_VALUE close_performative_value = amqpvalue_create_close(close_performative);
AzureIoTClient 4:98007eb79fa8 432 if (close_performative_value == NULL)
AzureIoTClient 4:98007eb79fa8 433 {
AzureIoTClient 28:add19eb7defa 434 LogError("Cannot create AMQP CLOSE performative value");
AzureIoTClient 28:add19eb7defa 435 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 436 }
AzureIoTClient 4:98007eb79fa8 437 else
AzureIoTClient 4:98007eb79fa8 438 {
AzureIoTClient 4:98007eb79fa8 439 /* Codes_SRS_CONNECTION_01_215: [Sending the AMQP CLOSE frame shall be done by calling amqp_frame_codec_begin_encode_frame with channel number 0, the actual performative payload and 0 as payload_size.] */
AzureIoTClient 4:98007eb79fa8 440 /* Codes_SRS_CONNECTION_01_013: [However, implementations SHOULD send it on channel 0] */
AzureIoTClient 28:add19eb7defa 441 connection->on_send_complete = NULL;
AzureIoTClient 28:add19eb7defa 442 connection->on_send_complete_callback_context = NULL;
AzureIoTClient 24:2c59c2d43ebf 443 if (amqp_frame_codec_encode_frame(connection->amqp_frame_codec, 0, close_performative_value, NULL, 0, on_bytes_encoded, connection) != 0)
AzureIoTClient 4:98007eb79fa8 444 {
AzureIoTClient 28:add19eb7defa 445 LogError("amqp_frame_codec_encode_frame failed");
AzureIoTClient 28:add19eb7defa 446 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 447 }
AzureIoTClient 4:98007eb79fa8 448 else
AzureIoTClient 4:98007eb79fa8 449 {
AzureIoTClient 24:2c59c2d43ebf 450 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 451 {
Azure.IoT Build 5:ae49385aff34 452 log_outgoing_frame(close_performative_value);
AzureIoTClient 4:98007eb79fa8 453 }
Azure.IoT Build 5:ae49385aff34 454
AzureIoTClient 4:98007eb79fa8 455 result = 0;
AzureIoTClient 4:98007eb79fa8 456 }
Azure.IoT Build 0:6ae2f7bca550 457
AzureIoTClient 4:98007eb79fa8 458 amqpvalue_destroy(close_performative_value);
AzureIoTClient 4:98007eb79fa8 459 }
AzureIoTClient 4:98007eb79fa8 460 }
Azure.IoT Build 0:6ae2f7bca550 461
AzureIoTClient 4:98007eb79fa8 462 close_destroy(close_performative);
AzureIoTClient 4:98007eb79fa8 463 }
Azure.IoT Build 0:6ae2f7bca550 464
AzureIoTClient 4:98007eb79fa8 465 return result;
Azure.IoT Build 0:6ae2f7bca550 466 }
Azure.IoT Build 0:6ae2f7bca550 467
AzureIoTClient 24:2c59c2d43ebf 468 static void close_connection_with_error(CONNECTION_HANDLE connection, const char* condition_value, const char* description)
Azure.IoT Build 0:6ae2f7bca550 469 {
AzureIoTClient 4:98007eb79fa8 470 ERROR_HANDLE error_handle = error_create(condition_value);
AzureIoTClient 4:98007eb79fa8 471 if (error_handle == NULL)
AzureIoTClient 4:98007eb79fa8 472 {
AzureIoTClient 4:98007eb79fa8 473 /* Codes_SRS_CONNECTION_01_214: [If the close frame cannot be constructed or sent, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 474 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 475 {
AzureIoTClient 28:add19eb7defa 476 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 477 }
AzureIoTClient 24:2c59c2d43ebf 478
AzureIoTClient 28:add19eb7defa 479 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 480 }
AzureIoTClient 4:98007eb79fa8 481 else
AzureIoTClient 4:98007eb79fa8 482 {
AzureIoTClient 4:98007eb79fa8 483 /* Codes_SRS_CONNECTION_01_219: [The error description shall be set to an implementation defined string.] */
AzureIoTClient 28:add19eb7defa 484 if (error_set_description(error_handle, description) != 0)
AzureIoTClient 28:add19eb7defa 485 {
AzureIoTClient 28:add19eb7defa 486 LogError("Cannot set error description on CLOSE frame");
AzureIoTClient 24:2c59c2d43ebf 487
AzureIoTClient 28:add19eb7defa 488 /* Codes_SRS_CONNECTION_01_214: [If the close frame cannot be constructed or sent, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 489 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 490 {
AzureIoTClient 28:add19eb7defa 491 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 492 }
AzureIoTClient 24:2c59c2d43ebf 493
AzureIoTClient 28:add19eb7defa 494 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 28:add19eb7defa 495 }
AzureIoTClient 28:add19eb7defa 496 else if (send_close_frame(connection, error_handle) != 0)
AzureIoTClient 28:add19eb7defa 497 {
AzureIoTClient 28:add19eb7defa 498 LogError("Cannot send CLOSE frame");
AzureIoTClient 24:2c59c2d43ebf 499
AzureIoTClient 28:add19eb7defa 500 /* Codes_SRS_CONNECTION_01_214: [If the close frame cannot be constructed or sent, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 501 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 502 {
AzureIoTClient 28:add19eb7defa 503 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 504 }
AzureIoTClient 24:2c59c2d43ebf 505
AzureIoTClient 24:2c59c2d43ebf 506 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 507 }
AzureIoTClient 4:98007eb79fa8 508 else
AzureIoTClient 4:98007eb79fa8 509 {
AzureIoTClient 4:98007eb79fa8 510 /* Codes_SRS_CONNECTION_01_213: [When passing the bytes to frame_codec fails, a CLOSE frame shall be sent and the state shall be set to DISCARDING.] */
AzureIoTClient 4:98007eb79fa8 511 /* Codes_SRS_CONNECTION_01_055: [DISCARDING The DISCARDING state is a variant of the CLOSE SENT state where the close is triggered by an error.] */
AzureIoTClient 16:22a72cf8e416 512 /* Codes_SRS_CONNECTION_01_010: [After writing this frame the peer SHOULD continue to read from the connection until it receives the partner's close frame ] */
AzureIoTClient 24:2c59c2d43ebf 513 connection_set_state(connection, CONNECTION_STATE_DISCARDING);
AzureIoTClient 4:98007eb79fa8 514 }
Azure.IoT Build 0:6ae2f7bca550 515
AzureIoTClient 4:98007eb79fa8 516 error_destroy(error_handle);
AzureIoTClient 4:98007eb79fa8 517 }
Azure.IoT Build 0:6ae2f7bca550 518 }
Azure.IoT Build 0:6ae2f7bca550 519
AzureIoTClient 24:2c59c2d43ebf 520 static ENDPOINT_INSTANCE* find_session_endpoint_by_outgoing_channel(CONNECTION_HANDLE connection, uint16_t outgoing_channel)
Azure.IoT Build 0:6ae2f7bca550 521 {
AzureIoTClient 4:98007eb79fa8 522 uint32_t i;
AzureIoTClient 4:98007eb79fa8 523 ENDPOINT_INSTANCE* result;
Azure.IoT Build 0:6ae2f7bca550 524
AzureIoTClient 4:98007eb79fa8 525 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 526 {
AzureIoTClient 4:98007eb79fa8 527 if (connection->endpoints[i]->outgoing_channel == outgoing_channel)
AzureIoTClient 4:98007eb79fa8 528 {
AzureIoTClient 4:98007eb79fa8 529 break;
AzureIoTClient 4:98007eb79fa8 530 }
AzureIoTClient 4:98007eb79fa8 531 }
Azure.IoT Build 0:6ae2f7bca550 532
AzureIoTClient 4:98007eb79fa8 533 if (i == connection->endpoint_count)
AzureIoTClient 4:98007eb79fa8 534 {
AzureIoTClient 28:add19eb7defa 535 LogError("Cannot find session endpoint for channel %u", (unsigned int)outgoing_channel);
AzureIoTClient 28:add19eb7defa 536 result = NULL;
AzureIoTClient 4:98007eb79fa8 537 }
AzureIoTClient 4:98007eb79fa8 538 else
AzureIoTClient 4:98007eb79fa8 539 {
AzureIoTClient 4:98007eb79fa8 540 result = connection->endpoints[i];
AzureIoTClient 4:98007eb79fa8 541 }
Azure.IoT Build 0:6ae2f7bca550 542
AzureIoTClient 4:98007eb79fa8 543 return result;
Azure.IoT Build 0:6ae2f7bca550 544 }
Azure.IoT Build 0:6ae2f7bca550 545
AzureIoTClient 24:2c59c2d43ebf 546 static ENDPOINT_INSTANCE* find_session_endpoint_by_incoming_channel(CONNECTION_HANDLE connection, uint16_t incoming_channel)
Azure.IoT Build 0:6ae2f7bca550 547 {
AzureIoTClient 4:98007eb79fa8 548 uint32_t i;
AzureIoTClient 4:98007eb79fa8 549 ENDPOINT_INSTANCE* result;
Azure.IoT Build 0:6ae2f7bca550 550
AzureIoTClient 4:98007eb79fa8 551 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 552 {
AzureIoTClient 4:98007eb79fa8 553 if (connection->endpoints[i]->incoming_channel == incoming_channel)
AzureIoTClient 4:98007eb79fa8 554 {
AzureIoTClient 4:98007eb79fa8 555 break;
AzureIoTClient 4:98007eb79fa8 556 }
AzureIoTClient 4:98007eb79fa8 557 }
Azure.IoT Build 0:6ae2f7bca550 558
AzureIoTClient 4:98007eb79fa8 559 if (i == connection->endpoint_count)
AzureIoTClient 4:98007eb79fa8 560 {
AzureIoTClient 28:add19eb7defa 561 LogError("Cannot find session endpoint for channel %u", (unsigned int)incoming_channel);
AzureIoTClient 28:add19eb7defa 562 result = NULL;
AzureIoTClient 4:98007eb79fa8 563 }
AzureIoTClient 4:98007eb79fa8 564 else
AzureIoTClient 4:98007eb79fa8 565 {
AzureIoTClient 4:98007eb79fa8 566 result = connection->endpoints[i];
AzureIoTClient 4:98007eb79fa8 567 }
Azure.IoT Build 0:6ae2f7bca550 568
AzureIoTClient 4:98007eb79fa8 569 return result;
Azure.IoT Build 0:6ae2f7bca550 570 }
Azure.IoT Build 0:6ae2f7bca550 571
AzureIoTClient 24:2c59c2d43ebf 572 static int connection_byte_received(CONNECTION_HANDLE connection, unsigned char b)
Azure.IoT Build 0:6ae2f7bca550 573 {
AzureIoTClient 4:98007eb79fa8 574 int result;
Azure.IoT Build 0:6ae2f7bca550 575
AzureIoTClient 24:2c59c2d43ebf 576 switch (connection->connection_state)
AzureIoTClient 4:98007eb79fa8 577 {
AzureIoTClient 4:98007eb79fa8 578 default:
AzureIoTClient 28:add19eb7defa 579 LogError("Unknown connection state: %d", (int)connection->connection_state);
AzureIoTClient 28:add19eb7defa 580 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 581 break;
Azure.IoT Build 0:6ae2f7bca550 582
AzureIoTClient 4:98007eb79fa8 583 /* Codes_SRS_CONNECTION_01_039: [START In this state a connection exists, but nothing has been sent or received. This is the state an implementation would be in immediately after performing a socket connect or socket accept.] */
AzureIoTClient 4:98007eb79fa8 584 case CONNECTION_STATE_START:
Azure.IoT Build 0:6ae2f7bca550 585
AzureIoTClient 4:98007eb79fa8 586 /* Codes_SRS_CONNECTION_01_041: [HDR SENT In this state the connection header has been sent to the peer but no connection header has been received.] */
AzureIoTClient 4:98007eb79fa8 587 case CONNECTION_STATE_HDR_SENT:
AzureIoTClient 24:2c59c2d43ebf 588 if (b != amqp_header[connection->header_bytes_received])
AzureIoTClient 4:98007eb79fa8 589 {
AzureIoTClient 4:98007eb79fa8 590 /* Codes_SRS_CONNECTION_01_089: [If the incoming and outgoing protocol headers do not match, both peers MUST close their outgoing stream] */
AzureIoTClient 28:add19eb7defa 591 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 592 {
AzureIoTClient 28:add19eb7defa 593 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 594 }
AzureIoTClient 24:2c59c2d43ebf 595
AzureIoTClient 28:add19eb7defa 596 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 597 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 598 }
AzureIoTClient 4:98007eb79fa8 599 else
AzureIoTClient 4:98007eb79fa8 600 {
AzureIoTClient 28:add19eb7defa 601 connection->header_bytes_received++;
AzureIoTClient 24:2c59c2d43ebf 602 if (connection->header_bytes_received == sizeof(amqp_header))
AzureIoTClient 4:98007eb79fa8 603 {
AzureIoTClient 24:2c59c2d43ebf 604 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 605 {
AzureIoTClient 16:22a72cf8e416 606 LOG(AZ_LOG_TRACE, LOG_LINE, "<- Header (AMQP 0.1.0.0)");
AzureIoTClient 4:98007eb79fa8 607 }
Azure.IoT Build 0:6ae2f7bca550 608
AzureIoTClient 24:2c59c2d43ebf 609 connection_set_state(connection, CONNECTION_STATE_HDR_EXCH);
Azure.IoT Build 0:6ae2f7bca550 610
AzureIoTClient 24:2c59c2d43ebf 611 if (send_open_frame(connection) != 0)
AzureIoTClient 4:98007eb79fa8 612 {
AzureIoTClient 28:add19eb7defa 613 LogError("Cannot send open frame");
AzureIoTClient 28:add19eb7defa 614 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 615 }
AzureIoTClient 4:98007eb79fa8 616 }
Azure.IoT Build 0:6ae2f7bca550 617
AzureIoTClient 4:98007eb79fa8 618 result = 0;
AzureIoTClient 4:98007eb79fa8 619 }
AzureIoTClient 4:98007eb79fa8 620 break;
Azure.IoT Build 0:6ae2f7bca550 621
AzureIoTClient 4:98007eb79fa8 622 /* Codes_SRS_CONNECTION_01_040: [HDR RCVD In this state the connection header has been received from the peer but a connection header has not been sent.] */
AzureIoTClient 4:98007eb79fa8 623 case CONNECTION_STATE_HDR_RCVD:
Azure.IoT Build 0:6ae2f7bca550 624
AzureIoTClient 4:98007eb79fa8 625 /* Codes_SRS_CONNECTION_01_042: [HDR EXCH In this state the connection header has been sent to the peer and a connection header has been received from the peer.] */
AzureIoTClient 4:98007eb79fa8 626 /* we should not really get into this state, but just in case, we would treat that in the same way as HDR_RCVD */
AzureIoTClient 4:98007eb79fa8 627 case CONNECTION_STATE_HDR_EXCH:
Azure.IoT Build 0:6ae2f7bca550 628
AzureIoTClient 4:98007eb79fa8 629 /* Codes_SRS_CONNECTION_01_045: [OPEN RCVD In this state the connection headers have been exchanged. An open frame has been received from the peer but an open frame has not been sent.] */
AzureIoTClient 4:98007eb79fa8 630 case CONNECTION_STATE_OPEN_RCVD:
Azure.IoT Build 0:6ae2f7bca550 631
AzureIoTClient 4:98007eb79fa8 632 /* Codes_SRS_CONNECTION_01_046: [OPEN SENT In this state the connection headers have been exchanged. An open frame has been sent to the peer but no open frame has yet been received.] */
AzureIoTClient 4:98007eb79fa8 633 case CONNECTION_STATE_OPEN_SENT:
Azure.IoT Build 0:6ae2f7bca550 634
AzureIoTClient 4:98007eb79fa8 635 /* Codes_SRS_CONNECTION_01_048: [OPENED In this state the connection header and the open frame have been both sent and received.] */
AzureIoTClient 4:98007eb79fa8 636 case CONNECTION_STATE_OPENED:
AzureIoTClient 4:98007eb79fa8 637 /* Codes_SRS_CONNECTION_01_212: [After the initial handshake has been done all bytes received from the io instance shall be passed to the frame_codec for decoding by calling frame_codec_receive_bytes.] */
AzureIoTClient 24:2c59c2d43ebf 638 if (frame_codec_receive_bytes(connection->frame_codec, &b, 1) != 0)
AzureIoTClient 4:98007eb79fa8 639 {
AzureIoTClient 28:add19eb7defa 640 LogError("Cannot process received bytes");
AzureIoTClient 28:add19eb7defa 641 /* Codes_SRS_CONNECTION_01_218: [The error amqp:internal-error shall be set in the error.condition field of the CLOSE frame.] */
AzureIoTClient 4:98007eb79fa8 642 /* Codes_SRS_CONNECTION_01_219: [The error description shall be set to an implementation defined string.] */
AzureIoTClient 24:2c59c2d43ebf 643 close_connection_with_error(connection, "amqp:internal-error", "connection_byte_received::frame_codec_receive_bytes failed");
AzureIoTClient 19:000ab4e6a2c1 644 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 645 }
AzureIoTClient 4:98007eb79fa8 646 else
AzureIoTClient 4:98007eb79fa8 647 {
AzureIoTClient 4:98007eb79fa8 648 result = 0;
AzureIoTClient 4:98007eb79fa8 649 }
Azure.IoT Build 0:6ae2f7bca550 650
AzureIoTClient 4:98007eb79fa8 651 break;
AzureIoTClient 4:98007eb79fa8 652 }
AzureIoTClient 4:98007eb79fa8 653
AzureIoTClient 4:98007eb79fa8 654 return result;
Azure.IoT Build 0:6ae2f7bca550 655 }
Azure.IoT Build 0:6ae2f7bca550 656
Azure.IoT Build 0:6ae2f7bca550 657 static void connection_on_bytes_received(void* context, const unsigned char* buffer, size_t size)
Azure.IoT Build 0:6ae2f7bca550 658 {
AzureIoTClient 4:98007eb79fa8 659 size_t i;
Azure.IoT Build 0:6ae2f7bca550 660
AzureIoTClient 4:98007eb79fa8 661 for (i = 0; i < size; i++)
AzureIoTClient 4:98007eb79fa8 662 {
AzureIoTClient 24:2c59c2d43ebf 663 if (connection_byte_received((CONNECTION_HANDLE)context, buffer[i]) != 0)
AzureIoTClient 4:98007eb79fa8 664 {
AzureIoTClient 28:add19eb7defa 665 LogError("Cannot process received bytes");
AzureIoTClient 28:add19eb7defa 666 break;
AzureIoTClient 4:98007eb79fa8 667 }
AzureIoTClient 4:98007eb79fa8 668 }
Azure.IoT Build 0:6ae2f7bca550 669 }
Azure.IoT Build 0:6ae2f7bca550 670
Azure.IoT Build 0:6ae2f7bca550 671 static void connection_on_io_open_complete(void* context, IO_OPEN_RESULT io_open_result)
Azure.IoT Build 0:6ae2f7bca550 672 {
AzureIoTClient 24:2c59c2d43ebf 673 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
Azure.IoT Build 0:6ae2f7bca550 674
AzureIoTClient 4:98007eb79fa8 675 if (io_open_result == IO_OPEN_OK)
AzureIoTClient 4:98007eb79fa8 676 {
AzureIoTClient 4:98007eb79fa8 677 /* Codes_SRS_CONNECTION_01_084: [The connection_instance state machine implementing the protocol requirements shall be run as part of connection_dowork.] */
AzureIoTClient 24:2c59c2d43ebf 678 switch (connection->connection_state)
AzureIoTClient 4:98007eb79fa8 679 {
AzureIoTClient 4:98007eb79fa8 680 default:
AzureIoTClient 28:add19eb7defa 681 LogError("Unknown connection state: %d", (int)connection->connection_state);
AzureIoTClient 28:add19eb7defa 682 break;
Azure.IoT Build 0:6ae2f7bca550 683
AzureIoTClient 4:98007eb79fa8 684 case CONNECTION_STATE_START:
AzureIoTClient 4:98007eb79fa8 685 /* Codes_SRS_CONNECTION_01_086: [Prior to sending any frames on a connection_instance, each peer MUST start by sending a protocol header that indicates the protocol version used on the connection_instance.] */
AzureIoTClient 4:98007eb79fa8 686 /* Codes_SRS_CONNECTION_01_091: [The AMQP peer which acted in the role of the TCP client (i.e. the peer that actively opened the connection_instance) MUST immediately send its outgoing protocol header on establishment of the TCP connection_instance.] */
AzureIoTClient 28:add19eb7defa 687 if (send_header(connection) != 0)
AzureIoTClient 28:add19eb7defa 688 {
AzureIoTClient 28:add19eb7defa 689 LogError("Cannot send header");
AzureIoTClient 28:add19eb7defa 690 }
AzureIoTClient 4:98007eb79fa8 691 break;
Azure.IoT Build 0:6ae2f7bca550 692
AzureIoTClient 4:98007eb79fa8 693 case CONNECTION_STATE_HDR_SENT:
AzureIoTClient 4:98007eb79fa8 694 case CONNECTION_STATE_OPEN_SENT:
AzureIoTClient 4:98007eb79fa8 695 case CONNECTION_STATE_OPENED:
AzureIoTClient 4:98007eb79fa8 696 break;
Azure.IoT Build 0:6ae2f7bca550 697
AzureIoTClient 4:98007eb79fa8 698 case CONNECTION_STATE_HDR_EXCH:
AzureIoTClient 4:98007eb79fa8 699 /* Codes_SRS_CONNECTION_01_002: [Each AMQP connection_instance begins with an exchange of capabilities and limitations, including the maximum frame size.] */
AzureIoTClient 4:98007eb79fa8 700 /* Codes_SRS_CONNECTION_01_004: [After establishing or accepting a TCP connection_instance and sending the protocol header, each peer MUST send an open frame before sending any other frames.] */
AzureIoTClient 4:98007eb79fa8 701 /* Codes_SRS_CONNECTION_01_005: [The open frame describes the capabilities and limits of that peer.] */
AzureIoTClient 24:2c59c2d43ebf 702 if (send_open_frame(connection) != 0)
AzureIoTClient 4:98007eb79fa8 703 {
AzureIoTClient 28:add19eb7defa 704 LogError("Cannot send OPEN frame");
AzureIoTClient 28:add19eb7defa 705 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 706 }
AzureIoTClient 4:98007eb79fa8 707 break;
Azure.IoT Build 0:6ae2f7bca550 708
AzureIoTClient 4:98007eb79fa8 709 case CONNECTION_STATE_OPEN_RCVD:
AzureIoTClient 4:98007eb79fa8 710 break;
AzureIoTClient 4:98007eb79fa8 711 }
AzureIoTClient 4:98007eb79fa8 712 }
AzureIoTClient 4:98007eb79fa8 713 else
AzureIoTClient 4:98007eb79fa8 714 {
AzureIoTClient 24:2c59c2d43ebf 715 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 716 }
Azure.IoT Build 0:6ae2f7bca550 717 }
Azure.IoT Build 0:6ae2f7bca550 718
Azure.IoT Build 0:6ae2f7bca550 719 static void connection_on_io_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 720 {
AzureIoTClient 28:add19eb7defa 721 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
Azure.IoT Build 0:6ae2f7bca550 722
Azure.IoT Build 0:6ae2f7bca550 723 /* Codes_SRS_CONNECTION_22_005: [If the io notifies the connection instance of an IO_STATE_ERROR state and an io error callback is registered, the connection shall call the registered callback.] */
AzureIoTClient 24:2c59c2d43ebf 724 if (connection->on_io_error)
Azure.IoT Build 0:6ae2f7bca550 725 {
AzureIoTClient 28:add19eb7defa 726 connection->on_io_error(connection->on_io_error_callback_context);
Azure.IoT Build 0:6ae2f7bca550 727 }
Azure.IoT Build 0:6ae2f7bca550 728
AzureIoTClient 24:2c59c2d43ebf 729 if (connection->connection_state != CONNECTION_STATE_END)
AzureIoTClient 4:98007eb79fa8 730 {
AzureIoTClient 4:98007eb79fa8 731 /* Codes_SRS_CONNECTION_01_202: [If the io notifies the connection instance of an IO_STATE_ERROR state the connection shall be closed and the state set to END.] */
AzureIoTClient 24:2c59c2d43ebf 732 connection_set_state(connection, CONNECTION_STATE_ERROR);
AzureIoTClient 28:add19eb7defa 733 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 734 {
AzureIoTClient 28:add19eb7defa 735 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 736 }
AzureIoTClient 28:add19eb7defa 737 }
Azure.IoT Build 0:6ae2f7bca550 738 }
Azure.IoT Build 0:6ae2f7bca550 739
Azure.IoT Build 0:6ae2f7bca550 740 static void on_empty_amqp_frame_received(void* context, uint16_t channel)
Azure.IoT Build 0:6ae2f7bca550 741 {
AzureIoTClient 28:add19eb7defa 742 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
AzureIoTClient 28:add19eb7defa 743 /* It does not matter on which channel we received the frame */
AzureIoTClient 28:add19eb7defa 744 (void)channel;
AzureIoTClient 24:2c59c2d43ebf 745
AzureIoTClient 28:add19eb7defa 746 if (connection->is_trace_on == 1)
AzureIoTClient 6:641a9672db08 747 {
AzureIoTClient 16:22a72cf8e416 748 LOG(AZ_LOG_TRACE, LOG_LINE, "<- Empty frame");
AzureIoTClient 6:641a9672db08 749 }
AzureIoTClient 24:2c59c2d43ebf 750 if (tickcounter_get_current_ms(connection->tick_counter, &connection->last_frame_received_time) != 0)
AzureIoTClient 4:98007eb79fa8 751 {
AzureIoTClient 28:add19eb7defa 752 LogError("Cannot get tickcounter value");
AzureIoTClient 28:add19eb7defa 753 }
Azure.IoT Build 0:6ae2f7bca550 754 }
Azure.IoT Build 0:6ae2f7bca550 755
Azure.IoT Build 0:6ae2f7bca550 756 static void on_amqp_frame_received(void* context, uint16_t channel, AMQP_VALUE performative, const unsigned char* payload_bytes, uint32_t payload_size)
Azure.IoT Build 0:6ae2f7bca550 757 {
AzureIoTClient 24:2c59c2d43ebf 758 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
AzureIoTClient 24:2c59c2d43ebf 759
AzureIoTClient 28:add19eb7defa 760 (void)channel;
Azure.IoT Build 0:6ae2f7bca550 761
AzureIoTClient 24:2c59c2d43ebf 762 if (tickcounter_get_current_ms(connection->tick_counter, &connection->last_frame_received_time) != 0)
AzureIoTClient 4:98007eb79fa8 763 {
AzureIoTClient 28:add19eb7defa 764 LogError("Cannot get tickcounter value");
AzureIoTClient 28:add19eb7defa 765 close_connection_with_error(connection, "amqp:internal-error", "cannot get current tick count");
AzureIoTClient 4:98007eb79fa8 766 }
AzureIoTClient 4:98007eb79fa8 767 else
AzureIoTClient 4:98007eb79fa8 768 {
AzureIoTClient 24:2c59c2d43ebf 769 if (connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 770 {
AzureIoTClient 24:2c59c2d43ebf 771 switch (connection->connection_state)
AzureIoTClient 4:98007eb79fa8 772 {
AzureIoTClient 4:98007eb79fa8 773 default:
AzureIoTClient 4:98007eb79fa8 774 if (performative == NULL)
AzureIoTClient 4:98007eb79fa8 775 {
AzureIoTClient 28:add19eb7defa 776 /* Codes_SRS_CONNECTION_01_223: [If the on_endpoint_frame_received is called with a NULL performative then the connection shall be closed with the error condition amqp:internal-error and an implementation defined error description.] */
AzureIoTClient 24:2c59c2d43ebf 777 close_connection_with_error(connection, "amqp:internal-error", "connection_endpoint_frame_received::NULL performative");
AzureIoTClient 28:add19eb7defa 778 LogError("connection_endpoint_frame_received::NULL performative");
AzureIoTClient 28:add19eb7defa 779 }
AzureIoTClient 4:98007eb79fa8 780 else
AzureIoTClient 4:98007eb79fa8 781 {
AzureIoTClient 4:98007eb79fa8 782 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
AzureIoTClient 4:98007eb79fa8 783 uint64_t performative_ulong;
Azure.IoT Build 0:6ae2f7bca550 784
AzureIoTClient 24:2c59c2d43ebf 785 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 786 {
Azure.IoT Build 5:ae49385aff34 787 log_incoming_frame(performative);
AzureIoTClient 4:98007eb79fa8 788 }
Azure.IoT Build 0:6ae2f7bca550 789
AzureIoTClient 4:98007eb79fa8 790 if (is_open_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 791 {
AzureIoTClient 4:98007eb79fa8 792 if (channel != 0)
AzureIoTClient 4:98007eb79fa8 793 {
AzureIoTClient 28:add19eb7defa 794 /* Codes_SRS_CONNECTION_01_006: [The open frame can only be sent on channel 0.] */
AzureIoTClient 4:98007eb79fa8 795 /* Codes_SRS_CONNECTION_01_222: [If an Open frame is received in a manner violating the ISO specification, the connection shall be closed with condition amqp:not-allowed and description being an implementation defined string.] */
AzureIoTClient 24:2c59c2d43ebf 796 close_connection_with_error(connection, "amqp:not-allowed", "OPEN frame received on a channel that is not 0");
AzureIoTClient 28:add19eb7defa 797 LogError("OPEN frame received on a channel that is not 0");
AzureIoTClient 28:add19eb7defa 798 }
Azure.IoT Build 0:6ae2f7bca550 799
AzureIoTClient 24:2c59c2d43ebf 800 if (connection->connection_state == CONNECTION_STATE_OPENED)
AzureIoTClient 4:98007eb79fa8 801 {
AzureIoTClient 4:98007eb79fa8 802 /* Codes_SRS_CONNECTION_01_239: [If an Open frame is received in the Opened state the connection shall be closed with condition amqp:illegal-state and description being an implementation defined string.] */
AzureIoTClient 24:2c59c2d43ebf 803 close_connection_with_error(connection, "amqp:illegal-state", "OPEN frame received in the OPENED state");
AzureIoTClient 28:add19eb7defa 804 LogError("OPEN frame received in the OPENED state");
AzureIoTClient 28:add19eb7defa 805 }
AzureIoTClient 24:2c59c2d43ebf 806 else if ((connection->connection_state == CONNECTION_STATE_OPEN_SENT) ||
AzureIoTClient 24:2c59c2d43ebf 807 (connection->connection_state == CONNECTION_STATE_HDR_EXCH))
AzureIoTClient 4:98007eb79fa8 808 {
AzureIoTClient 4:98007eb79fa8 809 OPEN_HANDLE open_handle;
AzureIoTClient 4:98007eb79fa8 810 if (amqpvalue_get_open(performative, &open_handle) != 0)
AzureIoTClient 4:98007eb79fa8 811 {
AzureIoTClient 4:98007eb79fa8 812 /* Codes_SRS_CONNECTION_01_143: [If any of the values in the received open frame are invalid then the connection shall be closed.] */
AzureIoTClient 4:98007eb79fa8 813 /* Codes_SRS_CONNECTION_01_220: [The error amqp:invalid-field shall be set in the error.condition field of the CLOSE frame.] */
AzureIoTClient 24:2c59c2d43ebf 814 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing OPEN frame");
AzureIoTClient 28:add19eb7defa 815 LogError("connection_endpoint_frame_received::failed parsing OPEN frame");
AzureIoTClient 28:add19eb7defa 816 }
AzureIoTClient 4:98007eb79fa8 817 else
AzureIoTClient 4:98007eb79fa8 818 {
AzureIoTClient 24:2c59c2d43ebf 819 (void)open_get_idle_time_out(open_handle, &connection->remote_idle_timeout);
AzureIoTClient 24:2c59c2d43ebf 820 if ((open_get_max_frame_size(open_handle, &connection->remote_max_frame_size) != 0) ||
AzureIoTClient 4:98007eb79fa8 821 /* Codes_SRS_CONNECTION_01_167: [Both peers MUST accept frames of up to 512 (MIN-MAX-FRAME-SIZE) octets.] */
AzureIoTClient 24:2c59c2d43ebf 822 (connection->remote_max_frame_size < 512))
AzureIoTClient 4:98007eb79fa8 823 {
AzureIoTClient 4:98007eb79fa8 824 /* Codes_SRS_CONNECTION_01_143: [If any of the values in the received open frame are invalid then the connection shall be closed.] */
AzureIoTClient 4:98007eb79fa8 825 /* Codes_SRS_CONNECTION_01_220: [The error amqp:invalid-field shall be set in the error.condition field of the CLOSE frame.] */
AzureIoTClient 24:2c59c2d43ebf 826 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing OPEN frame");
AzureIoTClient 28:add19eb7defa 827 LogError("connection_endpoint_frame_received::failed parsing OPEN frame");
AzureIoTClient 28:add19eb7defa 828 }
AzureIoTClient 4:98007eb79fa8 829 else
AzureIoTClient 4:98007eb79fa8 830 {
AzureIoTClient 24:2c59c2d43ebf 831 if (connection->connection_state == CONNECTION_STATE_OPEN_SENT)
AzureIoTClient 4:98007eb79fa8 832 {
AzureIoTClient 24:2c59c2d43ebf 833 connection_set_state(connection, CONNECTION_STATE_OPENED);
AzureIoTClient 4:98007eb79fa8 834 }
AzureIoTClient 4:98007eb79fa8 835 else
AzureIoTClient 4:98007eb79fa8 836 {
AzureIoTClient 24:2c59c2d43ebf 837 if (send_open_frame(connection) != 0)
AzureIoTClient 4:98007eb79fa8 838 {
AzureIoTClient 24:2c59c2d43ebf 839 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 840 }
AzureIoTClient 4:98007eb79fa8 841 else
AzureIoTClient 4:98007eb79fa8 842 {
AzureIoTClient 24:2c59c2d43ebf 843 connection_set_state(connection, CONNECTION_STATE_OPENED);
AzureIoTClient 4:98007eb79fa8 844 }
AzureIoTClient 4:98007eb79fa8 845 }
AzureIoTClient 4:98007eb79fa8 846 }
Azure.IoT Build 0:6ae2f7bca550 847
AzureIoTClient 4:98007eb79fa8 848 open_destroy(open_handle);
AzureIoTClient 4:98007eb79fa8 849 }
AzureIoTClient 4:98007eb79fa8 850 }
AzureIoTClient 4:98007eb79fa8 851 else
AzureIoTClient 4:98007eb79fa8 852 {
AzureIoTClient 4:98007eb79fa8 853 /* do nothing for now ... */
AzureIoTClient 4:98007eb79fa8 854 }
AzureIoTClient 4:98007eb79fa8 855 }
AzureIoTClient 4:98007eb79fa8 856 else if (is_close_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 857 {
AzureIoTClient 4:98007eb79fa8 858 /* Codes_SRS_CONNECTION_01_012: [A close frame MAY be received on any channel up to the maximum channel number negotiated in open.] */
AzureIoTClient 4:98007eb79fa8 859 /* Codes_SRS_CONNECTION_01_242: [The connection module shall accept CLOSE frames even if they have extra payload bytes besides the Close performative.] */
Azure.IoT Build 0:6ae2f7bca550 860
AzureIoTClient 4:98007eb79fa8 861 /* Codes_SRS_CONNECTION_01_225: [HDR_RCVD HDR OPEN] */
AzureIoTClient 24:2c59c2d43ebf 862 if ((connection->connection_state == CONNECTION_STATE_HDR_RCVD) ||
AzureIoTClient 4:98007eb79fa8 863 /* Codes_SRS_CONNECTION_01_227: [HDR_EXCH OPEN OPEN] */
AzureIoTClient 24:2c59c2d43ebf 864 (connection->connection_state == CONNECTION_STATE_HDR_EXCH) ||
AzureIoTClient 4:98007eb79fa8 865 /* Codes_SRS_CONNECTION_01_228: [OPEN_RCVD OPEN *] */
AzureIoTClient 24:2c59c2d43ebf 866 (connection->connection_state == CONNECTION_STATE_OPEN_RCVD) ||
AzureIoTClient 4:98007eb79fa8 867 /* Codes_SRS_CONNECTION_01_235: [CLOSE_SENT - * TCP Close for Write] */
AzureIoTClient 24:2c59c2d43ebf 868 (connection->connection_state == CONNECTION_STATE_CLOSE_SENT) ||
AzureIoTClient 4:98007eb79fa8 869 /* Codes_SRS_CONNECTION_01_236: [DISCARDING - * TCP Close for Write] */
AzureIoTClient 24:2c59c2d43ebf 870 (connection->connection_state == CONNECTION_STATE_DISCARDING))
AzureIoTClient 4:98007eb79fa8 871 {
AzureIoTClient 28:add19eb7defa 872 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 873 {
AzureIoTClient 28:add19eb7defa 874 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 875 }
AzureIoTClient 28:add19eb7defa 876 }
AzureIoTClient 4:98007eb79fa8 877 else
AzureIoTClient 4:98007eb79fa8 878 {
AzureIoTClient 4:98007eb79fa8 879 CLOSE_HANDLE close_handle;
Azure.IoT Build 0:6ae2f7bca550 880
AzureIoTClient 4:98007eb79fa8 881 /* Codes_SRS_CONNECTION_01_012: [A close frame MAY be received on any channel up to the maximum channel number negotiated in open.] */
AzureIoTClient 24:2c59c2d43ebf 882 if (channel > connection->channel_max)
AzureIoTClient 4:98007eb79fa8 883 {
AzureIoTClient 24:2c59c2d43ebf 884 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing CLOSE frame");
AzureIoTClient 28:add19eb7defa 885 LogError("connection_endpoint_frame_received::failed parsing CLOSE frame");
AzureIoTClient 28:add19eb7defa 886 }
AzureIoTClient 4:98007eb79fa8 887 else
AzureIoTClient 4:98007eb79fa8 888 {
AzureIoTClient 4:98007eb79fa8 889 if (amqpvalue_get_close(performative, &close_handle) != 0)
AzureIoTClient 4:98007eb79fa8 890 {
AzureIoTClient 24:2c59c2d43ebf 891 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing CLOSE frame");
AzureIoTClient 28:add19eb7defa 892 LogError("connection_endpoint_frame_received::failed parsing CLOSE frame");
AzureIoTClient 28:add19eb7defa 893 }
AzureIoTClient 4:98007eb79fa8 894 else
AzureIoTClient 4:98007eb79fa8 895 {
AzureIoTClient 4:98007eb79fa8 896 close_destroy(close_handle);
Azure.IoT Build 0:6ae2f7bca550 897
AzureIoTClient 24:2c59c2d43ebf 898 connection_set_state(connection, CONNECTION_STATE_CLOSE_RCVD);
Azure.IoT Build 0:6ae2f7bca550 899
AzureIoTClient 28:add19eb7defa 900 if (send_close_frame(connection, NULL) != 0)
AzureIoTClient 28:add19eb7defa 901 {
AzureIoTClient 28:add19eb7defa 902 LogError("Cannot send CLOSE frame");
AzureIoTClient 28:add19eb7defa 903 }
AzureIoTClient 24:2c59c2d43ebf 904
AzureIoTClient 4:98007eb79fa8 905 /* Codes_SRS_CONNECTION_01_214: [If the close frame cannot be constructed or sent, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 906 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 907 {
AzureIoTClient 28:add19eb7defa 908 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 909 }
Azure.IoT Build 0:6ae2f7bca550 910
AzureIoTClient 24:2c59c2d43ebf 911 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 912 }
AzureIoTClient 4:98007eb79fa8 913 }
AzureIoTClient 4:98007eb79fa8 914 }
AzureIoTClient 4:98007eb79fa8 915 }
AzureIoTClient 4:98007eb79fa8 916 else
AzureIoTClient 4:98007eb79fa8 917 {
AzureIoTClient 4:98007eb79fa8 918 amqpvalue_get_ulong(descriptor, &performative_ulong);
Azure.IoT Build 0:6ae2f7bca550 919
AzureIoTClient 4:98007eb79fa8 920 switch (performative_ulong)
AzureIoTClient 4:98007eb79fa8 921 {
AzureIoTClient 4:98007eb79fa8 922 default:
AzureIoTClient 28:add19eb7defa 923 LogError("Bad performative: %02x", performative);
AzureIoTClient 4:98007eb79fa8 924 break;
Azure.IoT Build 0:6ae2f7bca550 925
AzureIoTClient 4:98007eb79fa8 926 case AMQP_BEGIN:
AzureIoTClient 4:98007eb79fa8 927 {
AzureIoTClient 4:98007eb79fa8 928 BEGIN_HANDLE begin;
Azure.IoT Build 0:6ae2f7bca550 929
AzureIoTClient 24:2c59c2d43ebf 930 if (amqpvalue_get_begin(performative, &begin) != 0)
AzureIoTClient 4:98007eb79fa8 931 {
AzureIoTClient 28:add19eb7defa 932 LogError("Cannot get begin performative");
AzureIoTClient 28:add19eb7defa 933 }
AzureIoTClient 4:98007eb79fa8 934 else
AzureIoTClient 4:98007eb79fa8 935 {
AzureIoTClient 4:98007eb79fa8 936 uint16_t remote_channel;
AzureIoTClient 4:98007eb79fa8 937 ENDPOINT_HANDLE new_endpoint = NULL;
AzureIoTClient 4:98007eb79fa8 938 bool remote_begin = false;
Azure.IoT Build 0:6ae2f7bca550 939
AzureIoTClient 4:98007eb79fa8 940 if (begin_get_remote_channel(begin, &remote_channel) != 0)
AzureIoTClient 4:98007eb79fa8 941 {
AzureIoTClient 28:add19eb7defa 942 remote_begin = true;
AzureIoTClient 24:2c59c2d43ebf 943 if (connection->on_new_endpoint != NULL)
AzureIoTClient 4:98007eb79fa8 944 {
AzureIoTClient 24:2c59c2d43ebf 945 new_endpoint = connection_create_endpoint(connection);
AzureIoTClient 24:2c59c2d43ebf 946 if (!connection->on_new_endpoint(connection->on_new_endpoint_callback_context, new_endpoint))
AzureIoTClient 4:98007eb79fa8 947 {
AzureIoTClient 4:98007eb79fa8 948 connection_destroy_endpoint(new_endpoint);
AzureIoTClient 4:98007eb79fa8 949 new_endpoint = NULL;
AzureIoTClient 4:98007eb79fa8 950 }
AzureIoTClient 4:98007eb79fa8 951 }
AzureIoTClient 4:98007eb79fa8 952 }
Azure.IoT Build 0:6ae2f7bca550 953
AzureIoTClient 4:98007eb79fa8 954 if (!remote_begin)
AzureIoTClient 4:98007eb79fa8 955 {
AzureIoTClient 24:2c59c2d43ebf 956 ENDPOINT_INSTANCE* session_endpoint = find_session_endpoint_by_outgoing_channel(connection, remote_channel);
AzureIoTClient 4:98007eb79fa8 957 if (session_endpoint == NULL)
AzureIoTClient 4:98007eb79fa8 958 {
AzureIoTClient 28:add19eb7defa 959 LogError("Cannot create session endpoint");
AzureIoTClient 28:add19eb7defa 960 }
AzureIoTClient 4:98007eb79fa8 961 else
AzureIoTClient 4:98007eb79fa8 962 {
AzureIoTClient 4:98007eb79fa8 963 session_endpoint->incoming_channel = channel;
AzureIoTClient 4:98007eb79fa8 964 session_endpoint->on_endpoint_frame_received(session_endpoint->callback_context, performative, payload_size, payload_bytes);
AzureIoTClient 4:98007eb79fa8 965 }
AzureIoTClient 4:98007eb79fa8 966 }
AzureIoTClient 4:98007eb79fa8 967 else
AzureIoTClient 4:98007eb79fa8 968 {
Azure.IoT Build 0:6ae2f7bca550 969 if (new_endpoint != NULL)
Azure.IoT Build 0:6ae2f7bca550 970 {
Azure.IoT Build 0:6ae2f7bca550 971 new_endpoint->incoming_channel = channel;
Azure.IoT Build 0:6ae2f7bca550 972 new_endpoint->on_endpoint_frame_received(new_endpoint->callback_context, performative, payload_size, payload_bytes);
Azure.IoT Build 0:6ae2f7bca550 973 }
AzureIoTClient 4:98007eb79fa8 974 }
Azure.IoT Build 0:6ae2f7bca550 975
AzureIoTClient 4:98007eb79fa8 976 begin_destroy(begin);
AzureIoTClient 4:98007eb79fa8 977 }
Azure.IoT Build 0:6ae2f7bca550 978
AzureIoTClient 4:98007eb79fa8 979 break;
AzureIoTClient 4:98007eb79fa8 980 }
Azure.IoT Build 0:6ae2f7bca550 981
AzureIoTClient 4:98007eb79fa8 982 case AMQP_FLOW:
AzureIoTClient 4:98007eb79fa8 983 case AMQP_TRANSFER:
AzureIoTClient 4:98007eb79fa8 984 case AMQP_DISPOSITION:
AzureIoTClient 4:98007eb79fa8 985 case AMQP_END:
AzureIoTClient 4:98007eb79fa8 986 case AMQP_ATTACH:
AzureIoTClient 4:98007eb79fa8 987 case AMQP_DETACH:
AzureIoTClient 4:98007eb79fa8 988 {
AzureIoTClient 24:2c59c2d43ebf 989 ENDPOINT_INSTANCE* session_endpoint = find_session_endpoint_by_incoming_channel(connection, channel);
AzureIoTClient 4:98007eb79fa8 990 if (session_endpoint == NULL)
AzureIoTClient 4:98007eb79fa8 991 {
AzureIoTClient 28:add19eb7defa 992 LogError("Cannot find session endpoint for channel %u", (unsigned int)channel);
AzureIoTClient 28:add19eb7defa 993 }
AzureIoTClient 4:98007eb79fa8 994 else
AzureIoTClient 4:98007eb79fa8 995 {
AzureIoTClient 4:98007eb79fa8 996 session_endpoint->on_endpoint_frame_received(session_endpoint->callback_context, performative, payload_size, payload_bytes);
AzureIoTClient 4:98007eb79fa8 997 }
Azure.IoT Build 0:6ae2f7bca550 998
AzureIoTClient 4:98007eb79fa8 999 break;
AzureIoTClient 4:98007eb79fa8 1000 }
AzureIoTClient 4:98007eb79fa8 1001 }
AzureIoTClient 4:98007eb79fa8 1002 }
AzureIoTClient 4:98007eb79fa8 1003 }
AzureIoTClient 4:98007eb79fa8 1004 break;
Azure.IoT Build 0:6ae2f7bca550 1005
AzureIoTClient 4:98007eb79fa8 1006 case CONNECTION_STATE_START:
AzureIoTClient 4:98007eb79fa8 1007 /* Codes_SRS_CONNECTION_01_224: [START HDR HDR] */
AzureIoTClient 4:98007eb79fa8 1008 case CONNECTION_STATE_HDR_SENT:
AzureIoTClient 4:98007eb79fa8 1009 /* Codes_SRS_CONNECTION_01_226: [HDR_SENT OPEN HDR] */
AzureIoTClient 4:98007eb79fa8 1010 case CONNECTION_STATE_OPEN_PIPE:
AzureIoTClient 4:98007eb79fa8 1011 /* Codes_SRS_CONNECTION_01_230: [OPEN_PIPE ** HDR] */
AzureIoTClient 4:98007eb79fa8 1012 case CONNECTION_STATE_OC_PIPE:
AzureIoTClient 4:98007eb79fa8 1013 /* Codes_SRS_CONNECTION_01_232: [OC_PIPE - HDR TCP Close for Write] */
AzureIoTClient 4:98007eb79fa8 1014 case CONNECTION_STATE_CLOSE_RCVD:
AzureIoTClient 4:98007eb79fa8 1015 /* Codes_SRS_CONNECTION_01_234: [CLOSE_RCVD * - TCP Close for Read] */
AzureIoTClient 4:98007eb79fa8 1016 case CONNECTION_STATE_END:
AzureIoTClient 4:98007eb79fa8 1017 /* Codes_SRS_CONNECTION_01_237: [END - - TCP Close] */
AzureIoTClient 28:add19eb7defa 1018 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 1019 {
AzureIoTClient 28:add19eb7defa 1020 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 1021 }
AzureIoTClient 28:add19eb7defa 1022 break;
AzureIoTClient 4:98007eb79fa8 1023 }
AzureIoTClient 4:98007eb79fa8 1024 }
AzureIoTClient 4:98007eb79fa8 1025 }
Azure.IoT Build 0:6ae2f7bca550 1026 }
Azure.IoT Build 0:6ae2f7bca550 1027
Azure.IoT Build 0:6ae2f7bca550 1028 static void frame_codec_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 1029 {
AzureIoTClient 6:641a9672db08 1030 /* Bug: some error handling should happen here
AzureIoTClient 6:641a9672db08 1031 Filed: uAMQP: frame_codec error and amqp_frame_codec_error should handle the errors */
AzureIoTClient 28:add19eb7defa 1032 LogError("A frame_codec_error occured");
AzureIoTClient 28:add19eb7defa 1033 (void)context;
Azure.IoT Build 0:6ae2f7bca550 1034 }
Azure.IoT Build 0:6ae2f7bca550 1035
Azure.IoT Build 0:6ae2f7bca550 1036 static void amqp_frame_codec_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 1037 {
AzureIoTClient 6:641a9672db08 1038 /* Bug: some error handling should happen here
AzureIoTClient 6:641a9672db08 1039 Filed: uAMQP: frame_codec error and amqp_frame_codec_error should handle the errors */
AzureIoTClient 28:add19eb7defa 1040 LogError("An amqp_frame_codec_error occured");
AzureIoTClient 28:add19eb7defa 1041 (void)context;
Azure.IoT Build 0:6ae2f7bca550 1042 }
Azure.IoT Build 0:6ae2f7bca550 1043
Azure.IoT Build 0:6ae2f7bca550 1044 /* Codes_SRS_CONNECTION_01_001: [connection_create shall open a new connection to a specified host/port.] */
Azure.IoT Build 0:6ae2f7bca550 1045 CONNECTION_HANDLE connection_create(XIO_HANDLE xio, const char* hostname, const char* container_id, ON_NEW_ENDPOINT on_new_endpoint, void* callback_context)
Azure.IoT Build 0:6ae2f7bca550 1046 {
Azure.IoT Build 5:ae49385aff34 1047 return connection_create2(xio, hostname, container_id, on_new_endpoint, callback_context, NULL, NULL, NULL, NULL);
Azure.IoT Build 0:6ae2f7bca550 1048 }
Azure.IoT Build 0:6ae2f7bca550 1049
Azure.IoT Build 0:6ae2f7bca550 1050 /* Codes_SRS_CONNECTION_01_001: [connection_create shall open a new connection to a specified host/port.] */
Azure.IoT Build 0:6ae2f7bca550 1051 /* Codes_SRS_CONNECTION_22_002: [connection_create shall allow registering connections state and io error callbacks.] */
Azure.IoT Build 5:ae49385aff34 1052 CONNECTION_HANDLE connection_create2(XIO_HANDLE xio, const char* hostname, const char* container_id, ON_NEW_ENDPOINT on_new_endpoint, void* callback_context, ON_CONNECTION_STATE_CHANGED on_connection_state_changed, void* on_connection_state_changed_context, ON_IO_ERROR on_io_error, void* on_io_error_context)
Azure.IoT Build 0:6ae2f7bca550 1053 {
AzureIoTClient 24:2c59c2d43ebf 1054 CONNECTION_HANDLE result;
Azure.IoT Build 0:6ae2f7bca550 1055
AzureIoTClient 4:98007eb79fa8 1056 if ((xio == NULL) ||
AzureIoTClient 4:98007eb79fa8 1057 (container_id == NULL))
AzureIoTClient 4:98007eb79fa8 1058 {
AzureIoTClient 4:98007eb79fa8 1059 /* Codes_SRS_CONNECTION_01_071: [If xio or container_id is NULL, connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1060 LogError("Bad arguments: xio = %p, container_id = %p",
AzureIoTClient 28:add19eb7defa 1061 xio, container_id);
AzureIoTClient 28:add19eb7defa 1062 result = NULL;
AzureIoTClient 4:98007eb79fa8 1063 }
AzureIoTClient 4:98007eb79fa8 1064 else
AzureIoTClient 4:98007eb79fa8 1065 {
AzureIoTClient 24:2c59c2d43ebf 1066 result = (CONNECTION_HANDLE)malloc(sizeof(CONNECTION_INSTANCE));
AzureIoTClient 4:98007eb79fa8 1067 /* Codes_SRS_CONNECTION_01_081: [If allocating the memory for the connection fails then connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1068 if (result == NULL)
AzureIoTClient 28:add19eb7defa 1069 {
AzureIoTClient 28:add19eb7defa 1070 LogError("Cannot allocate memory for connection");
AzureIoTClient 28:add19eb7defa 1071 }
AzureIoTClient 28:add19eb7defa 1072 else
AzureIoTClient 28:add19eb7defa 1073 {
AzureIoTClient 4:98007eb79fa8 1074 result->io = xio;
Azure.IoT Build 0:6ae2f7bca550 1075
AzureIoTClient 4:98007eb79fa8 1076 /* Codes_SRS_CONNECTION_01_082: [connection_create shall allocate a new frame_codec instance to be used for frame encoding/decoding.] */
Azure.IoT Build 5:ae49385aff34 1077 result->frame_codec = frame_codec_create(frame_codec_error, result);
AzureIoTClient 4:98007eb79fa8 1078 if (result->frame_codec == NULL)
AzureIoTClient 4:98007eb79fa8 1079 {
AzureIoTClient 4:98007eb79fa8 1080 /* Codes_SRS_CONNECTION_01_083: [If frame_codec_create fails then connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1081 LogError("Cannot create frame_codec");
AzureIoTClient 28:add19eb7defa 1082 free(result);
AzureIoTClient 4:98007eb79fa8 1083 result = NULL;
AzureIoTClient 4:98007eb79fa8 1084 }
AzureIoTClient 4:98007eb79fa8 1085 else
AzureIoTClient 4:98007eb79fa8 1086 {
AzureIoTClient 4:98007eb79fa8 1087 result->amqp_frame_codec = amqp_frame_codec_create(result->frame_codec, on_amqp_frame_received, on_empty_amqp_frame_received, amqp_frame_codec_error, result);
AzureIoTClient 4:98007eb79fa8 1088 if (result->amqp_frame_codec == NULL)
AzureIoTClient 4:98007eb79fa8 1089 {
AzureIoTClient 4:98007eb79fa8 1090 /* Codes_SRS_CONNECTION_01_108: [If amqp_frame_codec_create fails, connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1091 LogError("Cannot create amqp_frame_codec");
AzureIoTClient 28:add19eb7defa 1092 frame_codec_destroy(result->frame_codec);
AzureIoTClient 21:f9c433d8e6ca 1093 free(result);
AzureIoTClient 4:98007eb79fa8 1094 result = NULL;
AzureIoTClient 4:98007eb79fa8 1095 }
AzureIoTClient 4:98007eb79fa8 1096 else
AzureIoTClient 4:98007eb79fa8 1097 {
AzureIoTClient 4:98007eb79fa8 1098 if (hostname != NULL)
AzureIoTClient 4:98007eb79fa8 1099 {
AzureIoTClient 23:1111ee8bcba4 1100 size_t hostname_length = strlen(hostname);
AzureIoTClient 23:1111ee8bcba4 1101 result->host_name = (char*)malloc(hostname_length + 1);
AzureIoTClient 4:98007eb79fa8 1102 if (result->host_name == NULL)
AzureIoTClient 4:98007eb79fa8 1103 {
AzureIoTClient 4:98007eb79fa8 1104 /* Codes_SRS_CONNECTION_01_081: [If allocating the memory for the connection fails then connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1105 LogError("Cannot allocate memory for host name");
AzureIoTClient 28:add19eb7defa 1106 amqp_frame_codec_destroy(result->amqp_frame_codec);
AzureIoTClient 4:98007eb79fa8 1107 frame_codec_destroy(result->frame_codec);
AzureIoTClient 21:f9c433d8e6ca 1108 free(result);
AzureIoTClient 4:98007eb79fa8 1109 result = NULL;
AzureIoTClient 4:98007eb79fa8 1110 }
AzureIoTClient 4:98007eb79fa8 1111 else
AzureIoTClient 4:98007eb79fa8 1112 {
AzureIoTClient 23:1111ee8bcba4 1113 (void)memcpy(result->host_name, hostname, hostname_length + 1);
AzureIoTClient 4:98007eb79fa8 1114 }
AzureIoTClient 4:98007eb79fa8 1115 }
AzureIoTClient 4:98007eb79fa8 1116 else
AzureIoTClient 4:98007eb79fa8 1117 {
AzureIoTClient 4:98007eb79fa8 1118 result->host_name = NULL;
AzureIoTClient 4:98007eb79fa8 1119 }
Azure.IoT Build 0:6ae2f7bca550 1120
AzureIoTClient 4:98007eb79fa8 1121 if (result != NULL)
AzureIoTClient 4:98007eb79fa8 1122 {
AzureIoTClient 23:1111ee8bcba4 1123 size_t container_id_length = strlen(container_id);
AzureIoTClient 23:1111ee8bcba4 1124 result->container_id = (char*)malloc(container_id_length + 1);
AzureIoTClient 4:98007eb79fa8 1125 if (result->container_id == NULL)
AzureIoTClient 4:98007eb79fa8 1126 {
AzureIoTClient 4:98007eb79fa8 1127 /* Codes_SRS_CONNECTION_01_081: [If allocating the memory for the connection fails then connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1128 LogError("Cannot allocate memory for container_id");
AzureIoTClient 28:add19eb7defa 1129 free(result->host_name);
AzureIoTClient 4:98007eb79fa8 1130 amqp_frame_codec_destroy(result->amqp_frame_codec);
AzureIoTClient 4:98007eb79fa8 1131 frame_codec_destroy(result->frame_codec);
AzureIoTClient 21:f9c433d8e6ca 1132 free(result);
AzureIoTClient 4:98007eb79fa8 1133 result = NULL;
AzureIoTClient 4:98007eb79fa8 1134 }
AzureIoTClient 4:98007eb79fa8 1135 else
AzureIoTClient 4:98007eb79fa8 1136 {
AzureIoTClient 4:98007eb79fa8 1137 result->tick_counter = tickcounter_create();
AzureIoTClient 4:98007eb79fa8 1138 if (result->tick_counter == NULL)
AzureIoTClient 4:98007eb79fa8 1139 {
AzureIoTClient 28:add19eb7defa 1140 LogError("Cannot create tick counter");
AzureIoTClient 28:add19eb7defa 1141 free(result->container_id);
AzureIoTClient 21:f9c433d8e6ca 1142 free(result->host_name);
AzureIoTClient 4:98007eb79fa8 1143 amqp_frame_codec_destroy(result->amqp_frame_codec);
AzureIoTClient 4:98007eb79fa8 1144 frame_codec_destroy(result->frame_codec);
AzureIoTClient 21:f9c433d8e6ca 1145 free(result);
AzureIoTClient 4:98007eb79fa8 1146 result = NULL;
AzureIoTClient 4:98007eb79fa8 1147 }
AzureIoTClient 4:98007eb79fa8 1148 else
AzureIoTClient 4:98007eb79fa8 1149 {
AzureIoTClient 23:1111ee8bcba4 1150 (void)memcpy(result->container_id, container_id, container_id_length + 1);
Azure.IoT Build 0:6ae2f7bca550 1151
AzureIoTClient 4:98007eb79fa8 1152 /* Codes_SRS_CONNECTION_01_173: [<field name="max-frame-size" type="uint" default="4294967295"/>] */
AzureIoTClient 4:98007eb79fa8 1153 result->max_frame_size = 4294967295u;
AzureIoTClient 4:98007eb79fa8 1154 /* Codes: [<field name="channel-max" type="ushort" default="65535"/>] */
AzureIoTClient 4:98007eb79fa8 1155 result->channel_max = 65535;
Azure.IoT Build 0:6ae2f7bca550 1156
AzureIoTClient 4:98007eb79fa8 1157 /* Codes_SRS_CONNECTION_01_175: [<field name="idle-time-out" type="milliseconds"/>] */
AzureIoTClient 4:98007eb79fa8 1158 /* Codes_SRS_CONNECTION_01_192: [A value of zero is the same as if it was not set (null).] */
AzureIoTClient 4:98007eb79fa8 1159 result->idle_timeout = 0;
AzureIoTClient 4:98007eb79fa8 1160 result->remote_idle_timeout = 0;
Azure.IoT Build 0:6ae2f7bca550 1161
AzureIoTClient 4:98007eb79fa8 1162 result->endpoint_count = 0;
AzureIoTClient 4:98007eb79fa8 1163 result->endpoints = NULL;
AzureIoTClient 4:98007eb79fa8 1164 result->header_bytes_received = 0;
AzureIoTClient 4:98007eb79fa8 1165 result->is_remote_frame_received = 0;
Azure.IoT Build 0:6ae2f7bca550 1166
AzureIoTClient 4:98007eb79fa8 1167 result->is_underlying_io_open = 0;
AzureIoTClient 4:98007eb79fa8 1168 result->remote_max_frame_size = 512;
AzureIoTClient 4:98007eb79fa8 1169 result->is_trace_on = 0;
Azure.IoT Build 0:6ae2f7bca550 1170
AzureIoTClient 4:98007eb79fa8 1171 /* Mark that settings have not yet been set by the user */
AzureIoTClient 4:98007eb79fa8 1172 result->idle_timeout_specified = 0;
Azure.IoT Build 0:6ae2f7bca550 1173
AzureIoTClient 4:98007eb79fa8 1174 result->on_new_endpoint = on_new_endpoint;
AzureIoTClient 4:98007eb79fa8 1175 result->on_new_endpoint_callback_context = callback_context;
Azure.IoT Build 0:6ae2f7bca550 1176
Azure.IoT Build 0:6ae2f7bca550 1177 result->on_io_error = on_io_error;
Azure.IoT Build 0:6ae2f7bca550 1178 result->on_io_error_callback_context = on_io_error_context;
Azure.IoT Build 0:6ae2f7bca550 1179 result->on_connection_state_changed = on_connection_state_changed;
Azure.IoT Build 0:6ae2f7bca550 1180 result->on_connection_state_changed_callback_context = on_connection_state_changed_context;
Azure.IoT Build 0:6ae2f7bca550 1181
AzureIoTClient 20:206846c14c80 1182 if (tickcounter_get_current_ms(result->tick_counter, &result->last_frame_received_time) != 0)
AzureIoTClient 20:206846c14c80 1183 {
AzureIoTClient 20:206846c14c80 1184 LogError("Could not retrieve time for last frame received time");
AzureIoTClient 20:206846c14c80 1185 tickcounter_destroy(result->tick_counter);
AzureIoTClient 21:f9c433d8e6ca 1186 free(result->container_id);
AzureIoTClient 21:f9c433d8e6ca 1187 free(result->host_name);
AzureIoTClient 20:206846c14c80 1188 amqp_frame_codec_destroy(result->amqp_frame_codec);
AzureIoTClient 20:206846c14c80 1189 frame_codec_destroy(result->frame_codec);
AzureIoTClient 21:f9c433d8e6ca 1190 free(result);
AzureIoTClient 20:206846c14c80 1191 result = NULL;
AzureIoTClient 20:206846c14c80 1192 }
AzureIoTClient 20:206846c14c80 1193 else
AzureIoTClient 20:206846c14c80 1194 {
AzureIoTClient 20:206846c14c80 1195 result->last_frame_sent_time = result->last_frame_received_time;
AzureIoTClient 20:206846c14c80 1196
AzureIoTClient 20:206846c14c80 1197 /* Codes_SRS_CONNECTION_01_072: [When connection_create succeeds, the state of the connection shall be CONNECTION_STATE_START.] */
AzureIoTClient 20:206846c14c80 1198 connection_set_state(result, CONNECTION_STATE_START);
AzureIoTClient 20:206846c14c80 1199 }
AzureIoTClient 4:98007eb79fa8 1200 }
AzureIoTClient 4:98007eb79fa8 1201 }
AzureIoTClient 4:98007eb79fa8 1202 }
AzureIoTClient 4:98007eb79fa8 1203 }
AzureIoTClient 4:98007eb79fa8 1204 }
AzureIoTClient 4:98007eb79fa8 1205 }
AzureIoTClient 4:98007eb79fa8 1206 }
Azure.IoT Build 0:6ae2f7bca550 1207
AzureIoTClient 4:98007eb79fa8 1208 return result;
Azure.IoT Build 0:6ae2f7bca550 1209 }
Azure.IoT Build 0:6ae2f7bca550 1210
Azure.IoT Build 0:6ae2f7bca550 1211 void connection_destroy(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1212 {
AzureIoTClient 4:98007eb79fa8 1213 /* Codes_SRS_CONNECTION_01_079: [If handle is NULL, connection_destroy shall do nothing.] */
AzureIoTClient 28:add19eb7defa 1214 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1215 {
AzureIoTClient 28:add19eb7defa 1216 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1217 }
AzureIoTClient 28:add19eb7defa 1218 else
AzureIoTClient 28:add19eb7defa 1219 {
AzureIoTClient 4:98007eb79fa8 1220 /* Codes_SRS_CONNECTION_01_073: [connection_destroy shall free all resources associated with a connection.] */
AzureIoTClient 4:98007eb79fa8 1221 if (connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 1222 {
AzureIoTClient 24:2c59c2d43ebf 1223 (void)connection_close(connection, NULL, NULL);
AzureIoTClient 4:98007eb79fa8 1224 }
Azure.IoT Build 0:6ae2f7bca550 1225
AzureIoTClient 4:98007eb79fa8 1226 amqp_frame_codec_destroy(connection->amqp_frame_codec);
AzureIoTClient 4:98007eb79fa8 1227 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 4:98007eb79fa8 1228 tickcounter_destroy(connection->tick_counter);
Azure.IoT Build 0:6ae2f7bca550 1229
AzureIoTClient 21:f9c433d8e6ca 1230 free(connection->host_name);
AzureIoTClient 21:f9c433d8e6ca 1231 free(connection->container_id);
Azure.IoT Build 0:6ae2f7bca550 1232
AzureIoTClient 4:98007eb79fa8 1233 /* Codes_SRS_CONNECTION_01_074: [connection_destroy shall close the socket connection.] */
AzureIoTClient 21:f9c433d8e6ca 1234 free(connection);
AzureIoTClient 4:98007eb79fa8 1235 }
Azure.IoT Build 0:6ae2f7bca550 1236 }
Azure.IoT Build 0:6ae2f7bca550 1237
Azure.IoT Build 0:6ae2f7bca550 1238 int connection_open(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1239 {
AzureIoTClient 4:98007eb79fa8 1240 int result;
Azure.IoT Build 0:6ae2f7bca550 1241
AzureIoTClient 4:98007eb79fa8 1242 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1243 {
AzureIoTClient 28:add19eb7defa 1244 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1245 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1246 }
AzureIoTClient 4:98007eb79fa8 1247 else
AzureIoTClient 4:98007eb79fa8 1248 {
AzureIoTClient 4:98007eb79fa8 1249 if (!connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 1250 {
AzureIoTClient 4:98007eb79fa8 1251 if (xio_open(connection->io, connection_on_io_open_complete, connection, connection_on_bytes_received, connection, connection_on_io_error, connection) != 0)
AzureIoTClient 4:98007eb79fa8 1252 {
AzureIoTClient 28:add19eb7defa 1253 LogError("Opening the underlying IO failed");
AzureIoTClient 28:add19eb7defa 1254 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 1255 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1256 }
AzureIoTClient 4:98007eb79fa8 1257 else
AzureIoTClient 4:98007eb79fa8 1258 {
AzureIoTClient 4:98007eb79fa8 1259 connection->is_underlying_io_open = 1;
Azure.IoT Build 0:6ae2f7bca550 1260
AzureIoTClient 4:98007eb79fa8 1261 connection_set_state(connection, CONNECTION_STATE_START);
Azure.IoT Build 0:6ae2f7bca550 1262
AzureIoTClient 4:98007eb79fa8 1263 result = 0;
AzureIoTClient 4:98007eb79fa8 1264 }
AzureIoTClient 4:98007eb79fa8 1265 }
AzureIoTClient 4:98007eb79fa8 1266 else
AzureIoTClient 4:98007eb79fa8 1267 {
AzureIoTClient 4:98007eb79fa8 1268 result = 0;
AzureIoTClient 4:98007eb79fa8 1269 }
AzureIoTClient 4:98007eb79fa8 1270 }
Azure.IoT Build 0:6ae2f7bca550 1271
AzureIoTClient 4:98007eb79fa8 1272 return result;
Azure.IoT Build 0:6ae2f7bca550 1273 }
Azure.IoT Build 0:6ae2f7bca550 1274
Azure.IoT Build 0:6ae2f7bca550 1275 int connection_listen(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1276 {
AzureIoTClient 4:98007eb79fa8 1277 int result;
Azure.IoT Build 0:6ae2f7bca550 1278
AzureIoTClient 4:98007eb79fa8 1279 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1280 {
AzureIoTClient 28:add19eb7defa 1281 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1282 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1283 }
AzureIoTClient 4:98007eb79fa8 1284 else
AzureIoTClient 4:98007eb79fa8 1285 {
AzureIoTClient 4:98007eb79fa8 1286 if (!connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 1287 {
AzureIoTClient 4:98007eb79fa8 1288 if (xio_open(connection->io, connection_on_io_open_complete, connection, connection_on_bytes_received, connection, connection_on_io_error, connection) != 0)
AzureIoTClient 4:98007eb79fa8 1289 {
AzureIoTClient 28:add19eb7defa 1290 LogError("Opening the underlying IO failed");
AzureIoTClient 28:add19eb7defa 1291 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 1292 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1293 }
AzureIoTClient 4:98007eb79fa8 1294 else
AzureIoTClient 4:98007eb79fa8 1295 {
AzureIoTClient 4:98007eb79fa8 1296 connection->is_underlying_io_open = 1;
Azure.IoT Build 0:6ae2f7bca550 1297
AzureIoTClient 4:98007eb79fa8 1298 connection_set_state(connection, CONNECTION_STATE_HDR_EXCH);
Azure.IoT Build 0:6ae2f7bca550 1299
AzureIoTClient 4:98007eb79fa8 1300 result = 0;
AzureIoTClient 4:98007eb79fa8 1301 }
AzureIoTClient 4:98007eb79fa8 1302 }
AzureIoTClient 4:98007eb79fa8 1303 else
AzureIoTClient 4:98007eb79fa8 1304 {
AzureIoTClient 4:98007eb79fa8 1305 result = 0;
AzureIoTClient 4:98007eb79fa8 1306 }
AzureIoTClient 4:98007eb79fa8 1307 }
Azure.IoT Build 0:6ae2f7bca550 1308
AzureIoTClient 4:98007eb79fa8 1309 return result;
Azure.IoT Build 0:6ae2f7bca550 1310 }
Azure.IoT Build 0:6ae2f7bca550 1311
Azure.IoT Build 0:6ae2f7bca550 1312 int connection_close(CONNECTION_HANDLE connection, const char* condition_value, const char* description)
Azure.IoT Build 0:6ae2f7bca550 1313 {
AzureIoTClient 4:98007eb79fa8 1314 int result;
Azure.IoT Build 0:6ae2f7bca550 1315
AzureIoTClient 4:98007eb79fa8 1316 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1317 {
AzureIoTClient 28:add19eb7defa 1318 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1319 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1320 }
AzureIoTClient 4:98007eb79fa8 1321 else
AzureIoTClient 4:98007eb79fa8 1322 {
AzureIoTClient 4:98007eb79fa8 1323 if (condition_value != NULL)
AzureIoTClient 4:98007eb79fa8 1324 {
AzureIoTClient 4:98007eb79fa8 1325 close_connection_with_error(connection, condition_value, description);
AzureIoTClient 4:98007eb79fa8 1326 }
AzureIoTClient 4:98007eb79fa8 1327 else
AzureIoTClient 4:98007eb79fa8 1328 {
AzureIoTClient 28:add19eb7defa 1329 if (send_close_frame(connection, NULL) != 0)
AzureIoTClient 28:add19eb7defa 1330 {
AzureIoTClient 28:add19eb7defa 1331 LogError("Sending CLOSE frame failed");
AzureIoTClient 28:add19eb7defa 1332 }
AzureIoTClient 24:2c59c2d43ebf 1333
AzureIoTClient 4:98007eb79fa8 1334 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 1335 }
Azure.IoT Build 0:6ae2f7bca550 1336
AzureIoTClient 28:add19eb7defa 1337 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 1338 {
AzureIoTClient 28:add19eb7defa 1339 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 1340 }
AzureIoTClient 24:2c59c2d43ebf 1341
AzureIoTClient 28:add19eb7defa 1342 connection->is_underlying_io_open = 1;
Azure.IoT Build 0:6ae2f7bca550 1343
Azure.IoT Build 0:6ae2f7bca550 1344 result = 0;
AzureIoTClient 4:98007eb79fa8 1345 }
Azure.IoT Build 0:6ae2f7bca550 1346
AzureIoTClient 4:98007eb79fa8 1347 return result;
Azure.IoT Build 0:6ae2f7bca550 1348 }
Azure.IoT Build 0:6ae2f7bca550 1349
Azure.IoT Build 0:6ae2f7bca550 1350 int connection_set_max_frame_size(CONNECTION_HANDLE connection, uint32_t max_frame_size)
Azure.IoT Build 0:6ae2f7bca550 1351 {
AzureIoTClient 4:98007eb79fa8 1352 int result;
Azure.IoT Build 0:6ae2f7bca550 1353
AzureIoTClient 4:98007eb79fa8 1354 /* Codes_SRS_CONNECTION_01_163: [If connection is NULL, connection_set_max_frame_size shall fail and return a non-zero value.] */
AzureIoTClient 28:add19eb7defa 1355 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1356 {
AzureIoTClient 28:add19eb7defa 1357 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1358 result = __FAILURE__;
AzureIoTClient 28:add19eb7defa 1359 }
AzureIoTClient 28:add19eb7defa 1360 /* Codes_SRS_CONNECTION_01_150: [If the max_frame_size is invalid then connection_set_max_frame_size shall fail and return a non-zero value.] */
AzureIoTClient 28:add19eb7defa 1361 /* Codes_SRS_CONNECTION_01_167: [Both peers MUST accept frames of up to 512 (MIN-MAX-FRAME-SIZE) octets.] */
AzureIoTClient 28:add19eb7defa 1362 else if (max_frame_size < 512)
AzureIoTClient 28:add19eb7defa 1363 {
AzureIoTClient 28:add19eb7defa 1364 LogError("max_frame_size too small");
AzureIoTClient 28:add19eb7defa 1365 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1366 }
AzureIoTClient 4:98007eb79fa8 1367 else
AzureIoTClient 4:98007eb79fa8 1368 {
AzureIoTClient 4:98007eb79fa8 1369 /* Codes_SRS_CONNECTION_01_157: [If connection_set_max_frame_size is called after the initial Open frame has been sent, it shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1370 if (connection->connection_state != CONNECTION_STATE_START)
AzureIoTClient 4:98007eb79fa8 1371 {
AzureIoTClient 28:add19eb7defa 1372 LogError("Connection already open");
AzureIoTClient 28:add19eb7defa 1373 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1374 }
AzureIoTClient 4:98007eb79fa8 1375 else
AzureIoTClient 4:98007eb79fa8 1376 {
AzureIoTClient 4:98007eb79fa8 1377 /* Codes_SRS_CONNECTION_01_148: [connection_set_max_frame_size shall set the max_frame_size associated with a connection.] */
AzureIoTClient 4:98007eb79fa8 1378 /* Codes_SRS_CONNECTION_01_164: [If connection_set_max_frame_size fails, the previous max_frame_size setting shall be retained.] */
AzureIoTClient 4:98007eb79fa8 1379 connection->max_frame_size = max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 1380
AzureIoTClient 4:98007eb79fa8 1381 /* Codes_SRS_CONNECTION_01_149: [On success connection_set_max_frame_size shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1382 result = 0;
AzureIoTClient 4:98007eb79fa8 1383 }
AzureIoTClient 4:98007eb79fa8 1384 }
Azure.IoT Build 0:6ae2f7bca550 1385
AzureIoTClient 4:98007eb79fa8 1386 return result;
Azure.IoT Build 0:6ae2f7bca550 1387 }
Azure.IoT Build 0:6ae2f7bca550 1388
Azure.IoT Build 0:6ae2f7bca550 1389 int connection_get_max_frame_size(CONNECTION_HANDLE connection, uint32_t* max_frame_size)
Azure.IoT Build 0:6ae2f7bca550 1390 {
AzureIoTClient 4:98007eb79fa8 1391 int result;
Azure.IoT Build 0:6ae2f7bca550 1392
AzureIoTClient 4:98007eb79fa8 1393 /* Codes_SRS_CONNECTION_01_170: [If connection or max_frame_size is NULL, connection_get_max_frame_size shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1394 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1395 (max_frame_size == NULL))
AzureIoTClient 4:98007eb79fa8 1396 {
AzureIoTClient 28:add19eb7defa 1397 LogError("Bad arguments: connection = %p, max_frame_size = %p",
AzureIoTClient 28:add19eb7defa 1398 connection, max_frame_size);
AzureIoTClient 28:add19eb7defa 1399 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1400 }
AzureIoTClient 4:98007eb79fa8 1401 else
AzureIoTClient 4:98007eb79fa8 1402 {
AzureIoTClient 4:98007eb79fa8 1403 /* Codes_SRS_CONNECTION_01_168: [connection_get_max_frame_size shall return in the max_frame_size argument the current max frame size setting.] */
AzureIoTClient 4:98007eb79fa8 1404 *max_frame_size = connection->max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 1405
AzureIoTClient 4:98007eb79fa8 1406 /* Codes_SRS_CONNECTION_01_169: [On success, connection_get_max_frame_size shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1407 result = 0;
AzureIoTClient 4:98007eb79fa8 1408 }
Azure.IoT Build 0:6ae2f7bca550 1409
AzureIoTClient 4:98007eb79fa8 1410 return result;
Azure.IoT Build 0:6ae2f7bca550 1411 }
Azure.IoT Build 0:6ae2f7bca550 1412
Azure.IoT Build 0:6ae2f7bca550 1413 int connection_set_channel_max(CONNECTION_HANDLE connection, uint16_t channel_max)
Azure.IoT Build 0:6ae2f7bca550 1414 {
AzureIoTClient 4:98007eb79fa8 1415 int result;
Azure.IoT Build 0:6ae2f7bca550 1416
AzureIoTClient 4:98007eb79fa8 1417 /* Codes_SRS_CONNECTION_01_181: [If connection is NULL then connection_set_channel_max shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1418 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1419 {
AzureIoTClient 28:add19eb7defa 1420 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1421 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1422 }
AzureIoTClient 4:98007eb79fa8 1423 else
AzureIoTClient 4:98007eb79fa8 1424 {
AzureIoTClient 4:98007eb79fa8 1425 /* Codes_SRS_CONNECTION_01_156: [If connection_set_channel_max is called after the initial Open frame has been sent, it shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1426 if (connection->connection_state != CONNECTION_STATE_START)
AzureIoTClient 4:98007eb79fa8 1427 {
AzureIoTClient 28:add19eb7defa 1428 LogError("Connection already open");
AzureIoTClient 28:add19eb7defa 1429 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1430 }
AzureIoTClient 4:98007eb79fa8 1431 else
AzureIoTClient 4:98007eb79fa8 1432 {
AzureIoTClient 4:98007eb79fa8 1433 /* Codes_SRS_CONNECTION_01_153: [connection_set_channel_max shall set the channel_max associated with a connection.] */
AzureIoTClient 4:98007eb79fa8 1434 /* Codes_SRS_CONNECTION_01_165: [If connection_set_channel_max fails, the previous channel_max setting shall be retained.] */
AzureIoTClient 4:98007eb79fa8 1435 connection->channel_max = channel_max;
Azure.IoT Build 0:6ae2f7bca550 1436
AzureIoTClient 4:98007eb79fa8 1437 /* Codes_SRS_CONNECTION_01_154: [On success connection_set_channel_max shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1438 result = 0;
AzureIoTClient 4:98007eb79fa8 1439 }
AzureIoTClient 4:98007eb79fa8 1440 }
Azure.IoT Build 0:6ae2f7bca550 1441
AzureIoTClient 4:98007eb79fa8 1442 return result;
Azure.IoT Build 0:6ae2f7bca550 1443 }
Azure.IoT Build 0:6ae2f7bca550 1444
Azure.IoT Build 0:6ae2f7bca550 1445 int connection_get_channel_max(CONNECTION_HANDLE connection, uint16_t* channel_max)
Azure.IoT Build 0:6ae2f7bca550 1446 {
AzureIoTClient 4:98007eb79fa8 1447 int result;
Azure.IoT Build 0:6ae2f7bca550 1448
AzureIoTClient 4:98007eb79fa8 1449 /* Codes_SRS_CONNECTION_01_184: [If connection or channel_max is NULL, connection_get_channel_max shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1450 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1451 (channel_max == NULL))
AzureIoTClient 4:98007eb79fa8 1452 {
AzureIoTClient 28:add19eb7defa 1453 LogError("Bad arguments: connection = %p, channel_max = %p",
AzureIoTClient 28:add19eb7defa 1454 connection, channel_max);
AzureIoTClient 28:add19eb7defa 1455 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1456 }
AzureIoTClient 4:98007eb79fa8 1457 else
AzureIoTClient 4:98007eb79fa8 1458 {
AzureIoTClient 4:98007eb79fa8 1459 /* Codes_SRS_CONNECTION_01_182: [connection_get_channel_max shall return in the channel_max argument the current channel_max setting.] */
AzureIoTClient 4:98007eb79fa8 1460 *channel_max = connection->channel_max;
Azure.IoT Build 0:6ae2f7bca550 1461
AzureIoTClient 4:98007eb79fa8 1462 /* Codes_SRS_CONNECTION_01_183: [On success, connection_get_channel_max shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1463 result = 0;
AzureIoTClient 4:98007eb79fa8 1464 }
Azure.IoT Build 0:6ae2f7bca550 1465
AzureIoTClient 4:98007eb79fa8 1466 return result;
Azure.IoT Build 0:6ae2f7bca550 1467 }
Azure.IoT Build 0:6ae2f7bca550 1468
Azure.IoT Build 0:6ae2f7bca550 1469 int connection_set_idle_timeout(CONNECTION_HANDLE connection, milliseconds idle_timeout)
Azure.IoT Build 0:6ae2f7bca550 1470 {
AzureIoTClient 4:98007eb79fa8 1471 int result;
Azure.IoT Build 0:6ae2f7bca550 1472
AzureIoTClient 4:98007eb79fa8 1473 /* Codes_SRS_CONNECTION_01_191: [If connection is NULL, connection_set_idle_timeout shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1474 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1475 {
AzureIoTClient 28:add19eb7defa 1476 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1477 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1478 }
AzureIoTClient 4:98007eb79fa8 1479 else
AzureIoTClient 4:98007eb79fa8 1480 {
AzureIoTClient 4:98007eb79fa8 1481 /* Codes_SRS_CONNECTION_01_158: [If connection_set_idle_timeout is called after the initial Open frame has been sent, it shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1482 if (connection->connection_state != CONNECTION_STATE_START)
AzureIoTClient 4:98007eb79fa8 1483 {
AzureIoTClient 28:add19eb7defa 1484 LogError("Connection already open");
AzureIoTClient 28:add19eb7defa 1485 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1486 }
AzureIoTClient 4:98007eb79fa8 1487 else
AzureIoTClient 4:98007eb79fa8 1488 {
AzureIoTClient 4:98007eb79fa8 1489 /* Codes_SRS_CONNECTION_01_159: [connection_set_idle_timeout shall set the idle_timeout associated with a connection.] */
AzureIoTClient 4:98007eb79fa8 1490 /* Codes_SRS_CONNECTION_01_166: [If connection_set_idle_timeout fails, the previous idle_timeout setting shall be retained.] */
AzureIoTClient 4:98007eb79fa8 1491 connection->idle_timeout = idle_timeout;
AzureIoTClient 4:98007eb79fa8 1492 connection->idle_timeout_specified = true;
Azure.IoT Build 0:6ae2f7bca550 1493
AzureIoTClient 4:98007eb79fa8 1494 /* Codes_SRS_CONNECTION_01_160: [On success connection_set_idle_timeout shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1495 result = 0;
AzureIoTClient 4:98007eb79fa8 1496 }
AzureIoTClient 4:98007eb79fa8 1497 }
Azure.IoT Build 0:6ae2f7bca550 1498
AzureIoTClient 4:98007eb79fa8 1499 return result;
Azure.IoT Build 0:6ae2f7bca550 1500 }
Azure.IoT Build 0:6ae2f7bca550 1501
Azure.IoT Build 0:6ae2f7bca550 1502 int connection_get_idle_timeout(CONNECTION_HANDLE connection, milliseconds* idle_timeout)
Azure.IoT Build 0:6ae2f7bca550 1503 {
AzureIoTClient 4:98007eb79fa8 1504 int result;
Azure.IoT Build 0:6ae2f7bca550 1505
AzureIoTClient 4:98007eb79fa8 1506 /* Codes_SRS_CONNECTION_01_190: [If connection or idle_timeout is NULL, connection_get_idle_timeout shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1507 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1508 (idle_timeout == NULL))
AzureIoTClient 4:98007eb79fa8 1509 {
AzureIoTClient 28:add19eb7defa 1510 LogError("Bad arguments: connection = %p, idle_timeout = %p",
AzureIoTClient 28:add19eb7defa 1511 connection, idle_timeout);
AzureIoTClient 28:add19eb7defa 1512 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1513 }
AzureIoTClient 4:98007eb79fa8 1514 else
AzureIoTClient 4:98007eb79fa8 1515 {
AzureIoTClient 4:98007eb79fa8 1516 /* Codes_SRS_CONNECTION_01_188: [connection_get_idle_timeout shall return in the idle_timeout argument the current idle_timeout setting.] */
AzureIoTClient 4:98007eb79fa8 1517 *idle_timeout = connection->idle_timeout;
Azure.IoT Build 0:6ae2f7bca550 1518
AzureIoTClient 4:98007eb79fa8 1519 /* Codes_SRS_CONNECTION_01_189: [On success, connection_get_idle_timeout shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1520 result = 0;
AzureIoTClient 4:98007eb79fa8 1521 }
Azure.IoT Build 0:6ae2f7bca550 1522
AzureIoTClient 4:98007eb79fa8 1523 return result;
Azure.IoT Build 0:6ae2f7bca550 1524 }
Azure.IoT Build 0:6ae2f7bca550 1525
Azure.IoT Build 0:6ae2f7bca550 1526 int connection_get_remote_max_frame_size(CONNECTION_HANDLE connection, uint32_t* remote_max_frame_size)
Azure.IoT Build 0:6ae2f7bca550 1527 {
AzureIoTClient 4:98007eb79fa8 1528 int result;
Azure.IoT Build 0:6ae2f7bca550 1529
AzureIoTClient 4:98007eb79fa8 1530 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1531 (remote_max_frame_size == NULL))
AzureIoTClient 4:98007eb79fa8 1532 {
AzureIoTClient 28:add19eb7defa 1533 LogError("Bad arguments: connection = %p, remote_max_frame_size = %p",
AzureIoTClient 28:add19eb7defa 1534 connection, remote_max_frame_size);
AzureIoTClient 28:add19eb7defa 1535 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1536 }
AzureIoTClient 4:98007eb79fa8 1537 else
AzureIoTClient 4:98007eb79fa8 1538 {
AzureIoTClient 4:98007eb79fa8 1539 *remote_max_frame_size = connection->remote_max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 1540
AzureIoTClient 4:98007eb79fa8 1541 result = 0;
AzureIoTClient 4:98007eb79fa8 1542 }
Azure.IoT Build 0:6ae2f7bca550 1543
AzureIoTClient 4:98007eb79fa8 1544 return result;
Azure.IoT Build 0:6ae2f7bca550 1545 }
Azure.IoT Build 0:6ae2f7bca550 1546
AzureIoTClient 1:eab586236bfe 1547 uint64_t connection_handle_deadlines(CONNECTION_HANDLE connection)
AzureIoTClient 1:eab586236bfe 1548 {
AzureIoTClient 1:eab586236bfe 1549 uint64_t local_deadline = (uint64_t )-1;
AzureIoTClient 1:eab586236bfe 1550 uint64_t remote_deadline = (uint64_t)-1;
AzureIoTClient 1:eab586236bfe 1551
AzureIoTClient 28:add19eb7defa 1552 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1553 {
AzureIoTClient 28:add19eb7defa 1554 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1555 }
AzureIoTClient 28:add19eb7defa 1556 else
AzureIoTClient 28:add19eb7defa 1557 {
Azure.IoT.Build 14:0b0e28c75ded 1558 tickcounter_ms_t current_ms;
AzureIoTClient 1:eab586236bfe 1559
AzureIoTClient 1:eab586236bfe 1560 if (tickcounter_get_current_ms(connection->tick_counter, &current_ms) != 0)
AzureIoTClient 1:eab586236bfe 1561 {
AzureIoTClient 28:add19eb7defa 1562 LogError("Could not get tick counter value");
AzureIoTClient 28:add19eb7defa 1563 close_connection_with_error(connection, "amqp:internal-error", "Could not get tick count");
AzureIoTClient 1:eab586236bfe 1564 }
AzureIoTClient 1:eab586236bfe 1565 else
AzureIoTClient 1:eab586236bfe 1566 {
AzureIoTClient 1:eab586236bfe 1567 if (connection->idle_timeout_specified && (connection->idle_timeout != 0))
AzureIoTClient 1:eab586236bfe 1568 {
AzureIoTClient 1:eab586236bfe 1569 /* Calculate time until configured idle timeout expires */
AzureIoTClient 1:eab586236bfe 1570
AzureIoTClient 1:eab586236bfe 1571 uint64_t time_since_last_received = current_ms - connection->last_frame_received_time;
AzureIoTClient 1:eab586236bfe 1572 if (time_since_last_received < connection->idle_timeout)
AzureIoTClient 1:eab586236bfe 1573 {
AzureIoTClient 1:eab586236bfe 1574 local_deadline = connection->idle_timeout - time_since_last_received;
AzureIoTClient 1:eab586236bfe 1575 }
AzureIoTClient 1:eab586236bfe 1576 else
AzureIoTClient 1:eab586236bfe 1577 {
AzureIoTClient 1:eab586236bfe 1578 local_deadline = 0;
AzureIoTClient 1:eab586236bfe 1579
AzureIoTClient 1:eab586236bfe 1580 /* close connection */
AzureIoTClient 1:eab586236bfe 1581 close_connection_with_error(connection, "amqp:internal-error", "No frame received for the idle timeout");
AzureIoTClient 1:eab586236bfe 1582 }
AzureIoTClient 1:eab586236bfe 1583 }
AzureIoTClient 1:eab586236bfe 1584
AzureIoTClient 1:eab586236bfe 1585 if (local_deadline != 0 && connection->remote_idle_timeout != 0)
AzureIoTClient 1:eab586236bfe 1586 {
AzureIoTClient 1:eab586236bfe 1587 /* Calculate time until remote idle timeout expires */
AzureIoTClient 1:eab586236bfe 1588
AzureIoTClient 1:eab586236bfe 1589 uint64_t remote_idle_timeout = (connection->remote_idle_timeout / 2);
AzureIoTClient 1:eab586236bfe 1590 uint64_t time_since_last_sent = current_ms - connection->last_frame_sent_time;
AzureIoTClient 1:eab586236bfe 1591
AzureIoTClient 1:eab586236bfe 1592 if (time_since_last_sent < remote_idle_timeout)
AzureIoTClient 1:eab586236bfe 1593 {
AzureIoTClient 1:eab586236bfe 1594 remote_deadline = remote_idle_timeout - time_since_last_sent;
AzureIoTClient 1:eab586236bfe 1595 }
AzureIoTClient 1:eab586236bfe 1596 else
AzureIoTClient 1:eab586236bfe 1597 {
AzureIoTClient 1:eab586236bfe 1598 connection->on_send_complete = NULL;
AzureIoTClient 1:eab586236bfe 1599 if (amqp_frame_codec_encode_empty_frame(connection->amqp_frame_codec, 0, on_bytes_encoded, connection) != 0)
AzureIoTClient 1:eab586236bfe 1600 {
AzureIoTClient 28:add19eb7defa 1601 LogError("Encoding the empty frame failed");
AzureIoTClient 28:add19eb7defa 1602 /* close connection */
AzureIoTClient 28:add19eb7defa 1603 close_connection_with_error(connection, "amqp:internal-error", "Cannot send empty frame");
AzureIoTClient 1:eab586236bfe 1604 }
AzureIoTClient 1:eab586236bfe 1605 else
AzureIoTClient 1:eab586236bfe 1606 {
AzureIoTClient 6:641a9672db08 1607 if (connection->is_trace_on == 1)
AzureIoTClient 6:641a9672db08 1608 {
AzureIoTClient 16:22a72cf8e416 1609 LOG(AZ_LOG_TRACE, LOG_LINE, "-> Empty frame");
AzureIoTClient 6:641a9672db08 1610 }
AzureIoTClient 1:eab586236bfe 1611
AzureIoTClient 1:eab586236bfe 1612 connection->last_frame_sent_time = current_ms;
AzureIoTClient 1:eab586236bfe 1613
AzureIoTClient 1:eab586236bfe 1614 remote_deadline = remote_idle_timeout;
AzureIoTClient 1:eab586236bfe 1615 }
AzureIoTClient 1:eab586236bfe 1616 }
AzureIoTClient 1:eab586236bfe 1617 }
AzureIoTClient 1:eab586236bfe 1618 }
AzureIoTClient 1:eab586236bfe 1619 }
AzureIoTClient 1:eab586236bfe 1620
AzureIoTClient 1:eab586236bfe 1621 /* Return the shorter of each deadline, or 0 to indicate connection closed */
AzureIoTClient 1:eab586236bfe 1622 return local_deadline > remote_deadline ? remote_deadline : local_deadline;
AzureIoTClient 1:eab586236bfe 1623 }
AzureIoTClient 1:eab586236bfe 1624
Azure.IoT Build 0:6ae2f7bca550 1625 void connection_dowork(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1626 {
AzureIoTClient 4:98007eb79fa8 1627 /* Codes_SRS_CONNECTION_01_078: [If handle is NULL, connection_dowork shall do nothing.] */
AzureIoTClient 28:add19eb7defa 1628 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1629 {
AzureIoTClient 28:add19eb7defa 1630 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1631 }
AzureIoTClient 28:add19eb7defa 1632 else
AzureIoTClient 28:add19eb7defa 1633 {
AzureIoTClient 1:eab586236bfe 1634 if (connection_handle_deadlines(connection) > 0)
AzureIoTClient 1:eab586236bfe 1635 {
AzureIoTClient 1:eab586236bfe 1636 /* Codes_SRS_CONNECTION_01_076: [connection_dowork shall schedule the underlying IO interface to do its work by calling xio_dowork.] */
AzureIoTClient 1:eab586236bfe 1637 xio_dowork(connection->io);
AzureIoTClient 1:eab586236bfe 1638 }
AzureIoTClient 1:eab586236bfe 1639 }
Azure.IoT Build 0:6ae2f7bca550 1640 }
Azure.IoT Build 0:6ae2f7bca550 1641
Azure.IoT Build 0:6ae2f7bca550 1642 ENDPOINT_HANDLE connection_create_endpoint(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1643 {
AzureIoTClient 28:add19eb7defa 1644 ENDPOINT_HANDLE result;
Azure.IoT Build 0:6ae2f7bca550 1645
AzureIoTClient 4:98007eb79fa8 1646 /* Codes_SRS_CONNECTION_01_113: [If connection, on_endpoint_frame_received or on_connection_state_changed is NULL, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 4:98007eb79fa8 1647 /* Codes_SRS_CONNECTION_01_193: [The context argument shall be allowed to be NULL.] */
AzureIoTClient 4:98007eb79fa8 1648 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1649 {
AzureIoTClient 28:add19eb7defa 1650 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1651 result = NULL;
AzureIoTClient 4:98007eb79fa8 1652 }
AzureIoTClient 4:98007eb79fa8 1653 else
AzureIoTClient 4:98007eb79fa8 1654 {
AzureIoTClient 4:98007eb79fa8 1655 /* Codes_SRS_CONNECTION_01_115: [If no more endpoints can be created due to all channels being used, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 4:98007eb79fa8 1656 if (connection->endpoint_count >= connection->channel_max)
AzureIoTClient 4:98007eb79fa8 1657 {
AzureIoTClient 4:98007eb79fa8 1658 result = NULL;
AzureIoTClient 4:98007eb79fa8 1659 }
AzureIoTClient 4:98007eb79fa8 1660 else
AzureIoTClient 4:98007eb79fa8 1661 {
AzureIoTClient 4:98007eb79fa8 1662 uint32_t i = 0;
Azure.IoT Build 0:6ae2f7bca550 1663
AzureIoTClient 4:98007eb79fa8 1664 /* Codes_SRS_CONNECTION_01_128: [The lowest number outgoing channel shall be associated with the newly created endpoint.] */
AzureIoTClient 4:98007eb79fa8 1665 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 1666 {
AzureIoTClient 4:98007eb79fa8 1667 if (connection->endpoints[i]->outgoing_channel > i)
AzureIoTClient 4:98007eb79fa8 1668 {
AzureIoTClient 4:98007eb79fa8 1669 /* found a gap in the sorted endpoint array */
AzureIoTClient 4:98007eb79fa8 1670 break;
AzureIoTClient 4:98007eb79fa8 1671 }
AzureIoTClient 4:98007eb79fa8 1672 }
Azure.IoT Build 0:6ae2f7bca550 1673
AzureIoTClient 4:98007eb79fa8 1674 /* Codes_SRS_CONNECTION_01_127: [On success, connection_create_endpoint shall return a non-NULL handle to the newly created endpoint.] */
AzureIoTClient 24:2c59c2d43ebf 1675 result = (ENDPOINT_HANDLE)malloc(sizeof(ENDPOINT_INSTANCE));
AzureIoTClient 4:98007eb79fa8 1676 /* Codes_SRS_CONNECTION_01_196: [If memory cannot be allocated for the new endpoint, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 28:add19eb7defa 1677 if (result == NULL)
AzureIoTClient 28:add19eb7defa 1678 {
AzureIoTClient 28:add19eb7defa 1679 LogError("Cannot allocate memory for endpoint");
AzureIoTClient 28:add19eb7defa 1680 }
AzureIoTClient 28:add19eb7defa 1681 else
AzureIoTClient 28:add19eb7defa 1682 {
AzureIoTClient 28:add19eb7defa 1683 ENDPOINT_HANDLE* new_endpoints;
Azure.IoT Build 0:6ae2f7bca550 1684
AzureIoTClient 4:98007eb79fa8 1685 result->on_endpoint_frame_received = NULL;
AzureIoTClient 4:98007eb79fa8 1686 result->on_connection_state_changed = NULL;
AzureIoTClient 4:98007eb79fa8 1687 result->callback_context = NULL;
AzureIoTClient 6:641a9672db08 1688 result->outgoing_channel = (uint16_t)i;
AzureIoTClient 4:98007eb79fa8 1689 result->connection = connection;
Azure.IoT Build 0:6ae2f7bca550 1690
AzureIoTClient 4:98007eb79fa8 1691 /* Codes_SRS_CONNECTION_01_197: [The newly created endpoint shall be added to the endpoints list, so that it can be tracked.] */
AzureIoTClient 24:2c59c2d43ebf 1692 new_endpoints = (ENDPOINT_HANDLE*)realloc(connection->endpoints, sizeof(ENDPOINT_HANDLE) * (connection->endpoint_count + 1));
AzureIoTClient 4:98007eb79fa8 1693 if (new_endpoints == NULL)
AzureIoTClient 4:98007eb79fa8 1694 {
AzureIoTClient 4:98007eb79fa8 1695 /* Tests_SRS_CONNECTION_01_198: [If adding the endpoint to the endpoints list tracked by the connection fails, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 28:add19eb7defa 1696 LogError("Cannot reallocate memory for connection endpoints");
AzureIoTClient 28:add19eb7defa 1697 free(result);
AzureIoTClient 4:98007eb79fa8 1698 result = NULL;
AzureIoTClient 4:98007eb79fa8 1699 }
AzureIoTClient 4:98007eb79fa8 1700 else
AzureIoTClient 4:98007eb79fa8 1701 {
AzureIoTClient 4:98007eb79fa8 1702 connection->endpoints = new_endpoints;
Azure.IoT Build 0:6ae2f7bca550 1703
AzureIoTClient 4:98007eb79fa8 1704 if (i < connection->endpoint_count)
AzureIoTClient 4:98007eb79fa8 1705 {
AzureIoTClient 4:98007eb79fa8 1706 (void)memmove(&connection->endpoints[i + 1], &connection->endpoints[i], sizeof(ENDPOINT_INSTANCE*) * (connection->endpoint_count - i));
AzureIoTClient 4:98007eb79fa8 1707 }
Azure.IoT Build 0:6ae2f7bca550 1708
AzureIoTClient 4:98007eb79fa8 1709 connection->endpoints[i] = result;
AzureIoTClient 4:98007eb79fa8 1710 connection->endpoint_count++;
Azure.IoT Build 0:6ae2f7bca550 1711
AzureIoTClient 4:98007eb79fa8 1712 /* Codes_SRS_CONNECTION_01_112: [connection_create_endpoint shall create a new endpoint that can be used by a session.] */
AzureIoTClient 4:98007eb79fa8 1713 }
AzureIoTClient 4:98007eb79fa8 1714 }
AzureIoTClient 4:98007eb79fa8 1715 }
AzureIoTClient 4:98007eb79fa8 1716 }
Azure.IoT Build 0:6ae2f7bca550 1717
AzureIoTClient 4:98007eb79fa8 1718 return result;
Azure.IoT Build 0:6ae2f7bca550 1719 }
Azure.IoT Build 0:6ae2f7bca550 1720
Azure.IoT Build 0:6ae2f7bca550 1721 int connection_start_endpoint(ENDPOINT_HANDLE endpoint, ON_ENDPOINT_FRAME_RECEIVED on_endpoint_frame_received, ON_CONNECTION_STATE_CHANGED on_connection_state_changed, void* context)
Azure.IoT Build 0:6ae2f7bca550 1722 {
AzureIoTClient 4:98007eb79fa8 1723 int result;
Azure.IoT Build 0:6ae2f7bca550 1724
AzureIoTClient 4:98007eb79fa8 1725 if ((endpoint == NULL) ||
AzureIoTClient 4:98007eb79fa8 1726 (on_endpoint_frame_received == NULL) ||
AzureIoTClient 4:98007eb79fa8 1727 (on_connection_state_changed == NULL))
AzureIoTClient 4:98007eb79fa8 1728 {
AzureIoTClient 28:add19eb7defa 1729 LogError("Bad arguments: endpoint = %p, on_endpoint_frame_received = %p, on_connection_state_changed = %p",
AzureIoTClient 28:add19eb7defa 1730 endpoint, on_endpoint_frame_received, on_connection_state_changed);
AzureIoTClient 28:add19eb7defa 1731 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1732 }
AzureIoTClient 4:98007eb79fa8 1733 else
AzureIoTClient 4:98007eb79fa8 1734 {
AzureIoTClient 4:98007eb79fa8 1735 endpoint->on_endpoint_frame_received = on_endpoint_frame_received;
AzureIoTClient 4:98007eb79fa8 1736 endpoint->on_connection_state_changed = on_connection_state_changed;
AzureIoTClient 4:98007eb79fa8 1737 endpoint->callback_context = context;
Azure.IoT Build 0:6ae2f7bca550 1738
AzureIoTClient 4:98007eb79fa8 1739 result = 0;
AzureIoTClient 4:98007eb79fa8 1740 }
Azure.IoT Build 0:6ae2f7bca550 1741
AzureIoTClient 4:98007eb79fa8 1742 return result;
Azure.IoT Build 0:6ae2f7bca550 1743 }
Azure.IoT Build 0:6ae2f7bca550 1744
Azure.IoT Build 0:6ae2f7bca550 1745 int connection_endpoint_get_incoming_channel(ENDPOINT_HANDLE endpoint, uint16_t* incoming_channel)
Azure.IoT Build 0:6ae2f7bca550 1746 {
AzureIoTClient 4:98007eb79fa8 1747 int result;
Azure.IoT Build 0:6ae2f7bca550 1748
AzureIoTClient 4:98007eb79fa8 1749 if ((endpoint == NULL) ||
AzureIoTClient 4:98007eb79fa8 1750 (incoming_channel == NULL))
AzureIoTClient 4:98007eb79fa8 1751 {
AzureIoTClient 28:add19eb7defa 1752 LogError("Bad arguments: endpoint = %p, incoming_channel = %p",
AzureIoTClient 28:add19eb7defa 1753 endpoint, incoming_channel);
AzureIoTClient 28:add19eb7defa 1754 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1755 }
AzureIoTClient 4:98007eb79fa8 1756 else
AzureIoTClient 4:98007eb79fa8 1757 {
AzureIoTClient 4:98007eb79fa8 1758 *incoming_channel = endpoint->incoming_channel;
AzureIoTClient 4:98007eb79fa8 1759 result = 0;
AzureIoTClient 4:98007eb79fa8 1760 }
Azure.IoT Build 0:6ae2f7bca550 1761
AzureIoTClient 4:98007eb79fa8 1762 return result;
Azure.IoT Build 0:6ae2f7bca550 1763 }
Azure.IoT Build 0:6ae2f7bca550 1764
Azure.IoT Build 0:6ae2f7bca550 1765 /* Codes_SRS_CONNECTION_01_129: [connection_destroy_endpoint shall free all resources associated with an endpoint created by connection_create_endpoint.] */
Azure.IoT Build 0:6ae2f7bca550 1766 void connection_destroy_endpoint(ENDPOINT_HANDLE endpoint)
Azure.IoT Build 0:6ae2f7bca550 1767 {
AzureIoTClient 28:add19eb7defa 1768 if (endpoint == NULL)
AzureIoTClient 28:add19eb7defa 1769 {
AzureIoTClient 28:add19eb7defa 1770 LogError("NULL endpoint");
AzureIoTClient 28:add19eb7defa 1771 }
AzureIoTClient 28:add19eb7defa 1772 else
AzureIoTClient 28:add19eb7defa 1773 {
AzureIoTClient 24:2c59c2d43ebf 1774 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)endpoint->connection;
AzureIoTClient 4:98007eb79fa8 1775 size_t i;
Azure.IoT Build 0:6ae2f7bca550 1776
AzureIoTClient 4:98007eb79fa8 1777 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 1778 {
AzureIoTClient 4:98007eb79fa8 1779 if (connection->endpoints[i] == endpoint)
AzureIoTClient 4:98007eb79fa8 1780 {
AzureIoTClient 4:98007eb79fa8 1781 break;
AzureIoTClient 4:98007eb79fa8 1782 }
AzureIoTClient 4:98007eb79fa8 1783 }
Azure.IoT Build 0:6ae2f7bca550 1784
AzureIoTClient 4:98007eb79fa8 1785 /* Codes_SRS_CONNECTION_01_130: [The outgoing channel associated with the endpoint shall be released by removing the endpoint from the endpoint list.] */
AzureIoTClient 4:98007eb79fa8 1786 /* Codes_SRS_CONNECTION_01_131: [Any incoming channel number associated with the endpoint shall be released.] */
AzureIoTClient 28:add19eb7defa 1787 if ((i < connection->endpoint_count) && (i > 0))
AzureIoTClient 28:add19eb7defa 1788 {
AzureIoTClient 28:add19eb7defa 1789 ENDPOINT_HANDLE* new_endpoints;
AzureIoTClient 28:add19eb7defa 1790 (void)memmove(connection->endpoints + i, connection->endpoints + i + 1, sizeof(ENDPOINT_HANDLE) * (connection->endpoint_count - i - 1));
Azure.IoT Build 0:6ae2f7bca550 1791
AzureIoTClient 28:add19eb7defa 1792 new_endpoints = (ENDPOINT_HANDLE*)realloc(connection->endpoints, (connection->endpoint_count - 1) * sizeof(ENDPOINT_HANDLE));
AzureIoTClient 28:add19eb7defa 1793 if (new_endpoints != NULL)
AzureIoTClient 28:add19eb7defa 1794 {
AzureIoTClient 28:add19eb7defa 1795 connection->endpoints = new_endpoints;
AzureIoTClient 28:add19eb7defa 1796 }
Azure.IoT Build 0:6ae2f7bca550 1797
AzureIoTClient 28:add19eb7defa 1798 connection->endpoint_count--;
AzureIoTClient 28:add19eb7defa 1799 }
AzureIoTClient 28:add19eb7defa 1800 else if (connection->endpoint_count == 1)
AzureIoTClient 28:add19eb7defa 1801 {
AzureIoTClient 28:add19eb7defa 1802 free(connection->endpoints);
AzureIoTClient 28:add19eb7defa 1803 connection->endpoints = NULL;
AzureIoTClient 28:add19eb7defa 1804 connection->endpoint_count = 0;
AzureIoTClient 28:add19eb7defa 1805 }
Azure.IoT Build 0:6ae2f7bca550 1806
AzureIoTClient 21:f9c433d8e6ca 1807 free(endpoint);
AzureIoTClient 4:98007eb79fa8 1808 }
Azure.IoT Build 0:6ae2f7bca550 1809 }
Azure.IoT Build 0:6ae2f7bca550 1810
Azure.IoT Build 0:6ae2f7bca550 1811 /* Codes_SRS_CONNECTION_01_247: [connection_encode_frame shall send a frame for a certain endpoint.] */
Azure.IoT Build 0:6ae2f7bca550 1812 int connection_encode_frame(ENDPOINT_HANDLE endpoint, const AMQP_VALUE performative, PAYLOAD* payloads, size_t payload_count, ON_SEND_COMPLETE on_send_complete, void* callback_context)
Azure.IoT Build 0:6ae2f7bca550 1813 {
AzureIoTClient 4:98007eb79fa8 1814 int result;
Azure.IoT Build 0:6ae2f7bca550 1815
AzureIoTClient 4:98007eb79fa8 1816 /* Codes_SRS_CONNECTION_01_249: [If endpoint or performative are NULL, connection_encode_frame shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1817 if ((endpoint == NULL) ||
AzureIoTClient 4:98007eb79fa8 1818 (performative == NULL))
AzureIoTClient 4:98007eb79fa8 1819 {
AzureIoTClient 28:add19eb7defa 1820 LogError("Bad arguments: endpoint = %p, performative = %p",
AzureIoTClient 28:add19eb7defa 1821 endpoint, performative);
AzureIoTClient 28:add19eb7defa 1822 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1823 }
AzureIoTClient 4:98007eb79fa8 1824 else
AzureIoTClient 4:98007eb79fa8 1825 {
AzureIoTClient 28:add19eb7defa 1826 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)endpoint->connection;
AzureIoTClient 4:98007eb79fa8 1827 AMQP_FRAME_CODEC_HANDLE amqp_frame_codec = connection->amqp_frame_codec;
Azure.IoT Build 0:6ae2f7bca550 1828
AzureIoTClient 4:98007eb79fa8 1829 /* Codes_SRS_CONNECTION_01_254: [If connection_encode_frame is called before the connection is in the OPENED state, connection_encode_frame shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1830 if (connection->connection_state != CONNECTION_STATE_OPENED)
AzureIoTClient 4:98007eb79fa8 1831 {
AzureIoTClient 28:add19eb7defa 1832 LogError("Connection not open");
AzureIoTClient 28:add19eb7defa 1833 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1834 }
AzureIoTClient 4:98007eb79fa8 1835 else
AzureIoTClient 4:98007eb79fa8 1836 {
AzureIoTClient 4:98007eb79fa8 1837 /* Codes_SRS_CONNECTION_01_255: [The payload size shall be computed based on all the payload chunks passed as argument in payloads.] */
AzureIoTClient 4:98007eb79fa8 1838 /* Codes_SRS_CONNECTION_01_250: [connection_encode_frame shall initiate the frame send by calling amqp_frame_codec_begin_encode_frame.] */
AzureIoTClient 4:98007eb79fa8 1839 /* Codes_SRS_CONNECTION_01_251: [The channel number passed to amqp_frame_codec_begin_encode_frame shall be the outgoing channel number associated with the endpoint by connection_create_endpoint.] */
AzureIoTClient 4:98007eb79fa8 1840 /* Codes_SRS_CONNECTION_01_252: [The performative passed to amqp_frame_codec_begin_encode_frame shall be the performative argument of connection_encode_frame.] */
AzureIoTClient 4:98007eb79fa8 1841 connection->on_send_complete = on_send_complete;
AzureIoTClient 4:98007eb79fa8 1842 connection->on_send_complete_callback_context = callback_context;
AzureIoTClient 4:98007eb79fa8 1843 if (amqp_frame_codec_encode_frame(amqp_frame_codec, endpoint->outgoing_channel, performative, payloads, payload_count, on_bytes_encoded, connection) != 0)
AzureIoTClient 4:98007eb79fa8 1844 {
AzureIoTClient 4:98007eb79fa8 1845 /* Codes_SRS_CONNECTION_01_253: [If amqp_frame_codec_begin_encode_frame or amqp_frame_codec_encode_payload_bytes fails, then connection_encode_frame shall fail and return a non-zero value.] */
AzureIoTClient 28:add19eb7defa 1846 LogError("Encoding AMQP frame failed");
AzureIoTClient 28:add19eb7defa 1847 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1848 }
AzureIoTClient 4:98007eb79fa8 1849 else
AzureIoTClient 4:98007eb79fa8 1850 {
AzureIoTClient 4:98007eb79fa8 1851 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 1852 {
Azure.IoT Build 5:ae49385aff34 1853 log_outgoing_frame(performative);
AzureIoTClient 4:98007eb79fa8 1854 }
Azure.IoT Build 5:ae49385aff34 1855
AzureIoTClient 4:98007eb79fa8 1856 if (tickcounter_get_current_ms(connection->tick_counter, &connection->last_frame_sent_time) != 0)
AzureIoTClient 4:98007eb79fa8 1857 {
AzureIoTClient 28:add19eb7defa 1858 LogError("Getting tick counter value failed");
AzureIoTClient 28:add19eb7defa 1859 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1860 }
AzureIoTClient 4:98007eb79fa8 1861 else
AzureIoTClient 4:98007eb79fa8 1862 {
AzureIoTClient 4:98007eb79fa8 1863 /* Codes_SRS_CONNECTION_01_248: [On success it shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1864 result = 0;
AzureIoTClient 4:98007eb79fa8 1865 }
AzureIoTClient 4:98007eb79fa8 1866 }
AzureIoTClient 4:98007eb79fa8 1867 }
AzureIoTClient 4:98007eb79fa8 1868 }
Azure.IoT Build 0:6ae2f7bca550 1869
AzureIoTClient 4:98007eb79fa8 1870 return result;
Azure.IoT Build 0:6ae2f7bca550 1871 }
AzureIoTClient 4:98007eb79fa8 1872
AzureIoTClient 24:2c59c2d43ebf 1873 void connection_set_trace(CONNECTION_HANDLE connection, bool trace_on)
AzureIoTClient 4:98007eb79fa8 1874 {
AzureIoTClient 4:98007eb79fa8 1875 /* Codes_SRS_CONNECTION_07_002: [If connection is NULL then connection_set_trace shall do nothing.] */
AzureIoTClient 28:add19eb7defa 1876 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1877 {
AzureIoTClient 28:add19eb7defa 1878 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1879 }
AzureIoTClient 28:add19eb7defa 1880 else
AzureIoTClient 28:add19eb7defa 1881 {
AzureIoTClient 4:98007eb79fa8 1882 /* Codes_SRS_CONNECTION_07_001: [connection_set_trace shall set the ability to turn on and off trace logging.] */
AzureIoTClient 24:2c59c2d43ebf 1883 connection->is_trace_on = trace_on ? 1 : 0;
AzureIoTClient 4:98007eb79fa8 1884 }
AzureIoTClient 4:98007eb79fa8 1885 }