Exemplo n.º 1
0
static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size)
{
	HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)context;

	while (size > 0)
	{
		switch (header_detect_io_instance->io_state)
		{
		default:
			break;

		case IO_STATE_WAIT_FOR_HEADER:
			if (amqp_header[header_detect_io_instance->header_pos] != buffer[0])
			{
                /* Send expected header, then close as per spec.  We do not care if we fail */
                (void)xio_send(header_detect_io_instance->underlying_io, amqp_header, sizeof(amqp_header), on_send_complete_close, context);

                header_detect_io_instance->io_state = IO_STATE_NOT_OPEN;
				indicate_open_complete(header_detect_io_instance, IO_OPEN_ERROR);
				size = 0;
			}
			else
			{
				header_detect_io_instance->header_pos++;
				size--;
				buffer++;
				if (header_detect_io_instance->header_pos == sizeof(amqp_header))
				{
					if (xio_send(header_detect_io_instance->underlying_io, amqp_header, sizeof(amqp_header), NULL, NULL) != 0)
					{
						header_detect_io_instance->io_state = IO_STATE_NOT_OPEN;
						indicate_open_complete(header_detect_io_instance, IO_OPEN_ERROR);
					}
					else
					{
						header_detect_io_instance->io_state = IO_STATE_OPEN;
						indicate_open_complete(header_detect_io_instance, IO_OPEN_OK);
					}
				}
			}
			break;

		case IO_STATE_OPEN:
			header_detect_io_instance->on_bytes_received(header_detect_io_instance->on_bytes_received_context, buffer, size);
			size = 0;
			break;
		}
	}
}
Exemplo n.º 2
0
static void on_underlying_io_open_complete(void* context, IO_OPEN_RESULT open_result)
{
	HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)context;

	switch (header_detect_io_instance->io_state)
	{
	default:
		break;

	case IO_STATE_OPENING_UNDERLYING_IO:
		if (open_result == IO_OPEN_OK)
		{
			header_detect_io_instance->io_state = IO_STATE_WAIT_FOR_HEADER;
		}
		else
		{
			if (xio_close(header_detect_io_instance->underlying_io, on_underlying_io_close_complete, header_detect_io_instance) != 0)
			{
				header_detect_io_instance->io_state = IO_STATE_NOT_OPEN;
				indicate_open_complete(header_detect_io_instance, IO_OPEN_ERROR);
			}
		}

		break;
	}
}
static int on_handshake_done(WOLFSSL* ssl, void* context)
{
    TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context;
    if (tls_io_instance->tlsio_state == TLSIO_STATE_IN_HANDSHAKE)
    {
        tls_io_instance->tlsio_state = TLSIO_STATE_OPEN;
        indicate_open_complete(tls_io_instance, IO_OPEN_OK);
    }

    return 0;
}
static void on_underlying_io_open_complete(void* context, IO_OPEN_RESULT open_result)
{
    TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context;

    if (open_result != IO_OPEN_OK)
    {
        tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
        indicate_open_complete(tls_io_instance, IO_OPEN_ERROR);
    }
    else
    {
        int res;
        tls_io_instance->tlsio_state = TLSIO_STATE_IN_HANDSHAKE;

        res = wolfSSL_connect(tls_io_instance->ssl);
        if (res != SSL_SUCCESS)
        {
            indicate_open_complete(tls_io_instance, IO_OPEN_ERROR);
            tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
        }
    }
}
Exemplo n.º 5
0
int headerdetectio_open(CONCRETE_IO_HANDLE header_detect_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)
{
	int result;

	if (header_detect_io == NULL)
	{
		result = __LINE__;
	}
	else
	{
		HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)header_detect_io;

        if (header_detect_io_instance->io_state != IO_STATE_NOT_OPEN &&
            header_detect_io_instance->io_state != IO_STATE_OPEN)
        {
            result = __LINE__;
        }
		else
		{
			header_detect_io_instance->on_bytes_received = on_bytes_received;
			header_detect_io_instance->on_io_open_complete = on_io_open_complete;
			header_detect_io_instance->on_io_error = on_io_error;
            header_detect_io_instance->on_bytes_received_context = on_bytes_received_context;
            header_detect_io_instance->on_io_open_complete_context = on_io_open_complete_context;
            header_detect_io_instance->on_io_error_context = on_io_error_context;

            if (header_detect_io_instance->io_state == IO_STATE_OPEN)
            {
                indicate_open_complete(header_detect_io_instance, IO_OPEN_OK);
            }
            else
            {
                header_detect_io_instance->header_pos = 0;
                header_detect_io_instance->io_state = IO_STATE_OPENING_UNDERLYING_IO;

                if (xio_open(header_detect_io_instance->underlying_io, on_underlying_io_open_complete, header_detect_io_instance, on_underlying_io_bytes_received, header_detect_io_instance, on_underlying_io_error, header_detect_io_instance) != 0)
                {
                    result = __LINE__;
                }
                else
                {
                    result = 0;
                }
            }
		}
	}

	return result;
}
Exemplo n.º 6
0
static void on_underlying_io_error(void* context)
{
	HEADER_DETECT_IO_INSTANCE* header_detect_io_instance = (HEADER_DETECT_IO_INSTANCE*)context;

	switch (header_detect_io_instance->io_state)
	{
	default:
		break;

	case IO_STATE_WAIT_FOR_HEADER:
	case IO_STATE_OPENING_UNDERLYING_IO:
		header_detect_io_instance->io_state = IO_STATE_NOT_OPEN;
		indicate_open_complete(header_detect_io_instance, IO_OPEN_ERROR);
		break;

	case IO_STATE_OPEN:
		header_detect_io_instance->io_state = IO_STATE_ERROR;
		indicate_error(header_detect_io_instance);
		break;
	}
}
Exemplo n.º 7
0
static void on_underlying_io_close_complete(void* context)
{
	SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context;

	switch (sasl_client_io_instance->io_state)
	{
	default:
		break;

	case IO_STATE_OPENING_UNDERLYING_IO:
	case IO_STATE_SASL_HANDSHAKE:
		sasl_client_io_instance->io_state = IO_STATE_NOT_OPEN;
		indicate_open_complete(sasl_client_io_instance, IO_OPEN_ERROR);
		break;

	case IO_STATE_CLOSING:
		sasl_client_io_instance->io_state = IO_STATE_NOT_OPEN;
		indicate_close_complete(sasl_client_io_instance);
		break;
	}
}
static void on_underlying_io_error(void* context)
{
    TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context;

    switch (tls_io_instance->tlsio_state)
    {
        default:
        case TLSIO_STATE_NOT_OPEN:
        case TLSIO_STATE_ERROR:
            break;

        case TLSIO_STATE_OPENING_UNDERLYING_IO:
        case TLSIO_STATE_IN_HANDSHAKE:
            tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
            indicate_open_complete(tls_io_instance, IO_OPEN_ERROR);
            break;

        case TLSIO_STATE_OPEN:
            tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
            indicate_error(tls_io_instance);
            break;
    }
}
Exemplo n.º 9
0
static void handle_error(SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance)
{
	switch (sasl_client_io_instance->io_state)
	{
	default:
	case IO_STATE_NOT_OPEN:
		break;

	case IO_STATE_OPENING_UNDERLYING_IO:
	case IO_STATE_SASL_HANDSHAKE:
		if (xio_close(sasl_client_io_instance->underlying_io, on_underlying_io_close_complete, sasl_client_io_instance) != 0)
		{
			sasl_client_io_instance->io_state = IO_STATE_NOT_OPEN;
			indicate_open_complete(sasl_client_io_instance, IO_OPEN_ERROR);
		}
		break;

	case IO_STATE_OPEN:
		sasl_client_io_instance->io_state = IO_STATE_ERROR;
		indicate_error(sasl_client_io_instance);
		break;
	}
}
/* Codes_SRS_TLSIO_SSL_ESP8266_99_026: [ The tlsio_openssl_open shall start the process to open the ssl connection with the host provided in the tlsio_openssl_create. ]*/
int tlsio_openssl_open(CONCRETE_IO_HANDLE tls_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)
{
    //LogInfo("tlsio_openssl_open begin: %d", system_get_free_heap_size());
    int result;

    if (tls_io == NULL)
    {
        /* Codes_TLSIO_SSL_ESP8266_99_036: [ If the tls_io handle is NULL, the tlsio_openssl_open shall not do anything, and return _LINE_. ]*/
        result = __LINE__;
        LogError("NULL tls_io.");
    }
    else
    {

        TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;

        /* Codes_SRS_TLSIO_SSL_ESP8266_99_035: [ If the tlsio state is not TLSIO_STATE_NOT_OPEN and not TLSIO_STATE_ERROR, then tlsio_openssl_open shall set the tlsio state as TLSIO_STATE_ERROR, and return _LINE_. ]*/
        if (tls_io_instance->tlsio_state != TLSIO_STATE_NOT_OPEN && tls_io_instance->tlsio_state != TLSIO_STATE_ERROR)
        {
            tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
            tls_io_instance->on_io_error = on_io_error;
            tls_io_instance->on_io_error_context = on_io_error_context;

            result = __LINE__;
            LogError("Invalid tlsio_state for open. Expected state is TLSIO_STATE_NOT_OPEN or TLSIO_STATE_ERROR.");
            if (tls_io_instance->on_io_error != NULL)
            {
                tls_io_instance->on_io_error(tls_io_instance->on_io_error_context);
            }
        }
        else
        {
            int netconn_retry = 0;
            int ret;

            /* Codes_SRS_TLSIO_SSL_ESP8266_99_004: [ The tlsio_ssl_esp8266 shall call the callbacks functions defined in the `xio.h`. ]*/
            /* Codes_SRS_TLSIO_SSL_ESP8266_99_006: [ The tlsio_ssl_esp8266 shall return the status of all async operations using the callbacks. ]*/
            /* Codes_SRS_TLSIO_SSL_ESP8266_99_007: [ If the callback function is set as NULL. The tlsio_ssl_esp8266 shall not call anything. ]*/
            /* Codes_SRS_TLSIO_SSL_ESP8266_99_028: [ The tlsio_openssl_open shall store the provided on_io_open_complete callback function address. ]*/
            tls_io_instance->on_io_open_complete = on_io_open_complete;
            /* Codes_SRS_TLSIO_SSL_ESP8266_99_029: [ The tlsio_openssl_open shall store the provided on_io_open_complete_context handle. ]*/
            tls_io_instance->on_io_open_complete_context = on_io_open_complete_context;

            /* Codes_SRS_TLSIO_SSL_ESP8266_99_030: [ The tlsio_openssl_open shall store the provided on_bytes_received callback function address. ]*/
            tls_io_instance->on_bytes_received = on_bytes_received;
            /* Codes_SRS_TLSIO_SSL_ESP8266_99_031: [ The tlsio_openssl_open shall store the provided on_bytes_received_context handle. ]*/
            tls_io_instance->on_bytes_received_context = on_bytes_received_context;

            /* Codes_SRS_TLSIO_SSL_ESP8266_99_032: [ The tlsio_openssl_open shall store the provided on_io_error callback function address. ]*/
            tls_io_instance->on_io_error = on_io_error;
            /* Codes_SRS_TLSIO_SSL_ESP8266_99_033: [ The tlsio_openssl_open shall store the provided on_io_error_context handle. ]*/
            tls_io_instance->on_io_error_context = on_io_error_context;

            tls_io_instance->tlsio_state = TLSIO_STATE_OPENING;

            do {
                //LogInfo("size before netconn_gethostbyname: %d", system_get_free_heap_size());
                /* Codes_SRS_TLSIO_SSL_ESP8266_99_018: [ The tlsio_openssl_open shall convert the provide hostName to an IP address. ]*/
                ret = netconn_gethostbyname(tls_io_instance->hostname, &tls_io_instance->target_ip);
                /* Codes_SRS_TLSIO_SSL_ESP8266_99_027: [ The tlsio_openssl_open shall set the tlsio to try to open the connection for MAX_RETRY times before assuming that connection failed. ]*/
            } while((ret != 0) && netconn_retry++ < MAX_RETRY);

            /* Codes_SRS_TLSIO_SSL_ESP8266_99_019: [ If the WiFi cannot find the IP for the hostName, the tlsio_openssl_open shall return __LINE__. ]*/
            if (ret != 0 || openssl_thread_LWIP_CONNECTION(tls_io_instance) != 0){
                tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
                /* Codes_SRS_TLSIO_SSL_ESP8266_99_039: [ If the tlsio_openssl_open failed to open the tls connection, and the on_io_open_complete callback was provided, it shall call the on_io_open_complete with IO_OPEN_ERROR. ]*/
                indicate_open_complete(tls_io_instance, IO_OPEN_ERROR);
                /* Codes_SRS_TLSIO_SSL_ESP8266_99_037: [ If the ssl client is not connected, the tlsio_openssl_open shall change the state to TLSIO_STATE_ERROR, log the error, and return _LINE_. ]*/
                result = __LINE__;
                LogError("openssl_thread_LWIP_CONNECTION failed.");
                if (tls_io_instance->on_io_error != NULL)
                {
                    /* Codes_SRS_TLSIO_SSL_ESP8266_99_040: [ If the tlsio_openssl_open failed to open the tls connection, and the on_io_error callback was provided, it shall call the on_io_error. ]*/
                    tls_io_instance->on_io_error(tls_io_instance->on_io_error_context);
                }
            }else{
                /* Codes_SRS_TLSIO_SSL_ESP8266_99_034: [ If tlsio_openssl_open get success to open the ssl connection, it shall set the tlsio state as TLSIO_STATE_OPEN, and return 0. ]*/
                tls_io_instance->tlsio_state = TLSIO_STATE_OPEN;
                /* Codes_SRS_TLSIO_SSL_ESP8266_99_041: [ If the tlsio_openssl_open get success to open the tls connection, and the on_io_open_complete callback was provided, it shall call the on_io_open_complete with IO_OPEN_OK. ]*/
                indicate_open_complete(tls_io_instance, IO_OPEN_OK);
                result = 0;
                os_delay_us(5000000); //delay added to give reconnect time to send last message
                //LogInfo("tlsio_openssl_open end: %d", system_get_free_heap_size());
            }
        }
    }
    return result;
}
Exemplo n.º 11
0
static void sasl_frame_received_callback(void* context, AMQP_VALUE sasl_frame)
{
	SASL_CLIENT_IO_INSTANCE* sasl_client_io_instance = (SASL_CLIENT_IO_INSTANCE*)context;

	/* Codes_SRS_SASLCLIENTIO_01_067: [The SASL frame exchange shall be started as soon as the SASL header handshake is done.] */
	switch (sasl_client_io_instance->io_state)
	{
	default:
		break;

	case IO_STATE_OPEN:
	case IO_STATE_OPENING_UNDERLYING_IO:
	case IO_STATE_CLOSING:
		/* 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.] */
		handle_error(sasl_client_io_instance);
		break;

	case IO_STATE_SASL_HANDSHAKE:
		if (sasl_client_io_instance->sasl_header_exchange_state != SASL_HEADER_EXCHANGE_HEADER_EXCH)
		{
			/* 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.] */
			handle_error(sasl_client_io_instance);
		}
		else
		{
			AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(sasl_frame);
			if (descriptor == NULL)
			{
				/* 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.] */
				handle_error(sasl_client_io_instance);
			}
			else
			{
				log_incoming_frame(sasl_client_io_instance, sasl_frame);

				/* Codes_SRS_SASLCLIENTIO_01_032: [The peer acting as the SASL server MUST announce supported authentication mechanisms using the sasl-mechanisms frame.] */
				/* 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.] */
				/* Codes_SRS_SASLCLIENTIO_01_034: [<-- SASL-MECHANISMS] */
				if (is_sasl_mechanisms_type_by_descriptor(descriptor))
				{
					switch (sasl_client_io_instance->sasl_client_negotiation_state)
					{
					case SASL_CLIENT_NEGOTIATION_NOT_STARTED:
					{
						SASL_MECHANISMS_HANDLE sasl_mechanisms_handle;

						if (amqpvalue_get_sasl_mechanisms(sasl_frame, &sasl_mechanisms_handle) != 0)
						{
							/* 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.] */
							handle_error(sasl_client_io_instance);
						}
						else
						{
							AMQP_VALUE sasl_server_mechanisms;
							uint32_t mechanisms_count;

							if ((sasl_mechanisms_get_sasl_server_mechanisms(sasl_mechanisms_handle, &sasl_server_mechanisms) != 0) ||
								(amqpvalue_get_array_item_count(sasl_server_mechanisms, &mechanisms_count) != 0) ||
								(mechanisms_count == 0))
							{
								/* Codes_SRS_SASLCLIENTIO_01_042: [It is invalid for this list to be null or empty.] */
								handle_error(sasl_client_io_instance);
							}
							else
							{
								const char* sasl_mechanism_name = saslmechanism_get_mechanism_name(sasl_client_io_instance->sasl_mechanism);
								if (sasl_mechanism_name == NULL)
								{
									/* 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.] */
									handle_error(sasl_client_io_instance);
								}
								else
								{
									uint32_t i;

									for (i = 0; i < mechanisms_count; i++)
									{
										AMQP_VALUE sasl_server_mechanism;
										sasl_server_mechanism = amqpvalue_get_array_item(sasl_server_mechanisms, i);
										if (sasl_server_mechanism == NULL)
										{
											i = mechanisms_count;
										}
										else
										{
											const char* sasl_server_mechanism_name;
											if (amqpvalue_get_symbol(sasl_server_mechanism, &sasl_server_mechanism_name) != 0)
											{
												i = mechanisms_count;
											}
											else
											{
												if (strcmp(sasl_mechanism_name, sasl_server_mechanism_name) == 0)
												{
                                                    amqpvalue_destroy(sasl_server_mechanism);
                                                    break;
												}
											}

                                            amqpvalue_destroy(sasl_server_mechanism);
                                        }
									}

									if (i == mechanisms_count)
									{
										/* 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.] */
										handle_error(sasl_client_io_instance);
									}
									else
									{
										sasl_client_io_instance->sasl_client_negotiation_state = SASL_CLIENT_NEGOTIATION_MECH_RCVD;

										/* Codes_SRS_SASLCLIENTIO_01_035: [SASL-INIT -->] */
										/* Codes_SRS_SASLCLIENTIO_01_033: [The partner MUST then choose one of the supported mechanisms and initiate a sasl exchange.] */
										/* Codes_SRS_SASLCLIENTIO_01_054: [Selects the sasl mechanism and provides the initial response if needed.] */
										if (send_sasl_init(sasl_client_io_instance, sasl_mechanism_name) != 0)
										{
											/* 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.] */
											handle_error(sasl_client_io_instance);
										}
										else
										{
											sasl_client_io_instance->sasl_client_negotiation_state = SASL_CLIENT_NEGOTIATION_INIT_SENT;
										}
									}
								}
							}

							sasl_mechanisms_destroy(sasl_mechanisms_handle);
						}

						break;
					}
					}
				}
				/* Codes_SRS_SASLCLIENTIO_01_052: [Send the SASL challenge data as defined by the SASL specification.] */
				/* Codes_SRS_SASLCLIENTIO_01_036: [<-- SASL-CHALLENGE *] */
				/* 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.] */
				else if (is_sasl_challenge_type_by_descriptor(descriptor))
				{
					/* Codes_SRS_SASLCLIENTIO_01_032: [The peer acting as the SASL server MUST announce supported authentication mechanisms using the sasl-mechanisms frame.] */
					if ((sasl_client_io_instance->sasl_client_negotiation_state != SASL_CLIENT_NEGOTIATION_INIT_SENT) &&
						(sasl_client_io_instance->sasl_client_negotiation_state != SASL_CLIENT_NEGOTIATION_RESPONSE_SENT))
					{
						handle_error(sasl_client_io_instance);
					}
					else
					{
						SASL_CHALLENGE_HANDLE sasl_challenge_handle;

						if (amqpvalue_get_sasl_challenge(sasl_frame, &sasl_challenge_handle) != 0)
						{
							/* 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.] */
							handle_error(sasl_client_io_instance);
						}
						else
						{
							amqp_binary challenge_binary_value;
							SASL_MECHANISM_BYTES response_bytes;

							/* Codes_SRS_SASLCLIENTIO_01_053: [Challenge information, a block of opaque binary data passed to the security mechanism.] */
							if (sasl_challenge_get_challenge(sasl_challenge_handle, &challenge_binary_value) != 0)
							{
								/* 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.] */
								handle_error(sasl_client_io_instance);
							}
							else
							{
								SASL_MECHANISM_BYTES challenge = { challenge_binary_value.bytes, challenge_binary_value.length };

								/* Codes_SRS_SASLCLIENTIO_01_057: [The contents of this data are defined by the SASL security mechanism.] */
								/* Codes_SRS_SASLCLIENTIO_01_037: [SASL-RESPONSE -->] */
								if ((saslmechanism_challenge(sasl_client_io_instance->sasl_mechanism, &challenge, &response_bytes) != 0) ||
									(send_sasl_response(sasl_client_io_instance, response_bytes) != 0))
								{
									/* 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.] */
									handle_error(sasl_client_io_instance);
								}
							}

							sasl_challenge_destroy(sasl_challenge_handle);
						}
					}
				}
				/* Codes_SRS_SASLCLIENTIO_01_058: [This frame indicates the outcome of the SASL dialog.] */
				/* Codes_SRS_SASLCLIENTIO_01_038: [<-- SASL-OUTCOME] */
				else if (is_sasl_outcome_type_by_descriptor(descriptor))
				{
					/* Codes_SRS_SASLCLIENTIO_01_032: [The peer acting as the SASL server MUST announce supported authentication mechanisms using the sasl-mechanisms frame.] */
					if ((sasl_client_io_instance->sasl_client_negotiation_state != SASL_CLIENT_NEGOTIATION_INIT_SENT) &&
						(sasl_client_io_instance->sasl_client_negotiation_state != SASL_CLIENT_NEGOTIATION_RESPONSE_SENT))
					{
						handle_error(sasl_client_io_instance);
					}
					else
					{
						SASL_OUTCOME_HANDLE sasl_outcome;

						sasl_client_io_instance->sasl_client_negotiation_state = SASL_CLIENT_NEGOTIATION_OUTCOME_RCVD;

						if (amqpvalue_get_sasl_outcome(sasl_frame, &sasl_outcome) != 0)
						{
							handle_error(sasl_client_io_instance);
						}
						else
						{
							sasl_code sasl_code;

							/* Codes_SRS_SASLCLIENTIO_01_060: [A reply-code indicating the outcome of the SASL dialog.] */
							if (sasl_outcome_get_code(sasl_outcome, &sasl_code) != 0)
							{
								handle_error(sasl_client_io_instance);
							}
							else
							{
								switch (sasl_code)
								{
								default:
								case sasl_code_auth:
									/* Codes_SRS_SASLCLIENTIO_01_063: [1 Connection authentication failed due to an unspecified problem with the supplied credentials.] */
								case sasl_code_sys:
									/* Codes_SRS_SASLCLIENTIO_01_064: [2 Connection authentication failed due to a system error.] */
								case sasl_code_sys_perm:
									/* Codes_SRS_SASLCLIENTIO_01_065: [3 Connection authentication failed due to a system error that is unlikely to be corrected without intervention.] */
								case sasl_code_sys_temp:
									/* Codes_SRS_SASLCLIENTIO_01_066: [4 Connection authentication failed due to a transient system error.] */
									handle_error(sasl_client_io_instance);
									break;

								case sasl_code_ok:
									/* Codes_SRS_SASLCLIENTIO_01_059: [Upon successful completion of the SASL dialog the security layer has been established] */
									/* Codes_SRS_SASLCLIENTIO_01_062: [0 Connection authentication succeeded.]  */
									sasl_client_io_instance->io_state = IO_STATE_OPEN;
									indicate_open_complete(sasl_client_io_instance, IO_OPEN_OK);
									break;
								}
							}

							sasl_outcome_destroy(sasl_outcome);
						}
					}
				}
				else
				{
					LOG(sasl_client_io_instance->logger_log, LOG_LINE, "Bad SASL frame");
				}
			}
		}
		break;
	}
}