Demo using MBED TLS

Dependencies:   EthernetInterface NTPClient iothub_amqp_transport iothub_client mbed-rtos mbed

Fork of iothub_client_sample_amqp by Azure IoT

Committer:
markrad
Date:
Thu Jan 05 00:20:03 2017 +0000
Revision:
58:f50b97b08851
Sample using MBED TLS

Who changed what in which revision?

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