Last active
January 23, 2019 09:33
-
-
Save truschival/b9667a37f818d2b52ece15d3f7dbf887 to your computer and use it in GitHub Desktop.
simple connection test program to reproduce issue 717 of azure-iot-sdk-c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Created on: Nov 26, 2018 | |
* Author: Roman Schneider | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <signal.h> | |
#include <getopt.h> | |
#include "azureiot/iothub.h" | |
#include "azureiot/iothub_client.h" | |
#include "azureiot/iothub_client_options.h" | |
#include "azureiot/iothub_client_version.h" | |
#include "azureiot/iothubtransportamqp_websockets.h" | |
#include "azureiot/iothubtransportmqtt.h" | |
#include "azureiot/iothubtransportmqtt_websockets.h" | |
#include "azureiot/iothubtransportamqp.h" | |
#include <azure_c_shared_utility/platform.h> | |
#include "azure_c_shared_utility/shared_util_options.h" | |
#include "azure_c_shared_utility/http_proxy_io.h" | |
#include "azure_c_shared_utility/threadapi.h" | |
#include "azure_prov_client/prov_device_client.h" | |
#include "azure_prov_client/prov_security_factory.h" | |
#include "azure_prov_client/prov_transport_amqp_ws_client.h" | |
#include "azure_prov_client/prov_transport_http_client.h" | |
#define UNUSED(expr) do { (void)(expr); } while (0) | |
DEFINE_ENUM_STRINGS(PROV_DEVICE_RESULT, PROV_DEVICE_RESULT_VALUE); | |
DEFINE_ENUM_STRINGS(PROV_DEVICE_REG_STATUS, PROV_DEVICE_REG_STATUS_VALUES); | |
static bool g_registration_complete = false; | |
static bool g_connection_complete = false; | |
static bool g_use_proxy = false; | |
static const char* PROXY_ADDRESS = "10.0.2.2"; | |
#define PROXY_PORT 3128 | |
#define MESSAGES_TO_SEND 2 | |
#define TIME_BETWEEN_MESSAGES 2 | |
static char* g_iothub_uri; | |
static char* g_device_id; | |
static size_t g_messageTrackingId; | |
static bool g_sending; | |
static bool g_dps_reconnect = false; | |
static size_t g_reconnect_cnt = 0; | |
/* callback requests reconnect */ | |
static bool g_please_reconnect; | |
// global Iothub & DPS variables | |
HTTP_PROXY_OPTIONS g_http_proxy; | |
char* g_prov_uri = "global.azure-devices-provisioning.net"; | |
char* g_id_scope = "0ne0001205C"; | |
bool g_traceOn = false; | |
static IOTHUB_CLIENT_HANDLE iothubclient; | |
static IOTHUB_CLIENT_TRANSPORT_PROVIDER g_iothub_protocol = AMQP_Protocol_over_WebSocketsTls; | |
static int connect_DPS(); | |
static int connect_IoTHub(); | |
static void set_iothub_protocol(const char* protocol); | |
/******************************************************************************/ | |
static void msg_confirmation_callback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, | |
void* data) | |
{ | |
size_t id = (size_t) data; | |
UNUSED(data); | |
printf("%s: result: %s for id %zd\n", __func__, | |
ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result), id); | |
} | |
int method_invocation_callback(const char* method_name, | |
const unsigned char* payload, size_t size, unsigned char** response, | |
size_t* response_size, void* user_context) { | |
UNUSED(user_context); | |
printf("%s: %s payload_len = %zd\n", __func__, method_name, size); | |
*response = (unsigned char*) malloc(size); | |
*response_size = size; | |
memcpy(*response, payload, size); | |
return 0; | |
} | |
IOTHUBMESSAGE_DISPOSITION_RESULT msg_receive_callback( | |
IOTHUB_MESSAGE_HANDLE message, void* user_context) | |
{ | |
UNUSED(user_context); | |
IOTHUB_MESSAGE_RESULT msg_ret = IOTHUB_MESSAGE_OK; | |
const char* buf; | |
size_t buf_size = 0; | |
int cb_result = IOTHUB_CLIENT_IOTHUB_METHOD_STATUS_ERROR; | |
IOTHUBMESSAGE_CONTENT_TYPE payload_type = | |
IoTHubMessage_GetContentType(message); | |
switch (payload_type) { | |
case IOTHUBMESSAGE_BYTEARRAY: | |
msg_ret = IoTHubMessage_GetByteArray( | |
message, (const unsigned char**)&buf, &buf_size); | |
if (msg_ret != IOTHUB_MESSAGE_OK) { | |
printf("%s: binary message parsing failed!\n", __func__); | |
} | |
break; | |
case IOTHUBMESSAGE_STRING: | |
buf = IoTHubMessage_GetString(message); | |
if (buf != NULL) { | |
buf_size = strlen(buf); | |
} else { | |
printf("%s: string message parsing failed!\n", __func__); | |
} | |
break; | |
case IOTHUBMESSAGE_UNKNOWN: | |
default: | |
printf("%s: Unknown Message content type!\n", __func__); | |
} | |
if (buf != NULL) { | |
printf("%s: received: %s\n", __func__, buf); | |
cb_result = IOTHUB_CLIENT_IOTHUB_METHOD_STATUS_SUCCESS; | |
} | |
return cb_result; | |
} | |
static void connection_callback(IOTHUB_CLIENT_CONNECTION_STATUS result, | |
IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void* user_context) | |
{ | |
UNUSED(user_context); | |
printf("%s: %s, reason: %s\n", __func__, | |
ENUM_TO_STRING(IOTHUB_CLIENT_CONNECTION_STATUS, result), | |
ENUM_TO_STRING(IOTHUB_CLIENT_CONNECTION_STATUS_REASON, reason)); | |
if (result == IOTHUB_CLIENT_CONNECTION_AUTHENTICATED) { | |
g_connection_complete = true; | |
g_reconnect_cnt++; | |
} else { | |
/** | |
* Disconnect looks like this: | |
* IOTHUB_CLIENT_CONNECTION_UNAUTHENTICATED, | |
* reason: IOTHUB_CLIENT_CONNECTION_COMMUNICATION_ERROR | |
*/ | |
// Do not trigger reconnect while callback is called during normal | |
// connect | |
if (g_dps_reconnect && !g_please_reconnect) { | |
printf("\n Signaling reconnect request \n"); | |
g_please_reconnect = true; | |
} | |
g_connection_complete = false; | |
} | |
} | |
static void registation_status_callback(PROV_DEVICE_REG_STATUS reg_status, void* user_context) | |
{ | |
UNUSED(user_context); | |
printf("%s: Provisioning Status: %s\n", __func__, | |
ENUM_TO_STRING(PROV_DEVICE_REG_STATUS, reg_status)); | |
} | |
static void register_device_callback(PROV_DEVICE_RESULT register_result, | |
const char* iothub_uri, const char* device_id, void* user_context) | |
{ | |
UNUSED(user_context); | |
if (register_result == PROV_DEVICE_RESULT_OK) { | |
printf("%s: Registration Information received from service: %s, deviceId: %s\n", | |
__func__, iothub_uri, device_id); | |
g_iothub_uri = strdup(iothub_uri); | |
g_device_id = strdup(device_id); | |
g_registration_complete = true; | |
} else { | |
(void) printf("%s: Failure registering device: %s\n", __func__, | |
ENUM_TO_STRING(PROV_DEVICE_RESULT, register_result)); | |
} | |
} | |
static void sendMessage(IOTHUB_CLIENT_HANDLE iotHubClientHandle) | |
{ | |
char payload[32]; | |
snprintf(payload, sizeof(payload), "%zd", g_messageTrackingId); | |
IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray( | |
(unsigned char*) payload, strlen(payload)); | |
if (messageHandle == NULL) { | |
printf("%s: unable to create a new IoTHubMessage\n", __func__); | |
} else { | |
if (IoTHubClient_SendEventAsync(iotHubClientHandle, messageHandle, | |
msg_confirmation_callback, (void*) g_messageTrackingId) | |
== IOTHUB_CLIENT_OK) { | |
printf("%s: with id %zd (recconnect_cnt = %zd) \n", __func__, | |
g_messageTrackingId, g_reconnect_cnt); | |
} | |
IoTHubMessage_Destroy(messageHandle); | |
} | |
g_messageTrackingId++; | |
} | |
static void sig_handler(int signo) { | |
if (signo == SIGINT) { | |
printf("\nreceived SIGINT - terminating\n"); | |
g_sending = false; | |
} else if (signo == SIGTERM) { | |
printf("\nreceived SIGTERM - terminating\n"); | |
g_sending = false; | |
} else { | |
printf("\nreceived unknown signal - ignoring\n"); | |
return; | |
} | |
} | |
static void print_help(void) | |
{ | |
char *txt = "" | |
"Usage: simplect[OPTIONS]\n" | |
"simple azure iot test framework\n\n" | |
"Options:\n" | |
"-d, --dps-reconnect perform full reconnect via DPS if SAS token expired \n" | |
"-P, --use-proxy use http proxy \n" | |
"-x, --protocol iothub protocol [AMQP_WEBSOCKETS | MQTT_WEBSOCKETS]\n" | |
"-t, --traceon activate Azure IoT SDK traces\n" | |
"-p, --period period in seconds (example: -p 60)\n" | |
"-s, --scope DPS scope (example: -s 0ne0001205C)\n" | |
"-h, --help this\n\n"; | |
printf("%s", txt); | |
} | |
static void connect() { | |
printf(">%s\n", __func__); | |
g_connection_complete = false; | |
if (connect_DPS() != EXIT_SUCCESS) { | |
printf("connect_DPS() failed, aborting\n"); | |
exit(-1); | |
} | |
if (connect_IoTHub() != EXIT_SUCCESS) { | |
printf("connect_IoTHub() failed, aborting\n"); | |
exit(-1); | |
} | |
printf("<%s\n", __func__); | |
} | |
int main(int argc, char* argv[]) { | |
int c; | |
size_t period_sec = 2; | |
while (1) { | |
static struct option long_options[] = { | |
{"dps-reconnect", no_argument, 0, 'd'}, | |
{"help", no_argument, 0, 'h'}, | |
{"period", required_argument, 0, 'p'}, | |
{"protocol", required_argument, 0, 'x'}, | |
{"scope", required_argument, 0, 's'}, | |
{"traceon", no_argument, 0, 't'}, | |
{"use-proxy", no_argument, 0, 'P'}, {0, 0, 0, 0} | |
}; | |
/* getopt_long stores the option index here. */ | |
int option_index = 0; | |
c = getopt_long(argc, argv, "x:ts:p:Ph", long_options, &option_index); | |
/* Detect the end of the options. */ | |
if (c == -1) | |
break; | |
switch (c) { | |
case 0: | |
/* If this option set a flag, do nothing else now. */ | |
if (long_options[option_index].flag != 0) | |
break; | |
printf("option %s", long_options[option_index].name); | |
if (optarg) | |
printf(" with arg %s", optarg); | |
printf("\n"); | |
break; | |
case 'd': /* dps-reconnect */ | |
g_dps_reconnect = true; | |
break; | |
case 'P': /* proxy */ | |
g_use_proxy = true; | |
break; | |
case 'x': /* protocol MQTT/AMQP */ | |
set_iothub_protocol(optarg); | |
break; | |
case 's': | |
g_id_scope = optarg; | |
break; | |
case 'p': | |
period_sec = atoi(optarg); | |
break; | |
case 't': | |
g_traceOn = true; | |
break; | |
case 'h': | |
print_help(); | |
return EXIT_SUCCESS; | |
case '?': | |
/* getopt_long already printed an error message. */ | |
break; | |
default: | |
abort(); | |
} | |
} | |
signal(SIGINT, sig_handler); | |
signal(SIGTERM, sig_handler); | |
if (platform_init() != 0) { | |
printf("Platform_init failed!\n"); | |
return EXIT_FAILURE; | |
} | |
SECURE_DEVICE_TYPE hsm_type = SECURE_DEVICE_TYPE_TPM; | |
(void) prov_dev_security_init(hsm_type); | |
memset(&g_http_proxy, 0, sizeof(HTTP_PROXY_OPTIONS)); | |
printf(" Provisioning API Version: %s\n", Prov_Device_GetVersionString()); | |
printf(" IOT HUB Client Version: %s\n", IoTHubClient_GetVersionString()); | |
printf(" Provisioning URI: %s\n", g_prov_uri); | |
printf(" Provisioning Scope: %s\n", g_id_scope); | |
printf("Message interval (period): %zd\n", period_sec); | |
if (g_use_proxy) { | |
g_http_proxy.host_address = PROXY_ADDRESS; | |
g_http_proxy.port = PROXY_PORT; | |
} | |
connect(); | |
g_sending = true; | |
do { | |
if (g_dps_reconnect && g_please_reconnect) { | |
printf("\n Reconnect requested - destroying IotHubClient \n"); | |
IoTHubClient_Destroy(iothubclient); | |
ThreadAPI_Sleep(5000); | |
printf("\n IotHubClient destroyed, trying reconnect\n"); | |
connect(); | |
} else if (g_connection_complete) { | |
sendMessage(iothubclient); | |
} | |
ThreadAPI_Sleep(1000 * period_sec); | |
} while (g_sending); | |
IoTHubClient_Destroy(iothubclient); | |
free(g_iothub_uri); | |
free(g_device_id); | |
prov_dev_security_deinit(); | |
// Free all the sdk subsystem | |
platform_deinit(); | |
return EXIT_SUCCESS; | |
} | |
/******************************************************************************/ | |
static void set_iothub_protocol(const char* protoname) { | |
if (strcmp(protoname, "AMPQ_WEBSOCKETS") == 0) { | |
g_iothub_protocol = AMQP_Protocol_over_WebSocketsTls; | |
return; | |
} | |
if (strcmp(protoname, "MQTT_WEBSOCKETS") == 0) { | |
g_iothub_protocol = MQTT_WebSocket_Protocol; | |
return; | |
} | |
} | |
/******************************************************************************/ | |
static int connect_DPS() { | |
PROV_DEVICE_TRANSPORT_PROVIDER_FUNCTION prov_transport; | |
prov_transport = Prov_Device_HTTP_Protocol; | |
PROV_DEVICE_RESULT prov_device_result; | |
PROV_DEVICE_HANDLE prov_device_handle; | |
g_please_reconnect = false; | |
g_registration_complete = false; | |
printf(">%s\n",__func__); | |
if ((prov_device_handle = Prov_Device_Create( | |
g_prov_uri, g_id_scope, prov_transport)) == NULL) { | |
printf("failed calling Prov_Device_Create\n"); | |
return EXIT_FAILURE; | |
} | |
if (g_http_proxy.host_address != NULL) { | |
Prov_Device_SetOption( | |
prov_device_handle, OPTION_HTTP_PROXY, &g_http_proxy); | |
} | |
Prov_Device_SetOption( | |
prov_device_handle, PROV_OPTION_LOG_TRACE, &g_traceOn); | |
prov_device_result = Prov_Device_Register_Device(prov_device_handle, | |
register_device_callback, NULL, registation_status_callback, NULL); | |
if (prov_device_result != PROV_DEVICE_RESULT_OK) { | |
printf("FATAL: Prov_Device_Register_Device failed\n"); | |
return EXIT_FAILURE; | |
} | |
printf("Registering Device ...\n"); | |
do { | |
ThreadAPI_Sleep(1000); | |
} while (!g_registration_complete); | |
printf(" DPS registration complete\n"); | |
Prov_Device_Destroy(prov_device_handle); | |
printf("<%s\n",__func__); | |
return EXIT_SUCCESS; | |
} | |
/******************************************************************************/ | |
static int connect_IoTHub() { | |
printf(">%s\n",__func__); | |
g_connection_complete = false; | |
iothubclient = IoTHubClient_CreateFromDeviceAuth( | |
g_iothub_uri, g_device_id, g_iothub_protocol); | |
if (iothubclient == NULL) { | |
printf("FATAL: can't IoTHubClient_CreateFromDeviceAuth.\n"); | |
return EXIT_FAILURE; | |
} | |
if (IoTHubClient_SetOption(iothubclient, OPTION_LOG_TRACE, &g_traceOn) != | |
IOTHUB_CLIENT_OK) { | |
printf("IoTHubClient_SetOption OPTION_LOG_TRACE failed.\n"); | |
} | |
if (IoTHubClient_SetRetryPolicy(iothubclient, IOTHUB_CLIENT_RETRY_INTERVAL, | |
120) != IOTHUB_CLIENT_OK) { | |
printf("IoTHubClient_SetRetryPolicy failed.\n"); | |
} | |
if (IoTHubClient_SetConnectionStatusCallback( | |
iothubclient, connection_callback, 0) != IOTHUB_CLIENT_OK) { | |
printf("IoTHubClient_SetConnectionStatusCallback failed.\n"); | |
} | |
if (IoTHubClient_SetMessageCallback( | |
iothubclient, msg_receive_callback, 0) != IOTHUB_CLIENT_OK) { | |
printf("IoTHubClient_SetMessageCallback failed.\n"); | |
} | |
if (IoTHubClient_SetDeviceMethodCallback( | |
iothubclient, method_invocation_callback, 0) != IOTHUB_CLIENT_OK) { | |
printf("IoTHubClient_SetDeviceMethodCallback failed.\n"); | |
} | |
printf("Waiting for Authentication ... \n"); | |
do { | |
ThreadAPI_Sleep(1000); | |
} while (!g_connection_complete); | |
printf(" IoT Hub connection complete\n"); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment