This commit is contained in:
Roy Sprowl 2017-09-14 10:35:25 -07:00
Родитель a102ed5055
Коммит 24fb05bf9c
13 изменённых файлов: 1310 добавлений и 0 удалений

3
.gitmodules поставляемый Normal file
Просмотреть файл

@ -0,0 +1,3 @@
[submodule "sdk"]
path = sdk
url = https://github.com/Azure/azure-iot-sdk-c.git

Просмотреть файл

@ -1,4 +1,100 @@
# Get Started with Microsoft Azure IoT Starter Kit - ESP32-DevKitC ("Core Board")
This sample was tested with Espressif's **ESP32-DevKitC ("Core Board")**, but many other kits would work as well.
Don't have a kit yet? Click [here](http://esp32.net/)
This sample was modified from [this one](https://github.com/ustccw/AzureESP32.git).
## Step 1 - Download the ESP32 SDK
Clone the [Espressif IoT Development Framework](https://github.com/espressif/esp-idf) repository with the following command:
`git clone https://github.com/espressif/esp-idf.git --recursive`
## Step 2 - Set up the ESP32 toolchain
Follow the instructions for setting up the ESP32 toolchain found [here](http://esp-idf.readthedocs.io/en/latest/#setup-toolchain).
## Step 3 - Set IDF_PATH
Set the IDF_PATH environment variable to point to the location of the **esp-idf** directory that you
cloned in Step 1.
If you're using MSYS on Windows, a good place to set the IDF_PATH variable is in the
`~\msys32\home\user\.bashrc` file that gets created the first time you run `msys2_shell.cmd`.
## Step 4 - Install the Azure IoT C SDK
Change to the ESP32 SDK's `components` directory:<br/>
`cd $IDF_PATH/components`<br/>
Clone this repository into the `components` directory as `azure-iot`:<br/>
`git clone --recursive https://github.com/Azure-Samples/iot-hub-c-esp32.git azure-iot`
## Step 5 - Assemble the sample project
Your `$IDF_PATH/components/azure-iot/sample` directory contains a sample project skeleton. You may
compile it from that location, or you may copy it to a new location, whichever you prefer.
To flesh out the skeleton,
copy the sample files from the Azure IoT SDK into `main` directory of the copy of the sample that
you're using:
`sloc=$IDF_PATH/components/azure-iot/sdk/iothub_client/samples/iothub_client_sample_mqtt`<br/>
`cp $sloc/iothub_client_sample_mqtt.h <your_sample_location>/main`<br/>
`cp $sloc/iothub_client_sample_mqtt.c <your_sample_location>/main`
## Step 6 - Set your device's connection string
Create an IoT Hub and an associated device identity
[as shown here](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-csharp-csharp-getstarted).
Then open the `main/iothub_client_sample_mqtt.c` file in the `main` directory of your
project and find the line near the top that reads
```c
static const char* connectionString = "";
```
and set the value of the connectionString variable to the be the connection string of the device
identity that you created.
## Step 7- Configure the make process
Using the toolchain you installed in Step 2 (MSYS, for example), navigate to the location of the
sample you assembled in Step 4 and run the following command:
`make menuconfig`
This command will bring up a configuration dialog.
1. Under "Serial flasher config --->Default serial port" set the serial port ID to that of your ESP32 device. (On Windows you can find the serial port ID under Computer Management.)
1. Under "Example Configuration --->" enter your WiFi router SSID and password.
1. Save the configuration and exit the dialog.
## Step 8 - Run the make process
Build the sample with the simple command:
`make`
This will produce a iothub_client_sample_mqtt.bin file, a partitions_singleapp.bin file, a bootloader/bootloader.bin file, plus associated maps.
## Step 9 - Flash the ESP32 device
Make sure the ESP32 device is plugged in and run the command:
`make flash`
This will flash the project onto the ESP32 device. Alternate methods of flashing the device can be found [here](https://espressif.com/en/support/download/other-tools)
## Step 10 - Monitor the device output
The sample program sends status output to the device's serial port at a default 115200 baud. You monitor this output by connecting to the serial port with any terminal program such as [Putty](http://www.putty.org/).
# Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a

110
component.mk Normal file
Просмотреть файл

@ -0,0 +1,110 @@
#
# Component Makefile
#
# Component configuration in preprocessor defines
CFLAGS += -DUSE_LWIP_SOCKET_FOR_AZURE_IOT
#COMPONENT_ADD_INCLUDEDIRS := sdk/iothub_client/inc sdk/c-utility/inc sdk/uamqp/inc
#COMPONENT_SRCDIRS := sdk/iothub_client/src sdk/c-utility/src sdk/uamqp/src
COMPONENT_ADD_INCLUDEDIRS := \
pal \
sdk/c-utility/inc \
sdk/c-utility/inc/azure_c_shared_utility \
sdk/c-utility/pal/inc \
sdk/iothub_client/inc \
sdk/umqtt/inc \
sdk/umqtt/inc/azure_umqtt_c \
sdk/parson
COMPONENT_OBJS = \
sdk/c-utility/src/xlogging.o \
sdk/c-utility/src/buffer.o \
sdk/c-utility/src/consolelogger.o \
sdk/c-utility/src/constbuffer.o \
sdk/c-utility/src/constmap.o \
sdk/c-utility/src/crt_abstractions.o \
sdk/c-utility/src/doublylinkedlist.o \
sdk/c-utility/src/gballoc.o \
sdk/c-utility/src/gb_stdio.o \
sdk/c-utility/src/gb_time.o \
sdk/c-utility/src/hmac.o \
sdk/c-utility/src/hmacsha256.o \
sdk/c-utility/src/httpapiex.o \
sdk/c-utility/src/httpapiexsas.o \
sdk/c-utility/src/httpheaders.o \
sdk/c-utility/src/map.o \
sdk/c-utility/src/optionhandler.o \
sdk/c-utility/src/sastoken.o \
sdk/c-utility/src/sha1.o \
sdk/c-utility/src/sha224.o \
sdk/c-utility/src/sha384-512.o \
sdk/c-utility/src/strings.o \
sdk/c-utility/src/string_tokenizer.o \
sdk/c-utility/src/urlencode.o \
sdk/c-utility/src/usha.o \
sdk/c-utility/src/vector.o \
sdk/c-utility/src/xio.o \
sdk/c-utility/src/base64.o \
\
\
sdk/iothub_client/src/iothub_client.o \
sdk/iothub_client/src/iothub_client_ll.o \
sdk/iothub_client/src/iothub_client_ll_uploadtoblob.o \
sdk/iothub_client/src/iothub_client_authorization.o \
sdk/iothub_client/src/iothub_client_retry_control.o \
sdk/iothub_client/src/iothub_message.o \
sdk/iothub_client/src/iothubtransport.o \
sdk/iothub_client/src/iothubtransportmqtt.o \
sdk/iothub_client/src/iothubtransport_mqtt_common.o \
sdk/iothub_client/src/version.o \
\
\
sdk/umqtt/src/mqtt_client.o \
sdk/umqtt/src/mqtt_codec.o \
sdk/umqtt/src/mqtt_message.o \
\
\
\
sdk/c-utility/adapters/agenttime.o \
sdk/c-utility/src/singlylinkedlist.o \
\
\
sdk/c-utility/pal/dns_async.o \
sdk/c-utility/pal/socket_async.o \
sdk/c-utility/pal/free_rtos/threadapi.o \
sdk/c-utility/pal/free_rtos/tickcounter.o \
sdk/c-utility/pal/lwip/sntp_lwip.o \
\
pal/platform_openssl_compact.o \
pal/tlsio_openssl_compact.o
COMPONENT_SRCDIRS := \
pal \
sdk/c-utility/pal \
sdk/c-utility/pal/free_rtos \
sdk/c-utility/pal/lwip \
sdk/c-utility/src \
sdk/c-utility/adapters \
sdk/umqtt/src \
sdk/iothub_client/src \
sdk/parson \

Просмотреть файл

@ -0,0 +1,42 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include "azure_c_shared_utility/platform.h"
#include "sntp.h"
#include "tlsio_openssl_compact.h"
static const char* const ntpServer = "pool.ntp.org";
/* Codes_SRS_PLATFORM_OPENSSL_COMPACT_30_004: [ The platform_init shall initialize the tlsio adapter. ] */
/* Codes_SRS_PLATFORM_OPENSSL_COMPACT_30_005: [ The platform_init shall initialize the sntp client. ] */
int platform_init(void)
{
// SNTP_SetServerName logs any necessary errors
int result = SNTP_SetServerName(ntpServer);
if (result == 0)
{
// SNTP_Init will have logged its own errors if necessary
result = SNTP_Init();
}
return result;
}
/* Codes_SRS_PLATFORM_OPENSSL_COMPACT_30_008: [ The platform_get_default_tlsio shall return a set of tlsio functions provided by the OpenSSL micro tlsio implementation. ] */
const IO_INTERFACE_DESCRIPTION* platform_get_default_tlsio(void)
{
return tlsio_openssl_compact_get_interface_description();
}
STRING_HANDLE platform_get_platform_info(void)
{
return STRING_construct("(openssl_compact)");
}
/* Codes_SRS_PLATFORM_OPENSSL_COMPACT_30_006: [ The platform_deinit shall deinitialize the sntp client. ] */
/* Codes_SRS_PLATFORM_OPENSSL_COMPACT_30_007: [ The platform_deinit shall deinitialize the tlsio adapter. ] */
void platform_deinit(void)
{
SNTP_Deinit();
// The tlsio adapter for this platform does not need (or support) deinitialization
}

16
pal/sntp_os.h Normal file
Просмотреть файл

@ -0,0 +1,16 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//This file pulls in OS-specific header files to allow compilation of socket_async.c under
// most OS's except for Windows.
// For ESP32 lwIP systems which use the ESP-IDF's non-standard lwIP include structure
// Tested with:
// ESP32
#ifndef LWIP_SNTP_OS_H
#define LWIP_SNTP_OS_H
#include "apps/sntp/sntp.h"
#endif // LWIP_SNTP_OS_H

17
pal/socket_async_os.h Normal file
Просмотреть файл

@ -0,0 +1,17 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//This file pulls in OS-specific header files to allow compilation of socket_async.c under
// most OS's except for Windows.
// For lwIP systems
// Tested with:
// ESP32
#ifndef SOCKET_ASYNC_OS_H
#define SOCKET_ASYNC_OS_H
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#endif // SOCKET_ASYNC_OS_H

879
pal/tlsio_openssl_compact.c Normal file
Просмотреть файл

@ -0,0 +1,879 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdlib.h>
#include "openssl/ssl.h"
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "socket_async.h"
#include "tlsio_openssl_compact.h"
#include "dns_async.h"
#include "azure_c_shared_utility/gballoc.h"
#include "azure_c_shared_utility/tlsio.h"
#include "azure_c_shared_utility/xlogging.h"
#include "azure_c_shared_utility/agenttime.h"
#include "azure_c_shared_utility/singlylinkedlist.h"
#include "azure_c_shared_utility/crt_abstractions.h"
typedef struct
{
unsigned char* bytes;
size_t size;
size_t unsent_size;
ON_SEND_COMPLETE on_send_complete;
void* callback_context;
} PENDING_TRANSMISSION;
#define MAX_VALID_PORT 0xffff
// The TLSIO_RECEIVE_BUFFER_SIZE has very little effect on performance, and is kept small
// to minimize memory consumption.
#define TLSIO_RECEIVE_BUFFER_SIZE 64
typedef enum TLSIO_STATE_TAG
{
TLSIO_STATE_CLOSED,
TLSIO_STATE_OPENING_WAITING_DNS,
TLSIO_STATE_OPENING_WAITING_SOCKET,
TLSIO_STATE_OPENING_WAITING_SSL,
TLSIO_STATE_OPEN,
TLSIO_STATE_ERROR,
} TLSIO_STATE;
bool is_an_opening_state(TLSIO_STATE state)
{
return state == TLSIO_STATE_OPENING_WAITING_DNS ||
state == TLSIO_STATE_OPENING_WAITING_SOCKET ||
state == TLSIO_STATE_OPENING_WAITING_SSL;
}
// This structure definition is mirrored in the unit tests, so if you change
// this struct, keep it in sync with the one in tlsio_openssl_compact_ut.c
typedef struct TLS_IO_INSTANCE_TAG
{
ON_BYTES_RECEIVED on_bytes_received;
ON_IO_ERROR on_io_error;
ON_IO_OPEN_COMPLETE on_open_complete;
void* on_bytes_received_context;
void* on_io_error_context;
void* on_open_complete_context;
SSL* ssl;
SSL_CTX* ssl_context;
TLSIO_STATE tlsio_state;
DNS_ASYNC_HANDLE dns;
char* hostname;
uint16_t port;
SOCKET_ASYNC_HANDLE sock;
SINGLYLINKEDLIST_HANDLE pending_transmission_list;
} TLS_IO_INSTANCE;
/* Codes_SRS_TLSIO_30_005: [ The phrase "enter TLSIO_STATE_EXT_ERROR" means the adapter shall call the on_io_error function and pass the on_io_error_context that was supplied in tlsio_open_async. ]*/
static void enter_tlsio_error_state(TLS_IO_INSTANCE* tls_io_instance)
{
if (tls_io_instance->tlsio_state != TLSIO_STATE_ERROR)
{
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
tls_io_instance->on_io_error(tls_io_instance->on_io_error_context);
}
}
/* Codes_SRS_TLSIO_30_005: [ When the adapter enters TLSIO_STATE_EXT_ERROR it shall call the on_io_error function and pass the on_io_error_context that were supplied in tlsio_open . ]*/
static void enter_open_error_state(TLS_IO_INSTANCE* tls_io_instance)
{
enter_tlsio_error_state(tls_io_instance);
// on_open_complete has already been checked for non-NULL
tls_io_instance->on_open_complete(tls_io_instance->on_open_complete_context, IO_OPEN_ERROR);
}
// Return true if a message was available to remove
static bool process_and_destroy_head_message(TLS_IO_INSTANCE* tls_io_instance, IO_SEND_RESULT send_result)
{
bool result;
LIST_ITEM_HANDLE head_pending_io;
if (send_result == IO_SEND_ERROR)
{
/* Codes_SRS_TLSIO_30_095: [ If the send process fails before sending all of the bytes in an enqueued message, the tlsio_dowork shall call the message's on_send_complete along with its associated callback_context and IO_SEND_ERROR. ]*/
enter_tlsio_error_state(tls_io_instance);
}
head_pending_io = singlylinkedlist_get_head_item(tls_io_instance->pending_transmission_list);
if (head_pending_io != NULL)
{
PENDING_TRANSMISSION* head_message = (PENDING_TRANSMISSION*)singlylinkedlist_item_get_value(head_pending_io);
// on_send_complete is checked for NULL during PENDING_TRANSMISSION creation
/* Codes_SRS_TLSIO_30_095: [ If the send process fails before sending all of the bytes in an enqueued message, the tlsio_dowork shall call the message's on_send_complete along with its associated callback_context and IO_SEND_ERROR. ]*/
head_message->on_send_complete(head_message->callback_context, send_result);
free(head_message->bytes);
free(head_message);
if (singlylinkedlist_remove(tls_io_instance->pending_transmission_list, head_pending_io) != 0)
{
// This particular situation is a bizarre and unrecoverable internal error
/* Codes_SRS_TLSIO_30_094: [ If the send process encounters an internal error or calls on_send_complete with IO_SEND_ERROR due to either failure or timeout, it shall also call on_io_error and pass in the associated on_io_error_context. ]*/
enter_tlsio_error_state(tls_io_instance);
LogError("Failed to remove message from list");
}
result = true;
}
else
{
result = false;
}
return result;
}
static void internal_close(TLS_IO_INSTANCE* tls_io_instance)
{
/* Codes_SRS_TLSIO_30_009: [ The phrase "enter TLSIO_STATE_EXT_CLOSING" means the adapter shall iterate through any unsent messages in the queue and shall delete each message after calling its on_send_complete with the associated callback_context and IO_SEND_CANCELLED. ]*/
/* Codes_SRS_TLSIO_30_006: [ The phrase "enter TLSIO_STATE_EXT_CLOSED" means the adapter shall forcibly close any existing connections then call the on_io_close_complete function and pass the on_io_close_complete_context that was supplied in tlsio_close_async. ]*/
/* Codes_SRS_TLSIO_30_051: [ On success, if the underlying TLS does not support asynchronous closing, then the adapter shall enter TLSIO_STATE_EXT_CLOSED immediately after entering TLSIO_STATE_EX_CLOSING. ]*/
if (tls_io_instance->tlsio_state == TLSIO_STATE_OPEN)
{
// From the OpenSSL manual pages: "According to the TLS standard, it is acceptable
// for an application to only send its shutdown alert and then close the
// underlying connection without waiting for the peer's response...". It goes
// on to say that waiting for shutdown only makes sense if the underlying
// connection is being re-used, which we do not do. So there's no need
// to wait for shutdown. The SSL_shutdown result is not logged because the
// return values are of no interest for unidirectional shutdown, which is
// what we use.
(void)SSL_shutdown(tls_io_instance->ssl);
}
if (tls_io_instance->dns != NULL)
{
dns_async_destroy(tls_io_instance->dns);
tls_io_instance->dns = NULL;
}
if (tls_io_instance->ssl != NULL)
{
SSL_free(tls_io_instance->ssl);
tls_io_instance->ssl = NULL;
}
if (tls_io_instance->ssl_context != NULL)
{
SSL_CTX_free(tls_io_instance->ssl_context);
tls_io_instance->ssl_context = NULL;
}
if (tls_io_instance->sock >= 0)
{
// The underlying socket API does not support waiting for close
// to complete, so it isn't possible to do so.
socket_async_destroy(tls_io_instance->sock);
tls_io_instance->sock = -1;
}
while (process_and_destroy_head_message(tls_io_instance, IO_SEND_CANCELLED));
// singlylinkedlist_destroy gets called in the main destroy
tls_io_instance->on_bytes_received = NULL;
tls_io_instance->on_io_error = NULL;
tls_io_instance->on_bytes_received_context = NULL;
tls_io_instance->on_io_error_context = NULL;
tls_io_instance->tlsio_state = TLSIO_STATE_CLOSED;
tls_io_instance->on_open_complete = NULL;
tls_io_instance->on_open_complete_context = NULL;
}
// This method tests for hard errors returned from either SSL_write or SSL_connect.
// Returns
// 0 for SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE
// The actual error for other errors (real failures)
static int is_hard_ssl_error(SSL* ssl, int callReturn)
{
int result = SSL_get_error(ssl, callReturn);
if (result == SSL_ERROR_WANT_READ || result == SSL_ERROR_WANT_WRITE)
{
result = 0;
}
return result;
}
static void tlsio_openssl_destroy(CONCRETE_IO_HANDLE tls_io)
{
if (tls_io == NULL)
{
/* Codes_SRS_TLSIO_30_020: [ If tlsio_handle is NULL, tlsio_destroy shall do nothing. ]*/
LogError("NULL tlsio");
}
else
{
TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
if (tls_io_instance->tlsio_state != TLSIO_STATE_CLOSED)
{
/* Codes_SRS_TLSIO_30_022: [ If the adapter is in any state other than TLSIO_STATE_EX_CLOSED when tlsio_destroy is called, the adapter shall enter TLSIO_STATE_EX_CLOSING and then enter TLSIO_STATE_EX_CLOSED before completing the destroy process. ]*/
LogError("tlsio_openssl_destroy called while not in TLSIO_STATE_CLOSED.");
internal_close(tls_io_instance);
}
/* Codes_SRS_TLSIO_30_021: [ The tlsio_destroy shall release all allocated resources and then release tlsio_handle. ]*/
if (tls_io_instance->hostname != NULL)
{
free(tls_io_instance->hostname);
}
if (tls_io_instance->pending_transmission_list != NULL)
{
/* Pending messages were cleared in internal_close */
singlylinkedlist_destroy(tls_io_instance->pending_transmission_list);
}
free(tls_io_instance);
}
}
/* Codes_SRS_TLSIO_30_010: [ The tlsio_create shall allocate and initialize all necessary resources and return an instance of the tlsio_openssl_compact. ]*/
static CONCRETE_IO_HANDLE tlsio_openssl_create(void* io_create_parameters)
{
TLS_IO_INSTANCE* result;
if (io_create_parameters == NULL)
{
/* Codes_SRS_TLSIO_30_013: [ If the io_create_parameters value is NULL, tlsio_create shall log an error and return NULL. ]*/
LogError("NULL tls_io_config");
result = NULL;
}
else
{
/* Codes_SRS_TLSIO_30_012: [ The tlsio_create shall receive the connection configuration as a TLSIO_CONFIG* in io_create_parameters. ]*/
TLSIO_CONFIG* tls_io_config = (TLSIO_CONFIG*)io_create_parameters;
if (tls_io_config->hostname == NULL)
{
/* Codes_SRS_TLSIO_30_014: [ If the hostname member of io_create_parameters value is NULL, tlsio_create shall log an error and return NULL. ]*/
LogError("NULL tls_io_config->hostname");
result = NULL;
}
else
{
if (tls_io_config->port < 0 || tls_io_config->port > MAX_VALID_PORT)
{
/* Codes_SRS_TLSIO_30_015: [ If the port member of io_create_parameters value is less than 0 or greater than 0xffff, tlsio_create shall log an error and return NULL. ]*/
LogError("tls_io_config->port out of range");
result = NULL;
}
else
{
result = malloc(sizeof(TLS_IO_INSTANCE));
if (result == NULL)
{
/* Codes_SRS_TLSIO_30_011: [ If any resource allocation fails, tlsio_create shall return NULL. ]*/
LogError("malloc failed");
}
else
{
int ms_result;
memset(result, 0, sizeof(TLS_IO_INSTANCE));
result->port = (uint16_t)tls_io_config->port;
result->tlsio_state = TLSIO_STATE_CLOSED;
result->sock = SOCKET_ASYNC_INVALID_SOCKET;
result->hostname = NULL;
result->dns = NULL;
result->pending_transmission_list = NULL;
/* Codes_SRS_TLSIO_30_016: [ tlsio_create shall make a copy of the hostname member of io_create_parameters to allow deletion of hostname immediately after the call. ]*/
ms_result = mallocAndStrcpy_s(&result->hostname, tls_io_config->hostname);
if (ms_result != 0)
{
/* Codes_SRS_TLSIO_30_011: [ If any resource allocation fails, tlsio_create shall return NULL. ]*/
LogError("malloc failed");
tlsio_openssl_destroy(result);
result = NULL;
}
else
{
// Create the message queue
result->pending_transmission_list = singlylinkedlist_create();
if (result->pending_transmission_list == NULL)
{
/* Codes_SRS_TLSIO_30_011: [ If any resource allocation fails, tlsio_create shall return NULL. ]*/
LogError("Failed singlylinkedlist_create");
tlsio_openssl_destroy(result);
result = NULL;
}
}
}
}
}
}
return (CONCRETE_IO_HANDLE)result;
}
static int tlsio_openssl_open_async(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)
{
int result;
if (on_io_open_complete == NULL)
{
/* Codes_SRS_TLSIO_30_031: [ If the on_io_open_complete parameter is NULL, tlsio_open shall log an error and return FAILURE. ]*/
LogError("Required parameter on_io_open_complete is NULL");
result = __FAILURE__;
}
else
{
if (tls_io == NULL)
{
/* Codes_SRS_TLSIO_30_030: [ If the tlsio_handle parameter is NULL, tlsio_open shall log an error and return FAILURE. ]*/
result = __FAILURE__;
LogError("NULL tlsio");
}
else
{
if (on_bytes_received == NULL)
{
/* Codes_SRS_TLSIO_30_032: [ If the on_bytes_received parameter is NULL, tlsio_open shall log an error and return FAILURE. ]*/
LogError("Required parameter on_bytes_received is NULL");
result = __FAILURE__;
}
else
{
if (on_io_error == NULL)
{
/* Codes_SRS_TLSIO_30_033: [ If the on_io_error parameter is NULL, tlsio_open shall log an error and return FAILURE. ]*/
LogError("Required parameter on_io_error is NULL");
result = __FAILURE__;
}
else
{
TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
if (tls_io_instance->tlsio_state != TLSIO_STATE_CLOSED)
{
/* Codes_SRS_TLSIO_30_037: [ If the adapter is in any state other than TLSIO_STATE_EXT_CLOSED when tlsio_open is called, it shall log an error, and return FAILURE. ]*/
LogError("Invalid tlsio_state. Expected state is TLSIO_STATE_CLOSED.");
result = __FAILURE__;
}
else
{
tls_io_instance->dns = dns_async_create(tls_io_instance->hostname, NULL);
if (tls_io_instance->dns == NULL)
{
/* Codes_SRS_TLSIO_30_038: [ If tlsio_open fails to enter TLSIO_STATE_EX_OPENING it shall return FAILURE. ]*/
LogError("dns_async_create failed");
result = __FAILURE__;
}
else
{
/* Codes_SRS_TLSIO_30_034: [ The tlsio_open shall store the provided on_bytes_received, on_bytes_received_context, on_io_error, on_io_error_context, on_io_open_complete, and on_io_open_complete_context parameters for later use as specified and tested per other line entries in this document. ]*/
tls_io_instance->on_bytes_received = on_bytes_received;
tls_io_instance->on_bytes_received_context = on_bytes_received_context;
tls_io_instance->on_io_error = on_io_error;
tls_io_instance->on_io_error_context = on_io_error_context;
tls_io_instance->on_open_complete = on_io_open_complete;
tls_io_instance->on_open_complete_context = on_io_open_complete_context;
/* Codes_SRS_TLSIO_30_035: [ On tlsio_open success the adapter shall enter TLSIO_STATE_EX_OPENING and return 0. ]*/
// All the real work happens in dowork
tls_io_instance->tlsio_state = TLSIO_STATE_OPENING_WAITING_DNS;
result = 0;
}
}
}
}
}
/* Codes_SRS_TLSIO_30_039: [ On failure, tlsio_open_async shall not call on_io_open_complete. ]*/
}
return result;
}
// This implementation does not have asynchronous close, but uses the _async name for consistencty with the spec
static int tlsio_openssl_close_async(CONCRETE_IO_HANDLE tls_io, ON_IO_CLOSE_COMPLETE on_io_close_complete, void* callback_context)
{
int result;
if (tls_io == NULL)
{
/* Codes_SRS_TLSIO_30_050: [ If the tlsio_handle parameter is NULL, tlsio_openssl_close_async shall log an error and return FAILURE. ]*/
LogError("NULL tlsio");
result = __FAILURE__;
}
else
{
if (on_io_close_complete == NULL)
{
/* Codes_SRS_TLSIO_30_055: [ If the on_io_close_complete parameter is NULL, tlsio_openssl_close_async shall log an error and return FAILURE. ]*/
LogError("NULL on_io_close_complete");
result = __FAILURE__;
}
else
{
TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
if (tls_io_instance->tlsio_state != TLSIO_STATE_OPEN &&
tls_io_instance->tlsio_state != TLSIO_STATE_ERROR)
{
/* Codes_SRS_TLSIO_30_053: [ If the adapter is in any state other than TLSIO_STATE_EXT_OPEN or TLSIO_STATE_EXT_ERROR then tlsio_close_async shall log that tlsio_close_async has been called and then continue normally. ]*/
// LogInfo rather than LogError because this is an unusual but not erroneous situation
LogInfo("tlsio_openssl_close has been called when in neither TLSIO_STATE_OPEN nor TLSIO_STATE_ERROR.");
}
if (is_an_opening_state(tls_io_instance->tlsio_state))
{
/* Codes_SRS_TLSIO_30_057: [ On success, if the adapter is in TLSIO_STATE_EXT_OPENING, it shall call on_io_open_complete with the on_io_open_complete_context supplied in tlsio_open_async and IO_OPEN_CANCELLED. This callback shall be made before changing the internal state of the adapter. ]*/
tls_io_instance->on_open_complete(tls_io_instance->on_open_complete_context, IO_OPEN_CANCELLED);
}
// This adapter does not support asynchronous closing
/* Codes_SRS_TLSIO_30_056: [ On success the adapter shall enter TLSIO_STATE_EX_CLOSING. ]*/
/* Codes_SRS_TLSIO_30_051: [ On success, if the underlying TLS does not support asynchronous closing, then the adapter shall enter TLSIO_STATE_EX_CLOSED immediately after entering TLSIO_STATE_EX_CLOSING. ]*/
/* Codes_SRS_TLSIO_30_052: [ On success tlsio_close shall return 0. ]*/
internal_close(tls_io_instance);
on_io_close_complete(callback_context);
result = 0;
}
}
/* Codes_SRS_TLSIO_30_054: [ On failure, the adapter shall not call on_io_close_complete. ]*/
return result;
}
static int tlsio_openssl_send_async(CONCRETE_IO_HANDLE tls_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context)
{
int result;
if (on_send_complete == NULL)
{
/* Codes_SRS_TLSIO_30_062: [ If the on_send_complete is NULL, tlsio_openssl_compact_send shall log the error and return FAILURE. ]*/
result = __FAILURE__;
LogError("NULL on_send_complete");
}
else
{
if (tls_io == NULL)
{
/* Codes_SRS_TLSIO_30_060: [ If the tlsio_handle parameter is NULL, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/
result = __FAILURE__;
LogError("NULL tlsio");
}
else
{
if (buffer == NULL)
{
/* Codes_SRS_TLSIO_30_061: [ If the buffer is NULL, tlsio_openssl_compact_send shall log the error and return FAILURE. ]*/
result = __FAILURE__;
LogError("NULL buffer");
}
else
{
if (size == 0)
{
/* Codes_SRS_TLSIO_30_067: [ If the size is 0, tlsio_send shall log the error and return FAILURE. ]*/
result = __FAILURE__;
LogError("0 size");
}
else
{
TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
if (tls_io_instance->tlsio_state != TLSIO_STATE_OPEN)
{
/* Codes_SRS_TLSIO_30_065: [ If tlsio_openssl_compact_open has not been called or the opening process has not been completed, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/
result = __FAILURE__;
LogError("tlsio_openssl_send_async without a prior successful open");
}
else
{
PENDING_TRANSMISSION* pending_transmission = (PENDING_TRANSMISSION*)malloc(sizeof(PENDING_TRANSMISSION));
if (pending_transmission == NULL)
{
/* Codes_SRS_TLSIO_30_064: [ If the supplied message cannot be enqueued for transmission, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/
result = __FAILURE__;
LogError("malloc failed");
}
else
{
/* Codes_SRS_TLSIO_30_063: [ The tlsio_openssl_compact_send shall enqueue for transmission the on_send_complete, the callback_context, the size, and the contents of buffer. ]*/
pending_transmission->bytes = (unsigned char*)malloc(size);
if (pending_transmission->bytes == NULL)
{
/* Codes_SRS_TLSIO_30_064: [ If the supplied message cannot be enqueued for transmission, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/
LogError("malloc failed");
free(pending_transmission);
result = __FAILURE__;
}
else
{
pending_transmission->size = size;
pending_transmission->unsent_size = size;
pending_transmission->on_send_complete = on_send_complete;
pending_transmission->callback_context = callback_context;
(void)memcpy(pending_transmission->bytes, buffer, size);
if (singlylinkedlist_add(tls_io_instance->pending_transmission_list, pending_transmission) == NULL)
{
/* Codes_SRS_TLSIO_30_064: [ If the supplied message cannot be enqueued for transmission, tlsio_openssl_compact_send shall log an error and return FAILURE. ]*/
LogError("Unable to add socket to pending list.");
free(pending_transmission->bytes);
free(pending_transmission);
result = __FAILURE__;
}
else
{
/* Codes_SRS_TLSIO_30_063: [ On success, tlsio_send shall enqueue for transmission the on_send_complete , the callback_context , the size , and the contents of buffer and then return 0. ]*/
result = 0;
}
}
}
}
}
}
}
/* Codes_SRS_TLSIO_30_066: [ On failure, on_send_complete shall not be called. ]*/
}
return result;
}
static void dowork_read(TLS_IO_INSTANCE* tls_io_instance)
{
// TRANSFER_BUFFER_SIZE is not very important because if the message is bigger
// then the framework just calls dowork repeatedly until it gets everything. So
// a bigger buffer would just use memory without buying anything.
// Putting this buffer in a small function also allows it to exist on the stack
// rather than adding to heap fragmentation.
unsigned char buffer[TLSIO_RECEIVE_BUFFER_SIZE];
int rcv_bytes;
if (tls_io_instance->tlsio_state == TLSIO_STATE_OPEN)
{
// SSL_read is not checked for errors because the "no data" condition is reported as a
// failure, but the docs do not guarantee that it will always be the same failure,
// so we have no reliable way to distinguish "no data" from something else.
//
// Pump all of the bytes currently available out
rcv_bytes = SSL_read(tls_io_instance->ssl, buffer, sizeof(buffer));
while (rcv_bytes > 0)
{
// tls_io_instance->on_bytes_received was already checked for NULL
// in the call to tlsio_openssl_open_async
/* Codes_SRS_TLSIO_30_100: [ As long as the TLS connection is able to provide received data, tlsio_dowork shall repeatedly read this data and call on_bytes_received with the pointer to the buffer containing the data, the number of bytes received, and the on_bytes_received_context. ]*/
tls_io_instance->on_bytes_received(tls_io_instance->on_bytes_received_context, buffer, rcv_bytes);
rcv_bytes = SSL_read(tls_io_instance->ssl, buffer, sizeof(buffer));
}
/* Codes_SRS_TLSIO_30_102: [ If the TLS connection receives no data then tlsio_dowork shall not call the on_bytes_received callback. ]*/
}
}
static int create_ssl(TLS_IO_INSTANCE* tls_io_instance)
{
int result;
int ret;
tls_io_instance->ssl_context = SSL_CTX_new(TLSv1_2_client_method());
if (tls_io_instance->ssl_context == NULL)
{
/* Codes_SRS_TLSIO_30_082: [ If the connection process fails for any reason, tlsio_dowork shall log an error, call on_io_open_complete with the on_io_open_complete_context parameter provided in tlsio_open and IO_OPEN_ERROR, and enter TLSIO_STATE_EX_ERROR. ]*/
result = __FAILURE__;
LogError("create new SSL CTX failed");
}
else
{
tls_io_instance->ssl = SSL_new(tls_io_instance->ssl_context);
if (tls_io_instance->ssl == NULL)
{
/* Codes_SRS_TLSIO_30_082: [ If the connection process fails for any reason, tlsio_dowork shall log an error, call on_io_open_complete with the on_io_open_complete_context parameter provided in tlsio_open and IO_OPEN_ERROR, and enter TLSIO_STATE_EX_ERROR. ]*/
result = __FAILURE__;
LogError("SSL_new failed");
}
else
{
// returns 1 on success
ret = SSL_set_fd(tls_io_instance->ssl, tls_io_instance->sock);
if (ret != 1)
{
/* Codes_SRS_TLSIO_30_082: [ If the connection process fails for any reason, tlsio_dowork shall log an error, call on_io_open_complete with the on_io_open_complete_context parameter provided in tlsio_open and IO_OPEN_ERROR, and enter TLSIO_STATE_EX_ERROR. ]*/
result = __FAILURE__;
LogError("SSL_set_fd failed");
}
else
{
result = 0;
}
}
}
return result;
}
static void dowork_send(TLS_IO_INSTANCE* tls_io_instance)
{
LIST_ITEM_HANDLE first_pending_io = singlylinkedlist_get_head_item(tls_io_instance->pending_transmission_list);
if (first_pending_io != NULL)
{
PENDING_TRANSMISSION* pending_message = (PENDING_TRANSMISSION*)singlylinkedlist_item_get_value(first_pending_io);
uint8_t* buffer = ((uint8_t*)pending_message->bytes) +
pending_message->size - pending_message->unsent_size;
int write_result = SSL_write(tls_io_instance->ssl, buffer, pending_message->unsent_size);
// https://wiki.openssl.org/index.php/Manual:SSL_write(3)
if (write_result > 0)
{
pending_message->unsent_size -= write_result;
if (pending_message->unsent_size == 0)
{
/* Codes_SRS_TLSIO_30_091: [ If tlsio_openssl_compact_dowork is able to send all the bytes in an enqueued message, it shall call the messages's on_send_complete along with its associated callback_context and IO_SEND_OK. ]*/
// The whole message has been sent successfully
process_and_destroy_head_message(tls_io_instance, IO_SEND_OK);
}
else
{
/* Codes_SRS_TLSIO_30_093: [ If the TLS connection was not able to send an entire enqueued message at once, subsequent calls to tlsio_dowork shall continue to send the remaining bytes. ]*/
// Repeat the send on the next pass with the rest of the message
// This empty else compiles to nothing but helps readability
}
}
else
{
// SSL_write returned non-success. It may just be busy, or it may be broken.
int hard_error = is_hard_ssl_error(tls_io_instance->ssl, write_result);
if (hard_error != 0)
{
/* Codes_SRS_TLSIO_30_002: [ The phrase "destroy the failed message" means that the adapter shall remove the message from the queue and destroy it after calling the message's on_send_complete along with its associated callback_context and IO_SEND_ERROR. ]*/
/* Codes_SRS_TLSIO_30_005: [ When the adapter enters TLSIO_STATE_EXT_ERROR it shall call the on_io_error function and pass the on_io_error_context that were supplied in tlsio_open . ]*/
/* Codes_SRS_TLSIO_30_095: [ If the send process fails before sending all of the bytes in an enqueued message, tlsio_dowork shall destroy the failed message and enter TLSIO_STATE_EX_ERROR. ]*/
// This is an unexpected error, and we need to bail out. Probably lost internet connection.
LogInfo("Error from SSL_write: %d", hard_error);
process_and_destroy_head_message(tls_io_instance, IO_SEND_ERROR);
}
}
}
else
{
/* Codes_SRS_TLSIO_30_096: [ If there are no enqueued messages available, tlsio_openssl_compact_dowork shall do nothing. ]*/
}
}
static void dowork_poll_dns(TLS_IO_INSTANCE* tls_io_instance)
{
bool dns_is_complete = dns_async_is_lookup_complete(tls_io_instance->dns);
if (dns_is_complete)
{
uint32_t host_ipV4_address = dns_async_get_ipv4(tls_io_instance->dns);
dns_async_destroy(tls_io_instance->dns);
tls_io_instance->dns = NULL;
if (host_ipV4_address == 0)
{
// Transition to TSLIO_STATE_ERROR
/* Codes_SRS_TLSIO_30_082: [ If the connection process fails for any reason, tlsio_dowork shall log an error, call on_io_open_complete with the on_io_open_complete_context parameter provided in tlsio_open and IO_OPEN_ERROR, and enter TLSIO_STATE_EX_ERROR. ]*/
// The DNS failure has already been logged
enter_open_error_state(tls_io_instance);
}
else
{
SOCKET_ASYNC_HANDLE sock = socket_async_create(host_ipV4_address, tls_io_instance->port, false, NULL);
if (sock < 0)
{
// This is a communication interruption rather than a program bug
/* Codes_SRS_TLSIO_30_082: [ If the connection process fails for any reason, tlsio_dowork shall log an error, call on_io_open_complete with the on_io_open_complete_context parameter provided in tlsio_open and IO_OPEN_ERROR, and enter TLSIO_STATE_EX_ERROR. ]*/
LogInfo("Could not open the socket");
enter_open_error_state(tls_io_instance);
}
else
{
// The socket has been created successfully, so now wait for it to
// finish the TCP handshake.
tls_io_instance->sock = sock;
tls_io_instance->tlsio_state = TLSIO_STATE_OPENING_WAITING_SOCKET;
}
}
}
}
static void dowork_poll_socket(TLS_IO_INSTANCE* tls_io_instance)
{
bool is_complete;
int result = socket_async_is_create_complete(tls_io_instance->sock, &is_complete);
if (result != 0)
{
// Transition to TSLIO_STATE_ERROR
LogInfo("socket_async_is_create_complete failure");
enter_open_error_state(tls_io_instance);
}
else
{
if (is_complete)
{
// Attempt to transition to TLSIO_STATE_OPENING_WAITING_SSL
int create_ssl_result = create_ssl(tls_io_instance);
if (create_ssl_result != 0)
{
// Transition to TSLIO_STATE_ERROR
// create_ssl already did error logging
enter_open_error_state(tls_io_instance);
}
else
{
tls_io_instance->tlsio_state = TLSIO_STATE_OPENING_WAITING_SSL;
}
}
}
}
static void dowork_poll_open_ssl(TLS_IO_INSTANCE* tls_io_instance)
{
// https://www.openssl.org/docs/man1.0.2/ssl/SSL_connect.html
// "If the underlying BIO is non - blocking, SSL_connect() will also
// return when the underlying BIO could not satisfy the needs of
// SSL_connect() to continue the handshake, indicating the
// problem by the return value -1. In this case a call to
// SSL_get_error() with the return value of SSL_connect() will
// yield SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE.The calling
// process then must repeat the call after taking appropriate
// action to satisfy the needs of SSL_connect().The action
// depends on the underlying BIO. When using a non - blocking
// socket, nothing is to be done, but select() can be used to
// check for the required condition."
int connect_result = SSL_connect(tls_io_instance->ssl);
// The following note applies to the Espressif ESP32 implementation
// of OpenSSL:
// The manual pages say that 0 is a failure,
// but by experiment, 0 is the success result, at least when using
// SSL_set_fd instead of custom BIO.
// https://www.openssl.org/docs/man1.0.2/ssl/SSL_connect.html
if (connect_result == 1 || connect_result == 0)
{
/* Codes_SRS_TLSIO_30_080: [ The tlsio_dowork shall establish a TLS connection using the hostName and port provided during tlsio_open. ]*/
// Connect succeeded
tls_io_instance->tlsio_state = TLSIO_STATE_OPEN;
/* Codes_SRS_TLSIO_30_007: [ The phrase "enter TLSIO_STATE_EXT_OPEN" means the adapter shall call the on_io_open_complete function and pass IO_OPEN_OK and the on_io_open_complete_context that was supplied in tlsio_open . ]*/
/* Codes_SRS_TLSIO_30_083: [ If tlsio_dowork successfully opens the TLS connection it shall enter TLSIO_STATE_EX_OPEN. ]*/
tls_io_instance->on_open_complete(tls_io_instance->on_open_complete_context, IO_OPEN_OK);
}
else
{
int hard_error = is_hard_ssl_error(tls_io_instance->ssl, connect_result);
if (hard_error != 0)
{
LogInfo("Hard error from SSL_connect: %d", hard_error);
enter_open_error_state(tls_io_instance);
}
}
}
static void tlsio_openssl_dowork(CONCRETE_IO_HANDLE tls_io)
{
if (tls_io == NULL)
{
/* Codes_SRS_TLSIO_30_070: [ If the tlsio_handle parameter is NULL, tlsio_dowork shall do nothing except log an error. ]*/
LogError("NULL tlsio");
}
else
{
TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
// This switch statement handles all of the state transitions during the opening process
switch (tls_io_instance->tlsio_state)
{
case TLSIO_STATE_CLOSED:
/* Codes_SRS_TLSIO_30_075: [ If the adapter is in TLSIO_STATE_EXT_CLOSED then tlsio_dowork shall do nothing. ]*/
// Waiting to be opened, nothing to do
break;
case TLSIO_STATE_OPENING_WAITING_DNS:
//LogInfo("dowork_poll_dns");
dowork_poll_dns(tls_io_instance);
break;
case TLSIO_STATE_OPENING_WAITING_SOCKET:
//LogInfo("dowork_poll_socket");
dowork_poll_socket(tls_io_instance);
break;
case TLSIO_STATE_OPENING_WAITING_SSL:
//LogInfo("dowork_poll_ssl");
dowork_poll_open_ssl(tls_io_instance);
break;
case TLSIO_STATE_OPEN:
dowork_read(tls_io_instance);
dowork_send(tls_io_instance);
break;
case TLSIO_STATE_ERROR:
/* Codes_SRS_TLSIO_30_071: [ If the adapter is in TLSIO_STATE_EXT_ERROR then tlsio_dowork shall do nothing. ]*/
// There's nothing valid to do here but wait to be retried
break;
default:
LogError("Unexpected internal tlsio state");
break;
}
}
}
static int tlsio_openssl_setoption(CONCRETE_IO_HANDLE tls_io, const char* optionName, const void* value)
{
TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
/* Codes_SRS_TLSIO_30_120: [ If the tlsio_handle parameter is NULL, tlsio_openssl_compact_setoption shall do nothing except log an error and return FAILURE. ]*/
int result;
if (tls_io_instance == NULL)
{
LogError("NULL tlsio");
result = __FAILURE__;
}
else
{
/* Codes_SRS_TLSIO_30_121: [ If the optionName parameter is NULL, tlsio_openssl_compact_setoption shall do nothing except log an error and return FAILURE. ]*/
if (optionName == NULL)
{
LogError("Required optionName parameter is NULL");
result = __FAILURE__;
}
else
{
/* Codes_SRS_TLSIO_30_122: [ If the value parameter is NULL, tlsio_openssl_compact_setoption shall do nothing except log an error and return FAILURE. ]*/
if (value == NULL)
{
LogError("Required value parameter is NULL");
result = __FAILURE__;
}
else
{
/* Codes_SRS_TLSIO_OPENSSL_COMPACT_30_520 [ The tlsio_setoption shall do nothing and return 0. ]*/
result = 0;
}
}
}
return result;
}
/* Codes_SRS_TLSIO_OPENSSL_COMPACT_30_560: [ The tlsio_retrieveoptions shall do nothing and return NULL. ]*/
static OPTIONHANDLER_HANDLE tlsio_openssl_retrieveoptions(CONCRETE_IO_HANDLE tls_io)
{
TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
/* Codes_SRS_TLSIO_30_160: [ If the tlsio_handle parameter is NULL, tlsio_openssl_compact_retrieveoptions shall do nothing except log an error and return FAILURE. ]*/
OPTIONHANDLER_HANDLE result;
if (tls_io_instance == NULL)
{
LogError("NULL tlsio");
result = NULL;
}
else
{
result = NULL;
}
return result;
}
/* Codes_SRS_TLSIO_30_008: [ The tlsio_get_interface_description shall return the VTable IO_INTERFACE_DESCRIPTION. ]*/
static const IO_INTERFACE_DESCRIPTION tlsio_openssl_interface_description =
{
tlsio_openssl_retrieveoptions,
tlsio_openssl_create,
tlsio_openssl_destroy,
tlsio_openssl_open_async,
tlsio_openssl_close_async,
tlsio_openssl_send_async,
tlsio_openssl_dowork,
tlsio_openssl_setoption
};
/* Codes_SRS_TLSIO_30_001: [ The tlsio_openssl_compact shall implement and export all the Concrete functions in the VTable IO_INTERFACE_DESCRIPTION defined in the xio.h. ]*/
const IO_INTERFACE_DESCRIPTION* tlsio_openssl_compact_get_interface_description(void)
{
return &tlsio_openssl_interface_description;
}

Просмотреть файл

@ -0,0 +1,19 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef TLSIO_OPENSSL_COMPACT_H
#define TLSIO_OPENSSL_COMPACT_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include "azure_c_shared_utility/tlsio.h"
MOCKABLE_FUNCTION(, const IO_INTERFACE_DESCRIPTION*, tlsio_openssl_compact_get_interface_description);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* TLSIO_OPENSSL_COMPACT_H */

8
sample/Makefile Normal file
Просмотреть файл

@ -0,0 +1,8 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := esp32
include $(IDF_PATH)/make/project.mk

Просмотреть файл

@ -0,0 +1,17 @@
menu "Example Configuration"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "myssid"
help
WiFi password (WPA or WPA2) for the example to use.
Can be left blank if the network has no security set.
endmenu

97
sample/main/azure_main.c Normal file
Просмотреть файл

@ -0,0 +1,97 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "iothub_client_sample_mqtt.h"
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;
/* The event group allows multiple bits for each event,
but we only care about one event - are we connected
to the AP with an IP? */
const int CONNECTED_BIT = BIT0;
static const char *TAG = "azure";
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently
auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
default:
break;
}
return ESP_OK;
}
static void initialise_wifi(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
void azure_task(void *pvParameter)
{
ESP_LOGI(TAG, "Waiting for WiFi access point ...");
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
false, true, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to access point success");
iothub_client_sample_mqtt_run();
while(1)
{
vTaskDelay(1000);
}
}
void app_main()
{
nvs_flash_init();
initialise_wifi();
xTaskCreate(&azure_task, "azure_task", 8192, NULL, 5, NULL);
}

5
sample/main/component.mk Normal file
Просмотреть файл

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

1
sdk Submodule

@ -0,0 +1 @@
Subproject commit 04aa51bf78ce819b6ebfda448f8c3a57c9c42b99