Skip to content

Instantly share code, notes, and snippets.

@dotMorten
Last active December 8, 2016 20:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dotMorten/e13551aafa8cc2f4c5bd939efa5f4fb3 to your computer and use it in GitHub Desktop.
Save dotMorten/e13551aafa8cc2f4c5bd939efa5f4fb3 to your computer and use it in GitHub Desktop.
Simple Iotivity Server and Light Resource created using .NET calling into the Iotivity C-API
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace SimpleServerNet
{
class Program
{
private static CancellationTokenSource ct;
private static TaskCompletionSource<object> tcs;
static void Main(string[] args)
{
Console.WriteLine("Initializing...");
var initResult = OCInit1(OCMode.OC_SERVER, OCTransportFlags.OC_DEFAULT_FLAGS, OCTransportFlags.OC_DEFAULT_FLAGS);
if (initResult != OCStackResult.OC_STACK_OK)
{
throw new Exception(initResult.ToString());
}
//Start OCProcess Loop
ct = new CancellationTokenSource();
tcs = new TaskCompletionSource<object>();
ThreadPool.QueueUserWorkItem(async (s) =>
{
Console.WriteLine("Running OCStack. Press any key to close");
while (!ct.IsCancellationRequested)
{
var reprocessResult = OCProcess();
await Task.Delay(1);
}
tcs.SetResult(null);
tcs = null;
ct = null;
});
// Create an iotivity resource
IntPtr lightHandle = IntPtr.Zero;
OCStackResult res1 = OCCreateResource(out lightHandle, "core.light", "oic.if.baseline", "/light/1", handler.OCEntityHandler, IntPtr.Zero, OCResourceProperty.OC_DISCOVERABLE | OCResourceProperty.OC_OBSERVABLE);
// Run until keypress
var k = Console.ReadKey();
Console.WriteLine("Cancelling...");
ct.Cancel();
tcs.Task.Wait();
var stopResult = OCStop();
}
private static CallbackHandler handler = new CallbackHandler();
public class CallbackHandler
{
public OCEntityHandlerResult OCEntityHandler(OCEntityHandlerFlag flag, OCEntityHandlerRequest entityHandlerRequest, IntPtr callbackParam)
{
Console.Write("OCEntityHandler callback called. Flag: " + flag.ToString());
return OCEntityHandlerResult.OC_EH_OK;
}
}
#region Interop Imports
internal static class Constants
{
internal const string DLL_IMPORT_TARGET = "octbstack.dll";
}
[DllImport(Constants.DLL_IMPORT_TARGET)]
internal static extern OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlags clientFlags);
[DllImport(Constants.DLL_IMPORT_TARGET)]
internal static extern OCStackResult OCStop();
[DllImport(Constants.DLL_IMPORT_TARGET)]
internal static extern OCStackResult OCProcess();
[DllImport(Constants.DLL_IMPORT_TARGET)]
internal static extern OCStackResult OCCreateResource([Out] out IntPtr handle,
[MarshalAs(UnmanagedType.LPStr)] string resourceTypeName,
[MarshalAs(UnmanagedType.LPStr)] string resourceInterfaceName,
[MarshalAs(UnmanagedType.LPStr)] string uri,
OCEntityHandler entityHandler,
IntPtr callbackParam,
OCResourceProperty resourceProperties);
#endregion
#region OC Type Definitions
/**
* Incoming requests handled by the server. Requests are passed in as a parameter to the
* OCEntityHandler callback API.
* The OCEntityHandler callback API must be implemented in the application in order
* to receive these requests.
*/
[StructLayout(LayoutKind.Sequential)]
internal class OCEntityHandlerRequest
{
/** Associated resource.*/
public IntPtr resource;
/** Associated request handle.*/
public IntPtr requestHandle;
/** the REST method retrieved from received request PDU.*/
public OCMethod method;
/** description of endpoint that sent the request.*/
public OCDevAddr devAddr;
/** resource query send by client.*/
[MarshalAs(UnmanagedType.LPStr)]
public string query;
/** Information associated with observation - valid only when OCEntityHandler flag includes
* ::OC_OBSERVE_FLAG.*/
public OCObservationInfo obsInfo;
/** Number of the received vendor specific header options.*/
public byte numRcvdVendorSpecificHeaderOptions;
/** Pointer to the array of the received vendor specific header options.*/
public OCHeaderOption rcvdVendorSpecificHeaderOptions;
/** Message id.*/
UInt16 messageID;
/** the payload from the request PDU.*/
public OCPayload payload;
}
/**
* Data structure to encapsulate IPv4/IPv6/Contiki/lwIP device addresses.
* OCDevAddr must be the same as CAEndpoint (in CACommon.h).
*/
[StructLayout(LayoutKind.Sequential)]
internal class OCDevAddr
{
public OCDevAddr(UInt16 port)
{
addr = new char[66];
routeData = new char[66];
deviceId = new char[37]; // 37 incl null terminating char
adapter = OCTransportAdapter.OC_ADAPTER_IP;
flags = OCTransportFlags.OC_IP_USE_V4;
this.port = port;
ifindex = 0;
}
/** adapter type.*/
public OCTransportAdapter adapter;
/** transport modifiers.*/
public OCTransportFlags flags;
/** for IP.*/
public UInt16 port;
/** address for all adapters.*/
public char[] addr;
/** usually zero for default interface.*/
public UInt32 ifindex;
/** destination GatewayID:ClientId.*/
public char[] routeData;
/** destination DeviceID.*/
public char[] deviceId;
}
/**
* This structure will be used to define the vendor specific header options to be included
* in communication packets.
*/
[StructLayout(LayoutKind.Sequential)]
internal class OCHeaderOption
{
public OCHeaderOption()
{
optionData = new byte[1024];
}
/** The protocol ID this option applies to.*/
public OCTransportProtocolID protocolID;
/** The header option ID which will be added to communication packets.*/
public UInt16 optionID;
/** its length 191.*/
public UInt16 optionLength;
/** pointer to its data.*/
public byte[] optionData;
#if SUPPORTS_DEFAULT_CTOR
OCHeaderOption() = default;
OCHeaderOption(OCTransportProtocolID pid,
uint16_t optId,
uint16_t optlen,
const uint8_t* optData)
: protocolID(pid),
optionID(optId),
optionLength(optlen)
{
// parameter includes the null terminator.
optionLength = optionLength < MAX_HEADER_OPTION_DATA_LENGTH ?
optionLength : MAX_HEADER_OPTION_DATA_LENGTH;
memcpy(optionData, optData, optionLength);
optionData[optionLength - 1] = '\0';
}
#endif
}
[StructLayout(LayoutKind.Sequential)]
internal class OCPayload
{
public OCPayload(OCPayloadType type = OCPayloadType.PAYLOAD_TYPE_INVALID)
{
this.type = type;
}
/** The type of message that was received */
public OCPayloadType type;
}
/**
* Possible returned values from entity handler.
*/
[StructLayout(LayoutKind.Sequential)]
internal class OCObservationInfo
{
/** Action associated with observation request.*/
OCObserveAction action;
/** Identifier for observation being registered/deregistered.*/
byte obsId;
}
#endregion
#region OC Enum Definitions
/** Enum to describe the type of object held by the OCPayload object.*/
internal enum OCPayloadType
{
/** Contents of the payload are invalid */
PAYLOAD_TYPE_INVALID,
/** The payload is an OCDiscoveryPayload */
PAYLOAD_TYPE_DISCOVERY,
/** The payload of the device */
PAYLOAD_TYPE_DEVICE,
/** The payload type of the platform */
PAYLOAD_TYPE_PLATFORM,
/** The payload is an OCRepPayload */
PAYLOAD_TYPE_REPRESENTATION,
/** The payload is an OCSecurityPayload */
PAYLOAD_TYPE_SECURITY,
/** The payload is an OCPresencePayload */
PAYLOAD_TYPE_PRESENCE
}
/**
* Action associated with observation.
*/
internal enum OCObserveAction
{
/** To Register. */
OC_OBSERVE_REGISTER = 0,
/** To Deregister. */
OC_OBSERVE_DEREGISTER = 1,
/** Others. */
OC_OBSERVE_NO_OPTION = 2,
}
internal enum OCMode
{
OC_CLIENT = 0,
OC_SERVER,
OC_CLIENT_SERVER,
OC_GATEWAY /**< Client server mode along with routing capabilities.*/
}
/**
* Declares Stack Results & Errors.
*/
internal enum OCStackResult
{
/** Success status code - START HERE.*/
OC_STACK_OK = 0, /** 203, 205*/
OC_STACK_RESOURCE_CREATED, /** 201*/
OC_STACK_RESOURCE_DELETED, /** 202*/
OC_STACK_CONTINUE,
OC_STACK_RESOURCE_CHANGED, /** 204*/
/** Success status code - END HERE.*/
/** Error status code - START HERE.*/
OC_STACK_INVALID_URI = 20,
OC_STACK_INVALID_QUERY, /** 400*/
OC_STACK_INVALID_IP,
OC_STACK_INVALID_PORT,
OC_STACK_INVALID_CALLBACK,
OC_STACK_INVALID_METHOD,
/** Invalid parameter.*/
OC_STACK_INVALID_PARAM,
OC_STACK_INVALID_OBSERVE_PARAM,
OC_STACK_NO_MEMORY,
OC_STACK_COMM_ERROR, /** 504*/
OC_STACK_TIMEOUT,
OC_STACK_ADAPTER_NOT_ENABLED,
OC_STACK_NOTIMPL,
/** Resource not found.*/
OC_STACK_NO_RESOURCE, /** 404*/
/** e.g: not supported method or interface.*/
OC_STACK_RESOURCE_ERROR,
OC_STACK_SLOW_RESOURCE,
OC_STACK_DUPLICATE_REQUEST,
/** Resource has no registered observers.*/
OC_STACK_NO_OBSERVERS,
OC_STACK_OBSERVER_NOT_FOUND,
OC_STACK_VIRTUAL_DO_NOT_HANDLE,
OC_STACK_INVALID_OPTION, /** 402*/
/** The remote reply contained malformed data.*/
OC_STACK_MALFORMED_RESPONSE,
OC_STACK_PERSISTENT_BUFFER_REQUIRED,
OC_STACK_INVALID_REQUEST_HANDLE,
OC_STACK_INVALID_DEVICE_INFO,
OC_STACK_INVALID_JSON,
/** Request is not authorized by Resource Server. */
OC_STACK_UNAUTHORIZED_REQ, /** 401*/
OC_STACK_TOO_LARGE_REQ, /** 413*/
/** Error code from PDM */
OC_STACK_PDM_IS_NOT_INITIALIZED,
OC_STACK_DUPLICATE_UUID,
OC_STACK_INCONSISTENT_DB,
/**
* Error code from OTM
* This error is pushed from DTLS interface when handshake failure happens
*/
OC_STACK_AUTHENTICATION_FAILURE,
OC_STACK_NOT_ALLOWED_OXM,
/** Request come from endpoint which is not mapped to the resource. */
OC_STACK_BAD_ENDPOINT,
/** Insert all new error codes here!.*/
#if WITH_PRESENCE
OC_STACK_PRESENCE_STOPPED = 128,
OC_STACK_PRESENCE_TIMEOUT,
OC_STACK_PRESENCE_DO_NOT_HANDLE,
#endif
/** Request is denied by the user*/
OC_STACK_USER_DENIED_REQ,
/** ERROR code from server */
OC_STACK_FORBIDDEN_REQ, /** 403*/
OC_STACK_INTERNAL_SERVER_ERROR, /** 500*/
/** ERROR in stack.*/
OC_STACK_ERROR = 255
/** Error status code - END HERE.*/
}
/**
* Enum layout assumes some targets have 16-bit integer (e.g., Arduino).
*/
[Flags]
internal enum OCTransportFlags
{
/** default flag is 0*/
OC_DEFAULT_FLAGS = 0,
/** Insecure transport is the default (subject to change).*/
/** secure the transport path*/
OC_FLAG_SECURE = (1 << 4),
/** IPv4 & IPv6 auto-selection is the default.*/
/** IP & TCP adapter only.*/
OC_IP_USE_V6 = (1 << 5),
/** IP & TCP adapter only.*/
OC_IP_USE_V4 = (1 << 6),
/** Multicast only.*/
OC_MULTICAST = (1 << 7),
/** Link-Local multicast is the default multicast scope for IPv6.
* These are placed here to correspond to the IPv6 multicast address bits.*/
/** IPv6 Interface-Local scope (loopback).*/
OC_SCOPE_INTERFACE = 0x1,
/** IPv6 Link-Local scope (default).*/
OC_SCOPE_LINK = 0x2,
/** IPv6 Realm-Local scope. */
OC_SCOPE_REALM = 0x3,
/** IPv6 Admin-Local scope. */
OC_SCOPE_ADMIN = 0x4,
/** IPv6 Site-Local scope. */
OC_SCOPE_SITE = 0x5,
/** IPv6 Organization-Local scope. */
OC_SCOPE_ORG = 0x8,
/**IPv6 Global scope. */
OC_SCOPE_GLOBAL = 0xE,
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate OCEntityHandlerResult OCEntityHandler(OCEntityHandlerFlag flag, OCEntityHandlerRequest entityHandlerRequest, IntPtr callbackParam);
/**
* Possible returned values from entity handler.
*/
internal enum OCEntityHandlerResult
{
OC_EH_OK = 0,
OC_EH_ERROR,
OC_EH_SLOW,
OC_EH_RESOURCE_CREATED = 201,
OC_EH_RESOURCE_DELETED = 202,
OC_EH_VALID = 203,
OC_EH_CHANGED = 204,
OC_EH_CONTENT = 205,
OC_EH_BAD_REQ = 400,
OC_EH_UNAUTHORIZED_REQ = 401,
OC_EH_BAD_OPT = 402,
OC_EH_FORBIDDEN = 403,
OC_EH_RESOURCE_NOT_FOUND = 404,
OC_EH_METHOD_NOT_ALLOWED = 405,
OC_EH_NOT_ACCEPTABLE = 406,
OC_EH_TOO_LARGE = 413,
OC_EH_UNSUPPORTED_MEDIA_TYPE = 415,
OC_EH_INTERNAL_SERVER_ERROR = 500,
OC_EH_BAD_GATEWAY = 502,
OC_EH_SERVICE_UNAVAILABLE = 503,
OC_EH_RETRANSMIT_TIMEOUT = 504
}
/**
* Entity's state
*/
internal enum OCEntityHandlerFlag
{
/** Request state.*/
OC_REQUEST_FLAG = (1 << 1),
/** Observe state.*/
OC_OBSERVE_FLAG = (1 << 2)
}
/**
* Resource Properties.
* The value of a policy property is defined as bitmap.
* The LSB represents OC_DISCOVERABLE and Second LSB bit represents OC_OBSERVABLE and so on.
* Not including the policy property is equivalent to zero.
*
*/
[Flags]
internal enum OCResourceProperty : byte
{
/** When none of the bits are set, the resource is non-discoverable &
* non-observable by the client.*/
OC_RES_PROP_NONE = (0),
/** When this bit is set, the resource is allowed to be discovered by clients.*/
OC_DISCOVERABLE = (1 << 0),
/** When this bit is set, the resource is allowed to be observed by clients.*/
OC_OBSERVABLE = (1 << 1),
/** When this bit is set, the resource is initialized, otherwise the resource
* is 'inactive'. 'inactive' signifies that the resource has been marked for
* deletion or is already deleted.*/
OC_ACTIVE = (1 << 2),
/** When this bit is set, the resource has been marked as 'slow'.
* 'slow' signifies that responses from this resource can expect delays in
* processing its requests from clients.*/
OC_SLOW = (1 << 3),
#if __WITH_DTLS__ || __WITH_TLS__
/** When this bit is set, the resource is a secure resource.*/
OC_SECURE = (1 << 4),
#else
OC_SECURE = (0),
#endif
/** When this bit is set, the resource is allowed to be discovered only
* if discovery request contains an explicit querystring.
* Ex: GET /oic/res?rt=oic.sec.acl */
OC_EXPLICIT_DISCOVERABLE = (1 << 5)
#if WITH_MQ
/** When this bit is set, the resource is allowed to be published */
, OC_MQ_PUBLISHER = (1 << 6)
#endif
#if MQ_BROKER
/** When this bit is set, the resource is allowed to be notified as MQ broker.*/
, OC_MQ_BROKER = (1 << 7)
#endif
}
/**
* OCDoResource methods to dispatch the request
*/
internal enum OCMethod
{
OC_REST_NOMETHOD = 0,
/** Read.*/
OC_REST_GET = (1 << 0),
/** Write.*/
OC_REST_PUT = (1 << 1),
/** Update.*/
OC_REST_POST = (1 << 2),
/** Delete.*/
OC_REST_DELETE = (1 << 3),
/** Register observe request for most up date notifications ONLY.*/
OC_REST_OBSERVE = (1 << 4),
/** Register observe request for all notifications, including stale notifications.*/
OC_REST_OBSERVE_ALL = (1 << 5),
#if WITH_PRESENCE
/** Subscribe for all presence notifications of a particular resource.*/
OC_REST_PRESENCE = (1 << 7),
#endif
/** Allows OCDoResource caller to do discovery.*/
OC_REST_DISCOVER = (1 << 8)
}
/**
* These enums (OCTransportAdapter and OCTransportFlags) must
* be kept synchronized with OCConnectivityType (below) as well as
* CATransportAdapter and CATransportFlags (in CACommon.h).
*/
internal enum OCTransportAdapter
{
/** value zero indicates discovery.*/
OC_DEFAULT_ADAPTER = 0,
/** IPv4 and IPv6, including 6LoWPAN.*/
OC_ADAPTER_IP = (1 << 0),
/** GATT over Bluetooth LE.*/
OC_ADAPTER_GATT_BTLE = (1 << 1),
/** RFCOMM over Bluetooth EDR.*/
OC_ADAPTER_RFCOMM_BTEDR = (1 << 2),
#if RA_ADAPTER
/**Remote Access over XMPP.*/
OC_ADAPTER_REMOTE_ACCESS = (1 << 3),
#endif
/** CoAP over TCP.*/
OC_ADAPTER_TCP = (1 << 4),
/** NFC Transport for Messaging.*/
OC_ADAPTER_NFC = (1 << 5)
}
/**
* Transport Protocol IDs.
*/
internal enum OCTransportProtocolID
{
/** For invalid ID.*/
OC_INVALID_ID = (1 << 0),
/* For coap ID.*/
OC_COAP_ID = (1 << 1)
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment