Skip to content
This repository has been archived by the owner on Oct 12, 2023. It is now read-only.

Commit

Permalink
Merge commit 'c4ab1580490f56484cb47687cadfb18ac58595e1' into HEAD
Browse files Browse the repository at this point in the history
  • Loading branch information
Azure IoT Builder committed Jan 14, 2017
2 parents ee47d31 + c4ab158 commit 50bab4d
Show file tree
Hide file tree
Showing 78 changed files with 610 additions and 195 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -220,4 +220,5 @@ browse.VC.db
api_reference/

# install prefix
install-deps/
install-deps/
Testing/Temporary/CTestCostData.txt
6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
[submodule "deps/azure-c-shared-utility"]
path = deps/c-utility
url = https://github.com/Azure/azure-c-shared-utility
[submodule "deps/azure-iot-sdks"]
path = deps/iot-sdk
url = https://github.com/azure/azure-iot-sdks
[submodule "deps/parson"]
path = deps/parson
url = https://github.com/kgabis/parson
Expand All @@ -25,3 +22,6 @@
[submodule "deps/umqtt"]
path = deps/umqtt
url = https://github.com/azure/azure-umqtt-c
[submodule "deps/iot-sdk-c"]
path = deps/iot-sdk-c
url = https://github.com/Azure/azure-iot-sdk-c.git
60 changes: 52 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
cmake_minimum_required(VERSION 2.8.12)
project(azure_iot_gateway_sdk)

set(GATEWAY_VERSION 1.0.0 CACHE INTERNAL "")
set(GATEWAY_VERSION 1.0.1 CACHE INTERNAL "")
set(COMPANY_NAME "Microsoft")
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

Expand Down Expand Up @@ -37,9 +37,13 @@ else()
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
endif()

# tests and samples should use pre-install path to gateway.so
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} ${CMAKE_CURRENT_BINARY_DIR}/core/)

