A small memory footprint AMQP implimentation

Dependents:   iothub_client_sample_amqp remote_monitoring simplesample_amqp

Committer:
AzureIoTClient
Date:
Mon May 22 10:35:21 2017 -0700
Revision:
25:1101516ee67d
Parent:
23:1111ee8bcba4
Child:
28:add19eb7defa
1.1.15

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Azure.IoT Build 0:6ae2f7bca550 1 // Copyright (c) Microsoft. All rights reserved.
Azure.IoT Build 0:6ae2f7bca550 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
Azure.IoT Build 0:6ae2f7bca550 3
Azure.IoT Build 0:6ae2f7bca550 4 #include <stdlib.h>
Azure.IoT Build 0:6ae2f7bca550 5 #include <stddef.h>
Azure.IoT Build 0:6ae2f7bca550 6 #include <stdio.h>
Azure.IoT Build 0:6ae2f7bca550 7 #include <string.h>
AzureIoTClient 6:641a9672db08 8 #include <stdbool.h>
AzureIoTClient 23:1111ee8bcba4 9
AzureIoTClient 21:f9c433d8e6ca 10 #include "azure_c_shared_utility/gballoc.h"
AzureIoTClient 19:000ab4e6a2c1 11 #include "azure_c_shared_utility/optimize_size.h"
Azure.IoT Build 0:6ae2f7bca550 12 #include "azure_uamqp_c/saslclientio.h"
Azure.IoT Build 0:6ae2f7bca550 13 #include "azure_c_shared_utility/xio.h"
Azure.IoT Build 0:6ae2f7bca550 14 #include "azure_c_shared_utility/xlogging.h"
Azure.IoT Build 0:6ae2f7bca550 15 #include "azure_uamqp_c/frame_codec.h"
Azure.IoT Build 0:6ae2f7bca550 16 #include "azure_uamqp_c/sasl_frame_codec.h"
Azure.IoT Build 0:6ae2f7bca550 17 #include "azure_uamqp_c/amqp_definitions.h"
Azure.IoT Build 0:6ae2f7bca550 18 #include "azure_uamqp_c/amqpvalue_to_string.h"
Azure.IoT Build 0:6ae2f7bca550 19
Azure.IoT Build 0:6ae2f7bca550 20 typedef enum IO_STATE_TAG
Azure.IoT Build 0:6ae2f7bca550 21 {
AzureIoTClient 6:641a9672db08 22 IO_STATE_NOT_OPEN,
AzureIoTClient 6:641a9672db08 23 IO_STATE_OPENING_UNDERLYING_IO,
AzureIoTClient 6:641a9672db08 24 IO_STATE_SASL_HANDSHAKE,
AzureIoTClient 6:641a9672db08 25 IO_STATE_OPEN,
AzureIoTClient 6:641a9672db08 26 IO_STATE_CLOSING,
AzureIoTClient 6:641a9672db08 27 IO_STATE_ERROR
Azure.IoT Build 0:6ae2f7bca550 28 } IO_STATE;
Azure.IoT Build 0:6ae2f7bca550 29
AzureIoTClient 23:1111ee8bcba4 30 #define SASL_HEADER_EXCHANGE_STATE_VALUES \
AzureIoTClient 23:1111ee8bcba4 31 SASL_HEADER_EXCHANGE_IDLE, \
AzureIoTClient 23:1111ee8bcba4 32 SASL_HEADER_EXCHANGE_HEADER_SENT, \
AzureIoTClient 23:1111ee8bcba4 33 SASL_HEADER_EXCHANGE_HEADER_RCVD, \
AzureIoTClient 6:641a9672db08 34 SASL_HEADER_EXCHANGE_HEADER_EXCH
AzureIoTClient 23:1111ee8bcba4 35
AzureIoTClient 23:1111ee8bcba4 36 DEFINE_LOCAL_ENUM(SASL_HEADER_EXCHANGE_STATE, SASL_HEADER_EXCHANGE_STATE_VALUES)
Azure.IoT Build 0:6ae2f7bca550 37
AzureIoTClient 23:1111ee8bcba4 38 #define SASL_CLIENT_NEGOTIATION_STATE_VALUES \
AzureIoTClient 23:1111ee8bcba4 39 SASL_CLIENT_NEGOTIATION_NOT_STARTED, \
AzureIoTClient 23:1111ee8bcba4 40 SASL_CLIENT_NEGOTIATION_MECH_RCVD, \
AzureIoTClient 23:1111ee8bcba4 41 SASL_CLIENT_NEGOTIATION_INIT_SENT, \
AzureIoTClient 23:1111ee8bcba4 42 SASL_CLIENT_NEGOTIATION_CHALLENGE_RCVD, \
AzureIoTClient 23:1111ee8bcba4 43 SASL_CLIENT_NEGOTIATION_RESPONSE_SENT, \
AzureIoTClient 23:1111ee8bcba4 44 SASL_CLIENT_NEGOTIATION_OUTCOME_RCVD, \
AzureIoTClient 6:641a9672db08 45 SASL_CLIENT_NEGOTIATION_ERROR
AzureIoTClient 23:1111ee8bcba4 46
AzureIoTClient 23:1111ee8bcba4 47 DEFINE_LOCAL_ENUM(SASL_CLIENT_NEGOTIATION_STATE, SASL_CLIENT_NEGOTIATION_STATE_VALUES)
Azure.IoT Build 0:6ae2f7bca550 48
Azure.IoT Build 0:6ae2f7bca550 49 typedef struct SASL_CLIENT_IO_INSTANCE_TAG
Azure.IoT Build 0:6ae2f7bca550 50 {
AzureIoTClient 6:641a9672db08 51 XIO_HANDLE underlying_io;
AzureIoTClient 6:641a9672db08 52 ON_BYTES_RECEIVED on_bytes_received;
AzureIoTClient 6:641a9672db08 53 ON_IO_OPEN_COMPLETE on_io_open_complete;
AzureIoTClient 6:641a9672db08 54 ON_IO_CLOSE_COMPLETE on_io_close_complete;
AzureIoTClient 6:641a9672db08 55 ON_IO_ERROR on_io_error;
Azure.IoT Build 0:6ae2f7bca550 56 void* on_bytes_received_context;
AzureIoTClient 6:641a9672db08 57 void* on_io_open_complete_context;
AzureIoTClient 6:641a9672db08 58 void* on_io_close_complete_context;
Azure.IoT Build 0:6ae2f7bca550 59 void* on_io_error_context;
AzureIoTClient 6:641a9672db08 60 SASL_HEADER_EXCHANGE_STATE sasl_header_exchange_state;
AzureIoTClient 6:641a9672db08 61 SASL_CLIENT_NEGOTIATION_STATE sasl_client_negotiation_state;
AzureIoTClient 6:641a9672db08 62 size_t header_bytes_received;
AzureIoTClient 6:641a9672db08 63 SASL_FRAME_CODEC_HANDLE sasl_frame_codec;
AzureIoTClient 6:641a9672db08 64 FRAME_CODEC_HANDLE frame_codec;
AzureIoTClient 6:641a9672db08 65 IO_STATE io_state;
AzureIoTClient 6:641a9672db08 66 SASL_MECHANISM_HANDLE sasl_mechanism;
AzureIoTClient 6:641a9672db08 67 unsigned int is_trace_on : 1;
Azure.IoT Build 0:6ae2f7bca550 68 } SASL_CLIENT_IO_INSTANCE;
Azure.IoT Build 0:6ae2f7bca550 69
AzureIoTClient 16:22a72cf8e416 70 /* Codes_SRS_SASLCLIENTIO_01_002: [The protocol header consists of the upper case ASCII letters "AMQP" followed by a protocol id of three, followed by three unsigned bytes representing the major, minor, and revision of the specification version (currently 1 (SASL-MAJOR), 0 (SASLMINOR), 0 (SASL-REVISION)).] */
Azure.IoT Build 0:6ae2f7bca550 71 /* Codes_SRS_SASLCLIENTIO_01_124: [SASL-MAJOR 1 major protocol version.] */
Azure.IoT Build 0:6ae2f7bca550 72 /* Codes_SRS_SASLCLIENTIO_01_125: [SASL-MINOR 0 minor protocol version.] */
Azure.IoT Build 0:6ae2f7bca550 73 /* Codes_SRS_SASLCLIENTIO_01_126: [SASL-REVISION 0 protocol revision.] */
AzureIoTClient 21:f9c433d8e6ca 74 static const unsigned char sasl_header[] = { 'A', 'M', 'Q', 'P', 3, 1, 0, 0 };
Azure.IoT Build 0:6ae2f7bca550 75
Azure.IoT Build 0:6ae2f7bca550 76 static void indicate_error(SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance)
Azure.IoT Build 0:6ae2f7bca550 77 {
AzureIoTClient 6:641a9672db08 78 if (sasl_client_io_instance->on_io_error != NULL)
AzureIoTClient 6:641a9672db08 79 {
AzureIoTClient 6:641a9672db08 80 sasl_client_io_instance->on_io_error(sasl_client_io_instance->on_io_error_context);
AzureIoTClient 6:641a9672db08 81 }
Azure.IoT Build 0:6ae2f7bca550 82 }
Azure.IoT Build 0:6ae2f7bca550 83
Azure.IoT Build 0:6ae2f7bca550 84 static void indicate_open_complete(SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance, IO_OPEN_RESULT open_result)
Azure.IoT Build 0:6ae2f7bca550 85 {
AzureIoTClient 6:641a9672db08 86 if (sasl_client_io_instance->on_io_open_complete != NULL)
AzureIoTClient 6:641a9672db08 87 {
AzureIoTClient 6:641a9672db08 88 sasl_client_io_instance->on_io_open_complete(sasl_client_io_instance->on_io_open_complete_context, open_result);
AzureIoTClient 6:641a9672db08 89 }
Azure.IoT Build 0:6ae2f7bca550 90 }
Azure.IoT Build 0:6ae2f7bca550 91
Azure.IoT Build 0:6ae2f7bca550 92 static void indicate_close_complete(SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance)
Azure.IoT Build 0:6ae2f7bca550 93 {
AzureIoTClient 6:641a9672db08 94 if (sasl_client_io_instance->on_io_close_complete != NULL)
AzureIoTClient 6:641a9672db08 95 {
AzureIoTClient 6:641a9672db08 96 sasl_client_io_instance->on_io_close_complete(sasl_client_io_instance->on_io_close_complete_context);
AzureIoTClient 6:641a9672db08 97 }
Azure.IoT Build 0:6ae2f7bca550 98 }
Azure.IoT Build 0:6ae2f7bca550 99
Azure.IoT Build 0:6ae2f7bca550 100 static void on_underlying_io_close_complete(void* context)
Azure.IoT Build 0:6ae2f7bca550 101 {
AzureIoTClient 6:641a9672db08 102 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context;
Azure.IoT Build 0:6ae2f7bca550 103
AzureIoTClient 6:641a9672db08 104 switch (sasl_client_io_instance->io_state)
AzureIoTClient 6:641a9672db08 105 {
AzureIoTClient 6:641a9672db08 106 default:
AzureIoTClient 6:641a9672db08 107 break;
Azure.IoT Build 0:6ae2f7bca550 108
AzureIoTClient 6:641a9672db08 109 case IO_STATE_OPENING_UNDERLYING_IO:
AzureIoTClient 6:641a9672db08 110 case IO_STATE_SASL_HANDSHAKE:
AzureIoTClient 6:641a9672db08 111 sasl_client_io_instance->io_state = IO_STATE_NOT_OPEN;
AzureIoTClient 6:641a9672db08 112 indicate_open_complete(sasl_client_io_instance, IO_OPEN_ERROR);
AzureIoTClient 6:641a9672db08 113 break;
Azure.IoT Build 0:6ae2f7bca550 114
AzureIoTClient 6:641a9672db08 115 case IO_STATE_CLOSING:
AzureIoTClient 6:641a9672db08 116 sasl_client_io_instance->io_state = IO_STATE_NOT_OPEN;
AzureIoTClient 6:641a9672db08 117 indicate_close_complete(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 118 break;
AzureIoTClient 6:641a9672db08 119 }
Azure.IoT Build 0:6ae2f7bca550 120 }
Azure.IoT Build 0:6ae2f7bca550 121
Azure.IoT Build 0:6ae2f7bca550 122 static void handle_error(SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance)
Azure.IoT Build 0:6ae2f7bca550 123 {
AzureIoTClient 6:641a9672db08 124 switch (sasl_client_io_instance->io_state)
AzureIoTClient 6:641a9672db08 125 {
AzureIoTClient 6:641a9672db08 126 default:
AzureIoTClient 6:641a9672db08 127 case IO_STATE_NOT_OPEN:
AzureIoTClient 6:641a9672db08 128 break;
Azure.IoT Build 0:6ae2f7bca550 129
AzureIoTClient 6:641a9672db08 130 case IO_STATE_OPENING_UNDERLYING_IO:
AzureIoTClient 6:641a9672db08 131 case IO_STATE_SASL_HANDSHAKE:
AzureIoTClient 6:641a9672db08 132 if (xio_close(sasl_client_io_instance->underlying_io, on_underlying_io_close_complete, sasl_client_io_instance) != 0)
AzureIoTClient 6:641a9672db08 133 {
AzureIoTClient 6:641a9672db08 134 sasl_client_io_instance->io_state = IO_STATE_NOT_OPEN;
AzureIoTClient 6:641a9672db08 135 indicate_open_complete(sasl_client_io_instance, IO_OPEN_ERROR);
AzureIoTClient 6:641a9672db08 136 }
AzureIoTClient 6:641a9672db08 137 break;
Azure.IoT Build 0:6ae2f7bca550 138
AzureIoTClient 6:641a9672db08 139 case IO_STATE_OPEN:
AzureIoTClient 6:641a9672db08 140 sasl_client_io_instance->io_state = IO_STATE_ERROR;
AzureIoTClient 6:641a9672db08 141 indicate_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 142 break;
AzureIoTClient 6:641a9672db08 143 }
Azure.IoT Build 0:6ae2f7bca550 144 }
Azure.IoT Build 0:6ae2f7bca550 145
Azure.IoT Build 0:6ae2f7bca550 146 static int send_sasl_header(SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance)
Azure.IoT Build 0:6ae2f7bca550 147 {
AzureIoTClient 6:641a9672db08 148 int result;
Azure.IoT Build 0:6ae2f7bca550 149
AzureIoTClient 6:641a9672db08 150 /* Codes_SRS_SASLCLIENTIO_01_078: [SASL client IO shall start the header exchange by sending the SASL header.] */
AzureIoTClient 6:641a9672db08 151 /* Codes_SRS_SASLCLIENTIO_01_095: [Sending the header shall be done by using xio_send.] */
AzureIoTClient 6:641a9672db08 152 if (xio_send(sasl_client_io_instance->underlying_io, sasl_header, sizeof(sasl_header), NULL, NULL) != 0)
AzureIoTClient 6:641a9672db08 153 {
AzureIoTClient 23:1111ee8bcba4 154 LogError("Sending SASL header failed");
AzureIoTClient 19:000ab4e6a2c1 155 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 156 }
AzureIoTClient 6:641a9672db08 157 else
AzureIoTClient 6:641a9672db08 158 {
AzureIoTClient 6:641a9672db08 159 if (sasl_client_io_instance->is_trace_on == 1)
AzureIoTClient 6:641a9672db08 160 {
AzureIoTClient 16:22a72cf8e416 161 LOG(AZ_LOG_TRACE, LOG_LINE, "-> Header (AMQP 3.1.0.0)");
AzureIoTClient 6:641a9672db08 162 }
AzureIoTClient 23:1111ee8bcba4 163
AzureIoTClient 6:641a9672db08 164 result = 0;
AzureIoTClient 6:641a9672db08 165 }
Azure.IoT Build 0:6ae2f7bca550 166
AzureIoTClient 6:641a9672db08 167 return result;
Azure.IoT Build 0:6ae2f7bca550 168 }
Azure.IoT Build 0:6ae2f7bca550 169
Azure.IoT Build 0:6ae2f7bca550 170 static void on_underlying_io_open_complete(void* context, IO_OPEN_RESULT open_result)
Azure.IoT Build 0:6ae2f7bca550 171 {
AzureIoTClient 6:641a9672db08 172 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context;
Azure.IoT Build 0:6ae2f7bca550 173
AzureIoTClient 6:641a9672db08 174 switch (sasl_client_io_instance->io_state)
AzureIoTClient 6:641a9672db08 175 {
AzureIoTClient 6:641a9672db08 176 default:
AzureIoTClient 23:1111ee8bcba4 177 LogError("Open complete received in unexpected state");
AzureIoTClient 6:641a9672db08 178 break;
Azure.IoT Build 0:6ae2f7bca550 179
AzureIoTClient 6:641a9672db08 180 case IO_STATE_OPENING_UNDERLYING_IO:
AzureIoTClient 6:641a9672db08 181 if (open_result == IO_OPEN_OK)
AzureIoTClient 6:641a9672db08 182 {
AzureIoTClient 6:641a9672db08 183 sasl_client_io_instance->io_state = IO_STATE_SASL_HANDSHAKE;
AzureIoTClient 6:641a9672db08 184 if (sasl_client_io_instance->sasl_header_exchange_state != SASL_HEADER_EXCHANGE_IDLE)
AzureIoTClient 6:641a9672db08 185 {
AzureIoTClient 6:641a9672db08 186 /* Codes_SRS_SASLCLIENTIO_01_116: [Any underlying IO state changes to state OPEN after the header exchange has been started shall trigger no action.] */
AzureIoTClient 6:641a9672db08 187 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 188 }
AzureIoTClient 6:641a9672db08 189 else
AzureIoTClient 6:641a9672db08 190 {
AzureIoTClient 6:641a9672db08 191 /* Codes_SRS_SASLCLIENTIO_01_105: [start header exchange] */
AzureIoTClient 6:641a9672db08 192 /* Codes_SRS_SASLCLIENTIO_01_001: [To establish a SASL layer, each peer MUST start by sending a protocol header.] */
AzureIoTClient 6:641a9672db08 193 if (send_sasl_header(sasl_client_io_instance) != 0)
AzureIoTClient 6:641a9672db08 194 {
AzureIoTClient 6:641a9672db08 195 /* Codes_SRS_SASLCLIENTIO_01_073: [If the handshake fails (i.e. the outcome is an error) the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 6:641a9672db08 196 /* Codes_SRS_SASLCLIENTIO_01_077: [If sending the SASL header fails, the SASL client IO state shall be set to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 6:641a9672db08 197 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 198 }
AzureIoTClient 6:641a9672db08 199 else
AzureIoTClient 6:641a9672db08 200 {
AzureIoTClient 6:641a9672db08 201 sasl_client_io_instance->sasl_header_exchange_state = SASL_HEADER_EXCHANGE_HEADER_SENT;
AzureIoTClient 6:641a9672db08 202 }
AzureIoTClient 6:641a9672db08 203 }
AzureIoTClient 6:641a9672db08 204 }
AzureIoTClient 6:641a9672db08 205 else
AzureIoTClient 6:641a9672db08 206 {
AzureIoTClient 6:641a9672db08 207 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 208 }
Azure.IoT Build 0:6ae2f7bca550 209
AzureIoTClient 6:641a9672db08 210 break;
AzureIoTClient 6:641a9672db08 211 }
Azure.IoT Build 0:6ae2f7bca550 212 }
Azure.IoT Build 0:6ae2f7bca550 213
Azure.IoT Build 0:6ae2f7bca550 214 static void on_underlying_io_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 215 {
AzureIoTClient 6:641a9672db08 216 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context;
Azure.IoT Build 0:6ae2f7bca550 217
AzureIoTClient 6:641a9672db08 218 switch (sasl_client_io_instance->io_state)
AzureIoTClient 6:641a9672db08 219 {
AzureIoTClient 6:641a9672db08 220 default:
AzureIoTClient 23:1111ee8bcba4 221 LogError("Error callback received in unexpected state");
AzureIoTClient 6:641a9672db08 222 break;
Azure.IoT Build 0:6ae2f7bca550 223
AzureIoTClient 6:641a9672db08 224 case IO_STATE_OPENING_UNDERLYING_IO:
AzureIoTClient 6:641a9672db08 225 case IO_STATE_SASL_HANDSHAKE:
AzureIoTClient 6:641a9672db08 226 sasl_client_io_instance->io_state = IO_STATE_NOT_OPEN;
AzureIoTClient 6:641a9672db08 227 indicate_open_complete(sasl_client_io_instance, IO_OPEN_ERROR);
AzureIoTClient 6:641a9672db08 228 break;
Azure.IoT Build 0:6ae2f7bca550 229
AzureIoTClient 6:641a9672db08 230 case IO_STATE_OPEN:
AzureIoTClient 6:641a9672db08 231 sasl_client_io_instance->io_state = IO_STATE_ERROR;
AzureIoTClient 6:641a9672db08 232 indicate_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 233 break;
AzureIoTClient 6:641a9672db08 234 }
Azure.IoT Build 0:6ae2f7bca550 235 }
Azure.IoT Build 0:6ae2f7bca550 236
Azure.IoT Build 0:6ae2f7bca550 237 static const char* get_frame_type_as_string(AMQP_VALUE descriptor)
Azure.IoT Build 0:6ae2f7bca550 238 {
AzureIoTClient 6:641a9672db08 239 const char* result;
Azure.IoT Build 0:6ae2f7bca550 240
AzureIoTClient 6:641a9672db08 241 if (is_sasl_mechanisms_type_by_descriptor(descriptor))
AzureIoTClient 6:641a9672db08 242 {
AzureIoTClient 6:641a9672db08 243 result = "[SASL MECHANISMS]";
AzureIoTClient 6:641a9672db08 244 }
AzureIoTClient 6:641a9672db08 245 else if (is_sasl_init_type_by_descriptor(descriptor))
AzureIoTClient 6:641a9672db08 246 {
AzureIoTClient 6:641a9672db08 247 result = "[SASL INIT]";
AzureIoTClient 6:641a9672db08 248 }
AzureIoTClient 6:641a9672db08 249 else if (is_sasl_challenge_type_by_descriptor(descriptor))
AzureIoTClient 6:641a9672db08 250 {
AzureIoTClient 6:641a9672db08 251 result = "[SASL CHALLENGE]";
AzureIoTClient 6:641a9672db08 252 }
AzureIoTClient 6:641a9672db08 253 else if (is_sasl_response_type_by_descriptor(descriptor))
AzureIoTClient 6:641a9672db08 254 {
AzureIoTClient 6:641a9672db08 255 result = "[SASL RESPONSE]";
AzureIoTClient 6:641a9672db08 256 }
AzureIoTClient 6:641a9672db08 257 else if (is_sasl_outcome_type_by_descriptor(descriptor))
AzureIoTClient 6:641a9672db08 258 {
AzureIoTClient 6:641a9672db08 259 result = "[SASL OUTCOME]";
AzureIoTClient 6:641a9672db08 260 }
AzureIoTClient 6:641a9672db08 261 else
AzureIoTClient 6:641a9672db08 262 {
AzureIoTClient 6:641a9672db08 263 result = "[Unknown]";
AzureIoTClient 6:641a9672db08 264 }
Azure.IoT Build 0:6ae2f7bca550 265
AzureIoTClient 6:641a9672db08 266 return result;
Azure.IoT Build 0:6ae2f7bca550 267 }
Azure.IoT Build 0:6ae2f7bca550 268
AzureIoTClient 6:641a9672db08 269 static void log_incoming_frame(AMQP_VALUE performative)
Azure.IoT Build 0:6ae2f7bca550 270 {
AzureIoTClient 9:c22db038556c 271 #ifdef NO_LOGGING
AzureIoTClient 9:c22db038556c 272 UNUSED(performative);
AzureIoTClient 9:c22db038556c 273 #else
AzureIoTClient 6:641a9672db08 274 if (xlogging_get_log_function() != NULL)
AzureIoTClient 6:641a9672db08 275 {
AzureIoTClient 6:641a9672db08 276 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
AzureIoTClient 6:641a9672db08 277 if (descriptor != NULL)
AzureIoTClient 6:641a9672db08 278 {
AzureIoTClient 25:1101516ee67d 279 char* performative_as_string;
AzureIoTClient 16:22a72cf8e416 280 LOG(AZ_LOG_TRACE, 0, "<- ");
AzureIoTClient 16:22a72cf8e416 281 LOG(AZ_LOG_TRACE, 0, (char*)get_frame_type_as_string(descriptor));
AzureIoTClient 25:1101516ee67d 282 performative_as_string = NULL;
AzureIoTClient 16:22a72cf8e416 283 LOG(AZ_LOG_TRACE, LOG_LINE, (performative_as_string = amqpvalue_to_string(performative)));
AzureIoTClient 6:641a9672db08 284 if (performative_as_string != NULL)
AzureIoTClient 6:641a9672db08 285 {
AzureIoTClient 21:f9c433d8e6ca 286 free(performative_as_string);
AzureIoTClient 6:641a9672db08 287 }
AzureIoTClient 6:641a9672db08 288 }
AzureIoTClient 6:641a9672db08 289 }
AzureIoTClient 9:c22db038556c 290 #endif
Azure.IoT Build 0:6ae2f7bca550 291 }
Azure.IoT Build 0:6ae2f7bca550 292
AzureIoTClient 6:641a9672db08 293 static void log_outgoing_frame(AMQP_VALUE performative)
Azure.IoT Build 0:6ae2f7bca550 294 {
AzureIoTClient 9:c22db038556c 295 #ifdef NO_LOGGING
AzureIoTClient 9:c22db038556c 296 UNUSED(performative);
AzureIoTClient 9:c22db038556c 297 #else
AzureIoTClient 6:641a9672db08 298 if (xlogging_get_log_function() != NULL)
AzureIoTClient 6:641a9672db08 299 {
AzureIoTClient 6:641a9672db08 300 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
AzureIoTClient 6:641a9672db08 301 if (descriptor != NULL)
AzureIoTClient 6:641a9672db08 302 {
AzureIoTClient 25:1101516ee67d 303 char* performative_as_string;
AzureIoTClient 16:22a72cf8e416 304 LOG(AZ_LOG_TRACE, 0, "-> ");
AzureIoTClient 16:22a72cf8e416 305 LOG(AZ_LOG_TRACE, 0, (char*)get_frame_type_as_string(descriptor));
AzureIoTClient 25:1101516ee67d 306 performative_as_string = NULL;
AzureIoTClient 16:22a72cf8e416 307 LOG(AZ_LOG_TRACE, LOG_LINE, (performative_as_string = amqpvalue_to_string(performative)));
AzureIoTClient 6:641a9672db08 308 if (performative_as_string != NULL)
AzureIoTClient 6:641a9672db08 309 {
AzureIoTClient 21:f9c433d8e6ca 310 free(performative_as_string);
AzureIoTClient 6:641a9672db08 311 }
AzureIoTClient 6:641a9672db08 312 }
AzureIoTClient 6:641a9672db08 313 }
AzureIoTClient 9:c22db038556c 314 #endif
Azure.IoT Build 0:6ae2f7bca550 315 }
Azure.IoT Build 0:6ae2f7bca550 316
Azure.IoT Build 0:6ae2f7bca550 317 static int saslclientio_receive_byte(SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance, unsigned char b)
Azure.IoT Build 0:6ae2f7bca550 318 {
AzureIoTClient 6:641a9672db08 319 int result;
Azure.IoT Build 0:6ae2f7bca550 320
AzureIoTClient 6:641a9672db08 321 switch (sasl_client_io_instance->sasl_header_exchange_state)
AzureIoTClient 6:641a9672db08 322 {
AzureIoTClient 6:641a9672db08 323 default:
AzureIoTClient 23:1111ee8bcba4 324 LogError("Byte being received in unexpected state: %s", ENUM_TO_STRING(SASL_HEADER_EXCHANGE_STATE, sasl_client_io_instance->sasl_header_exchange_state));
AzureIoTClient 19:000ab4e6a2c1 325 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 326 break;
Azure.IoT Build 0:6ae2f7bca550 327
AzureIoTClient 6:641a9672db08 328 case SASL_HEADER_EXCHANGE_HEADER_EXCH:
AzureIoTClient 6:641a9672db08 329 switch (sasl_client_io_instance->sasl_client_negotiation_state)
AzureIoTClient 6:641a9672db08 330 {
AzureIoTClient 6:641a9672db08 331 case SASL_CLIENT_NEGOTIATION_ERROR:
AzureIoTClient 23:1111ee8bcba4 332 LogError("Byte being received in unexpected state: %s", ENUM_TO_STRING(SASL_CLIENT_NEGOTIATION_STATE, SASL_CLIENT_NEGOTIATION_ERROR));
AzureIoTClient 19:000ab4e6a2c1 333 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 334 break;
Azure.IoT Build 0:6ae2f7bca550 335
AzureIoTClient 6:641a9672db08 336 default:
AzureIoTClient 6:641a9672db08 337 /* Codes_SRS_SASLCLIENTIO_01_068: [During the SASL frame exchange that constitutes the handshake the received bytes from the underlying IO shall be fed to the frame_codec instance created in saslclientio_create by calling frame_codec_receive_bytes.] */
AzureIoTClient 6:641a9672db08 338 if (frame_codec_receive_bytes(sasl_client_io_instance->frame_codec, &b, 1) != 0)
AzureIoTClient 6:641a9672db08 339 {
AzureIoTClient 6:641a9672db08 340 /* Codes_SRS_SASLCLIENTIO_01_088: [If frame_codec_receive_bytes fails, the state of SASL client IO shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 19:000ab4e6a2c1 341 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 342 }
AzureIoTClient 6:641a9672db08 343 else
AzureIoTClient 6:641a9672db08 344 {
AzureIoTClient 6:641a9672db08 345 result = 0;
AzureIoTClient 6:641a9672db08 346 }
Azure.IoT Build 0:6ae2f7bca550 347
AzureIoTClient 6:641a9672db08 348 break;
Azure.IoT Build 0:6ae2f7bca550 349
AzureIoTClient 6:641a9672db08 350 case SASL_CLIENT_NEGOTIATION_OUTCOME_RCVD:
AzureIoTClient 6:641a9672db08 351 sasl_client_io_instance->on_bytes_received(sasl_client_io_instance->on_bytes_received_context, &b, 1);
AzureIoTClient 6:641a9672db08 352 result = 0;
AzureIoTClient 6:641a9672db08 353 break;
AzureIoTClient 6:641a9672db08 354 }
Azure.IoT Build 0:6ae2f7bca550 355
AzureIoTClient 6:641a9672db08 356 break;
Azure.IoT Build 0:6ae2f7bca550 357
AzureIoTClient 6:641a9672db08 358 /* Codes_SRS_SASLCLIENTIO_01_003: [Other than using a protocol id of three, the exchange of SASL layer headers follows the same rules specified in the version negotiation section of the transport specification (See Part 2: section 2.2).] */
AzureIoTClient 6:641a9672db08 359 case SASL_HEADER_EXCHANGE_IDLE:
AzureIoTClient 6:641a9672db08 360 case SASL_HEADER_EXCHANGE_HEADER_SENT:
AzureIoTClient 6:641a9672db08 361 if (b != sasl_header[sasl_client_io_instance->header_bytes_received])
AzureIoTClient 6:641a9672db08 362 {
AzureIoTClient 23:1111ee8bcba4 363 LogError("Mismatched SASL header");
AzureIoTClient 19:000ab4e6a2c1 364 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 365 }
AzureIoTClient 6:641a9672db08 366 else
AzureIoTClient 6:641a9672db08 367 {
AzureIoTClient 6:641a9672db08 368 sasl_client_io_instance->header_bytes_received++;
AzureIoTClient 6:641a9672db08 369 if (sasl_client_io_instance->header_bytes_received == sizeof(sasl_header))
AzureIoTClient 6:641a9672db08 370 {
AzureIoTClient 6:641a9672db08 371 if (sasl_client_io_instance->is_trace_on == 1)
AzureIoTClient 6:641a9672db08 372 {
AzureIoTClient 16:22a72cf8e416 373 LOG(AZ_LOG_TRACE, LOG_LINE, "<- Header (AMQP 3.1.0.0)");
AzureIoTClient 6:641a9672db08 374 }
Azure.IoT Build 0:6ae2f7bca550 375
AzureIoTClient 6:641a9672db08 376 switch (sasl_client_io_instance->sasl_header_exchange_state)
AzureIoTClient 6:641a9672db08 377 {
AzureIoTClient 6:641a9672db08 378 default:
AzureIoTClient 23:1111ee8bcba4 379 LogError("Invalid SASL header exchange state: %s", ENUM_TO_STRING(SASL_HEADER_EXCHANGE_STATE, sasl_client_io_instance->sasl_header_exchange_state));
AzureIoTClient 19:000ab4e6a2c1 380 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 381 break;
AzureIoTClient 6:641a9672db08 382
AzureIoTClient 6:641a9672db08 383 case SASL_HEADER_EXCHANGE_HEADER_SENT:
AzureIoTClient 6:641a9672db08 384 /* from this point on we need to decode SASL frames */
AzureIoTClient 6:641a9672db08 385 sasl_client_io_instance->sasl_header_exchange_state = SASL_HEADER_EXCHANGE_HEADER_EXCH;
AzureIoTClient 6:641a9672db08 386 result = 0;
AzureIoTClient 6:641a9672db08 387 break;
Azure.IoT Build 0:6ae2f7bca550 388
AzureIoTClient 6:641a9672db08 389 case SASL_HEADER_EXCHANGE_IDLE:
AzureIoTClient 6:641a9672db08 390 sasl_client_io_instance->sasl_header_exchange_state = SASL_HEADER_EXCHANGE_HEADER_RCVD;
AzureIoTClient 6:641a9672db08 391 if (send_sasl_header(sasl_client_io_instance) != 0)
AzureIoTClient 6:641a9672db08 392 {
AzureIoTClient 6:641a9672db08 393 /* Codes_SRS_SASLCLIENTIO_01_077: [If sending the SASL header fails, the SASL client IO state shall be set to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 394 LogError("Could not send SASL header");
AzureIoTClient 19:000ab4e6a2c1 395 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 396 }
AzureIoTClient 6:641a9672db08 397 else
AzureIoTClient 6:641a9672db08 398 {
AzureIoTClient 6:641a9672db08 399 result = 0;
AzureIoTClient 6:641a9672db08 400 }
Azure.IoT Build 0:6ae2f7bca550 401
AzureIoTClient 6:641a9672db08 402 break;
AzureIoTClient 6:641a9672db08 403 }
AzureIoTClient 6:641a9672db08 404 }
AzureIoTClient 6:641a9672db08 405 else
AzureIoTClient 6:641a9672db08 406 {
AzureIoTClient 6:641a9672db08 407 result = 0;
AzureIoTClient 6:641a9672db08 408 }
AzureIoTClient 6:641a9672db08 409 }
Azure.IoT Build 0:6ae2f7bca550 410
AzureIoTClient 6:641a9672db08 411 break;
AzureIoTClient 6:641a9672db08 412 }
AzureIoTClient 6:641a9672db08 413
AzureIoTClient 6:641a9672db08 414 return result;
Azure.IoT Build 0:6ae2f7bca550 415 }
Azure.IoT Build 0:6ae2f7bca550 416
Azure.IoT Build 0:6ae2f7bca550 417 static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size)
Azure.IoT Build 0:6ae2f7bca550 418 {
AzureIoTClient 6:641a9672db08 419 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context;
Azure.IoT Build 0:6ae2f7bca550 420
AzureIoTClient 6:641a9672db08 421 /* Codes_SRS_SASLCLIENTIO_01_028: [If buffer is NULL or size is zero, nothing should be indicated as received and the saslio state shall be switched to ERROR the on_state_changed callback shall be triggered.] */
AzureIoTClient 6:641a9672db08 422 if ((buffer == NULL) ||
AzureIoTClient 6:641a9672db08 423 (size == 0))
AzureIoTClient 6:641a9672db08 424 {
AzureIoTClient 23:1111ee8bcba4 425 LogError("Bad buffer received from the underlying IO, buffer = %p, size = %u",
AzureIoTClient 23:1111ee8bcba4 426 buffer, (unsigned int)size);
AzureIoTClient 6:641a9672db08 427 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 428 }
AzureIoTClient 6:641a9672db08 429 else
AzureIoTClient 6:641a9672db08 430 {
AzureIoTClient 6:641a9672db08 431 switch (sasl_client_io_instance->io_state)
AzureIoTClient 6:641a9672db08 432 {
AzureIoTClient 6:641a9672db08 433 default:
AzureIoTClient 6:641a9672db08 434 break;
Azure.IoT Build 0:6ae2f7bca550 435
AzureIoTClient 6:641a9672db08 436 case IO_STATE_OPEN:
AzureIoTClient 6:641a9672db08 437 /* Codes_SRS_SASLCLIENTIO_01_027: [When the on_bytes_received callback passed to the underlying IO is called and the SASL client IO state is IO_STATE_OPEN, the bytes shall be indicated to the user of SASL client IO by calling the on_bytes_received that was passed in saslclientio_open.] */
AzureIoTClient 6:641a9672db08 438 /* Codes_SRS_SASLCLIENTIO_01_029: [The context argument shall be set to the callback_context passed in saslclientio_open.] */
AzureIoTClient 6:641a9672db08 439 sasl_client_io_instance->on_bytes_received(sasl_client_io_instance->on_bytes_received_context, buffer, size);
AzureIoTClient 6:641a9672db08 440 break;
Azure.IoT Build 0:6ae2f7bca550 441
AzureIoTClient 6:641a9672db08 442 case IO_STATE_SASL_HANDSHAKE:
AzureIoTClient 6:641a9672db08 443 {
AzureIoTClient 6:641a9672db08 444 size_t i;
Azure.IoT Build 0:6ae2f7bca550 445
AzureIoTClient 6:641a9672db08 446 for (i = 0; i < size; i++)
AzureIoTClient 6:641a9672db08 447 {
AzureIoTClient 6:641a9672db08 448 if (saslclientio_receive_byte(sasl_client_io_instance, buffer[i]) != 0)
AzureIoTClient 6:641a9672db08 449 {
AzureIoTClient 6:641a9672db08 450 break;
AzureIoTClient 6:641a9672db08 451 }
AzureIoTClient 6:641a9672db08 452 }
Azure.IoT Build 0:6ae2f7bca550 453
AzureIoTClient 6:641a9672db08 454 if (i < size)
AzureIoTClient 6:641a9672db08 455 {
AzureIoTClient 6:641a9672db08 456 /* Codes_SRS_SASLCLIENTIO_01_073: [If the handshake fails (i.e. the outcome is an error) the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 6:641a9672db08 457 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 458 }
Azure.IoT Build 0:6ae2f7bca550 459
AzureIoTClient 6:641a9672db08 460 break;
AzureIoTClient 6:641a9672db08 461 }
Azure.IoT Build 0:6ae2f7bca550 462
AzureIoTClient 6:641a9672db08 463 case IO_STATE_ERROR:
AzureIoTClient 6:641a9672db08 464 /* Codes_SRS_SASLCLIENTIO_01_031: [If bytes are received when the SASL client IO state is IO_STATE_ERROR, SASL client IO shall do nothing.] */
AzureIoTClient 6:641a9672db08 465 break;
AzureIoTClient 6:641a9672db08 466 }
AzureIoTClient 6:641a9672db08 467 }
Azure.IoT Build 0:6ae2f7bca550 468 }
Azure.IoT Build 0:6ae2f7bca550 469
Azure.IoT Build 0:6ae2f7bca550 470 static void on_bytes_encoded(void* context, const unsigned char* bytes, size_t length, bool encode_complete)
Azure.IoT Build 0:6ae2f7bca550 471 {
AzureIoTClient 25:1101516ee67d 472 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context;
Azure.IoT Build 0:6ae2f7bca550 473
AzureIoTClient 25:1101516ee67d 474 (void)encode_complete;
Azure.IoT Build 0:6ae2f7bca550 475
AzureIoTClient 6:641a9672db08 476 /* Codes_SRS_SASLCLIENTIO_01_120: [When SASL client IO is notified by sasl_frame_codec of bytes that have been encoded via the on_bytes_encoded callback and SASL client IO is in the state OPENING, SASL client IO shall send these bytes by using xio_send.] */
AzureIoTClient 6:641a9672db08 477 if (xio_send(sasl_client_io_instance->underlying_io, bytes, length, NULL, NULL) != 0)
AzureIoTClient 6:641a9672db08 478 {
AzureIoTClient 6:641a9672db08 479 /* Codes_SRS_SASLCLIENTIO_01_121: [If xio_send fails, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 480 LogError("xio_send failed");
AzureIoTClient 6:641a9672db08 481 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 482 }
Azure.IoT Build 0:6ae2f7bca550 483 }
Azure.IoT Build 0:6ae2f7bca550 484
Azure.IoT Build 0:6ae2f7bca550 485 static int send_sasl_init(SASL_CLIENT_IO_INSTANCE* sasl_client_io, const char* sasl_mechanism_name)
Azure.IoT Build 0:6ae2f7bca550 486 {
AzureIoTClient 6:641a9672db08 487 int result;
Azure.IoT Build 0:6ae2f7bca550 488
AzureIoTClient 6:641a9672db08 489 SASL_INIT_HANDLE sasl_init;
AzureIoTClient 6:641a9672db08 490 SASL_MECHANISM_BYTES init_bytes;
Azure.IoT Build 0:6ae2f7bca550 491
AzureIoTClient 6:641a9672db08 492 /* Codes_SRS_SASLCLIENTIO_01_045: [The name of the SASL mechanism used for the SASL exchange.] */
AzureIoTClient 6:641a9672db08 493 sasl_init = sasl_init_create(sasl_mechanism_name);
AzureIoTClient 6:641a9672db08 494 if (sasl_init == NULL)
AzureIoTClient 6:641a9672db08 495 {
AzureIoTClient 6:641a9672db08 496 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 497 LogError("Could not create sasl_init");
AzureIoTClient 19:000ab4e6a2c1 498 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 499 }
AzureIoTClient 6:641a9672db08 500 else
AzureIoTClient 6:641a9672db08 501 {
AzureIoTClient 6:641a9672db08 502 /* Codes_SRS_SASLCLIENTIO_01_048: [The contents of this data are defined by the SASL security mechanism.] */
AzureIoTClient 6:641a9672db08 503 if (saslmechanism_get_init_bytes(sasl_client_io->sasl_mechanism, &init_bytes) != 0)
AzureIoTClient 6:641a9672db08 504 {
AzureIoTClient 6:641a9672db08 505 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 506 LogError("Could not get SASL init bytes");
AzureIoTClient 19:000ab4e6a2c1 507 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 508 }
AzureIoTClient 6:641a9672db08 509 else
AzureIoTClient 6:641a9672db08 510 {
AzureIoTClient 6:641a9672db08 511 amqp_binary creds;
AzureIoTClient 6:641a9672db08 512 creds.bytes = init_bytes.bytes;
AzureIoTClient 6:641a9672db08 513 creds.length = init_bytes.length;
AzureIoTClient 6:641a9672db08 514 if ((init_bytes.length > 0) &&
AzureIoTClient 6:641a9672db08 515 /* Codes_SRS_SASLCLIENTIO_01_047: [A block of opaque data passed to the security mechanism.] */
AzureIoTClient 6:641a9672db08 516 (sasl_init_set_initial_response(sasl_init, creds) != 0))
AzureIoTClient 6:641a9672db08 517 {
AzureIoTClient 6:641a9672db08 518 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 519 LogError("Could not set initial response");
AzureIoTClient 19:000ab4e6a2c1 520 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 521 }
AzureIoTClient 6:641a9672db08 522 else
AzureIoTClient 6:641a9672db08 523 {
AzureIoTClient 6:641a9672db08 524 AMQP_VALUE sasl_init_value = amqpvalue_create_sasl_init(sasl_init);
AzureIoTClient 6:641a9672db08 525 if (sasl_init_value == NULL)
AzureIoTClient 6:641a9672db08 526 {
AzureIoTClient 6:641a9672db08 527 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 528 LogError("Could not create SASL init");
AzureIoTClient 19:000ab4e6a2c1 529 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 530 }
AzureIoTClient 6:641a9672db08 531 else
AzureIoTClient 6:641a9672db08 532 {
AzureIoTClient 6:641a9672db08 533 /* Codes_SRS_SASLCLIENTIO_01_070: [When a frame needs to be sent as part of the SASL handshake frame exchange, the send shall be done by calling sasl_frame_codec_encode_frame.] */
AzureIoTClient 6:641a9672db08 534 if (sasl_frame_codec_encode_frame(sasl_client_io->sasl_frame_codec, sasl_init_value, on_bytes_encoded, sasl_client_io) != 0)
AzureIoTClient 6:641a9672db08 535 {
AzureIoTClient 6:641a9672db08 536 /* Codes_SRS_SASLCLIENTIO_01_071: [If sasl_frame_codec_encode_frame fails, then the state of SASL client IO shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 537 LogError("Could not encode SASL init value");
AzureIoTClient 19:000ab4e6a2c1 538 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 539 }
AzureIoTClient 6:641a9672db08 540 else
AzureIoTClient 6:641a9672db08 541 {
AzureIoTClient 6:641a9672db08 542 if (sasl_client_io->is_trace_on == 1)
AzureIoTClient 6:641a9672db08 543 {
AzureIoTClient 6:641a9672db08 544 log_outgoing_frame(sasl_init_value);
AzureIoTClient 6:641a9672db08 545 }
Azure.IoT Build 0:6ae2f7bca550 546
AzureIoTClient 6:641a9672db08 547 result = 0;
AzureIoTClient 6:641a9672db08 548 }
Azure.IoT Build 0:6ae2f7bca550 549
AzureIoTClient 6:641a9672db08 550 amqpvalue_destroy(sasl_init_value);
AzureIoTClient 6:641a9672db08 551 }
AzureIoTClient 6:641a9672db08 552 }
AzureIoTClient 6:641a9672db08 553 }
Azure.IoT Build 0:6ae2f7bca550 554
AzureIoTClient 6:641a9672db08 555 sasl_init_destroy(sasl_init);
AzureIoTClient 6:641a9672db08 556 }
Azure.IoT Build 0:6ae2f7bca550 557
AzureIoTClient 6:641a9672db08 558 return result;
Azure.IoT Build 0:6ae2f7bca550 559 }
Azure.IoT Build 0:6ae2f7bca550 560
Azure.IoT Build 0:6ae2f7bca550 561 static int send_sasl_response(SASL_CLIENT_IO_INSTANCE* sasl_client_io, SASL_MECHANISM_BYTES sasl_response)
Azure.IoT Build 0:6ae2f7bca550 562 {
AzureIoTClient 6:641a9672db08 563 int result;
Azure.IoT Build 0:6ae2f7bca550 564
AzureIoTClient 6:641a9672db08 565 SASL_RESPONSE_HANDLE sasl_response_handle;
AzureIoTClient 6:641a9672db08 566 amqp_binary response_binary_value;
AzureIoTClient 6:641a9672db08 567
AzureIoTClient 6:641a9672db08 568 response_binary_value.bytes = sasl_response.bytes;
AzureIoTClient 6:641a9672db08 569 response_binary_value.length = sasl_response.length;
Azure.IoT Build 0:6ae2f7bca550 570
AzureIoTClient 6:641a9672db08 571 /* Codes_SRS_SASLCLIENTIO_01_055: [Send the SASL response data as defined by the SASL specification.] */
AzureIoTClient 6:641a9672db08 572 /* Codes_SRS_SASLCLIENTIO_01_056: [A block of opaque data passed to the security mechanism.] */
AzureIoTClient 6:641a9672db08 573 if ((sasl_response_handle = sasl_response_create(response_binary_value)) == NULL)
AzureIoTClient 6:641a9672db08 574 {
AzureIoTClient 23:1111ee8bcba4 575 LogError("Could not create SASL response");
AzureIoTClient 19:000ab4e6a2c1 576 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 577 }
AzureIoTClient 6:641a9672db08 578 else
AzureIoTClient 6:641a9672db08 579 {
AzureIoTClient 6:641a9672db08 580 AMQP_VALUE sasl_response_value = amqpvalue_create_sasl_response(sasl_response_handle);
AzureIoTClient 6:641a9672db08 581 if (sasl_response_value == NULL)
AzureIoTClient 6:641a9672db08 582 {
AzureIoTClient 23:1111ee8bcba4 583 LogError("Could not create SASL response AMQP value");
AzureIoTClient 19:000ab4e6a2c1 584 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 585 }
AzureIoTClient 6:641a9672db08 586 else
AzureIoTClient 6:641a9672db08 587 {
AzureIoTClient 6:641a9672db08 588 /* Codes_SRS_SASLCLIENTIO_01_070: [When a frame needs to be sent as part of the SASL handshake frame exchange, the send shall be done by calling sasl_frame_codec_encode_frame.] */
AzureIoTClient 6:641a9672db08 589 if (sasl_frame_codec_encode_frame(sasl_client_io->sasl_frame_codec, sasl_response_value, on_bytes_encoded, sasl_client_io) != 0)
AzureIoTClient 6:641a9672db08 590 {
AzureIoTClient 23:1111ee8bcba4 591 LogError("Could not encode SASL response in the frame");
AzureIoTClient 19:000ab4e6a2c1 592 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 593 }
AzureIoTClient 6:641a9672db08 594 else
AzureIoTClient 6:641a9672db08 595 {
AzureIoTClient 6:641a9672db08 596 if (sasl_client_io->is_trace_on == 1)
AzureIoTClient 6:641a9672db08 597 {
AzureIoTClient 6:641a9672db08 598 log_outgoing_frame(sasl_response_value);
AzureIoTClient 6:641a9672db08 599 }
AzureIoTClient 23:1111ee8bcba4 600
AzureIoTClient 6:641a9672db08 601 result = 0;
AzureIoTClient 6:641a9672db08 602 }
Azure.IoT Build 0:6ae2f7bca550 603
AzureIoTClient 6:641a9672db08 604 amqpvalue_destroy(sasl_response_value);
AzureIoTClient 6:641a9672db08 605 }
Azure.IoT Build 0:6ae2f7bca550 606
AzureIoTClient 6:641a9672db08 607 sasl_response_destroy(sasl_response_handle);
AzureIoTClient 6:641a9672db08 608 }
Azure.IoT Build 0:6ae2f7bca550 609
AzureIoTClient 6:641a9672db08 610 return result;
Azure.IoT Build 0:6ae2f7bca550 611 }
Azure.IoT Build 0:6ae2f7bca550 612
Azure.IoT Build 0:6ae2f7bca550 613 static void sasl_frame_received_callback(void* context, AMQP_VALUE sasl_frame)
Azure.IoT Build 0:6ae2f7bca550 614 {
AzureIoTClient 6:641a9672db08 615 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context;
Azure.IoT Build 0:6ae2f7bca550 616
AzureIoTClient 6:641a9672db08 617 /* Codes_SRS_SASLCLIENTIO_01_067: [The SASL frame exchange shall be started as soon as the SASL header handshake is done.] */
AzureIoTClient 6:641a9672db08 618 switch (sasl_client_io_instance->io_state)
AzureIoTClient 6:641a9672db08 619 {
AzureIoTClient 6:641a9672db08 620 default:
AzureIoTClient 23:1111ee8bcba4 621 LogError("SASL frame received while in state %d", (int)sasl_client_io_instance->io_state);
AzureIoTClient 6:641a9672db08 622 break;
Azure.IoT Build 0:6ae2f7bca550 623
AzureIoTClient 6:641a9672db08 624 case IO_STATE_OPEN:
AzureIoTClient 6:641a9672db08 625 case IO_STATE_OPENING_UNDERLYING_IO:
AzureIoTClient 6:641a9672db08 626 case IO_STATE_CLOSING:
AzureIoTClient 6:641a9672db08 627 /* Codes_SRS_SASLCLIENTIO_01_117: [If on_sasl_frame_received_callback is called when the state of the IO is OPEN then the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 6:641a9672db08 628 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 629 break;
Azure.IoT Build 0:6ae2f7bca550 630
AzureIoTClient 6:641a9672db08 631 case IO_STATE_SASL_HANDSHAKE:
AzureIoTClient 6:641a9672db08 632 if (sasl_client_io_instance->sasl_header_exchange_state != SASL_HEADER_EXCHANGE_HEADER_EXCH)
AzureIoTClient 6:641a9672db08 633 {
AzureIoTClient 6:641a9672db08 634 /* Codes_SRS_SASLCLIENTIO_01_118: [If on_sasl_frame_received_callback is called in the OPENING state but the header exchange has not yet been completed, then the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 6:641a9672db08 635 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 636 }
AzureIoTClient 6:641a9672db08 637 else
AzureIoTClient 6:641a9672db08 638 {
AzureIoTClient 6:641a9672db08 639 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(sasl_frame);
AzureIoTClient 6:641a9672db08 640 if (descriptor == NULL)
AzureIoTClient 6:641a9672db08 641 {
AzureIoTClient 6:641a9672db08 642 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 643 LogError("Could not obtain SASL frame descriptor");
AzureIoTClient 6:641a9672db08 644 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 645 }
AzureIoTClient 6:641a9672db08 646 else
AzureIoTClient 6:641a9672db08 647 {
AzureIoTClient 6:641a9672db08 648 if (sasl_client_io_instance->is_trace_on == 1)
AzureIoTClient 6:641a9672db08 649 {
AzureIoTClient 6:641a9672db08 650 log_incoming_frame(sasl_frame);
AzureIoTClient 6:641a9672db08 651 }
Azure.IoT Build 0:6ae2f7bca550 652
AzureIoTClient 6:641a9672db08 653 /* Codes_SRS_SASLCLIENTIO_01_032: [The peer acting as the SASL server MUST announce supported authentication mechanisms using the sasl-mechanisms frame.] */
AzureIoTClient 6:641a9672db08 654 /* Codes_SRS_SASLCLIENTIO_01_040: [The peer playing the role of the SASL client and the peer playing the role of the SASL server MUST correspond to the TCP client and server respectively.] */
AzureIoTClient 6:641a9672db08 655 /* Codes_SRS_SASLCLIENTIO_01_034: [<-- SASL-MECHANISMS] */
AzureIoTClient 6:641a9672db08 656 if (is_sasl_mechanisms_type_by_descriptor(descriptor))
AzureIoTClient 6:641a9672db08 657 {
AzureIoTClient 6:641a9672db08 658 switch (sasl_client_io_instance->sasl_client_negotiation_state)
AzureIoTClient 6:641a9672db08 659 {
AzureIoTClient 17:923575db8b2d 660 default:
AzureIoTClient 23:1111ee8bcba4 661 LogError("SASL mechanisms frame received in %s state", ENUM_TO_STRING(SASL_CLIENT_NEGOTIATION_STATE, sasl_client_io_instance->sasl_client_negotiation_state));
AzureIoTClient 17:923575db8b2d 662 handle_error(sasl_client_io_instance);
AzureIoTClient 17:923575db8b2d 663 break;
AzureIoTClient 17:923575db8b2d 664
AzureIoTClient 6:641a9672db08 665 case SASL_CLIENT_NEGOTIATION_NOT_STARTED:
AzureIoTClient 6:641a9672db08 666 {
AzureIoTClient 6:641a9672db08 667 SASL_MECHANISMS_HANDLE sasl_mechanisms_handle;
Azure.IoT Build 0:6ae2f7bca550 668
AzureIoTClient 6:641a9672db08 669 if (amqpvalue_get_sasl_mechanisms(sasl_frame, &sasl_mechanisms_handle) != 0)
AzureIoTClient 6:641a9672db08 670 {
AzureIoTClient 6:641a9672db08 671 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 672 LogError("Could not get SASL mechanisms");
AzureIoTClient 6:641a9672db08 673 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 674 }
AzureIoTClient 6:641a9672db08 675 else
AzureIoTClient 6:641a9672db08 676 {
AzureIoTClient 6:641a9672db08 677 AMQP_VALUE sasl_server_mechanisms;
AzureIoTClient 6:641a9672db08 678 uint32_t mechanisms_count;
Azure.IoT Build 0:6ae2f7bca550 679
AzureIoTClient 6:641a9672db08 680 if ((sasl_mechanisms_get_sasl_server_mechanisms(sasl_mechanisms_handle, &sasl_server_mechanisms) != 0) ||
AzureIoTClient 6:641a9672db08 681 (amqpvalue_get_array_item_count(sasl_server_mechanisms, &mechanisms_count) != 0) ||
AzureIoTClient 6:641a9672db08 682 (mechanisms_count == 0))
AzureIoTClient 6:641a9672db08 683 {
AzureIoTClient 6:641a9672db08 684 /* Codes_SRS_SASLCLIENTIO_01_042: [It is invalid for this list to be null or empty.] */
AzureIoTClient 23:1111ee8bcba4 685 LogError("Invalid SASL mechanisms list");
AzureIoTClient 6:641a9672db08 686 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 687 }
AzureIoTClient 6:641a9672db08 688 else
AzureIoTClient 6:641a9672db08 689 {
AzureIoTClient 6:641a9672db08 690 const char* sasl_mechanism_name = saslmechanism_get_mechanism_name(sasl_client_io_instance->sasl_mechanism);
AzureIoTClient 6:641a9672db08 691 if (sasl_mechanism_name == NULL)
AzureIoTClient 6:641a9672db08 692 {
AzureIoTClient 6:641a9672db08 693 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 694 LogError("Cannot get the mechanism name");
AzureIoTClient 6:641a9672db08 695 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 696 }
AzureIoTClient 6:641a9672db08 697 else
AzureIoTClient 6:641a9672db08 698 {
AzureIoTClient 6:641a9672db08 699 uint32_t i;
Azure.IoT Build 0:6ae2f7bca550 700
AzureIoTClient 6:641a9672db08 701 for (i = 0; i < mechanisms_count; i++)
AzureIoTClient 6:641a9672db08 702 {
AzureIoTClient 6:641a9672db08 703 AMQP_VALUE sasl_server_mechanism;
AzureIoTClient 6:641a9672db08 704 sasl_server_mechanism = amqpvalue_get_array_item(sasl_server_mechanisms, i);
AzureIoTClient 6:641a9672db08 705 if (sasl_server_mechanism == NULL)
AzureIoTClient 6:641a9672db08 706 {
AzureIoTClient 23:1111ee8bcba4 707 LogError("Cannot get SASL mechanisms array item for index %u", (unsigned int)i);
AzureIoTClient 6:641a9672db08 708 i = mechanisms_count;
AzureIoTClient 6:641a9672db08 709 }
AzureIoTClient 6:641a9672db08 710 else
AzureIoTClient 6:641a9672db08 711 {
AzureIoTClient 6:641a9672db08 712 const char* sasl_server_mechanism_name;
AzureIoTClient 6:641a9672db08 713 if (amqpvalue_get_symbol(sasl_server_mechanism, &sasl_server_mechanism_name) != 0)
AzureIoTClient 6:641a9672db08 714 {
AzureIoTClient 23:1111ee8bcba4 715 LogError("Error getting server SASL mechanism from array item");
AzureIoTClient 6:641a9672db08 716 i = mechanisms_count;
AzureIoTClient 6:641a9672db08 717 }
AzureIoTClient 6:641a9672db08 718 else
AzureIoTClient 6:641a9672db08 719 {
AzureIoTClient 6:641a9672db08 720 if (strcmp(sasl_mechanism_name, sasl_server_mechanism_name) == 0)
AzureIoTClient 6:641a9672db08 721 {
Azure.IoT Build 0:6ae2f7bca550 722 amqpvalue_destroy(sasl_server_mechanism);
Azure.IoT Build 0:6ae2f7bca550 723 break;
AzureIoTClient 6:641a9672db08 724 }
AzureIoTClient 6:641a9672db08 725 }
Azure.IoT Build 0:6ae2f7bca550 726
Azure.IoT Build 0:6ae2f7bca550 727 amqpvalue_destroy(sasl_server_mechanism);
Azure.IoT Build 0:6ae2f7bca550 728 }
AzureIoTClient 6:641a9672db08 729 }
Azure.IoT Build 0:6ae2f7bca550 730
AzureIoTClient 6:641a9672db08 731 if (i == mechanisms_count)
AzureIoTClient 6:641a9672db08 732 {
AzureIoTClient 6:641a9672db08 733 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 734 LogError("Could not find desired SASL mechanism in the list presented by server");
AzureIoTClient 6:641a9672db08 735 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 736 }
AzureIoTClient 6:641a9672db08 737 else
AzureIoTClient 6:641a9672db08 738 {
AzureIoTClient 6:641a9672db08 739 sasl_client_io_instance->sasl_client_negotiation_state = SASL_CLIENT_NEGOTIATION_MECH_RCVD;
Azure.IoT Build 0:6ae2f7bca550 740
AzureIoTClient 6:641a9672db08 741 /* Codes_SRS_SASLCLIENTIO_01_035: [SASL-INIT -->] */
AzureIoTClient 6:641a9672db08 742 /* Codes_SRS_SASLCLIENTIO_01_033: [The partner MUST then choose one of the supported mechanisms and initiate a sasl exchange.] */
AzureIoTClient 6:641a9672db08 743 /* Codes_SRS_SASLCLIENTIO_01_054: [Selects the sasl mechanism and provides the initial response if needed.] */
AzureIoTClient 6:641a9672db08 744 if (send_sasl_init(sasl_client_io_instance, sasl_mechanism_name) != 0)
AzureIoTClient 6:641a9672db08 745 {
AzureIoTClient 6:641a9672db08 746 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 747 LogError("Could not send SASL init");
AzureIoTClient 6:641a9672db08 748 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 749 }
AzureIoTClient 6:641a9672db08 750 else
AzureIoTClient 6:641a9672db08 751 {
AzureIoTClient 6:641a9672db08 752 sasl_client_io_instance->sasl_client_negotiation_state = SASL_CLIENT_NEGOTIATION_INIT_SENT;
AzureIoTClient 6:641a9672db08 753 }
AzureIoTClient 6:641a9672db08 754 }
AzureIoTClient 6:641a9672db08 755 }
AzureIoTClient 6:641a9672db08 756 }
Azure.IoT Build 0:6ae2f7bca550 757
AzureIoTClient 6:641a9672db08 758 sasl_mechanisms_destroy(sasl_mechanisms_handle);
AzureIoTClient 6:641a9672db08 759 }
Azure.IoT Build 0:6ae2f7bca550 760
AzureIoTClient 6:641a9672db08 761 break;
AzureIoTClient 6:641a9672db08 762 }
AzureIoTClient 6:641a9672db08 763 }
AzureIoTClient 6:641a9672db08 764 }
AzureIoTClient 6:641a9672db08 765 /* Codes_SRS_SASLCLIENTIO_01_052: [Send the SASL challenge data as defined by the SASL specification.] */
AzureIoTClient 6:641a9672db08 766 /* Codes_SRS_SASLCLIENTIO_01_036: [<-- SASL-CHALLENGE *] */
AzureIoTClient 6:641a9672db08 767 /* Codes_SRS_SASLCLIENTIO_01_039: [the SASL challenge/response step can occur zero or more times depending on the details of the SASL mechanism chosen.] */
AzureIoTClient 6:641a9672db08 768 else if (is_sasl_challenge_type_by_descriptor(descriptor))
AzureIoTClient 6:641a9672db08 769 {
AzureIoTClient 6:641a9672db08 770 /* Codes_SRS_SASLCLIENTIO_01_032: [The peer acting as the SASL server MUST announce supported authentication mechanisms using the sasl-mechanisms frame.] */
AzureIoTClient 6:641a9672db08 771 if ((sasl_client_io_instance->sasl_client_negotiation_state != SASL_CLIENT_NEGOTIATION_INIT_SENT) &&
AzureIoTClient 6:641a9672db08 772 (sasl_client_io_instance->sasl_client_negotiation_state != SASL_CLIENT_NEGOTIATION_RESPONSE_SENT))
AzureIoTClient 6:641a9672db08 773 {
AzureIoTClient 23:1111ee8bcba4 774 LogError("SASL challenge received in a bad state: %s", ENUM_TO_STRING(SASL_CLIENT_NEGOTIATION_STATE, sasl_client_io_instance->sasl_client_negotiation_state));
AzureIoTClient 6:641a9672db08 775 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 776 }
AzureIoTClient 6:641a9672db08 777 else
AzureIoTClient 6:641a9672db08 778 {
AzureIoTClient 6:641a9672db08 779 SASL_CHALLENGE_HANDLE sasl_challenge_handle;
Azure.IoT Build 0:6ae2f7bca550 780
AzureIoTClient 6:641a9672db08 781 if (amqpvalue_get_sasl_challenge(sasl_frame, &sasl_challenge_handle) != 0)
AzureIoTClient 6:641a9672db08 782 {
AzureIoTClient 6:641a9672db08 783 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 784 LogError("Cannot get SASL challenge values");
AzureIoTClient 6:641a9672db08 785 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 786 }
AzureIoTClient 6:641a9672db08 787 else
AzureIoTClient 6:641a9672db08 788 {
AzureIoTClient 6:641a9672db08 789 amqp_binary challenge_binary_value;
AzureIoTClient 6:641a9672db08 790 SASL_MECHANISM_BYTES response_bytes;
Azure.IoT Build 0:6ae2f7bca550 791
AzureIoTClient 6:641a9672db08 792 /* Codes_SRS_SASLCLIENTIO_01_053: [Challenge information, a block of opaque binary data passed to the security mechanism.] */
AzureIoTClient 6:641a9672db08 793 if (sasl_challenge_get_challenge(sasl_challenge_handle, &challenge_binary_value) != 0)
AzureIoTClient 6:641a9672db08 794 {
AzureIoTClient 6:641a9672db08 795 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 796 LogError("Cannot get SASL challenge binary value");
AzureIoTClient 6:641a9672db08 797 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 798 }
AzureIoTClient 6:641a9672db08 799 else
AzureIoTClient 6:641a9672db08 800 {
AzureIoTClient 6:641a9672db08 801 SASL_MECHANISM_BYTES challenge;
AzureIoTClient 6:641a9672db08 802
AzureIoTClient 6:641a9672db08 803 challenge.bytes = challenge_binary_value.bytes;
AzureIoTClient 6:641a9672db08 804 challenge.length = challenge_binary_value.length;
Azure.IoT Build 0:6ae2f7bca550 805
AzureIoTClient 6:641a9672db08 806 /* Codes_SRS_SASLCLIENTIO_01_057: [The contents of this data are defined by the SASL security mechanism.] */
AzureIoTClient 6:641a9672db08 807 /* Codes_SRS_SASLCLIENTIO_01_037: [SASL-RESPONSE -->] */
AzureIoTClient 23:1111ee8bcba4 808 if (saslmechanism_challenge(sasl_client_io_instance->sasl_mechanism, &challenge, &response_bytes) != 0)
AzureIoTClient 6:641a9672db08 809 {
AzureIoTClient 6:641a9672db08 810 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 811 LogError("SASL Challenge failed");
AzureIoTClient 23:1111ee8bcba4 812 handle_error(sasl_client_io_instance);
AzureIoTClient 23:1111ee8bcba4 813 }
AzureIoTClient 23:1111ee8bcba4 814 else if (send_sasl_response(sasl_client_io_instance, response_bytes) != 0)
AzureIoTClient 23:1111ee8bcba4 815 {
AzureIoTClient 23:1111ee8bcba4 816 /* Codes_SRS_SASLCLIENTIO_01_119: [If any error is encountered when parsing the received frame, the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 23:1111ee8bcba4 817 LogError("Cannot send SASL reponse");
AzureIoTClient 6:641a9672db08 818 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 819 }
AzureIoTClient 6:641a9672db08 820 }
Azure.IoT Build 0:6ae2f7bca550 821
AzureIoTClient 6:641a9672db08 822 sasl_challenge_destroy(sasl_challenge_handle);
AzureIoTClient 6:641a9672db08 823 }
AzureIoTClient 6:641a9672db08 824 }
AzureIoTClient 6:641a9672db08 825 }
AzureIoTClient 6:641a9672db08 826 /* Codes_SRS_SASLCLIENTIO_01_058: [This frame indicates the outcome of the SASL dialog.] */
AzureIoTClient 6:641a9672db08 827 /* Codes_SRS_SASLCLIENTIO_01_038: [<-- SASL-OUTCOME] */
AzureIoTClient 6:641a9672db08 828 else if (is_sasl_outcome_type_by_descriptor(descriptor))
AzureIoTClient 6:641a9672db08 829 {
AzureIoTClient 6:641a9672db08 830 /* Codes_SRS_SASLCLIENTIO_01_032: [The peer acting as the SASL server MUST announce supported authentication mechanisms using the sasl-mechanisms frame.] */
AzureIoTClient 6:641a9672db08 831 if ((sasl_client_io_instance->sasl_client_negotiation_state != SASL_CLIENT_NEGOTIATION_INIT_SENT) &&
AzureIoTClient 6:641a9672db08 832 (sasl_client_io_instance->sasl_client_negotiation_state != SASL_CLIENT_NEGOTIATION_RESPONSE_SENT))
AzureIoTClient 6:641a9672db08 833 {
AzureIoTClient 23:1111ee8bcba4 834 LogError("SASL outcome received in a bad state: %s", ENUM_TO_STRING(SASL_CLIENT_NEGOTIATION_STATE, sasl_client_io_instance->sasl_client_negotiation_state));
AzureIoTClient 6:641a9672db08 835 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 836 }
AzureIoTClient 6:641a9672db08 837 else
AzureIoTClient 6:641a9672db08 838 {
AzureIoTClient 6:641a9672db08 839 SASL_OUTCOME_HANDLE sasl_outcome;
Azure.IoT Build 0:6ae2f7bca550 840
AzureIoTClient 6:641a9672db08 841 sasl_client_io_instance->sasl_client_negotiation_state = SASL_CLIENT_NEGOTIATION_OUTCOME_RCVD;
Azure.IoT Build 0:6ae2f7bca550 842
AzureIoTClient 6:641a9672db08 843 if (amqpvalue_get_sasl_outcome(sasl_frame, &sasl_outcome) != 0)
AzureIoTClient 6:641a9672db08 844 {
AzureIoTClient 23:1111ee8bcba4 845 LogError("Cannot get SASL outcome");
AzureIoTClient 6:641a9672db08 846 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 847 }
AzureIoTClient 6:641a9672db08 848 else
AzureIoTClient 6:641a9672db08 849 {
AzureIoTClient 6:641a9672db08 850 sasl_code sasl_code;
Azure.IoT Build 0:6ae2f7bca550 851
AzureIoTClient 6:641a9672db08 852 /* Codes_SRS_SASLCLIENTIO_01_060: [A reply-code indicating the outcome of the SASL dialog.] */
AzureIoTClient 6:641a9672db08 853 if (sasl_outcome_get_code(sasl_outcome, &sasl_code) != 0)
AzureIoTClient 6:641a9672db08 854 {
AzureIoTClient 23:1111ee8bcba4 855 LogError("Cannot get SASL outcome code");
AzureIoTClient 6:641a9672db08 856 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 857 }
AzureIoTClient 6:641a9672db08 858 else
AzureIoTClient 6:641a9672db08 859 {
AzureIoTClient 6:641a9672db08 860 switch (sasl_code)
AzureIoTClient 6:641a9672db08 861 {
AzureIoTClient 6:641a9672db08 862 default:
AzureIoTClient 6:641a9672db08 863 case sasl_code_auth:
AzureIoTClient 6:641a9672db08 864 /* Codes_SRS_SASLCLIENTIO_01_063: [1 Connection authentication failed due to an unspecified problem with the supplied credentials.] */
AzureIoTClient 6:641a9672db08 865 case sasl_code_sys:
AzureIoTClient 6:641a9672db08 866 /* Codes_SRS_SASLCLIENTIO_01_064: [2 Connection authentication failed due to a system error.] */
AzureIoTClient 6:641a9672db08 867 case sasl_code_sys_perm:
AzureIoTClient 6:641a9672db08 868 /* Codes_SRS_SASLCLIENTIO_01_065: [3 Connection authentication failed due to a system error that is unlikely to be corrected without intervention.] */
AzureIoTClient 6:641a9672db08 869 case sasl_code_sys_temp:
AzureIoTClient 6:641a9672db08 870 /* Codes_SRS_SASLCLIENTIO_01_066: [4 Connection authentication failed due to a transient system error.] */
AzureIoTClient 23:1111ee8bcba4 871 LogError("SASL handshake failed with code %02X", (unsigned char)sasl_code);
AzureIoTClient 6:641a9672db08 872 handle_error(sasl_client_io_instance);
AzureIoTClient 6:641a9672db08 873 break;
Azure.IoT Build 0:6ae2f7bca550 874
AzureIoTClient 6:641a9672db08 875 case sasl_code_ok:
AzureIoTClient 6:641a9672db08 876 /* Codes_SRS_SASLCLIENTIO_01_059: [Upon successful completion of the SASL dialog the security layer has been established] */
AzureIoTClient 6:641a9672db08 877 /* Codes_SRS_SASLCLIENTIO_01_062: [0 Connection authentication succeeded.] */
AzureIoTClient 6:641a9672db08 878 sasl_client_io_instance->io_state = IO_STATE_OPEN;
AzureIoTClient 6:641a9672db08 879 indicate_open_complete(sasl_client_io_instance, IO_OPEN_OK);
AzureIoTClient 6:641a9672db08 880 break;
AzureIoTClient 6:641a9672db08 881 }
AzureIoTClient 6:641a9672db08 882 }
Azure.IoT Build 0:6ae2f7bca550 883
AzureIoTClient 6:641a9672db08 884 sasl_outcome_destroy(sasl_outcome);
AzureIoTClient 6:641a9672db08 885 }
AzureIoTClient 6:641a9672db08 886 }
AzureIoTClient 6:641a9672db08 887 }
AzureIoTClient 6:641a9672db08 888 else
AzureIoTClient 6:641a9672db08 889 {
AzureIoTClient 6:641a9672db08 890 LogError("Bad SASL frame");
AzureIoTClient 6:641a9672db08 891 }
AzureIoTClient 6:641a9672db08 892 }
AzureIoTClient 6:641a9672db08 893 }
AzureIoTClient 6:641a9672db08 894 break;
AzureIoTClient 6:641a9672db08 895 }
Azure.IoT Build 0:6ae2f7bca550 896 }
Azure.IoT Build 0:6ae2f7bca550 897
Azure.IoT Build 0:6ae2f7bca550 898 static void on_frame_codec_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 899 {
AzureIoTClient 6:641a9672db08 900 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context;
Azure.IoT Build 0:6ae2f7bca550 901
AzureIoTClient 6:641a9672db08 902 /* Codes_SRS_SASLCLIENTIO_01_122: [When on_frame_codec_error is called while in the OPENING or OPEN state the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 6:641a9672db08 903 /* Codes_SRS_SASLCLIENTIO_01_123: [When on_frame_codec_error is called in the ERROR state nothing shall be done.] */
AzureIoTClient 23:1111ee8bcba4 904 LogError("Error encoding frame (on_frame_codec_error)");
AzureIoTClient 6:641a9672db08 905 handle_error(sasl_client_io_instance);
Azure.IoT Build 0:6ae2f7bca550 906 }
Azure.IoT Build 0:6ae2f7bca550 907
Azure.IoT Build 0:6ae2f7bca550 908 static void on_sasl_frame_codec_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 909 {
AzureIoTClient 6:641a9672db08 910 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context;
Azure.IoT Build 0:6ae2f7bca550 911
AzureIoTClient 6:641a9672db08 912 /* Codes_SRS_SASLCLIENTIO_01_124: [**When on_sasl_frame_codec_error is called while in the OPENING or OPEN state the SASL client IO state shall be switched to IO_STATE_ERROR and the on_state_changed callback shall be triggered.] */
AzureIoTClient 6:641a9672db08 913 /* Codes_SRS_SASLCLIENTIO_01_125: [When on_sasl_frame_codec_error is called in the ERROR state nothing shall be done.] */
AzureIoTClient 23:1111ee8bcba4 914 LogError("Error encoding SASL frame (on_sasl_frame_codec_error)");
AzureIoTClient 6:641a9672db08 915 handle_error(sasl_client_io_instance);
Azure.IoT Build 0:6ae2f7bca550 916 }
Azure.IoT Build 0:6ae2f7bca550 917
Azure.IoT Build 5:ae49385aff34 918 CONCRETE_IO_HANDLE saslclientio_create(void* io_create_parameters)
Azure.IoT Build 0:6ae2f7bca550 919 {
AzureIoTClient 23:1111ee8bcba4 920 SASLCLIENTIO_CONFIG* sasl_client_io_config = (SASLCLIENTIO_CONFIG*)io_create_parameters;
AzureIoTClient 6:641a9672db08 921 SASL_CLIENT_IO_INSTANCE* result;
Azure.IoT Build 0:6ae2f7bca550 922
AzureIoTClient 6:641a9672db08 923 /* Codes_SRS_SASLCLIENTIO_01_005: [If xio_create_parameters is NULL, saslclientio_create shall fail and return NULL.] */
AzureIoTClient 23:1111ee8bcba4 924 if (sasl_client_io_config == NULL)
AzureIoTClient 23:1111ee8bcba4 925 {
AzureIoTClient 23:1111ee8bcba4 926 LogError("NULL io_create_parameters");
AzureIoTClient 23:1111ee8bcba4 927 result = NULL;
AzureIoTClient 23:1111ee8bcba4 928 }
AzureIoTClient 23:1111ee8bcba4 929 /* Codes_SRS_SASLCLIENTIO_01_092: [If any of the sasl_mechanism or underlying_io members of the configuration structure are NULL, saslclientio_create shall fail and return NULL.] */
AzureIoTClient 23:1111ee8bcba4 930 else if ((sasl_client_io_config->underlying_io == NULL) ||
AzureIoTClient 6:641a9672db08 931 (sasl_client_io_config->sasl_mechanism == NULL))
AzureIoTClient 6:641a9672db08 932 {
AzureIoTClient 23:1111ee8bcba4 933 LogError("Bad parameters: underlying_io = %p, sasl_mechanism = %p",
AzureIoTClient 23:1111ee8bcba4 934 sasl_client_io_config->underlying_io, sasl_client_io_config->sasl_mechanism);
AzureIoTClient 6:641a9672db08 935 result = NULL;
AzureIoTClient 6:641a9672db08 936 }
AzureIoTClient 6:641a9672db08 937 else
AzureIoTClient 6:641a9672db08 938 {
AzureIoTClient 23:1111ee8bcba4 939 result = (SASL_CLIENT_IO_INSTANCE*)malloc(sizeof(SASL_CLIENT_IO_INSTANCE));
AzureIoTClient 6:641a9672db08 940 /* Codes_SRS_SASLCLIENTIO_01_006: [If memory cannot be allocated for the new instance, saslclientio_create shall fail and return NULL.] */
AzureIoTClient 23:1111ee8bcba4 941 if (result == NULL)
AzureIoTClient 23:1111ee8bcba4 942 {
AzureIoTClient 23:1111ee8bcba4 943 LogError("Cannot allocate sasl client IO instance");
AzureIoTClient 23:1111ee8bcba4 944 }
AzureIoTClient 23:1111ee8bcba4 945 else
AzureIoTClient 6:641a9672db08 946 {
AzureIoTClient 6:641a9672db08 947 result->underlying_io = sasl_client_io_config->underlying_io;
AzureIoTClient 23:1111ee8bcba4 948 /* Codes_SRS_SASLCLIENTIO_01_089: [saslclientio_create shall create a frame_codec to be used for encoding/decoding frames bycalling frame_codec_create and passing the underlying_io as argument.] */
AzureIoTClient 23:1111ee8bcba4 949 result->frame_codec = frame_codec_create(on_frame_codec_error, result);
AzureIoTClient 23:1111ee8bcba4 950 if (result->frame_codec == NULL)
AzureIoTClient 6:641a9672db08 951 {
AzureIoTClient 23:1111ee8bcba4 952 /* Codes_SRS_SASLCLIENTIO_01_090: [If frame_codec_create fails, then saslclientio_create shall fail and return NULL.] */
AzureIoTClient 23:1111ee8bcba4 953 LogError("frame_codec_create failed");
AzureIoTClient 21:f9c433d8e6ca 954 free(result);
AzureIoTClient 6:641a9672db08 955 result = NULL;
AzureIoTClient 6:641a9672db08 956 }
AzureIoTClient 6:641a9672db08 957 else
AzureIoTClient 6:641a9672db08 958 {
AzureIoTClient 23:1111ee8bcba4 959 /* Codes_SRS_SASLCLIENTIO_01_084: [saslclientio_create shall create a sasl_frame_codec to be used for SASL frame encoding/decoding by calling sasl_frame_codec_create and passing the just created frame_codec as argument.] */
AzureIoTClient 23:1111ee8bcba4 960 result->sasl_frame_codec = sasl_frame_codec_create(result->frame_codec, sasl_frame_received_callback, on_sasl_frame_codec_error, result);
AzureIoTClient 23:1111ee8bcba4 961 if (result->sasl_frame_codec == NULL)
AzureIoTClient 6:641a9672db08 962 {
AzureIoTClient 23:1111ee8bcba4 963 LogError("sasl_frame_codec_create failed");
AzureIoTClient 23:1111ee8bcba4 964 frame_codec_destroy(result->frame_codec);
AzureIoTClient 21:f9c433d8e6ca 965 free(result);
AzureIoTClient 6:641a9672db08 966 result = NULL;
AzureIoTClient 6:641a9672db08 967 }
AzureIoTClient 6:641a9672db08 968 else
AzureIoTClient 6:641a9672db08 969 {
AzureIoTClient 23:1111ee8bcba4 970 /* Codes_SRS_SASLCLIENTIO_01_004: [saslclientio_create shall return on success a non-NULL handle to a new SASL client IO instance.] */
AzureIoTClient 23:1111ee8bcba4 971 result->on_bytes_received = NULL;
AzureIoTClient 23:1111ee8bcba4 972 result->on_io_open_complete = NULL;
AzureIoTClient 23:1111ee8bcba4 973 result->on_io_error = NULL;
AzureIoTClient 23:1111ee8bcba4 974 result->on_io_close_complete = NULL;
AzureIoTClient 23:1111ee8bcba4 975 result->on_bytes_received_context = NULL;
AzureIoTClient 23:1111ee8bcba4 976 result->on_io_open_complete_context = NULL;
AzureIoTClient 23:1111ee8bcba4 977 result->on_io_close_complete_context = NULL;
AzureIoTClient 23:1111ee8bcba4 978 result->on_io_error_context = NULL;
AzureIoTClient 23:1111ee8bcba4 979 result->sasl_mechanism = sasl_client_io_config->sasl_mechanism;
Azure.IoT Build 0:6ae2f7bca550 980
AzureIoTClient 23:1111ee8bcba4 981 result->io_state = IO_STATE_NOT_OPEN;
AzureIoTClient 6:641a9672db08 982 }
AzureIoTClient 6:641a9672db08 983 }
AzureIoTClient 6:641a9672db08 984 }
AzureIoTClient 6:641a9672db08 985 }
Azure.IoT Build 0:6ae2f7bca550 986
AzureIoTClient 6:641a9672db08 987 return result;
Azure.IoT Build 0:6ae2f7bca550 988 }
Azure.IoT Build 0:6ae2f7bca550 989
Azure.IoT Build 0:6ae2f7bca550 990 void saslclientio_destroy(CONCRETE_IO_HANDLE sasl_client_io)
Azure.IoT Build 0:6ae2f7bca550 991 {
AzureIoTClient 23:1111ee8bcba4 992 if (sasl_client_io == NULL)
AzureIoTClient 23:1111ee8bcba4 993 {
AzureIoTClient 23:1111ee8bcba4 994 /* Codes_SRS_SASLCLIENTIO_01_008: [If the argument sasl_client_io is NULL, saslclientio_destroy shall do nothing.]*/
AzureIoTClient 23:1111ee8bcba4 995 LogError("NULL sasl_client_io");
AzureIoTClient 23:1111ee8bcba4 996 }
AzureIoTClient 23:1111ee8bcba4 997 else
AzureIoTClient 6:641a9672db08 998 {
AzureIoTClient 6:641a9672db08 999 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)sasl_client_io;
Azure.IoT Build 0:6ae2f7bca550 1000
AzureIoTClient 6:641a9672db08 1001 /* Codes_SRS_SASLCLIENTIO_01_007: [saslclientio_destroy shall free all resources associated with the SASL client IO handle.] */
AzureIoTClient 6:641a9672db08 1002 /* Codes_SRS_SASLCLIENTIO_01_086: [saslclientio_destroy shall destroy the sasl_frame_codec created in saslclientio_create by calling sasl_frame_codec_destroy.] */
AzureIoTClient 6:641a9672db08 1003 sasl_frame_codec_destroy(sasl_client_io_instance->sasl_frame_codec);
Azure.IoT Build 0:6ae2f7bca550 1004
AzureIoTClient 6:641a9672db08 1005 /* Codes_SRS_SASLCLIENTIO_01_091: [saslclientio_destroy shall destroy the frame_codec created in saslclientio_create by calling frame_codec_destroy.] */
AzureIoTClient 6:641a9672db08 1006 frame_codec_destroy(sasl_client_io_instance->frame_codec);
AzureIoTClient 21:f9c433d8e6ca 1007 free(sasl_client_io);
AzureIoTClient 6:641a9672db08 1008 }
Azure.IoT Build 0:6ae2f7bca550 1009 }
Azure.IoT Build 0:6ae2f7bca550 1010
Azure.IoT Build 0:6ae2f7bca550 1011 int saslclientio_open(CONCRETE_IO_HANDLE sasl_client_io, ON_IO_OPEN_COMPLETE on_io_open_complete, void* on_io_open_complete_context, ON_BYTES_RECEIVED on_bytes_received, void* on_bytes_received_context, ON_IO_ERROR on_io_error, void* on_io_error_context)
Azure.IoT Build 0:6ae2f7bca550 1012 {
AzureIoTClient 6:641a9672db08 1013 int result = 0;
Azure.IoT Build 0:6ae2f7bca550 1014
AzureIoTClient 6:641a9672db08 1015 /* Codes_SRS_SASLCLIENTIO_01_011: [If any of the sasl_client_io or on_bytes_received arguments is NULL, saslclientio_open shall fail and return a non-zero value.] */
AzureIoTClient 6:641a9672db08 1016 if ((sasl_client_io == NULL) ||
AzureIoTClient 6:641a9672db08 1017 (on_bytes_received == NULL))
AzureIoTClient 6:641a9672db08 1018 {
AzureIoTClient 23:1111ee8bcba4 1019 LogError("Bad arguments: sasl_client_io = %p, on_bytes_received = %p",
AzureIoTClient 23:1111ee8bcba4 1020 sasl_client_io, on_bytes_received);
AzureIoTClient 19:000ab4e6a2c1 1021 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 1022 }
AzureIoTClient 6:641a9672db08 1023 else
AzureIoTClient 6:641a9672db08 1024 {
AzureIoTClient 6:641a9672db08 1025 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)sasl_client_io;
Azure.IoT Build 0:6ae2f7bca550 1026
AzureIoTClient 6:641a9672db08 1027 if (sasl_client_io_instance->io_state != IO_STATE_NOT_OPEN)
AzureIoTClient 6:641a9672db08 1028 {
AzureIoTClient 23:1111ee8bcba4 1029 LogError("Open called while already OPEN");
AzureIoTClient 19:000ab4e6a2c1 1030 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 1031 }
AzureIoTClient 6:641a9672db08 1032 else
AzureIoTClient 6:641a9672db08 1033 {
AzureIoTClient 6:641a9672db08 1034 sasl_client_io_instance->on_bytes_received = on_bytes_received;
AzureIoTClient 6:641a9672db08 1035 sasl_client_io_instance->on_io_open_complete = on_io_open_complete;
AzureIoTClient 6:641a9672db08 1036 sasl_client_io_instance->on_io_error = on_io_error;
AzureIoTClient 6:641a9672db08 1037 sasl_client_io_instance->on_bytes_received_context = on_bytes_received_context;
Azure.IoT Build 0:6ae2f7bca550 1038 sasl_client_io_instance->on_io_open_complete_context = on_io_open_complete_context;
Azure.IoT Build 0:6ae2f7bca550 1039 sasl_client_io_instance->on_io_error_context = on_io_error_context;
AzureIoTClient 6:641a9672db08 1040 sasl_client_io_instance->sasl_header_exchange_state = SASL_HEADER_EXCHANGE_IDLE;
AzureIoTClient 6:641a9672db08 1041 sasl_client_io_instance->sasl_client_negotiation_state = SASL_CLIENT_NEGOTIATION_NOT_STARTED;
AzureIoTClient 6:641a9672db08 1042 sasl_client_io_instance->header_bytes_received = 0;
AzureIoTClient 6:641a9672db08 1043 sasl_client_io_instance->io_state = IO_STATE_OPENING_UNDERLYING_IO;
AzureIoTClient 6:641a9672db08 1044 sasl_client_io_instance->is_trace_on = 0;
Azure.IoT Build 0:6ae2f7bca550 1045
AzureIoTClient 6:641a9672db08 1046 /* Codes_SRS_SASLCLIENTIO_01_009: [saslclientio_open shall call xio_open on the underlying_io passed to saslclientio_create.] */
AzureIoTClient 6:641a9672db08 1047 /* Codes_SRS_SASLCLIENTIO_01_013: [saslclientio_open shall pass to xio_open a callback for receiving bytes and a state changed callback for the underlying_io state changes.] */
AzureIoTClient 6:641a9672db08 1048 if (xio_open(sasl_client_io_instance->underlying_io, on_underlying_io_open_complete, sasl_client_io_instance, on_underlying_io_bytes_received, sasl_client_io_instance, on_underlying_io_error, sasl_client_io_instance) != 0)
AzureIoTClient 6:641a9672db08 1049 {
AzureIoTClient 6:641a9672db08 1050 /* Codes_SRS_SASLCLIENTIO_01_012: [If the open of the underlying_io fails, saslclientio_open shall fail and return non-zero value.] */
AzureIoTClient 23:1111ee8bcba4 1051 LogError("xio_open failed");
AzureIoTClient 19:000ab4e6a2c1 1052 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 1053 }
AzureIoTClient 6:641a9672db08 1054 else
AzureIoTClient 6:641a9672db08 1055 {
AzureIoTClient 6:641a9672db08 1056 /* Codes_SRS_SASLCLIENTIO_01_010: [On success, saslclientio_open shall return 0.] */
AzureIoTClient 6:641a9672db08 1057 result = 0;
AzureIoTClient 6:641a9672db08 1058 }
AzureIoTClient 6:641a9672db08 1059 }
AzureIoTClient 6:641a9672db08 1060 }
AzureIoTClient 6:641a9672db08 1061
AzureIoTClient 6:641a9672db08 1062 return result;
Azure.IoT Build 0:6ae2f7bca550 1063 }
Azure.IoT Build 0:6ae2f7bca550 1064
Azure.IoT Build 0:6ae2f7bca550 1065 int saslclientio_close(CONCRETE_IO_HANDLE sasl_client_io, ON_IO_CLOSE_COMPLETE on_io_close_complete, void* on_io_close_complete_context)
Azure.IoT Build 0:6ae2f7bca550 1066 {
AzureIoTClient 6:641a9672db08 1067 int result = 0;
Azure.IoT Build 0:6ae2f7bca550 1068
AzureIoTClient 6:641a9672db08 1069 /* Codes_SRS_SASLCLIENTIO_01_017: [If sasl_client_io is NULL, saslclientio_close shall fail and return a non-zero value.] */
AzureIoTClient 6:641a9672db08 1070 if (sasl_client_io == NULL)
AzureIoTClient 6:641a9672db08 1071 {
AzureIoTClient 23:1111ee8bcba4 1072 LogError("NULL saslclientio_close");
AzureIoTClient 19:000ab4e6a2c1 1073 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 1074 }
AzureIoTClient 6:641a9672db08 1075 else
AzureIoTClient 6:641a9672db08 1076 {
AzureIoTClient 6:641a9672db08 1077 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)sasl_client_io;
Azure.IoT Build 0:6ae2f7bca550 1078
AzureIoTClient 6:641a9672db08 1079 /* Codes_SRS_SASLCLIENTIO_01_098: [saslclientio_close shall only perform the close if the state is OPEN, OPENING or ERROR.] */
AzureIoTClient 6:641a9672db08 1080 if ((sasl_client_io_instance->io_state == IO_STATE_NOT_OPEN) ||
AzureIoTClient 6:641a9672db08 1081 (sasl_client_io_instance->io_state == IO_STATE_CLOSING))
AzureIoTClient 6:641a9672db08 1082 {
AzureIoTClient 23:1111ee8bcba4 1083 LogError("saslclientio_close called while not open");
AzureIoTClient 19:000ab4e6a2c1 1084 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 1085 }
AzureIoTClient 6:641a9672db08 1086 else
AzureIoTClient 6:641a9672db08 1087 {
AzureIoTClient 6:641a9672db08 1088 sasl_client_io_instance->io_state = IO_STATE_CLOSING;
Azure.IoT Build 0:6ae2f7bca550 1089
Azure.IoT Build 0:6ae2f7bca550 1090 sasl_client_io_instance->on_io_close_complete = on_io_close_complete;
Azure.IoT Build 0:6ae2f7bca550 1091 sasl_client_io_instance->on_io_close_complete_context = on_io_close_complete_context;
Azure.IoT Build 0:6ae2f7bca550 1092
AzureIoTClient 6:641a9672db08 1093 /* Codes_SRS_SASLCLIENTIO_01_015: [saslclientio_close shall close the underlying io handle passed in saslclientio_create by calling xio_close.] */
AzureIoTClient 6:641a9672db08 1094 if (xio_close(sasl_client_io_instance->underlying_io, on_underlying_io_close_complete, sasl_client_io_instance) != 0)
AzureIoTClient 6:641a9672db08 1095 {
AzureIoTClient 6:641a9672db08 1096 /* Codes_SRS_SASLCLIENTIO_01_018: [If xio_close fails, then saslclientio_close shall return a non-zero value.] */
AzureIoTClient 23:1111ee8bcba4 1097 LogError("xio_close failed");
AzureIoTClient 19:000ab4e6a2c1 1098 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 1099 }
AzureIoTClient 6:641a9672db08 1100 else
AzureIoTClient 6:641a9672db08 1101 {
AzureIoTClient 6:641a9672db08 1102 /* Codes_SRS_SASLCLIENTIO_01_016: [On success, saslclientio_close shall return 0.] */
AzureIoTClient 6:641a9672db08 1103 result = 0;
AzureIoTClient 6:641a9672db08 1104 }
AzureIoTClient 6:641a9672db08 1105 }
AzureIoTClient 6:641a9672db08 1106 }
Azure.IoT Build 0:6ae2f7bca550 1107
AzureIoTClient 6:641a9672db08 1108 return result;
Azure.IoT Build 0:6ae2f7bca550 1109 }
Azure.IoT Build 0:6ae2f7bca550 1110
Azure.IoT Build 0:6ae2f7bca550 1111 int saslclientio_send(CONCRETE_IO_HANDLE sasl_client_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context)
Azure.IoT Build 0:6ae2f7bca550 1112 {
AzureIoTClient 6:641a9672db08 1113 int result;
Azure.IoT Build 0:6ae2f7bca550 1114
AzureIoTClient 6:641a9672db08 1115 /* Codes_SRS_SASLCLIENTIO_01_022: [If the saslio or buffer argument is NULL, saslclientio_send shall fail and return a non-zero value.] */
AzureIoTClient 6:641a9672db08 1116 if ((sasl_client_io == NULL) ||
AzureIoTClient 6:641a9672db08 1117 (buffer == NULL) ||
AzureIoTClient 6:641a9672db08 1118 /* Codes_SRS_SASLCLIENTIO_01_023: [If size is 0, saslclientio_send shall fail and return a non-zero value.] */
AzureIoTClient 6:641a9672db08 1119 (size == 0))
AzureIoTClient 6:641a9672db08 1120 {
AzureIoTClient 6:641a9672db08 1121 /* Invalid arguments */
AzureIoTClient 23:1111ee8bcba4 1122 LogError("Bad arguments: sasl_client_io = %p, buffer = %p, size = %u",
AzureIoTClient 23:1111ee8bcba4 1123 sasl_client_io, buffer, (unsigned int)size);
AzureIoTClient 19:000ab4e6a2c1 1124 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 1125 }
AzureIoTClient 6:641a9672db08 1126 else
AzureIoTClient 6:641a9672db08 1127 {
AzureIoTClient 6:641a9672db08 1128 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)sasl_client_io;
Azure.IoT Build 0:6ae2f7bca550 1129
AzureIoTClient 6:641a9672db08 1130 /* Codes_SRS_SASLCLIENTIO_01_019: [If saslclientio_send is called while the SASL client IO state is not IO_STATE_OPEN, saslclientio_send shall fail and return a non-zero value.] */
AzureIoTClient 6:641a9672db08 1131 if (sasl_client_io_instance->io_state != IO_STATE_OPEN)
AzureIoTClient 6:641a9672db08 1132 {
AzureIoTClient 23:1111ee8bcba4 1133 LogError("send called while not open");
AzureIoTClient 19:000ab4e6a2c1 1134 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 1135 }
AzureIoTClient 6:641a9672db08 1136 else
AzureIoTClient 6:641a9672db08 1137 {
AzureIoTClient 6:641a9672db08 1138 /* Codes_SRS_SASLCLIENTIO_01_020: [If the SASL client IO state is IO_STATE_OPEN, saslclientio_send shall call xio_send on the underlying_io passed to saslclientio_create, while passing as arguments the buffer, size, on_send_complete and callback_context.] */
AzureIoTClient 6:641a9672db08 1139 if (xio_send(sasl_client_io_instance->underlying_io, buffer, size, on_send_complete, callback_context) != 0)
AzureIoTClient 6:641a9672db08 1140 {
AzureIoTClient 6:641a9672db08 1141 /* Codes_SRS_SASLCLIENTIO_01_024: [If the call to xio_send fails, then saslclientio_send shall fail and return a non-zero value.] */
AzureIoTClient 23:1111ee8bcba4 1142 LogError("xio_send failed");
AzureIoTClient 19:000ab4e6a2c1 1143 result = __FAILURE__;
AzureIoTClient 6:641a9672db08 1144 }
AzureIoTClient 6:641a9672db08 1145 else
AzureIoTClient 6:641a9672db08 1146 {
AzureIoTClient 6:641a9672db08 1147 /* Codes_SRS_SASLCLIENTIO_01_021: [On success, saslclientio_send shall return 0.] */
AzureIoTClient 6:641a9672db08 1148 result = 0;
AzureIoTClient 6:641a9672db08 1149 }
AzureIoTClient 6:641a9672db08 1150 }
AzureIoTClient 6:641a9672db08 1151 }
Azure.IoT Build 0:6ae2f7bca550 1152
AzureIoTClient 6:641a9672db08 1153 return result;
Azure.IoT Build 0:6ae2f7bca550 1154 }
Azure.IoT Build 0:6ae2f7bca550 1155
Azure.IoT Build 0:6ae2f7bca550 1156 void saslclientio_dowork(CONCRETE_IO_HANDLE sasl_client_io)
Azure.IoT Build 0:6ae2f7bca550 1157 {
AzureIoTClient 6:641a9672db08 1158 /* Codes_SRS_SASLCLIENTIO_01_026: [If the sasl_client_io argument is NULL, saslclientio_dowork shall do nothing.] */
AzureIoTClient 23:1111ee8bcba4 1159 if (sasl_client_io == NULL)
AzureIoTClient 23:1111ee8bcba4 1160 {
AzureIoTClient 23:1111ee8bcba4 1161 LogError("NULL sasl_client_io");
AzureIoTClient 23:1111ee8bcba4 1162 }
AzureIoTClient 23:1111ee8bcba4 1163 else
AzureIoTClient 6:641a9672db08 1164 {
AzureIoTClient 6:641a9672db08 1165 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)sasl_client_io;
Azure.IoT Build 0:6ae2f7bca550 1166
AzureIoTClient 6:641a9672db08 1167 /* Codes_SRS_SASLCLIENTIO_01_025: [saslclientio_dowork shall call the xio_dowork on the underlying_io passed in saslclientio_create.] */
AzureIoTClient 6:641a9672db08 1168 if (sasl_client_io_instance->io_state != IO_STATE_NOT_OPEN)
AzureIoTClient 6:641a9672db08 1169 {
AzureIoTClient 6:641a9672db08 1170 /* Codes_SRS_SASLCLIENTIO_01_025: [saslclientio_dowork shall call the xio_dowork on the underlying_io passed in saslclientio_create.] */
AzureIoTClient 6:641a9672db08 1171 xio_dowork(sasl_client_io_instance->underlying_io);
AzureIoTClient 6:641a9672db08 1172 }
AzureIoTClient 6:641a9672db08 1173 }
Azure.IoT Build 0:6ae2f7bca550 1174 }
Azure.IoT Build 0:6ae2f7bca550 1175
AzureIoTClient 1:eab586236bfe 1176 /* Codes_SRS_SASLCLIENTIO_03_001: [saslclientio_setoption shall forward options to underlying io.]*/
AzureIoTClient 1:eab586236bfe 1177 int saslclientio_setoption(CONCRETE_IO_HANDLE sasl_client_io, const char* optionName, const void* value)
Azure.IoT Build 0:6ae2f7bca550 1178 {
AzureIoTClient 1:eab586236bfe 1179 int result;
AzureIoTClient 1:eab586236bfe 1180
AzureIoTClient 1:eab586236bfe 1181 if (sasl_client_io == NULL)
AzureIoTClient 1:eab586236bfe 1182 {
AzureIoTClient 23:1111ee8bcba4 1183 LogError("NULL sasl_client_io");
AzureIoTClient 19:000ab4e6a2c1 1184 result = __FAILURE__;
AzureIoTClient 1:eab586236bfe 1185 }
AzureIoTClient 1:eab586236bfe 1186 else
AzureIoTClient 1:eab586236bfe 1187 {
AzureIoTClient 1:eab586236bfe 1188 SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)sasl_client_io;
AzureIoTClient 1:eab586236bfe 1189
AzureIoTClient 1:eab586236bfe 1190 if (sasl_client_io_instance->underlying_io == NULL)
AzureIoTClient 1:eab586236bfe 1191 {
AzureIoTClient 23:1111ee8bcba4 1192 LogError("NULL underlying_io");
AzureIoTClient 19:000ab4e6a2c1 1193 result = __FAILURE__;
AzureIoTClient 1:eab586236bfe 1194 }
AzureIoTClient 6:641a9672db08 1195 else if (strcmp("logtrace", optionName) == 0)
AzureIoTClient 6:641a9672db08 1196 {
AzureIoTClient 6:641a9672db08 1197 sasl_client_io_instance->is_trace_on = *((bool*)value) == true ? 1 : 0;
AzureIoTClient 6:641a9672db08 1198 result = 0;
AzureIoTClient 6:641a9672db08 1199 }
AzureIoTClient 1:eab586236bfe 1200 else
AzureIoTClient 1:eab586236bfe 1201 {
AzureIoTClient 1:eab586236bfe 1202 result = xio_setoption(sasl_client_io_instance->underlying_io, optionName, value);
AzureIoTClient 1:eab586236bfe 1203 }
AzureIoTClient 1:eab586236bfe 1204 }
AzureIoTClient 23:1111ee8bcba4 1205
AzureIoTClient 6:641a9672db08 1206 return result;
AzureIoTClient 6:641a9672db08 1207 }
AzureIoTClient 1:eab586236bfe 1208
AzureIoTClient 6:641a9672db08 1209 /*this function will clone an option given by name and value*/
AzureIoTClient 6:641a9672db08 1210 static void* saslclientio_CloneOption(const char* name, const void* value)
AzureIoTClient 6:641a9672db08 1211 {
AzureIoTClient 17:923575db8b2d 1212 (void)name;
AzureIoTClient 17:923575db8b2d 1213 (void)value;
AzureIoTClient 6:641a9672db08 1214 return NULL;
AzureIoTClient 6:641a9672db08 1215 }
AzureIoTClient 6:641a9672db08 1216
AzureIoTClient 6:641a9672db08 1217 /*this function destroys an option previously created*/
AzureIoTClient 6:641a9672db08 1218 static void saslclientio_DestroyOption(const char* name, const void* value)
AzureIoTClient 6:641a9672db08 1219 {
AzureIoTClient 17:923575db8b2d 1220 (void)name;
AzureIoTClient 17:923575db8b2d 1221 (void)value;
AzureIoTClient 6:641a9672db08 1222 }
AzureIoTClient 6:641a9672db08 1223
AzureIoTClient 6:641a9672db08 1224 static OPTIONHANDLER_HANDLE saslclientio_retrieveoptions(CONCRETE_IO_HANDLE handle)
AzureIoTClient 6:641a9672db08 1225 {
AzureIoTClient 6:641a9672db08 1226 OPTIONHANDLER_HANDLE result;
AzureIoTClient 6:641a9672db08 1227 (void)handle;
AzureIoTClient 6:641a9672db08 1228 result = OptionHandler_Create(saslclientio_CloneOption, saslclientio_DestroyOption, saslclientio_setoption);
AzureIoTClient 6:641a9672db08 1229 if (result == NULL)
AzureIoTClient 6:641a9672db08 1230 {
AzureIoTClient 6:641a9672db08 1231 LogError("unable to OptionHandler_Create");
AzureIoTClient 6:641a9672db08 1232 /*return as is*/
AzureIoTClient 6:641a9672db08 1233 }
AzureIoTClient 6:641a9672db08 1234 else
AzureIoTClient 6:641a9672db08 1235 {
AzureIoTClient 6:641a9672db08 1236 /*insert here work to add the options to "result" handle*/
AzureIoTClient 6:641a9672db08 1237 }
AzureIoTClient 23:1111ee8bcba4 1238
AzureIoTClient 1:eab586236bfe 1239 return result;
Azure.IoT Build 0:6ae2f7bca550 1240 }
Azure.IoT Build 0:6ae2f7bca550 1241
Azure.IoT Build 0:6ae2f7bca550 1242 static const IO_INTERFACE_DESCRIPTION sasl_client_io_interface_description =
Azure.IoT Build 0:6ae2f7bca550 1243 {
AzureIoTClient 6:641a9672db08 1244 saslclientio_retrieveoptions,
AzureIoTClient 6:641a9672db08 1245 saslclientio_create,
AzureIoTClient 6:641a9672db08 1246 saslclientio_destroy,
AzureIoTClient 6:641a9672db08 1247 saslclientio_open,
AzureIoTClient 6:641a9672db08 1248 saslclientio_close,
AzureIoTClient 6:641a9672db08 1249 saslclientio_send,
AzureIoTClient 6:641a9672db08 1250 saslclientio_dowork,
Azure.IoT Build 0:6ae2f7bca550 1251 saslclientio_setoption
Azure.IoT Build 0:6ae2f7bca550 1252 };
Azure.IoT Build 0:6ae2f7bca550 1253
Azure.IoT Build 0:6ae2f7bca550 1254 /* Codes_SRS_SASLCLIENTIO_01_087: [saslclientio_get_interface_description shall return a pointer to an IO_INTERFACE_DESCRIPTION structure that contains pointers to the functions: saslclientio_create, saslclientio_destroy, saslclientio_open, saslclientio_close, saslclientio_send and saslclientio_dowork.] */
Azure.IoT Build 0:6ae2f7bca550 1255 const IO_INTERFACE_DESCRIPTION* saslclientio_get_interface_description(void)
Azure.IoT Build 0:6ae2f7bca550 1256 {
AzureIoTClient 6:641a9672db08 1257 return &sasl_client_io_interface_description;
Azure.IoT Build 0:6ae2f7bca550 1258 }