The purpose of this document is to provide guidance on how to port the C Internet of Things (IoT) client library to platforms not supported out of the box. The document does not cover the specifics of any particular platform.
## BackgroundThe C IoT client library is written in C for the purpose of portability to most platforms. However, several components rely on platform-specific resources in order to achieve the functionality required by the C IoT client library.
The following platform-specific components are required by the IoT client library and must be implemented for all new platforms:
Component | Interface declared in | Description |
---|---|---|
Mutual exclusion locking | Lock.h | This module implements the platform-specific locking mechanisms (mutex, etc.). |
Threading | ThreadAPI.h | This module implements support for creating new threads, terminating threads, and sleeping threads. |
There are also a number of components that must be implemented, depending on the communication protocol used. You must implement at least one of the following communication protocol components:
Component | Interface declared in | Description |
---|---|---|
HTTP protocol interface | HttpAPI.h | This module implements the standard HTTP API used by the C IoT client library. For example, on a Windows platform the HTTP API code uses WinHTTP; for a Linux platform it uses curl, etc. HTTPAPI must support HTTPs (HTTP+SSL). |
-
After downloading the source code from GitHub, navigate to the Platform folder located at ..\common\adapters.
-
In the adapters folder, create the following .c files that implement the platform-specific interfaces:
-
HttpApi_<Library>.c.
-
Lock_<Library>.c
-
ThreadApi_<Library>.c
-
-
In each of these files, implement the functions provided in the header files, relying on the APIs of the libraries provided for that specific platform. You can see the implementation of these components provided for the platforms already supported in the SDK, under .\common\adapters. For more information, also refer to the specification for modules in the .\common\doc folder.
Global initialization for the HTTP API component.
Frees resources allocated in HTTPAPI_Init.
Creates the HTTPS connection to the host specified by the hostName parameter. This function returns a handle to the newly created connection. You can use the handle in subsequent calls to execute specific HTTP calls using HTTPAPI\_ExecuteRequest
.
Closes a connection created with HTTPAPI\_CreateConnection
. All resources allocated by HTTPAPI\_CreateConnection
should be freed in HTTPAPI\_CloseConnection
.
HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath, HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content, size_t contentLength, unsigned int* statusCode, HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER* responseContent);
Sends the HTTP request to the host and handles the response for the HTTP call.
-
requestType specifies which HTTP method is used (GET, POST, DELETE, PUT, PATCH).
-
relativePath specifies the relative path of the URL excluding the host name.
-
httpHeadersHandle specifies a set of HTTP headers name-value pairs to be added to the HTTP request. The httpHeadersHandle handle can be created and set up with the proper name-value pairs by using the HTTPHeaders APIs available in HTTPHeaders.h.
-
The content argument specifies a pointer to the request body. This value is optional and can be NULL.
-
contentLength specifies the request body size (this is typically added into the HTTP headers as the Content-Length header). This value is optional and can be 0.
-
statusCode is an out parameter, where
HTTPAPI\_ExecuteRequest
returns the status code from the HTTP response (200, 201, 400, 401, etc.) -
responseHeadersHandle is an HTTP headers handle to which the
HTTPAPI\_ExecuteRequest
must add all the HTTP response headers so that the caller ofHTTPAPI\_ExecuteRequest
can inspect them. You can manipulate responseHeadersHandle by using the HTTPHeaders APIs available in HTTPHeaders.h. -
responseContent is a buffer that must be filled by
HTTPAPI\_ExecuteRequest
with the contents of the HTTP response body. The buffer size must be increased by theHTTPAPI\_ExecuteRequest
implementation in order to fit the response body.HTTPAPI\_ExecuteRequest
must also handle chunked transfer for the HTTP responses. To manipulate the responseContent buffer, use the APIs available in Strings.h.
HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const char* value, const void** savedValue);
Clones the option named optionName bearing the value value into the pointer savedValue
-
optionName is a NULL terminated string representing the name of the option
-
value is a pointer to the value of the option
-
savedValue receives the copy of the value of the option. The copy needs to be free-able.
Sets the option named optionName bearing the value value for the HTTP_HANDLE handle
-
handle is an existing HTTP_HANDLE
-
optionName is a NULL terminated string representing the name of the option
-
value is a pointer to the value of the option
Initializes a new lock instance and returns a new lock handle that can be used in subsequent calls to Lock/Unlock.
Gets a lock for a specific lock handle.
- handle is the lock handle instance returned from Lock_Init().
Releases a lock for a specific lock handle.
- handle is the lock handle instance returned from Lock_Init().
Frees the resources allocated for a lock handle instance.
- handle is the lock handle instance returned from Lock_Init().
Creates a thread with an entry point specified by the func argument.
-
threadHandle is a handle to the new thread.
-
func is a function pointer that indicates the entry point to the new thread.
-
arg is a void pointer that must be passed to the function pointed to by func.
Waits for the thread identified by the threadHandle argument to complete. When the threadHandle thread completes, all resources associated with the thread must be released and the thread handle will no longer be valid.
-
threadHandle is the handle of the thread to wait for completion.
-
res is the result returned by the thread, provided by the
ThreadAPI\_Exit
function.
This function is called by a thread when the thread exits in order to return a result value to the caller of the ThreadAPI_Join function. The res value must be copied into the res out argument passed to the ThreadAPI\_Join
function.
- res is an integer that represents the exit status of the thread.
Sleeps the current thread for a given number of milliseconds.
- milliseconds is the number of milliseconds to sleep.
Now build the C IoT client library for your platform
## Verify the client library portTo verify that the port to the target platform is successful, ensure that data can be sent to the Event Hub endpoint. You can do this by running the samples in the following locations:
-
iothub_schema_client/Samples/SimpleSample_HTTP
-
iothub_schema_client/Samples/SimpleSample_AMQP
Both samples send temporary data to an Event Hubs endpoint using either the HTTP or AMQP protocols.
It may be necessary to create a build script specifically designed for your platform. To do so, follow these steps:
-
Create a folder under
serializer/samples/SimpleSample_HTTP/<Platform>
. -
Generate a build script using Main.c as the entry point (see existing platform scripts as examples).
-
Build and run the sample.