#the following variables are project-wide and can be used with cmake-gui
option(skip_unittests "set skip_unittests to ON to skip unittests (default is OFF)[if possible, they are always built]" OFF)
option(run_e2e_tests "set run_e2e_tests to ON to run e2e tests (default is OFF) [if possible, they are always built]" OFF)
option(run_unittests "set run_unittests to ON to run unittests (default is OFF)" OFF)
option(run_e2e_tests "set run_e2e_tests to ON to run e2e tests (default is OFF) " OFF)
option(nuget_e2e_tests "" OFF)
option(install_executables "should cmake run cmake's install function (that includes dynamic link libraries) [it does for yocto]" OFF)
option(install_modules "should cmake install the default gateway modules" OFF)
option(enable_java_binding "set enable_java_binding to ON to enable building of Java binding (default is OFF)" OFF)
Expand All @@ -51,6 +55,7 @@ option(use_amqp "set use_amqp to ON if amqp is to be used, set to OFF to not use
option(use_http "set use_http to ON if http is to be used, set to OFF to not use http" ON)
option(use_mqtt "set use_mqtt to ON if mqtt is to be used, set to OFF to not use mqtt" ON)


SET(use_condition ON CACHE BOOL "Build C shared utility with condition code" FORCE)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

Expand Down Expand Up @@ -120,11 +125,9 @@ endfunction()

function(add_sample_to_solution sampleName)
set_target_properties(${sampleName} PROPERTIES FOLDER "Samples")
#if(DEFINED ${dependency_install_prefix})
set_target_properties(${sampleName} PROPERTIES
BUILD_WITH_INSTALL_RPATH TRUE
)
#endif()
set_target_properties(${sampleName} PROPERTIES
BUILD_WITH_INSTALL_RPATH TRUE
)
endfunction()


Expand Down Expand Up @@ -184,6 +187,46 @@ function(install_broker whatIsBuilding whatIsBuildingLocation)
endif()
endfunction(install_broker)

set(preinstall_gateway_library_dll ${CMAKE_CURRENT_BINARY_DIR}/core/$(Configuration)/gateway.dll)

function(copy_gateway_dll whatIsBuilding whatIsBuildingLocation)
if(WIN32)
add_custom_command(TARGET ${whatIsBuilding} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${preinstall_gateway_library_dll}
${whatIsBuildingLocation})
if(EXISTS "${azure_c_shared_utility_DIR}/../bin/${SHARED_UTIL_LIB}.dll")
add_custom_command(TARGET ${whatIsBuilding} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${azure_c_shared_utility_DIR}/../bin/${SHARED_UTIL_LIB}.dll"
${whatIsBuildingLocation})
endif()


endif()
endfunction(copy_gateway_dll)

function(copy_iothub_client_dll whatIsBuilding whatIsBuildingLocation)
if(WIN32)
if(EXISTS "${azure_iot_sdks_DIR}/../bin/iothub_client.dll")
add_custom_command(TARGET ${whatIsBuilding} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${azure_iot_sdks_DIR}/../bin/iothub_client.dll"
${whatIsBuildingLocation})
endif()
endif()
endfunction(copy_iothub_client_dll)

function(copy_iothub_service_dll whatIsBuilding whatIsBuildingLocation)
if(WIN32)
if(EXISTS "${azure_iot_sdks_DIR}/../bin/iothub_service_client.dll")
add_custom_command(TARGET ${whatIsBuilding} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${azure_iot_sdks_DIR}/../bin/iothub_service_client.dll"
${whatIsBuildingLocation})
endif()
endif()
endfunction(copy_iothub_service_dll)

if(${ARCHITECTURE} STREQUAL "x86_64")
set(dotnet_managed_binding_dll ${CMAKE_CURRENT_BINARY_DIR}/../bindings/dotnet/dotnet-binding/Microsoft.Azure.IoT.Gateway/bin/x64/$(Configuration)/Microsoft.Azure.IoT.Gateway.dll CACHE INTERNAL "The location of the Microsoft.Azure.IoT.Gateway.dll (windows)" FORCE)
Expand All @@ -193,6 +236,7 @@ if(${ARCHITECTURE} STREQUAL "x86_64")
set(dotnet_sensor_module_dll ${CMAKE_CURRENT_BINARY_DIR}/../bindings/dotnet/dotnet-binding/SensorModule/bin/x64/$(Configuration)/SensorModule.dll CACHE INTERNAL "The location of the SensorModule.dll (windows)" FORCE)

set(dotnet_printer_module_dll ${CMAKE_CURRENT_BINARY_DIR}/../bindings/dotnet/dotnet-binding/PrinterModule/bin/x64/$(Configuration)/PrinterModule.dll CACHE INTERNAL "The location of the PrinterModule.dll (windows)" FORCE)

elseif(${ARCHITECTURE} STREQUAL "x86")
set(dotnet_managed_binding_dll ${CMAKE_CURRENT_BINARY_DIR}/../bindings/dotnet/dotnet-binding/Microsoft.Azure.IoT.Gateway/bin/x86/$(Configuration)/Microsoft.Azure.IoT.Gateway.dll CACHE INTERNAL "The location of the Microsoft.Azure.IoT.Gateway.dll (windows)" FORCE)

Expand Down
2 changes: 1 addition & 1 deletion bindings/dotnet/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ target_link_libraries(dotnet_static gateway mscoree)
linkSharedUtil(dotnet)
linkSharedUtil(dotnet_static)

if(NOT ${skip_unittests})
if(${run_unittests})
add_subdirectory(tests)
endif()

Expand Down
7 changes: 4 additions & 3 deletions bindings/dotnet/devdoc/dotnet_binding_hld.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ The JSON configuration for .NET Module will be similar to the configuration for
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. `loader->name` is the name of the module created (.NET Module) that will be stored by the gateway and used internally;
1. `name` is the name of the module created (.NET Module) that will be stored by the gateway and used internally;

2. `loader` is the configuration specifically for the .NET Loader.

2.1 `loader->assembly_name`: place where the .NET module is located;
2.2 `loader->entry_type`: class that implements `IGatewayModule`;
2.1 `loader->assembly.name`: Name of the managed assembly that contains the module implementation;

2.2 `loader->entry.type`: Fully qualified name of the managed class that implements `IGatewayModule`;

3. `args` The value of this property is used to supply configuration information specific to a given .NET module. The value is passed as a byte[] to .NET module and it shall be converted as a UTF-8 String;

Expand Down
Binary file modified bindings/dotnet/devdoc/images/flow_chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified bindings/dotnet/devdoc/images/overall-design.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified bindings/dotnet/devdoc/resources/dotnetbiding-hld.vsdx
Binary file not shown.
1 change: 1 addition & 0 deletions bindings/dotnet/tests/dotnet_e2e/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ if(TARGET ${theseTestsName}_exe)
add_dependencies(${theseTestsName}_exe dotnet)

install_broker(${theseTestsName}_exe ${CMAKE_CURRENT_BINARY_DIR}/$(Configuration) )
copy_gateway_dll(${theseTestsName}_exe ${CMAKE_CURRENT_BINARY_DIR}/$(Configuration) )
install_binaries(${theseTestsName}_exe ${CMAKE_CURRENT_BINARY_DIR}/$(Configuration) ${dotnet_managed_binding_dll} )
install_binaries(${theseTestsName}_exe ${CMAKE_CURRENT_BINARY_DIR}/$(Configuration) ${dotnet_e2etest_module_dll} )
install_binaries(${theseTestsName}_exe ${CMAKE_CURRENT_BINARY_DIR}/$(Configuration) ${dotnet_host_binding_dll} )
Expand Down
218 changes: 218 additions & 0 deletions bindings/dotnetcore/devdoc/dotnet_core_binding_hld.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
Building Azure IoT Gateway Modules in .NET Core
===============================================

Overview
--------

This document describes the high level design of the .NET Core binding mechanism used by Azure IoT Gateway SDK.
It describes how the .NET Core CLR is hosted in the gateway process's memory and how the interaction between the
native and .NET Core Managed Modules will work.

The existing binding implementation in the Gateway SDK for .NET targets the full .NET framework (desktop and server) on Windows only.
The binding discussed in this document relates to the cross platform open source .NET Core product that works on Windows, Linux and macOS.

Hosting .NET CLR
----------------

In order to be able to host the CLR, we are going to use the following exports from .NET Core CLR:
-coreclr_initialize;
-coreclr_create_delegate;
-coreclr_shutdown;

Some documentation on how to host the .NET CLR can be found on:
- [.NET Core GitHub](https://github.com/dotnet/) - Check sample `corerun` and `coreconsole` for both windows and linux.

Design
------
![](images/overall-design.png)

.NET Core Module Host
---------------------
The **.NET Core Module Host** is a C module that

1. Creates a [.NET Core](https://github.com/dotnet/) CLR instance;

2. Creates delegates for .NET Module Calls (Create, destroy, receive, start);

3. Brokers calls **from** the managed module to the message broker (dotnetHost_PublishMessage, which invokes `MessageCreate_FromByteArray` and `Broker_Publish`);

###JSON Configuration

The JSON configuration for [.NET Core](https://github.com/dotnet/) Module will be similar to the configuration for Node and Java Module Host:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
{
"modules": [
{
"name": "csharp_hello_world",
"loader": {
"name": "dotnetcore",
"entrypoint": {
"assembly.name": "mymoduleassembly",
"entry.type": "mycsharpmodule.classname"
}
},
"args": "module configuration"
}
]
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. `name` is the name of the module created ([.NET Core](https://github.com/dotnet/) Module) that will be stored by the gateway and used internally;

2. `loader` is the configuration specifically for the [.NET Core](https://github.com/dotnet/) Loader.

2.1 `loader->assembly.name`: Name of the managed assembly that contains the module implementation;

2.2 `loader->entry.type`: Fully qualified name of the managed class that implements `IGatewayModule`;

3. `args` The value of this property is used to supply configuration information specific to a given [.NET Core](https://github.com/dotnet/) module. The value is passed as a byte[] to .NET module and it shall be converted as a UTF-8 String;

##Native methods description
### Module\_Create

When the **.NET Core Module Host**’s `Module_Create` function is invoked by the
gateway process, it:

- Creates a CLR instance by calling `coreclr_initialize;

- Creates [.NET Core](https://github.com/dotnet/) Delegates for Create, Receive, Start and Destroy;

- Calls Create Delegate, which will call the Create method on the user [.NET Core](https://github.com/dotnet/) Module (Module that implemented `IGatewayModule`);

### Module\_Start

When the **.NET Core Module Host**’s `Module_Start` function is invoked by the
gateway, it:

- Call the `Start` Delegate;
- Managed implementation of Start delegate checks if [.NET Core](https://github.com/dotnet/) module has implemented the `Start` method;
- If defined, invokes the `Start` method implemented by the [.NET Core](https://github.com/dotnet/) module.

### Module\_Receive

When the **.NET Core Module Host**’s `Module_Receive` function is invoked by the
gateway process, it:

- Serializes (by calling `Message_ToByteArray`) the message content and properties and invokes the `Receive` method implemented by the .NET module (`IGatewayInterface` below). The .NET module will deserialize this byte array into a Message object.
- Calls the `Receive` delegate;

### Module\_Destroy

When the **.NET Module Host**’s `Module_Destroy` function is invoked by the
gateway, it:

- Calls the `Destroy` delegate (which is going to call `Destroy` method implemented by the [.NET Core](https://github.com/dotnet/) Module);
- Releases resources allocated;
- Calls the `coreclr_shutdown` method;

.NET Wrappers and objects
-------------------------

This is going to be a layer written in .NET that will wrap a method in our host that is responsible to publish a given message.
For [.NET Core](https://github.com/dotnet/) Modules the following wrappers will be provided:

1. `Message` - Object that represents a message;

2. `Broker` - Object that represents the broker, which passes messages between modules;

3. `IGatewayModule` - interface that has to be implemented by the [.NET Core](https://github.com/dotnet/) Module;

4. `nativeDotNetHostWrapper` - Uses DLLImport to marshal call to dotnetHost_PublishMessage. This will be transparent to the .NET User, it will be called by the Broker Class when the user calls Publish.

The high level design of these objects and interfaces is documented below:

### Message
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C#

namespace Microsoft.Azure.IoT.Gateway
{
/// <summary> Object that represents a message passed between modules. </summary>
public class Message
{
public byte[] Content { set; get; };

public Dictionary<string,string> Properties { set; get; };

public Message();

public Message(byte[] msgInByteArray);

public Message(string content, Dictionary<string, string> properties);

public Message(Message message);

public byte[] ToByteArray();
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


### Broker
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C#

namespace Microsoft.Azure.IoT.Gateway
{
/// <summary> Object that represents the message broker, to which messsages will be published. </summary>
public class Broker
{
/// <summary>
/// Publish a message to the message broker.
/// </summary>
/// <param name="message">Object representing the message to be published to the broker.</param>
/// <returns></returns>
public void Publish(Message message);
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

### IGatewayModule
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C#

/// <summary> Interface to be implemented by the .NET Module </summary>
public interface IGatewayModule
{
/// <summary>
/// Creates a module using the specified configuration connecting to the specified message broker.
/// </summary>
/// <param name="broker">The broker to which this module will connect.</param>
/// <param name="configuration">A byte[] with user-defined configuration for this module. This parameter shall be enconded to a UTF-8 String.</param>
/// <returns></returns>
void Create(Broker broker, byte[] configuration);

/// <summary>
/// Disposes of the resources allocated by/for this module.
/// </summary>
/// <returns></returns>
void Destroy();

/// <summary>
/// The module's callback function that is called upon message receipt.
/// </summary>
/// <param name="received_message">The message being sent to the module.</param>
/// <returns></returns>
void Receive(Message received_message);
}

/// <summary> Optional Start Interface to be implemented by the .NET Module </summary>
public interface IGatewayModuleStart
{

/// <summary>
/// Informs module the gateway is ready to send and receive messages.
/// </summary>
/// <returns></returns>
void Start();

}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Flow Diagram
------------

Following is the flow diagram of a lifecycle of the [.NET Core](https://github.com/dotnet/) module:
![](images/flow_chart.png)



Binary file added bindings/dotnetcore/devdoc/images/flow_chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
2 changes: 1 addition & 1 deletion bindings/java/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ linkSharedUtil(java_module_host_static)
add_binding_to_solution(java_module_host)
add_binding_to_solution(java_module_host_static)

if(NOT ${skip_unittests})
if(${run_unittests})
add_subdirectory(tests)
endif()

Expand Down
2 changes: 1 addition & 1 deletion bindings/nodejs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ target_include_directories(nodejs_binding_static PUBLIC $ENV{NODE_INCLUDE})
add_binding_to_solution(nodejs_binding)
add_binding_to_solution(nodejs_binding_static)

if(NOT ${skip_unittests})
if(${run_unittests})
add_subdirectory(tests)
endif()

Expand Down
Loading

0 comments on commit 50bab4d

Please sign in to comment.