--- /dev/null
+#******************************************************************
+#
+# Copyright 2017 Microsoft
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+##
+# 'ipca' sub-project main build script
+#
+##
+
+Import('env')
+
+ipca_env = env.Clone()
+ipca_env.AppendUnique(CCFLAGS=['/W4'])
+
+# Build ipca lib
+SConscript('src/SConscript', 'ipca_env')
+
+# Build examples
+SConscript('samples/SConscript', 'ipca_env')
\ No newline at end of file
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef IPCA_H_ // IoTivity Procedural Client API
+#define IPCA_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A physical device (piece of plastic) is represented by a platform object with a UUID identifier
+ *
+ * A logical device is a virtual device that runs on the platform and is represented by a UUID
+ * identifier. Multiple logical devices can run on a platform.
+ *
+ * A logical device is made up of one or more resources. Each resource is identified by a "/"
+ * separated string which is unique within the device.
+ *
+ * A resource implements one or more resource types. A resource type is identified by a "."
+ * separated string which is unique within the resource.
+ *
+ * Finally each resource type has a number of properties. Each property is represented by a pair of
+ * key and value.
+ *
+ * Below is an example of a physical device with one logical device. The logical device implements
+ * multiple resources as follows:
+ * 1. Base platform resources (/oic/p, /oic/d) [note: refer to the OCF spec for a complete set of
+ * mandatory resources a device implements]
+ * 2. OEM Elevator resource
+ * 3. OEM Display screen resource
+ *
+ * Platform (id: UUID)
+ * |
+ * + Device (id: UUID)
+ * |
+ * + Resource (name: "/oic/d")
+ * | |
+ * | + Resource Type (name: "oic.wk.d", interface: "oic.if.r")
+ * | |
+ * | + Property (key: "piid", type: string, access: read-only)
+ * | + Property (key: "di", type: string, access: read-only)
+ * | + Property (key: "n", type: string, access: read-only)
+ * | + Property (key: "icv", type: string, access: read-only)
+ * | + Property (key: "dmv", type: string, access: read-only)
+ * |
+ * + Resource (name: "/oic/p")
+ * | |
+ * | + Resource Type (name: "oic.wk.p", interface: "oic.if.r")
+ * | |
+ * | + Property (key: "pi", type: string, access: read-only)
+ * | + Property (key: "mnmn", type: string, access: read-only)
+ * | + Property (key: "mnmo", type: string, access: read-only)
+ * | + Property (key: "mnos", type: string, access: read-only)
+ * | + Property (key: "mnfv", type: string, access: read-only)
+ * | + ...
+ * |
+ * + Resource ("/oem/elevator")
+ * | |
+ * | + Resource Type ("x.oem.elevator.status", interface: "oic.if.r")
+ * | | |
+ * | | + Property ("x.oem.CurrentFloor", type: integer, access: read-only)
+ * | | + Property ("x.oem.Direction", type: integer, access: read-only)
+ * | |
+ * | + Resource Type ("x.oem.elevator.operation", interface: "oic.if.a")
+ * | | |
+ * | | + Property ("x.oem.TargetFloor" type: integer, access: read-write)
+ * | |
+ * | + Resource Type ("x.oem.elevator.maintenance", interface: "oic.if.r")
+ * | |
+ * | + Property ("x.oem.MotorTemperature", type: integer, access: read-only)
+ * | + Property ("x.oem.PulleyTension", type: integer, access: read-only)
+ * |
+ * + Resource ("/oem/display")
+ * |
+ * + Resource Type ("x.oem.display.screen", interface: "oic.if.r, oic.if.w")
+ * |
+ * + Property ("x.oem.DisplayText", type: string, access: read-write)
+ * + Property ("x.oem.DisplayBackground", type: string, access: read-write)
+ */
+
+/**
+ * Handle types returned by IPCA.
+ */
+typedef struct IPCAAppHandleStruct* IPCAAppHandle;
+typedef struct IPCACallbackHandleStruct* IPCACallbackHandle;
+typedef struct IPCADeviceHandleStruct* IPCADeviceHandle;
+typedef struct IPCAPropertyBagHandleStruct* IPCAPropertyBagHandle;
+typedef struct IPCAHandleStruct* IPCAHandle;
+
+struct IPCAUuid
+{
+ uint8_t uuid[16];
+};
+
+// @todo: determine if this needs to map to __stdcall.
+// On x86 this causes the following run time failure.
+// "Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.
+// This is usually a result of calling a function declared with one calling convention with a
+// function pointer declared with a different calling convention."
+#define IPCA_CALL
+
+/**
+ * Some information about the device from device discovery.
+ * Use IPCAGetDeviceInfo() for detailed device information.
+ *
+ * deviceId UUID of the device. The value is as defined in OCF 1.0 Security Specification
+ * for DeviceID.
+ * An example of UUID string: d99c2350-d95e-11e6-bf26-cec0c932ce01.
+ * deviceUris An array of device URIs (e.g., coap://[fe80::c0bd:f33:6783:78fe%2]:49555).
+ * A device can have multiple endpoints.
+ * deviceUriCount Number of device URIs in the deviceUris array.
+ * deviceName Human friendly name of the device.
+ */
+typedef struct
+{
+ const char* deviceId;
+ const char** deviceUris;
+ size_t deviceUriCount;
+ const char* deviceName;
+} IPCADiscoveredDeviceInfo;
+
+/**
+ * The IPCA version.
+ */
+typedef enum
+{
+ IPCA_VERSION_1 = 1
+} IPCAVersion;
+
+/**
+ * Device information.
+ *
+ * version The IPCA version of the IPCADeviceInfo structure matching version
+ * requested in IPCAOpen.
+ * protocolIndependentId Protocol independent ID of the device. This is in UUID format.
+ * An example of UUID string: d99c2350-d95e-11e6-bf26-cec0c932ce01.
+ * deviceId UUID of the device. The value is as defined in OCF 1.0 Security
+ * Specification for DeviceID.
+ * deviceUris An array of of device URIs
+ * (e.g., coap://[fe80::c0bd:f33:6783:78fe%2]:49555).
+ * A device can have multiple endpoints.
+ * deviceUriCount Number of device URIs in the deviceUris array.
+ * deviceName Human friendly name of the device.
+ * deviceSpecVersion Spec version of the the core specification this device is
+ * implemented to.
+ * dataModelVersions Array of spec versions of the vertical specifications.
+ * dataModelVersionCount Number of spec versions in dataModelVersions array.
+ * localizedDescriptions Detailed description of the device in one or more languages. Each
+ * object has a 'language' key field and 'value' field.
+ * deviceSoftwareVersion Version of device software.
+ * manufacturerName Name of manufacturer of device. Each object has a 'language' key
+ * field and manufacturer name 'value' field.
+ * modelNumber Model number as designated by manufacturer.
+ */
+typedef struct
+{
+ IPCAVersion version;
+ const char* protocolIndependentId;
+ const char* deviceId;
+ const char** deviceUris;
+ size_t deviceUriCount;
+ const char* deviceName;
+ const char* deviceSpecVersion;
+ const char** dataModelVersions;
+ size_t dataModelVersionCount;
+ IPCAPropertyBagHandle localizedDescriptions;
+ const char* deviceSoftwareVersion;
+ IPCAPropertyBagHandle manufacturerNames;
+ const char* modelNumber;
+} IPCADeviceInfo;
+
+/**
+ * Platform information.
+ *
+ * version The IPCA version of the IPCAPlatformInfo structure matching version
+ * requested in IPCAOpen.
+ * platformId UUID of platform identifier.
+ * An example of UUID string: d99c2350-d95e-11e6-bf26-cec0c932ce01.
+ * manufacturerName Name of the manufacturer of the platform.
+ * manufacturerURL Manufacturer's URL.
+ * modelNumber Model number as defined by the manufacturer.
+ * manufacturingDate Manufacturing date.
+ * platformVersion Platform version.
+ * osVersion Platform resident OS version.
+ * hardwareVersion Platform hardware version.
+ * firmwareVersion Platform firmware version.
+ * manufacturerSupportURL Manufacturer's support information URL.
+ * referenceTime Reference time for the device.
+ */
+typedef struct
+{
+ IPCAVersion version;
+ const char* platformId;
+ const char* manufacturerName;
+ const char* manufacturerURL;
+ const char* modelNumber;
+ const char* manufacturingDate;
+ const char* platformVersion;
+ const char* osVersion;
+ const char* hardwareVersion;
+ const char* firmwareVersion;
+ const char* manufacturerSupportURL;
+ const char* referenceTime;
+} IPCAPlatformInfo;
+
+/**
+ * Application's information.
+ *
+ * appId UUID of the app.
+ * appName Friendly name of the app.
+ * appSoftwareVersion Software version of the app.
+ * appCompanyName Name of the software company that produced this app.
+ *
+ */
+typedef struct
+{
+ IPCAUuid appId;
+ const char* appName;
+ const char* appSoftwareVersion;
+ const char* appCompanyName;
+} IPCAAppInfo;
+
+/**
+ * IPCA status.
+ */
+typedef enum
+{
+ IPCA_OK = 0, // Successful.
+ IPCA_FAIL, // Generic error status.
+ IPCA_ALREADY_OPENED, // IPCAOpen() is already called.
+ // Use IPCAClose() to close the IPCA session.
+ IPCA_INVALID_ARGUMENT, // Invalid parameters passed to IPCA methods.
+ IPCA_INVALID_GUID, // Invalid GUID string.
+ IPCA_OUT_OF_MEMORY, // Out of memory error.
+ IPCA_INFO_VERSION_NOT_SUPPORTED, // Requested info version is not supported.
+
+ // Device related
+ IPCA_DEVICE_APPEAR_OFFLINE = 0x1000, // Device is either offline or not responding and
+ // assumed offline.
+ IPCA_DEVICE_NOT_DISCOVERED, // Device is not discovered by IPCADiscoverDevices().
+ IPCA_INFORMATION_NOT_AVAILABLE, // Information is not available, caller can retry in a
+ // few seconds.
+
+ // Resource related
+ IPCA_RESOURCE_NOT_FOUND = 0x2000, // No matching resource.
+ IPCA_RESOURCE_CREATED, // Device created new resource.
+ IPCA_RESOURCE_DELETED, // Device deleted resource.
+ IPCA_REQUEST_TIMEOUT, // No response from server.
+
+ // Resource type related
+ IPCA_PROPERTY_NOT_SUPPORTED = 0x3000, // When property is not mandatory in a resource type,
+ // e.g., Factory_Reset in oic.wk.mnt.
+
+ // Security related
+ IPCA_ACCESS_DENIED = 0x4000, // The requested access to a device has failed due to
+ // the current security settings.
+ // The application can then call IPCARequestAccess, to
+ // request updated settings.
+
+ IPCA_SECURITY_UPDATE_REQUEST_FINISHED, // Security settings have been updated. Re-attemping an
+ // operation that previously failed with status
+ // IPCA_ACCESS_DENIED might yield a different result.
+
+ IPCA_SECURITY_UPDATE_REQUEST_INCORRECT_PASSWORD, // Updating the security settings failed
+ // due to an incorrect password.
+
+ IPCA_SECURITY_UPDATE_REQUEST_NOT_SUPPORTED, // Updating the security settings corresponding to
+ // a device is not supported.
+
+ IPCA_SECURITY_UPDATE_REQUEST_FAILED, // Updating the security settings has been
+ // attempted, but failed.
+} IPCAStatus;
+
+/**
+ * Callback from IPCA to application when device sends a resource change notification.
+ * To receive resource change notifications, application calls IPCAObserveResource() to set
+ * observation on a resource.
+ *
+ * @param[in] result Result of the call.
+ * @param[in] context Caller's context set in IPCAObserveResource().
+ * @param[in] propertyBagHandle Handle to an IPCAPropertyBag object.
+ * Use IPCAPropertyBag APIs to retrieve the values indexed by keys.
+ * propertyBagHandle is only valid during this callback.
+ */
+typedef void (IPCA_CALL *IPCAResourceChangeCallback)(IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle);
+
+/**
+ * Callback from IPCA to application when device responds to IPCAGetProperties().
+ *
+ * @param[in] result Result of the call.
+ * @param[in] context Caller's context set in IPCAGetProperties().
+ * @param[in] propertyBagHandle Handle to an IPCAPropertyBag bag object.
+ * Use IPCAPropertyBag APIs to retrieve the values indexed by keys.
+ * propertyBagHandle is only valid during this callback.
+ */
+typedef void (IPCA_CALL *IPCAGetPropertiesComplete)(IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle);
+/**
+ * Callback from IPCA to application when device responds to IPCASetProperties().
+ *
+ * @param[in] result Result of the call.
+ * @param[in] context Caller's context set in IPCASetProperties().
+ * @param[in] propertyBagHandle Handle to an IPCAPropertyBag object.
+ * Use IPCAPropertyBag APIs to retrieve the values indexed by keys.
+ * propertyBagHandle is only valid during this callback.
+ */
+typedef void (IPCA_CALL *IPCASetPropertiesComplete)(IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle);
+
+/**
+ * Callback from IPCA to application when device responds to IPCACreateResource().
+ *
+ * @param[in] result Result of the call.
+ * @param[in] context Caller's context set in IPCACreateResource().
+ * @param[in] newResourcePath The relative path of the newly created resource in the collection.
+ * @param[in] propertyBagHandle Handle to an IPCAPropertyBag object.
+ * Use IPCAPropertyBag APIs to retrieve the values indexed by keys.
+ * propertyBagHandle is only valid during this callback.
+ *
+ */
+typedef void (IPCA_CALL *IPCACreateResourceComplete)(IPCAStatus result,
+ void* context,
+ const char* newResourcePath,
+ IPCAPropertyBagHandle propertyBagHandle);
+
+/**
+ * Callback from IPCA to application when device responds to IPCADeleteResource().
+ *
+ * @param[in] result Result of the call.
+ * @param[in] context Caller's context set in IPCADeleteResource().
+ *
+ */
+typedef void (IPCA_CALL *IPCADeleteResourceComplete)(IPCAStatus result, void* context);
+
+/**
+ * Discovery status in IPCADiscoverDeviceCallback.
+ */
+typedef enum
+{
+ IPCA_DEVICE_DISCOVERED = 1, /* Device responded to discovery request. */
+ IPCA_DEVICE_UPDATED_INFO, /* There's an update in discoveredDeviceInfo. */
+ IPCA_DEVICE_STOPPED_RESPONDING, /* Device stopped responding to discovery request. */
+} IPCADeviceStatus;
+
+
+/**
+ * Callback when a device that implements resourceTypeList in IPCADiscoverDevices() is either
+ * discovered or has stopped responding to discovery request.
+ *
+ * @param[in] context Application's context in IPCADiscoverDevices().
+ * @param[in] deviceStatus See IPCADeviceStatus.
+ * @param[in] discoveredDeviceInfo Some information of device.
+ */
+
+typedef void (IPCA_CALL *IPCADiscoverDeviceCallback)(
+ void* context,
+ IPCADeviceStatus deviceStatus,
+ const IPCADiscoveredDeviceInfo* discoveredDeviceInfo);
+
+/**
+ * An application calls this method one time to register with IPCA.
+ *
+ * @param[in] ipcaAppInfo Application's information. See IPCAAppInfo.
+ * @param[in] ipcaVersion The IPCAVersion the application can work with.
+ * @param[out] ipcaAppHandle Handle returned by IPCA. Use IPCAClose() to close the handle.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCA_CALL IPCAOpen(const IPCAAppInfo* ipcaAppInfo,
+ IPCAVersion ipcaVersion,
+ IPCAAppHandle* ipcaAppHandle);
+
+/**
+ * Close the handle returned in IPCAOpen().
+ * After this call returns, application should consider any outstanding calls to devices canceled
+ * and opened handles closed.
+ *
+ * @param[in] ipcaAppHandle Handle returned in IPCAOpen().
+ */
+void IPCA_CALL IPCAClose(IPCAAppHandle ipcaAppHandle);
+
+
+/**
+ * Application calls this method to start discovery of devices that implement resource types
+ * specified in resourceTypeList.
+ * The underlying framework triggers discovery request periodically until caller cancels the
+ * request using IPCACloseHandle().
+ *
+ * @param[in] ipcaAppHandle Application handle returned in IPCAOpen().
+ * @param[in] callback Callback from IPCA when devices are found.
+ * @param[in] context Application's context that is passed back as argument in the
+ * callback.
+ * @param[in] resourceTypeList A list of resource types, a device must implement all of them
+ * to be discovered. Empty string indicates any resource type.
+ * @param[in] resourceTypeCount Number of resource types pointed by resourceTypeList.
+ * @param[out] handle Handle that can be used in IPCACloseHandle() to stop device
+ * discovery.
+ * Null handle pointer is not allowed.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCA_CALL IPCADiscoverDevices(IPCAAppHandle ipcaAppHandle,
+ IPCADiscoverDeviceCallback discoverDeviceCallback,
+ void* context,
+ const char* const* resourceTypeList,
+ int resourceTypeCount,
+ IPCAHandle* handle);
+
+/**
+ * Application indicates to IPCA the intention to start working with a device whose ID matches
+ * deviceID.
+ *
+ * @param[in] ipcaAppHandle Application handle returned in IPCAOpen().
+ * @param[in] deviceId UUID of device (see: IPCADeviceInfo).
+ * @param[out] deviceHandle Handle to the device. Use IPCACloseDevice() to close device handle.
+ *
+ * @return IPCA_OK if successful. IPCA_DEVICE_NOT_DISCOVERED if device is not yet discovered, call
+ * IPCADiscoverDevices().
+ */
+IPCAStatus IPCA_CALL IPCAOpenDevice(IPCAAppHandle ipcaAppHandle,
+ const char* deviceId,
+ IPCADeviceHandle* deviceHandle);
+
+/**
+ * Closes device handle. The application will stop receiving notifications and callbacks from the
+ * device.
+ *
+ * @param[in] deviceHandle device handle returned in IPCAOpenDevice().
+ */
+void IPCA_CALL IPCACloseDevice(IPCADeviceHandle deviceHandle);
+
+/**
+ * This method returns a pointer to IPCADeviceInfo structure.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[out] deviceInfo IPCA returns a pointer to IPCADeviceInfo structure.
+ * Use IPCAFreeDeviceInfo() to free the memory.
+ *
+ * @return
+ * IPCA_OK if successful.
+ * IPCA_INFORMATION_NOT_AVAILABLE if server has not returned the device info query.
+ * IPCA_INFO_VERSION_NOT_SUPPORTED when requested info version is not supported.
+ */
+IPCAStatus IPCAGetDeviceInfo(IPCADeviceHandle deviceHandle, IPCADeviceInfo** deviceInfo);
+
+/**
+ * Free the memory allocated in IPCAGetDeviceInfo().
+ *
+ * @param[in] deviceInfo a Pointer to IPCADeviceInfo structure returned in IPCAGetDeviceInfo().
+ */
+void IPCAFreeDeviceInfo(IPCADeviceInfo* deviceInfo);
+
+/**
+ * This method returns a pointer to IPCAPlatformInfo structure.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[out] platformInfo IPCA returns a pointer to IPCAPlatformInfo structure.
+ * Use IPCAFreePlatformInfo() to free the memory.
+ *
+ * @return
+ * IPCA_OK if successful.
+ * IPCA_INFORMATION_NOT_AVAILABLE if server has not returned the platform info query.
+ * IPCA_INFO_VERSION_NOT_SUPPORTED when requested info version is not supported.
+ */
+IPCAStatus IPCAGetPlatformInfo(IPCADeviceHandle deviceHandle, IPCAPlatformInfo** platformInfo);
+
+/**
+ * Free the memory allocated in IPCAGetPlatformInfo().
+ *
+ * @param[in] platformInfo A pointer to IPCAPlatformInfo structure returned
+ * in IPCAGetPlatformInfo().
+ */
+void IPCAFreePlatformInfo(IPCAPlatformInfo* platformInfo);
+
+/**
+ * Get the resources that implement resource types in IPCADiscoverDevices().
+ * Application must call IPCAFreeStringArray() to free memory allocated for resourcePathList.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[in] resourceInterface Interface the resource must support. Use NULL or empty string
+ * for any interface.
+ * @param[in] resourceType Resource type the resource must implement. Use NULL or empty
+ * string for any resource type.
+ * @param[out] resourcePathList A pointer to an array of resource path, a percent encoded URI
+ * reference, that IPCA returns.
+ * @param[out] resourcePathCount Number of resource paths returned.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCA_CALL IPCAGetResources(IPCADeviceHandle deviceHandle,
+ const char* resourceInterface,
+ const char* resourceType,
+ char*** resourcePathList,
+ size_t* resourcePathCount);
+
+/**
+ * Get the list of resource types implemented by a resource.
+ * Application must call IPCAFreeStringArray() to free memory allocated for resourceTypeList.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[in] resourcePath Resource path, a percent encoded URI reference, e.g., "/oic/d".
+ * If resourcePath is equal to NULL or empty string, IPCA returns
+ * all resource types.
+ * @param[out] resourceTypeList A pointer to an array of resource types that IPCA returns.
+ * @param[out] resourceTypeCount Number of resource types returned.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCA_CALL IPCAGetResourceTypes(IPCADeviceHandle deviceHandle,
+ const char* resourcePath,
+ char*** resourceTypeList,
+ size_t* resourceTypeCount);
+
+/**
+ * Get the list of resource interfaces implemented by a resource.
+ * Application must call IPCAFreeStringArray() to free memory allocated for resourceInterfaceList.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[in] resourcePath Resource path, a percent encoded URI reference,
+ * e.g., "/oic/d".
+ * If resourcePath is equal to NULL or empty string,
+ * IPCA returns all interfaces the device supports.
+ * @param[out] resourceInterfaceList A pointer to an array of resource interfaces.
+ * @param[out] resourceInterfaceCount Number of resource interfaces returned.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCA_CALL IPCAGetResourceInterfaces(IPCADeviceHandle deviceHandle,
+ const char* resourcePath,
+ char*** resourceInterfaceList,
+ size_t* resourceInterfaceCount);
+
+/**
+ * Free string array returned in IPCAGetResources(), IPCAGetResourceTypes(),
+ * IPCAGetResourceInterfaces().
+ *
+ * @param[in] stringArray Array of strings.
+ * @param[in] stringCount Number of strings.
+ *
+ */
+void IPCA_CALL IPCAFreeStringArray(char** stringArray, size_t stringCount);
+
+/**
+ * Get property values of a resource.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[in] getPropertiesComplete Caller's callback when device responds to
+ * IPCAGetProperties()
+ * @param[in] context Application's context that is passed back as argument in the
+ * callback.
+ * @param[in] resourcePath Resource which implements the resource type. E.g., "/oic/d".
+ * @param[in] resourceInterface Resource interface to be used. Use NULL or empty string for
+ * default interface.
+ * @param[in] resourceType The resource type which implements the properties.
+ * @param[out] handle Handle that can be used in IPCACloseHandle() to cancel the
+ * callback.
+ * The reference count to the handle is handled by IPCA.
+ * Therefore, caller does not need to close the handle.
+ * Null handle pointer is allowed when caller does not plan to
+ * receive device's response.
+ *
+ * @return IPCA_OK if successful. IPCA calls getPropertiesComplete() when device responds.
+ */
+IPCAStatus IPCA_CALL IPCAGetProperties(IPCADeviceHandle deviceHandle,
+ IPCAGetPropertiesComplete getPropertiesComplete,
+ void* context,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType,
+ IPCAHandle* handle);
+
+/**
+ * Set property values of a resource.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[in] setPropertiesComplete Caller's callback when device responds to
+ * IPCASetProperties()
+ * @param[in] context Application's context that is passed back as argument in the
+ * callback.
+ * @param[in] resourcePath Resource path which implements the resource type.
+ * E.g., "/oic/d".
+ * @param[in] resourceInterface Resource interface to be used. Use NULL or empty string for
+ * default interface.
+ * @param[in] resourceType The resource type which implements the properties.
+ * @param[in] propertyBagHandle Data to set (see IPCAPropertyBagCreate()).
+ * @param[out] handle Handle that can be used in IPCACloseHandle() to cancel the
+ * callback.
+ * The reference count to the handle is handled by IPCA.
+ * Therefore, caller does not need to close the handle.
+ * Null handle pointer is allowed when caller does not plan to
+ * receive device's response.
+ *
+ * @return IPCA_OK if successful. IPCA calls setPropertiesComplete() when device reponds.
+ */
+IPCAStatus IPCA_CALL IPCASetProperties(IPCADeviceHandle deviceHandle,
+ IPCASetPropertiesComplete setPropertiesComplete,
+ void* context,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType,
+ IPCAPropertyBagHandle propertyBagHandle,
+ IPCAHandle* handle);
+
+/**
+ * Request device to create a new resource.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[in] createResourceComplete Caller's callback when device responds to
+ * IPCACreateResource()
+ * @param[in] context Application's context that is passed back as argument in
+ * the callback.
+ * @param[in] resourceCollectionPath Resource that handles resource creation.
+ * @param[in] resourceInterface Resource interface to be used. Use NULL or empty string for
+ * default interface.
+ * @param[in] resourceType The resource type which implements the properties.
+ * @param[in] propertyBagHandle Data to set (see IPCAPropertyBagCreate()).
+ * @param[out] handle Handle that can be used in IPCACloseHandle() to cancel the
+ * callback.
+ * The reference count to the handle is handled by IPCA.
+ * Therefore, caller does not need to close the handle.
+ * Null handle pointer is allowed when caller does not plan to
+ * receive device's response.
+ *
+ * @return IPCA_OK if successful. IPCA calls createResourceComplete() when device reponds.
+ */
+IPCAStatus IPCA_CALL IPCACreateResource(IPCADeviceHandle deviceHandle,
+ IPCACreateResourceComplete createResourceComplete,
+ void* context,
+ const char* resourceCollectionPath,
+ const char* resourceInterface,
+ const char* resourceType,
+ IPCAPropertyBagHandle propertyBagHandle,
+ IPCAHandle* handle);
+
+/**
+ * Request device to delete a resource.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[in] deleteResourceComplete Caller's callback when device responds to
+ * IPCADeleteResource()
+ * @param[in] context Application's context that is passed back as argument in
+ * the callback.
+ * @param[in] resourcePath Resource path of resource to be deleted.
+ * @param[out] handle Handle that can be used in IPCACloseHandle() to cancel the
+ * callback.
+ * The reference count to the handle is handled by IPCA.
+ * Therefore, caller does not need to close the handle.
+ * Null handle pointer is allowed when caller does not plan to
+ * receive device's response.
+ *
+ * @return IPCA_OK if successful. IPCA calls deleteResourceComplete() when device reponds.
+ */
+
+IPCAStatus IPCA_CALL IPCADeleteResource(IPCADeviceHandle deviceHandle,
+ IPCADeleteResourceComplete deleteResourceComplete,
+ void* context,
+ const char* resourcePath,
+ IPCAHandle* handle);
+
+/**
+ * Function returns whether a resource is observable.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[in] resourcePath Resource to check for observability.
+ * @param[out] isObservable Set to true if resourcePath is observable. Set to false otherwise.
+ *
+ * @return IPCA_OK if successful.
+ */
+void IPCA_CALL IPCAIsResourceObservable(IPCADeviceHandle deviceHandle,
+ const char* resourcePath,
+ bool* isObservable);
+
+/**
+ * Function to start observing a resource. Use IPCACloseHandle() to stop receiving resource change
+ * notifications from the device.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[in] resourceChangeCallback Caller's callback when device sends a resource change
+ * notification.
+ * @param[in] context Application's context that is passed back as argument in the
+ * callback.
+ * @param[in] resourcePath Resource to observe. E.g., "/oic/d".
+ * @param[in] resourceType The resource type which implements the properties to
+ * observe.
+ * @param[out] handle Handle that can be used in IPCACloseHandle() to stop
+ * observing the resource.
+ * Null handle pointer is not allowed.
+ *
+ * @return IPCA_OK if successful. IPCA calls resourceChangeCallback() when device sends
+ * notifications.
+ */
+IPCAStatus IPCA_CALL IPCAObserveResource(IPCADeviceHandle deviceHandle,
+ IPCAResourceChangeCallback resourceChangeCallback,
+ void* context,
+ const char* resourcePath,
+ const char* resourceType,
+ IPCAHandle* handle);
+
+/**
+ * Stop receiving callbacks for the handle.
+ * For handle returned by IPCAObserveResource(), IPCACloseHandle unsubscribes server's resource
+ * change notification.
+ *
+ * @param[in] handle Handle returned in the following methods:
+ * IPCAGetProperties()
+ * IPCASetProperties()
+ * IPCAObserveResource()
+ * IPCADiscoverDevices()
+ *
+ */
+void IPCA_CALL IPCACloseHandle(IPCAHandle handle);
+
+/**
+ * Perform factory reset.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ *
+ * @return IPCA_OK if successful. IPCA_PROPERTY_NOT_SUPPORTED if device does not support factory
+ * reset.
+ */
+IPCAStatus IPCA_CALL IPCAFactoryReset(IPCADeviceHandle deviceHandle);
+
+/**
+ * Perform device warm reset.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ *
+ * @return IPCA_OK if successful. IPCA_PROPERTY_NOT_SUPPORTED if device does not support reboot
+ * request.
+ */
+IPCAStatus IPCA_CALL IPCAReboot(IPCADeviceHandle deviceHandle);
+
+/**
+ * Create a handle to an IPCAPropertyBag object. Use IPCAPropertyBagDestroy() to delete the object.
+ *
+ * @param[out] propertyBagHandle Handle to an IPCAPropertyBag object.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCAPropertyBagCreate(IPCAPropertyBagHandle* propertyBagHandle);
+
+/**
+ * Delete an IPCPropertyBag object.
+ *
+ * @param[in] propertyBagHandle Handle returned in IPCAPropertyBagCreate().
+ */
+
+void IPCAPropertyBagDestroy(IPCAPropertyBagHandle propertyBagHandle);
+
+/**
+ * Get the resource path of the property bag.
+ * Use IPCAPropertyBagFreeString() to free string buffer returned in resourcePath.
+ *
+ * @param[in] propertyBagHandle IPCAPropertyBagHandle object returned by device.
+ * @param[out] resourcePath Buffer containing resource path, caller must use
+ * IPCAPropertyBagFreeString() to free the buffer.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCAPropertyBagGetResourcePath(IPCAPropertyBagHandle propertyBagHandle,
+ char** resourcePath);
+
+/**
+ * Value type of a property in a property bag.
+ */
+typedef enum
+{
+ IPCA_INTEGER = 1,
+ IPCA_DOUBLE,
+ IPCA_BOOLEAN,
+ IPCA_STRING,
+ IPCA_ARRAY,
+ IPCA_PROPERTY_BAG,
+ IPCA_VALUE_TYPE_NOT_SUPPORTED
+} IPCAValueType;
+
+/**
+ * Get the key and the value type of all the properties in a property bag.
+ * Caller must free the memory allocated for the keys and valueTypes array returned.
+ *
+ * @param[in] propertyBagHandle IPCAPropertyBagHandle object returned by device.
+ * @param[out] keys A pointer to an array of property names.
+ * @param[out] valueTypes A pointer to an array of property value types.
+ * Note: valueTypes[0] is the value type for property keys[0]
+ * and so on.
+ * @param[out] count Number of entries in keys and valueTypes array.
+ *
+ * Note:
+ * Use IPCAPropertyBagFreeStringArray() to free keys buffer.
+ * Use IPCAPropertyBagFreeIPCAValueTypeArray() to free valueTypes buffer.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCAPropertyBagGetAllKeyValuePairs(IPCAPropertyBagHandle propertyBagHandle,
+ char*** keys,
+ IPCAValueType** valueTypes,
+ size_t* count);
+
+/**
+ * Free memory allocated for IPCAValueType in IPCAPropertyBagGetAllKeyValuePairs().
+ *
+ * @param[in] valueArray Array of IPCAValueType values returned in
+ * IPCAPropertyBagGetAllKeyValuePairs().
+ */
+void IPCAPropertyBagFreeIPCAValueTypeArray(IPCAValueType* valueArray);
+
+/**
+ * Set property value.
+ *
+ * @param[in] propertyBagHandle Handle returned in IPCAPropertyBagCreate.
+ * @param[in] key The key of the key-value pair to be stored in the
+ * propertyBagHandle.
+ * @param[in] value The value of the key-value pair to be stored in propertyBagHandle.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCAPropertyBagSetValueInt(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ int value);
+
+IPCAStatus IPCAPropertyBagSetValueDouble(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ double value);
+
+IPCAStatus IPCAPropertyBagSetValueBool(IPCAPropertyBagHandle
+ propertyBagHandle,
+ const char* key,
+ bool value);
+
+IPCAStatus IPCAPropertyBagSetValueString(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const char* value);
+
+IPCAStatus IPCAPropertyBagSetValuePropertyBag(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const IPCAPropertyBagHandle value);
+
+/**
+ * Set array value.
+ *
+ * @param[in] propertyBagHandle Handle returned in IPCAPropertyBagCreate.
+ * @param[in] key The key of the key-value pair to be stored in the
+ * propertyBagHandle.
+ * @param[in] valueArray The array value of the key-value pair to be stored in
+ * propertyBagHandle.
+ * @param[in] valueCount Size of the valueArray.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCAPropertyBagSetValueIntArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const int* valueArray,
+ size_t valueCount);
+
+IPCAStatus IPCAPropertyBagSetValueDoubleArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const double* valueArray,
+ size_t valueCount);
+
+IPCAStatus IPCAPropertyBagSetValueBoolArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const bool* valueArray,
+ size_t valueCount);
+
+IPCAStatus IPCAPropertyBagSetValueStringArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const char** valueArray,
+ size_t valueCount);
+
+IPCAStatus IPCAPropertyBagSetValuePropertyBagArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const IPCAPropertyBagHandle* valueArray,
+ size_t valueCount);
+
+/**
+ * Get property value.
+ *
+ * @param[in] propertyBagHandle Handle returned in IPCAPropertyBagCreate or IPCAPropertyBagHandle
+ * object returned by device.
+ * @param[in] key The key of key-value pair of data stored in propertyBagHandle.
+ * @param[out] value The value of key-value pair of data stored in propertyBagHandle.
+ *
+ * Note:
+ *
+ * For IPCAPropertyBagGetValueString() caller must use IPCAPropertyBagFreeString() to free the
+ * string buffer returned in value argument.
+ *
+ * For IPCAPropertyBagGetValuePropertyBag(), use IPCAPropertyBagDestroy() to free the
+ * IPCAPropertyBagHandle returned in value argument.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCAPropertyBagGetValueInt(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ int* value);
+
+IPCAStatus IPCAPropertyBagGetValueDouble(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ double* value);
+
+IPCAStatus IPCAPropertyBagGetValueBool(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ bool* value);
+
+IPCAStatus IPCAPropertyBagGetValueString(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ char** value);
+
+IPCAStatus IPCAPropertyBagGetValuePropertyBag(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ IPCAPropertyBagHandle* value);
+
+/**
+ * Get array value.
+ *
+ * @param[in] propertyBagHandle Handle returned in IPCAPropertyBagCreate or IPCAPropertyBagHandle
+ * object returned by device.
+ * @param[in] key The key of the key-value pair to be stored in the
+ * propertyBagHandle.
+ * @param[out] valueArray The array value of the key-value pair to be stored in
+ * propertyBagHandle.
+ * @param[out] valueCount Size of the valueArray.
+ *
+ * Note:
+ * Use corresponding IPCAPropertyBagFreeXXXXArray()to free the array of value type returned in value
+ * buffer.
+ *
+ * @return IPCA_OK if successful.
+ */
+IPCAStatus IPCAPropertyBagGetValueIntArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ int** value,
+ size_t* valueCount);
+
+IPCAStatus IPCAPropertyBagGetValueDoubleArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ double** value,
+ size_t* valueCount);
+
+IPCAStatus IPCAPropertyBagGetValueBoolArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ bool** value,
+ size_t* valueCount);
+
+IPCAStatus IPCAPropertyBagGetValueStringArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ char*** value,
+ size_t* valueCount);
+
+IPCAStatus IPCAPropertyBagGetValuePropertyBagArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ IPCAPropertyBagHandle** value,
+ size_t* valueCount);
+
+/**
+ * Free array types.
+ */
+void IPCAPropertyBagFreeIntArray(int* valueArray);
+void IPCAPropertyBagFreeDoubleArray(double* valueArray);
+void IPCAPropertyBagFreeBoolArray(bool* valueArray);
+void IPCAPropertyBagFreeStringArray(char** valueArray, size_t valueCount);
+void IPCAPropertyBagFreePropertyBagArray(IPCAPropertyBagHandle* valueArray, size_t valueCount);
+
+/**
+ * Free stringBuffer allocated in IPCAPropertyBagGetValueString().
+ *
+ * @param[in] stringBuffer String buffer returned in IPCAPropertyBagGetValueString().
+ */
+void IPCAPropertyBagFreeString(char* stringBuffer);
+
+/**
+ * Security authentication type used during Ownership Transfer communication.
+ *
+ * Ownership Transfer is currently supported in two different cases:
+ * - Between an Onboarding Tool (OBT) and the application. The OBT becomes the owner of the
+ * application.
+ * - Between the application and a device, if the device has Multiple Owner Transfer (MOT) enabled.
+ * The application becomes one of the sub-owners of the device.
+ *
+ */
+typedef enum
+{
+ IPCA_OWNERSHIP_TRANSFER_JUST_WORKS = 0, // No authentication is required.
+
+ IPCA_OWNERSHIP_TRANSFER_RANDOM_PIN = 1, // Either:
+ // - The device displays a random password, and the
+ // user inputs the same password in the
+ // application, or:
+ // - The application displays a random password, and
+ // the user inputs the same password in an
+ // onboarding tool.
+
+ IPCA_OWNERSHIP_TRANSFER_MANUFACTURER_CERTIFICATE = 2, // Authenticate using a pre-provisioned
+ // security certificate.
+
+ IPCA_OWNERSHIP_TRANSFER_PRECONFIGURED_PIN = 0xFF00, // The device owner configures a
+ // password using an onboarding tool.
+ // Then, the application obtains the
+ // password and passes it to IPCA.
+} IPCAOwnershipTransferType;
+
+/**
+ * This callback will be called whenever a device requires that the app provide a password, in order
+ * to complete the security provisioning of the application. This will be called when a device
+ * implements the "Multiple Ownership Transfer" (MOT) method. The app is responsible for eliciting
+ * the appropriate password from the user.
+ *
+ * @param[in] context Applications's context set in IPCASetPasswordCallbacks().
+ * @param[in] deviceInformation Information about the device or onboarding tool requiring
+ * authentication.
+ * @param[in] platformInformation Information about the platform of the device or onboarding tool
+ * requiring authentication.
+ * @param[in] type The type of authentication requiring the password entry. An
+ * application might display different messages to the user,
+ * depending on the value of authenticationType.
+ * The current version of IPCA supports these values for this
+ * parameter:
+ * - IPCA_OWNERSHIP_TRANSFER_RANDOM_PIN
+ * - IPCA_OWNERSHIP_TRANSFER_PRECONFIGURED_PIN
+ * @param[out] passwordBuffer Buffer to fill with a password, as a zero-terminated string. The
+ * application can obtain the password:
+ * - Directly from the MOT-enabled device, for
+ * IPCA_OWNERSHIP_TRANSFER_RANDOM_PIN
+ * - From the owner of the MOT-enabled device, for
+ * IPCA_OWNERSHIP_TRANSFER_PRECONFIGURED_PIN
+ * @param[in] passwordBufferSize Size of passwordBuffer.
+ *
+ * @return IPCA_OK if successful. IPCA_FAIL if the app did not provide a password, or if the
+ * passwordBufferSize was too small.
+ */
+typedef IPCAStatus (IPCA_CALL *IPCAProvidePasswordCallback)(
+ void* context,
+ const IPCADeviceInfo* deviceInformation,
+ const IPCAPlatformInfo* platformInformation,
+ IPCAOwnershipTransferType type,
+ char* passwordBuffer,
+ size_t passwordBufferSize);
+
+/**
+ * Callback used to display a password in the application. The user would typically read this
+ * password and communicate it to the user of an onboarding tool.
+ *
+ * @param[in] context Applications's context set in IPCASetPasswordCallbacks().
+ * @param[in] deviceInformation Information about the device or onboarding tool requiring
+ * authentication.
+ * @param[in] platformInformation Information about the platform of the device or onboarding tool
+ * requiring authentication.
+ * @param[in] type The type of authentication that requires displaying the
+ * password.
+ * An application might display different messages to the user,
+ * depending on the value of authenticationType. The current
+ * version of IPCA supports the following value for this parameter:
+ * - IPCA_OWNERSHIP_TRANSFER_RANDOM_PIN - to authenticate with an
+ * onboarding tool.
+ * @param[in] password Password to be displayed, as a zero-terminated string.
+ *
+ * @return IPCA_OK if successful. IPCA_FAIL if the app or its user decided to cancel the
+ * authentication with the onboarding tool.
+ */
+typedef IPCAStatus (IPCA_CALL *IPCADisplayPasswordCallback)(
+ void* context,
+ const IPCADeviceInfo* deviceInformation,
+ const IPCAPlatformInfo* platformInformation,
+ IPCAOwnershipTransferType type,
+ const char* password);
+
+/**
+ * An application calls this method one time to set up its password input and display callbacks.
+ * The callbacks get automatically removed by IPCA, when the application calls IPCAClose for the
+ * ipcaAppHandle.
+ *
+ * @param[in] ipcaAppHandle: Handle returned by IPCAOpen().
+ * @param[in] providePasswordCallback: Callback from IPCA when the application must obtain a
+ * password and provide it to IPCA.
+ * @param[in] displayPasswordCallback: Callback from IPCA when the application must display a
+ * password to the user.
+ * @param[in] context: Application's context that is passed back by IPCA as
+ * argument in the password callbacks.
+ *
+ */
+IPCAStatus IPCA_CALL IPCASetPasswordCallbacks(IPCAAppHandle ipcaAppHandle,
+ IPCAProvidePasswordCallback providePasswordCallback,
+ IPCADisplayPasswordCallback displayPasswordCallback,
+ void* context);
+
+/**
+ * Callback from IPCA when a request initiated by the application using IPCARequestAccess has been
+ * completed.
+ *
+ * @param[in] completionStatus One of IPCA_SECURITY_UPDATE_REQUEST_FINISHED,
+ * IPCA_SECURITY_UPDATE_REQUEST_INCORRECT_PASSWORD,
+ * IPCA_SECURITY_UPDATE_REQUEST_NOT_SUPPORTED,
+ * IPCA_SECURITY_UPDATE_REQUEST_FAILED.
+ * @param[in] context Applications's context set in IPCARequestAccess().
+ */
+typedef void (IPCA_CALL *IPCARequestAccessCompletionCallback)(IPCAStatus completionStatus,
+ void* context);
+
+/**
+ * Initiate a request to access a device. Called by the application after IPCAGetProperties or
+ * IPCASetProperties failed with status IPCA_ACCESS_DENIED. completionCallback gets called after the
+ * access request has been processed by IPCA.
+ *
+ * @param[in] deviceHandle Device handle returned in IPCAOpenDevice().
+ * @param[in] resourcePath E.g., "/oic/d". If NULL the application requests access to all
+ * vertical resources on the device.
+ * @param[in] completionCallback Callback from IPCA when access request has been completed.
+ * @param[in] context Application's context that is passed back as argument in the
+ * completion callback.
+ * @param[out] handle Handle that can be used in IPCACloseHandle() to cancel the
+ * request.
+ * The reference count to the handle is handled by IPCA. Therefore,
+ * the caller does not need to close the handle. Null handle
+ * pointer is allowed when the caller does not plan to cancel the
+ * request.
+ * @return
+ * IPCA_OK if the request has been successfully initiated.
+ */
+IPCAStatus IPCA_CALL IPCARequestAccess(IPCADeviceHandle deviceHandle,
+ const char* resourcePath,
+ IPCARequestAccessCompletionCallback completionCallback,
+ void* context,
+ IPCAHandle* handle);
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif // IPCA_H_
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include <mutex>
+#include <array>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <map>
+#include <thread>
+#include <chrono>
+#include <condition_variable>
+
+#include "ipca.h"
+#include "OCFDevice.h"
+
+#if defined(_MSC_VER)
+#define UNREFERENCED_PARAMETER(P) (P)
+#else
+#define UNREFERENCED_PARAMETER(P)
+#endif
+
+// Forward decls.
+extern bool RediscoverElevator();
+extern void ResourceChangeNotificationCallback(IPCAStatus result, void* context,
+ IPCAPropertyBagHandle propertyBagHandle);
+
+// Key is device id. Value is pointer to OCFDevice.
+std::map<std::string, OCFDevice::Ptr> g_OCFDeviceList;
+std::recursive_mutex g_globalMutex; // Sync access to g_OCFDeviceList.
+
+// Command line arguments
+std::string g_targetDeviceId;
+bool g_isList = false;
+bool g_isId = false;
+bool g_isSet = false;
+bool g_isGet = false;
+bool g_isObserve = false;
+bool g_isAuth = false;
+int g_targetFloor = 0;
+bool g_isContinuous = false;
+
+// Handles
+IPCADeviceHandle g_deviceHandle = nullptr;
+IPCAHandle g_observeHandle = nullptr;
+IPCAAppHandle g_ipcaAppHandle = nullptr;
+
+// Operation flags
+bool g_targetElevatorDiscovered = false; // Set to true when device matching g_targetDeviceId is
+ // discovered.
+bool g_rediscoverFailedQuitNow = false;
+
+// Call IPCAObserveResource();
+IPCAStatus RequestObserve()
+{
+ if (g_observeHandle != nullptr)
+ {
+ IPCACloseHandle(g_observeHandle);
+ g_observeHandle = nullptr;
+ }
+
+ return IPCAObserveResource(
+ g_deviceHandle,
+ &ResourceChangeNotificationCallback,
+ 0,
+ "/ipca/sample/elevator",
+ nullptr,
+ &g_observeHandle);
+}
+
+// Callback from IPCAObserveResource().
+void ResourceChangeNotificationCallback(IPCAStatus result, void* context,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ UNREFERENCED_PARAMETER(context);
+
+ int observedCurrentFloor = -1, observedDirection = -1, observedTargetFloor = -1;
+
+ if (result != IPCA_OK)
+ {
+ std::cout << "!!! ResourceChangeNotificationCallback callback !!! error: " << result
+ << std::endl;
+
+ RediscoverElevator();
+ if (g_rediscoverFailedQuitNow != true)
+ {
+ // Restart the observe request.
+ RequestObserve();
+ }
+
+ return;
+ }
+
+ if (IPCA_OK != IPCAPropertyBagGetValueInt(propertyBagHandle,
+ "x.org.iotivity.CurrentFloor",
+ &observedCurrentFloor))
+ {
+ std::cout << "ResourceChangeNotificationCallback(): failed get CurrentFloor." << std::endl;
+ }
+
+ if (IPCA_OK != IPCAPropertyBagGetValueInt(propertyBagHandle,
+ "x.org.iotivity.Direction",
+ &observedDirection))
+ {
+ std::cout << "ResourceChangeNotificationCallback(): failed get Direction." << std::endl;
+ }
+
+ if (IPCA_OK != IPCAPropertyBagGetValueInt(propertyBagHandle,
+ "x.org.iotivity.TargetFloor",
+ &observedTargetFloor))
+ {
+ std::cout << "ResourceChangeNotificationCallback(): failed get TargetFloor." << std::endl;
+ }
+
+ std::cout << "Resource Change Notification: " << std::endl;
+ std::cout << " CurrentFloor: " << observedCurrentFloor;
+ std::cout << " Direction: " << observedDirection;
+ std::cout << " TargetFloor: " << observedTargetFloor << std::endl;
+}
+
+// IPCAGetProperties() completion callback.
+std::mutex g_getPropertiesCbMutex;
+std::condition_variable g_getPropertiesCompleteCV;
+
+void GetPropertiesCallback(IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ UNREFERENCED_PARAMETER(context);
+
+ int currentFloor = 0, direction = 0, targetFloor = 0;
+
+ if (result != IPCA_OK)
+ {
+ std::cout << "!!! GetProperties callback !!! error: " << result << std::endl;
+ RediscoverElevator();
+ g_getPropertiesCompleteCV.notify_all();
+ return;
+ }
+
+ if (propertyBagHandle != nullptr)
+ {
+ if (IPCA_OK != IPCAPropertyBagGetValueInt(propertyBagHandle,
+ "x.org.iotivity.CurrentFloor",
+ ¤tFloor))
+ {
+ std::cout << "GetPropertiesCallback(): failed get CurrentFloor." << std::endl;
+ }
+
+ if (IPCA_OK != IPCAPropertyBagGetValueInt(propertyBagHandle,
+ "x.org.iotivity.Direction",
+ &direction))
+ {
+ std::cout << "GetPropertiesCallback(): failed get Direction." << std::endl;
+ }
+
+ if (IPCA_OK != IPCAPropertyBagGetValueInt(propertyBagHandle,
+ "x.org.iotivity.TargetFloor",
+ &targetFloor))
+ {
+ std::cout << "GetPropertiesCallback(): failed get TargetFloor." << std::endl;
+ }
+ }
+
+ std::cout << "*** GetProperties callback: successful ***" << std::endl;
+ std::cout << "Current Floor : " << currentFloor << std::endl;
+ std::cout << "Direction : " << direction << std::endl;
+ std::cout << "TargetFloor : " << targetFloor << std::endl;
+
+ g_getPropertiesCompleteCV.notify_all();
+}
+
+// IPCASetProperties() completion callback.
+std::mutex g_setPropertiesCbMutex;
+std::condition_variable g_setPropertiesCompleteCV;
+void SetPropertiesCallback(IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ UNREFERENCED_PARAMETER(context);
+ UNREFERENCED_PARAMETER(propertyBagHandle);
+
+ if (result == IPCA_OK)
+ {
+ std::cout << "*** SetProperties callback: successful ***" << std::endl;
+ }
+ else
+ {
+ std::cout << "!!! SetProperties callback !!! error: " << result << std::endl;
+ RediscoverElevator();
+ }
+
+ g_setPropertiesCompleteCV.notify_all();
+}
+
+// Callback when device is discovered.
+std::mutex g_deviceDiscoveredCbMutex;
+std::condition_variable g_deviceDiscoveredCV;
+void DiscoverDevicesCallback(void* context,
+ IPCADeviceStatus deviceStatus,
+ const IPCADiscoveredDeviceInfo* deviceInfo)
+{
+ UNREFERENCED_PARAMETER(context);
+
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);
+
+ std::string deviceId = deviceInfo->deviceId;
+ std::string deviceName = deviceInfo->deviceName;
+ std::vector<std::string> deviceUris;
+ for (int i = 0; i < deviceInfo->deviceUriCount; i++)
+ {
+ deviceUris.push_back(deviceInfo->deviceUris[i]);
+ }
+
+ if (g_OCFDeviceList.find(deviceId) == g_OCFDeviceList.end())
+ {
+ OCFDevice::Ptr ocfDevice = std::shared_ptr<OCFDevice>(new
+ OCFDevice(g_ipcaAppHandle, deviceId));
+ if (ocfDevice == nullptr)
+ {
+ std::cout << "Out of memory" << std::endl;
+ return;
+ }
+ g_OCFDeviceList[deviceId] = ocfDevice;
+ }
+
+ OCFDevice::Ptr ocfDevice = g_OCFDeviceList[deviceId];
+
+ // Wake up any thread waiting for discovery of this device.
+ if ((!g_targetElevatorDiscovered) &&
+ (g_targetDeviceId.length() != 0) &&
+ (g_targetDeviceId.compare(deviceId) == 0))
+ {
+ g_targetElevatorDiscovered = true;
+ g_deviceDiscoveredCV.notify_all();
+ }
+
+ if (g_isList)
+ {
+ if (deviceStatus == IPCA_DEVICE_DISCOVERED)
+ {
+ std::cout << "*** New elevator: *** " << std::endl << std::endl;
+ }
+ else
+ if (deviceStatus == IPCA_DEVICE_UPDATED_INFO)
+ {
+ std::cout << "+++ Elevator info updated for id: [" << deviceId << "] +++";
+ std::cout << std::endl << std::endl;
+ }
+ else
+ {
+ std::cout << "--- Elevator is no longer discoverable. Device ID: [";
+ std::cout << deviceId << "] ---" << std::endl << std::endl;
+ g_OCFDeviceList.erase(deviceId);
+ return;
+ }
+
+ IPCADeviceInfo* di = ocfDevice->GetDeviceInfo();
+
+ if (di != nullptr)
+ {
+ std::cout << "Device Info: " << std::endl;
+ std::cout << std::endl;
+ if (deviceUris.size() != 0)
+ {
+ int i = 0;
+ for (auto& uri : deviceUris)
+ {
+ if (i++ == 0)
+ {
+
+ std::cout << " Device URI . . . . . . . : " << uri << std::endl;
+ }
+ else
+ {
+ std::cout << " " << uri << std::endl;
+ }
+ }
+ }
+
+ std::cout << " Device ID . . . . . . . : " << (di->deviceId ? di->deviceId : "");
+ std::cout << std::endl;
+
+ std::cout << " Device Name . . . . . . : ";
+ std::cout << (di ->deviceName ? di->deviceName : "") << std::endl;
+
+ std::cout << " Device Software Version : ";
+ std::cout << (di->deviceSoftwareVersion ? di->deviceSoftwareVersion : "") << std::endl;
+ std::cout << std::endl;
+
+ }
+ else
+ {
+ std::cout << "Device Info: Not available." << std::endl << std::endl;
+ }
+
+ IPCAPlatformInfo* pi = ocfDevice->GetPlatformInfo();
+
+ if (pi != nullptr)
+ {
+ std::cout << "Platform Info:" << std::endl;
+ std::cout << std::endl;
+
+ std::cout << " Plaform ID . . . . . . . : ";
+ std::cout << (pi->platformId ? pi->platformId : "") << std::endl;
+
+ std::cout << " Manufacturer Name . . . : ";
+ std::cout << (pi->manufacturerName ? pi->manufacturerName : "") << std::endl;
+
+ std::cout << " Manufacturer URL . . . . : ";
+ std::cout << (pi->manufacturerURL ? pi->manufacturerURL : "") << std::endl;
+
+ std::cout << " Model Number . . . . . . : ";
+ std::cout << (pi->modelNumber ? pi->modelNumber : "") << std::endl;
+
+ std::cout << " Manufacturing Date . . . : ";
+ std::cout << (pi->manufacturingDate ? pi->manufacturingDate : "") << std::endl;
+
+ std::cout << " Platform Version . . . . : ";
+ std::cout << (pi->platformVersion ? pi->platformVersion : "") << std::endl;
+
+ std::cout << " OS Version . . . . . . . : ";
+ std::cout << (pi->osVersion ? pi->osVersion : "") << std::endl;
+
+ std::cout << " Hardware Version . . . . : ";
+ std::cout << (pi->hardwareVersion ? pi->hardwareVersion : "") << std::endl;
+
+ std::cout << " Firmware Version . . . . : ";
+ std::cout << (pi->firmwareVersion ? pi->firmwareVersion : "") << std::endl;
+
+ std::cout << " Manufacturer Support URL : ";
+ std::cout << (pi->manufacturerSupportURL ? pi->manufacturerSupportURL : "");
+ std::cout << std::endl;
+
+ std::cout << " Reference Time . . . . . : ";
+ std::cout << (pi->referenceTime ? pi->referenceTime : "") << std::endl;
+ std::cout << std::endl;
+ }
+ else
+ {
+ std::cout << "Platform info: Not available. " << std::endl << std::endl;
+ }
+
+ std::cout << "Resource List:" << std::endl;
+ ResourceList resourceList = ocfDevice->GetResourceInfo();
+ for (auto const& resource : resourceList)
+ {
+ bool firstEntry = true;
+ std::cout << " Resource URI . . . . . : " << resource.first << std::endl;
+ std::cout << " Resource Types . . . : ";
+ for (auto const& resourceType : resource.second)
+ {
+ if (firstEntry == true)
+ {
+ std::cout << resourceType << std::endl;
+ firstEntry = false;
+ }
+ else
+ {
+ std::cout << " " << resourceType << std::endl;
+ }
+ }
+ std::cout << std::endl;
+ }
+ std::cout << std::endl;
+ std::cout << "[Press enter to exit discovery]"<< std::endl << std::endl;
+ }
+}
+
+void ShowUsage()
+{
+ std::cout << std::endl;
+ std::cout << "USAGE: elevatorclient [-l] [-id elevator_id] [-s target_floor] [-g] [-o]";
+ std::cout << std::endl;
+ std::cout << std::endl;
+ std::cout << "Options" << std::endl;
+ std::cout << " -l Discover and list elevators." << std::endl;
+ std::cout << " -id Device ID of elevator, must be set for -s, -g, and -o arguments.";
+ std::cout << std::endl;
+ std::cout << " -auth Authenticate to device." << std::endl;
+ std::cout << " -s target_floor Set target floor." << std::endl;
+ std::cout << " -g Get current floor." << std::endl;
+ std::cout << " -o Observe." << std::endl;
+ std::cout << " -cont Run continuous -g or -s with increasing target floor";
+ std::cout << std::endl;
+}
+
+bool ParseArgv(int argc, char* argv[])
+{
+ const std::string ListArgument = "-l";
+ const std::string IdArgument = "-id";
+ const std::string SetArgument = "-s";
+ const std::string GetArgument = "-g";
+ const std::string ObserveArgument = "-o";
+ const std::string ContinuousArgument = "-cont";
+ const std::string AuthenticateToDeviceArgument = "-auth";
+
+ for (int i = 1 ; i < argc; i++)
+ {
+ if (ListArgument.compare(argv[i]) == 0)
+ {
+ g_isList = true;
+ continue;
+ }
+
+ if (GetArgument.compare(argv[i]) == 0)
+ {
+ g_isGet = true;
+ continue;
+ }
+
+ if (ObserveArgument.compare(argv[i]) == 0)
+ {
+ g_isObserve = true;
+ continue;
+ }
+
+ if (ContinuousArgument.compare(argv[i]) == 0)
+ {
+ g_isContinuous = true;
+ continue;
+ }
+
+ if (IdArgument.compare(argv[i]) == 0)
+ {
+ if (++i == argc)
+ {
+ return false;
+ }
+
+ g_targetDeviceId = argv[i];
+ g_isId = true;
+ continue;
+ }
+
+ if (SetArgument.compare(argv[i]) == 0)
+ {
+ if (++i == argc)
+ {
+ return false;
+ }
+
+ g_targetFloor = std::stoi(argv[i]);
+ g_isSet = true;
+ continue;
+ }
+
+ if (AuthenticateToDeviceArgument.compare(argv[i]) == 0)
+ {
+ g_isAuth = true;
+ continue;
+ }
+ }
+
+ return true;
+}
+
+void CloseDeviceTargetElevator()
+{
+ if (g_deviceHandle != nullptr)
+ {
+ IPCACloseDevice(g_deviceHandle);
+ g_deviceHandle = nullptr;
+ }
+}
+
+bool OpenDeviceTargetElevator()
+{
+ if (g_deviceHandle != nullptr)
+ {
+ CloseDeviceTargetElevator();
+ }
+
+ IPCAStatus status = IPCAOpenDevice(g_ipcaAppHandle, g_targetDeviceId.c_str(), &g_deviceHandle);
+ if (status != IPCA_OK)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+IPCAHandle g_discoverDeviceHandle;
+
+// Synchronous call to discovery device.
+// If not free run, Function waits for timeOut milliseconds and stops when function exits.
+bool DiscoverElevator(bool freeRun, size_t timeOutMs)
+{
+ std::unique_lock<std::mutex> lock { g_deviceDiscoveredCbMutex };
+
+ char* resourceTypes[] = {
+ "x.org.iotivity.sample.elevator",
+ "x.org.iotivity.sample.elevator2",
+ "x.org.iotivity.sample.elevator3",
+ "x.org.iotivity.sample.elevator4",
+ };
+
+ const int NUMBER_OF_RESOURCE_TYPES = sizeof(resourceTypes) / sizeof(char*);
+
+ IPCAStatus status = IPCADiscoverDevices(
+ g_ipcaAppHandle,
+ &DiscoverDevicesCallback,
+ nullptr,
+ resourceTypes,
+ NUMBER_OF_RESOURCE_TYPES,
+ &g_discoverDeviceHandle);
+
+ if (status != IPCA_OK)
+ {
+ return false;
+ }
+
+ if (!freeRun)
+ {
+ g_deviceDiscoveredCV.wait_for(lock, std::chrono::milliseconds{ timeOutMs });
+
+ // Stop discovery.
+ IPCACloseHandle(g_discoverDeviceHandle);
+ }
+
+ return g_targetElevatorDiscovered;
+}
+
+bool RediscoverElevator()
+{
+ g_targetElevatorDiscovered = false;
+
+ CloseDeviceTargetElevator();
+
+ std::cout << "Rediscovering elevator..." << std::endl;
+
+ if (false == DiscoverElevator(false, INT_MAX) || false == OpenDeviceTargetElevator())
+ {
+ std::cout << "Failed to rediscover elevator! " << std::endl;
+ g_rediscoverFailedQuitNow = true;
+ return false;
+ }
+
+ std::cout << "Elevator rediscovered." << std::endl;
+ return true;
+}
+
+IPCAStatus PwdInputCallback(
+ void* context,
+ const IPCADeviceInfo* deviceInformation,
+ const IPCAPlatformInfo* platformInformation,
+ IPCAOwnershipTransferType type,
+ char* passwordBuffer,
+ size_t passwordBufferSize)
+{
+ UNREFERENCED_PARAMETER(passwordBufferSize);
+ UNREFERENCED_PARAMETER(type);
+ UNREFERENCED_PARAMETER(platformInformation);
+ UNREFERENCED_PARAMETER(deviceInformation);
+ UNREFERENCED_PARAMETER(context);
+
+ std::cout << "Received Password Input Callback" << std::endl;
+
+ std::cout << "Input password: ";
+
+ for (int ret = 0; 1 != ret; )
+ {
+ ret = scanf("%32s", passwordBuffer);
+ for (; 0x20 <= getchar(); ); // for removing overflow garbages
+ // '0x20<=code' is character region
+ }
+
+ std::cout << std::endl;
+
+ return IPCA_OK;
+}
+
+IPCAStatus PwdDisplayCallback(
+ void* context,
+ const IPCADeviceInfo* deviceInformation,
+ const IPCAPlatformInfo* platformInformation,
+ IPCAOwnershipTransferType type,
+ const char* password)
+{
+ UNREFERENCED_PARAMETER(context);
+ UNREFERENCED_PARAMETER(deviceInformation);
+ UNREFERENCED_PARAMETER(platformInformation);
+ UNREFERENCED_PARAMETER(type);
+
+
+ std::cout << "==========================================" << std::endl;
+
+ std::cout << "Password for device: " << password << std::endl;
+
+ std::cout << "==========================================" << std::endl;
+
+ return IPCA_OK;
+}
+
+void AuthCompletionCallback(IPCAStatus completionStatus, void* context)
+{
+ UNREFERENCED_PARAMETER(context);
+ std::cout << "AuthCompletionCallback(). Completion status is: " << completionStatus;
+ std::cout << std::endl;
+}
+
+int main(int argc, char* argv[])
+{
+ if ((argc == 1) || (ParseArgv(argc, argv) == false))
+ {
+ ShowUsage();
+ return 0;
+ }
+
+ IPCAUuid appId = {0xb6, 0x12, 0x38, 0x0c, 0x8c, 0x4c, 0x11, 0xe6,
+ 0xae, 0x22, 0x56, 0xb6, 0xb6, 0x49, 0x96, 0x11};
+
+ IPCAAppInfo ipcaAppInfo = { appId, "ElevatorClient", "1.0.0", "Microsoft" };
+
+ IPCAStatus status = IPCAOpen(&ipcaAppInfo, IPCA_VERSION_1, &g_ipcaAppHandle);
+ if (status != IPCA_OK)
+ {
+ std::cout << "Failed IPCAOpen(). Status: " << status << std::endl;
+ goto exit;
+ }
+
+ status = IPCASetPasswordCallbacks(g_ipcaAppHandle,
+ &PwdInputCallback,
+ &PwdDisplayCallback,
+ nullptr);
+
+ if (status != IPCA_OK)
+ {
+ std::cout << "Failed IPCASetPasswordCallbacks(). Status: " << status << std::endl;
+ goto exit;
+ }
+
+ // List discovered elevators.
+ if (g_isList)
+ {
+ DiscoverElevator(true, 0);
+ std::cin.get();
+ goto exit;
+ }
+
+ // Other than "-l" option, device ID is required.
+ if (!g_isId)
+ {
+ std::cout << "Error, device ID is required." << std::endl;
+ ShowUsage();
+ goto exit;
+ }
+
+ // Wait for discovery of target elevator.
+ if (false == DiscoverElevator(false, 3000))
+ {
+ std::cout << "Target elevator was not discovered." << std::endl;
+ goto exit;
+ }
+
+ // Open target elevator.
+ if (false == OpenDeviceTargetElevator())
+ {
+ std:: cout << "Error opening target elevator" << std::endl;
+ goto exit;
+ }
+
+ // Get target elevator data.
+ if (g_isGet)
+ {
+ std::unique_lock<std::mutex> lock { g_getPropertiesCbMutex };
+ int loopCount = (g_isContinuous == true) ? INT_MAX : 1;
+
+ for (int i = 0; i < loopCount; i++)
+ {
+ std::cout << "Calling IPCAGetProperties().. (" << i << ")" << std::endl;
+ IPCAStatus getStatus = IPCAGetProperties(g_deviceHandle,
+ &GetPropertiesCallback,
+ 0,
+ "/ipca/sample/elevator",
+ nullptr,
+ nullptr,
+ nullptr);
+ if (IPCA_OK == getStatus)
+ {
+ g_getPropertiesCompleteCV.wait_for(lock, std::chrono::milliseconds{ INT_MAX });
+ }
+ if (g_rediscoverFailedQuitNow)
+ {
+ break;
+ }
+ }
+ goto exit;
+ }
+
+ // Set target elevator's TargetFloor.
+ if (g_isSet)
+ {
+ std::unique_lock<std::mutex> lock { g_setPropertiesCbMutex };
+ int loopCount = g_isContinuous == true ? INT_MAX : 1;
+ int targetFloor = g_targetFloor;
+
+ for (int i = 0; i < loopCount; i++)
+ {
+ std::cout << "Calling IPCASetProperties() to target floor: ";
+ std::cout << targetFloor << " (" << i << ")" << std::endl;
+
+ IPCAPropertyBagHandle propertyBagHandle;
+ status = IPCAPropertyBagCreate(&propertyBagHandle);
+ if (IPCA_OK == status)
+ {
+ status = IPCAPropertyBagSetValueInt(propertyBagHandle,
+ "x.org.iotivity.TargetFloor",
+ targetFloor++);
+
+ if (IPCA_OK == status)
+ {
+ status = IPCASetProperties(g_deviceHandle,
+ &SetPropertiesCallback,
+ 0,
+ "/ipca/sample/elevator",
+ "x.org.iotivity.sample.elevator",
+ nullptr,
+ propertyBagHandle,
+ nullptr);
+
+ if (IPCA_OK == status)
+ {
+ g_setPropertiesCompleteCV.wait_for(
+ lock, std::chrono::milliseconds{ INT_MAX });
+ }
+ }
+ IPCAPropertyBagDestroy(propertyBagHandle);
+ }
+
+ if (g_rediscoverFailedQuitNow)
+ {
+ break;
+ }
+ }
+ goto exit;
+ }
+
+ // Register for observation.
+ if (g_isObserve)
+ {
+ RequestObserve();
+ std::cout << "any key and enter to exit.." << std::endl;
+ std::cin.get();
+ goto exit;
+ }
+
+ // Authenticate to a device (i.e. MOT).
+ if (g_isAuth)
+ {
+ IPCARequestAccess(g_deviceHandle, nullptr, AuthCompletionCallback, nullptr, nullptr);
+ std::cout << "Authenticating to device. Use ctrl-c to quit when authentication is complete.";
+ std::cout << std::endl;
+ std::this_thread::sleep_for(std::chrono::seconds(1000));
+ }
+
+exit:
+ CloseDeviceTargetElevator();
+ g_OCFDeviceList.clear();
+
+ if (g_ipcaAppHandle != nullptr)
+ {
+ IPCAClose(g_ipcaAppHandle);
+ }
+
+ return 0;
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include <string>
+#include <iostream>
+#include "ipca.h"
+#include "OCFDevice.h"
+
+OCFDevice::OCFDevice(IPCAAppHandle appHandle, std::string id) :
+ m_ipcaAppHandle(appHandle),
+ m_deviceId(id),
+ m_deviceHandle(nullptr),
+ m_deviceInfo(nullptr),
+ m_platformInfo(nullptr)
+{
+}
+
+OCFDevice::~OCFDevice()
+{
+ if (m_deviceHandle != nullptr)
+ {
+ IPCACloseDevice(m_deviceHandle);
+ }
+
+ if (m_deviceInfo != nullptr)
+ {
+ IPCAFreeDeviceInfo(m_deviceInfo);
+ }
+
+ if (m_platformInfo != nullptr)
+ {
+ IPCAFreePlatformInfo(m_platformInfo);
+ }
+}
+
+IPCAStatus OCFDevice::OpenDevice()
+{
+ if (m_deviceHandle != nullptr)
+ {
+ return IPCA_OK;
+ }
+ else
+ {
+ return IPCAOpenDevice(m_ipcaAppHandle, m_deviceId.c_str(), &m_deviceHandle);
+ }
+}
+
+IPCADeviceInfo* OCFDevice::GetDeviceInfo()
+{
+ IPCAStatus status;
+
+ if (m_deviceInfo != nullptr)
+ {
+ return m_deviceInfo;
+ }
+
+ if (OpenDevice() != IPCA_OK)
+ {
+ return nullptr;
+ }
+
+ status = IPCAGetDeviceInfo(m_deviceHandle, &m_deviceInfo);
+
+ if (IPCA_OK != status)
+ {
+ return nullptr;
+ }
+
+ return m_deviceInfo;
+}
+
+IPCAPlatformInfo* OCFDevice::GetPlatformInfo()
+{
+ IPCAStatus status;
+
+ if (m_platformInfo != nullptr)
+ {
+ return m_platformInfo;
+ }
+
+ if (OpenDevice() != IPCA_OK)
+ {
+ return nullptr;
+ }
+
+ status = IPCAGetPlatformInfo(m_deviceHandle, &m_platformInfo);
+
+ if (IPCA_OK != status)
+ {
+ return nullptr;
+ }
+
+ return m_platformInfo;
+}
+
+ResourceList OCFDevice::GetResourceInfo()
+{
+ IPCAStatus status;
+
+ ResourceList emptyResourceList;
+ if (OpenDevice() != IPCA_OK)
+ {
+ return emptyResourceList;
+ }
+
+ char** resourcePathList;
+ size_t resourceListCount;
+ status = IPCAGetResources(m_deviceHandle,
+ nullptr, nullptr, &resourcePathList, &resourceListCount);
+ if (IPCA_OK != status)
+ {
+ return emptyResourceList;
+ }
+
+ m_resourceList.clear();
+ size_t i;
+ for (i = 0 ; i < resourceListCount ; i++)
+ {
+ char** resourceTypes;
+ size_t resourceTypeCount;
+ status = IPCAGetResourceTypes(m_deviceHandle,
+ resourcePathList[i], &resourceTypes, &resourceTypeCount);
+ if (IPCA_OK == status)
+ {
+ int j;
+ for (j = 0 ; j < resourceTypeCount; j++)
+ {
+ m_resourceList[resourcePathList[i]].push_back(resourceTypes[j]);
+ }
+ IPCAFreeStringArray(resourceTypes, resourceTypeCount);
+ }
+ else
+ {
+ std::cout << "Failed IPCAGetResourceTypes() for resource: " << resourcePathList[i];
+ std::cout << std::endl;
+ }
+ }
+
+ IPCAFreeStringArray(resourcePathList, resourceListCount);
+ return m_resourceList;
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include <mutex>
+#include <array>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <map>
+#include <thread>
+#include <chrono>
+#include <memory>
+#include <functional>
+
+#include "ipca.h"
+
+// Key of map is resource path. Value is array of resource types.
+typedef std::map<std::string, std::vector<std::string>> ResourceList;
+
+/**
+ * Each OCFDevice object represents a device discovered by IPCA.
+ */
+class OCFDevice
+{
+public:
+ typedef std::shared_ptr<OCFDevice> Ptr;
+ OCFDevice(IPCAAppHandle appHandle, std::string id);
+ ~OCFDevice();
+ IPCADeviceInfo* GetDeviceInfo();
+ IPCAPlatformInfo* GetPlatformInfo();
+ ResourceList GetResourceInfo();
+
+private:
+ IPCAStatus OpenDevice();
+
+private:
+ IPCAAppHandle m_ipcaAppHandle;
+ std::string m_deviceId;
+ std::string m_hostAddress;
+ IPCADeviceHandle m_deviceHandle; // from IPCAOpenDevice();
+ IPCADeviceInfo* m_deviceInfo; // valid between IPCAOpenDevice() and IPCACloseDevice().
+ IPCAPlatformInfo* m_platformInfo; // valid between IPCAOpenDevice() and IPCACloseDevice().
+ ResourceList m_resourceList;
+};
--- /dev/null
+#******************************************************************
+#
+# Copyright 2017 Microsoft
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+##
+# ElevatorClient (application) build script
+##
+Import('ipca_env')
+target_os = ipca_env.get('TARGET_OS')
+elevator_client_env = ipca_env.Clone()
+
+######################################################################
+# Build flags
+######################################################################
+elevator_client_env.PrependUnique(CPPPATH = [
+ '..\..\inc',
+ ])
+
+elevator_client_env.PrependUnique(LIBS = ['ipca'])
+
+elevator_client_src = [
+ 'ElevatorClient.cpp',
+ 'OCFDevice.cpp'
+ ]
+######################################################################
+# Source files and Targets
+######################################################################
+ipcapp = elevator_client_env.Program('elevatorclient', elevator_client_src)
\ No newline at end of file
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "ipca.h"
+#include "elevatorserver.h"
+
+ElevatorServer g_testElevator;
+
+int main()
+{
+ std::string elevatorName = "Standalone Test Elevator";
+ g_testElevator.Start(elevatorName);
+
+ std::cout << "enter any key and press enter to exit" << std::endl;
+ int userInput;
+ std::cin >> userInput;
+
+ g_testElevator.Stop();
+}
--- /dev/null
+{
+ "acl": {
+ "aclist": {
+ "aces": [
+ {
+ "subjectuuid": "*",
+ "resources": [
+ {
+ "href": "/oic/res",
+ "rel": "",
+ "rt": ["oic.wk.res"],
+ "if": ["oic.if.ll"]
+ },{
+ "href": "/oic/d",
+ "rel": "",
+ "rt": ["oic.wk.d"],
+ "if": ["oic.if.baseline", "oic.if.r"]
+ },{
+ "href": "/oic/p",
+ "rel": "",
+ "rt": ["oic.wk.p"],
+ "if": ["oic.if.baseline", "oic.if.r"]
+ }
+ ],
+ "permission": 2
+ },
+ {
+ "subjectuuid": "*",
+ "resources": [
+ {
+ "href": "/oic/sec/doxm",
+ "rel": "",
+ "rt": ["oic.r.doxm"],
+ "if": ["oic.if.baseline"]
+ },
+ {
+ "href": "/oic/sec/pstat",
+ "rel": "",
+ "rt": ["oic.r.pstat"],
+ "if": ["oic.if.baseline"]
+ },
+ {
+ "href": "/oic/sec/cred",
+ "rel": "",
+ "rt": ["oic.r.cred"],
+ "if": ["oic.if.baseline"]
+ }
+ ],
+ "permission": 6
+ }
+ ]
+ },
+ "rowneruuid" : "E068A3E6-90EF-4A26-A75F-9B098D43F54D"
+ },
+ "pstat": {
+ "isop": false,
+ "deviceuuid": "E068A3E6-90EF-4A26-A75F-9B098D43F54D",
+ "rowneruuid": "E068A3E6-90EF-4A26-A75F-9B098D43F54D",
+ "cm": 2,
+ "tm": 0,
+ "om": 4,
+ "sm": 4
+ },
+ "doxm": {
+ "oxms": [0,1,65280],
+ "oxmsel": 0,
+ "sct": 1,
+ "owned": false,
+ "deviceuuid": "E068A3E6-90EF-4A26-A75F-9B098D43F54D",
+ "devowneruuid": "",
+ "rowneruuid": "E068A3E6-90EF-4A26-A75F-9B098D43F54D"
+ }
+}
--- /dev/null
+#******************************************************************
+#
+# Copyright 2017 Microsoft
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+import os
+import os.path
+
+##
+# ElevatorServer build script
+##
+Import('ipca_env')
+target_os = ipca_env.get('TARGET_OS')
+elevator_server_env = ipca_env.Clone()
+rd_mode = elevator_server_env.get('RD_MODE')
+
+######################################################################
+# Build flags
+######################################################################
+elevator_server_env.PrependUnique(CPPPATH = [
+ '#/resource/include',
+ '#/resource/oc_logger/include',
+ '#/resource/csdk/include',
+ '#/resource/csdk/stack/include',
+ '#/resource/csdk/security/include',
+ '#/resource/csdk/security/provisioning/include',
+ '#/resource/csdk/security/provisioning/include/internal',
+ '#/resource/csdk/connectivity/api',
+ '#/resource/csdk/connectivity/external/inc',
+ '#/resource/csdk/ocsocket/include',
+ '#/resource/c_common/ocrandom/include',
+ '#/resource/csdk/logger/include',
+ '#/extlibs/boost/boost',
+ '../../inc'
+ ])
+
+elevator_server_env.AppendUnique(LIBPATH = [ipca_env.get('BUILD_DIR')])
+elevator_server_env.PrependUnique(LIBS = [
+ 'oc',
+ 'connectivity_abstraction',
+ 'coap',
+ 'octbstack',
+ 'oc_logger',
+ ])
+
+if elevator_server_env.get('SECURED') == '1':
+ elevator_server_env.AppendUnique(CPPDEFINES = ['SECURED'])
+ elevator_server_env.AppendUnique(LIBS = ['mbedtls', 'mbedx509','mbedcrypto', 'ocprovision'])
+
+if target_os in ['msys_nt', 'windows']:
+ elevator_server_env.AppendUnique(LINKFLAGS = ['/subsystem:CONSOLE'])
+
+if 'CLIENT' in rd_mode or 'SERVER' in rd_mode:
+ elevator_server_env.PrependUnique(LIBS = ['resource_directory'])
+
+######################################################################
+# Source files and Targets
+######################################################################
+elevator_server_src = [
+ 'ElevatorServerSample.cpp',
+ 'elevatorserver.cpp'
+ ]
+
+elevator_server_src_dir = os.path.join(elevator_server_env.get('SRC_DIR'),
+ 'resource', 'ipca', 'samples', 'ElevatorServer') + os.sep
+elevator_server_build_dir = os.path.join(elevator_server_env.get('BUILD_DIR'),
+ 'resource', 'ipca', 'samples', 'ElevatorServer') + os.sep
+
+elevator_server_env.Install(elevator_server_build_dir,
+ elevator_server_src_dir + 'ElevatorServerSecurityDB.json')
+elevator_server_env.Install(elevator_server_build_dir,
+ elevator_server_src_dir + 'ElevatorServerSecurityDB.dat')
+
+elevator_app = elevator_server_env.Program('ElevatorServer', elevator_server_src)
\ No newline at end of file
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "logger.h"
+#include "ElevatorServer.h"
+
+using namespace OC;
+using namespace std::placeholders;
+
+#define TAG "ElevatorServer.cpp"
+
+// Secure Virtual Resource database for Iotivity Server
+// It contains Server's Identity and the PSK credentials
+// of other devices which the server trusts
+static char CredFile[] = "ElevatorServerSecurityDB.dat";
+
+FILE* server_fopen(const char *path, const char *mode)
+{
+ (void)path;
+ return fopen(CredFile, mode);
+}
+
+//
+// class ElevatorServer implementation.
+//
+ElevatorServer::ElevatorServer() :
+ engineThread(),
+ m_elevatorResourceHandle(nullptr),
+ m_elevatorResourceHandle2(nullptr),
+ m_elevatorResourceHandle3(nullptr),
+ m_elevatorResourceHandle4(nullptr),
+ m_targetFloor(1),
+ m_currentFloor(1),
+ m_direction(ElevatorDirection::Stopped)
+{
+#ifdef SECURED
+ m_displayPasswordCallbackHandle = nullptr;
+#endif
+}
+
+ElevatorServer::~ElevatorServer()
+{
+ Stop();
+}
+
+// Return all properties in response.
+OCStackResult ElevatorServer::SendResponse(std::shared_ptr<OCResourceRequest> request)
+{
+ // Values to return.
+ OCRepresentation responseRep;
+ responseRep["x.org.iotivity.CurrentFloor"] = GetCurrentFloor();
+ responseRep["x.org.iotivity.TargetFloor"] = GetTargetFloor();
+ responseRep["x.org.iotivity.Direction"] = (int)GetElevatorDirection();
+
+ // Prepare the response.
+ auto pResponse = std::make_shared<OC::OCResourceResponse>();
+ pResponse->setRequestHandle(request->getRequestHandle());
+ pResponse->setResourceHandle(request->getResourceHandle());
+ pResponse->setResourceRepresentation(responseRep);
+ pResponse->setResponseResult(OC_EH_OK);
+
+ // Send the response.
+ return OCPlatform::sendResponse(pResponse);
+}
+
+// Callback handler for elevator resource.
+OCEntityHandlerResult ElevatorServer::ElevatorEntityHandler(
+ std::shared_ptr<OCResourceRequest> request)
+{
+ OCEntityHandlerResult ehResult = OC_EH_ERROR;
+
+ if(request != nullptr)
+ {
+ // Get the request type and request flag
+ std::string requestType = request->getRequestType();
+ int requestFlag = request->getRequestHandlerFlag();
+
+ if(requestFlag & RequestHandlerFlag::RequestFlag)
+ {
+ // If the request type is GET
+ if(requestType == "GET")
+ {
+ if (SendResponse(request) == OC_STACK_OK)
+ {
+ ehResult = OC_EH_OK;
+ }
+ }
+ else if(requestType == "POST")
+ {
+ OCRepresentation requestRep = request->getResourceRepresentation();
+
+ // Target floor can be set.
+ int targetFloor;
+ if (requestRep.getValue("x.org.iotivity.TargetFloor", targetFloor))
+ {
+ SetTargetFloor(static_cast<int>(targetFloor));
+ }
+
+ if(OC_STACK_OK == SendResponse(request))
+ {
+ ehResult = OC_EH_OK;
+ }
+ }
+ else if(requestType == "PUT")
+ {
+ // not supported.
+ }
+ else if(requestType == "DELETE")
+ {
+ // not supported.
+ }
+ }
+
+ if(requestFlag & RequestHandlerFlag::ObserverFlag)
+ {
+ // Hold the lock to make sure no iterator is in progress.
+ std::lock_guard<std::mutex> lock(m_elevatorMutex);
+
+ ObservationInfo observationInfo = request->getObservationInfo();
+ if(ObserveAction::ObserveRegister == observationInfo.action)
+ {
+ OIC_LOG_V(INFO, TAG, "ElevatorEntityHandler(): new observer ID: %d",
+ observationInfo.obsId);
+ m_observers.push_back(observationInfo.obsId);
+ }
+ else if(ObserveAction::ObserveUnregister == observationInfo.action)
+ {
+ OIC_LOG_V(INFO, TAG, "ElevatorEntityHandler(): removing observer ID: %d",
+ observationInfo.obsId);
+ m_observers.erase(std::remove(
+ m_observers.begin(),
+ m_observers.end(),
+ observationInfo.obsId),
+ m_observers.end());
+ }
+
+ ehResult = OC_EH_OK;
+ }
+ }
+
+ return ehResult;
+}
+
+// Copy from std::string to char array. Return true if source is truncated at dest.
+bool CopyStringToBuffer(const std::string& source, char* dest, size_t destSize)
+{
+ bool isTruncated = false;
+ size_t copied = source.copy(dest, destSize, 0);
+ if (copied == destSize)
+ {
+ copied -= 1; // make room for null
+ isTruncated = true;
+ }
+
+ // std::string copy does not include null.
+ dest[copied] = 0x00;
+ return isTruncated;
+}
+
+// Initialize Persistent Storage for security database
+OCPersistentStorage ps = {server_fopen, fread, fwrite, fclose, unlink};
+
+bool ElevatorServer::Start(const std::string& elevatorName)
+{
+ std::lock_guard<std::mutex> lock(m_elevatorMutex);
+
+ // OCPlatform needs only 1 time initialization.
+ static bool OCFInitialized = false;
+ if (false == OCFInitialized)
+ {
+ PlatformConfig Configuration {
+ ServiceType::InProc,
+ ModeType::Server,
+ "0.0.0.0", // By setting to "0.0.0.0", it binds to all available
+ // interfaces
+ 0, // Uses randomly available port
+ QualityOfService::NaQos,
+ &ps
+ };
+
+ OCPlatform::Configure(Configuration);
+ OCFInitialized = true;
+ }
+
+ if (false == m_isRunning)
+ {
+ std::string defaultResourceTypeName("x.org.iotivity.sample.elevator");
+ std::string defaultResourceName("/ipca/sample/elevator");
+
+ m_name = elevatorName;
+
+ // Start with known state.
+ m_targetFloor = m_currentFloor = 1;
+ m_direction = ElevatorDirection::Stopped;
+
+ // Start the engine thread.
+ m_isRunning = true;
+ engineThread = std::thread(&ElevatorServer::Engine, this);
+
+ // Device Info.
+ char devName[256];
+ char resTypeName[256];
+ CopyStringToBuffer(m_name, devName, 256);
+ CopyStringToBuffer(defaultResourceTypeName, resTypeName, 256);
+ OCStringLL types { nullptr, resTypeName };
+ OCDeviceInfo deviceInfo = { devName, &types, "0.0.1", nullptr };
+
+ // Platform Info
+ char platformId[] = "6cb6c994-8c4b-11e6-ae22-56b6b6499611";
+ char manufacturerName[] = "E Manufacturer";
+ char manufacturerUrl[] = "http://www.example.com/elevator";
+ char modelNumber[] = "Elevator Model Number";
+ char dateManufacture[] = "2017-02-28";
+ char platformVersion[] = "Elevator Platform Version";
+ char osVersion[] = "Elevator OS Version";
+ char hardwareVersion[] = "Elevator HW Version";
+ char firmwareVersion[] = "Elevator FW Version";
+ char supportURL[] = "http://www.example.com/elevator/support";
+
+ OCPlatformInfo platformInfo = {
+ platformId,
+ manufacturerName,
+ manufacturerUrl,
+ modelNumber,
+ dateManufacture,
+ platformVersion,
+ osVersion,
+ hardwareVersion,
+ firmwareVersion,
+ supportURL,
+ nullptr};
+
+ // Register elevator's platformInfo, deviceInfo, and resource.
+ if (OC_STACK_OK != OCPlatform::registerPlatformInfo(platformInfo))
+ {
+ return false;
+ }
+
+ if (OC_STACK_OK != OCPlatform::registerDeviceInfo(deviceInfo))
+ {
+ return false;
+ }
+
+#ifdef SECURED
+ if (OC_STACK_OK != OCSecure::registerDisplayPinCallback(
+ std::bind(&ElevatorServer::PinDisplayCallback, this, _1, _2),
+ &m_displayPasswordCallbackHandle))
+ {
+ return false;
+ }
+#endif
+ OCStackResult result = OCPlatform::registerResource(
+ m_elevatorResourceHandle,
+ defaultResourceName,
+ defaultResourceTypeName,
+ DEFAULT_INTERFACE,
+ std::bind(&ElevatorServer::ElevatorEntityHandler, this, _1),
+ OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
+
+ if (result != OC_STACK_OK)
+ {
+ return false;
+ }
+
+ // These extra resources are created but not implemented by the entity handler.
+ // They better reflect real devices supporting multiple resources.
+
+ std::string defaultResourceTypeName2("x.org.iotivity.sample.elevator2");
+ std::string defaultResourceName2("/ipca/sample/elevator2");
+ result = OCPlatform::registerResource(
+ m_elevatorResourceHandle2,
+ defaultResourceName2,
+ defaultResourceTypeName2,
+ DEFAULT_INTERFACE,
+ std::bind(&ElevatorServer::ElevatorEntityHandler, this, _1),
+ OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
+
+ if (result != OC_STACK_OK)
+ {
+ return false;
+ }
+
+ std::string defaultResourceTypeName3("x.org.iotivity.sample.elevator3");
+ std::string defaultResourceName3("/ipca/sample/elevator3");
+ result = OCPlatform::registerResource(
+ m_elevatorResourceHandle3,
+ defaultResourceName3,
+ defaultResourceTypeName3,
+ DEFAULT_INTERFACE,
+ std::bind(&ElevatorServer::ElevatorEntityHandler, this, _1),
+ OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
+
+ if (result != OC_STACK_OK)
+ {
+ return false;
+ }
+
+ std::string defaultResourceTypeName4("x.org.iotivity.sample.elevator4");
+ std::string defaultResourceName4("/ipca/sample/elevator4");
+ result = OCPlatform::registerResource(
+ m_elevatorResourceHandle4,
+ defaultResourceName4,
+ defaultResourceTypeName4,
+ DEFAULT_INTERFACE,
+ std::bind(&ElevatorServer::ElevatorEntityHandler, this, _1),
+ OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
+
+ return (result == OC_STACK_OK);
+ }
+
+ // It's already running.
+ return true;
+}
+
+void ElevatorServer::Stop()
+{
+ std::lock_guard<std::mutex> lock(m_elevatorMutex);
+
+ if (true == m_isRunning)
+ {
+ // Unregister OCF resource.
+ OCPlatform::unregisterResource(m_elevatorResourceHandle);
+ OCPlatform::unregisterResource(m_elevatorResourceHandle2);
+ OCPlatform::unregisterResource(m_elevatorResourceHandle3);
+ OCPlatform::unregisterResource(m_elevatorResourceHandle4);
+ m_elevatorResourceHandle = nullptr;
+ m_elevatorResourceHandle2 = nullptr;
+ m_elevatorResourceHandle3 = nullptr;
+ m_elevatorResourceHandle4 = nullptr;
+
+ // Signal the engineThread to stop and wait for it to exit.
+ m_isRunning = false;
+ if (engineThread.joinable())
+ {
+ engineThread.join();
+ }
+
+#ifdef SECURED
+ // Unregister the password display callback
+ OCSecure::deregisterDisplayPinCallback(m_displayPasswordCallbackHandle);
+ m_displayPasswordCallbackHandle = nullptr;
+#endif
+ }
+}
+
+void ElevatorServer::SetTargetFloor(int floor)
+{
+ m_targetFloor = floor;
+}
+
+int ElevatorServer::GetTargetFloor()
+{
+ return m_targetFloor;
+}
+
+int ElevatorServer::GetCurrentFloor()
+{
+ return m_currentFloor;
+}
+
+ElevatorDirection ElevatorServer::GetElevatorDirection()
+{
+ return m_direction;
+}
+
+void ElevatorServer::Engine(ElevatorServer* elevator)
+{
+ const size_t EngineSleepTimeSeconds = 2;
+ std::chrono::seconds engineSleepTime(EngineSleepTimeSeconds);
+
+ while (elevator->m_isRunning == true)
+ {
+ elevator->MoveElevator();
+ std::this_thread::sleep_for(engineSleepTime);
+ }
+}
+
+void ElevatorServer::NotifyObservers()
+{
+ // Local copy of observers so the code below doesn't need to hold the lock when
+ // calling out to notifyListOfObservers.
+ ObservationIds localCopyObservers;
+
+ if (m_observers.size() == 0)
+ {
+ return;
+ }
+ else
+ {
+ std::lock_guard<std::mutex> lock(m_elevatorMutex);
+ localCopyObservers = m_observers;
+ }
+
+ OCRepresentation rep;
+ rep["x.org.iotivity.CurrentFloor"] = GetCurrentFloor();
+ rep["x.org.iotivity.Direction"] = GetElevatorDirection();
+ rep["x.org.iotivity.TargetFloor"] = GetTargetFloor();
+
+ // Prepare the response.
+ auto response = std::make_shared<OC::OCResourceResponse>();
+ response->setResourceRepresentation(rep, DEFAULT_INTERFACE);
+
+ OCStackResult result = OCPlatform::notifyListOfObservers(
+ m_elevatorResourceHandle,
+ localCopyObservers,
+ response);
+
+ if(OC_STACK_NO_OBSERVERS == result)
+ {
+ std::cout << "ElevatorServer:: failed notifyListOfObservers: result = ";
+ std::cout << result << std::endl;
+ }
+}
+
+void ElevatorServer::MoveElevator()
+{
+ int dwTargetFloor = m_targetFloor;
+ int incrementValue;
+
+ if (m_currentFloor == dwTargetFloor)
+ {
+ return;
+ }
+
+ if (m_currentFloor < dwTargetFloor)
+ {
+ m_direction = ElevatorDirection::Up;
+ incrementValue = 1;
+ }
+ else
+ {
+ m_direction = ElevatorDirection::Down;
+ incrementValue = -1;
+ }
+
+ std::cout << "ElevatorServer::MoveElevator() new Direction: " << m_direction << std::endl;
+ NotifyObservers();
+
+ const int DelayBetweenFloorMilliseconds = 10;
+ std::chrono::milliseconds delayBetweenFloor(DelayBetweenFloorMilliseconds);
+
+ while (m_currentFloor != dwTargetFloor)
+ {
+
+ m_currentFloor += incrementValue;
+ NotifyObservers();
+ std::cout << "ElevatorServer::MoveElevator() new CurrentFloor: " << m_currentFloor;
+ std::cout << std::endl;
+ std::this_thread::sleep_for(delayBetweenFloor);
+ }
+
+ m_direction = ElevatorDirection::Stopped;
+ NotifyObservers();
+ std::cout << "ElevatorServer::MoveElevator() new Direction: " << m_direction << std::endl;
+}
+
+void ElevatorServer::PinDisplayCallback(char* pinData, size_t pinLength)
+{
+ if ((nullptr == pinData) || (pinLength == 0))
+ {
+ std::cout << "Invalid pin!" << std::endl;
+ return;
+ }
+
+ std::cout << "============================" << std::endl;
+ std::cout << " PIN CODE: " << pinData << std::endl;
+ std::cout << "============================" << std::endl;
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef ELEVATOR_SERVER_H_
+#define ELEVATOR_SERVER_H_
+
+#include <string>
+#include <mutex>
+#include "OCPlatform.h"
+#include "OCApi.h"
+#include <OCProvisioningManager.hpp>
+
+using namespace OC;
+
+typedef enum
+{
+ Stopped = 0,
+ Up,
+ Down
+} ElevatorDirection;
+
+class ElevatorServer
+{
+public:
+ ElevatorServer();
+ ~ElevatorServer();
+
+ // Start stop the thread processing the elevator movement. Also register/unregister the
+ // elevator from IoTivity.
+ bool Start(const std::string& elevatorName);
+ void Stop();
+
+ // Target floor is set by caller.
+ void SetTargetFloor(int floor);
+ int GetTargetFloor();
+
+ // Current floor is set by elevator.
+ int GetCurrentFloor();
+ ElevatorDirection GetElevatorDirection();
+
+private:
+ std::mutex m_elevatorMutex;
+
+ // List of observers, when client app calls resource->Observer().
+ ObservationIds m_observers;
+
+ // Send notification to observers.
+ void NotifyObservers();
+
+ // Elevator resources
+ OCResourceHandle m_elevatorResourceHandle;
+ OCResourceHandle m_elevatorResourceHandle2;
+ OCResourceHandle m_elevatorResourceHandle3;
+ OCResourceHandle m_elevatorResourceHandle4;
+
+ int m_targetFloor; // where elevator needs to be.
+ int m_currentFloor; // where elevator is.
+ ElevatorDirection m_direction; // current direction of the elevator.
+
+ // Thread moving the elevator.
+ std::thread engineThread;
+ bool m_isRunning;
+ static void Engine(ElevatorServer* elevator);
+
+ // Move current floor to target floor.
+ void MoveElevator();
+
+ // Helper function to send response for a request.
+ OCStackResult SendResponse(std::shared_ptr<OCResourceRequest> request);
+
+ // OCF callback for this elevator.
+ OCEntityHandlerResult ElevatorEntityHandler(std::shared_ptr<OCResourceRequest> request);
+
+ // OCF callback for a generated pin
+ void PinDisplayCallback(char* pinData, size_t pinLength);
+
+ // Elevator device details.
+ std::string m_name;
+
+ // Elevator platform details.
+ std::string m_platformID;
+ std::string m_modelNumber;
+ std::string m_platformVersion;
+ std::string m_serialNumber;
+ std::string m_specVersion;
+ std::string m_defaultLanguage;
+ std::string m_manufacturerName;
+ std::string m_manufacturerUrl;
+ std::string m_dateOfManufacture;
+ std::string m_operatingSystemVersion;
+ std::string m_hardwareVersion;
+ std::string m_firmwareVersion;
+ std::string m_supportUrl;
+ std::string m_systemTime;
+
+#ifdef SECURED
+ DisplayPinCallbackHandle m_displayPasswordCallbackHandle;
+#endif
+};
+#endif // ELEVATOR_SERVER_H_
--- /dev/null
+#******************************************************************
+#
+# Copyright 2017 Microsoft
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+##
+# ipca samples
+#
+##
+
+Import('ipca_env')
+
+SConscript('ipcaapp/SConscript', 'ipca_env')
+SConscript('elevatorserver/SConscript', 'ipca_env')
+SConscript('elevatorclient/SConscript', 'ipca_env')
--- /dev/null
+#******************************************************************
+#
+# Copyright 2017 Microsoft
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+##
+# ipcapp (application) build script
+##
+Import('ipca_env')
+target_os = ipca_env.get('TARGET_OS')
+ipcaapp_env = ipca_env.Clone()
+
+######################################################################
+# Build flags
+######################################################################
+ipcaapp_env.PrependUnique(CPPPATH = [
+ '..\..\inc',
+ ])
+
+ipcaapp_env.PrependUnique(LIBS = ['ipca'])
+
+######################################################################
+# Source files and Targets
+######################################################################
+ipcapp_src = [
+ 'ipcaapp.cpp'
+ ]
+
+ipcaapp = ipcaapp_env.Program('ipcaapp', ipcapp_src)
\ No newline at end of file
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include <mutex>
+#include <array>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <map>
+#include <thread>
+#include <chrono>
+#include <memory>
+#include <functional>
+
+#include "ipca.h"
+
+#if defined(_MSC_VER)
+#define UNREFERENCED_PARAMETER(P) (P)
+#else
+#define UNREFERENCED_PARAMETER(P)
+#endif
+
+IPCAAppHandle g_ipcaAppHandle;
+std::recursive_mutex g_globalMutex;
+
+// Key is resource URI. Value is array of resource types.
+typedef std::map<std::string, std::vector<std::string>> ResourceTypeList;
+
+// Key is resource URI. Value is array of resource interfaces.
+typedef std::map<std::string, std::vector<std::string>> ResourceInterfaceList;
+
+// Key is resource URI, Values is array of property name & property value type pair.
+typedef std::map<std::string, std::map<std::string, IPCAValueType>> ResourceProperties;
+
+size_t g_idPool = 1;
+size_t GenerateUniqueId()
+{
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);
+ return g_idPool++;
+}
+
+class OCFDevice
+{
+public:
+ typedef std::shared_ptr<OCFDevice> Ptr;
+ size_t m_localId; // used as context to async IPCA call so there's no need to take a
+ // ref count.
+
+ OCFDevice(std::string id);
+ ~OCFDevice();
+ void GetDeviceDetails(std::string deviceName, const char** deviceUris, size_t count);
+ void DisplayDevice();
+ void GetPropertiesCallback(IPCAStatus result, const void* context,
+ IPCAPropertyBagHandle propertyBagHandle);
+
+private:
+ IPCADeviceInfo* GetDeviceInfo();
+ IPCAPlatformInfo* GetPlatformInfo();
+ ResourceTypeList GetResourceTypeInfo();
+ ResourceInterfaceList GetResourceInterfaceInfo();
+
+private:
+ IPCAStatus OpenDevice();
+ std::string m_deviceId;
+ std::string m_deviceName;
+ IPCADeviceHandle m_deviceHandle; // from IPCAOpenDevice();
+ IPCADeviceInfo* m_deviceInfo;
+ IPCAPlatformInfo* m_platformInfo;
+ std::vector<std::string> m_deviceUris; // Uris of device.
+ ResourceTypeList m_resourceTypeList;
+ ResourceInterfaceList m_resourceInterfaceList;
+ ResourceProperties m_resourceProperties;
+};
+
+OCFDevice::OCFDevice(std::string id) :
+ m_deviceId (id),
+ m_deviceHandle(nullptr),
+ m_deviceInfo(nullptr),
+ m_platformInfo(nullptr),
+ m_localId(GenerateUniqueId())
+{
+}
+
+OCFDevice::~OCFDevice()
+{
+ if (m_deviceHandle != nullptr)
+ {
+ IPCACloseDevice(m_deviceHandle);
+ }
+
+ if (m_deviceInfo != nullptr)
+ {
+ IPCAFreeDeviceInfo(m_deviceInfo);
+ }
+
+ if (m_platformInfo != nullptr)
+ {
+ IPCAFreePlatformInfo(m_platformInfo);
+ }
+}
+
+IPCAStatus OCFDevice::OpenDevice()
+{
+ if (m_deviceHandle != nullptr)
+ {
+ return IPCA_OK;
+ }
+ else
+ {
+ return IPCAOpenDevice(g_ipcaAppHandle, m_deviceId.c_str(), &m_deviceHandle);
+ }
+}
+
+IPCADeviceInfo* OCFDevice::GetDeviceInfo()
+{
+ return m_deviceInfo;
+}
+
+IPCAPlatformInfo* OCFDevice::GetPlatformInfo()
+{
+ return m_platformInfo;
+}
+
+void C_GetPropertiesCallback(IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);
+
+ size_t localId = reinterpret_cast<size_t>(context);
+ OCFDevice::Ptr device = nullptr;
+
+ extern std::map<std::string, OCFDevice::Ptr> g_OCFDeviceList;
+
+ // Find the device.
+ for (const auto& ocfDevice : g_OCFDeviceList)
+ {
+ if (ocfDevice.second->m_localId == localId)
+ {
+ device = ocfDevice.second;
+ break;
+ }
+ }
+
+ if (device)
+ {
+ device->GetPropertiesCallback(result, context, propertyBagHandle);
+ }
+}
+
+void OCFDevice::GetPropertiesCallback(IPCAStatus result,
+ const void* context,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ UNREFERENCED_PARAMETER(context);
+ UNREFERENCED_PARAMETER(result);
+
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);
+
+ IPCAStatus status;
+ char* resourcePath;
+ char** allKeys;
+ IPCAValueType* allValueTypes;
+ size_t count;
+
+ status = IPCAPropertyBagGetResourcePath(propertyBagHandle, &resourcePath);
+ if ((status != IPCA_OK) || (resourcePath == nullptr))
+ {
+ return;
+ }
+
+ status = IPCAPropertyBagGetAllKeyValuePairs(propertyBagHandle,
+ &allKeys, &allValueTypes, &count);
+ if (status != IPCA_OK)
+ {
+ IPCAPropertyBagFreeString(resourcePath);
+ return;
+ }
+
+ std::map<std::string, IPCAValueType> properties;
+ for (int i = 0 ; i < count ; i++)
+ {
+ properties[allKeys[i]] = allValueTypes[i];
+ }
+
+ // Trigger new display if there's any new info.
+ std::map<std::string, IPCAValueType> knownProperties = m_resourceProperties[resourcePath];
+
+ for (auto& newProperty : properties)
+ {
+ if ((knownProperties.size() == 0) ||
+ (knownProperties.find(newProperty.first) == knownProperties.end()))
+ {
+ // At least one new property is not in known properties.
+ // Replace known properties & display device.
+ m_resourceProperties[resourcePath] = properties;
+ std::cout << "=== Updated info on device properties: === " << std::endl << std::endl;
+ DisplayDevice();
+ break;
+ }
+ }
+
+ IPCAPropertyBagFreeString(resourcePath);
+ IPCAPropertyBagFreeStringArray(allKeys, count);
+ IPCAPropertyBagFreeIPCAValueTypeArray(allValueTypes);
+}
+
+ResourceTypeList OCFDevice::GetResourceTypeInfo()
+{
+ return m_resourceTypeList;
+}
+
+ResourceInterfaceList OCFDevice::GetResourceInterfaceInfo()
+{
+ return m_resourceInterfaceList;
+}
+
+std::string MapIPCAValueTypeToString(IPCAValueType type)
+{
+ switch(type)
+ {
+ case IPCA_INTEGER:
+ return "integer";
+
+ case IPCA_DOUBLE:
+ return "double";
+
+ case IPCA_BOOLEAN:
+ return "boolean";
+
+ case IPCA_STRING:
+ return "string";
+
+ case IPCA_ARRAY:
+ return "array";
+
+ case IPCA_PROPERTY_BAG:
+ return "property bag";
+
+ case IPCA_VALUE_TYPE_NOT_SUPPORTED:
+ return "not supported";
+
+ default:
+ return "unknown";
+ }
+}
+
+void OCFDevice::DisplayDevice()
+{
+ IPCADeviceInfo* di = GetDeviceInfo();
+
+ if (di != nullptr)
+ {
+ std::cout << "Device Info: " << std::endl;
+ std::cout << std::endl;
+ if (m_deviceUris.size() != 0)
+ {
+ int i = 0;
+ for (auto& uri : m_deviceUris)
+ {
+ if (i++ == 0)
+ {
+
+ std::cout << " Device URI . . . . . . . : " << uri << std::endl;
+ }
+ else
+ {
+ std::cout << " " << uri << std::endl;
+ }
+ }
+ }
+
+ std::cout << " Device ID . . . . . . . : " << (di->deviceId ? di->deviceId : "");
+ std::cout << std::endl;
+ std::cout << " Device Name . . . . . . : " << (di ->deviceName ? di->deviceName : "");
+ std::cout << std::endl;
+ std::cout << " Device Software Version : ";
+ std::cout << (di->deviceSoftwareVersion ? di->deviceSoftwareVersion : "") << std::endl;
+ std::cout << std::endl;
+ }
+ else
+ {
+ std::cout << "Device Info: Not available." << std::endl << std::endl;
+ }
+
+ IPCAPlatformInfo* pi = GetPlatformInfo();
+
+ if (pi != nullptr)
+ {
+ std::cout << "Platform Info:" << std::endl;
+ std::cout << std::endl;
+ std::cout << " Plaform ID . . . . . . . : ";
+ std::cout << (pi->platformId ? pi->platformId : "") << std::endl;
+ std::cout << " Manufacturer Name . . . : ";
+ std::cout << (pi->manufacturerName ? pi->manufacturerName : "") << std::endl;
+ std::cout << " Manufacturer URL . . . . : ";
+ std::cout << (pi->manufacturerURL ? pi->manufacturerURL : "") << std::endl;
+ std::cout << " Model Number . . . . . . : ";
+ std::cout << (pi->modelNumber ? pi->modelNumber : "") << std::endl;
+ std::cout << " Manufacturing Date . . . : ";
+ std::cout << (pi->manufacturingDate ? pi->manufacturingDate : "") << std::endl;
+ std::cout << " Platform Version . . . . : ";
+ std::cout << (pi->platformVersion ? pi->platformVersion : "") << std::endl;
+ std::cout << " OS Version . . . . . . . : ";
+ std::cout << (pi->osVersion ? pi->osVersion : "") << std::endl;
+ std::cout << " Hardware Version . . . . : ";
+ std::cout << (pi->hardwareVersion ? pi->hardwareVersion : "") << std::endl;
+ std::cout << " Firmware Version . . . . : ";
+ std::cout << (pi->firmwareVersion ? pi->firmwareVersion : "") << std::endl;
+ std::cout << " Manufacturer Support URL : ";
+ std::cout << (pi->manufacturerSupportURL ? pi->manufacturerSupportURL : "") << std::endl;
+ std::cout << " Reference Time . . . . . : ";
+ std::cout << (pi->referenceTime ? pi->referenceTime : "") << std::endl;
+ std::cout << std::endl;
+ }
+ else
+ {
+ std::cout << "Platform Info: Not available." << std::endl << std::endl;
+ }
+
+ std::cout << "Resource List:" << std::endl;
+ ResourceTypeList resourceTypeList = GetResourceTypeInfo();
+ ResourceInterfaceList resourceInterfaceList = GetResourceInterfaceInfo();
+ for (auto const& resourceType : resourceTypeList)
+ {
+ bool firstEntry = true;
+ std::cout << " Resource URI . . . . . : " << resourceType.first << std::endl;
+ std::cout << " Resource Types . . . : ";
+ for (auto const& rt : resourceType.second)
+ {
+ if (firstEntry == true)
+ {
+ std::cout << rt << std::endl;
+ firstEntry = false;
+ }
+ else
+ {
+ std::cout << " " << rt << std::endl;
+ }
+ }
+
+ firstEntry = true;
+ std::cout << " Resource Interfaces . : ";
+ for (auto const& resourceInterface : resourceInterfaceList[resourceType.first])
+ {
+ if (firstEntry == true)
+ {
+ std::cout << resourceInterface << std::endl;
+ firstEntry = false;
+ }
+ else
+ {
+ std::cout << " " << resourceInterface << std::endl;
+ }
+ }
+
+ std::map<std::string, IPCAValueType> properties = m_resourceProperties[resourceType.first];
+ if (properties.size() != 0)
+ {
+ std::cout << " Properties . . . . . : ";
+ firstEntry = true;
+ for (auto const& property : properties)
+ {
+ if (firstEntry == true)
+ {
+ firstEntry = false;
+ }
+ else
+ {
+ std::cout << " ";
+ }
+
+ std::cout << property.first << " (";
+ std::cout << MapIPCAValueTypeToString(property.second) << ")" << std::endl;
+ }
+ }
+
+ std::cout << std::endl;
+ }
+
+ std::cout << std::endl << std::endl;
+}
+
+void OCFDevice::GetDeviceDetails(std::string deviceName, const char** deviceUris, size_t count)
+{
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);
+
+ m_deviceName = deviceName;
+
+ for (size_t i = 0; i < count; i++)
+ {
+ if (std::find(m_deviceUris.begin(), m_deviceUris.end(), deviceUris[i]) == m_deviceUris.end())
+ {
+ m_deviceUris.push_back(deviceUris[i]);
+ }
+ }
+
+ IPCAStatus status;
+
+ if (OpenDevice() != IPCA_OK)
+ {
+ return;
+ }
+
+ // Get device info, platform info, and resources incl. resource types & property types.
+ if (m_deviceInfo == nullptr)
+ {
+ status = IPCAGetDeviceInfo(m_deviceHandle, &m_deviceInfo);
+ if ((status != IPCA_INFORMATION_NOT_AVAILABLE) && (status != IPCA_OK))
+ {
+ std::cout << "Failed IPCAGetDeviceInfo() status: " << status << std::endl;
+ }
+ }
+
+ if (m_platformInfo == nullptr)
+ {
+ status = IPCAGetPlatformInfo(m_deviceHandle, &m_platformInfo);
+ if ((status != IPCA_INFORMATION_NOT_AVAILABLE) && (status != IPCA_OK))
+ {
+ std::cout << "Failed IPCAGetPlatformInfo() status: " << status << std::endl;
+ }
+ }
+
+ char** resourcePathList;
+ size_t resourceListCount;
+ status = IPCAGetResources(m_deviceHandle,
+ nullptr, nullptr, &resourcePathList, &resourceListCount);
+ if (IPCA_OK != status)
+ {
+ std::cout << "Failed IPCAGetResourceURIs() status: " << status << std::endl;
+ }
+
+ m_resourceTypeList.clear();
+ m_resourceInterfaceList.clear();
+
+ for (size_t i = 0 ; i < resourceListCount ; i++)
+ {
+ // Get resource types for each resource.
+ char** resourceTypes;
+ size_t resourceTypeCount;
+ status = IPCAGetResourceTypes(m_deviceHandle,
+ resourcePathList[i], &resourceTypes, &resourceTypeCount);
+ if (IPCA_OK == status)
+ {
+ for (size_t j = 0 ; j < resourceTypeCount; j++)
+ {
+ m_resourceTypeList[resourcePathList[i]].push_back(resourceTypes[j]);
+ }
+ IPCAFreeStringArray(resourceTypes, resourceTypeCount);
+ }
+ else
+ {
+ std::cout << "Failed IPCAGetResourceTypes() for resource: ";
+ std::cout << resourcePathList[i] << std::endl;
+ }
+
+ // Get resource interfaces for each resource.
+ char** resourceInterfaces;
+ size_t resourceInterfaceCount;
+ status = IPCAGetResourceInterfaces(m_deviceHandle,
+ resourcePathList[i], &resourceInterfaces, &resourceInterfaceCount);
+ if (IPCA_OK == status)
+ {
+ for (size_t j = 0 ; j < resourceInterfaceCount; j++)
+ {
+ m_resourceInterfaceList[resourcePathList[i]].push_back(resourceInterfaces[j]);
+ }
+ IPCAFreeStringArray(resourceInterfaces, resourceInterfaceCount);
+ }
+ else
+ {
+ std::cout << "Failed IPCAGetResourceInterfaces() for resource: ";
+ std::cout << resourcePathList[i] << std::endl;
+ }
+
+ // Get the resource properties.
+ status = IPCAGetProperties(m_deviceHandle,
+ &C_GetPropertiesCallback,
+ reinterpret_cast<void*>(m_localId),
+ resourcePathList[i],
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (status != IPCA_OK)
+ {
+ std::cout << "Failed IPCAGetProperties() status: " << status << std::endl;
+ }
+ }
+
+ IPCAFreeStringArray(resourcePathList, resourceListCount);
+}
+
+// Key is device id. Value is pointer to OCFDevice.
+std::map<std::string, OCFDevice::Ptr> g_OCFDeviceList;
+
+// Callback when device is discovered.
+void DiscoverDevicesCallback(void* context,
+ IPCADeviceStatus deviceStatus,
+ const IPCADiscoveredDeviceInfo* deviceInfo)
+{
+ UNREFERENCED_PARAMETER(context);
+
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);
+
+ std::string deviceId = deviceInfo->deviceId;
+ std::string deviceName = deviceInfo->deviceName;
+
+ if (g_OCFDeviceList.find(deviceId) == g_OCFDeviceList.end())
+ {
+ OCFDevice::Ptr ocfDevice = std::shared_ptr<OCFDevice>(new OCFDevice(deviceId));
+ if (ocfDevice == nullptr)
+ {
+ std::cout << "Out of memory" << std::endl;
+ return;
+ }
+ g_OCFDeviceList[deviceId] = ocfDevice;
+ }
+
+ OCFDevice::Ptr ocfDevice = g_OCFDeviceList[deviceId];
+
+ ocfDevice->GetDeviceDetails(deviceName, deviceInfo->deviceUris, deviceInfo->deviceUriCount);
+
+ if (deviceStatus == IPCA_DEVICE_DISCOVERED)
+ {
+ std::cout << "*** New Device. Device ID: [" << deviceId << "] ***";
+ std::cout << std::endl << std::endl;
+ }
+ else
+ if (deviceStatus == IPCA_DEVICE_UPDATED_INFO)
+ {
+ std::cout << "+++ Updated Info. Device ID: [" << deviceId << "] +++";
+ std::cout << std::endl << std::endl;
+ }
+ else
+ {
+ std::cout << "--- Device no longer discoverable. Device ID: [" << deviceId << "] ---";
+ std::cout << std::endl << std::endl;
+ g_OCFDeviceList.erase(deviceId);
+ return;
+ }
+
+ ocfDevice->DisplayDevice();
+}
+
+IPCAStatus IPCA_CALL PasswordInputCallback(void* context,
+ const IPCADeviceInfo* deviceInformation,
+ const IPCAPlatformInfo* platformInformation,
+ IPCAOwnershipTransferType type,
+ char* passwordBuffer,
+ size_t passwordBufferSize)
+{
+ UNREFERENCED_PARAMETER(context);
+ UNREFERENCED_PARAMETER(deviceInformation);
+ UNREFERENCED_PARAMETER(platformInformation);
+ UNREFERENCED_PARAMETER(type);
+ UNREFERENCED_PARAMETER(passwordBuffer);
+ UNREFERENCED_PARAMETER(passwordBufferSize);
+
+ // @todo: collect the password from the user
+
+ // Refuse authentication for ownership transfer.
+ return IPCA_FAIL;
+}
+
+IPCAStatus IPCA_CALL PasswordDisplayCallback(void* context,
+ const IPCADeviceInfo* deviceInformation,
+ const IPCAPlatformInfo* platformInformation,
+ IPCAOwnershipTransferType type,
+ const char* password)
+{
+ UNREFERENCED_PARAMETER(context);
+ UNREFERENCED_PARAMETER(deviceInformation);
+ UNREFERENCED_PARAMETER(platformInformation);
+ UNREFERENCED_PARAMETER(type);
+ UNREFERENCED_PARAMETER(password);
+
+ // @todo: display the password and ask for confirmation from the user
+
+ // Refuse authentication for ownership transfer.
+ return IPCA_FAIL;
+}
+
+int main()
+{
+ // @future:
+ // possible options:
+ // ipcapp [-o] | [-rt] | [-g] | [-s]
+ // -r <resource URI>
+ // -rt <resource type name>
+ // -g <dataName>
+ // -s <dataName> <value>
+
+ IPCAHandle discoverDeviceHandle;
+ IPCAStatus status;
+
+ // Initialize IPCA.
+ IPCAUuid appId = {0x37, 0x9d, 0xf2, 0xf2, 0x7e, 0xf7, 0x11, 0xe6,
+ 0xae, 0x22, 0x56, 0xb6, 0xb6, 0x49, 0x96, 0x11};
+ IPCAAppInfo ipcaAppInfo = { appId, "IPCAAPP", "1.0.0", "Microsoft" };
+
+ status = IPCAOpen(&ipcaAppInfo, IPCA_VERSION_1, &g_ipcaAppHandle);
+ if (status != IPCA_OK)
+ {
+ std::cout << "IPCAOpen failed, status = " << status << std::endl;
+ }
+
+ // Get ready for Ownership Transfer.
+ IPCASetPasswordCallbacks(g_ipcaAppHandle,
+ PasswordInputCallback, PasswordDisplayCallback, nullptr);
+
+ // Start discovering devices.
+ char* resourceTypes[] = {
+ "" /* any resource type */
+ };
+
+ const int ResourceTypeCount = sizeof(resourceTypes)/sizeof(char*);
+
+ status = IPCADiscoverDevices(
+ g_ipcaAppHandle,
+ &DiscoverDevicesCallback,
+ nullptr,
+ resourceTypes,
+ ResourceTypeCount,
+ &discoverDeviceHandle);
+
+
+ int userInput;
+ std::cin >> userInput;
+
+ g_OCFDeviceList.clear();
+
+ IPCACloseHandle(discoverDeviceHandle);
+ IPCAClose(g_ipcaAppHandle);
+}
--- /dev/null
+#******************************************************************
+#
+# Copyright 2017 Microsoft
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+##
+# ipca lib (shared library) build script
+##
+Import('ipca_env')
+target_os = ipca_env.get('TARGET_OS')
+ipca_lib_env = ipca_env.Clone()
+rd_mode = ipca_lib_env.get('RD_MODE')
+
+######################################################################
+# Build flags
+######################################################################
+ipca_lib_env.PrependUnique(CPPPATH = [
+ '../inc',
+ 'inc',
+ '#/resource/include',
+ '#/resource/oc_logger/include',
+ '#/resource/csdk/include',
+ '#/resource/csdk/stack/include',
+ '#/resource/csdk/security/include',
+ '#/resource/csdk/security/provisioning/include',
+ '#/resource/csdk/security/provisioning/include/internal',
+ '#/resource/csdk/connectivity/api',
+ '#/resource/csdk/connectivity/external/inc',
+ '#/resource/csdk/connectivity/lib/libcoap-4.1.1/include',
+ '#/resource/csdk/ocsocket/include',
+ '#/resource/csdk/logger/include',
+ '#/resource/c_common/ocrandom/include',
+ '#/extlibs/boost/boost',
+ '#/extlibs/cjson',
+ ])
+
+ipca_lib_env.Replace(WINDOWS_INSERT_DEF = ['1'])
+
+ipca_lib_env.PrependUnique(LIBS = [
+ 'oc',
+ 'connectivity_abstraction',
+ 'coap',
+ 'octbstack',
+ 'oc_logger'
+ ])
+
+if ipca_env.get('SECURED') == '1':
+ ipca_lib_env.PrependUnique(LIBS = [
+ 'mbedtls',
+ 'mbedx509',
+ 'mbedcrypto',
+ 'ocprovision'
+ ])
+
+if 'CLIENT' in rd_mode or 'SERVER' in rd_mode:
+ ipca_lib_env.PrependUnique(LIBS = ['resource_directory'])
+
+######################################################################
+# Source files and Targets
+######################################################################
+ipca_lib_src = [
+ 'app.cpp',
+ 'ipca.cpp',
+ 'callback.cpp',
+ 'ocfframework.cpp',
+ 'device.cpp',
+ 'ipcavariant.cpp',
+ 'common.cpp'
+ ]
+
+if ipca_lib_env.get('SECURED') != '1':
+ ipca_lib_src.append('pretendocprovision.cpp')
+
+ipca_shared_lib = ipca_lib_env.SharedLibrary('ipca', ipca_lib_src)
+ipca_lib = Flatten(ipca_shared_lib)
+
+ipca_static_lib = ipca_lib_env.StaticLibrary('ipca_static', ipca_lib_src)
+
+ipca_lib_env.UserInstallTargetHeader('../inc/ipca.h', 'resource', 'ipca.h')
+ipca_lib_env.UserInstallTargetLib(ipca_lib, 'ipca')
+ipca_lib_env.UserInstallTargetLib(ipca_static_lib, 'ipca')
\ No newline at end of file
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "oic_time.h"
+#include "ipcainternal.h"
+
+// Object that implements interface to IoTivity.
+// @future: Consider having an instance of this per app when there's mechanism to unregister
+// from IoTivity and IoTivity supports multiple apps in same process.
+OCFFramework ocfFramework;
+
+#define TAG "IPCA_App"
+
+App::App(const IPCAAppInfo* ipcaAppInfo, IPCAVersion ipcaVersion) :
+ m_isStopped(false),
+ m_passwordInputCallbackHandle(nullptr),
+ m_passwordDisplayCallbackHandle(nullptr),
+ m_ipcaVersion(ipcaVersion)
+{
+ m_ipcaAppInfo.appId = ipcaAppInfo->appId;
+ m_ipcaAppInfo.appName = ipcaAppInfo->appName;
+ m_ipcaAppInfo.appSoftwareVersion = ipcaAppInfo->appSoftwareVersion;
+ m_ipcaAppInfo.appCompanyName = ipcaAppInfo->appCompanyName;
+}
+
+App::~App()
+{
+}
+
+IPCAStatus App::Start(bool unitTestMode)
+{
+ m_callback = std::shared_ptr<Callback>(new Callback(this));
+ if (m_callback == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ // Start OCFFramework
+ IPCAStatus status = ocfFramework.Start(m_ipcaAppInfo, unitTestMode);
+ if (status != IPCA_OK)
+ {
+ m_callback = nullptr;
+ return status;
+ }
+
+ // Register app's callback with OCFFramework.
+ if (ocfFramework.RegisterAppCallbackObject(m_callback) != IPCA_OK)
+ {
+ ocfFramework.Stop(m_passwordInputCallbackHandle, m_passwordDisplayCallbackHandle);
+ m_callback = nullptr;
+ return IPCA_FAIL;
+ }
+
+ // Start periodic discovery thread.
+ m_appWorkerThread = std::thread(&App::AppWorkerThread, this);
+ return IPCA_OK;
+}
+
+void App::Stop()
+{
+ ocfFramework.UnregisterAppCallbackObject(m_callback);
+
+ if (m_isStopped)
+ {
+ assert(false); // code fault in ipca.cpp if this happens.
+ return;
+ }
+
+ // Stop the discovery thread.
+ m_isStopped = true;
+ m_discoveryThreadCV.notify_all(); // Wake discovery thread and wait for it to quit.
+ if (m_appWorkerThread.joinable())
+ {
+ m_appWorkerThread.join();
+ }
+
+ // Wait for all in progress callbacks are completed.
+ m_callback->Stop();
+ m_callback = nullptr;
+
+ // Force close devices that are still open. Caller continues to own the deviceWrapper memory
+ // but with device handle closed.
+ for(auto& it : m_openedDevices)
+ {
+ it.second->device->Close();
+ it.second->device = nullptr; // releases reference to device.
+ }
+
+ // Stop the OCFFramework.
+ ocfFramework.Stop(m_passwordInputCallbackHandle, m_passwordDisplayCallbackHandle);
+ m_passwordInputCallbackHandle = nullptr;
+ m_passwordDisplayCallbackHandle = nullptr;
+}
+
+void App::AppWorkerThread(App* app)
+{
+ const uint64_t FastDiscoveryCount = 4; // First 4 periodic discovery requests use fast period.
+ const uint64_t SlowDiscoveryPeriodMs = 30000;
+ const uint64_t FastDiscoveryPeriodMs = 2000;
+
+ const uint64_t PingPeriodMS = 30000; // Do device ping for Observed devices every 30 seconds.
+
+ // Outstanding requests should time out in 2 seconds per rfc 7252.
+ // Wake up every second to check.
+ const size_t AppThreadSleepTimeSeconds = 1;
+ std::chrono::seconds appThreadSleepTime(AppThreadSleepTimeSeconds);
+
+ std::unique_lock<std::mutex> appWorkerLock(app->m_appWorkerThreadMutex);
+
+ OIC_LOG_V(INFO, TAG, "+AppWorkerThread started.");
+
+ while (false == app->m_isStopped)
+ {
+ uint64_t currentTime = OICGetCurrentTime(TIME_IN_MS);
+
+ // Do periodic discovery for active IPCADiscoverDevices() requests.
+ std::map<uint32_t, std::vector<std::string>> resourceTypesToDiscover;
+ {
+ std::lock_guard<std::mutex> lock(app->m_appMutex);
+ for (auto& entry : app->m_discoveryList)
+ {
+ DiscoveryDetails::Ptr discoveryDetails = entry.second;
+
+ if (discoveryDetails->discoveryCount < FastDiscoveryCount)
+ {
+ if (currentTime - discoveryDetails->lastDiscoveryTime > FastDiscoveryPeriodMs)
+ {
+ resourceTypesToDiscover[entry.first] =
+ discoveryDetails->resourceTypesToDiscover;
+
+ discoveryDetails->lastDiscoveryTime = currentTime;
+ discoveryDetails->discoveryCount++;
+ }
+ }
+ else
+ {
+ if (currentTime - discoveryDetails->lastDiscoveryTime > SlowDiscoveryPeriodMs)
+ {
+ resourceTypesToDiscover[entry.first] =
+ discoveryDetails->resourceTypesToDiscover;
+
+ discoveryDetails->lastDiscoveryTime = currentTime;
+ discoveryDetails->discoveryCount++;
+ }
+ }
+ }
+ }
+
+ for (auto& resourceTypes : resourceTypesToDiscover)
+ {
+ ocfFramework.DiscoverResources(resourceTypes.second);
+ }
+
+ // Do callbacks for expired outstanding requests.
+ std::vector<CallbackInfo::Ptr> expiredCallbacks;
+ app->m_callback->CompleteAndRemoveExpiredCallbackInfo(expiredCallbacks);
+
+ // Get oustanding Observe requests and ping the device every PingPeriodMS.
+ std::vector<CallbackInfo::Ptr> observeCallbacks;
+ app->m_callback->GetCallbackInfoList(CallbackType_ResourceChange, observeCallbacks);
+ for (auto& cbInfo : observeCallbacks)
+ {
+ uint64_t lastPingTime;
+ if ((IPCA_OK == cbInfo->device->GetLastPingTime(lastPingTime)) &&
+ (currentTime - lastPingTime > PingPeriodMS))
+ {
+ cbInfo->device->Ping();
+ }
+ }
+
+ app->m_discoveryThreadCV.wait_for(appWorkerLock,
+ appThreadSleepTime,
+ [app]()
+ {
+ return app->m_isStopped;
+ });
+ }
+
+ OIC_LOG_V(INFO, TAG, "-AppWorkerThread exit.");
+}
+
+IPCAStatus App::OpenDevice(const char* deviceId, IPCADeviceHandle* deviceHandle)
+{
+ *deviceHandle = nullptr;
+
+ std::unique_ptr<DeviceWrapper> deviceWrapper(new DeviceWrapper);
+ if (deviceWrapper == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ Device::Ptr device = std::shared_ptr<Device>(new Device(deviceId, &ocfFramework, this));
+ if (device == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ IPCAStatus status = device->Open();
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ deviceWrapper->app = this;
+ deviceWrapper->device = device;
+ *deviceHandle = reinterpret_cast<IPCADeviceHandle>(deviceWrapper.get());
+ m_openedDevices[deviceWrapper.get()] = deviceWrapper.get(); // Take a device reference.
+ deviceWrapper.release();
+ return IPCA_OK;
+}
+
+void App::CloseDevice(IPCADeviceHandle deviceHandle)
+{
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ if (m_openedDevices.find(deviceWrapper) == m_openedDevices.end())
+ {
+ return;
+ }
+
+ if (deviceWrapper->device != nullptr)
+ {
+ deviceWrapper->device->Close();
+ deviceWrapper->device = nullptr; // Release reference to device.
+ }
+
+ m_openedDevices.erase(deviceWrapper);
+ delete deviceWrapper;
+}
+
+IPCAStatus App::DiscoverDevices(
+ IPCADiscoverDeviceCallback callback,
+ const void* context,
+ const char* const* resourceTypeList,
+ int resourceTypeCount,
+ IPCAHandle* handle)
+{
+ CallbackInfo::Ptr cbInfo = nullptr;
+
+ // Discovery must have a callback.
+ if (callback == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ DiscoveryDetails::Ptr discoveryDetails = std::shared_ptr<DiscoveryDetails>
+ (new(DiscoveryDetails));
+
+ if (discoveryDetails == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ IPCAStatus status = CreateAndRegisterNewCallbackInfo(
+ handle,
+ nullptr, // No device handle, discovery is a multicast.
+ &cbInfo,
+ CallbackType_Discovery,
+ context,
+ callback,
+ resourceTypeList,
+ resourceTypeCount,
+ nullptr, // Not Get/Set/Create/Observe request.
+ nullptr, // Resource interface is not needed.
+ nullptr, // Resource path is not needed.
+ nullptr); // Similarly resource type is also not needed.
+
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ // Start discovery.
+ discoveryDetails->lastDiscoveryTime = OICGetCurrentTime(TIME_IN_MS);
+ discoveryDetails->discoveryCount = 1;
+ discoveryDetails->resourceTypesToDiscover = cbInfo->resourceTypeList;
+ status = ocfFramework.DiscoverResources(cbInfo->resourceTypeList);
+
+ if (status == IPCA_OK)
+ {
+ // Add it to the periodic discovery list.
+ std::lock_guard<std::mutex> lock(m_appMutex);
+ m_discoveryList[cbInfo->mapKey] = discoveryDetails;
+ }
+ else
+ {
+ if (handle != nullptr)
+ {
+ *handle = nullptr;
+ }
+
+ DeleteAndUnregisterCallbackInfo(cbInfo->mapKey);
+ }
+
+ return status;
+}
+
+IPCAStatus App::SetPasswordCallbacks(
+ IPCAProvidePasswordCallback inputCallback,
+ IPCADisplayPasswordCallback displayCallback,
+ void* context)
+{
+ if ((inputCallback == nullptr) || (displayCallback == nullptr))
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ CallbackInfo::Ptr inputCallbackInfo = nullptr;
+ CallbackInfo::Ptr displayCallbackInfo = nullptr;
+
+ inputCallbackInfo = m_callback->CreatePasswordCallbackInfo(
+ CallbackType_PasswordInputCallback,
+ context,
+ inputCallback,
+ nullptr);
+
+ if (inputCallbackInfo == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ IPCAStatus status = m_callback->AddCallbackInfo(inputCallbackInfo);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ displayCallbackInfo = m_callback->CreatePasswordCallbackInfo(
+ CallbackType_PasswordDisplayCallback,
+ context,
+ nullptr,
+ displayCallback);
+
+ if (displayCallbackInfo == nullptr)
+ {
+ DeleteAndUnregisterCallbackInfo(inputCallbackInfo->mapKey);
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ status = m_callback->AddCallbackInfo(displayCallbackInfo);
+ if (status != IPCA_OK)
+ {
+ // Failed to add displayCallbackInfo to the callback list, deregister inputCallbackInfo.
+ // Note that: Failure to add displayCallbackInfo to the list means no ref count is taken on
+ // displayCallbackInfo. Therefore it will automatically be deleted outside the
+ // scope of this function.
+ DeleteAndUnregisterCallbackInfo(inputCallbackInfo->mapKey);
+ return status;
+ }
+
+ ocfFramework.SetInputPasswordCallback(inputCallbackInfo, &m_passwordInputCallbackHandle);
+ ocfFramework.SetDisplayPasswordCallback(displayCallbackInfo, &m_passwordDisplayCallbackHandle);
+
+ return IPCA_OK;
+}
+
+IPCAStatus App::RequestAccess(
+ Device::Ptr device,
+ const char* resourcePath,
+ IPCARequestAccessCompletionCallback completionCallback,
+ void* context,
+ IPCAHandle* handle)
+{
+ CallbackInfo::Ptr cbInfo;
+ CallbackInfo::Ptr passwordInputCbInfo;
+
+ if (handle != nullptr)
+ {
+ *handle = nullptr;
+ }
+
+ cbInfo = m_callback->CreateRequestAccessCompletionCallbackInfo(
+ device,
+ context,
+ resourcePath,
+ completionCallback);
+
+ if (cbInfo == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ IPCAStatus status = m_callback->AddCallbackInfo(cbInfo);
+ if (status == IPCA_OK)
+ {
+ if (handle != nullptr)
+ {
+ *handle = reinterpret_cast<IPCAHandle>(cbInfo->mapKey);
+ }
+ }
+ else
+ {
+ return status;
+ }
+
+ passwordInputCbInfo = m_callback->GetPasswordInputCallbackInfo();
+ if (passwordInputCbInfo == nullptr)
+ {
+ // App has not registered for password callback.
+ // Delete the request access callback completion.
+ DeleteAndUnregisterCallbackInfo(cbInfo->mapKey);
+ return IPCA_FAIL;
+ }
+
+ status = device->RequestAccess(cbInfo, passwordInputCbInfo);
+ if (status != IPCA_OK)
+ {
+ if (handle != nullptr)
+ {
+ *handle = nullptr;
+ }
+
+ DeleteAndUnregisterCallbackInfo(cbInfo->mapKey);
+ }
+
+ return status;
+}
+
+IPCAStatus App::GetProperties(
+ Device::Ptr device,
+ IPCAGetPropertiesComplete callback,
+ const void* context,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType,
+ IPCAHandle* handle)
+{
+ CallbackInfo::Ptr cbInfo = nullptr;
+
+ IPCAStatus status = CreateAndRegisterNewCallbackInfo(
+ handle,
+ device,
+ &cbInfo,
+ CallbackType_GetPropertiesComplete,
+ context,
+ nullptr, // Not discovery request.
+ nullptr, // Therefore resourceTypeList is not needed.
+ 0,
+ callback,
+ resourcePath,
+ resourceInterface,
+ resourceType);
+
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ status = device->GetProperties(cbInfo);
+
+ if (status != IPCA_OK)
+ {
+ if (handle != nullptr)
+ {
+ *handle = nullptr;
+ }
+
+ DeleteAndUnregisterCallbackInfo(cbInfo->mapKey);
+ }
+
+ return status;
+}
+
+IPCAStatus App::SetProperties(
+ Device::Ptr device,
+ IPCASetPropertiesComplete callback,
+ const void* context,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType,
+ OC::OCRepresentation* rep,
+ IPCAHandle* handle)
+{
+ CallbackInfo::Ptr cbInfo = nullptr;
+
+ IPCAStatus status = CreateAndRegisterNewCallbackInfo(
+ handle,
+ device,
+ &cbInfo,
+ CallbackType_SetPropertiesComplete,
+ context,
+ nullptr, // Not discovery request.
+ nullptr, // Therefore resourceTypeList is not needed.
+ 0,
+ callback,
+ resourcePath,
+ resourceInterface,
+ resourceType);
+
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ status = device->SetProperties(cbInfo, rep);
+
+ if ((status != IPCA_OK) && (cbInfo != nullptr))
+ {
+ if (handle != nullptr)
+ {
+ *handle = nullptr;
+ }
+
+ DeleteAndUnregisterCallbackInfo(cbInfo->mapKey);
+ }
+
+ return status;
+}
+
+IPCAStatus App::ObserveResource(
+ Device::Ptr device,
+ IPCAResourceChangeCallback callback,
+ const void* context,
+ const char* resourcePath,
+ const char* resourceType,
+ IPCAHandle* handle)
+{
+ CallbackInfo::Ptr cbInfo = nullptr;
+
+ // ObserveResource must have a callback.
+ if (callback == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ IPCAStatus status = CreateAndRegisterNewCallbackInfo(
+ handle,
+ device,
+ &cbInfo,
+ CallbackType_ResourceChange,
+ context,
+ nullptr, // Not a discovery request.
+ nullptr, // Therefore resourceTypeList is not needed.
+ 0,
+ callback,
+ resourcePath,
+ nullptr,
+ resourceType);
+
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ status = device->ObserveResource(cbInfo);
+
+ if ((status != IPCA_OK) && (cbInfo != nullptr))
+ {
+ if (handle != nullptr)
+ {
+ *handle = nullptr;
+ }
+
+ DeleteAndUnregisterCallbackInfo(cbInfo->mapKey);
+ }
+
+ return status;
+}
+
+IPCAStatus App::CreateResource(
+ Device::Ptr device,
+ IPCACreateResourceComplete createResourceCb,
+ const void* context,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType,
+ OC::OCRepresentation* rep,
+ IPCAHandle* handle)
+{
+ CallbackInfo::Ptr cbInfo = nullptr;
+
+ IPCAStatus status = CreateAndRegisterNewCallbackInfo(
+ handle,
+ device,
+ &cbInfo,
+ CallbackType_CreateResourceComplete,
+ context,
+ nullptr, // Not a discovery request.
+ nullptr, // Therefore resourceTypeList is not needed.
+ 0,
+ reinterpret_cast<GenericAppCallback>(createResourceCb),
+ resourcePath,
+ resourceInterface,
+ resourceType);
+
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ status = device->CreateResource(cbInfo, rep);
+
+ if ((status != IPCA_OK) && (cbInfo != nullptr))
+ {
+ if (handle != nullptr)
+ {
+ *handle = nullptr;
+ }
+
+ DeleteAndUnregisterCallbackInfo(cbInfo->mapKey);
+ }
+
+ return status;
+}
+
+IPCAStatus App::DeleteResource(
+ Device::Ptr device,
+ IPCADeleteResourceComplete deleteResourceCb,
+ const void* context,
+ const char* resourcePath,
+ IPCAHandle* handle)
+{
+ CallbackInfo::Ptr cbInfo = nullptr;
+
+ IPCAStatus status = CreateAndRegisterNewCallbackInfo(
+ handle,
+ device,
+ &cbInfo,
+ CallbackType_DeleteResourceComplete,
+ context,
+ nullptr, // Not a discovery request.
+ nullptr, // Therefore resourceTypeList is not needed.
+ 0,
+ reinterpret_cast<GenericAppCallback>(deleteResourceCb),
+ resourcePath,
+ nullptr,
+ nullptr);
+
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ status = device->DeleteResource(cbInfo);
+
+ if ((status != IPCA_OK) && (cbInfo != nullptr))
+ {
+ if (handle != nullptr)
+ {
+ *handle = nullptr;
+ }
+
+ DeleteAndUnregisterCallbackInfo(cbInfo->mapKey);
+ }
+
+ return status;
+}
+
+void App::CloseIPCAHandle(IPCAHandle handle)
+{
+ size_t mapKey = reinterpret_cast<size_t>(handle);
+
+ CallbackInfo::Ptr cbInfo = m_callback->GetCallbackInfo(mapKey);
+
+ if (cbInfo != nullptr)
+ {
+ if (cbInfo->type == CallbackType_Discovery)
+ {
+ // Stop periodic discovery of these resource types.
+ std::lock_guard<std::mutex> lock(m_appMutex);
+ m_discoveryList.erase(cbInfo->mapKey);
+ }
+ else
+ if (cbInfo->type == CallbackType_ResourceChange)
+ {
+ cbInfo->device->StopObserve(cbInfo);
+ }
+ }
+
+ DeleteAndUnregisterCallbackInfo(mapKey);
+}
+
+IPCAStatus App::CreateAndRegisterNewCallbackInfo(
+ IPCAHandle* handle,
+ Device::Ptr device,
+ CallbackInfo::Ptr* cbInfo,
+ CallbackType cbType,
+ const void* context,
+ IPCADiscoverDeviceCallback discoverDeviceCallback,
+ const char* const* resourceTypeList,
+ int resourceTypeCount,
+ GenericAppCallback appCallback,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType)
+{
+ if (handle != nullptr)
+ {
+ *handle = nullptr;
+ }
+
+ *cbInfo = m_callback->CreateCallbackInfo(
+ device,
+ cbType,
+ context,
+ discoverDeviceCallback,
+ resourceTypeList,
+ resourceTypeCount,
+ appCallback,
+ resourcePath,
+ resourceInterface,
+ resourceType);
+
+ if (*cbInfo == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ IPCAStatus status = m_callback->AddCallbackInfo(*cbInfo);
+
+ if (status == IPCA_OK)
+ {
+ if (handle != nullptr)
+ {
+ *handle = reinterpret_cast<IPCAHandle>((*cbInfo)->mapKey);
+ }
+ }
+
+ return status;
+}
+
+void App::DeleteAndUnregisterCallbackInfo(size_t mapKey)
+{
+ m_callback->RemoveCallbackInfo(mapKey);
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "oic_time.h"
+#include "ipcainternal.h"
+#include <map>
+#include <algorithm>
+#include <stdexcept>
+
+#define TAG "IPCA_Callback"
+
+extern OCFFramework ocfFramework;
+
+Callback::Callback(App* app) :
+ m_nextKey(0),
+ m_app(app),
+ m_stopCalled(false),
+ m_expiredCallbacksInprogress(0)
+{
+}
+
+Callback::~Callback()
+{
+}
+
+// Exception when Stop() times out waiting for pending callback to complete.
+class StopTimeout : public std::exception
+{
+ virtual const char* what() const throw()
+ {
+ return "Time out waiting for callback to complete in Callback::Stop().";
+ }
+} timeoutException;
+
+void Callback::Stop()
+{
+ bool allStopped = false;
+
+ // No more callbacks from here on as SetCallbackInProgress() and
+ // CompleteAndRemoveExpiredCallbackInfo() check for this flag.
+ m_stopCalled = true;
+
+ // Wait some amount of time for all callbacks in progress to complete.
+ const int WaitTimeSeconds = 3;
+ int i = 0;
+ while (i < WaitTimeSeconds)
+ {
+ if (m_callbackInfoList.size() != 0)
+ {
+ std::lock_guard<std::mutex> lock(m_callbackMutex);
+ for (auto it = m_callbackInfoList.cbegin();
+ it != m_callbackInfoList.cend();
+ /* increment inside loop */)
+ {
+ if (it->second->callbackInProgressCount == 0)
+ {
+ m_callbackInfoList.erase(it++);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ }
+
+ // There are 2 group of callbacks.
+ // One tracked by m_callbackInfoList and the other tracked by m_expiredCallbacksInprogress.
+ if ((m_callbackInfoList.size() == 0) && (m_expiredCallbacksInprogress == 0))
+ {
+ allStopped = true;
+ break;
+ }
+
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ i++;
+ }
+
+ if (allStopped == false)
+ {
+ OIC_LOG_V(WARNING, TAG, "Stop() time out waiting for pending callbacks to complete.");
+ throw timeoutException;
+ }
+
+}
+
+CallbackInfo::Ptr Callback::CreatePasswordCallbackInfo(
+ CallbackType cbType,
+ const void* context,
+ IPCAProvidePasswordCallback passwordInputCb,
+ IPCADisplayPasswordCallback passwordDisplayCb)
+{
+ if ((cbType != CallbackType_PasswordInputCallback) &&
+ (cbType != CallbackType_PasswordDisplayCallback))
+ {
+ assert(false);
+ return nullptr;
+ }
+
+ CallbackInfo::Ptr cbInfo = std::shared_ptr<CallbackInfo>(new(CallbackInfo));
+
+ if (cbInfo == nullptr)
+ {
+ return nullptr;
+ }
+
+ cbInfo->app = m_app;
+ cbInfo->type = cbType;
+ cbInfo->callbackContext = context;
+ cbInfo->callbackInProgressCount = 0;
+ cbInfo->markedToBeRemoved = false;
+
+ switch (cbType)
+ {
+ case CallbackType_PasswordInputCallback:
+ cbInfo->passwordInputCallback = passwordInputCb;
+ break;
+
+ case CallbackType_PasswordDisplayCallback:
+ cbInfo->passwordDisplayCallback = passwordDisplayCb;
+ break;
+ }
+
+ return cbInfo;
+}
+
+CallbackInfo::Ptr Callback::CreateRequestAccessCompletionCallbackInfo(
+ DevicePtr device,
+ const void* context,
+ const char* resourcePath,
+ IPCARequestAccessCompletionCallback completionCallback)
+{
+ CallbackInfo::Ptr cbInfo = std::shared_ptr<CallbackInfo>(new(CallbackInfo));
+
+ if (cbInfo == nullptr)
+ {
+ return nullptr;
+ }
+
+ cbInfo->app = m_app;
+ cbInfo->device = device;
+ cbInfo->type = Callbacktype_RequestAccessCompletionCallback;
+ cbInfo->callbackContext = context;
+ cbInfo->callbackInProgressCount = 0;
+ cbInfo->markedToBeRemoved = false;
+ cbInfo->requestAccessCompletionCallback = completionCallback;
+
+ if (resourcePath != nullptr)
+ {
+ cbInfo->resourcePath = resourcePath;
+ }
+
+ return cbInfo;
+}
+
+CallbackInfo::Ptr Callback::CreateCallbackInfo(
+ DevicePtr device,
+ CallbackType cbType,
+ const void* context,
+ IPCADiscoverDeviceCallback discoverDeviceCallback,
+ const char* const* resourceTypeList,
+ int resourceTypeCount,
+ GenericAppCallback appCallback,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType)
+{
+ CallbackInfo::Ptr cbInfo = std::shared_ptr<CallbackInfo>(new(CallbackInfo));
+
+ if (cbInfo == nullptr)
+ {
+ return nullptr;
+ }
+
+ cbInfo->app = m_app;
+ cbInfo->device = device;
+ cbInfo->type = cbType;
+ cbInfo->callbackContext = context;
+ cbInfo->callbackInProgressCount = 0;
+ cbInfo->markedToBeRemoved = false;
+ cbInfo->requestSentTimestamp = 0;
+
+ cbInfo->resourcePath = std::string(resourcePath ? resourcePath : "");
+ cbInfo->resourceInterface = std::string(resourceInterface ? resourceInterface : "");
+ cbInfo->resourceType = std::string(resourceType ? resourceType : "");
+
+ switch (cbType)
+ {
+ case CallbackType_Discovery:
+ {
+ cbInfo->discoveryCallback = discoverDeviceCallback;
+ int i = 0;
+ while (i < resourceTypeCount)
+ {
+ cbInfo->resourceTypeList.push_back(resourceTypeList[i++]);
+ }
+ break;
+ }
+
+ case CallbackType_ResourceChange:
+ {
+ cbInfo->resourceChangeCallback= appCallback;
+ break;
+ }
+
+ case CallbackType_GetPropertiesComplete:
+ {
+ cbInfo->getCallback = appCallback;
+ break;
+ }
+
+ case CallbackType_SetPropertiesComplete:
+ {
+ cbInfo->setCallback = appCallback;
+ break;
+ }
+
+ case CallbackType_CreateResourceComplete:
+ {
+ cbInfo->createResourceCallback=
+ reinterpret_cast<IPCACreateResourceComplete>(appCallback);
+ break;
+ }
+
+ case CallbackType_DeleteResourceComplete:
+ {
+ cbInfo->deleteResourceCallback=
+ reinterpret_cast<IPCADeleteResourceComplete>(appCallback);
+ break;
+ }
+
+ default:
+ {
+ // Must be new CallbackType definition that needs new code.
+ assert(false);
+ break;
+ }
+ }
+
+ return cbInfo;
+}
+
+IPCAStatus Callback::AddCallbackInfo(CallbackInfo::Ptr cbInfo)
+{
+ std::lock_guard<std::mutex> lock(m_callbackMutex);
+
+ // App has called IPCAClose(). Stop taking CallbackInfo.
+ if (m_stopCalled == true)
+ {
+ return IPCA_FAIL;
+ }
+
+ uint32_t i = 0;
+ while (i++ < UINT32_MAX)
+ {
+ uint32_t newKey = m_nextKey++;
+ if (m_callbackInfoList.find(newKey) == m_callbackInfoList.end())
+ {
+ OIC_LOG_V(INFO, TAG, "AddCallbackInfo() with key: %d", newKey);
+ cbInfo->mapKey = newKey;
+ m_callbackInfoList[newKey] = cbInfo;
+ return IPCA_OK;
+ }
+ }
+
+ // All map entries are filled. It's a large table (32 bit)!
+ return IPCA_OUT_OF_MEMORY;
+}
+
+CallbackInfo::Ptr Callback::GetCallbackInfo(size_t mapKey)
+{
+ std::lock_guard<std::mutex> lock(m_callbackMutex);
+
+ // App has called IPCAClose().
+ if (m_stopCalled == true)
+ {
+ return nullptr;
+ }
+
+ if (m_callbackInfoList.find(mapKey) != m_callbackInfoList.end())
+ {
+ return m_callbackInfoList[mapKey];
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+CallbackInfo::Ptr Callback::GetPasswordInputCallbackInfo()
+{
+ std::lock_guard<std::mutex> lock(m_callbackMutex);
+
+ // App has called IPCAClose().
+ if (m_stopCalled == true)
+ {
+ return nullptr;
+ }
+
+ // Go through the CallbackInfo list to find the PasswordInputCallback CallbackInfo.
+ // PasswordInputCallback is only registered once by the app so there can only be one result.
+ for (auto const& entry : m_callbackInfoList)
+ {
+ if (entry.second->type == CallbackType_PasswordInputCallback)
+ {
+ return entry.second;
+ }
+ }
+
+ return nullptr;
+}
+
+bool Callback::SetCallbackInProgress(size_t mapKey)
+{
+ std::lock_guard<std::mutex> lock(m_callbackMutex);
+
+ // App has called IPCAClose(). Pending callbacks are automatically cleared.
+ if (m_stopCalled == true)
+ {
+ return false;
+ }
+
+ if (m_callbackInfoList.find(mapKey) != m_callbackInfoList.end())
+ {
+ CallbackInfo::Ptr callbackInfo = m_callbackInfoList[mapKey];
+
+ // This callback is marked for removal.
+ if (callbackInfo->markedToBeRemoved)
+ {
+ return false;
+ }
+
+ // Indicate that callback is in progress.
+ callbackInfo->callbackInProgressCount++;
+ return true;
+ }
+ else
+ {
+ // Callback handle is already closed by app.
+ return false;
+ }
+}
+
+bool Callback::ClearCallbackInProgress(size_t mapKey)
+{
+ std::lock_guard<std::mutex> lock(m_callbackMutex);
+
+ // This function does not check m_stopCalled, because any call already in progress
+ // must complete.
+ if (m_callbackInfoList.find(mapKey) != m_callbackInfoList.end())
+ {
+ m_callbackInfoList[mapKey]->callbackInProgressCount--;
+ return true;
+ }
+
+ OIC_LOG_V(INFO, TAG, "ClearCallbackInProgress() mapKey [%d] is not found", mapKey);
+ assert(false); // In progress callback is not expected to be removed from the list.
+ return false;
+}
+
+void Callback::RemoveCallbackInfo(size_t mapKey)
+{
+ std::lock_guard<std::mutex> lock(m_callbackMutex);
+
+ if (m_callbackInfoList.find(mapKey) != m_callbackInfoList.end())
+ {
+ if (m_callbackInfoList[mapKey]->callbackInProgressCount == 0)
+ {
+ m_callbackInfoList.erase(mapKey);
+ }
+ else
+ {
+ m_callbackInfoList[mapKey]->markedToBeRemoved = true;
+ }
+ }
+}
+
+void Callback::CompleteAndRemoveExpiredCallbackInfo(std::vector<CallbackInfo::Ptr>& cbInfoList)
+{
+ // @tbd: determine a good value for response timeout.
+ const int RequestTimeoutMs = 2000; // 2 seconds for request timeout.
+
+ uint64_t currentTime = OICGetCurrentTime(TIME_IN_MS);
+
+ {
+ std::lock_guard<std::mutex> lock(m_callbackMutex);
+
+ if (m_stopCalled == true)
+ {
+ return;
+ }
+
+ // Collect the expired requests.
+ for(auto const& entry : m_callbackInfoList)
+ {
+ // Opportunistic removal of callback that couldn't be removed during
+ // RemoveCallbackInfo().
+ if (entry.second->markedToBeRemoved == true)
+ {
+ cbInfoList.push_back(entry.second);
+ continue;
+ }
+
+ // Look for outstanding get, set, create requests that have been sent
+ // (time stamp is not 0), have timed out and not already in the middle of callback.
+ if ((entry.second->requestSentTimestamp != 0) &&
+ (entry.second->callbackInProgressCount == 0) &&
+ ((entry.second->type == CallbackType_GetPropertiesComplete) ||
+ (entry.second->type == CallbackType_SetPropertiesComplete) ||
+ (entry.second->type == CallbackType_CreateResourceComplete) ||
+ (entry.second->type == CallbackType_DeleteResourceComplete)))
+ {
+ if ((currentTime - entry.second->requestSentTimestamp) > RequestTimeoutMs)
+ {
+ m_expiredCallbacksInprogress++;
+ cbInfoList.push_back(entry.second);
+ }
+ }
+ }
+
+ // Remove them from the list.
+ for (auto const& entry : cbInfoList)
+ {
+ m_callbackInfoList.erase(entry->mapKey);
+ }
+ }
+
+ // Complete the callback for each.
+ for (auto const& cbInfo : cbInfoList)
+ {
+ if (cbInfo->getCallback != nullptr)
+ {
+ std::thread thrd;
+ switch(cbInfo->type)
+ {
+ case CallbackType_GetPropertiesComplete:
+ thrd = std::thread(cbInfo->getCallback,
+ IPCA_REQUEST_TIMEOUT,
+ const_cast<void*>(cbInfo->callbackContext),
+ nullptr);
+ thrd.detach();
+ break;
+
+ case CallbackType_SetPropertiesComplete:
+ thrd = std::thread(cbInfo->setCallback,
+ IPCA_REQUEST_TIMEOUT,
+ const_cast<void*>(cbInfo->callbackContext),
+ nullptr);
+ thrd.detach();
+ break;
+
+ case CallbackType_CreateResourceComplete:
+ thrd = std::thread(cbInfo->createResourceCallback,
+ IPCA_REQUEST_TIMEOUT,
+ const_cast<void*>(cbInfo->callbackContext),
+ nullptr,
+ nullptr);
+ thrd.detach();
+ break;
+
+ case CallbackType_DeleteResourceComplete:
+ thrd = std::thread(cbInfo->deleteResourceCallback,
+ IPCA_REQUEST_TIMEOUT,
+ const_cast<void*>(cbInfo->callbackContext));
+ thrd.detach();
+ break;
+
+ default:
+ assert(false); // check the filter code above to match the handling here.
+ break;
+ }
+ }
+
+ {
+ std::lock_guard<std::mutex> lock(m_callbackMutex);
+ m_expiredCallbacksInprogress--;
+ }
+ }
+
+}
+
+void Callback::GetCallbackInfoList(CallbackType type, std::vector<CallbackInfo::Ptr>& filteredList)
+{
+ std::lock_guard<std::mutex> lock(m_callbackMutex);
+
+ for(auto const& entry : m_callbackInfoList)
+ {
+ if (entry.second->type == type)
+ {
+ filteredList.push_back(entry.second);
+ }
+ }
+}
+
+bool Callback::MatchAllRequiredResourceTypes(
+ std::vector<std::string>& requiredResourceTypes,
+ std::vector<std::string>& deviceResourceTypes)
+{
+ for (auto const& targetResourceType : requiredResourceTypes)
+ {
+ if (targetResourceType.length() == 0)
+ {
+ OIC_LOG_V(INFO, TAG,
+ "MatchAllRequiredResourceTypes(): app has nullptr target function. returning true");
+ return true;
+ }
+
+ if (std::find(deviceResourceTypes.begin(),
+ deviceResourceTypes.end(),
+ targetResourceType) == deviceResourceTypes.end())
+ {
+ OIC_LOG_V(INFO, TAG,
+ "MatchAllRequiredResourceTypes(): return false. Resource Type not found: [%s]",
+ targetResourceType.c_str());
+ return false;
+ }
+ }
+
+ OIC_LOG_V(INFO, TAG, "MatchAllRequiredResourceTypes(): returning true. ");
+ return true;
+}
+
+void Callback::DeviceDiscoveryCallback(
+ bool deviceResponding,
+ bool newInfoLearntAboutDevice,
+ InternalDeviceInfo deviceInfo,
+ std::vector<std::string> deviceResourceTypeList)
+{
+ // Create IPCADiscoveredDeviceInfo object for callback.
+ IPCADiscoveredDeviceInfo deviceInfoUsedForCallback = {0};
+
+ if (deviceInfo.deviceUris.size() != 0)
+ {
+ deviceInfoUsedForCallback.deviceUris =
+ static_cast<const char**>(OICCalloc(deviceInfo.deviceUris.size(), sizeof(char*)));
+
+ if (deviceInfoUsedForCallback.deviceUris == nullptr)
+ {
+ OIC_LOG_V(WARNING, TAG, "Callback::DeviceDiscoveryCallback: out of memory.");
+ return;
+ }
+
+ int i = 0;
+ for (auto const& deviceUri : deviceInfo.deviceUris)
+ {
+ deviceInfoUsedForCallback.deviceUris[i++] = deviceUri.c_str();
+ }
+ }
+
+ deviceInfoUsedForCallback.deviceId = deviceInfo.deviceId.c_str();
+ deviceInfoUsedForCallback.deviceName = deviceInfo.deviceName.c_str();
+ deviceInfoUsedForCallback.deviceUriCount = deviceInfo.deviceUris.size();
+
+ // 2 groups of callbacks are interested in device discovery status.
+ // One is outstanding Observe requests. The other is outstanding IPCADiscoveryDevices()
+ // requests.
+
+ // Outstanding observe requests are interested in IPCA_DEVICE_APPEAR_OFFLINE.
+ if (false == deviceResponding)
+ {
+ // Call Observe callback with IPCA_DEVICE_APPEAR_OFFLINE if this is the device whose
+ // resource it is observing.
+ std::vector<CallbackInfo::Ptr> observeCallbackinfoList;
+ GetCallbackInfoList(CallbackType_ResourceChange, observeCallbackinfoList);
+
+ for(auto const& cbInfo : observeCallbackinfoList)
+ {
+ // if device id matches and not in shut down already
+ if ((cbInfo->device->GetDeviceId().compare(deviceInfo.deviceId) == 0) &&
+ (SetCallbackInProgress(cbInfo->mapKey) == true))
+ {
+ std::thread exec(
+ cbInfo->resourceChangeCallback,
+ IPCA_DEVICE_APPEAR_OFFLINE,
+ const_cast<void*>(cbInfo->callbackContext),
+ nullptr);
+ exec.detach();
+ ClearCallbackInProgress(cbInfo->mapKey);
+ }
+ }
+ }
+
+ // IPCADiscoverDevices() requests are interested in IPCADeviceStatus callback.
+ std::vector<CallbackInfo::Ptr> discoveryCallbackInfoList;
+ GetCallbackInfoList(CallbackType_Discovery, discoveryCallbackInfoList);
+
+ // Synchronize discovery callback to app to ensure IPCA_DEVICE_DISCOVERED is always first.
+ m_discoverDeviceCallbackMutex.lock();
+
+ // Callback if it matches resource types requested by app in IPCADiscoverDevices().
+ for(auto const& cbInfo : discoveryCallbackInfoList)
+ {
+ if (MatchAllRequiredResourceTypes(cbInfo->resourceTypeList, deviceResourceTypeList))
+ {
+ // Indicate that callback is in progress and call the app's callback.
+ if (SetCallbackInProgress(cbInfo->mapKey) == true)
+ {
+ m_callbackMutex.lock();
+ auto it = std::find(cbInfo->discoveredDevicesList.begin(),
+ cbInfo->discoveredDevicesList.end(),
+ deviceInfo.deviceId);
+
+ if (it == cbInfo->discoveredDevicesList.end())
+ {
+ // App has never received IPCA_DEVICE_DISCOVERED for this device.
+ if (deviceResponding) // New device for this callback if device is responding,
+ // otherwise it's a nop.
+ {
+ // Track that app receives IPCA_DEVICE_DISCOVERED callback for this device.
+ cbInfo->discoveredDevicesList.push_back(deviceInfo.deviceId);
+
+ // Release lock to call out to app.
+ m_callbackMutex.unlock();
+ (cbInfo->discoveryCallback)(const_cast<void*>(cbInfo->callbackContext),
+ IPCA_DEVICE_DISCOVERED, &deviceInfoUsedForCallback);
+ m_callbackMutex.lock();
+ }
+ }
+ else
+ {
+ // App has received IPCA_DEVICE_DISCOVERED for this device in the past.
+ if (deviceResponding)
+ {
+ // Callback to app if there's new info.
+ if (newInfoLearntAboutDevice == true)
+ {
+ m_callbackMutex.unlock();
+ (cbInfo->discoveryCallback)(const_cast<void*>(cbInfo->callbackContext),
+ IPCA_DEVICE_UPDATED_INFO, &deviceInfoUsedForCallback);
+ m_callbackMutex.lock();
+ }
+ }
+ else
+ {
+ // Remove the device from discovered device list of this callback.
+ // Next time the same device shows up, this callback will get
+ // IPCA_DEVICE_DISCOVERED.
+ cbInfo->discoveredDevicesList.erase(it);
+
+ m_callbackMutex.unlock();
+ (cbInfo->discoveryCallback)(const_cast<void*>(cbInfo->callbackContext),
+ IPCA_DEVICE_STOPPED_RESPONDING, &deviceInfoUsedForCallback);
+ m_callbackMutex.lock();
+ }
+ }
+ m_callbackMutex.unlock();
+
+ ClearCallbackInProgress(cbInfo->mapKey);
+ }
+ }
+ }
+
+ m_discoverDeviceCallbackMutex.unlock();
+
+ if (deviceInfoUsedForCallback.deviceUris != nullptr)
+ {
+ OICFree(deviceInfoUsedForCallback.deviceUris);
+ deviceInfoUsedForCallback.deviceUris = nullptr;
+ }
+}
+
+void Callback::GetCallback(IPCAStatus status, const OCRepresentation& rep, CallbackInfo::Ptr cbInfo)
+{
+ // Check if cbInfo is for this app and mark that callback in progress.
+ if ((cbInfo->app != m_app) || (SetCallbackInProgress(cbInfo->mapKey) == false))
+ {
+ return;
+ }
+
+ if (cbInfo->getCallback != nullptr)
+ {
+ cbInfo->getCallback(
+ status,
+ const_cast<void*>(cbInfo->callbackContext),
+ (IPCAPropertyBagHandle)&rep);
+ }
+
+ ClearCallbackInProgress(cbInfo->mapKey);
+ RemoveCallbackInfo(cbInfo->mapKey);
+}
+
+void Callback::SetCallback(IPCAStatus status, const OCRepresentation& rep, CallbackInfo::Ptr cbInfo)
+{
+ if ((cbInfo->app != m_app) || (SetCallbackInProgress(cbInfo->mapKey) == false))
+ {
+ return;
+ }
+
+ if (cbInfo->type == CallbackType_CreateResourceComplete)
+ {
+ cbInfo->createResourceCallback(
+ status,
+ const_cast<void*>(cbInfo->callbackContext),
+ NULL, /* tbd: no info on new resource URI. */
+ /* See https://jira.iotivity.org/browse/IOT-1819 */
+ (IPCAPropertyBagHandle)&rep);
+ }
+ else
+ {
+ cbInfo->setCallback(
+ status,
+ const_cast<void*>(cbInfo->callbackContext),
+ (IPCAPropertyBagHandle)&rep);
+ }
+
+ ClearCallbackInProgress(cbInfo->mapKey);
+ RemoveCallbackInfo(cbInfo->mapKey);
+}
+
+void Callback::ObserveCallback(IPCAStatus status,
+ const OCRepresentation& rep,
+ CallbackInfo::Ptr cbInfo)
+{
+ if ((cbInfo->app != m_app) || (SetCallbackInProgress(cbInfo->mapKey) == false))
+ {
+ return;
+ }
+
+ cbInfo->resourceChangeCallback(
+ status,
+ const_cast<void*>(cbInfo->callbackContext),
+ (IPCAPropertyBagHandle)&rep);
+
+ ClearCallbackInProgress(cbInfo->mapKey);
+}
+
+void Callback::DeleteResourceCallback(IPCAStatus status, CallbackInfo::Ptr cbInfo)
+{
+ if ((cbInfo->app != m_app) || (SetCallbackInProgress(cbInfo->mapKey) == false))
+ {
+ return;
+ }
+
+ cbInfo->deleteResourceCallback(
+ status,
+ const_cast<void*>(cbInfo->callbackContext));
+
+ ClearCallbackInProgress(cbInfo->mapKey);
+}
+
+void Callback::PasswordInputCallback(std::string deviceId,
+ IPCAOwnershipTransferType type,
+ char* passwordBuffer,
+ size_t passwordBufferSize,
+ CallbackInfo::Ptr cbInfo)
+{
+ IPCADeviceInfo* deviceInfo = nullptr;
+ IPCAPlatformInfo* platformInfo = nullptr;
+
+ if ((cbInfo->app != m_app) || (SetCallbackInProgress(cbInfo->mapKey) == false))
+ {
+ return;
+ }
+
+ IPCAStatus status = ocfFramework.CopyDeviceInfo(deviceId, &deviceInfo);
+ if (IPCA_OK == status)
+ {
+ status = ocfFramework.CopyPlatformInfo(deviceId, &platformInfo);
+ if (IPCA_OK != status)
+ {
+ OIC_LOG_V(INFO, TAG,
+ "Callback::PasswordInfoCallback: Failed to retrieve platform information.");
+ }
+ }
+ else
+ {
+ OIC_LOG_V(INFO, TAG,
+ "Callback::PasswordInfoCallback: Failed to retrieve device information.");
+ }
+
+ if (cbInfo->passwordInputCallback != nullptr)
+ {
+ cbInfo->passwordInputCallback(
+ const_cast<void*>(cbInfo->callbackContext),
+ deviceInfo,
+ platformInfo,
+ type,
+ passwordBuffer,
+ passwordBufferSize);
+ }
+
+ ClearCallbackInProgress(cbInfo->mapKey);
+
+ if (deviceInfo != nullptr)
+ {
+ OCFFramework::FreeDeviceInfo(deviceInfo);
+ deviceInfo = nullptr;
+ }
+
+ if (platformInfo != nullptr)
+ {
+ OCFFramework::FreePlatformInfo(platformInfo);
+ platformInfo = nullptr;
+ }
+}
+
+void Callback::PasswordDisplayCallback(
+ std::string deviceId,
+ IPCAOwnershipTransferType type,
+ const char* passwordBuffer,
+ CallbackInfo::Ptr cbInfo)
+{
+ if ((cbInfo->app != m_app) || (SetCallbackInProgress(cbInfo->mapKey) == false))
+ {
+ return;
+ }
+
+ if (cbInfo->passwordDisplayCallback != nullptr)
+ {
+ cbInfo->passwordDisplayCallback(
+ const_cast<void*>(cbInfo->callbackContext),
+ nullptr,
+ nullptr,
+ type,
+ passwordBuffer);
+ }
+
+ ClearCallbackInProgress(cbInfo->mapKey);
+}
+
+void Callback::RequestAccessCompletionCallback(IPCAStatus status, CallbackInfo::Ptr cbInfo)
+{
+ if ((cbInfo->app != m_app) || (SetCallbackInProgress(cbInfo->mapKey) == false))
+ {
+ return;
+ }
+
+ if (cbInfo->requestAccessCompletionCallback != nullptr)
+ {
+ cbInfo->requestAccessCompletionCallback(status, const_cast<void*>(cbInfo->callbackContext));
+ }
+
+ ClearCallbackInProgress(cbInfo->mapKey);
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include <string>
+
+#include "oic_malloc.h"
+#include "ipca.h"
+#include "ipcainternal.h"
+
+// Copy from std::string to char array. Return true if source is truncated at dest.
+bool CopyStringToBufferAllowTruncate(const std::string& source, char* dest, size_t destSize)
+{
+ if ((dest == nullptr) || (destSize == 0))
+ {
+ return false;
+ }
+
+ bool isTruncated = false;
+ size_t copied = source.copy(dest, destSize, 0);
+ if (copied == destSize)
+ {
+ copied--; // make room for null
+ isTruncated = true;
+ }
+
+ // std::string copy does not include null.
+ dest[copied] = '\0';
+ return isTruncated;
+}
+
+bool CopyStringToFlatBuffer(const std::string& source, char* dest, size_t* destBufferSize)
+{
+ if (dest == nullptr)
+ {
+ return false;
+ }
+
+ size_t sourceLength = source.length(); // excl. null.
+ if (sourceLength + 1 > *destBufferSize)
+ {
+ *destBufferSize = sourceLength + 1; // the required buffer size.
+ return false;
+ }
+
+ source.copy(dest, sourceLength, 0);
+ dest[sourceLength] = '\0';
+ return true;
+}
+
+IPCAStatus AllocateAndCopyStringToFlatBuffer(const std::string& source, char** dest)
+{
+ if (dest == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ size_t bufferSize = source.length() + 1; // incl. null.
+ *dest = static_cast<char*>(OICMalloc(bufferSize));
+ if (*dest == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ if (CopyStringToFlatBuffer(source, *dest, &bufferSize) == false)
+ {
+ OICFreeAndSetToNull(reinterpret_cast<void**>(dest));
+ return IPCA_FAIL;
+ }
+
+ return IPCA_OK;
+}
+
+IPCAStatus AllocateAndCopyStringVectorToArrayOfCharPointers(
+ const std::vector<std::string>& source,
+ char*** dest,
+ size_t* count)
+{
+ if ((count == nullptr) || (dest == nullptr))
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ size_t stringCount = source.size();
+
+ if (stringCount == 0)
+ {
+ *count = 0;
+ *dest = nullptr;
+ return IPCA_OK;
+ }
+
+ *count = stringCount;
+ *dest = static_cast<char**>(OICCalloc(stringCount, sizeof(char*)));
+ if (*dest == nullptr)
+ {
+ *count = 0;
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ size_t i = 0;
+ IPCAStatus status = IPCA_FAIL;
+ for (auto& sourceString : source)
+ {
+ status = AllocateAndCopyStringToFlatBuffer(sourceString, &((*dest)[i]));
+ if (status != IPCA_OK)
+ {
+ break;
+ }
+
+ i++;
+ }
+
+ // Rollback if any failure.
+ if (i != stringCount)
+ {
+ FreeArrayOfCharPointers(*dest, i);
+ *count = 0;
+ *dest = nullptr;
+ return status;
+ }
+
+ return IPCA_OK;
+}
+
+void FreeArrayOfCharPointers(char** array, size_t count)
+{
+ if ((array == nullptr) || (count == 0))
+ {
+ return;
+ }
+
+ for (int i = 0; i < count; i++)
+ {
+ OICFree((void*)(array[i]));
+ }
+
+ OICFree(array);
+}
+
+bool IsStringInList(const std::string& string, const std::vector<std::string>& list)
+{
+ return (std::find(list.begin(), list.end(), string) != list.end());
+}
+
+bool AddNewStringsToTargetList(const std::vector<std::string>& newList,
+ std::vector<std::string>& targetList)
+{
+ bool foundNewEntry = false;
+ for (auto const& newString : newList)
+ {
+ if (!IsStringInList(newString, targetList))
+ {
+ targetList.push_back(newString.c_str());
+ foundNewEntry = true;
+ }
+ }
+
+ return foundNewEntry;
+}
+
+void PrintMargin(size_t marginDepth)
+{
+ std::cout << std::string(3 * marginDepth, ' ');
+}
+
+template <typename _T>
+void PrintVectorValues(std::vector<_T> vector, size_t marginDepth)
+{
+ OC_UNUSED(marginDepth);
+
+ for (auto value : vector)
+ {
+ std::cout << value << std::endl;
+ }
+}
+
+void PrintOCRep(const OCRepresentation& rep, size_t marginDepth)
+{
+ OCRepresentation::const_iterator itr= rep.begin();
+ OCRepresentation::const_iterator endItr = rep.end();
+
+ PrintMargin(marginDepth);
+ std::cout << "{" << std::endl;
+ marginDepth++;
+
+ for (; itr != endItr; ++itr)
+ {
+ PrintMargin(marginDepth);
+ std::cout << "\"" << itr->attrname() << "\" : ";
+
+ switch(itr->type())
+ {
+ case AttributeType::Null:
+ std::cout << "Null" << std::endl;
+ break;
+
+ case AttributeType::Integer:
+ std::cout << (*itr).getValue<int>() << std::endl;
+ break;
+
+ case AttributeType::Double:
+ std::cout << (*itr).getValue<double>() << std::endl;
+ break;
+
+ case AttributeType::Boolean:
+ std::cout << (*itr).getValue<bool>() << std::endl;
+ break;
+
+ case AttributeType::String:
+ std::cout << "\"" << ((*itr).getValue<std::string>()).c_str() << "\"" << std::endl;
+ break;
+
+ case AttributeType::OCRepresentation:
+ {
+ OC::OCRepresentation repValue = (*itr).getValue<OC::OCRepresentation>();
+ std::cout << std::endl;
+ PrintOCRep(repValue, marginDepth);
+ break;
+ }
+
+ case AttributeType::Vector:
+ {
+ AttributeType vectorBaseType = itr->base_type();
+ std::cout << std::endl;
+ PrintMargin(marginDepth);
+ std::cout << "[" << std::endl;
+
+ if (itr->depth() != 1)
+ {
+ PrintMargin(marginDepth);
+ std::cout << "PrintOCRep works with 1 level depth vector. " << std::endl;
+ continue;
+ }
+
+ switch (vectorBaseType)
+ {
+ case AttributeType::Integer:
+ {
+ std::vector<int> vec = (*itr).getValue<std::vector<int>>();
+ PrintVectorValues(vec, marginDepth);
+ break;
+ }
+
+ case AttributeType::Double:
+ {
+ std::vector<double> vec = (*itr).getValue<std::vector<double>>();
+ PrintVectorValues(vec, marginDepth);
+ break;
+ }
+
+ case AttributeType::Boolean:
+ {
+ std::vector<bool> vec = (*itr).getValue<std::vector<bool>>();
+ PrintVectorValues(vec, marginDepth);
+ break;
+ }
+
+ case AttributeType::String:
+ {
+ std::vector<std::string> vec = (*itr).getValue<std::vector<std::string>>();
+ PrintVectorValues(vec, marginDepth);
+ break;
+ }
+
+ case AttributeType::OCRepresentation:
+ {
+ std::vector<OC::OCRepresentation> vec =
+ (*itr).getValue<std::vector<OC::OCRepresentation>>();
+ for (auto& value : vec)
+ {
+ PrintOCRep(value, (marginDepth+1));
+ }
+ break;
+ }
+
+ default:
+ PrintMargin(marginDepth);
+ std::cout << "Unhandled vector base type: " << vectorBaseType << std::endl;
+ break;
+ }
+
+ PrintMargin(marginDepth);
+ std::cout << "]" << std::endl;
+ break;
+ }
+
+ default:
+ PrintMargin(marginDepth);
+ std::cout << "Value type not handled: " << itr->type() << std::endl;
+ break;
+ }
+ }
+
+ marginDepth--;
+ PrintMargin(marginDepth);
+ std::cout << "}" << std::endl;
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "ipca.h"
+#include "ipcainternal.h"
+#include "oic_malloc.h"
+
+Device::Device(const char* deviceId, OCFFramework* ocf, App* app) :
+ m_deviceId(deviceId),
+ m_app(app),
+ m_ocfFramework(ocf),
+ m_isClosed(false)
+{
+}
+
+Device::~Device()
+{
+}
+
+IPCAStatus Device::Open()
+{
+ return m_ocfFramework->IPCADeviceOpenCalled(m_deviceId);
+}
+
+IPCAStatus Device::Close()
+{
+ m_isClosed = true;
+ return m_ocfFramework->IPCADeviceCloseCalled(m_deviceId);
+}
+
+IPCAStatus Device::GetDeviceInfo(IPCADeviceInfo** callerDeviceInfo)
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ return m_ocfFramework->CopyDeviceInfo(m_deviceId, callerDeviceInfo);
+}
+
+IPCAStatus Device::GetPlatformInfo(IPCAPlatformInfo** callerPlatformInfo)
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ return m_ocfFramework->CopyPlatformInfo(m_deviceId, callerPlatformInfo);
+}
+
+IPCAStatus Device::GetResourcePathList(const std::string& resourceInterface,
+ const std::string& resourceType,
+ char*** resourcePathList,
+ size_t* resourcePathCount)
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ *resourcePathList = nullptr;
+ *resourcePathCount = 0;
+
+ std::vector<std::string> resourcePaths;
+ IPCAStatus status = m_ocfFramework->CopyResourcePaths(
+ resourceInterface, resourceType, m_deviceId, resourcePaths);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ return AllocateAndCopyStringVectorToArrayOfCharPointers(
+ resourcePaths, resourcePathList, resourcePathCount);
+}
+
+IPCAStatus Device::GetResourceInfo(const char* resourcePath,
+ ResourceInfoType resourceInfoType,
+ char*** stringArray,
+ size_t* stringArrayCount)
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ *stringArray = nullptr;
+ *stringArrayCount = 0;
+
+ std::vector<std::string> resourceInfo;
+ std::string resURI = "";
+ if (resourcePath)
+ {
+ resURI = resourcePath;
+ }
+
+ IPCAStatus status = m_ocfFramework->CopyResourceInfo(
+ m_deviceId, resURI, resourceInfoType, resourceInfo);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ return AllocateAndCopyStringVectorToArrayOfCharPointers(
+ resourceInfo, stringArray, stringArrayCount);
+}
+
+IPCAStatus Device::GetProperties(CallbackInfo::Ptr callbackInfo)
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ return m_ocfFramework->SendCommandToDevice(m_deviceId, callbackInfo, nullptr);
+}
+
+IPCAStatus Device::SetProperties(CallbackInfo::Ptr callbackInfo, OC::OCRepresentation* rep)
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ return m_ocfFramework->SendCommandToDevice(m_deviceId, callbackInfo, rep);
+}
+
+IPCAStatus Device::CreateResource(CallbackInfo::Ptr callbackInfo, OC::OCRepresentation* rep)
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ return m_ocfFramework->SendCommandToDevice(m_deviceId, callbackInfo, rep);
+}
+
+IPCAStatus Device::DeleteResource(CallbackInfo::Ptr callbackInfo)
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ return m_ocfFramework->SendCommandToDevice(m_deviceId, callbackInfo, nullptr);
+}
+
+IPCAStatus Device::ObserveResource(CallbackInfo::Ptr callbackInfo)
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ return m_ocfFramework->SendCommandToDevice(m_deviceId, callbackInfo, nullptr);
+}
+
+void Device::StopObserve(CallbackInfo::Ptr cbInfo)
+{
+ return m_ocfFramework->StopObserve(cbInfo);
+}
+
+void Device::IsResourceObservable(const char* resourcePath, bool* isObservable)
+{
+ if (m_isClosed)
+ {
+ *isObservable = false;
+ return;
+ }
+
+ m_ocfFramework->IsResourceObservable(m_deviceId, resourcePath, isObservable);
+}
+
+IPCAStatus Device::Ping()
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ return m_ocfFramework->PingDevice(m_deviceId);
+}
+
+IPCAStatus Device::GetLastPingTime(uint64_t& lastPingTime)
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ return m_ocfFramework->GetLastPingTime(m_deviceId, lastPingTime);
+}
+
+IPCAStatus Device::RequestAccess(CallbackInfo::Ptr callbackInfo,
+ CallbackInfo::Ptr passwordInputCallbackInfo)
+{
+ if (m_isClosed)
+ {
+ return IPCA_FAIL;
+ }
+
+ return m_ocfFramework->RequestAccess(m_deviceId, callbackInfo, passwordInputCallbackInfo);
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef APP_H_
+#define APP_H_
+
+typedef std::shared_ptr<CallbackInfo> CallbackInfoPtr;
+
+// Internal version of IPCAAppInfo.
+struct IPCAAppInfoInternal
+{
+ IPCAUuid appId;
+ std::string appName;
+ std::string appSoftwareVersion;
+ std::string appCompanyName;
+};
+
+// Housekeeping for periodic discovery.
+// The lastDiscoveryTime & discoveryCount are used to schedule more frequent discovery in
+// the beginning.
+typedef struct _DiscoveryDetails
+{
+ typedef std::shared_ptr<_DiscoveryDetails> Ptr;
+ std::vector<std::string> resourceTypesToDiscover; // list of resource types
+ uint64_t lastDiscoveryTime; // last time discovery request was sent for this DiscoveryDetails.
+ size_t discoveryCount; // and how many times already.
+} DiscoveryDetails;
+
+// One App object per IPCAOpen()
+class App
+{
+ public:
+ App(const IPCAAppInfo* ipcaAppInfo, IPCAVersion ipcaVersion);
+ ~App();
+
+ // Application calls IPCAOpen()/IPCAClose().
+ IPCAStatus Start(bool unitTestMode);
+ void Stop();
+
+ // Application calls IPCADiscoverDevices().
+ IPCAStatus DiscoverDevices(
+ IPCADiscoverDeviceCallback callback,
+ const void* context,
+ const char* const* resourceTypeList,
+ int resourceTypeCount,
+ IPCAHandle* handle);
+
+ // Application calls IPCAOpenDevice().
+ IPCAStatus OpenDevice(const char* deviceId, IPCADeviceHandle* deviceHandle);
+ void CloseDevice(IPCADeviceHandle deviceHandle);
+
+ // Application calls IPCAGetProperties().
+ IPCAStatus GetProperties(
+ Device::Ptr device,
+ IPCAGetPropertiesComplete getPropertiesCb,
+ const void* context,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType,
+ IPCAHandle* handle);
+
+ // Application calls IPCASetProperties().
+ IPCAStatus SetProperties(
+ Device::Ptr device,
+ IPCAGetPropertiesComplete getPropertiesCb,
+ const void* context,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType,
+ OC::OCRepresentation* rep,
+ IPCAHandle* handle);
+
+ // Application calls IPCAObserveResource().
+ IPCAStatus ObserveResource(
+ Device::Ptr device,
+ IPCAResourceChangeCallback resourceChangeCb,
+ const void* context,
+ const char* resourcePath,
+ const char* resourceType,
+ IPCAHandle* handle);
+
+ // Application calls IPCACreateResource().
+ IPCAStatus CreateResource(
+ Device::Ptr device,
+ IPCACreateResourceComplete createResourceCb,
+ const void* context,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType,
+ OC::OCRepresentation* rep,
+ IPCAHandle* handle);
+
+ // Application calls IPCADeleteResource()
+ IPCAStatus DeleteResource(
+ Device::Ptr device,
+ IPCADeleteResourceComplete deleteResourceCb,
+ const void* context,
+ const char* resourcePath,
+ IPCAHandle* handle);
+
+ /* Security/Ownership */
+ IPCAStatus SetPasswordCallbacks(
+ IPCAProvidePasswordCallback inputCallback,
+ IPCADisplayPasswordCallback displayCallback,
+ void* context);
+
+ IPCAStatus RequestAccess(
+ Device::Ptr device,
+ const char* resourcePath,
+ IPCARequestAccessCompletionCallback completionCallback,
+ void* context,
+ IPCAHandle* handle);
+
+
+ // Close handle returned in DiscoverDevices(), GetProperties(), SetProperties(), or
+ // ObserveResource().
+ void CloseIPCAHandle(IPCAHandle handle);
+
+ private:
+ std::mutex m_appMutex;
+ volatile bool m_isStopped; // set to true when Stop() is called.
+
+ IPCAAppInfoInternal m_ipcaAppInfo;
+ IPCAVersion m_ipcaVersion; // IPCA version requested in the call to IPCAOpen().
+
+ // Object that implements callbacks to the app.
+ std::shared_ptr<Callback> m_callback;
+
+ // Devices this app opened.
+ std::map<DeviceWrapper*, DeviceWrapper*> m_openedDevices;
+
+ // Thread that performs periodic discovery.
+ std::thread m_appWorkerThread;
+ std::condition_variable m_discoveryThreadCV;
+ std::mutex m_appWorkerThreadMutex;
+
+ // Create and register CallbackInfo with the Callback object.
+ IPCAStatus CreateAndRegisterNewCallbackInfo(
+ IPCAHandle* handle,
+ Device::Ptr device,
+ CallbackInfo::Ptr* cbInfo,
+ CallbackType cbType,
+ const void* context,
+ IPCADiscoverDeviceCallback discoverDeviceCallback,
+ const char* const* resourceTypeList,
+ int resourceTypeCount,
+ GenericAppCallback appCallback,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType);
+
+ // Delete the CallbackInfo and unregister from Callback object list.
+ void DeleteAndUnregisterCallbackInfo(size_t mapKey);
+
+ // Thread performing periodic discovery.
+ static void AppWorkerThread(App* app);
+
+ // List of resource types to discover periodically.
+ // Key is cbInfo->mapKey of each IPCADiscoverDevices() request.
+ std::map<uint32_t, DiscoveryDetails::Ptr> m_discoveryList;
+
+ // Password callback registration
+ InputPinCallbackHandle m_passwordInputCallbackHandle;
+ DisplayPinCallbackHandle m_passwordDisplayCallbackHandle;
+};
+#endif // APP_H_
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef CALLBACK_H_
+#define CALLBACK_H_
+
+typedef enum
+{
+ CallbackType_Discovery = 1,
+ CallbackType_ResourceChange,
+ CallbackType_GetPropertiesComplete,
+ CallbackType_SetPropertiesComplete,
+ CallbackType_CreateResourceComplete,
+ CallbackType_DeleteResourceComplete,
+ CallbackType_PasswordInputCallback,
+ CallbackType_PasswordDisplayCallback,
+ Callbacktype_RequestAccessCompletionCallback,
+ CallbackType_InvalidType
+} CallbackType;
+
+class App;
+class Device;
+class OC::OCResource;
+typedef std::shared_ptr<Device> DevicePtr;
+
+// Structure contains information to make callbacks to app.
+struct CallbackInfo
+{
+ public:
+ CallbackInfo() { /* std::cout << "+ CallbackInfo " << this << std::endl; */ }
+ ~CallbackInfo() { /* std::cout << "- CallbackInfo " << this << " mapKey: ";
+ std::cout << mapKey << std::endl; */ }
+ typedef std::shared_ptr<CallbackInfo> Ptr;
+ size_t mapKey; // key to m_callbackInfoList map. Initialized in AddCallbackInfo().
+ App* app; // the app that creates this callback.
+ DevicePtr device; // the device expected to respond to the callback.
+ CallbackType type;
+ union
+ {
+ IPCADiscoverDeviceCallback discoveryCallback;
+ IPCAResourceChangeCallback resourceChangeCallback;
+ IPCAGetPropertiesComplete getCallback;
+ IPCASetPropertiesComplete setCallback;
+ IPCACreateResourceComplete createResourceCallback;
+ IPCADeleteResourceComplete deleteResourceCallback;
+ IPCAProvidePasswordCallback passwordInputCallback;
+ IPCADisplayPasswordCallback passwordDisplayCallback;
+ IPCARequestAccessCompletionCallback requestAccessCompletionCallback;
+ };
+ const void* callbackContext; // app's callback context.
+ std::vector<std::string> resourceTypeList; // Parameter for Discovery.
+ std::string resourcePath; // Parameters for for Get, Set, Observe request.
+ std::string resourceInterface;
+ std::string resourceType;
+ size_t callbackInProgressCount; // Non zero if callback is in progress.
+ bool markedToBeRemoved; // Set to true when this object can't be removed in
+ // RemoveCallbackInfo(). It'll be removed opportunistically.
+ std::vector<std::string> discoveredDevicesList; // List of device ids that were indicated to
+ // app with IPCA_DEVICE_DISCOVERED.
+ std::shared_ptr<OC::OCResource> ocResource; // The OCResource this callback works with.
+
+ uint64_t requestSentTimestamp; // when the request was sent to the server.
+};
+
+// Represent IPCAResourceChangeCallback, IPCAGetPropertiesComplete, IPCASetPropertiesComplete.
+typedef void (IPCA_CALL *GenericAppCallback)(IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle);
+
+// One Callback object per App. One app per IPCAOpen().
+class Callback
+{
+ public:
+ typedef std::shared_ptr<Callback> Ptr;
+ Callback(App* app);
+ ~Callback();
+
+ // Preparation to shut down.
+ // Function returns when there's no pending callback.
+ // No callback is allowed after returning from this call.
+ void Stop();
+
+ CallbackInfo::Ptr CreateCallbackInfo(
+ DevicePtr device,
+ CallbackType cbType,
+ const void* context,
+ IPCADiscoverDeviceCallback discoveryCallback,/* discovery */
+ /* callback */
+ const char* const* resourceTypeList,
+ int resourceTypeCount,
+ GenericAppCallback callback, /* get, set, observe, create &
+ delete resource callbacks */
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType);
+
+ // Password display or password input callback.
+ CallbackInfo::Ptr CreatePasswordCallbackInfo(
+ CallbackType cbType,
+ const void* context,
+ IPCAProvidePasswordCallback passwordInputCallback,
+ IPCADisplayPasswordCallback passwordDisplayCallback);
+
+ // Auth completion callback.
+ CallbackInfo::Ptr CreateRequestAccessCompletionCallbackInfo(
+ DevicePtr device,
+ const void* context,
+ const char* resourceURI,
+ IPCARequestAccessCompletionCallback completionCallback);
+
+ // Add CallbackInfo to the list of pending callbacks.
+ IPCAStatus AddCallbackInfo(CallbackInfo::Ptr cbInfo);
+
+ // Return pointer to CallbackInfo matching mapKey.
+ CallbackInfo::Ptr GetCallbackInfo(size_t mapKey);
+
+ // Return a pointer to PasswordInputCallback CallbackInfo
+ CallbackInfo::Ptr GetPasswordInputCallbackInfo();
+
+ // Remove the CallbackInfo matching mapKey. This function sets markedToBeRemoved if the
+ // callback is in the middle of calling back.
+ void RemoveCallbackInfo(size_t mapKey);
+
+ // Complete the callback for expired CallbackInfo and remove them from the
+ // m_callbackInfoList. Caller receives a list of them.
+ void CompleteAndRemoveExpiredCallbackInfo(std::vector<CallbackInfo::Ptr>& cbInfoList);
+
+ // Return a list of CallbackInfo object matching the type.
+ void GetCallbackInfoList(CallbackType type, std::vector<CallbackInfo::Ptr>& cbInfoList);
+
+ // Device discovery related.
+ void DeviceDiscoveryCallback(bool deviceResponding,
+ bool newInfoLearntAboutDevice,
+ InternalDeviceInfo deviceInfo,
+ std::vector<std::string> resourceTypes);
+
+ // resource->get() callback.
+ void GetCallback(IPCAStatus status,
+ const OC::OCRepresentation& rep,
+ CallbackInfo::Ptr cbInfo);
+
+ // resource->put() callback.
+ void SetCallback(IPCAStatus status,
+ const OC::OCRepresentation& rep,
+ CallbackInfo::Ptr cbInfo);
+
+ // resource->observe() callback.
+ void ObserveCallback(IPCAStatus status,
+ const OC::OCRepresentation& rep,
+ CallbackInfo::Ptr cbInfo);
+
+ // resource->deleteResource() callback.
+ void DeleteResourceCallback(IPCAStatus status, CallbackInfo::Ptr cbInfo);
+
+ // Security/Auth
+ void PasswordInputCallback(
+ std::string deviceId,
+ IPCAOwnershipTransferType type,
+ char* passwordBuffer,
+ size_t passwordBufferSize,
+ CallbackInfo::Ptr cbInfo);
+
+ void PasswordDisplayCallback(
+ std::string deviceId,
+ IPCAOwnershipTransferType type,
+ const char* password,
+ CallbackInfo::Ptr cbInfo);
+
+ void RequestAccessCompletionCallback(IPCAStatus status, CallbackInfo::Ptr cbInfo);
+
+ private:
+ bool MatchAllRequiredResourceTypes(std::vector<std::string>& requiredResourceTypes,
+ std::vector<std::string>& deviceResourceTypes);
+
+ private:
+ // Mutex for synchronization use.
+ std::mutex m_callbackMutex;
+
+ // Mutex used for synchronizing discovery callback to app.
+ std::mutex m_discoverDeviceCallbackMutex;
+
+ // Table of CallbackInfo. Key is autogenerated.
+ std::atomic<uint32_t> m_nextKey; // next key for the m_callbackInfoList map.
+ std::map<uint32_t, CallbackInfo::Ptr> m_callbackInfoList; // List of expected callbacks.
+ App* m_app; // Callback object is per app.
+ volatile bool m_stopCalled; // Set to true when Stop() is called.
+
+ // Number of expired callbacks in progress.
+ size_t m_expiredCallbacksInprogress;
+
+ // Indicate that callback is in progress for callbackInfo matching mapKey.
+ // Return false if the callback is already cancelled by app.
+ bool SetCallbackInProgress(size_t mapKey);
+
+ // Indicate that callback is not in progress.
+ bool ClearCallbackInProgress(size_t mapKey);
+};
+
+#endif // CALLBACK_H_
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+#if defined(_MSC_VER)
+#define ARRAY_SIZE(a) _countof(a)
+#else
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#endif
+
+// Copy the source std string to dest.
+bool CopyStringToBufferAllowTruncate(const std::string& source, char* dest, size_t destSize);
+bool CopyStringToFlatBuffer(const std::string& source, char* dest, size_t* destBufferSize);
+
+// Allocate the dest buffer and copy the source std string to dest.
+IPCAStatus AllocateAndCopyStringToFlatBuffer(const std::string& source, char** dest);
+
+// Allocate the dest buffer of string and copy from source std string to dest.
+IPCAStatus AllocateAndCopyStringVectorToArrayOfCharPointers(
+ const std::vector<std::string>& source,
+ char*** dest,
+ size_t* count);
+
+// Free array of string.
+void FreeArrayOfCharPointers(char** array, size_t count);
+
+// Return true if string is in list.
+bool IsStringInList(const std::string& string, const std::vector<std::string>& list);
+
+// Add strings in newList that is not in targetList. Return true if there's new entry added.
+bool AddNewStringsToTargetList(const std::vector<std::string>& newList,
+ std::vector<std::string>& targetList);
+
+// Same information as IPCADeviceInfo in ipca.h but with std::string.
+typedef struct
+{
+ std::string deviceId;
+ std::string platformIndependentId;
+ std::vector<std::string> deviceUris;
+ std::string deviceName;
+ std::string deviceSoftwareVersion;
+ std::vector<std::string> dataModelVersions;
+} InternalDeviceInfo;
+
+// Same information as IPCAPlatformInfo in ipca.h, but with std::string.
+typedef struct
+{
+ std::string platformId;
+ std::string manufacturerName;
+ std::string manufacturerURL;
+ std::string modelNumber;
+ std::string manufacturingDate;
+ std::string platformVersion;
+ std::string osVersion;
+ std::string hardwareVersion;
+ std::string firmwareVersion;
+ std::string manufacturerSupportURL;
+ std::string referenceTime;
+} InternalPlatformInfo;
+
+// Security information
+typedef struct
+{
+ bool subowner;
+ bool isStarted;
+ std::shared_ptr<OC::OCSecureResource> device;
+ std::thread requestAccessThread;
+ std::mutex requestAccessThreadMutex;
+ std::condition_variable requestAccessThreadCV;
+} InternalSecurityInfo;
+
+// Debug helpers
+void PrintOCRep(const OC::OCRepresentation& rep, size_t marginDepth = 0);
+#endif // COMMON_H_
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef DEVICE_H_
+#define DEVICE_H_
+
+class App;
+class OCFFramework;
+
+/* Type of resource info requested in GetResourceInfo() */
+enum class ResourceInfoType
+{
+ ResourceType,
+ ResourceInterface
+};
+
+class Device
+{
+ public:
+ typedef std::shared_ptr<Device> Ptr;
+
+ Device(const char* deviceId, OCFFramework* ocf, App* app);
+ ~Device();
+
+ App* GetApp() { return m_app; }
+ std::string GetDeviceId() { return m_deviceId; }
+
+ // Make sure OCFFramework has found this device and let it know that it's opened.
+ IPCAStatus Open();
+ IPCAStatus Close();
+
+ IPCAStatus GetDeviceInfo(IPCADeviceInfo** callerDeviceInfo);
+ IPCAStatus GetPlatformInfo(IPCAPlatformInfo** callerPlatformInfo);
+
+ // Return array of resource paths (examples of resource paths: "/oic/d", "/oem/elevator").
+ IPCAStatus GetResourcePathList(const std::string& resourceInterface,
+ const std::string& resourceType,
+ char*** resourcePathList,
+ size_t* resourcePathCount);
+
+ // Depending on resourceInfoType, return an array of:
+ // Resource types (examples of resource types: "oic.wk.d", "x.oem.elevator.status").
+ // Resource interfaces (e.g., "oic.if.baseline", "oic.if.r").
+ IPCAStatus GetResourceInfo(const char* resourcePath,
+ ResourceInfoType resourceInfoType,
+ char*** stringArray,
+ size_t* stringCount);
+
+ // Send Get request to device.
+ IPCAStatus GetProperties(CallbackInfo::Ptr callbackInfo);
+
+ // Send Post request to device.
+ IPCAStatus SetProperties(CallbackInfo::Ptr callbackInfo, OC::OCRepresentation* rep);
+
+ // Subscribe to resource change notifications.
+ IPCAStatus ObserveResource(CallbackInfo::Ptr callbackInfo);
+ void StopObserve(CallbackInfo::Ptr callbackInfo);
+ void IsResourceObservable(const char* resourcePath, bool* isObservable);
+
+ // Send Post for IPCA_RELATIVE_RESOURCE_PATH and Put for IPCA_EXPLICIT_RESOURCE_PATH.
+ IPCAStatus CreateResource(CallbackInfo::Ptr callbackInfo, OC::OCRepresentation* rep);
+
+ // Send Delete request to device.
+ IPCAStatus DeleteResource(CallbackInfo::Ptr callbackInfo);
+
+ // Ping device to determine that it's still there.
+ // If device responds, OCFFramework will update the device's lastResponseTimeToDiscovery.
+ IPCAStatus Ping();
+ IPCAStatus GetLastPingTime(uint64_t& lastPingTime);
+
+ // Request access to a device
+ IPCAStatus RequestAccess(CallbackInfo::Ptr callbackInfo,
+ CallbackInfo::Ptr passwordInputCallbackInfo);
+
+ private:
+ IPCAStatus ToArrayOfCharPointers(std::vector<std::string>& stringList,
+ char*** callerPointer, size_t* arraySize);
+
+ private:
+ std::string m_deviceId; // from IPCAOpenDevice()
+ App* m_app;
+ OCFFramework* m_ocfFramework;
+ bool m_isClosed; // set to true after Close().
+};
+
+// returned as IPCAHandle to the app.
+typedef struct
+{
+ App* app;
+ Device::Ptr device;
+} DeviceWrapper;
+
+#endif // DEVICE_H_
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef IPCA_INTERNAL_H_
+#define IPCA_INTERNAL_H_
+
+#include <mutex>
+#include <array>
+#include <string>
+#include <vector>
+#include <atomic>
+#include <map>
+#include <memory>
+#include <condition_variable>
+
+#include <stdbool.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include "OCPlatform.h"
+#include "OCApi.h"
+#include "OCProvisioningManager.hpp"
+#include "logger.h"
+
+#include "oic_malloc.h"
+#include "ipca.h"
+#include "common.h"
+#include "callback.h"
+#include "device.h"
+#include "ocfframework.h"
+#include "app.h"
+
+#endif // IPCA_INTERNAL_H_
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef OCF_FRAMEWORK_H_
+#define OCF_FRAMEWORK_H_
+
+using namespace OC;
+
+struct IPCAAppInfoInternal;
+
+// Map's key is resource path obtained from resource->uri() (e.g.: /oic/d).
+typedef std::map<std::string, std::shared_ptr<OCResource>> ResourceMap;
+
+// Some information about an OCF device.
+typedef struct DeviceDetails
+{
+ typedef std::shared_ptr<DeviceDetails> Ptr;
+
+ // Value is set to value returned by OICGetCurrentTime(TIME_IN_MS).
+ uint64_t lastResponseTimeToDiscovery;
+
+ // Indicate device not responding 1 time.
+ bool deviceNotRespondingIndicated;
+
+ // How many IPCAOpenDevice() on this device.
+ size_t deviceOpenCount;
+
+ // Timestamp of final close.
+ uint64_t lastCloseDeviceTime;
+
+ // Timestamp of last ping call to device.
+ uint64_t lastPingTime;
+
+ // Device ID in OnResourceFound().
+ std::string deviceId;
+
+ // Device Uri in OnResourceFound(). A device can have multiple device uris
+ // (e.g. ipv4 and ipv6).
+ std::vector<std::string> deviceUris;
+
+ // Device info
+ size_t deviceInfoRequestCount; // Number of requests sent for /oic/d
+ bool deviceInfoAvailable;
+ InternalDeviceInfo deviceInfo;
+
+ // Platform info
+ size_t platformInfoRequestCount; // Number of requests sent for /oic/p
+ bool platformInfoAvailable;
+ InternalPlatformInfo platformInfo;
+
+ // Maintenance resource.
+ size_t maintenanceResourceRequestCount; // Number of requests sent for /oic/mnt
+ bool maintenanceResourceAvailable; // Set to true if device returns resource for rt: oic.wk.mnt.
+
+ // Security Info
+ bool securityInfoAvailable;
+ InternalSecurityInfo securityInfo;
+
+ // List of resources, not necessarily complete list, depending on the resource type requested
+ // in the discovery.
+ ResourceMap resourceMap;
+
+ // List of resource types, not necessarily a complete list, depending on the resource type
+ // in discovery.
+ std::vector<std::string> discoveredResourceTypes;
+
+ // List of resource interfaces, not necessarily a complete list, depending on the resource
+ // type in discovery.
+ std::vector<std::string> discoveredResourceInterfaces;
+} DeviceDetails;
+
+typedef struct RequestAccessContext
+{
+ std::string deviceId;
+ OCFFramework* ocfFramework;
+ CallbackInfo::Ptr callbackInfo;
+ CallbackInfo::Ptr passwordInputCallbackInfo;
+} RequestAccessContext;
+
+// Implements OCF related functions.
+class OCFFramework
+{
+ public:
+ OCFFramework();
+ ~OCFFramework();
+
+ // When app calls IPCAOpen()/IPCAClose().
+ IPCAStatus Start(const IPCAAppInfoInternal& ipcaAppInfo, bool isUnitTestMode);
+ IPCAStatus Stop(InputPinCallbackHandle passwordInputCallbackHandle,
+ DisplayPinCallbackHandle passwordDisplayCallbackHandle);
+
+ IPCAStatus RegisterAppCallbackObject(Callback::Ptr cb);
+ void UnregisterAppCallbackObject(Callback::Ptr cb);
+
+ // Discover on network, resources that match resource type.
+ IPCAStatus DiscoverResources(std::vector<std::string>& resourceTypeList);
+
+ // Discover all the resources for specific device.
+ IPCAStatus DiscoverAllResourcesGivenHost(std::string deviceUri);
+
+ // App calls IPCAOpenDevice() on deviceId.
+ IPCAStatus IPCADeviceOpenCalled(std::string& deviceId);
+ IPCAStatus IPCADeviceCloseCalled(std::string& deviceId);
+
+ // Information pertaining to the device.
+ IPCAStatus CopyDeviceInfo(std::string& deviceId, IPCADeviceInfo** callerDeviceInfo);
+ IPCAStatus CopyPlatformInfo(std::string& deviceId, IPCAPlatformInfo** callerPlatformInfo);
+ static void FreeDeviceInfo(IPCADeviceInfo* deviceInfo);
+ static void FreePlatformInfo(IPCAPlatformInfo* platformInfo);
+
+ // Resource and resource information.
+ IPCAStatus CopyResourcePaths(
+ const std::string& resourceInterface,
+ const std::string& resourceType,
+ std::string& deviceId,
+ std::vector<std::string>& resourcePathList);
+
+ IPCAStatus CopyResourceInfo(
+ const std::string& deviceId,
+ const std::string& resourcePath,
+ ResourceInfoType resourceInfoType,
+ std::vector<std::string>& resourceInfo);
+
+ // Get/Set/Observe requests.
+ IPCAStatus OCFFramework::SendCommandToDevice(
+ std::string& deviceId,
+ CallbackInfo::Ptr callbackInfo,
+ OCRepresentation* rep);
+
+ IPCAStatus GetProperties(std::string& deviceId, CallbackInfo::Ptr callbackInfo);
+
+ IPCAStatus SetProperties(std::string& deviceId,
+ CallbackInfo::Ptr callbackInfo,
+ OCRepresentation* rep);
+
+ IPCAStatus CreateResource(std::string& deviceId,
+ CallbackInfo::Ptr callbackInfo,
+ OCRepresentation* rep);
+
+ IPCAStatus StartObserve(std::string& deviceId, CallbackInfo::Ptr callbackInfo);
+ void StopObserve(CallbackInfo::Ptr callbackInfo);
+
+ void IsResourceObservable(std::string& deviceId,
+ const char* resourcePath,
+ bool* isObservable);
+
+ // Ping specific device for the given resource type.
+ // The function sends oic/res request with rt = oic.wk.d.
+ IPCAStatus PingDevice(std::string& deviceId);
+ IPCAStatus GetLastPingTime(std::string& deviceId, uint64_t& lastPingTime);
+
+ // Security requests.
+ IPCAStatus SetInputPasswordCallback(CallbackInfo::Ptr callbackInfo,
+ InputPinCallbackHandle* passwordInputCallbackHandle);
+
+ IPCAStatus SetDisplayPasswordCallback(CallbackInfo::Ptr callbackInfo,
+ DisplayPinCallbackHandle* passwordDisplayCallbackHandle);
+
+ IPCAStatus RequestAccess(std::string& deviceId,
+ CallbackInfo::Ptr callbackInfo,
+ CallbackInfo::Ptr passwordInputCallbackInfo);
+
+ private:
+ // Callback from OCF for OCResource->get()
+ void OnObserve(const HeaderOptions headerOptions,
+ const OCRepresentation &rep,
+ const int &eCode,
+ const int &sequenceNumber,
+ CallbackInfo::Ptr callbackInfo);
+
+ void OnGet(const HeaderOptions& headerOptions,
+ const OCRepresentation& rep,
+ const int eCode,
+ CallbackInfo::Ptr callbackInfo);
+
+ void OnDelete(const HeaderOptions& headerOptions,
+ const int eCode,
+ CallbackInfo::Ptr callbackInfo);
+
+ void OnPostPut(const HeaderOptions& headerOptions,
+ const OCRepresentation& rep,
+ const int eCode,
+ CallbackInfo::Ptr callbackInfo);
+
+ // Callback from OCF when a resource is found.
+ void OnResourceFound(std::shared_ptr<OCResource> resource);
+
+ // Callback from OCF for requested device info.
+ void OnDeviceInfoCallback(const OCRepresentation& rep);
+
+ // Callback from OCF for requested platform info.
+ void OnPlatformInfoCallback(const OCRepresentation& rep);
+
+ // Callback from OCF for MOT completion
+ void OnMultipleOwnershipTransferCompleteCallback(PMResultList_t* result,
+ bool error,
+ std::string deviceId,
+ CallbackInfo::Ptr callbackInfo);
+
+ // Callback from OCF for password input
+ void OnPasswordInputCallback(OicUuid_t deviceId,
+ char* passwordBuffer,
+ size_t passwordBufferSize,
+ CallbackInfo::Ptr callbackInfo);
+
+ // Callback from OCF to display a password
+ void OnPasswordDisplayCallback(char* passwordBuffer,
+ size_t passwordBufferSize,
+ CallbackInfo::Ptr callbackInfo);
+
+ // A device is formed when all its device info and platform info are known.
+ IPCAStatus GetCommonResources(DeviceDetails::Ptr deviceDetails);
+
+ // See m_workerThread variable below.
+ static void WorkerThread(OCFFramework* ocfFramework);
+
+ // Entry point for the thread that will request access to a device.
+ static void RequestAccessWorkerThread(RequestAccessContext* requestContext);
+
+ // Get DeviceDetails for devieId.
+ IPCAStatus FindDeviceDetails(const std::string& deviceId,
+ DeviceDetails::Ptr& deviceDetails);
+
+ // Get the first OCResource that implements the resource type.
+ std::shared_ptr<OCResource> FindOCResource(const DeviceDetails::Ptr& deviceDetails,
+ const std::string& resourcePath,
+ const std::string& resourceType);
+
+ // Cleanup RequestAccess calls
+ void CleanupRequestAccessDevices();
+
+ // Some helper functions to help debugging.
+ void DebugOutputOCFDevices();
+ void DebugOutputOCRep(const OCRepresentation& rep);
+
+ private:
+ // Lock for sync access to protected members in OCFFramework.
+ std::recursive_mutex m_OCFFrameworkMutex;
+
+ // A list of devices and their resources.
+ // Key to the map is device ID (which is a UUID)
+ std::map<std::string, DeviceDetails::Ptr> m_OCFDevices;
+
+ // Fast look up for DeviceDetails given device's URI.
+ // Key to the map is device URI (e.g., "coap://[fe80::5828:93a8:d53e:4222%7]:62744").
+ // A device may have multiple URIs (e.g., ipv4 and ipv6).
+ std::map<std::string, DeviceDetails::Ptr> m_OCFDevicesIndexedByDeviceURI;
+
+ // A list of RequestAccess contexts.
+ // Key to the map is the device ID (which is a UUID)
+ std::map<std::string, RequestAccessContext*> m_OCFRequestAccessContexts;
+
+ // One Callback per App. One App per IPCAOpen().
+ std::vector<Callback::Ptr> m_callbacks;
+ std::thread m_workerThread;
+ std::condition_variable m_workerThreadCV;
+ std::mutex m_workerThreadMutex;
+
+ // Synchronize Start()/Stop()
+ std::mutex m_startStopMutex;
+ bool m_isStarted;
+ bool m_isStopping;
+};
+#endif // OCF_FRAMEWORK_H_
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "oic_malloc.h"
+#include "ipca.h"
+#include "ipcainternal.h"
+
+#define OCFFactoryReset "fr"
+#define OCFReboot "rb"
+
+// As in proc there's no reason for multiple IPCAOpen().
+// There's no ref count for g_app. Therefore must hold g_ipcaAppMutex when using g_app.
+App* g_app = nullptr;
+std::mutex g_ipcaAppMutex;
+
+bool g_unitTestMode = false;
+
+IPCAStatus IPCA_CALL IPCAOpen(const IPCAAppInfo* ipcaAppInfo,
+ IPCAVersion ipcaVersion,
+ IPCAAppHandle* ipcaAppHandle)
+{
+ std::lock_guard<std::mutex> lock(g_ipcaAppMutex);
+
+ if (ipcaVersion != IPCA_VERSION_1)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ if (g_app != nullptr)
+ {
+ return IPCA_ALREADY_OPENED;
+ }
+
+ if (ipcaAppInfo == nullptr ||
+ ipcaAppInfo->appName == nullptr ||
+ ipcaAppInfo->appSoftwareVersion == nullptr ||
+ ipcaAppInfo->appCompanyName == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ g_app= new App(ipcaAppInfo, ipcaVersion);
+
+ if (g_app == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ IPCAStatus status = g_app->Start(g_unitTestMode);
+ if (status != IPCA_OK)
+ {
+ delete g_app;
+ g_app = nullptr;
+ return status;
+ }
+
+ *ipcaAppHandle = reinterpret_cast<IPCAAppHandle>(g_app);
+ return IPCA_OK;
+}
+
+void IPCA_CALL IPCAClose(IPCAAppHandle ipcaAppHandle)
+{
+ App* app = reinterpret_cast<App*>(ipcaAppHandle);
+ std::lock_guard<std::mutex> lock(g_ipcaAppMutex);
+ if (g_app == nullptr)
+ {
+ return;
+ }
+
+ app->Stop();
+ delete app;
+ g_app = nullptr;
+}
+
+IPCAStatus IPCA_CALL IPCADiscoverDevices(IPCAAppHandle ipcaAppHandle,
+ IPCADiscoverDeviceCallback callback,
+ void* context,
+ const char* const* resourceTypeList,
+ int resourceTypeCount,
+ IPCAHandle* handle)
+{
+ App* app = reinterpret_cast<App*>(ipcaAppHandle);
+ return app->DiscoverDevices(callback, context, resourceTypeList, resourceTypeCount, handle);
+}
+
+IPCAStatus IPCA_CALL IPCAOpenDevice(IPCAAppHandle ipcaAppHandle,
+ const char* deviceId,
+ IPCADeviceHandle* deviceHandle)
+{
+ App* app = reinterpret_cast<App*>(ipcaAppHandle);
+ return app->OpenDevice(deviceId, deviceHandle);
+}
+
+void IPCA_CALL IPCACloseDevice(IPCADeviceHandle deviceHandle)
+{
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ App* app = deviceWrapper->device->GetApp();
+ app->CloseDevice(deviceHandle);
+}
+
+IPCAStatus IPCAGetDeviceInfo(IPCADeviceHandle deviceHandle, IPCADeviceInfo** deviceInfo)
+{
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ return deviceWrapper->device->GetDeviceInfo(deviceInfo);
+}
+
+void IPCAFreeDeviceInfo(IPCADeviceInfo* deviceInfo)
+{
+ OCFFramework::FreeDeviceInfo(deviceInfo);
+}
+
+IPCAStatus IPCAGetPlatformInfo(IPCADeviceHandle deviceHandle, IPCAPlatformInfo** platformInfo)
+{
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ return deviceWrapper->device->GetPlatformInfo(platformInfo);
+}
+
+void IPCAFreePlatformInfo(IPCAPlatformInfo* platformInfo)
+{
+ OCFFramework::FreePlatformInfo(platformInfo);
+}
+
+IPCAStatus IPCA_CALL IPCAGetResources(IPCADeviceHandle deviceHandle,
+ const char* resourceInterface,
+ const char* resourceType,
+ char*** resourcePathList,
+ size_t* resourcePathCount)
+{
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ return deviceWrapper->device->GetResourcePathList(
+ std::string(resourceInterface ? resourceInterface : ""),
+ std::string(resourceType ? resourceType : ""),
+ resourcePathList,
+ resourcePathCount);
+}
+
+IPCAStatus IPCA_CALL IPCAGetResourceTypes(IPCADeviceHandle deviceHandle,
+ const char* resourcePath,
+ char*** resourceTypeList,
+ size_t* resourceTypeCount)
+{
+ DeviceWrapper* deviceWrapper = (DeviceWrapper*)deviceHandle;
+ return deviceWrapper->device->GetResourceInfo(resourcePath,
+ ResourceInfoType::ResourceType, resourceTypeList, resourceTypeCount);
+}
+
+IPCAStatus IPCA_CALL IPCAGetResourceInterfaces(IPCADeviceHandle deviceHandle,
+ const char* resourcePath,
+ char*** resourceInterfaceList,
+ size_t* resourceInterfaceCount)
+{
+ DeviceWrapper* deviceWrapper = (DeviceWrapper*)deviceHandle;
+ return deviceWrapper->device->GetResourceInfo(resourcePath,
+ ResourceInfoType::ResourceInterface, resourceInterfaceList, resourceInterfaceCount);
+}
+
+void IPCA_CALL IPCAFreeStringArray(char** stringArray, size_t stringCount)
+{
+ FreeArrayOfCharPointers(stringArray, stringCount);
+}
+
+IPCAStatus IPCA_CALL IPCAGetProperties(IPCADeviceHandle deviceHandle,
+ IPCAGetPropertiesComplete getPropertiesCb,
+ void* context,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType,
+ IPCAHandle* handle)
+{
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ return deviceWrapper->app->GetProperties(
+ deviceWrapper->device,
+ getPropertiesCb,
+ context,
+ resourcePath,
+ resourceInterface,
+ resourceType,
+ handle);
+}
+
+IPCAStatus IPCA_CALL IPCASetProperties(IPCADeviceHandle deviceHandle,
+ IPCASetPropertiesComplete setPropertiesCb,
+ void* context,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType,
+ IPCAPropertyBagHandle propertyBagHandle,
+ IPCAHandle* handle)
+{
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ return deviceWrapper->app->SetProperties(
+ deviceWrapper->device,
+ setPropertiesCb,
+ context,
+ resourcePath,
+ resourceInterface,
+ resourceType,
+ (OC::OCRepresentation*)propertyBagHandle,
+ handle);
+}
+
+void IPCA_CALL IPCAIsResourceObservable(IPCADeviceHandle deviceHandle,
+ const char* resourcePath,
+ bool* isObservable)
+{
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ deviceWrapper->device->IsResourceObservable(resourcePath, isObservable);
+ return;
+}
+
+IPCAStatus IPCA_CALL IPCAObserveResource(IPCADeviceHandle deviceHandle,
+ IPCAResourceChangeCallback resourceChangeCb,
+ void* context,
+ const char* resourcePath,
+ const char* resourceType,
+ IPCAHandle* handle)
+{
+ if (handle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ return deviceWrapper->app->ObserveResource(
+ deviceWrapper->device,
+ resourceChangeCb,
+ context,
+ resourcePath,
+ resourceType,
+ handle);
+}
+
+IPCAStatus IPCA_CALL IPCACreateResource(IPCADeviceHandle deviceHandle,
+ IPCACreateResourceComplete createResourceCb,
+ void* context,
+ const char* resourcePath,
+ const char* resourceInterface,
+ const char* resourceType,
+ IPCAPropertyBagHandle propertyBagHandle,
+ IPCAHandle* handle)
+{
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ return deviceWrapper->app->CreateResource(
+ deviceWrapper->device,
+ createResourceCb,
+ context,
+ resourcePath,
+ resourceInterface,
+ resourceType,
+ (OC::OCRepresentation*)propertyBagHandle,
+ handle);
+}
+
+IPCAStatus IPCA_CALL IPCADeleteResource(IPCADeviceHandle deviceHandle,
+ IPCADeleteResourceComplete deleteResourceCb,
+ void* context,
+ const char* resourcePath,
+ IPCAHandle* handle)
+{
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ return deviceWrapper->app->DeleteResource(
+ deviceWrapper->device,
+ deleteResourceCb,
+ context,
+ resourcePath,
+ handle);
+}
+
+void IPCA_CALL IPCACloseHandle(IPCAHandle handle)
+{
+ std::lock_guard<std::mutex> lock(g_ipcaAppMutex);
+ if (g_app != nullptr)
+ {
+ g_app->CloseIPCAHandle(handle);
+ }
+}
+
+typedef struct
+{
+ std::mutex syncMutex;
+ std::condition_variable condVar;
+ IPCAStatus result;
+} AsyncContext;
+
+void AsyncCallback(IPCAStatus result, void* context, IPCAPropertyBagHandle propertyBagHandle)
+{
+ OC_UNUSED(propertyBagHandle);
+
+ AsyncContext* async = reinterpret_cast<AsyncContext*>(context);
+ async->result = result;
+ async->condVar.notify_all();
+}
+
+IPCAStatus IPCA_CALL IPCAFactoryReset(IPCADeviceHandle deviceHandle)
+{
+ IPCAStatus status;
+
+ AsyncContext factoryResetContext;
+ std::unique_lock<std::mutex> lock { factoryResetContext.syncMutex };
+
+ IPCAPropertyBagHandle propertyBagHandle;
+ status = IPCAPropertyBagCreate(&propertyBagHandle);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ status = IPCAPropertyBagSetValueBool(propertyBagHandle, OCFFactoryReset, true);
+ if (status != IPCA_OK)
+ {
+ IPCAPropertyBagDestroy(propertyBagHandle);
+ return status;
+ }
+
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ status = deviceWrapper->app->SetProperties(
+ deviceWrapper->device,
+ &AsyncCallback,
+ &factoryResetContext,
+ nullptr,
+ nullptr,
+ OC_RSRVD_RESOURCE_TYPE_MAINTENANCE,
+ (OC::OCRepresentation*)propertyBagHandle,
+ nullptr);
+
+ if (status == IPCA_OK)
+ {
+ factoryResetContext.condVar.wait_for(lock, std::chrono::milliseconds{ INT_MAX });
+ IPCAPropertyBagDestroy(propertyBagHandle);
+ return factoryResetContext.result;
+ }
+
+ IPCAPropertyBagDestroy(propertyBagHandle);
+ return status;
+}
+
+IPCAStatus IPCA_CALL IPCAReboot(IPCADeviceHandle deviceHandle)
+{
+ IPCAStatus status;
+
+ AsyncContext rebootContext;
+ std::unique_lock<std::mutex> lock { rebootContext.syncMutex };
+
+ IPCAPropertyBagHandle propertyBagHandle;
+ status = IPCAPropertyBagCreate(&propertyBagHandle);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ status = IPCAPropertyBagSetValueBool(propertyBagHandle, OCFReboot, true);
+ if (status != IPCA_OK)
+ {
+ IPCAPropertyBagDestroy(propertyBagHandle);
+ return status;
+ }
+
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ status = deviceWrapper->app->SetProperties(
+ deviceWrapper->device,
+ &AsyncCallback,
+ &rebootContext,
+ nullptr,
+ nullptr,
+ OC_RSRVD_RESOURCE_TYPE_MAINTENANCE,
+ (OC::OCRepresentation*)propertyBagHandle,
+ nullptr);
+
+ if (status == IPCA_OK)
+ {
+ rebootContext.condVar.wait_for(lock, std::chrono::milliseconds{ INT_MAX });
+ IPCAPropertyBagDestroy(propertyBagHandle);
+ return rebootContext.result;
+ }
+
+ IPCAPropertyBagDestroy(propertyBagHandle);
+ return status;
+}
+
+IPCAStatus IPCA_CALL IPCASetPasswordCallbacks(IPCAAppHandle ipcaAppHandle,
+ IPCAProvidePasswordCallback inputCallback,
+ IPCADisplayPasswordCallback displayCallback,
+ void* context)
+{
+ App* app = reinterpret_cast<App*>(ipcaAppHandle);
+ return app->SetPasswordCallbacks(inputCallback, displayCallback, context);
+}
+
+IPCAStatus IPCA_CALL IPCARequestAccess(IPCADeviceHandle deviceHandle,
+ const char* resourcePath,
+ IPCARequestAccessCompletionCallback completionCallback,
+ void* context,
+ IPCAHandle* handle)
+{
+ DeviceWrapper* deviceWrapper = reinterpret_cast<DeviceWrapper*>(deviceHandle);
+ return deviceWrapper->app->RequestAccess(
+ deviceWrapper->device,
+ resourcePath,
+ completionCallback,
+ context,
+ handle);
+}
+
+/*********************/
+/* Utility functions */
+/*********************/
+
+void IPCA_CALL IPCASetUnitTestMode()
+{
+ g_unitTestMode = true;
+}
--- /dev/null
+LIBRARY ipca
+
+EXPORTS
+
+IPCAClose
+IPCACloseDevice
+IPCACloseHandle
+IPCACreateResource
+IPCADiscoverDevices
+IPCADeleteResource
+IPCAFactoryReset
+IPCAFreeDeviceInfo
+IPCAFreePlatformInfo
+IPCAFreeStringArray
+IPCAGetProperties
+IPCAGetDeviceInfo
+IPCAGetResourceInterfaces
+IPCAGetResourceTypes
+IPCAGetPlatformInfo
+IPCAGetResources
+IPCAIsResourceObservable
+IPCAObserveResource
+IPCAOpen
+IPCAOpenDevice
+IPCAReboot
+IPCASetProperties
+
+; Property bag functions
+
+IPCAPropertyBagCreate
+IPCAPropertyBagDestroy
+
+IPCAPropertyBagFreeBoolArray
+IPCAPropertyBagFreeDoubleArray
+IPCAPropertyBagFreeIntArray
+IPCAPropertyBagFreeIPCAValueTypeArray
+IPCAPropertyBagFreeString
+IPCAPropertyBagFreeStringArray
+IPCAPropertyBagFreePropertyBagArray
+
+IPCAPropertyBagGetAllKeyValuePairs
+IPCAPropertyBagGetResourcePath
+IPCAPropertyBagGetValueBool
+IPCAPropertyBagGetValueBoolArray
+IPCAPropertyBagGetValueDouble
+IPCAPropertyBagGetValueDoubleArray
+IPCAPropertyBagGetValueInt
+IPCAPropertyBagGetValueIntArray
+IPCAPropertyBagGetValuePropertyBag
+IPCAPropertyBagGetValuePropertyBagArray
+IPCAPropertyBagGetValueString
+IPCAPropertyBagGetValueStringArray
+
+IPCAPropertyBagSetValueBool
+IPCAPropertyBagSetValueBoolArray
+IPCAPropertyBagSetValueDouble
+IPCAPropertyBagSetValueDoubleArray
+IPCAPropertyBagSetValueInt
+IPCAPropertyBagSetValueIntArray
+IPCAPropertyBagSetValuePropertyBag
+IPCAPropertyBagSetValuePropertyBagArray
+IPCAPropertyBagSetValueString
+IPCAPropertyBagSetValueStringArray
+
+; Security
+
+IPCASetPasswordCallbacks
+IPCARequestAccess
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include <string>
+
+#include "oic_malloc.h"
+#include "ipca.h"
+#include "ipcainternal.h"
+
+#define TAG "IPCA_Variant"
+
+IPCAStatus IPCAPropertyBagCreate(IPCAPropertyBagHandle* propertyBagHandle)
+{
+ OC::OCRepresentation* rep = new OC::OCRepresentation();
+
+ if (rep == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ *propertyBagHandle = reinterpret_cast<IPCAPropertyBagHandle>(rep);
+ return IPCA_OK;
+}
+
+void IPCAPropertyBagDestroy(IPCAPropertyBagHandle propertyBagHandle)
+{
+ delete(reinterpret_cast<OC::OCRepresentation*>(propertyBagHandle));
+}
+
+template <typename _T>
+IPCAStatus IPCAPropertySetValue(IPCAPropertyBagHandle propertyBagHandle, const char* key, _T value)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ try
+ {
+ (reinterpret_cast<OC::OCRepresentation*>(propertyBagHandle))->setValue(key, value);
+ return IPCA_OK;
+ }
+ catch (std::exception &e)
+ {
+ OC_UNUSED(e);
+ OIC_LOG_V(WARNING, TAG, e.what());
+ return IPCA_FAIL;
+ }
+}
+
+IPCAStatus IPCAPropertyBagSetValueInt(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ int value)
+{
+ return IPCAPropertySetValue(propertyBagHandle, key, value);
+}
+
+IPCAStatus IPCAPropertyBagSetValueDouble(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ double value)
+{
+ return IPCAPropertySetValue(propertyBagHandle, key, value);
+}
+
+IPCAStatus IPCAPropertyBagSetValueBool(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ bool value)
+{
+ return IPCAPropertySetValue(propertyBagHandle, key, value);
+}
+
+IPCAStatus IPCAPropertyBagSetValueString(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const char* value)
+{
+ std::string valueString = value;
+ return IPCAPropertySetValue(propertyBagHandle, key, valueString);
+}
+
+IPCAStatus IPCAPropertyBagSetValuePropertyBag(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const IPCAPropertyBagHandle value)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ OC::OCRepresentation* ocRep = reinterpret_cast<OC::OCRepresentation*>(propertyBagHandle);
+
+ try
+ {
+ (*ocRep)[key] = *(reinterpret_cast<OC::OCRepresentation*>(value));
+ return IPCA_OK;
+ }
+ catch (std::exception &e)
+ {
+ OC_UNUSED(e);
+ OIC_LOG_V(WARNING, TAG, e.what());
+ return IPCA_FAIL;
+ }
+}
+
+template <typename _T>
+IPCAStatus IPCAPropertyBagSetValueArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const _T* valueArray,
+ size_t arrayCount)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ OC::OCRepresentation* ocRep = reinterpret_cast<OC::OCRepresentation*>(propertyBagHandle);
+
+ std::vector<_T> array;
+ for (int i = 0; i < arrayCount; i++)
+ {
+ array.insert(array.end(), valueArray[i]);
+ }
+
+ try
+ {
+ (*ocRep)[key] = array;
+ return IPCA_OK;
+ }
+ catch (std::exception &e)
+ {
+ OC_UNUSED(e);
+ OCLog(WARNING, TAG, e.what());
+ return IPCA_FAIL;
+ }
+}
+
+IPCAStatus IPCAPropertyBagSetValueIntArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const int* valueArray,
+ size_t arrayCount)
+{
+ return IPCAPropertyBagSetValueArray(propertyBagHandle, key, valueArray, arrayCount);
+}
+
+IPCAStatus IPCAPropertyBagSetValueDoubleArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const double* valueArray,
+ size_t arrayCount)
+{
+ return IPCAPropertyBagSetValueArray(propertyBagHandle, key, valueArray, arrayCount);
+
+}
+
+IPCAStatus IPCAPropertyBagSetValueBoolArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const bool* valueArray,
+ size_t arrayCount)
+{
+ return IPCAPropertyBagSetValueArray(propertyBagHandle, key, valueArray, arrayCount);
+}
+
+IPCAStatus IPCAPropertyBagSetValueStringArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const char** valueArray,
+ size_t arrayCount)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ OC::OCRepresentation* ocRep = reinterpret_cast<OC::OCRepresentation*>(propertyBagHandle);
+
+ std::vector<std::string> array;
+ for (int i = 0; i < arrayCount; i++)
+ {
+ array.insert(array.end(), valueArray[i]);
+ }
+
+ try
+ {
+ (*ocRep)[key] = array;
+ return IPCA_OK;
+ }
+ catch (std::exception &e)
+ {
+ OC_UNUSED(e);
+ OIC_LOG_V(WARNING, TAG, e.what());
+ return IPCA_FAIL;
+ }
+}
+
+IPCAStatus IPCAPropertyBagSetValuePropertyBagArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ const IPCAPropertyBagHandle* valueArray,
+ size_t valueCount)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ OC::OCRepresentation* ocRep = reinterpret_cast<OC::OCRepresentation*>(propertyBagHandle);
+
+ std::vector<OC::OCRepresentation> ocRepArray;
+ for (int i = 0; i < valueCount; i++)
+ {
+ ocRepArray.insert(ocRepArray.end(),
+ *(reinterpret_cast<OC::OCRepresentation*>((valueArray[i]))));
+ }
+
+ try
+ {
+ (*ocRep)[key] = ocRepArray;
+ return IPCA_OK;
+ }
+ catch (std::exception &e)
+ {
+ OC_UNUSED(e);
+ OIC_LOG_V(WARNING, TAG, e.what());
+ return IPCA_FAIL;
+ }
+}
+
+template <typename _T>
+IPCAStatus AllocateAndCopyTypeVectorToArrayOfType(std::vector<_T> array, _T** dest, size_t* count)
+{
+ _T* buffer;
+ size_t arraySize = array.size();
+ buffer = static_cast<_T*>(OICCalloc(arraySize, sizeof(_T)));
+ if (buffer == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ int i = 0;
+ for (auto x : array)
+ {
+ buffer[i] = x;
+ i++;
+ }
+
+ *dest = buffer;
+ *count = arraySize;
+
+ return IPCA_OK;
+}
+
+template <typename _T>
+IPCAStatus IPCAPropertyBagGetValueArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key, _T** value,
+ size_t* valueCount)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ std::vector<_T> array;
+
+ if ((reinterpret_cast<const OC::OCRepresentation*>(propertyBagHandle))->getValue(key, array) == false)
+ {
+ return IPCA_FAIL;
+ }
+
+ return AllocateAndCopyTypeVectorToArrayOfType(array, value, valueCount);
+}
+
+IPCAStatus IPCAPropertyBagGetValueIntArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ int** value,
+ size_t* valueCount)
+{
+ return IPCAPropertyBagGetValueArray(propertyBagHandle, key, value, valueCount);
+}
+
+void IPCAPropertyBagFreeIntArray(int* valueArray)
+{
+ OICFree((void*)valueArray);
+}
+
+IPCAStatus IPCAPropertyBagGetValueDoubleArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ double** value,
+ size_t* valueCount)
+{
+ return IPCAPropertyBagGetValueArray(propertyBagHandle, key, value, valueCount);
+}
+
+void IPCAPropertyBagFreeDoubleArray(double* valueArray)
+{
+ OICFree((void*)valueArray);
+}
+
+IPCAStatus IPCAPropertyBagGetValueBoolArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ bool** value,
+ size_t* valueCount)
+{
+ return IPCAPropertyBagGetValueArray(propertyBagHandle, key, value, valueCount);
+}
+
+void IPCAPropertyBagFreeBoolArray(bool* valueArray)
+{
+ OICFree((void*)valueArray);
+}
+
+IPCAStatus IPCAPropertyBagGetValueStringArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ char*** value,
+ size_t* valueCount)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ std::vector<std::string> array;
+
+ if ((reinterpret_cast<const OC::OCRepresentation*>
+ (propertyBagHandle))->getValue(key, array) == false)
+ {
+ return IPCA_FAIL;
+ }
+
+ return AllocateAndCopyStringVectorToArrayOfCharPointers(array, value, valueCount);
+}
+
+void IPCAPropertyBagFreeStringArray(char** valueArray, size_t valueCount)
+{
+ FreeArrayOfCharPointers(valueArray, valueCount);
+}
+
+IPCAStatus IPCAPropertyBagGetValuePropertyBagArray(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ IPCAPropertyBagHandle** value,
+ size_t* count)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ std::vector<OC::OCRepresentation> array;
+
+ if ((reinterpret_cast<const OC::OCRepresentation*>
+ (propertyBagHandle))->getValue(key, array) == false)
+ {
+ return IPCA_FAIL;
+ }
+
+ if (count == nullptr || value == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ size_t ocrepCount = array.size();
+
+ if (ocrepCount == 0)
+ {
+ *count = 0;
+ *value = nullptr;
+ return IPCA_OK;
+ }
+
+ *count = ocrepCount;
+ *value = static_cast<IPCAPropertyBagHandle*>
+ (OICCalloc(ocrepCount, sizeof(IPCAPropertyBagHandle)));
+ if (*value == nullptr)
+ {
+ *count = 0;
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ int i = 0;
+ IPCAStatus status = IPCA_FAIL;
+ for (auto& ocrep : array)
+ {
+ IPCAPropertyBagHandle newPropertyBag;
+ status = IPCAPropertyBagCreate(&newPropertyBag);
+ if (status != IPCA_OK)
+ {
+ break;
+ }
+
+ *(OC::OCRepresentation*)newPropertyBag = ocrep;
+ (*value)[i] = newPropertyBag;
+ i++;
+ }
+
+ // rollback if any failure.
+ if (i != ocrepCount)
+ {
+ for (int x = 0; x < i; x++)
+ {
+ IPCAPropertyBagDestroy(*value[x]);
+ }
+ OICFree((void*)(*value));
+ *count = 0;
+ *value = nullptr;
+ return status;
+ }
+
+ return IPCA_OK;
+}
+
+void IPCAPropertyBagFreePropertyBagArray(IPCAPropertyBagHandle* valueArray, size_t valueCount)
+{
+ for (int i = 0; i < valueCount; i++)
+ {
+ IPCAPropertyBagDestroy(valueArray[i]);
+ }
+
+ OICFree(valueArray);
+}
+
+IPCAStatus IPCAPropertyBagGetValueInt(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ int* value)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ if ((reinterpret_cast<const OC::OCRepresentation*>
+ (propertyBagHandle))->getValue(key, *value) == false)
+ {
+ return IPCA_FAIL;
+ }
+
+ return IPCA_OK;
+}
+
+IPCAStatus IPCAPropertyBagGetValueDouble(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ double* value)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ if ((reinterpret_cast<const OC::OCRepresentation*>
+ (propertyBagHandle))->getValue(key, *value) == false)
+ {
+ return IPCA_FAIL;
+ }
+
+ return IPCA_OK;
+}
+
+IPCAStatus IPCAPropertyBagGetValueBool(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ bool* value)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ if ((reinterpret_cast<const OC::OCRepresentation*>
+ (propertyBagHandle))->getValue(key, *value) == false)
+ {
+ return IPCA_FAIL;
+ }
+
+ return IPCA_OK;
+}
+
+IPCAStatus IPCAPropertyBagGetValueString(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ char** buffer)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ std::string stringValue;
+ if ((reinterpret_cast<const OC::OCRepresentation*>
+ (propertyBagHandle))->getValue(key, stringValue) == false)
+ {
+ return IPCA_FAIL;
+ }
+
+ return AllocateAndCopyStringToFlatBuffer(stringValue, buffer);
+}
+
+void IPCAPropertyBagFreeString(char* buffer)
+{
+ OICFree(static_cast<void*>(buffer));
+}
+
+IPCAStatus IPCAPropertyBagGetValuePropertyBag(IPCAPropertyBagHandle propertyBagHandle,
+ const char* key,
+ IPCAPropertyBagHandle* value)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ OC::OCRepresentation* rep = new OC::OCRepresentation();
+ if (rep == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ if ((reinterpret_cast<const OC::OCRepresentation*>
+ (propertyBagHandle))->getValue(key, *rep) == false)
+ {
+ delete rep;
+ return IPCA_FAIL;
+ }
+
+ *value = (IPCAPropertyBagHandle)rep;
+ return IPCA_OK;
+}
+
+IPCAStatus IPCAPropertyBagGetResourcePath(IPCAPropertyBagHandle propertyBagHandle,
+ char** resourcePath)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ return AllocateAndCopyStringToFlatBuffer(
+ (reinterpret_cast<const OC::OCRepresentation*>(propertyBagHandle))->getUri(),
+ resourcePath);
+}
+
+IPCAValueType AttributeTypeToIPCAValueType(AttributeType type)
+{
+ IPCAValueType ipcaValueType;
+
+ switch(type)
+ {
+ case AttributeType::Integer:
+ ipcaValueType = IPCA_INTEGER;
+ break;
+
+ case AttributeType::Double:
+ ipcaValueType = IPCA_DOUBLE;
+ break;
+
+ case AttributeType::Boolean:
+ ipcaValueType = IPCA_BOOLEAN;
+ break;
+
+ case AttributeType::String:
+ ipcaValueType = IPCA_STRING;
+ break;
+
+ case AttributeType::OCRepresentation:
+ ipcaValueType = IPCA_PROPERTY_BAG;
+ break;
+
+ case AttributeType::Vector:
+ ipcaValueType = IPCA_ARRAY;
+ break;
+
+ case AttributeType::Binary:
+ ipcaValueType = IPCA_ARRAY;
+ break;
+
+ case AttributeType::OCByteString:
+ ipcaValueType = IPCA_ARRAY;
+ break;
+
+ default:
+ ipcaValueType = IPCA_VALUE_TYPE_NOT_SUPPORTED;
+ break;
+ }
+
+ return ipcaValueType;
+}
+
+IPCAStatus IPCAPropertyBagGetAllKeyValuePairs(IPCAPropertyBagHandle propertyBagHandle,
+ char*** keys,
+ IPCAValueType** valueTypes,
+ size_t* count)
+{
+ if (propertyBagHandle == nullptr)
+ {
+ return IPCA_INVALID_ARGUMENT;
+ }
+
+ OC::OCRepresentation* rep = (reinterpret_cast<OC::OCRepresentation*>(propertyBagHandle));
+
+ size_t propertyCount = rep->numberOfAttributes();
+
+ std::vector<std::string> repKeys;
+ std::vector<IPCAValueType> repValueTypes;
+
+ OCRepresentation::const_iterator itr= rep->begin();
+ OCRepresentation::const_iterator endItr = rep->end();
+ for(; itr!=endItr; ++itr)
+ {
+ repKeys.push_back(itr->attrname());
+ repValueTypes.push_back(AttributeTypeToIPCAValueType(itr->type()));
+ }
+
+ IPCAStatus status = AllocateAndCopyStringVectorToArrayOfCharPointers(repKeys, keys, count);
+
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ status = AllocateAndCopyTypeVectorToArrayOfType(repValueTypes, valueTypes, count);
+
+ if (status != IPCA_OK)
+ {
+ FreeArrayOfCharPointers(*keys, propertyCount);
+ *keys = nullptr;
+ *count = 0;
+ return status;
+ }
+
+ return status;
+}
+
+void IPCAPropertyBagFreeIPCAValueTypeArray(IPCAValueType* valueArray)
+{
+ OICFree((void*)valueArray);
+}
+
+void IPCAPropertyBagDebugDump(IPCAPropertyBagHandle propertyBagHandle)
+{
+ OC::OCRepresentation* rep = (reinterpret_cast<OC::OCRepresentation*>(propertyBagHandle));
+ PrintOCRep(*rep);
+}
\ No newline at end of file
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "ipcainternal.h"
+
+using namespace std;
+using namespace std::placeholders;
+
+#include "oic_malloc.h"
+#include "oic_time.h"
+#include "ocapi.h"
+#include "pinoxmcommon.h"
+#include "srmutility.h"
+#include "ocrandom.h"
+
+#define TAG "IPCA_OcfFramework"
+#define DO_DEBUG 0
+
+const unsigned short c_discoveryTimeout = 5; // Max number of seconds to discover
+ // security information for a device
+
+// Initialize Persistent Storage for security database
+FILE* server_fopen(const char *path, const char *mode)
+{
+ return fopen(path, mode);
+}
+
+OCPersistentStorage ps = {server_fopen, fread, fwrite, fclose, unlink};
+
+OCFFramework::OCFFramework() :
+ m_isStarted(false),
+ m_isStopping(false)
+{
+}
+
+OCFFramework::~OCFFramework()
+{
+}
+
+IPCAStatus OCFFramework::Start(const IPCAAppInfoInternal& appInfo, bool isUnitTestMode)
+{
+ std::lock_guard<std::mutex> lock(m_startStopMutex);
+
+ if (m_isStarted)
+ {
+ // it's already started.
+ return IPCA_OK;
+ }
+
+ PlatformConfig Configuration {
+ ServiceType::InProc,
+ ModeType::Both, // Server mode is required for security provisioning.
+ "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
+ 0, // Uses randomly available port
+ QualityOfService::NaQos,
+ &ps};
+
+ OCPlatform::Configure(Configuration);
+
+ // Initialize the database that will be used for provisioning
+ if (OCSecure::provisionInit("") != OC_STACK_OK)
+ {
+ OIC_LOG_V(FATAL, TAG, "Failed provisionInit()");
+ return IPCA_FAIL;
+ }
+
+ // Device Info.
+ char deviceName[256];
+ char deviceSoftwareVersion[256];
+ char manufacturerName[256];
+ OCStringLL types { nullptr, nullptr }; // no vertical resource type.
+
+ CopyStringToBufferAllowTruncate(
+ appInfo.appName, deviceName, ARRAY_SIZE(deviceName));
+ CopyStringToBufferAllowTruncate(
+ appInfo.appSoftwareVersion, deviceSoftwareVersion, ARRAY_SIZE(deviceSoftwareVersion));
+ CopyStringToBufferAllowTruncate(
+ appInfo.appCompanyName, manufacturerName, ARRAY_SIZE(manufacturerName));
+
+ OCDeviceInfo deviceInfo = { deviceName, &types, deviceSoftwareVersion, nullptr };
+
+ // Platform Info
+ IPCAUuid platformUUID;
+ char platformId[UUID_STRING_SIZE] = { 0 };
+ char platformManufacturerName[256] = "";
+ char manufacturerUrl[256] = "";
+ char modelNumber[] = "";
+ char dateManufacture[] = "";
+ char platformVersion[] = "";
+ char osVersion[] = "";
+ char hardwareVersion[] = "";
+ char firmwareVersion[] = "";
+ char supportURL[] = "";
+
+#if defined(_WIN32)
+ // @todo: generate per platform UUID (e.g. using input such as hostname).
+ platformUUID = {0xd9, 0x9c, 0x23, 0x50, 0xd9, 0x5e, 0x11, 0xe6,
+ 0xbf, 0x26, 0xce, 0xc0, 0xc9, 0x32, 0xce, 0x01};
+ std::string platformName = "Microsoft";
+ std::string platformUrl = "http://www.microsoft.com";
+#else
+ platformUUID = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+ std::string platformName = "";
+ std::string platformUrl = "";
+#endif
+
+ CopyStringToBufferAllowTruncate(platformName,
+ platformManufacturerName, ARRAY_SIZE(platformManufacturerName));
+
+ CopyStringToBufferAllowTruncate(platformUrl,
+ manufacturerUrl, ARRAY_SIZE(manufacturerUrl));
+
+ OCConvertUuidToString(platformUUID.uuid, platformId);
+
+ OCPlatformInfo platformInfo = {
+ platformId,
+ platformManufacturerName,
+ manufacturerUrl,
+ modelNumber,
+ dateManufacture,
+ platformVersion,
+ osVersion,
+ hardwareVersion,
+ firmwareVersion,
+ supportURL,
+ nullptr};
+
+ if (!isUnitTestMode)
+ {
+ if (OC_STACK_OK != OCPlatform::registerPlatformInfo(platformInfo))
+ {
+ return IPCA_FAIL;
+ }
+
+ if (OC_STACK_OK != OCPlatform::registerDeviceInfo(deviceInfo))
+ {
+ return IPCA_FAIL;
+ }
+ }
+
+ // Start the worker thread that performs periodic check on device status.
+ m_workerThread = std::thread(&OCFFramework::WorkerThread, this);
+ m_isStarted = true;
+ return IPCA_OK;
+}
+
+IPCAStatus OCFFramework::Stop(InputPinCallbackHandle passwordInputCallbackHandle,
+ DisplayPinCallbackHandle passwordDisplayCallbackHandle)
+{
+ std::lock_guard<std::mutex> lock(m_startStopMutex);
+
+ if (m_isStarted == false)
+ {
+ // not started yet.
+ return IPCA_OK;
+ }
+
+ CleanupRequestAccessDevices();
+
+ OCSecure::deregisterInputPinCallback(passwordInputCallbackHandle);
+ OCSecure::deregisterDisplayPinCallback(passwordDisplayCallbackHandle);
+
+
+ m_isStopping = true;
+
+ m_workerThreadCV.notify_all();
+ if (m_workerThread.joinable())
+ {
+ m_workerThread.join();
+ }
+
+// @future: OCFFramework can't shut down because there's no cancellation for all underlying apis
+// like OCPlatform::findResource, etc.
+#if 0
+ m_OCFDevices.clear();
+ m_OCFDevicesIndexedByDeviceURI.clear();
+#endif
+
+ m_isStopping = false;
+ m_isStarted = false;
+
+ return IPCA_OK;
+}
+
+void OCFFramework::WorkerThread(OCFFramework* ocfFramework)
+{
+ std::unique_lock<std::mutex> workerThreadLock(ocfFramework->m_workerThreadMutex);
+
+ const size_t WorkerThreadSleepTimeSeconds = 2;
+ std::chrono::seconds workerThreadSleepTime(WorkerThreadSleepTimeSeconds);
+
+ while (false == ocfFramework->m_isStopping)
+ {
+ uint64_t currentTime = OICGetCurrentTime(TIME_IN_MS);
+ std::vector<DeviceDetails::Ptr> devicesThatAreNotResponding;
+ std::vector<DeviceDetails::Ptr> devicesThatAreNotOpened;
+ std::vector<DeviceDetails::Ptr> devicesToGetCommonResources;
+
+ // Collect devices that are not used, i.e. discovered a while back and those that are not
+ // used by app for a while.
+ {
+ std::lock_guard<std::recursive_mutex> lock(ocfFramework->m_OCFFrameworkMutex);
+ const unsigned int AllowedTimeSincLastCloseMs = 300000;
+ const unsigned int AllowedTimeSinceLastDiscoveryResponseMs = 60000;
+
+ // Walk through each device.
+ for (auto const& device : ocfFramework->m_OCFDevices)
+ {
+ // Is device opened by app?
+ if ((device.second->deviceOpenCount == 0) &&
+ (currentTime - device.second->lastCloseDeviceTime > AllowedTimeSincLastCloseMs))
+ {
+ devicesThatAreNotOpened.push_back(device.second);
+ continue; // device details is about to be deleted.
+ }
+
+ // Has device responded to Discovery?
+ if ((device.second->deviceNotRespondingIndicated == false) &&
+ (currentTime - device.second->lastResponseTimeToDiscovery > AllowedTimeSinceLastDiscoveryResponseMs))
+ {
+ device.second->deviceNotRespondingIndicated = true;
+ devicesThatAreNotResponding.push_back(device.second);
+ }
+
+ // Are there common resources that are not yet obtained.
+ if (!device.second->deviceInfoAvailable ||
+ !device.second->platformInfoAvailable ||
+ !device.second->maintenanceResourceAvailable)
+ {
+ devicesToGetCommonResources.push_back(device.second);
+ }
+ }
+
+ // Erase unopened devices from the m_OCFDevices.
+ for (auto& device : devicesThatAreNotOpened)
+ {
+ for (auto const& deviceUri : ocfFramework->m_OCFDevices[device->deviceId]->deviceUris)
+ {
+ ocfFramework->m_OCFDevicesIndexedByDeviceURI.erase(deviceUri);
+ }
+
+ ocfFramework->m_OCFDevices.erase(device->deviceId);
+ OIC_LOG_V(INFO, TAG, "Device deleted from m_OCFDevices: %s",
+ device->deviceId.c_str());
+ }
+ }
+
+ // Get common resources.
+ for (const auto& device : devicesToGetCommonResources)
+ {
+ ocfFramework->GetCommonResources(device);
+ }
+
+ // Make a snapshot of all callbacks.
+ std::vector<Callback::Ptr> callbackSnapshot;
+ {
+ std::lock_guard<std::recursive_mutex> lock(ocfFramework->m_OCFFrameworkMutex);
+ callbackSnapshot = ocfFramework->m_callbacks;
+ }
+
+ // Callback to apps.
+ for (const auto& device : devicesThatAreNotResponding)
+ {
+ for (const auto& callback : callbackSnapshot)
+ {
+ callback->DeviceDiscoveryCallback(
+ false, /* device is no longer responding to discovery */
+ false,
+ device->deviceInfo,
+ device->discoveredResourceTypes);
+ }
+ }
+
+ ocfFramework->m_workerThreadCV.wait_for(
+ workerThreadLock,
+ workerThreadSleepTime,
+ [ocfFramework]() { return ocfFramework->m_isStopping; });
+ }
+}
+
+
+IPCAStatus OCFFramework::IPCADeviceOpenCalled(std::string& deviceId)
+{
+ // Has the app discovered the device?
+ DeviceDetails::Ptr deviceDetails;
+ IPCAStatus status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status != IPCA_OK)
+ {
+ return IPCA_DEVICE_NOT_DISCOVERED;
+ }
+
+ deviceDetails->deviceOpenCount++;
+ return IPCA_OK;
+}
+
+IPCAStatus OCFFramework::IPCADeviceCloseCalled(std::string& deviceId)
+{
+ // Has the app discovered the device?
+ DeviceDetails::Ptr deviceDetails;
+ IPCAStatus status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status != IPCA_OK)
+ {
+ return IPCA_DEVICE_NOT_DISCOVERED;
+ }
+
+ {
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+ if (--deviceDetails->deviceOpenCount == 0)
+ {
+ deviceDetails->lastCloseDeviceTime = OICGetCurrentTime(TIME_IN_MS);
+ }
+ }
+
+ assert(deviceDetails->deviceOpenCount >= 0);
+ return IPCA_OK;
+}
+
+IPCAStatus OCFFramework::RegisterAppCallbackObject(Callback::Ptr cb)
+{
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+ m_callbacks.push_back(cb);
+ return IPCA_OK;
+}
+
+void OCFFramework::UnregisterAppCallbackObject(Callback::Ptr cb)
+{
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+ for (size_t i = 0 ; i < m_callbacks.size() ; i++)
+ {
+ if (m_callbacks[i] == cb)
+ {
+ m_callbacks.erase(m_callbacks.begin() + i);
+ break;
+ }
+ }
+}
+
+void OCFFramework::OnResourceFound(std::shared_ptr<OCResource> resource)
+{
+ bool newDevice = false; // set to true if the resource is from new device.
+ bool updatedDeviceInformation = false; // set to true when device information is updated
+ // (e.g. new resource, new resource type, etc.)
+
+ OIC_LOG_V(INFO, TAG, "OCFFramework::OnResourceFound: sid: [%s] uri[%s]",
+ resource->sid().c_str(), resource->uri().c_str());
+
+ std::string resourcePath = resource->uri();
+ DeviceDetails::Ptr deviceDetails;
+
+ {
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+
+ // Create new DeviceDetails if it's a newly found device id.
+ if (m_OCFDevices.find(resource->sid()) == m_OCFDevices.end())
+ {
+ // New device.
+ newDevice = true;
+ deviceDetails = std::shared_ptr<DeviceDetails>(new DeviceDetails());
+ if (deviceDetails == nullptr)
+ {
+ OIC_LOG_V(WARNING, TAG, "OnResourceFound:: out of memory.");
+ return; // system is out of memory, this device won't show up in app.
+ }
+
+ deviceDetails->deviceId = resource->sid();
+ deviceDetails->deviceInfoRequestCount = 0;
+ deviceDetails->deviceInfoAvailable = false; // set to true in OnDeviceInfoCallback()
+ deviceDetails->platformInfoRequestCount = 0;
+ deviceDetails->platformInfoAvailable = false; // set to true in OnPlatformInfoCallback()
+ deviceDetails->maintenanceResourceRequestCount = 0;
+ deviceDetails->maintenanceResourceAvailable = false;
+ deviceDetails->securityInfoAvailable = false; // set to true in
+ // RequestAccessWorkerThread()
+ deviceDetails->securityInfo.isStarted = false; // set to true in RequestAccess()
+ deviceDetails->deviceOpenCount = 0;
+ deviceDetails->lastPingTime = 0;
+
+ // Device is not opened at this time.
+ deviceDetails->lastCloseDeviceTime = OICGetCurrentTime(TIME_IN_MS);
+
+ // Device ID is known at this time.
+ deviceDetails->deviceInfo.deviceId = resource->sid();
+
+ // Add to list of devices.
+ m_OCFDevices[resource->sid()] = deviceDetails;
+
+ OIC_LOG_V(INFO, TAG, "Added device ID: [%s]", resource->sid().c_str());
+ OIC_LOG_V(INFO, TAG, "m_OCFDevices count = [%d]", m_OCFDevices.size());
+ }
+
+ // Populate the details about the device.
+ deviceDetails = m_OCFDevices[resource->sid()];
+
+ // Device is discovered.
+ deviceDetails->deviceNotRespondingIndicated = false;
+ deviceDetails->lastResponseTimeToDiscovery = OICGetCurrentTime(TIME_IN_MS);
+
+ if (deviceDetails->resourceMap.find(resourcePath) == deviceDetails->resourceMap.end())
+ {
+ updatedDeviceInformation = true; // new resource.
+ }
+
+ // Add (or replace with this latest) resource for the resource path.
+ deviceDetails->resourceMap[resourcePath] = resource;
+
+ // Add the device uri if it's new.
+ if (std::find(deviceDetails->deviceUris.begin(),
+ deviceDetails->deviceUris.end(),
+ resource->host()) == deviceDetails->deviceUris.end())
+ {
+ deviceDetails->deviceUris.push_back(resource->host());
+ m_OCFDevicesIndexedByDeviceURI[resource->host()] = deviceDetails;
+ updatedDeviceInformation = true; // new device uri.
+ }
+
+ // Add the resource types to global list of this device. Overlapped resource types among
+ // resources will be collapsed.
+ if (AddNewStringsToTargetList(resource->getResourceTypes(),
+ deviceDetails->discoveredResourceTypes))
+ {
+ updatedDeviceInformation = true; // new resource type.
+ }
+
+ if (AddNewStringsToTargetList(resource->getResourceInterfaces(),
+ deviceDetails->discoveredResourceInterfaces))
+ {
+ updatedDeviceInformation = true; // new resource interface.
+ }
+ }
+
+ if (newDevice)
+ {
+ // Discover all the resources of this device.
+ DiscoverAllResourcesGivenHost(resource->host());
+
+ // Get device & platform info for the new device URI.
+ GetCommonResources(deviceDetails);
+ }
+
+ // Inform apps. If new device, the device info may come in subsequent discovery callbacks with
+ // IPCA_DEVICE_UPDATED_INFO status. Make a snapshot of all callbacks.
+ std::vector<Callback::Ptr> callbackSnapshot;
+ {
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+ callbackSnapshot = m_callbacks;
+ }
+
+ // Indicate discovery to apps.
+ for (const auto& callback : callbackSnapshot)
+ {
+ callback->DeviceDiscoveryCallback(
+ true,
+ updatedDeviceInformation,
+ deviceDetails->deviceInfo,
+ deviceDetails->discoveredResourceTypes);
+ }
+
+
+ DebugOutputOCFDevices();
+
+}
+
+IPCAStatus OCFFramework::DiscoverAllResourcesGivenHost(std::string hostAddress)
+{
+ std::ostringstream resourceUri;
+ OCConnectivityType connectivityType = CT_DEFAULT;
+
+ // Request for all resources.
+ resourceUri << OC_RSRVD_WELL_KNOWN_URI;
+ OCStackResult result = OCPlatform::findResource(
+ hostAddress,
+ resourceUri.str(),
+ connectivityType,
+ std::bind(&OCFFramework::OnResourceFound, this, _1));
+
+ if (result != OC_STACK_OK)
+ {
+ return IPCA_FAIL;
+ }
+
+ return IPCA_OK;
+}
+
+IPCAStatus OCFFramework::DiscoverResources(std::vector<std::string>& resourceTypeList)
+{
+ for (auto& resourceType : resourceTypeList)
+ {
+ std::ostringstream resourceUri;
+ OCConnectivityType connectivityType = CT_DEFAULT;
+
+ resourceUri << OC_RSRVD_WELL_KNOWN_URI;
+
+ if (resourceType != "")
+ {
+ resourceUri << "?rt=" << resourceType;
+ }
+
+ OCStackResult result = OCPlatform::findResource(
+ "",
+ resourceUri.str(),
+ connectivityType,
+ std::bind(&OCFFramework::OnResourceFound, this, _1));
+
+ if (result != OC_STACK_OK)
+ {
+ return IPCA_FAIL;
+ }
+ }
+
+ return IPCA_OK;
+}
+
+void OCFFramework::OnDeviceInfoCallback(const OCRepresentation& rep)
+{
+ DeviceDetails::Ptr deviceDetails;
+
+ {
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+
+ if (m_OCFDevicesIndexedByDeviceURI.find(rep.getHost()) == m_OCFDevicesIndexedByDeviceURI.end())
+ {
+ OIC_LOG_V(WARNING, TAG,
+ "OCFFramework::OnDeviceInfoCallback: Unknown device URI: [%s]",
+ rep.getHost().c_str());
+ return;
+ }
+
+ deviceDetails = m_OCFDevicesIndexedByDeviceURI[rep.getHost()];
+ OCFFramework::DebugOutputOCRep(rep);
+
+ if (deviceDetails == nullptr)
+ {
+ return; // there's no longer interest in this information.
+ }
+
+ if (deviceDetails->deviceInfoAvailable == true)
+ {
+ return; // device info was processed before.
+ }
+
+ // Not reading "di" because it's already known in OnResourceFound().
+ std::array<std::string, 3> keys = { {"n", "icv", "dmv"} };
+ std::string dataModelVersion;
+ std::vector<std::string*> Values =
+ {
+ &(deviceDetails->deviceInfo.deviceName),
+ &(deviceDetails->deviceInfo.deviceSoftwareVersion),
+ &dataModelVersion
+ };
+
+ for (size_t i = 0; i < keys.size(); i++)
+ {
+ rep.getValue(keys[i], *Values[i]);
+ }
+
+ // Add the device uri if it's new.
+ if (std::find(deviceDetails->deviceUris.begin(),
+ deviceDetails->deviceUris.end(),
+ rep.getHost()) == deviceDetails->deviceUris.end())
+ {
+ deviceDetails->deviceUris.push_back(rep.getHost());
+ m_OCFDevicesIndexedByDeviceURI[rep.getHost()] = deviceDetails;
+ }
+
+ deviceDetails->deviceInfo.deviceUris = deviceDetails->deviceUris;
+
+ OCPlatform::getPropertyValue(
+ PAYLOAD_TYPE_DEVICE,
+ OC_RSRVD_DATA_MODEL_VERSION,
+ deviceDetails->deviceInfo.dataModelVersions);
+
+ OCPlatform::getPropertyValue(
+ PAYLOAD_TYPE_DEVICE,
+ OC_RSRVD_PROTOCOL_INDEPENDENT_ID,
+ deviceDetails->deviceInfo.platformIndependentId);
+
+ deviceDetails->deviceInfoAvailable = true;
+ }
+
+ // Inform apps.
+ // Make a snapshot of all callbacks.
+ std::vector<Callback::Ptr> callbackSnapshot;
+ {
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+ callbackSnapshot = m_callbacks;
+ }
+
+ // Indicate discovery to apps.
+ for (const auto& callback : callbackSnapshot)
+ {
+ callback->DeviceDiscoveryCallback(
+ true, /* device is responding */
+ true, /* this is an updated device info */
+ deviceDetails->deviceInfo,
+ deviceDetails->discoveredResourceTypes);
+ }
+
+ DebugOutputOCFDevices();
+}
+
+void OCFFramework::OnPlatformInfoCallback(const OCRepresentation& rep)
+{
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+
+ OCFFramework::DebugOutputOCRep(rep);
+
+ if (m_OCFDevicesIndexedByDeviceURI.find(rep.getHost()) == m_OCFDevicesIndexedByDeviceURI.end())
+ {
+ OIC_LOG_V(WARNING, TAG, "OCFFramework::OnDeviceInfoCallback: Unknown device URI: [%s]",
+ rep.getHost().c_str());
+ return;
+ }
+
+ DeviceDetails::Ptr deviceDetails = m_OCFDevicesIndexedByDeviceURI[rep.getHost()];
+
+ if (deviceDetails == nullptr)
+ {
+ return; // there's no longer interest in this information.
+ }
+
+ if (deviceDetails->platformInfoAvailable == true)
+ {
+ return; // multiple platform info received.
+ }
+
+ std::array<std::string, 11> keys =
+ {
+ {"pi", "mnmn", "mnml", "mnmo", "mndt", "mnpv", "mnos", "mnhw", "mnfv", "mnsl", "st"}
+ };
+
+ std::vector<std::string*> Values =
+ {
+ &(deviceDetails->platformInfo.platformId),
+ &(deviceDetails->platformInfo.manufacturerName),
+ &(deviceDetails->platformInfo.manufacturerURL),
+ &(deviceDetails->platformInfo.modelNumber),
+ &(deviceDetails->platformInfo.manufacturingDate),
+ &(deviceDetails->platformInfo.platformVersion),
+ &(deviceDetails->platformInfo.osVersion),
+ &(deviceDetails->platformInfo.hardwareVersion),
+ &(deviceDetails->platformInfo.firmwareVersion),
+ &(deviceDetails->platformInfo.manufacturerSupportURL),
+ &(deviceDetails->platformInfo.referenceTime)
+ };
+
+ for (size_t i = 0; i < keys.size(); i++)
+ {
+ rep.getValue(keys[i], *Values[i]);
+ }
+
+ deviceDetails->platformInfoAvailable = true;
+ DebugOutputOCFDevices();
+}
+
+IPCAStatus OCFFramework::GetCommonResources(DeviceDetails::Ptr deviceDetails)
+{
+ const int MAX_REQUEST_COUNT = 3;
+
+ OCStackResult result;
+
+ // Get platform info if device hasn't responded to earlier request.
+ if ((deviceDetails->platformInfoAvailable == false) &&
+ (deviceDetails->platformInfoRequestCount < MAX_REQUEST_COUNT))
+ {
+ // Use host address of oic/p if the resource is returned by oic/res.
+ std::string platformResourcePath(OC_RSRVD_PLATFORM_URI);
+ std::string resourceType;
+ std::shared_ptr<OCResource> platformResource = FindOCResource(deviceDetails,
+ platformResourcePath, resourceType);
+
+ result = OCPlatform::getPlatformInfo(
+ platformResource ? platformResource->host() : deviceDetails->deviceUris[0],
+ OC_RSRVD_PLATFORM_URI,
+ CT_DEFAULT,
+ std::bind(&OCFFramework::OnPlatformInfoCallback, this, _1));
+
+ if (result != OC_STACK_OK)
+ {
+ OIC_LOG_V(WARNING, TAG, "Failed getPlatformInfo() for: [%s] OC result: [%d]",
+ deviceDetails->deviceUris[0], result);
+ }
+
+ deviceDetails->platformInfoRequestCount++;
+ }
+
+ // Get device info.
+ if ((deviceDetails->deviceInfoAvailable == false) &&
+ (deviceDetails->deviceInfoRequestCount < MAX_REQUEST_COUNT))
+ {
+ // Use host address of oic/d if the resource is returned by oic/res.
+ std::string deviceResourcePath(OC_RSRVD_DEVICE_URI);
+ std::string resourceType;
+ std::shared_ptr<OCResource> deviceResource = FindOCResource(
+ deviceDetails,
+ deviceResourcePath,
+ resourceType);
+
+ result = OCPlatform::getDeviceInfo(
+ deviceResource ? deviceResource->host() :
+ deviceDetails->deviceUris[0],
+ OC_RSRVD_DEVICE_URI,
+ CT_DEFAULT,
+ std::bind(&OCFFramework::OnDeviceInfoCallback, this, _1));
+ if (result != OC_STACK_OK)
+ {
+ OIC_LOG_V(WARNING, TAG, "Failed getDeviceInfo() for [%s] OC result: [%d]",
+ deviceDetails->deviceUris[0], result);
+ }
+
+ deviceDetails->deviceInfoRequestCount++;
+ }
+
+ // Get maintenance resource.
+ if ((deviceDetails->maintenanceResourceAvailable == false) &&
+ (deviceDetails->maintenanceResourceRequestCount < MAX_REQUEST_COUNT))
+ {
+ std::ostringstream deviceUri;
+ OCConnectivityType connectivityType = CT_DEFAULT;
+ deviceUri << OC_RSRVD_WELL_KNOWN_URI;
+ deviceUri << "?rt=" << OC_RSRVD_RESOURCE_TYPE_MAINTENANCE;
+
+ result = OCPlatform::findResource(
+ deviceDetails->deviceUris[0],
+ deviceUri.str(),
+ connectivityType,
+ std::bind(&OCFFramework::OnResourceFound, this, _1));
+
+ if (result != OC_STACK_OK)
+ {
+ OIC_LOG_V(WARNING, TAG, "Failed findResource() for oic/mnt OC result: [%d]", result);
+ }
+
+ deviceDetails->maintenanceResourceRequestCount++;
+ }
+
+ return IPCA_OK;
+}
+
+IPCAStatus MapOCStackResultToIPCAStatus(OCStackResult result)
+{
+ IPCAStatus status;
+
+ switch(result)
+ {
+ case OC_STACK_OK:
+ case OC_STACK_CONTINUE:
+ case OC_STACK_RESOURCE_CHANGED:
+ status = IPCA_OK;
+ break;
+
+ case OC_STACK_UNAUTHORIZED_REQ:
+ status = IPCA_ACCESS_DENIED;
+ break;
+
+ case OC_STACK_RESOURCE_CREATED:
+ status = IPCA_RESOURCE_CREATED;
+ break;
+
+ case OC_STACK_RESOURCE_DELETED:
+ status = IPCA_RESOURCE_DELETED;
+ break;
+
+ default:
+ status = IPCA_FAIL;
+ break;
+ }
+
+ return status;
+}
+
+// Callback handler on PUT request
+void OCFFramework::OnPostPut(const HeaderOptions& headerOptions,
+ const OCRepresentation& rep,
+ const int eCode,
+ CallbackInfo::Ptr callbackInfo)
+{
+ OC_UNUSED(headerOptions);
+
+ IPCAStatus status = MapOCStackResultToIPCAStatus((OCStackResult)eCode);
+
+ for (const auto& callback : m_callbacks)
+ {
+ callback->SetCallback(status, rep, callbackInfo);
+ }
+}
+
+// Callback handler on GET request
+void OCFFramework::OnGet(const HeaderOptions& headerOptions,
+ const OCRepresentation& rep,
+ const int eCode,
+ CallbackInfo::Ptr callbackInfo)
+{
+ headerOptions;
+
+ IPCAStatus status = IPCA_OK;
+
+ if (eCode > OCStackResult::OC_STACK_RESOURCE_CHANGED)
+ {
+ status = IPCA_FAIL;
+ }
+
+ for (const auto& callback : m_callbacks)
+ {
+ callback->GetCallback(status, rep, callbackInfo);
+ }
+}
+
+void OCFFramework::OnObserve(
+ const HeaderOptions headerOptions,
+ const OCRepresentation &rep,
+ const int &eCode,
+ const int &sequenceNumber,
+ CallbackInfo::Ptr callbackInfo)
+{
+ OC_UNUSED(sequenceNumber);
+
+ IPCAStatus status = IPCA_OK;
+ if (eCode > OCStackResult::OC_STACK_RESOURCE_CHANGED)
+ {
+ status = IPCA_FAIL;
+ }
+
+ for (const auto& callback : m_callbacks)
+ {
+ callback->ObserveCallback(status, rep, callbackInfo);
+ }
+}
+
+void OCFFramework::OnDelete(const HeaderOptions& headerOptions,
+ const int eCode,
+ CallbackInfo::Ptr callbackInfo)
+{
+ OC_UNUSED(headerOptions);
+
+ IPCAStatus status = MapOCStackResultToIPCAStatus((OCStackResult)eCode);
+
+ for (const auto& callback : m_callbacks)
+ {
+ callback->DeleteResourceCallback(status, callbackInfo);
+ }
+}
+
+IPCAStatus OCFFramework::SendCommandToDevice(std::string& deviceId,
+ CallbackInfo::Ptr callbackInfo,
+ OCRepresentation* rep)
+{
+ DeviceDetails::Ptr deviceDetails;
+ IPCAStatus status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ std::shared_ptr<OCResource> ocResource = FindOCResource(
+ deviceDetails,
+ callbackInfo->resourcePath,
+ callbackInfo->resourceType);
+ if (ocResource == nullptr)
+ {
+ return IPCA_RESOURCE_NOT_FOUND;
+ }
+
+ QueryParamsMap queryParamsMap;
+ if (callbackInfo->resourceType.empty() == false)
+ {
+ queryParamsMap[OC::Key::RESOURCETYPESKEY] = callbackInfo->resourceType;
+ }
+
+ if (callbackInfo->resourceInterface.empty() == false)
+ {
+ queryParamsMap[OC::Key::INTERFACESKEY] = callbackInfo->resourceInterface;
+ }
+
+ OCStackResult result = OC_STACK_ERROR;
+ switch (callbackInfo->type)
+ {
+ case CallbackType_GetPropertiesComplete:
+ {
+ result = ocResource->get(
+ queryParamsMap,
+ std::bind(&OCFFramework::OnGet, this, _1, _2, _3, callbackInfo));
+ break;
+ }
+
+ case CallbackType_SetPropertiesComplete:
+ {
+ result = ocResource->post(
+ *rep,
+ queryParamsMap,
+ std::bind(&OCFFramework::OnPostPut, this, _1, _2, _3, callbackInfo));
+ break;
+ }
+
+ case CallbackType_CreateResourceComplete:
+ {
+ result = ocResource->post(
+ *rep,
+ queryParamsMap,
+ std::bind(&OCFFramework::OnPostPut, this, _1, _2, _3, callbackInfo));
+ break;
+ }
+
+ case CallbackType_DeleteResourceComplete:
+ {
+ result = ocResource->deleteResource(
+ std::bind(&OCFFramework::OnDelete, this, _1, _2, callbackInfo));
+ break;
+ }
+
+ case CallbackType_ResourceChange:
+ {
+ callbackInfo->ocResource = ocResource;
+ result = ocResource->observe(
+ ObserveType::Observe,
+ queryParamsMap,
+ std::bind(&OCFFramework::OnObserve, this,
+ _1, _2, _3, _4, callbackInfo));
+ break;
+ }
+ }
+
+ if (result == OC_STACK_OK)
+ {
+ callbackInfo->requestSentTimestamp = OICGetCurrentTime(TIME_IN_MS);
+ return IPCA_OK;
+ }
+ else
+ {
+ return IPCA_FAIL;
+ }
+}
+
+void OCFFramework::StopObserve(CallbackInfo::Ptr cbInfo)
+{
+ std::shared_ptr<OCResource> ocResource = cbInfo->ocResource;
+ ocResource->cancelObserve();
+}
+
+void OCFFramework::IsResourceObservable(std::string& deviceId,
+ const char* resourcePath,
+ bool* isObservable)
+{
+ *isObservable = false;
+
+ DeviceDetails::Ptr deviceDetails;
+ IPCAStatus status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status != IPCA_OK)
+ {
+ return;
+ }
+
+ if (deviceDetails->resourceMap.find(resourcePath) == deviceDetails->resourceMap.end())
+ {
+ return;
+ }
+
+ std::shared_ptr<OCResource> ocResource = deviceDetails->resourceMap[resourcePath];
+ *isObservable = ocResource->isObservable();
+}
+
+IPCAStatus OCFFramework::PingDevice(std::string& deviceId)
+{
+ DeviceDetails::Ptr deviceDetails;
+ IPCAStatus status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ std::ostringstream resourceUri;
+ resourceUri << OC_RSRVD_WELL_KNOWN_URI;
+ resourceUri << "?rt=" << OC_RSRVD_RESOURCE_TYPE_DEVICE;
+
+ assert(deviceDetails->deviceUris.size() > 0);
+ OCConnectivityType connectivityType = CT_DEFAULT;
+ OCStackResult result = OCPlatform::findResource(
+ deviceDetails->deviceUris[0],
+ resourceUri.str(),
+ connectivityType,
+ std::bind(&OCFFramework::OnResourceFound, this, _1));
+
+ if (result != OC_STACK_OK)
+ {
+ return IPCA_FAIL;
+ }
+
+ deviceDetails->lastPingTime = OICGetCurrentTime(TIME_IN_MS);
+ return IPCA_OK;
+}
+
+IPCAStatus OCFFramework::GetLastPingTime(std::string& deviceId, uint64_t& lastPingTime)
+{
+ DeviceDetails::Ptr deviceDetails;
+ IPCAStatus status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ lastPingTime = deviceDetails->lastPingTime;
+ return IPCA_OK;
+}
+
+IPCAStatus OCFFramework::FindDeviceDetails(const std::string& deviceId,
+ DeviceDetails::Ptr& deviceDetails)
+{
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+
+ auto device = m_OCFDevices.find(deviceId);
+ if (device == m_OCFDevices.end())
+ {
+ return IPCA_FAIL;
+ }
+
+ deviceDetails = device->second;
+ return IPCA_OK;
+}
+
+std::shared_ptr<OCResource> OCFFramework::FindOCResource(
+ const DeviceDetails::Ptr& deviceDetails,
+ const std::string& targetResourcePath,
+ const std::string& targetRT)
+{
+ // Return resource matching resource path.
+ if (deviceDetails->resourceMap.find(targetResourcePath) != deviceDetails->resourceMap.end())
+ {
+ return deviceDetails->resourceMap[targetResourcePath];
+ }
+
+ // No matching resource path. Return first resource that implements target resource type.
+ for (auto const& resource : deviceDetails->resourceMap)
+ {
+ for (auto const& rt : resource.second->getResourceTypes())
+ {
+ if (rt.compare(targetRT) == 0)
+ {
+ return resource.second;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+IPCAStatus OCFFramework::CopyDeviceInfo(std::string& deviceId, IPCADeviceInfo** callerDeviceInfo)
+{
+ *callerDeviceInfo = nullptr;
+
+ DeviceDetails::Ptr deviceDetails;
+ IPCAStatus status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ // Determine if server has responded to OCPlatform::getDeviceInfo().
+ if (deviceDetails->deviceInfoAvailable == false)
+ {
+ return IPCA_INFORMATION_NOT_AVAILABLE;
+ }
+
+ IPCADeviceInfo* deviceInfo = static_cast<IPCADeviceInfo*>(OICMalloc(sizeof(IPCADeviceInfo)));
+ if (deviceInfo == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ memset(deviceInfo, 0, sizeof(IPCADeviceInfo));
+
+ // @future: versionRequested determines what's copied to the caller buffer.
+ deviceInfo->version = IPCA_VERSION_1;
+
+ if (IPCA_OK != AllocateAndCopyStringVectorToArrayOfCharPointers(
+ deviceDetails->deviceUris,
+ const_cast<char***>(&deviceInfo->deviceUris),
+ &deviceInfo->deviceUriCount))
+ {
+ OICFree(deviceInfo);
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ if (IPCA_OK != AllocateAndCopyStringVectorToArrayOfCharPointers(
+ deviceDetails->deviceInfo.dataModelVersions,
+ const_cast<char***>(&deviceInfo->dataModelVersions),
+ &deviceInfo->dataModelVersionCount))
+ {
+ FreeArrayOfCharPointers(const_cast<char**>(deviceInfo->deviceUris), deviceInfo->deviceUriCount);
+ OICFree(deviceInfo);
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ if ((IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->deviceId,
+ const_cast<char**>(&deviceInfo->deviceId))) ||
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->deviceInfo.platformIndependentId,
+ const_cast<char**>(&deviceInfo->protocolIndependentId))) ||
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->deviceInfo.deviceName,
+ const_cast<char**>(&deviceInfo->deviceName))) ||
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->deviceInfo.deviceSoftwareVersion,
+ const_cast<char**>(&deviceInfo->deviceSoftwareVersion))))
+ {
+ FreeDeviceInfo(deviceInfo);
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ *callerDeviceInfo = deviceInfo;
+ return IPCA_OK;
+}
+
+void OCFFramework::FreeDeviceInfo(IPCADeviceInfo* deviceInfo)
+{
+ FreeArrayOfCharPointers(const_cast<char**>
+ (deviceInfo->deviceUris), deviceInfo->deviceUriCount);
+ FreeArrayOfCharPointers(const_cast<char**>
+ (deviceInfo->dataModelVersions), deviceInfo->dataModelVersionCount);
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(deviceInfo->deviceId)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(deviceInfo->protocolIndependentId)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(deviceInfo->deviceName)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(deviceInfo->deviceSoftwareVersion)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(deviceInfo)));
+}
+
+IPCAStatus OCFFramework::CopyPlatformInfo(std::string& deviceId,
+ IPCAPlatformInfo** callerPlatformInfo)
+{
+ *callerPlatformInfo = nullptr;
+
+ DeviceDetails::Ptr deviceDetails;
+ IPCAStatus status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ if (deviceDetails->platformInfoAvailable == false)
+ {
+ return IPCA_INFORMATION_NOT_AVAILABLE;
+ }
+
+ IPCAPlatformInfo* platformInfo = static_cast<IPCAPlatformInfo*>
+ (OICMalloc(sizeof(IPCAPlatformInfo)));
+ if (platformInfo == nullptr)
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ // @future: versionRequested determines what's copied to the caller buffer.
+ platformInfo->version = IPCA_VERSION_1;
+
+ if ((IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->platformInfo.platformId,
+ const_cast<char**>(&platformInfo->platformId))) ||
+
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->platformInfo.manufacturerName,
+ const_cast<char**>(&platformInfo->manufacturerName))) ||
+
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->platformInfo.manufacturerURL,
+ const_cast<char**>(&platformInfo->manufacturerURL))) ||
+
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->platformInfo.modelNumber,
+ const_cast<char**>(&platformInfo->modelNumber))) ||
+
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->platformInfo.manufacturingDate,
+ const_cast<char**>(&platformInfo->manufacturingDate))) ||
+
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->platformInfo.platformVersion,
+ const_cast<char**>(&platformInfo->platformVersion)) ||
+
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->platformInfo.osVersion,
+ const_cast<char**>(&platformInfo->osVersion))) ||
+
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->platformInfo.hardwareVersion,
+ const_cast<char**>(&platformInfo->hardwareVersion))) ||
+
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->platformInfo.firmwareVersion,
+ const_cast<char**>(&platformInfo->firmwareVersion))) ||
+
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->platformInfo.manufacturerSupportURL,
+ const_cast<char**>(&platformInfo->manufacturerSupportURL))) ||
+
+ (IPCA_OK != AllocateAndCopyStringToFlatBuffer(
+ deviceDetails->platformInfo.referenceTime,
+ const_cast<char**>(&platformInfo->referenceTime)))))
+ {
+ FreePlatformInfo(platformInfo);
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ *callerPlatformInfo = platformInfo;
+ return IPCA_OK;
+}
+
+void OCFFramework::FreePlatformInfo(IPCAPlatformInfo* platformInfo)
+{
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo->platformId)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo->manufacturerName)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo->manufacturerURL)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo->modelNumber)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo->manufacturingDate)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo->platformVersion)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo->osVersion)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo->hardwareVersion)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo->firmwareVersion)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo->manufacturerSupportURL)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo->referenceTime)));
+ OICFree(const_cast<void*>(reinterpret_cast<const void*>(platformInfo)));
+}
+
+IPCAStatus OCFFramework::CopyResourcePaths(const std::string& resourceInterface,
+ const std::string& resourceType,
+ std::string& deviceId,
+ std::vector<std::string>& resourcePathList)
+{
+ DeviceDetails::Ptr deviceDetails;
+ IPCAStatus status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ for (auto const& resource : deviceDetails->resourceMap)
+ {
+ if ((!resourceInterface.empty()) &&
+ (!IsStringInList(resourceInterface, resource.second->getResourceInterfaces())))
+ {
+ continue;
+ }
+
+ if ((!resourceType.empty()) &&
+ (!IsStringInList(resourceType, resource.second->getResourceTypes())))
+ {
+ continue;
+ }
+
+ resourcePathList.push_back(resource.second->uri());
+ }
+
+ return IPCA_OK;
+}
+
+IPCAStatus OCFFramework::CopyResourceInfo(const std::string& deviceId,
+ const std::string& resourcePath,
+ ResourceInfoType resourceInfoType,
+ std::vector<std::string>& resourceInfo)
+{
+ DeviceDetails::Ptr deviceDetails;
+ IPCAStatus status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status != IPCA_OK)
+ {
+ return status;
+ }
+
+ // Not specific resource.
+ if (resourcePath.length() == 0)
+ {
+ switch(resourceInfoType)
+ {
+ case ResourceInfoType::ResourceType:
+ resourceInfo = deviceDetails->discoveredResourceTypes;
+ status = IPCA_OK;
+ break;
+
+ case ResourceInfoType::ResourceInterface:
+ resourceInfo = deviceDetails->discoveredResourceInterfaces;
+ status = IPCA_OK;
+ break;
+
+ default:
+ status = IPCA_INVALID_ARGUMENT;
+ break;
+ }
+
+ return status;
+ }
+
+ status = IPCA_RESOURCE_NOT_FOUND;
+
+ // Filter for target resource URI.
+ for (auto const& resource : deviceDetails->resourceMap)
+ {
+ if (resourcePath.compare(resource.second->uri()) == 0)
+ {
+ switch(resourceInfoType)
+ {
+ case ResourceInfoType::ResourceType:
+ resourceInfo = resource.second->getResourceTypes();
+ status = IPCA_OK;
+ break;
+
+ case ResourceInfoType::ResourceInterface:
+ resourceInfo = resource.second->getResourceInterfaces();
+ status = IPCA_OK;
+ break;
+
+ default:
+ status = IPCA_INVALID_ARGUMENT;
+ break;
+
+ }
+ }
+ }
+
+ return status;
+}
+
+void OCFFramework::DebugOutputOCFDevices()
+{
+#if DO_DEBUG
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+
+ std::cout << "***** DebugOutputOCFDevices() ****" << std::endl;
+ std::cout << "Device count: " << m_OCFDevices.size() << std::endl;
+
+ // For each device
+ for (auto const& device : m_OCFDevices)
+ {
+ std::cout << "Device URI : " << device.first << std::endl;
+ std::cout << "Device id : " << device.second->deviceInfo.deviceId << std::endl;
+ std::cout << "Device name : " << device.second->deviceInfo.deviceName << std::endl;
+ std::cout << "Resource Types: " << std::endl;
+ for (auto const& res : device.second->discoveredResourceTypes)
+ {
+ std::cout << " " << res.c_str() << std::endl;
+ }
+
+ // For each resource
+ for (auto const& res : device.second->resourceMap)
+ {
+ std::cout << "Resource: " << res.first << std::endl;
+ std::cout << " URI: " << res.second->uri() << std::endl;
+
+ // For each resource type
+ std::vector<std::string> resourceTypes = res.second->getResourceTypes();
+ for(auto rType : resourceTypes)
+ {
+ std::cout << " Resource Type: " << rType.c_str() << std::endl;
+ }
+ }
+
+ std::cout << std::endl;
+ }
+#endif
+}
+
+void OCFFramework::DebugOutputOCRep(const OCRepresentation& rep)
+{
+#if DO_DEBUG
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+ PrintOCRep(rep);
+#else
+ OC_UNUSED(rep);
+#endif
+}
+
+IPCAStatus OCFFramework::RequestAccess(std::string& deviceId,
+ CallbackInfo::Ptr callbackInfo,
+ CallbackInfo::Ptr passwordInputCallbackInfo)
+{
+ IPCAStatus status = IPCA_OK;
+ DeviceDetails::Ptr deviceDetails;
+ RequestAccessContext* requestAccessContext = nullptr;
+
+ if (m_isStopping)
+ {
+ return IPCA_FAIL;
+ }
+
+ // Find the device details for this device
+ status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status == IPCA_OK)
+ {
+ // Return a failure if an access request is already in progress for this device.
+ if (!deviceDetails->securityInfo.isStarted)
+ {
+ deviceDetails->securityInfo.isStarted = true;
+ }
+ else
+ {
+ return IPCA_FAIL;
+ }
+ }
+ else
+ {
+ return status;
+ }
+
+ // Construct context for the worker thread
+ requestAccessContext = static_cast<RequestAccessContext*>
+ (OICCalloc(1, sizeof(RequestAccessContext)));
+ if (nullptr != requestAccessContext)
+ {
+ requestAccessContext->deviceId = deviceId;
+ requestAccessContext->ocfFramework = this;
+ requestAccessContext->callbackInfo = callbackInfo;
+ requestAccessContext->passwordInputCallbackInfo = passwordInputCallbackInfo;
+ }
+ else
+ {
+ return IPCA_OUT_OF_MEMORY;
+ }
+
+ // Add the context information to the list of contexts so we can clean it up later
+ {
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+ m_OCFRequestAccessContexts[deviceId] = requestAccessContext;
+ }
+
+ // Create a new thread to handle the RequestAccess request
+ deviceDetails->securityInfo.requestAccessThread =
+ std::thread(&OCFFramework::RequestAccessWorkerThread, requestAccessContext);
+
+ return status;
+}
+
+void OCFFramework::RequestAccessWorkerThread(RequestAccessContext* requestContext)
+{
+ IPCAStatus status = IPCA_OK;
+ IPCAStatus callbackStatus = IPCA_SECURITY_UPDATE_REQUEST_FAILED;
+ OCStackResult result = OC_STACK_OK;
+ std::string deviceId = requestContext->deviceId;
+ OCFFramework* ocfFramework = requestContext->ocfFramework;
+ CallbackInfo::Ptr callbackInfo = requestContext->callbackInfo;
+ CallbackInfo::Ptr passwordInputCallbackInfo = requestContext->passwordInputCallbackInfo;
+ DeviceDetails::Ptr deviceDetails;
+ OicUuid_t uuid;
+
+ // Check to make sure the OCFFramework is not shutting down before we start this request
+ if (ocfFramework->m_isStopping)
+ {
+ status = IPCA_FAIL;
+ }
+
+ // Find the device details for this device and convert the device id into a UUID
+ if (IPCA_OK == status)
+ {
+ status = ocfFramework->FindDeviceDetails(deviceId, deviceDetails);
+ if (status == IPCA_OK)
+ {
+ result = ConvertStrToUuid(deviceId.c_str(), &uuid);
+ if (OC_STACK_OK != result)
+ {
+ status = MapOCStackResultToIPCAStatus(result);
+ }
+ }
+ }
+
+ // Check to see if the device supports MOT
+ if (IPCA_OK == status)
+ {
+ result = OCSecure::discoverMultipleOwnerEnabledDevice(
+ c_discoveryTimeout, &uuid, deviceDetails->securityInfo.device);
+
+ if ((OC_STACK_OK == result) && (nullptr == deviceDetails->securityInfo.device))
+ {
+ status = IPCA_DEVICE_NOT_DISCOVERED;
+ }
+ else if(OC_STACK_OK != result)
+ {
+ status = MapOCStackResultToIPCAStatus(result);
+ }
+ }
+
+ // Take ownership of the device if it supports MOT and the calling app is not a subowner.
+ // Otherwise if the app is a subowner we will callback to the app indicating success without
+ // doing anything.
+ if ((IPCA_OK == status) && (nullptr != deviceDetails->securityInfo.device))
+ {
+ result = deviceDetails->securityInfo.device->isSubownerOfDevice(
+ &deviceDetails->securityInfo.subowner);
+ if (OC_STACK_OK == result)
+ {
+ deviceDetails->securityInfoAvailable = true;
+
+ if (!deviceDetails->securityInfo.subowner)
+ {
+ // Check the selected ownership transfer method of the device to see if there
+ // is anything we need to do before performing MOT
+ switch (deviceDetails->securityInfo.device->getSelectedOwnershipTransferMethod())
+ {
+ case OIC_RANDOM_DEVICE_PIN:
+ {
+ // Requests for a random pin will be handled by the underlying stack so
+ // there is nothing else to do
+ break;
+ }
+ case OIC_PRECONFIG_PIN:
+ {
+ char passwordBuffer[OXM_PRECONFIG_PIN_MAX_SIZE + 1];
+ size_t passwordBufferSize = OXM_PRECONFIG_PIN_MAX_SIZE + 1;
+ memset(passwordBuffer, 0, passwordBufferSize);
+
+ // We need to set the preconfigured pin before attempting to do MOT.
+ // Callback to the app asking for the password.
+ for (const auto& callback : ocfFramework->m_callbacks)
+ {
+ callback->PasswordInputCallback(deviceId,
+ IPCA_OWNERSHIP_TRANSFER_PRECONFIGURED_PIN,
+ passwordBuffer,
+ passwordBufferSize,
+ passwordInputCallbackInfo);
+ }
+
+ // Set the preconfigured pin
+ result = deviceDetails->securityInfo.device->addPreconfigPIN(
+ passwordBuffer,
+ strnlen_s(passwordBuffer, passwordBufferSize));
+
+ if (OC_STACK_OK != result)
+ {
+ status = MapOCStackResultToIPCAStatus(result);
+ }
+ break;
+ }
+ default:
+ {
+ // Preconfigured and random pin are the only supported MOT ownership
+ // transfer methods.
+ // Callback to the app reporting that the current selected method on the
+ // device is not supported and there needs to be intervention by the admin.
+ status = IPCA_FAIL;
+ callbackStatus = IPCA_SECURITY_UPDATE_REQUEST_NOT_SUPPORTED;
+ break;
+ }
+ }
+
+ if (IPCA_OK == status)
+ {
+ std::unique_lock<std::mutex> lock(
+ deviceDetails->securityInfo.requestAccessThreadMutex);
+
+ result = deviceDetails->securityInfo.device->doMultipleOwnershipTransfer(
+ std::bind(
+ &OCFFramework::OnMultipleOwnershipTransferCompleteCallback,
+ ocfFramework,
+ _1,
+ _2,
+ deviceId,
+ callbackInfo));
+
+ if (OC_STACK_OK == result)
+ {
+ // Wait for the callback to indicate that MOT and calling back to the app
+ // has finished. If this takes longer
+ // then 30 seconds we assume that something has failed and continue.
+ // This is to prevent blocking forever and
+ // not allowing the app to close properly.
+ cv_status waitStatus =
+ deviceDetails->securityInfo.requestAccessThreadCV.wait_for(
+ lock, std::chrono::seconds(30));
+
+ if ((cv_status::timeout == waitStatus) || ocfFramework->m_isStopping)
+ {
+ status = IPCA_FAIL;
+ }
+ }
+ else
+ {
+ status = MapOCStackResultToIPCAStatus(result);
+ }
+ }
+ }
+ else
+ {
+ // This app is already a subowner of the device
+ for (const auto& callback : ocfFramework->m_callbacks)
+ {
+ callback->RequestAccessCompletionCallback(
+ IPCA_SECURITY_UPDATE_REQUEST_FINISHED,
+ callbackInfo);
+ }
+ }
+ }
+ else
+ {
+ status = MapOCStackResultToIPCAStatus(result);
+ }
+ }
+
+ // Callback to the application with the appropriate status information if we encountered an
+ // issue while preparing to perform Multiple Ownership Transfer.
+ // OnMultipleOwnershipTransferCompleteCallback will callback to the application to report the
+ // success or failure of doMultipleOwnershipTransfer.
+ if (IPCA_OK != status)
+ {
+ for (const auto& callback : ocfFramework->m_callbacks)
+ {
+ callback->RequestAccessCompletionCallback(callbackStatus, callbackInfo);
+ }
+ }
+}
+
+void OCFFramework::OnMultipleOwnershipTransferCompleteCallback(PMResultList_t* result,
+ bool error,
+ std::string deviceId,
+ CallbackInfo::Ptr callbackInfo)
+{
+ OC_UNUSED(result);
+
+ IPCAStatus status = IPCA_SECURITY_UPDATE_REQUEST_FINISHED;
+ DeviceDetails::Ptr deviceDetails;
+
+ // @todo: Provide more specific errors once the underlying IoTivity stack is able to provide us
+ // with better error codes.
+ if (error)
+ {
+ status = IPCA_SECURITY_UPDATE_REQUEST_FAILED;
+ }
+
+ for (const auto& callback : m_callbacks)
+ {
+ callback->RequestAccessCompletionCallback(status, callbackInfo);
+ }
+
+ // Get the device details so we can make sure the thread has finished and update the
+ // request state accordingly
+ status = FindDeviceDetails(deviceId, deviceDetails);
+ if (status == IPCA_OK)
+ {
+ deviceDetails->securityInfo.subowner = true;
+ deviceDetails->securityInfo.requestAccessThreadCV.notify_all();
+ }
+}
+
+IPCAStatus OCFFramework::SetInputPasswordCallback(CallbackInfo::Ptr callbackInfo,
+ InputPinCallbackHandle* passwordInputCallbackHandle)
+{
+ OCSecure::registerInputPinCallback(std::bind(
+ &OCFFramework::OnPasswordInputCallback,
+ this,
+ _1,
+ _2,
+ _3,
+ callbackInfo),
+ passwordInputCallbackHandle);
+
+ return IPCA_OK;
+}
+
+void OCFFramework::OnPasswordInputCallback(OicUuid_t deviceId,
+ char* passwordBuffer,
+ size_t passwordBufferSize,
+ CallbackInfo::Ptr callbackInfo)
+{
+ std::string strDeviceId;
+ char uuidString[UUID_STRING_SIZE] = { 0 };
+ OCConvertUuidToString(deviceId.id, uuidString);
+ strDeviceId = uuidString;
+
+ for (const auto& callback : m_callbacks)
+ {
+ callback->PasswordInputCallback(
+ strDeviceId,
+ IPCA_OWNERSHIP_TRANSFER_RANDOM_PIN,
+ passwordBuffer,
+ passwordBufferSize,
+ callbackInfo);
+ }
+}
+
+IPCAStatus OCFFramework::SetDisplayPasswordCallback(CallbackInfo::Ptr callbackInfo,
+ DisplayPinCallbackHandle* passwordDisplayCallbackHandle)
+{
+ OCSecure::registerDisplayPinCallback(std::bind(
+ &OCFFramework::OnPasswordDisplayCallback,
+ this,
+ _1,
+ _2,
+ callbackInfo),
+ passwordDisplayCallbackHandle);
+
+ return IPCA_OK;
+}
+
+void OCFFramework::OnPasswordDisplayCallback(char* passwordBuffer,
+ size_t passwordBufferSize,
+ CallbackInfo::Ptr callbackInfo)
+{
+ OC_UNUSED(passwordBufferSize);
+
+ for (const auto& callback : m_callbacks)
+ {
+ callback->PasswordDisplayCallback("",
+ IPCA_OWNERSHIP_TRANSFER_RANDOM_PIN,
+ passwordBuffer,
+ callbackInfo);
+ }
+}
+
+void OCFFramework::CleanupRequestAccessDevices()
+{
+ std::vector<DeviceDetails::Ptr> requestAccessDevices;
+
+ // Discover all of the devices that performed security operations
+ {
+ std::lock_guard<std::recursive_mutex> lock(m_OCFFrameworkMutex);
+
+ for (auto const& device : m_OCFDevices)
+ {
+ if (device.second->securityInfo.isStarted)
+ {
+ requestAccessDevices.push_back(device.second);
+ }
+ }
+ }
+
+ // If a RequestAccess operation is still in progress for a device wait for it to finish.
+ // Once the operation is complete cleanup the RequestAccess context for the operation.
+ for (auto const& device : requestAccessDevices)
+ {
+ device->securityInfo.requestAccessThreadCV.notify_all();
+
+ if (device->securityInfo.requestAccessThread.joinable())
+ {
+ device->securityInfo.requestAccessThread.join();
+ }
+
+ auto context = m_OCFRequestAccessContexts.find(device->deviceId);
+ if (context != m_OCFRequestAccessContexts.end())
+ {
+ RequestAccessContext* requestAccessContext = context->second;
+ if (nullptr != requestAccessContext)
+ {
+ requestAccessContext->callbackInfo = nullptr;
+ requestAccessContext->passwordInputCallbackInfo = nullptr;
+ requestAccessContext->ocfFramework = nullptr;
+ OICFree(static_cast<void*>(requestAccessContext));
+ }
+ m_OCFRequestAccessContexts.erase(device->deviceId);
+ }
+ }
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "ipcainternal.h"
+
+#include "ocstack.h"
+#include "srmutility.h"
+#include "base64.h"
+
+#include <thread>
+
+#include "pinoxmcommon.h"
+#include "srmutility.h"
+#include "common.h"
+
+// These APIs are used when building with SECURED=0.
+
+OCStackResult OCSecure::discoverMultipleOwnerEnabledDevices(unsigned short timeout,
+ DeviceList_t &list)
+{
+ OC_UNUSED(timeout);
+ OC_UNUSED(list);
+ return OC_STACK_OK;
+}
+
+OCStackResult OCSecure::registerInputPinCallback(InputPinCB inputPinCB,
+ InputPinCallbackHandle* inputPinCallbackHandle)
+{
+ OC_UNUSED(inputPinCB);
+ OC_UNUSED(inputPinCallbackHandle);
+ return OC_STACK_OK;
+}
+
+OCStackResult OCSecure::provisionInit(const std::string& dbPath)
+{
+ OC_UNUSED(dbPath);
+ return OC_STACK_OK;
+}
+
+OCStackResult OCSecure::deregisterInputPinCallback(InputPinCallbackHandle inputPinCallbackHandle)
+{
+ OC_UNUSED(inputPinCallbackHandle);
+ return OC_STACK_OK;
+}
+
+OCStackResult OCSecure::registerDisplayPinCallback(DisplayPinCB displayPinCB,
+ DisplayPinCallbackHandle* displayPinCallbackHandle)
+{
+ OC_UNUSED(displayPinCB);
+ OC_UNUSED(displayPinCallbackHandle);
+ return OC_STACK_OK;
+}
+
+OCStackResult OCSecure::deregisterDisplayPinCallback(
+ DisplayPinCallbackHandle displayPinCallbackHandle)
+{
+ OC_UNUSED(displayPinCallbackHandle);
+ return OC_STACK_OK;
+}
+
+OicSecOxm_t OCSecureResource::getSelectedOwnershipTransferMethod()
+{
+ return OIC_JUST_WORKS;
+}
+
+OCStackResult OCSecure::discoverMultipleOwnerEnabledDevice(unsigned short timeout,
+ const OicUuid_t* deviceID,
+ std::shared_ptr<OCSecureResource> &foundDevice)
+{
+ OC_UNUSED(timeout);
+ OC_UNUSED(deviceID);
+ OC_UNUSED(foundDevice);
+ return OC_STACK_OK;
+}
+
+OCStackResult OCSecureResource::addPreconfigPIN(const char* preconfPIN, size_t preconfPINLength)
+{
+ OC_UNUSED(preconfPIN);
+ OC_UNUSED(preconfPINLength);
+ return OC_STACK_OK;
+}
+
+OCStackResult OCSecureResource::doMultipleOwnershipTransfer(ResultCallBack resultCallback)
+{
+ OC_UNUSED(resultCallback);
+ return OC_STACK_OK;
+}
+
+OCStackResult OCSecureResource::isSubownerOfDevice(bool* subowner)
+{
+ OC_UNUSED(subowner);
+ return OC_STACK_OK;
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include <thread>
+#include <chrono>
+#include <mutex>
+#include <condition_variable>
+
+#include "gtest/gtest.h"
+#include "ocrandom.h"
+#include "octypes.h"
+#include "ipca.h"
+#include "ipcatestdata.h"
+#include "ipcaelevatorclient.h"
+
+extern IPCAUuid IPCATestAppUuid;
+extern char IPCATestAppName[];
+extern std::string g_elevator1Name;
+
+IPCAStatus IPCAElevatorClient::FactoryResetElevator()
+{
+ IPCAStatus status = IPCAFactoryReset(m_deviceHandle);
+
+ if (status == IPCA_RESOURCE_NOT_FOUND)
+ {
+ // Give it some time to discover the maintenance resource.
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ status = IPCAFactoryReset(m_deviceHandle);
+ }
+
+ return status;
+}
+
+IPCAStatus IPCAElevatorClient::RebootElevator()
+{
+ IPCAStatus status = IPCAReboot(m_deviceHandle);
+
+ if (status == IPCA_RESOURCE_NOT_FOUND)
+ {
+ // Give it some time to discover the maintenance resource.
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ status = IPCAReboot(m_deviceHandle);
+ }
+
+ return status;
+}
+
+void C_GetPropertiesCb(IPCAStatus result, void* context, IPCAPropertyBagHandle propertyBagHandle)
+{
+ IPCAElevatorClient* ipcaElevatorClient = (IPCAElevatorClient*)context;
+ ipcaElevatorClient->GetPropertiesCallback(result, context, propertyBagHandle);
+}
+
+bool IPCAElevatorClient::GetElevatorProperties()
+{
+ m_getPropertiesCallbackCalled = false;
+
+ // Get the data.
+ EXPECT_EQ(IPCA_OK, IPCAGetProperties(
+ m_deviceHandle,
+ &C_GetPropertiesCb,
+ (void*)this,
+ ELEVATOR_RESOURCE_PATH,
+ nullptr,
+ nullptr,
+ nullptr));
+
+ // Wait for get data completion.
+ std::unique_lock<std::mutex> lock(m_getDataCompleteCbMutex);
+ m_getDataCompleteCbCV.wait_for(
+ lock,
+ std::chrono::seconds(10),
+ [this ] { return m_getPropertiesCallbackCalled; });
+
+ return m_getPropertiesCallbackCalled;
+}
+
+void C_SetPropertiesCb(IPCAStatus result, void* context, IPCAPropertyBagHandle propertyBagHandle)
+{
+ IPCAElevatorClient* ipcaTest = (IPCAElevatorClient*)context;
+ ipcaTest->SetPropertiesCallback(result, context, propertyBagHandle);
+}
+
+bool IPCAElevatorClient::SetElevatorProperties(IPCAPropertyBagHandle propertyBagHandle)
+{
+ m_setPropertiesCallbackCalled = false;
+
+ // Set properties.
+ EXPECT_EQ(IPCA_OK, IPCASetProperties(
+ m_deviceHandle,
+ &C_SetPropertiesCb,
+ this,
+ (const char*)ELEVATOR_RESOURCE_PATH,
+ nullptr,
+ (const char*)ELEVATOR_RESOURCE_TYPE,
+ propertyBagHandle,
+ nullptr));
+
+
+ std::unique_lock<std::mutex> lock(m_setPropertiesCompleteCbMutex);
+
+ m_setPropertiesCompleteCV.wait_for(
+ lock,
+ std::chrono::seconds(10),
+ [this] { return m_setPropertiesCallbackCalled; });
+
+ return m_setPropertiesCallbackCalled;
+}
+
+void C_CreateResourceCb(IPCAStatus result,
+ void* context,
+ const char* newResourcePath,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ IPCAElevatorClient* ipcaTest = (IPCAElevatorClient*)context;
+ ipcaTest->CreateResourceCallback(result, newResourcePath, propertyBagHandle);
+}
+
+bool IPCAElevatorClient::CreateElevatorResource(std::string resourcePath,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ m_createResourceCallbackCalled = false;
+
+ // Set properties.
+ EXPECT_EQ(IPCA_OK, IPCACreateResource(
+ m_deviceHandle,
+ &C_CreateResourceCb,
+ this,
+ resourcePath.c_str(),
+ nullptr,
+ nullptr,
+ propertyBagHandle,
+ nullptr));
+
+
+ std::unique_lock<std::mutex> lock(m_createResourceCompleteCbMutex);
+
+ m_createResourceCompleteCV.wait_for(
+ lock,
+ std::chrono::seconds(10),
+ [this] { return m_createResourceCallbackCalled; });
+
+ return m_createResourceCallbackCalled;
+}
+
+void C_DeleteResourceCb(IPCAStatus result, void* context)
+{
+ IPCAElevatorClient* ipcaTest = (IPCAElevatorClient*)context;
+ ipcaTest->DeleteResourceCallback(result);
+}
+
+bool IPCAElevatorClient::DeleteElevatorResource()
+{
+ m_deleteResourceCallbackCalled = false;
+
+ // Set properties.
+ EXPECT_EQ(IPCA_OK, IPCADeleteResource(
+ m_deviceHandle,
+ &C_DeleteResourceCb,
+ this,
+ (const char*)ELEVATOR_RESOURCE_DELETE_PATH,
+ nullptr));
+
+
+ std::unique_lock<std::mutex> lock(m_deleteResourceCompleteCbMutex);
+
+ m_deleteResourceCompleteCV.wait_for(
+ lock,
+ std::chrono::seconds(10),
+ [this] { return m_deleteResourceCallbackCalled; });
+
+ return m_deleteResourceCallbackCalled;
+}
+
+void IPCAElevatorClient::GetCurrentFloor(int* currentFloor, bool* result)
+{
+ *result = false;
+ if (GetElevatorProperties() == true)
+ {
+ *currentFloor = m_currentFloor;
+ *result = true;
+ }
+}
+
+void IPCAElevatorClient::GetTargetFloor(int* targetFloor, bool* result)
+{
+ *result = false;
+ if (GetElevatorProperties() == true)
+ {
+ *targetFloor = m_targetFloor;
+ *result = true;
+ }
+}
+
+void IPCAElevatorClient::SetTargetFloor(int targetFloor, bool* result)
+{
+ *result = false;
+
+ IPCAPropertyBagHandle propertyBagHandle;
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle));
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagSetValueInt(
+ propertyBagHandle, ELEVATOR_PROPERTY_TARGET_FLOOR, targetFloor));
+
+ *result = SetElevatorProperties(propertyBagHandle);
+ IPCAPropertyBagDestroy(propertyBagHandle);
+}
+
+void IPCAElevatorClient::CreateResourceRelativePath()
+{
+ IPCAPropertyBagHandle propertyBagHandle;
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle));
+
+ CreateElevatorResource(ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH, propertyBagHandle);
+
+ IPCAPropertyBagDestroy(propertyBagHandle);
+}
+
+void IPCAElevatorClient::DeleteResource()
+{
+ DeleteElevatorResource();
+}
+
+void IPCAElevatorClient::CreateResouceExplicitPath()
+{
+}
+
+void C_ResourceChangeNotificationCb(IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ IPCAElevatorClient* ipcaTest = (IPCAElevatorClient*)context;
+ ipcaTest->ResourceChangeNotificationCallback(result, propertyBagHandle);
+}
+
+bool IPCAElevatorClient::StartObserve()
+{
+ m_observedCurrentFloor = 0;
+ m_observedDirection = 0;
+ m_observedTargetFloor = 0;
+
+ bool isObservable;
+ IPCAIsResourceObservable(m_deviceHandle, "fakePath", &isObservable);
+ EXPECT_FALSE(isObservable);
+
+ IPCAIsResourceObservable(m_deviceHandle, ELEVATOR_RESOURCE_PATH, &isObservable);
+ EXPECT_TRUE(isObservable);
+
+ IPCAStatus status = IPCAObserveResource(
+ m_deviceHandle,
+ &C_ResourceChangeNotificationCb,
+ (void*)this,
+ ELEVATOR_RESOURCE_PATH,
+ nullptr,
+ &m_observeHandle);
+
+ return (status == IPCA_OK ? true : false);
+}
+
+void IPCAElevatorClient::StopObserve()
+{
+ if (m_observeHandle)
+ {
+ IPCACloseHandle(m_observeHandle);
+ }
+}
+
+IPCAStatus IPCAElevatorClient::GetUnknownResource()
+{
+ // Get the data.
+ IPCAStatus status = IPCAGetProperties(
+ m_deviceHandle,
+ &C_GetPropertiesCb,
+ (void*)this,
+ "/ipca/test/unknownresource",
+ nullptr,
+ nullptr,
+ nullptr);
+
+ return status;
+}
+
+IPCAStatus IPCAElevatorClient::SetUnknownResource()
+{
+ IPCAPropertyBagHandle propertyBagHandle;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueInt(propertyBagHandle,
+ ELEVATOR_PROPERTY_TARGET_FLOOR, 1)); /* 1 is randomly chosen */
+
+ IPCAStatus status = IPCASetProperties(
+ m_deviceHandle,
+ &C_SetPropertiesCb,
+ this,
+ "/ipca/test/unknownresource",
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ IPCAPropertyBagDestroy(propertyBagHandle);
+
+ return status;
+}
+
+bool IPCAElevatorClient::SetUnknoownInterface()
+{
+ m_setPropertiesCallbackCalled = false;
+
+ IPCAPropertyBagHandle propertyBagHandle;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueInt(propertyBagHandle,
+ ELEVATOR_PROPERTY_TARGET_FLOOR, 1)); /* 1 is randomly chosen */
+
+ IPCAStatus status = IPCASetProperties(
+ m_deviceHandle,
+ &C_SetPropertiesCb,
+ this,
+ ELEVATOR_RESOURCE_PATH,
+ ELEVATOR_RESOURCE_MADE_UP_INTERFACE,
+ nullptr,
+ propertyBagHandle,
+ nullptr);
+
+ EXPECT_EQ(IPCA_OK, status);
+
+ std::unique_lock<std::mutex> lock(m_setPropertiesCompleteCbMutex);
+
+ m_setPropertiesCompleteCV.wait_for(
+ lock,
+ std::chrono::seconds(10),
+ [this] { return m_setPropertiesCallbackCalled; });
+
+ return m_setPropertiesCallbackCalled;
+}
+
+void IPCAElevatorClient::SetUp()
+{
+ m_elevator1Discovered = false;
+ m_discoveredElevator1DeviceId.clear();
+ m_discoveredElevator1DeviceName.clear();
+
+ m_ipcaAppHandle = nullptr;
+ m_deviceDiscoveryHandle = nullptr;
+ m_deviceHandle = nullptr;
+ m_newResourcePath = "";
+
+ IPCAAppInfo ipcaAppInfo = { IPCATestAppUuid, IPCATestAppName, "1.0.0", "Microsoft" };
+
+ IPCAStatus status = IPCAOpen(&ipcaAppInfo, IPCA_VERSION_1, &m_ipcaAppHandle);
+
+ ASSERT_EQ(IPCA_OK, status);
+
+ DiscoverElevator1();
+}
+
+void IPCAElevatorClient::TearDown()
+{
+ if (m_observeHandle != nullptr)
+ {
+ IPCACloseHandle(m_observeHandle);
+ m_observeHandle = nullptr;
+ }
+
+ if (m_deviceHandle != nullptr)
+ {
+ IPCACloseDevice(m_deviceHandle);
+ m_deviceHandle = nullptr;
+ }
+
+ if (m_deviceDiscoveryHandle != nullptr)
+ {
+ IPCACloseHandle(m_deviceDiscoveryHandle);
+ m_deviceDiscoveryHandle = nullptr;
+ }
+
+ if (m_ipcaAppHandle != nullptr)
+ {
+ IPCAClose(m_ipcaAppHandle);
+ m_ipcaAppHandle = nullptr;
+ }
+}
+
+IPCAStatus IPCAElevatorClient::ConfirmDeviceAndPlatformInfo()
+{
+ IPCAStatus status;
+
+ // Device info.
+ IPCADeviceInfo *deviceInfo = nullptr;
+ int loopCount = 0;
+ while (loopCount++ < 10)
+ {
+ status = IPCAGetDeviceInfo(m_deviceHandle, &deviceInfo);
+ if (status == IPCA_OK)
+ {
+ break;
+ }
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ }
+
+ EXPECT_NE(nullptr, deviceInfo);
+ if (deviceInfo)
+ {
+ EXPECT_STREQ(g_elevator1Name.c_str(), deviceInfo->deviceName);
+
+ // See: ipcatestdata.h ELEVATOR_DATA_MODEL_VERSION_1 to 3.
+ EXPECT_EQ(3, deviceInfo->dataModelVersionCount);
+
+ bool modelFound = false;
+ std::string Model1(ELEVATOR_DATA_MODEL_VERSION_1);
+ for (size_t i = 0; i < deviceInfo->dataModelVersionCount; i++)
+ {
+ if (Model1.compare(deviceInfo->dataModelVersions[i]) == 0)
+ {
+ modelFound = true;
+ break;
+ }
+ }
+
+ EXPECT_TRUE(modelFound);
+ EXPECT_STREQ(ELEVATOR_PLATFORM_INDEPENDENT_ID, deviceInfo->protocolIndependentId);
+ IPCAFreeDeviceInfo(deviceInfo);
+ }
+
+ // Platform info.
+ IPCAPlatformInfo *platformInfo;
+ loopCount = 0;
+ while (loopCount++ < 10)
+ {
+ status = IPCAGetPlatformInfo(m_deviceHandle, &platformInfo);
+ if (status == IPCA_OK)
+ {
+ break;
+ }
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ }
+ EXPECT_EQ(IPCA_OK, IPCAGetPlatformInfo(m_deviceHandle, &platformInfo));
+ EXPECT_STREQ(ELEVATOR_PLATFORM_ID, platformInfo->platformId);
+ IPCAFreePlatformInfo(platformInfo);
+
+ return IPCA_OK;
+}
+
+IPCAStatus IPCAElevatorClient::ConfirmResources()
+{
+ // Resource list in array of char*, expect elevator resource is one of them.
+ char** resourcePathList;
+ size_t resourcePathCount;
+ EXPECT_EQ(IPCA_OK, IPCAGetResources(m_deviceHandle,
+ nullptr, nullptr, &resourcePathList, &resourcePathCount));
+ EXPECT_LT(0, resourcePathCount); // At least there must be elevator resource.
+ int i = 0;
+ bool elevatorResourceFound = false;
+ for (i = 0; i < resourcePathCount; i++)
+ {
+ std::string resourcePath = resourcePathList[i];
+ if (resourcePath.find(ELEVATOR_KEYWORD) != std::string::npos)
+ {
+ elevatorResourceFound = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(elevatorResourceFound);
+ IPCAFreeStringArray(resourcePathList, resourcePathCount);
+ return IPCA_OK;
+}
+
+IPCAStatus IPCAElevatorClient::ConfirmResourceTypes()
+{
+ // Function list in array of char*, expect elevator function is one of them.
+ char** resourceTypes;
+ size_t resourceTypeCount;
+ EXPECT_EQ(IPCA_OK, IPCAGetResourceTypes(m_deviceHandle,
+ nullptr, &resourceTypes, &resourceTypeCount));
+ EXPECT_LT(0, resourceTypeCount); // At least 1 resource type.
+ int i = 0;
+ bool elevatorResourceTypeFound = false;
+ for (i = 0; i < resourceTypeCount; i++)
+ {
+ std::string rt = resourceTypes[i];
+ if (rt.find(ELEVATOR_KEYWORD) != std::string::npos)
+ {
+ elevatorResourceTypeFound = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(elevatorResourceTypeFound);
+ IPCAFreeStringArray(resourceTypes, resourceTypeCount); // free the IPCA allocated memory.
+
+ // Function list for a given resource.
+ EXPECT_EQ(IPCA_RESOURCE_NOT_FOUND, IPCAGetResourceTypes(m_deviceHandle,
+ "oic/fake", &resourceTypes, &resourceTypeCount));
+ EXPECT_EQ(0, resourceTypeCount);
+ EXPECT_EQ(nullptr, resourceTypes);
+
+ EXPECT_EQ(IPCA_OK, IPCAGetResourceTypes(m_deviceHandle,
+ ELEVATOR_RESOURCE_PATH, &resourceTypes, &resourceTypeCount));
+ EXPECT_LT(0, resourceTypeCount); // At least 1 function.
+ elevatorResourceTypeFound = false;
+ for (i = 0; i < resourceTypeCount; i++)
+ {
+ std::string rt = resourceTypes[i];
+ if (rt.find(ELEVATOR_KEYWORD) != std::string::npos)
+ {
+ elevatorResourceTypeFound = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(elevatorResourceTypeFound);
+ IPCAFreeStringArray(resourceTypes, resourceTypeCount); // free the IPCA allocated memory.
+
+ return IPCA_OK;
+}
+
+IPCAStatus IPCAElevatorClient::ConfirmResourceInterfaces()
+{
+ // There should be at least 2 interfaces (ELEVATOR_CO_PRIVATE_INTERFACE and DEFAULT_INTERFACE).
+ char** resourceInterfaces;
+ size_t resourceInterfaceCount;
+ EXPECT_EQ(IPCA_OK, IPCAGetResourceInterfaces(m_deviceHandle,
+ nullptr, &resourceInterfaces, &resourceInterfaceCount));
+ EXPECT_LT(1, resourceInterfaceCount);
+
+ // Should return only 1 resource with ELEVATOR_CO_PRIVATE_INTERFACE interface.
+ char** resourcePathList;
+ size_t resourcePathCount;
+ EXPECT_EQ(IPCA_OK, IPCAGetResources(m_deviceHandle,
+ ELEVATOR_CO_PRIVATE_INTERFACE,
+ nullptr,
+ &resourcePathList,
+ &resourcePathCount));
+ EXPECT_EQ(1, resourcePathCount);
+ EXPECT_STREQ(ELEVATOR_CO_RESOURCE_PATH, resourcePathList[0]);
+ IPCAFreeStringArray(resourcePathList, resourcePathCount);
+
+ // Should return 0 resource with non existence interface.
+ EXPECT_EQ(IPCA_OK, IPCAGetResources(m_deviceHandle,
+ ELEVATOR_RESOURCE_MADE_UP_INTERFACE,
+ nullptr,
+ &resourcePathList,
+ &resourcePathCount));
+ EXPECT_EQ(0, resourcePathCount);
+ IPCAFreeStringArray(resourcePathList, resourcePathCount);
+
+ // Should be at least 4 resouces with DEFAULT_INTERFACE created in ElevatorServer::Start().
+ EXPECT_EQ(IPCA_OK, IPCAGetResources(m_deviceHandle,
+ OC_RSRVD_INTERFACE_DEFAULT,
+ nullptr,
+ &resourcePathList,
+ &resourcePathCount));
+ EXPECT_LT(3, resourcePathCount);
+ IPCAFreeStringArray(resourcePathList, resourcePathCount);
+
+ return IPCA_OK;
+}
+
+void IPCAElevatorClient::DiscoverElevator1Callback(
+ void* context,
+ IPCADeviceStatus deviceStatus,
+ const IPCADiscoveredDeviceInfo* discoveredDeviceInfo)
+{
+ OC_UNUSED(deviceStatus);
+ OC_UNUSED(context);
+
+ if (g_elevator1Name.compare(discoveredDeviceInfo->deviceName) == 0)
+ {
+ m_discoveredElevator1DeviceUris.clear();
+ for (int i = 0; i < discoveredDeviceInfo->deviceUriCount; i++)
+ {
+ m_discoveredElevator1DeviceUris.push_back(discoveredDeviceInfo->deviceUris[i]);
+ }
+
+ m_discoveredElevator1DeviceId = discoveredDeviceInfo->deviceId;
+ m_discoveredElevator1DeviceName = discoveredDeviceInfo->deviceId;
+ m_elevator1Discovered = true;
+ m_deviceDiscoveredCV.notify_all();
+ }
+}
+
+void C_DiscoverElevator1Cb(void* context,
+ IPCADeviceStatus deviceStatus,
+ const IPCADiscoveredDeviceInfo* discoveredDeviceInfo)
+{
+ IPCAElevatorClient* ipcaTest = (IPCAElevatorClient*)context;
+ ipcaTest->DiscoverElevator1Callback(context, deviceStatus, discoveredDeviceInfo);
+}
+
+void IPCAElevatorClient::DiscoverElevator1()
+{
+ // Resource types to work with, an elevator device with vertical function (ipca.test.elevator)
+ // and standard OCF resource type (carbon monoxide detection).
+ const char* RequiredResourceTypes[] = {
+ ELEVATOR_RESOURCE_TYPE,
+ ELEVATOR_CO_RESOURCE_TYPE,
+ ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH_TYPE,
+ ELEVATOR_RESOURCE_DELETE_TYPE
+ };
+
+ const int ResourceTypeCount = sizeof(RequiredResourceTypes) / sizeof(char*);
+
+ // Start discovery.
+ IPCAStatus status = IPCADiscoverDevices(
+ m_ipcaAppHandle,
+ &C_DiscoverElevator1Cb,
+ (void*)this,
+ RequiredResourceTypes,
+ ResourceTypeCount,
+ &m_deviceDiscoveryHandle);
+
+ ASSERT_EQ(IPCA_OK, status);
+
+ // Wait for the callback.
+ std::unique_lock<std::mutex> lock(m_deviceDiscoveredCVMutex);
+ m_deviceDiscoveredCV.wait_for(
+ lock,
+ std::chrono::seconds(10),
+ [this]{ return IsElevator1Discovered(); });
+
+ ASSERT_EQ(true, IsElevator1Discovered());
+ ASSERT_EQ(IPCA_OK, IPCAOpenDevice(m_ipcaAppHandle,
+ m_discoveredElevator1DeviceId.c_str(), &m_deviceHandle));
+}
+
+void IPCAElevatorClient::SetPropertiesCallback(IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ OC_UNUSED(propertyBagHandle);
+ OC_UNUSED(context);
+ OC_UNUSED(result);
+
+ m_setPropertiesCallbackCalled = true;
+ m_setPropertiesCompleteCV.notify_all();
+}
+
+void IPCAElevatorClient::GetPropertiesCallback(IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ OC_UNUSED(context);
+
+ m_getPropertiesCallbackCalled = true;
+ m_statusOfLastCallback = result;
+
+ if (propertyBagHandle != nullptr)
+ {
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueInt(propertyBagHandle,
+ ELEVATOR_PROPERTY_CURRENT_FLOOR, &m_currentFloor));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueInt(propertyBagHandle,
+ ELEVATOR_PROPERTY_DIRECTION, &m_direction));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueInt(propertyBagHandle,
+ ELEVATOR_PROPERTY_TARGET_FLOOR, &m_targetFloor));
+ }
+
+ m_getDataCompleteCbCV.notify_all();
+}
+
+void IPCAElevatorClient::CreateResourceCallback(IPCAStatus result,
+ const char* newResourcePath,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ OC_UNUSED(result);
+ OC_UNUSED(propertyBagHandle);
+
+ m_newResourcePath = (newResourcePath != nullptr) ? newResourcePath : "";
+ m_createResourceCallbackCalled = true;
+ m_createResourceCompleteCV.notify_all();
+}
+
+void IPCAElevatorClient::DeleteResourceCallback(IPCAStatus result)
+{
+ OC_UNUSED(result);
+
+ m_deleteResourceCallbackCalled = true;
+ m_deleteResourceCompleteCV.notify_all();
+}
+
+void IPCAElevatorClient::ResourceChangeNotificationCallback(IPCAStatus result,
+ IPCAPropertyBagHandle propertyBagHandle)
+{
+ EXPECT_EQ(IPCA_OK, result);
+
+ IPCAPropertyBagGetValueInt(propertyBagHandle,
+ ELEVATOR_PROPERTY_CURRENT_FLOOR, &m_observedCurrentFloor);
+ IPCAPropertyBagGetValueInt(propertyBagHandle,
+ ELEVATOR_PROPERTY_DIRECTION, &m_observedDirection);
+ IPCAPropertyBagGetValueInt(propertyBagHandle,
+ ELEVATOR_PROPERTY_TARGET_FLOOR, &m_observedTargetFloor);
+
+ m_resourceChangeCbCV.notify_all();
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef IPCA_ELEVATOR_CLIENT_H
+#define IPCA_ELEVATOR_CLIENT_H
+
+/**
+ * Class that asssists testing IPCA apis.
+ */
+class IPCAElevatorClient : public testing::Test
+{
+public:
+ // Discovery functionalities
+ bool IsElevator1Discovered() { return m_elevator1Discovered; }
+ IPCAStatus ConfirmDeviceAndPlatformInfo();
+ IPCAStatus ConfirmResources();
+ IPCAStatus ConfirmResourceTypes();
+ IPCAStatus ConfirmResourceInterfaces();
+
+ // Use IPCA to get the elevator's current floor.
+ void GetCurrentFloor(int* currentFloor, bool* result);
+ void GetTargetFloor(int* targetFloor, bool* result);
+ void SetTargetFloor(int targetFloor, bool* result);
+ void CreateResourceRelativePath();
+ const char* GetNewResourceURI() { return m_newResourcePath.c_str(); }
+ void CreateResouceExplicitPath();
+ void DeleteResource();
+
+ // These are values updated by notifications.
+ int GetObservedCurrentFloor() { return m_observedCurrentFloor; }
+ int GetObservedTargetFloor() { return m_observedTargetFloor; }
+ int GetObservedDirection() { return m_observedDirection; }
+
+ // Use IPCA to start/stop observing elevator resource.
+ IPCAHandle m_observeHandle;
+ std::mutex m_resourceChangeCbMutex;
+ std::condition_variable m_resourceChangeCbCV;
+ bool StartObserve();
+ void StopObserve();
+
+ // Helper functions
+ IPCAStatus FactoryResetElevator();
+ IPCAStatus RebootElevator();
+
+ void DiscoverElevator1();
+ void DiscoverElevator1Callback(
+ void* context,
+ IPCADeviceStatus deviceStatus,
+ const IPCADiscoveredDeviceInfo* discoveredDeviceInfo);
+
+ void GetPropertiesCallback(
+ IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle);
+
+ void SetPropertiesCallback(
+ IPCAStatus result,
+ void* context,
+ IPCAPropertyBagHandle propertyBagHandle);
+
+ void CreateResourceCallback(
+ IPCAStatus result,
+ const char* newResourcePath,
+ IPCAPropertyBagHandle propertyBagHandle);
+
+ void DeleteResourceCallback(IPCAStatus result);
+
+ void ResourceChangeNotificationCallback(
+ IPCAStatus result,
+ IPCAPropertyBagHandle propertyBagHandle);
+
+ // Failure cases.
+ IPCAStatus GetUnknownResource();
+ IPCAStatus SetUnknownResource();
+ bool SetUnknoownInterface();
+
+private:
+ IPCAAppHandle m_ipcaAppHandle;
+ IPCAHandle m_deviceDiscoveryHandle;
+ IPCADeviceHandle m_deviceHandle;
+
+ int m_currentFloor;
+ int m_targetFloor;
+ int m_direction;
+
+ int m_observedCurrentFloor;
+ int m_observedDirection;
+ int m_observedTargetFloor;
+
+ // Used by IPCADiscoverDevices() tests.
+ bool m_elevator1Discovered;
+ std::string m_discoveredElevator1DeviceName;
+ std::string m_discoveredElevator1DeviceId;
+ std::vector<std::string> m_discoveredElevator1DeviceUris;
+ std::mutex m_deviceDiscoveredCVMutex;
+ std::condition_variable m_deviceDiscoveredCV; // conditional variable to wake up thread waiting
+ // for device discovered callback.
+
+ // Used by IPCAGetProperties() tests.
+ bool m_getPropertiesCallbackCalled;
+ IPCAStatus m_statusOfLastCallback; // the IPCAStatus of the last callback.
+ std::mutex m_getDataCompleteCbMutex;
+ std::condition_variable m_getDataCompleteCbCV;
+
+ // Used by IPCASetProperties() tests.
+ bool m_setPropertiesCallbackCalled;
+ std::mutex m_setPropertiesCompleteCbMutex;
+ std::condition_variable m_setPropertiesCompleteCV;
+
+ // Used by IPCACreateResource() tests
+ std::string m_newResourcePath;
+ bool m_createResourceCallbackCalled;
+ std::mutex m_createResourceCompleteCbMutex;
+ std::condition_variable m_createResourceCompleteCV;
+
+ // Used by IPCADeleteResource() tests
+ bool m_deleteResourceCallbackCalled;
+ std::mutex m_deleteResourceCompleteCbMutex;
+ std::condition_variable m_deleteResourceCompleteCV;
+
+ bool GetElevatorProperties();
+ bool SetElevatorProperties(IPCAPropertyBagHandle propertyBagHandle);
+ bool CreateElevatorResource(
+ std::string resourcePath, IPCAPropertyBagHandle propertyBagHandle);
+ bool DeleteElevatorResource();
+
+protected:
+ virtual void SetUp();
+ virtual void TearDown();
+};
+
+#endif // IPCA_ELEVATOR_CLIENT_H
--- /dev/null
+{
+ "acl": {
+ "aclist": {
+ "aces": [
+ {
+ "subjectuuid": "*",
+ "resources": [
+ {
+ "href": "/oic/res",
+ "rel": "",
+ "rt": ["oic.wk.res"],
+ "if": ["oic.if.ll"]
+ },
+ {
+ "href": "/oic/d",
+ "rel": "",
+ "rt": ["oic.wk.d"],
+ "if": ["oic.if.baseline", "oic.if.r"]
+ },
+ {
+ "href": "/oic/p",
+ "rel": "",
+ "rt": ["oic.wk.p"],
+ "if": ["oic.if.baseline", "oic.if.r"]
+ },
+ {
+ "href": "/oic/sec/acl",
+ "rel": "",
+ "rt": ["oic.r.acl"],
+ "if": ["oic.if.baseline"]
+ }
+ ],
+ "permission": 2
+ },
+ {
+ "subjectuuid": "*",
+ "resources": [
+ {
+ "href": "/oic/sec/doxm",
+ "rel": "",
+ "rt": ["oic.r.doxm"],
+ "if": ["oic.if.baseline"]
+ },
+ {
+ "href": "/oic/sec/pstat",
+ "rel": "",
+ "rt": ["oic.r.pstat"],
+ "if": ["oic.if.baseline"]
+ }
+ ],
+ "permission": 2
+ },
+ {
+ "subjectuuid": "32323232-3232-3232-3232-323232323232",
+ "resources": [
+ {
+ "href": "/oic/sec/cred",
+ "rel": "",
+ "rt": ["oic.r.cred"],
+ "if": ["oic.if.baseline"]
+ }
+ ],
+ "permission": 8
+ },
+ {
+ "subjectuuid": "31393139-3139-3139-3139-313931393139",
+ "resources": [
+ {
+ "href": "/a/led",
+ "rel": "",
+ "rt": ["oic.core"],
+ "if": ["oic.if.baseline"]
+ }
+ ],
+ "permission": 6
+ },
+ {
+ "subjectuuid": "37373737-3737-3737-3737-373737373737",
+ "resources": [
+ {
+ "href": "/ipca/test/elevator",
+ "rel": "",
+ "rt": ["x.ipca.test.elevator"],
+ "if": ["oic.if.baseline"]
+ }
+ ],
+ "permission": 6
+ }
+ ]
+ },
+ "rowneruuid" : "31313131-3131-3131-3131-313131313131"
+ },
+ "pstat": {
+ "isop": true,
+ "deviceuuid": "31313131-3131-3131-3131-313131313131",
+ "rowneruuid": "31313131-3131-3131-3131-313131313131",
+ "cm": 0,
+ "tm": 0,
+ "om": 4,
+ "sm": 4
+ },
+ "doxm": {
+ "oxms": [0],
+ "oxmsel": 0,
+ "sct": 1,
+ "owned": true,
+ "deviceuuid": "31313131-3131-3131-3131-313131313131",
+ "devowneruuid": "31313131-3131-3131-3131-313131313131",
+ "rowneruuid": "31313131-3131-3131-3131-313131313131"
+ },
+ "cred": {
+ "creds": [
+ {
+ "credid": 1,
+ "subjectuuid": "32323232-3232-3232-3232-323232323232",
+ "credtype": 1,
+ "period": "20150630T060000/20990920T220000",
+ "privatedata": {
+ "data": "AAAAAAAAAAAAAAAA",
+ "encoding": "oic.sec.encoding.raw"
+ }
+ },
+ {
+ "credid": 2,
+ "subjectuuid": "31393139-3139-3139-3139-313931393139",
+ "credtype": 1,
+ "period": "20150630T060000/20990920T220000",
+ "privatedata": {
+ "data": "BBBBBBBBBBBBBBBB",
+ "encoding": "oic.sec.encoding.raw"
+ }
+ }
+ ],
+ "rowneruuid": "31313131-3131-3131-3131-313131313131"
+ }
+}
--- /dev/null
+#******************************************************************
+#
+# Copyright 2017 Microsoft
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+import os
+import os.path
+
+# Set to 1 for the test elevator client and elevator server to communicate through IoTivity stack.
+use_iotivity = 0
+
+Import('test_env')
+ipcatest_env = test_env.Clone()
+src_dir = ipcatest_env.get('SRC_DIR')
+target_os = ipcatest_env.get('TARGET_OS')
+rd_mode = ipcatest_env.get('RD_MODE')
+
+ipcatest_env.AppendUnique(CCFLAGS=['/W4'])
+
+######################################################################
+# Build flags
+######################################################################
+ipcatest_env.AppendUnique(CPPPATH = [
+ '#/resource/include',
+ '#/resource/oc_logger/include',
+ '#/resource/csdk/include',
+ '#/resource/csdk/stack/include',
+ '#/resource/csdk/security/include',
+ '#/resource/csdk/security/provisioning/include',
+ '#/resource/csdk/security/provisioning/include/internal',
+ '#/resource/csdk/stack/include/internal',
+ '#/resource/csdk/connectivity/api',
+ '#/resource/csdk/connectivity/external/inc',
+ '#/resource/csdk/ocsocket/include',
+ '#/resource/csdk/logger/include',
+ '#/resource/c_common/ocrandom/include',
+ '#/extlibs/boost/boost',
+ '#/extlibs/libcoap/libcoap/include',
+ '../inc',
+ '../src/inc'
+ ])
+
+ipcatest_env.PrependUnique(LIBS = [
+ 'oc_logger',
+ 'octbstack',
+ 'ipca_static'
+ ])
+
+if use_iotivity == 1:
+ ipcatest_env.PrependUnique(LIBS = [
+ 'oc',
+ 'connectivity_abstraction',
+ 'coap',
+ ])
+
+ if ipcatest_env.get('SECURED') == '1':
+ ipcatest_env.PrependUnique(LIBS = [
+ 'mbedtls',
+ 'mbedx509',
+ 'mbedcrypto',
+ 'ocprovision'
+ ])
+
+if target_os in ['msys_nt', 'windows']:
+ ipcatest_env.AppendUnique(LINKFLAGS = ['/subsystem:CONSOLE'])
+
+if 'CLIENT' in rd_mode or 'SERVER' in rd_mode:
+ ipcatest_env.PrependUnique(LIBS = ['resource_directory'])
+
+######################################################################
+# Source files and Targets
+######################################################################
+
+unittests_src = [
+ 'IPCAUnitTests.cpp',
+ 'IPCAElevatorClient.cpp',
+ 'TestElevatorServer.cpp',
+ 'TestElevatorClient.cpp'
+ ]
+
+if use_iotivity == 0:
+ unittests_src += [
+ 'mockOC.cpp',
+ 'mockInProcClientWrapper.cpp',
+ 'mockInProcServerWrapper.cpp',
+ 'mockOCPlatform_impl.cpp',
+ '#/resource/src/OCRepresentation.cpp'
+ ]
+
+ if ipcatest_env.get('SECURED') == '1':
+ unittests_src += ['../src/pretendocprovision.cpp']
+
+ipcatest_src_dir = os.path.join(src_dir, 'resource', 'ipca', 'unittests') + os.sep
+ipcatest_build_dir = os.path.join(
+ ipcatest_env.get('BUILD_DIR'), 'resource', 'ipca', 'unittests') + os.sep
+
+ipcatest_env.Alias("install", ipcatest_env.Install( ipcatest_build_dir,
+ ipcatest_src_dir + 'IPCAUnitTest.json'))
+ipcatest_env.Alias("install", ipcatest_env.Install( ipcatest_build_dir,
+ ipcatest_src_dir + 'IPCAUnitTest.dat'))
+
+ipcatests = ipcatest_env.Program('ipcatests', unittests_src)
+
+if target_os in ['windows']:
+ #path to ipca.dll
+ ipcatest_env.AppendENVPath('PATH', ipcatest_env.get('BUILD_DIR'))
+
+if ipcatest_env.get('TEST') == '1':
+ if target_os in ['windows']:
+ # Disabled for VS2013 due to https://jira.iotivity.org/browse/IOT-1842.
+ if '14.0' == ipcatest_env['MSVC_VERSION']:
+ from tools.scons.RunTest import *
+ run_test(ipcatest_env,
+ 'resource_ipca_unittests.memcheck',
+ 'resource/ipca/unittests/ipcatests',
+ ipcatests)
+
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef IPCATESTDATA_H_
+#define IPCATESTDATA_H_
+
+static char* ELEVATOR_PLATFORM_ID = "2386034c-8099-11e6-ae22-56b6b6499611";
+static char* ELEVATOR_PLATFORM_INDEPENDENT_ID = "be182fc4-f336-11e6-bc64-92361f002671";
+static char* ELEVATOR_DATA_MODEL_VERSION_1 = "x.org.iotivity.test.1.0.0";
+static char* ELEVATOR_DATA_MODEL_VERSION_2 = "x.org.iotivity.test.2.0.0";
+static char* ELEVATOR_DATA_MODEL_VERSION_3 = "x.org.iotivity.test.3.0.0";
+
+static char* ELEVATOR_RESOURCE_PATH = "/ipca/test/elevator";
+static char* ELEVATOR_RESOURCE_TYPE = "x.org.iotivity.test.elevator";
+static char* ELEVATOR_PROPERTY_CURRENT_FLOOR = "x.org.iotivity.CurrentFloor";
+static char* ELEVATOR_PROPERTY_TARGET_FLOOR = "x.org.iotivity.TargetFloor";
+static char* ELEVATOR_PROPERTY_DIRECTION = "x.org.iotivity.Direction";
+
+static char* ELEVATOR_RESOURCE_MADE_UP_INTERFACE = "non.existence.if";
+
+static char* ELEVATOR_CO_RESOURCE_PATH = "/ipca/test/carbonmonoxide";
+static char* ELEVATOR_CO_RESOURCE_TYPE = "oic.r.sensor.carbonmonoxide";
+static char* ELEVATOR_CO_PRIVATE_INTERFACE = "my.private.if";
+
+static char* ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH = "/ipca/new/resource/relative";
+static char* ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH_TYPE = "x.ipca.test.elevator.create.resource.relative";
+static char* ELEVATOR_RESOURCE_NEW_RESOURCE_PATH = "/ipca/new/resource/relative/1";
+
+static char* ELEVATOR_RESOURCE_CREATE_EXPLICIT_PATH = "/ipca/new/resource/explicit";
+static char* ELEVATOR_RESOURCE_CREATE_EXPLICIT_PATH_TYPE = "x.ipca.test.elevator.create.resource.explicit";
+
+static char* ELEVATOR_RESOURCE_DELETE_PATH = "/ipca/resource/delete";
+static char* ELEVATOR_RESOURCE_DELETE_TYPE = "x.ipca.test.elevator.delete";
+
+static char* ELEVATOR_KEYWORD = "elevator";
+#endif // IPCATESTDATA_H_
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include <thread>
+#include <chrono>
+#include <mutex>
+#include <condition_variable>
+
+#include "gtest/gtest.h"
+#include "ocrandom.h"
+#include "ipca.h"
+#include "testelevatorserver.h"
+#include "testelevatorclient.h"
+#include "ipcatestdata.h"
+#include "ipcaelevatorclient.h"
+
+using namespace std;
+using namespace std::placeholders;
+
+// Implemented in ipca.dll.
+void IPCASetUnitTestMode();
+
+// IPCA test app info.
+IPCAUuid IPCATestAppUuid = {0x84, 0x71, 0x88, 0x78, 0xe6, 0x91, 0x4b, 0xf4,
+ 0xa9, 0x57, 0x04, 0xe0, 0x1b, 0x9b, 0x59, 0xd1};
+char IPCATestAppName[] = "IPCA Unittests";
+
+// IoTivity supports 1 server per instance.
+ElevatorServer g_testElevator1;
+
+// The elevator's name is suffixed with random number to differentiate it from elevators from
+// other unit tests.
+std::string g_elevator1Name;
+
+/**
+ * Start elevator 1.
+ */
+bool StartElevator1()
+{
+ // One time generation of the elevator's device name.
+ if (g_elevator1Name.length() == 0)
+ {
+ char uuidString[37] = {};
+ uint8_t uuid[UUID_SIZE] = {};
+ OCGenerateUuid(uuid);
+ OCConvertUuidToString(uuid, uuidString);
+
+ g_elevator1Name = "IPCA Test Elevator ";
+
+ // e.g., IPCA Test Elevator 2923be84-e16c-d6ae-5290-49f1f1bbe9eb
+ g_elevator1Name.append(uuidString);
+ }
+
+ bool result = g_testElevator1.Start(g_elevator1Name);
+ return result;
+}
+
+/**
+ * Stop elevator 1.
+ */
+void StopElevator1()
+{
+ g_testElevator1.Stop();
+}
+
+// Start the test elevator once and use it through out the rest of the tests.
+TEST(ElevatorServerStart, start)
+{
+ IPCASetUnitTestMode();
+ ASSERT_TRUE(StartElevator1());
+}
+
+// Test IoTivity api directly before subsequent tests which use IPCA apis.
+TEST(IoTivityDirect, IsIoTivityWorking)
+{
+ ElevatorClient elevatorClient;
+ int loopCount;
+
+ // Able to find the elevator server.
+ elevatorClient.FindElevator(g_elevator1Name);
+ loopCount = 0;
+ while ((loopCount++ < 100) && (elevatorClient.IsElevatorFound() == false))
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+ ASSERT_EQ(true, elevatorClient.IsElevatorFound());
+
+ // Confirm able to set target floor using IoTivity client API and read the value back from the
+ // elevator server.
+ loopCount = 0;
+ const int TARGET_FLOOR = 3;
+ elevatorClient.SetTargetFloor(TARGET_FLOOR);
+ while ((loopCount++ < 20) && (g_testElevator1.GetCurrentFloor() != TARGET_FLOOR))
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+ EXPECT_EQ(TARGET_FLOOR, g_testElevator1.GetCurrentFloor());
+
+ // Confirm able to get current floor using IoTivity client API. The current floor should be
+ // TARGET_FLOOR.
+ int m_currentFloor;
+ elevatorClient.GetCurrentFloor(&m_currentFloor);
+ EXPECT_EQ(g_testElevator1.GetCurrentFloor(), m_currentFloor);
+
+ // Confirm observation by setting the target floor to NEW_TARGET_FLOOR.
+ // The client should receive current floor notification that it reaches the NEW_TARGET_FLOOR.
+ const int NEW_TARGET_FLOOR = 8;
+ bool returnValue = elevatorClient.StartObservation();
+ EXPECT_TRUE(returnValue);
+ elevatorClient.SetTargetFloor(NEW_TARGET_FLOOR);
+ while ((loopCount++ < 20) && (elevatorClient.GetObservedCurrentFloor() != NEW_TARGET_FLOOR))
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+ EXPECT_EQ(NEW_TARGET_FLOOR, elevatorClient.GetObservedCurrentFloor());
+ returnValue = elevatorClient.StopObservation();
+ EXPECT_TRUE(returnValue);
+}
+
+/*
+ * IPCA property bag tests.
+ */
+class IPCAPropertyBagTest : public testing::Test
+{
+ public:
+ IPCAPropertyBagHandle m_propertyBagHandle;
+
+ // Create a property bag containing an integar value.
+ void CreateIntPropertyBag(IPCAPropertyBagHandle& propertyBagHandle, const char* key, int value)
+ {
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle));
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagSetValueInt(propertyBagHandle, key, value));
+ }
+
+ public:
+ int m_intValue;
+ double m_doubleValue;
+ char* m_charPointerValue;
+
+ protected:
+ virtual void SetUp()
+ {
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagCreate(&m_propertyBagHandle));
+ }
+ virtual void TearDown()
+ {
+ IPCAPropertyBagDestroy(m_propertyBagHandle);
+ }
+};
+
+TEST_F(IPCAPropertyBagTest, PropertyBagNonExistenceAttribute)
+{
+ EXPECT_EQ(IPCA_FAIL, IPCAPropertyBagGetValueInt(m_propertyBagHandle,
+ "NonexistenceAttribute", &m_intValue));
+}
+
+TEST_F(IPCAPropertyBagTest, PropertyBagInt)
+{
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagSetValueInt(m_propertyBagHandle, "IntValue", 3));
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagGetValueInt(m_propertyBagHandle, "IntValue", &m_intValue));
+ EXPECT_EQ(3, m_intValue);
+}
+
+TEST_F(IPCAPropertyBagTest, PropertyBagDouble)
+{
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagSetValueDouble(m_propertyBagHandle,
+ "DoubleValue", 12345678));
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagGetValueDouble(m_propertyBagHandle,
+ "DoubleValue", &m_doubleValue));
+ EXPECT_EQ(12345678, m_doubleValue);
+
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagSetValueDouble(m_propertyBagHandle,
+ "DoubleValue", 1234.5678));
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagGetValueDouble(m_propertyBagHandle,
+ "DoubleValue", &m_doubleValue));
+ EXPECT_EQ(1234.5678, m_doubleValue);
+
+ EXPECT_EQ(IPCA_FAIL, IPCAPropertyBagGetValueDouble(m_propertyBagHandle,
+ "doubleValue", &m_doubleValue)); // incorrect capital case
+}
+
+TEST_F(IPCAPropertyBagTest, PropertyBagBool)
+{
+ bool trueBool, falseBool;
+
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagSetValueBool(m_propertyBagHandle,
+ "TrueBoolValue", true));
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagGetValueBool(m_propertyBagHandle,
+ "TrueBoolValue", &trueBool));
+ EXPECT_TRUE(trueBool);
+
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagSetValueBool(m_propertyBagHandle,
+ "FalseBoolValue", false));
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagGetValueBool(m_propertyBagHandle,
+ "FalseBoolValue", &falseBool));
+ EXPECT_FALSE(falseBool);
+}
+
+TEST_F(IPCAPropertyBagTest, PropertyBagString)
+{
+ ASSERT_EQ(IPCA_OK, IPCAPropertyBagSetValueString(m_propertyBagHandle,
+ "MyString", "Hello World"));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueString(m_propertyBagHandle,
+ "MyString", &m_charPointerValue));
+ EXPECT_STREQ("Hello World", m_charPointerValue);
+ IPCAPropertyBagFreeString(m_charPointerValue);
+}
+
+TEST_F(IPCAPropertyBagTest, PropertyBagPropertyBagType)
+{
+ IPCAPropertyBagHandle propertyBagHandle1, propertyBagHandle2, propertyBagHandle3;
+ CreateIntPropertyBag(propertyBagHandle1, "IntValue1", 1);
+ CreateIntPropertyBag(propertyBagHandle2, "IntValue2", 2);
+ CreateIntPropertyBag(propertyBagHandle3, "IntValue3", 3);
+
+ // Add propertyBagHandle1 to 3 to propertyBagHandle.
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValuePropertyBag(m_propertyBagHandle,
+ "PropertyBag1", propertyBagHandle1));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValuePropertyBag(m_propertyBagHandle,
+ "PropertyBag2", propertyBagHandle2));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValuePropertyBag(m_propertyBagHandle,
+ "PropertyBag3", propertyBagHandle3));
+
+ // The original is no longer needed.
+ IPCAPropertyBagDestroy(propertyBagHandle1);
+ IPCAPropertyBagDestroy(propertyBagHandle2);
+ IPCAPropertyBagDestroy(propertyBagHandle3);
+
+ // Read back each property bag object and compare with the original values.
+ IPCAPropertyBagHandle propertyBag1;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValuePropertyBag(m_propertyBagHandle,
+ "PropertyBag1", &propertyBag1));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueInt(propertyBag1,
+ "IntValue1", &m_intValue));
+ EXPECT_EQ(1, m_intValue);
+ IPCAPropertyBagDestroy(propertyBag1);
+
+ IPCAPropertyBagHandle propertyBag2;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValuePropertyBag(m_propertyBagHandle,
+ "PropertyBag2", &propertyBag2));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueInt(propertyBag2,
+ "IntValue2", &m_intValue));
+ EXPECT_EQ(2, m_intValue);
+ IPCAPropertyBagDestroy(propertyBag2);
+
+ IPCAPropertyBagHandle propertyBag3;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValuePropertyBag(m_propertyBagHandle,
+ "PropertyBag3", &propertyBag3));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueInt(propertyBag3,
+ "IntValue3", &m_intValue));
+ EXPECT_EQ(3, m_intValue);
+
+ IPCAPropertyBagDestroy(propertyBag3);
+}
+
+TEST_F(IPCAPropertyBagTest, PropertyBagIntArrayType)
+{
+ // array of int
+ int intArray[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueIntArray(m_propertyBagHandle,
+ "IntArray", intArray, 10));
+
+ int* readBackIntArray;
+ size_t readBackIntArraySize;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueIntArray(m_propertyBagHandle,
+ "IntArray", &readBackIntArray, &readBackIntArraySize));
+ EXPECT_EQ(10, readBackIntArraySize);
+ EXPECT_EQ(0, memcmp(intArray, readBackIntArray, readBackIntArraySize));
+
+ IPCAPropertyBagFreeIntArray(readBackIntArray);
+}
+
+TEST_F(IPCAPropertyBagTest, PropertyBagDoubleArrayType)
+{
+ // array of double
+ double doubleArray[] = {1.01, 2.02, 3.03, 4.04, 5.05, 6.06, 7.07, 8.08, 9.09, 10.010};
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueDoubleArray(m_propertyBagHandle,
+ "DoubleArray", doubleArray, 10));
+
+ double* readBackDoubleArray;
+ size_t readBackDoubleArraySize;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueDoubleArray(m_propertyBagHandle,
+ "DoubleArray", &readBackDoubleArray, &readBackDoubleArraySize));
+ EXPECT_EQ(10, readBackDoubleArraySize);
+ EXPECT_EQ(0, memcmp(doubleArray, readBackDoubleArray, readBackDoubleArraySize));
+
+ IPCAPropertyBagFreeDoubleArray(readBackDoubleArray);
+}
+
+TEST_F(IPCAPropertyBagTest, PropertyBagBoolArrayType)
+{
+ // array of bool
+ bool boolArray[] = {true, true, false, false, true, false, true, false, false, false};
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueBoolArray(m_propertyBagHandle,
+ "boolArray", boolArray, 10));
+
+ bool* readBackBoolArray;
+ size_t readBackBoolArraySize;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueBoolArray(m_propertyBagHandle,
+ "boolArray", &readBackBoolArray, &readBackBoolArraySize));
+ EXPECT_EQ(10, readBackBoolArraySize);
+ EXPECT_EQ(0, memcmp(boolArray, readBackBoolArray, readBackBoolArraySize));
+
+ IPCAPropertyBagFreeBoolArray(readBackBoolArray);
+}
+
+TEST_F(IPCAPropertyBagTest, PropertyBagStringArrayType)
+{
+ // array of string
+ char* stringArray[] = {"hello world 1", "hello world 2", "hello world 3"};
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueStringArray(m_propertyBagHandle,
+ "stringArray", (const char**)stringArray, 3));
+
+ char** readBackString;
+ size_t readbackStringSize;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueStringArray(m_propertyBagHandle,
+ "stringArray", &readBackString, &readbackStringSize));
+ ASSERT_EQ(3, readbackStringSize);
+ EXPECT_STREQ(stringArray[0], readBackString[0]);
+ EXPECT_STREQ(stringArray[1], readBackString[1]);
+ EXPECT_STREQ(stringArray[2], readBackString[2]);
+ IPCAPropertyBagFreeStringArray(readBackString, readbackStringSize);
+}
+
+TEST_F(IPCAPropertyBagTest, PropertyBagPropertyBagArrayType)
+{
+ IPCAPropertyBagHandle propertyBagHandle1, propertyBagHandle1A;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle1));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle1A));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueInt(propertyBagHandle1A, "IntKey1", 1));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueString(propertyBagHandle1A, "StringKey1", "One"));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValuePropertyBag(propertyBagHandle1,
+ "values", propertyBagHandle1A));
+
+ IPCAPropertyBagHandle propertyBagHandle2, propertyBagHandle2A;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle2));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle2A));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueInt(propertyBagHandle2A, "IntKey2", 2));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueString(propertyBagHandle2A, "StringKey2", "Two"));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValuePropertyBag(propertyBagHandle2,
+ "values", propertyBagHandle2A));
+
+ IPCAPropertyBagHandle propertyBagHandle3, propertyBagHandle3A;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle3));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagCreate(&propertyBagHandle3A));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueInt(propertyBagHandle3A, "IntKey3", 3));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValueString(propertyBagHandle3A, "StringKey3", "Three"));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValuePropertyBag(propertyBagHandle3,
+ "values", propertyBagHandle3A));
+
+ IPCAPropertyBagHandle propertyBagArray[] = {
+ propertyBagHandle1, propertyBagHandle2, propertyBagHandle3 };
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagSetValuePropertyBagArray(m_propertyBagHandle,
+ "PropertyBagArray", propertyBagArray, 3));
+
+ // the original is no longer needed.
+ IPCAPropertyBagDestroy(propertyBagHandle3);
+ IPCAPropertyBagDestroy(propertyBagHandle3A);
+ IPCAPropertyBagDestroy(propertyBagHandle2);
+ IPCAPropertyBagDestroy(propertyBagHandle2A);
+ IPCAPropertyBagDestroy(propertyBagHandle1);
+ IPCAPropertyBagDestroy(propertyBagHandle1A);
+
+ // Read back each property bag object and compare with the original values.
+ IPCAPropertyBagHandle* propertyBagReadBackArray;
+ size_t arrayCount;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValuePropertyBagArray(m_propertyBagHandle,
+ "PropertyBagArray", &propertyBagReadBackArray, &arrayCount));
+ ASSERT_EQ(3, arrayCount);
+
+ IPCAPropertyBagHandle propertyBag1 = propertyBagReadBackArray[0], propertyBag1A;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValuePropertyBag(propertyBag1, "values", &propertyBag1A));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueInt(propertyBag1A, "IntKey1", &m_intValue));
+ EXPECT_EQ(1, m_intValue);
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueString(propertyBag1A,
+ "StringKey1", &m_charPointerValue));
+ EXPECT_STREQ("One", m_charPointerValue);
+
+ IPCAPropertyBagHandle propertyBag2 = propertyBagReadBackArray[1], propertyBag2A;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValuePropertyBag(propertyBag2, "values", &propertyBag2A));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueInt(propertyBag2A, "IntKey2", &m_intValue));
+ EXPECT_EQ(2, m_intValue);
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueString(propertyBag2A,
+ "StringKey2", &m_charPointerValue));
+ EXPECT_STREQ("Two", m_charPointerValue);
+
+ IPCAPropertyBagHandle propertyBag3 = propertyBagReadBackArray[2], propertyBag3A;
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValuePropertyBag(propertyBag3, "values", &propertyBag3A));
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueInt(propertyBag3A, "IntKey3", &m_intValue));
+ EXPECT_EQ(3, m_intValue);
+ EXPECT_EQ(IPCA_OK, IPCAPropertyBagGetValueString(propertyBag3A,
+ "StringKey3", &m_charPointerValue));
+ EXPECT_STREQ("Three", m_charPointerValue);
+
+ IPCAPropertyBagDestroy(propertyBag1A);
+ IPCAPropertyBagDestroy(propertyBag2A);
+ IPCAPropertyBagDestroy(propertyBag3A);
+}
+
+/*
+ * Test multiple IPCAOpen().
+ */
+
+class IPCAMiscTest : public testing::Test
+{
+ public:
+ IPCAAppHandle m_ipcaAppHandle;
+ IPCAAppHandle m_anotherIPCAAppHandle;
+ IPCAAppInfo m_ipcaAppInfo;
+
+ IPCAStatus DoAnotherIPCAOpen()
+ {
+ return IPCAOpen(&m_ipcaAppInfo, IPCA_VERSION_1, &m_anotherIPCAAppHandle);
+ }
+
+ protected:
+ virtual void SetUp()
+ {
+ m_anotherIPCAAppHandle = NULL;
+ m_ipcaAppInfo = { IPCATestAppUuid, IPCATestAppName, "1.0.0", "Microsoft" };
+ ASSERT_EQ(IPCA_OK, IPCAOpen(&m_ipcaAppInfo, IPCA_VERSION_1, &m_ipcaAppHandle));
+ }
+ virtual void TearDown()
+ {
+ if (m_ipcaAppHandle != NULL)
+ {
+ IPCAClose(m_ipcaAppHandle);
+ m_ipcaAppHandle = NULL;
+ }
+
+ if (m_anotherIPCAAppHandle != NULL)
+ {
+ IPCAClose(m_anotherIPCAAppHandle);
+ m_anotherIPCAAppHandle = NULL;
+ }
+ }
+};
+
+TEST_F(IPCAMiscTest, ShouldNotAllowMultipleCallsToIPCOpen)
+{
+ EXPECT_EQ(IPCA_ALREADY_OPENED, DoAnotherIPCAOpen());
+}
+
+TEST_F(IPCAMiscTest, IPCAOpenShouldBeAllowedAfterIPCAClose)
+{
+ IPCAClose(m_ipcaAppHandle);
+ m_ipcaAppHandle = NULL;
+
+ ASSERT_EQ(IPCA_OK, DoAnotherIPCAOpen());
+}
+
+/*
+ * IPCADiscoverDevices() must be called before IPCAOpenDevice().
+ */
+TEST_F(IPCAMiscTest, ShouldFailOpenDeviceWithoutDiscoveryFirst)
+{
+ IPCADeviceHandle deviceHandle;
+
+ // UUID is just random.
+ EXPECT_EQ(IPCA_DEVICE_NOT_DISCOVERED, IPCAOpenDevice(m_ipcaAppHandle,
+ "eee01972-8a91-11e6-ae22-56b6b6499611",
+ &deviceHandle));
+}
+
+TEST_F(IPCAElevatorClient, DiscoveryShouldFindElevatorServer)
+{
+ EXPECT_TRUE(IsElevator1Discovered());
+}
+
+TEST_F(IPCAElevatorClient, DiscoveryShouldFindDeviceAndPlatformInfo)
+{
+ EXPECT_EQ(IPCA_OK, ConfirmDeviceAndPlatformInfo());
+}
+
+TEST_F(IPCAElevatorClient, DiscoveryShouldFindElevatorResources)
+{
+ EXPECT_EQ(IPCA_OK, ConfirmResources());
+}
+
+TEST_F(IPCAElevatorClient, DiscoveryShouldFindTargetedResourceTypes)
+{
+ EXPECT_EQ(IPCA_OK, ConfirmResourceTypes());
+}
+
+TEST_F(IPCAElevatorClient, ShouldBeAbleToFilterOnResourceInterface)
+{
+ EXPECT_EQ(IPCA_OK, ConfirmResourceInterfaces());
+}
+
+TEST_F(IPCAElevatorClient, SuccessfullyGetDataFromElevatorServer)
+{
+ // Directly set target floor of the elevator to 8.
+ g_testElevator1.SetTargetFloor(8);
+
+ int elevatorTargetFloor;
+ bool result;
+
+ GetTargetFloor(&elevatorTargetFloor, &result);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(8, elevatorTargetFloor);
+}
+
+TEST_F(IPCAElevatorClient, ShouldFailGetUnknownResource)
+{
+ EXPECT_EQ(IPCA_RESOURCE_NOT_FOUND, GetUnknownResource());
+}
+
+TEST_F(IPCAElevatorClient, ShouldFailSetUnknownResource)
+{
+ EXPECT_EQ(IPCA_RESOURCE_NOT_FOUND, SetUnknownResource());
+}
+
+TEST_F(IPCAElevatorClient, ShouldFailSetWithUnknownInterface)
+{
+ size_t incorrectInterfaceCount = g_testElevator1.GetIncorrectInterfaceCount();
+ EXPECT_EQ(true, SetUnknoownInterface());
+ EXPECT_EQ((incorrectInterfaceCount + 1), g_testElevator1.GetIncorrectInterfaceCount());
+}
+
+TEST_F(IPCAElevatorClient, SuccessfullySetElevatorServerProperties)
+{
+ g_testElevator1.SetTargetFloor(1); // Set to known target floor.
+
+ bool result;
+ SetTargetFloor(8, &result); // Set it to 8th floor.
+ ASSERT_EQ(true, result);
+
+ // Now read back directly from the elevator.
+ int newTargetFloor = g_testElevator1.GetTargetFloor();
+ EXPECT_EQ(8, newTargetFloor);
+}
+
+TEST_F(IPCAElevatorClient, SuccessfullyCreateAndDeleteResources)
+{
+ // Do a few rounds of create resource with relative path.
+ size_t beforeCreateCount, afterCreateCount;
+ for (int i = 0 ; i < 3 ; i++)
+ {
+ beforeCreateCount = g_testElevator1.GetRelativePathResourceCreateCount();
+ CreateResourceRelativePath();
+ afterCreateCount = g_testElevator1.GetRelativePathResourceCreateCount();
+ ASSERT_EQ(beforeCreateCount + 1, afterCreateCount);
+ // @todo: when IOT-1819 is resolved.
+ // EXPECT_STREQ(ELEVATOR_RESOURCE_NEW_RESOURCE_PATH, GetNewResourceURI());
+ }
+
+ // Delete resource
+ size_t beforeDeleteCount, afterDeleteCount;
+ for (int i = 0 ; i < 3 ; i++)
+ {
+ beforeDeleteCount = g_testElevator1.GetDeleteResourceCount();
+ DeleteResource(); // the test elevator simply increments count,
+ // therefore can be deleted multiple times
+ afterDeleteCount = g_testElevator1.GetDeleteResourceCount();
+ ASSERT_EQ(beforeDeleteCount + 1, afterDeleteCount);
+ }
+}
+
+TEST_F(IPCAElevatorClient, SuccessfullyReceiveResourceChangeNotifications)
+{
+ // Set to known target floor.
+ g_testElevator1.SetTargetFloor(1);
+
+ // Start observing
+ ASSERT_EQ(true, StartObserve());
+
+ // Use IPCA to set the target floor.
+ bool result;
+ SetTargetFloor(10, &result); // Set to floor 10
+ ASSERT_EQ(true, result);
+
+ // Wait until observed current floor is set to targeted floor.
+ std::unique_lock<std::mutex> lock(m_resourceChangeCbMutex);
+ m_resourceChangeCbCV.wait_for(
+ lock,
+ std::chrono::seconds(10),
+ [this] { return GetObservedCurrentFloor() == 10; });
+
+ EXPECT_EQ(10, GetObservedCurrentFloor()); // check it is at floor 10.
+
+ StopObserve();
+}
+
+TEST_F(IPCAElevatorClient, SuccessfulFactoryReset)
+{
+ EXPECT_EQ(IPCA_OK, FactoryResetElevator());
+}
+
+TEST_F(IPCAElevatorClient, SuccessfulReboot)
+{
+ EXPECT_EQ(IPCA_OK, RebootElevator());
+}
+
+
+TEST(ElevatorServerStop, Stop)
+{
+ StopElevator1();
+}
--- /dev/null
+/* *****************************************************************\r
+ *\r
+ * Copyright 2017 Microsoft\r
+ *\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ ******************************************************************/\r
+\r
+#include "OCPlatform_impl.h"\r
+#include <OCPlatform.h>\r
+#include <OCResource.h>\r
+#include <string>\r
+#include "ipcatestdata.h"\r
+\r
+namespace OC\r
+{\r
+ // This is mocked because OCPlatform_impl instantiates the client and the server wrappers.\r
+ // There is no implementation in this file since the mock directly links the client and server\r
+ // apps.\r
+ InProcClientWrapper::InProcClientWrapper(\r
+ std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg)\r
+ : m_threadRun(false), m_csdkLock(csdkLock),\r
+ m_cfg { cfg }\r
+ {\r
+ }\r
+\r
+ InProcClientWrapper::~InProcClientWrapper()\r
+ {\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::start()\r
+ {\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::stop()\r
+ {\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ void InProcClientWrapper::listeningFunc()\r
+ {\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::ListenForResource(\r
+ const std::string& serviceUrl,\r
+ const std::string& resourceType,\r
+ OCConnectivityType connectivityType,\r
+ FindCallback& callback, QualityOfService QoS)\r
+ {\r\r
+ OC_UNUSED(serviceUrl);\r
+ OC_UNUSED(resourceType);\r
+ OC_UNUSED(connectivityType);\r
+ OC_UNUSED(callback);\r
+ OC_UNUSED(QoS);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::ListenErrorForResource(\r
+ const std::string& serviceUrl,\r
+ const std::string& resourceType,\r
+ OCConnectivityType connectivityType,\r
+ FindCallback& callback, FindErrorCallback& errorCallback,\r
+ QualityOfService QoS)\r
+ {\r
+ OC_UNUSED(serviceUrl);\r
+ OC_UNUSED(resourceType);\r
+ OC_UNUSED(connectivityType);\r
+ OC_UNUSED(callback);\r
+ OC_UNUSED(errorCallback);\r
+ OC_UNUSED(QoS);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+\r
+ OCStackResult InProcClientWrapper::ListenForResourceList(\r
+ const std::string& serviceUrl,\r
+ const std::string& resourceType,\r
+ OCConnectivityType connectivityType,\r
+ FindResListCallback& callback, QualityOfService QoS)\r
+ {\r
+ OC_UNUSED(serviceUrl);\r
+ OC_UNUSED(resourceType);\r
+ OC_UNUSED(connectivityType);\r
+ OC_UNUSED(callback);\r
+ OC_UNUSED(QoS);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::ListenForResourceListWithError(\r
+ const std::string& serviceUrl,\r
+ const std::string& resourceType,\r
+ OCConnectivityType connectivityType,\r
+ FindResListCallback& callback,\r
+ FindErrorCallback& errorCallback, QualityOfService QoS)\r
+ {\r
+ OC_UNUSED(serviceUrl);\r
+ OC_UNUSED(resourceType);\r
+ OC_UNUSED(connectivityType);\r
+ OC_UNUSED(callback);\r
+ OC_UNUSED(errorCallback);\r
+ OC_UNUSED(QoS);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::ListenForDevice(\r
+ const std::string& serviceUrl,\r
+ const std::string& deviceURI,\r
+ OCConnectivityType connectivityType,\r
+ FindDeviceCallback& callback,\r
+ QualityOfService QoS)\r
+ {\r
+ OC_UNUSED(serviceUrl);\r
+ OC_UNUSED(deviceURI);\r
+ OC_UNUSED(connectivityType);\r
+ OC_UNUSED(callback);\r
+ OC_UNUSED(QoS);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::GetResourceRepresentation(\r
+ const OCDevAddr& devAddr,\r
+ const std::string& resourceUri,\r
+ const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,\r
+ OCConnectivityType connectivityType,\r
+ GetCallback& callback, QualityOfService QoS)\r
+ {\r
+ OC_UNUSED(devAddr);\r
+ OC_UNUSED(resourceUri);\r
+ OC_UNUSED(queryParams);\r
+ OC_UNUSED(headerOptions);\r
+ OC_UNUSED(connectivityType);\r
+ OC_UNUSED(callback);\r
+ OC_UNUSED(QoS);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::PutResourceRepresentation(\r
+ const OCDevAddr& devAddr,\r
+ const std::string& uri,\r
+ const OCRepresentation& rep,\r
+ const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,\r
+ PutCallback& callback, QualityOfService QoS)\r
+ {\r
+ OC_UNUSED(devAddr);\r
+ OC_UNUSED(uri);\r
+ OC_UNUSED(rep);\r
+ OC_UNUSED(queryParams);\r
+ OC_UNUSED(headerOptions);\r
+ OC_UNUSED(callback);\r
+ OC_UNUSED(QoS);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::PostResourceRepresentation(\r
+ const OCDevAddr& devAddr,\r
+ const std::string& uri,\r
+ const OCRepresentation& rep,\r
+ const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,\r
+ OCConnectivityType connectivityType,\r
+ PostCallback& callback, QualityOfService QoS)\r
+ {\r
+ OC_UNUSED(devAddr);\r
+ OC_UNUSED(uri);\r
+ OC_UNUSED(rep);\r
+ OC_UNUSED(queryParams);\r
+ OC_UNUSED(headerOptions);\r
+ OC_UNUSED(connectivityType);\r
+ OC_UNUSED(callback);\r
+ OC_UNUSED(QoS);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+\r
+ OCStackResult InProcClientWrapper::DeleteResource(\r
+ const OCDevAddr& devAddr,\r
+ const std::string& uri,\r
+ const HeaderOptions& headerOptions,\r
+ OCConnectivityType connectivityType,\r
+ DeleteCallback& callback,\r
+ QualityOfService /*QoS*/)\r
+ {\r
+ OC_UNUSED(devAddr);\r
+ OC_UNUSED(uri);\r
+ OC_UNUSED(headerOptions);\r
+ OC_UNUSED(connectivityType);\r
+ OC_UNUSED(callback);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+\r
+ OCStackResult InProcClientWrapper::ObserveResource(ObserveType observeType, OCDoHandle* handle,\r
+ const OCDevAddr& devAddr,\r
+ const std::string& uri,\r
+ const QueryParamsMap& queryParams, const HeaderOptions& headerOptions,\r
+ ObserveCallback& callback, QualityOfService QoS)\r
+\r
+ {\r
+ OC_UNUSED(observeType);\r
+ OC_UNUSED(handle);\r
+ OC_UNUSED(devAddr);\r
+ OC_UNUSED(uri);\r
+ OC_UNUSED(queryParams);\r
+ OC_UNUSED(headerOptions);\r
+ OC_UNUSED(callback);\r
+ OC_UNUSED(QoS);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::CancelObserveResource(\r
+ OCDoHandle handle,\r
+ const std::string& /*host*/,\r
+ const std::string& /*uri*/,\r
+ const HeaderOptions& headerOptions,\r
+ QualityOfService QoS)\r
+\r
+ {\r
+ OC_UNUSED(handle);\r
+ OC_UNUSED(headerOptions);\r
+ OC_UNUSED(QoS);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::SubscribePresence(OCDoHandle* handle,\r
+ const std::string& host, const std::string& resourceType,\r
+ OCConnectivityType connectivityType, SubscribeCallback& presenceHandler)\r
+ {\r
+ OC_UNUSED(handle);\r
+ OC_UNUSED(host);\r
+ OC_UNUSED(resourceType);\r
+ OC_UNUSED(connectivityType);\r
+ OC_UNUSED(presenceHandler);\r
+\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+\r
+ OCStackResult InProcClientWrapper::UnsubscribePresence(OCDoHandle handle)\r
+ {\r
+ OC_UNUSED(handle);\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::GetDefaultQos(QualityOfService& qos)\r
+ {\r
+ OC_UNUSED(qos);\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+\r
+ OCStackResult InProcClientWrapper::FindDirectPairingDevices(unsigned short waittime,\r
+ GetDirectPairedCallback& callback)\r
+ {\r
+ OC_UNUSED(waittime);\r
+ OC_UNUSED(callback);\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::GetDirectPairedDevices(GetDirectPairedCallback& callback)\r
+ {\r
+ OC_UNUSED(callback);\r
+ return OC_STACK_OK;\r
+ }\r
+\r
+ OCStackResult InProcClientWrapper::DoDirectPairing(std::shared_ptr<OCDirectPairing> peer,\r
+ const OCPrm_t& pmSel, const std::string& pinNumber, DirectPairingCallback& callback)\r
+ {\r
+ OC_UNUSED(peer);\r
+ OC_UNUSED(pmSel);\r
+ OC_UNUSED(pinNumber);\r
+ OC_UNUSED(callback);\r
+ return OC_STACK_OK;\r
+ }\r
+}\r
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "OCPlatform_impl.h"
+#include <OCPlatform.h>
+#include <OCResource.h>
+#include <string>
+#include "ipcatestdata.h"
+
+namespace OC
+{
+ // This is mocked because OCPlatform_impl instantiates the client and the server wrappers.
+ // There is no implementation in this file since the mock directly links the client and server
+ // apps.
+ InProcServerWrapper::InProcServerWrapper(
+ std::weak_ptr<std::recursive_mutex> csdkLock, PlatformConfig cfg)
+ : m_threadRun(false), m_csdkLock(csdkLock),
+ m_cfg { cfg }
+ {
+ }
+
+ InProcServerWrapper::~InProcServerWrapper()
+ {
+ }
+
+ OCStackResult InProcServerWrapper::start()
+ {
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::stop()
+ {
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::registerResource(
+ OCResourceHandle& resourceHandle,
+ std::string& resourceURI,
+ const std::string& resourceTypeName,
+ const std::string& resourceInterface,
+ EntityHandler& eHandler,
+ uint8_t resourceProperties)
+ {
+ OC_UNUSED(resourceHandle);
+ OC_UNUSED(resourceURI);
+ OC_UNUSED(resourceTypeName);
+ OC_UNUSED(resourceInterface);
+ OC_UNUSED(eHandler);
+ OC_UNUSED(resourceProperties);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::registerDeviceInfo(const OCDeviceInfo deviceInfo)
+ {
+ OC_UNUSED(deviceInfo);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::registerPlatformInfo(const OCPlatformInfo platformInfo)
+ {
+ OC_UNUSED(platformInfo);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::unregisterResource(const OCResourceHandle& resourceHandle)
+ {
+ OC_UNUSED(resourceHandle);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::bindTypeToResource(const OCResourceHandle& resourceHandle,
+ const std::string& resourceTypeName)
+ {
+ OC_UNUSED(resourceHandle);
+ OC_UNUSED(resourceTypeName);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::bindInterfaceToResource(
+ const OCResourceHandle& resourceHandle,
+ const std::string& resourceInterfaceName)
+ {
+ OC_UNUSED(resourceHandle);
+ OC_UNUSED(resourceInterfaceName);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::startPresence(const unsigned int seconds)
+ {
+ OC_UNUSED(seconds);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::stopPresence()
+ {
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::setDefaultDeviceEntityHandler
+ (EntityHandler entityHandler)
+ {
+ OC_UNUSED(entityHandler);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::sendResponse(
+ const std::shared_ptr<OCResourceResponse> pResponse)
+ {
+ OC_UNUSED(pResponse);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::setPropertyValue(OCPayloadType type,
+ const std::string& propName,
+ const std::string& propValue)
+ {
+ OC_UNUSED(type);
+ OC_UNUSED(propName);
+ OC_UNUSED(propValue);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::getPropertyValue(OCPayloadType type,
+ const std::string& propName, std::string& propValue)
+ {
+ OC_UNUSED(type);
+ OC_UNUSED(propName);
+ OC_UNUSED(propValue);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::getPropertyList(OCPayloadType type,
+ const std::string& propName, std::vector<std::string>& propValue)
+ {
+ OC_UNUSED(type);
+ OC_UNUSED(propName);
+ OC_UNUSED(propValue);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::registerResourceWithTps(
+ OCResourceHandle& resourceHandle,
+ std::string& resourceURI,
+ const std::string& resourceTypeName,
+ const std::string& resourceInterface,
+ EntityHandler& eHandler,
+ uint8_t resourceProperties,
+ OCTpsSchemeFlags resourceTpsTypes)
+ {
+ OC_UNUSED(resourceHandle);
+ OC_UNUSED(resourceURI);
+ OC_UNUSED(resourceTypeName);
+ OC_UNUSED(resourceInterface);
+ OC_UNUSED(eHandler);
+ OC_UNUSED(resourceProperties);
+ OC_UNUSED(resourceTpsTypes);
+
+ return OC_STACK_OK;
+ }
+
+ OCStackResult InProcServerWrapper::getSupportedTransportsInfo(OCTpsSchemeFlags& supportedTps)
+ {
+ OC_UNUSED(supportedTps);
+
+ return OC_STACK_OK;
+ }
+}
--- /dev/null
+/* *****************************************************************\r
+ *\r
+ * Copyright 2017 Microsoft\r
+ *\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ ******************************************************************/\r
+\r
+#include "OCPlatform_impl.h"\r
+#include <OCPlatform.h>\r
+#include <OCResource.h>\r
+#include <string>\r
+#include "ipcatestdata.h"\r
+\r
+// This file implements subset of functions of the following classes that are required by IPCA unit\r
+// tests.\r
+// OCResource\r
+// OCPlatform\r
+// OCResourceRequest (data structure sent to server app's entity handler)\r
+// OCResourceReponse (data structure sent to client app's callbacks)\r
+\r
+using namespace OC;\r
+\r
+typedef struct\r
+{\r
+ std::string deviceName;\r
+ std::vector<std::string> types;\r
+ std::string specVersion;\r
+ std::string platformIndependentId;\r
+ std::vector<std::string> dataModelVersions;\r
+} Mock_OCDeviceInfo;\r
+\r
+typedef struct\r
+{\r
+ std::string platformID;\r
+ std::string manufacturerName;\r
+ std::string manufacturerUrl;\r
+ std::string modelNumber;\r
+ std::string dateOfManufacture;\r
+ std::string platformVersion;\r
+ std::string operatingSystemVersion;\r
+ std::string hardwareVersion;\r
+ std::string firmwareVersion;\r
+ std::string supportUrl;\r
+ std::string systemTime;\r
+} Mock_OCPlatformInfo;\r
+\r
+class MockOCResource\r
+{\r
+ public:\r
+ typedef std::shared_ptr<MockOCResource> Ptr;\r
+ MockOCResource(const std::string& uri,\r
+ const std::string& resourceTypeName,\r
+ const std::string& resourceInterface,\r
+ EntityHandler entityHandler,\r
+ uint8_t resourceProperty,\r
+ std::shared_ptr<OCResource> ocResource) :\r
+ m_uri(uri),\r
+ m_resourceType(resourceTypeName),\r
+ m_resourceInterface(resourceInterface),\r
+ m_entityHandler(entityHandler),\r
+ m_resourceProperty(resourceProperty),\r
+ m_ocResource(ocResource)\r
+ {\r
+ };\r
+ std::string m_uri;\r
+ std::string m_resourceType;\r
+ std::string m_resourceInterface;\r
+ EntityHandler m_entityHandler;\r
+ uint8_t m_resourceProperty;\r
+ OCResource::Ptr m_ocResource;\r
+};\r
+\r
+size_t g_requestId = 0; // incremented per request.\r
+OCObservationId g_observationId = 0; // incremented per observe request.\r
+struct PendingRequest\r
+{\r
+ typedef std::shared_ptr<PendingRequest> Ptr;\r
+ size_t requestNumber;\r
+ MockOCResource::Ptr mockOCResource;\r
+ OCMethod method;\r
+ PutCallback postCallback;\r
+ GetCallback getCallback;\r
+ ObserveCallback observeCallback;\r
+ OCObservationId observationId;\r
+ DeleteCallback deleteCallback;\r
+};\r
+\r
+PlatformConfig g_platformConfig;\r
+Mock_OCDeviceInfo g_deviceInfo; // C++ version of OCDeviceInfo.\r
+Mock_OCPlatformInfo g_platformInfo; // C++ version of OCPlatformInfo.\r
+\r
+std::recursive_mutex g_globalMutex; // the only lock.\r
+std::map<std::string, MockOCResource::Ptr> g_resourceList; // Key is resource uri.\r
+std::map<size_t, PendingRequest::Ptr> g_requestList; // Key is PendingRequest.requestNumber.\r
+\r
+std::string g_mockHostAddress = "fe80::1%eth0";\r
+uint16_t g_mockHostPort = 10000;\r
+std::string g_mockCompleteAddress = "coap://[fe80::1%25eth0]:10000";\r
+void SetMockOCDevAddr(OCDevAddr& addr)\r
+{\r
+ addr = {OC_DEFAULT_ADAPTER, OC_IP_USE_V6};\r
+ addr.port = g_mockHostPort;\r
+ strcpy(addr.addr, g_mockHostAddress.c_str());\r
+}\r
+\r
+// Forward decl.\r
+OCEntityHandlerResult MockEntityHandler(OCEntityHandlerFlag flag,\r
+ OCMethod method,\r
+ const OCRepresentation& rep,\r
+ const QueryParamsMap& queryParametersMap,\r
+ PostCallback postCallback,\r
+ GetCallback getCallback,\r
+ ObserveCallback observeCallback,\r
+ DeleteCallback deleteCallback,\r
+ const std::string& uri);\r
+\r
+// Called to configure platform config.\r
+void OCPlatform::Configure(const PlatformConfig& config)\r
+{\r
+ g_platformConfig = config;\r
+}\r
+\r
+OCStackResult OCPlatform::setPropertyValue(OCPayloadType type, const std::string& tag,\r
+ const std::string& value)\r
+{\r
+ if ((type == PAYLOAD_TYPE_DEVICE) && (tag.compare(OC_RSRVD_PROTOCOL_INDEPENDENT_ID) == 0))\r
+ {\r
+ g_deviceInfo.platformIndependentId = value;\r
+ }\r
+\r
+ return OC_STACK_OK;\r
+}\r
+\r
+OCStackResult OCPlatform::setPropertyValue(OCPayloadType type, const std::string& tag,\r
+ const std::vector<std::string>& value)\r
+{\r
+ if ((type == PAYLOAD_TYPE_DEVICE) && (tag.compare(OC_RSRVD_DATA_MODEL_VERSION) == 0))\r
+ {\r
+ g_deviceInfo.dataModelVersions = value;\r
+ }\r
+\r
+ return OC_STACK_OK;\r
+}\r
+\r
+OCStackResult OCPlatform::getPropertyValue(OCPayloadType type, const std::string& tag,\r
+ std::string& value)\r
+{\r
+ if ((type == PAYLOAD_TYPE_DEVICE) && (tag.compare(OC_RSRVD_PROTOCOL_INDEPENDENT_ID) == 0))\r
+ {\r
+ value = g_deviceInfo.platformIndependentId;\r
+ }\r
+\r
+ return OC_STACK_OK;\r
+}\r
+\r
+OCStackResult OCPlatform::getPropertyValue(OCPayloadType type, const std::string& tag,\r
+ std::vector<std::string>& value)\r
+{\r
+ if ((type == PAYLOAD_TYPE_DEVICE) && (tag.compare(OC_RSRVD_DATA_MODEL_VERSION) == 0))\r
+ {\r
+ value = g_deviceInfo.dataModelVersions;\r
+ }\r
+\r
+ return OC_STACK_OK;\r
+}\r
+\r
+// Called by server app to register device info.\r
+OCStackResult OCPlatform::registerDeviceInfo(const OCDeviceInfo deviceInfo)\r
+{\r
+ g_deviceInfo.deviceName = deviceInfo.deviceName;\r
+ g_deviceInfo.specVersion = deviceInfo.specVersion;\r
+\r
+ if (deviceInfo.types)\r
+ {\r
+ for (OCStringLL* temp = deviceInfo.types; temp; temp = temp->next)\r
+ {\r
+ if (temp->value)\r
+ {\r
+ g_deviceInfo.types.push_back(temp->value);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (deviceInfo.dataModelVersions)\r
+ {\r
+ for (OCStringLL* temp = deviceInfo.dataModelVersions; temp; temp = temp->next)\r
+ {\r
+ if (temp->value)\r
+ {\r
+ g_deviceInfo.dataModelVersions.push_back(temp->value);\r
+ }\r
+ }\r
+ }\r
+\r
+ return OC_STACK_OK;\r
+}\r
+\r
+// Called by server app to register platform info.\r
+OCStackResult OCPlatform::registerPlatformInfo(const OCPlatformInfo platformInfo)\r
+{\r
+ g_platformInfo.platformID = platformInfo.platformID;\r
+ g_platformInfo.manufacturerName = platformInfo.manufacturerName;\r
+ g_platformInfo.manufacturerUrl = platformInfo.manufacturerUrl;\r
+ g_platformInfo.modelNumber = platformInfo.modelNumber;\r
+ g_platformInfo.dateOfManufacture = platformInfo.dateOfManufacture;\r
+ g_platformInfo.platformVersion = platformInfo.platformVersion;\r
+ g_platformInfo.operatingSystemVersion = platformInfo.operatingSystemVersion;\r
+ g_platformInfo.hardwareVersion = platformInfo.hardwareVersion;\r
+ g_platformInfo.firmwareVersion = platformInfo.firmwareVersion;\r
+ g_platformInfo.supportUrl = platformInfo.supportUrl;\r
+ g_platformInfo.systemTime = platformInfo.systemTime ? platformInfo.systemTime : "";\r
+ return OC_STACK_OK;\r
+}\r
+\r
+// Called by server app to register resource. This mock creates an OCResource that can be used by\r
+// client app.\r
+// MockOCResource keeps track of OC::OCResource and callbacks to the server app.\r
+OCStackResult OCPlatform::registerResource(\r
+ OCResourceHandle& resourceHandle,\r
+ std::string& resourceURI,\r
+ const std::string& resourceTypeName,\r
+ const std::string& resourceInterface,\r
+ EntityHandler entityHandler,\r
+ uint8_t resourceProperty)\r
+{\r
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);\r
+\r
+ if (g_resourceList.find(resourceURI) != g_resourceList.end())\r
+ {\r
+ // duplicate resource.\r
+ return OC_STACK_ERROR;\r
+ }\r
+\r
+ OCConnectivityType connectivityType = CT_DEFAULT;\r
+ std::vector<std::string> types = { resourceTypeName };\r
+ std::vector<std::string> ifaces = { resourceInterface };\r
+ OCResource::Ptr ocResource = OCPlatform::constructResourceObject(\r
+ "", // host address is mocked in SetHost().\r
+ resourceURI,\r
+ connectivityType,\r
+ (resourceProperty & OC_OBSERVABLE) ? true : false,\r
+ types,\r
+ ifaces);\r
+\r
+ std::shared_ptr<MockOCResource> newMockResource = std::shared_ptr<MockOCResource>(\r
+ new MockOCResource(\r
+ resourceURI,\r
+ resourceTypeName,\r
+ resourceInterface,\r
+ entityHandler,\r
+ resourceProperty,\r
+ ocResource));\r
+ if (newMockResource == nullptr)\r
+ {\r
+ return OC_STACK_ERROR;\r
+ }\r
+\r
+ g_resourceList[resourceURI] = newMockResource;\r
+ resourceHandle = reinterpret_cast<OCResourceHandle>(newMockResource.get());\r
+ return OC_STACK_OK;\r
+}\r
+\r
+// Called by server app to shut down a resource.\r
+// This also deletes the MockOCResource.\r
+OCStackResult OCPlatform::unregisterResource(const OCResourceHandle& resourceHandle)\r
+{\r
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);\r
+\r
+ MockOCResource* rawMockOCResource = reinterpret_cast<MockOCResource*>(resourceHandle);\r
+\r
+ for (auto mockResource : g_resourceList)\r
+ {\r
+ if (mockResource.second.get() == rawMockOCResource)\r
+ {\r
+ g_resourceList.erase(mockResource.second->m_uri);\r
+ break;\r
+ }\r
+ }\r
+\r
+ return OC_STACK_OK;\r
+}\r
+\r
+// Called by client app to discover a resource.\r
+OCStackResult OCPlatform::findResource(const std::string& host,\r
+ const std::string& resourceName,\r
+ OCConnectivityType connectivityType,\r
+ FindCallback resourceHandler)\r
+{\r
+ OC_UNUSED(connectivityType);\r
+ OC_UNUSED(resourceName);\r
+ OC_UNUSED(host);\r
+\r
+ // Ideally: return only requested resource types embedded in resourceName.\r
+ // This mock fires back everything that server app registered.\r
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);\r
+ for (auto mockResource : g_resourceList)\r
+ {\r
+ std::thread findResourceCallbackThread(resourceHandler, mockResource.second->m_ocResource);\r
+ findResourceCallbackThread.detach();\r
+ }\r
+\r
+ return OC_STACK_OK;\r
+}\r
+\r
+// Called by client app to get device info of device.\r
+OCStackResult OCPlatform::getDeviceInfo(const std::string& host,\r
+ const std::string& deviceURI,\r
+ OCConnectivityType connectivityType,\r
+ FindDeviceCallback deviceInfoHandler)\r
+{\r
+ OC_UNUSED(host);\r
+ OC_UNUSED(connectivityType);\r
+ OC_UNUSED(deviceURI);\r
+\r
+ OCDevAddr addr;\r
+ SetMockOCDevAddr(addr);\r
+\r
+ OCRepresentation ocRep;\r
+ ocRep.setDevAddr(addr);\r
+ ocRep.setValue(OC_RSRVD_DEVICE_NAME, g_deviceInfo.deviceName);\r
+ ocRep.setValue(OC_RSRVD_SPEC_VERSION, g_deviceInfo.specVersion);\r
+ ocRep.setValue(OC_RSRVD_DATA_MODEL_VERSION, g_deviceInfo.dataModelVersions);\r
+\r
+ std::thread getDeviceInfoCallbackThread(deviceInfoHandler, ocRep);\r
+ getDeviceInfoCallbackThread.detach();\r
+ return OC_STACK_OK;\r
+}\r
+\r
+// Called by client app to get platform info of device.\r
+OCStackResult OCPlatform::getPlatformInfo(const std::string& host,\r
+ const std::string& platformURI,\r
+ OCConnectivityType connectivityType,\r
+ FindPlatformCallback platformInfoHandler)\r
+{\r
+ OC_UNUSED(host);\r
+ OC_UNUSED(platformURI);\r
+ OC_UNUSED(connectivityType);\r
+\r
+ OCDevAddr addr;\r
+ SetMockOCDevAddr(addr);\r
+\r
+ OCRepresentation ocRep;\r
+ ocRep.setDevAddr(addr);\r
+ ocRep.setValue(OC_RSRVD_PLATFORM_ID, g_platformInfo.platformID);\r
+ ocRep.setValue(OC_RSRVD_MFG_NAME, g_platformInfo.manufacturerName);\r
+ ocRep.setValue(OC_RSRVD_MFG_URL, g_platformInfo.manufacturerUrl);\r
+ ocRep.setValue(OC_RSRVD_MODEL_NUM, g_platformInfo.modelNumber);\r
+ ocRep.setValue(OC_RSRVD_MFG_DATE, g_platformInfo.dateOfManufacture);\r
+ ocRep.setValue(OC_RSRVD_PLATFORM_VERSION, g_platformInfo.platformVersion);\r
+ ocRep.setValue(OC_RSRVD_OS_VERSION, g_platformInfo.operatingSystemVersion);\r
+ ocRep.setValue(OC_RSRVD_HARDWARE_VERSION, g_platformInfo.hardwareVersion);\r
+ ocRep.setValue(OC_RSRVD_FIRMWARE_VERSION, g_platformInfo.firmwareVersion);\r
+ ocRep.setValue(OC_RSRVD_SUPPORT_URL, g_platformInfo.supportUrl);\r
+ ocRep.setValue(OC_RSRVD_SYSTEM_TIME, g_platformInfo.systemTime);\r
+\r
+ std::thread getPlatformInfoCallbackThread(platformInfoHandler, ocRep);\r
+ getPlatformInfoCallbackThread.detach();\r
+ return OC_STACK_OK;\r
+\r
+}\r
+\r
+// Called by server app to send notification to a list of observers that have called ObserveResource().\r
+OCStackResult OCPlatform::notifyListOfObservers(OCResourceHandle resourceHandle,\r
+ ObservationIds& observationIds,\r
+ const std::shared_ptr<OCResourceResponse> pResponse)\r
+{\r
+ OC_UNUSED(resourceHandle);\r
+\r
+ OCRepresentation ocRep = pResponse->getResourceRepresentation();\r
+ OCEntityHandlerResult result = pResponse->getResponseResult();\r
+ HeaderOptions serverHeaderOptions; /* not mocked */\r
+ ObservationIds localCopy = observationIds;\r
+\r
+ {\r
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);\r
+ for (auto targetObserveId : localCopy)\r
+ {\r
+ for (auto request : g_requestList)\r
+ {\r
+ PendingRequest::Ptr pendingRequest = request.second;\r
+ if ((pendingRequest->method == OC_REST_OBSERVE) ||\r
+ (pendingRequest->method == OC_REST_OBSERVE_ALL))\r
+ {\r
+ if (pendingRequest->observationId == targetObserveId)\r
+ {\r
+ std::thread observeCallbackThread(pendingRequest->observeCallback,\r
+ serverHeaderOptions,\r
+ ocRep,\r
+ (result == OC_EH_OK) ? OC_STACK_OK : OC_STACK_ERROR,\r
+ 1 /* sequence number, not mocked */);\r
+ observeCallbackThread.detach();\r
+ }\r
+\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return OC_STACK_OK;\r
+}\r
+\r
+// Every response from server app to client app is performed by this function.\r
+OCStackResult OCPlatform::sendResponse(const std::shared_ptr<OCResourceResponse> pResponse)\r
+{\r
+ size_t requestNumber = reinterpret_cast<size_t>(pResponse->getRequestHandle());\r
+ OCRepresentation ocRep = pResponse->getResourceRepresentation();\r
+ OCEntityHandlerResult result = pResponse->getResponseResult();\r
+ HeaderOptions serverHeaderOptions;\r
+\r
+ PendingRequest::Ptr pendingRequest;\r
+ {\r
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);\r
+ if (g_requestList.find(requestNumber) == g_requestList.end())\r
+ {\r
+ return OC_STACK_ERROR;\r
+ }\r
+\r
+ pendingRequest = g_requestList[requestNumber];\r
+ }\r
+\r
+ switch (pendingRequest->method)\r
+ {\r
+ case OC_REST_POST:\r
+ {\r
+ std::thread postCallbackThread(pendingRequest->postCallback,\r
+ serverHeaderOptions,\r
+ ocRep,\r
+ (result == OC_EH_OK) ? OC_STACK_OK : OC_STACK_ERROR);\r
+ postCallbackThread.detach();\r
+ break;\r
+ }\r
+\r
+ case OC_REST_GET:\r
+ {\r
+ std::thread getCallbackThread(pendingRequest->getCallback,\r
+ serverHeaderOptions,\r
+ ocRep,\r
+ (result == OC_EH_OK) ? OC_STACK_OK : OC_STACK_ERROR);\r
+ getCallbackThread.detach();\r
+ break;\r
+ }\r
+\r
+ case OC_REST_DELETE:\r
+ {\r
+ std::thread deleteCallbackThread(pendingRequest->deleteCallback,\r
+ serverHeaderOptions,\r
+ (result == OC_EH_OK) ? OC_STACK_OK : OC_STACK_ERROR);\r
+ deleteCallbackThread.detach();\r
+ break;\r
+ }\r
+ }\r
+\r
+ return OC_STACK_OK;\r
+}\r
+\r
+// Constructor of OCResource.\r
+OCResource::OCResource(std::weak_ptr<IClientWrapper> clientWrapper,\r
+ const std::string& host,\r
+ const std::string& uri,\r
+ const std::string& serverId,\r
+ OCConnectivityType connectivityType,\r
+ uint8_t property,\r
+ const std::vector<std::string>& resourceTypes,\r
+ const std::vector<std::string>& interfaces) :\r
+ m_clientWrapper(clientWrapper),\r
+ m_uri(uri),\r
+ m_resourceId(serverId, m_uri),\r
+ m_isCollection(false),\r
+ m_property(property),\r
+ m_resourceTypes(resourceTypes),\r
+ m_interfaces(interfaces),\r
+ m_observeHandle(nullptr)\r
+{\r
+ m_devAddr.adapter = static_cast<OCTransportAdapter>(connectivityType >> CT_ADAPTER_SHIFT);\r
+ m_devAddr.flags = static_cast<OCTransportFlags>(connectivityType & CT_MASK_FLAGS);\r
+ this->setHost(host);\r
+}\r
+\r
+OCResource::~OCResource()\r
+{\r
+}\r
+\r
+void defaultCallback(const HeaderOptions&, const OCRepresentation&, const int)\r
+{\r
+}\r
+\r
+void defaultDeleteCallback(const HeaderOptions&, const int)\r
+{\r\r
+}\r
+\r
+void defaultObserveCallback(const HeaderOptions&, const OCRepresentation&, const int, const int)\r
+{\r
+}\r
+\r
+// Client app's request to Delete a resource.\r
+OCStackResult OCResource::deleteResource(DeleteCallback deleteHandler)\r
+{\r
+ OCRepresentation rep;\r
+ QueryParamsMap queryParametersMap;\r
+ OCEntityHandlerResult result = MockEntityHandler(\r
+ OC_REQUEST_FLAG,\r
+ OC_REST_DELETE,\r
+ rep,\r
+ queryParametersMap,\r
+ &defaultCallback,\r
+ &defaultCallback,\r
+ &defaultObserveCallback,\r
+ deleteHandler,\r
+ uri());\r
+\r
+ return (result == OC_EH_OK) ? OC_STACK_OK : OC_STACK_ERROR;\r
+}\r
+\r
+// Client app's request to Get a resource.\r
+OCStackResult OCResource::get(const QueryParamsMap& queryParametersMap,\r
+ GetCallback attributeHandler)\r
+{\r
+ OC_UNUSED(queryParametersMap);\r
+\r
+ OCRepresentation rep;\r
+ OCEntityHandlerResult result = MockEntityHandler(\r
+ OC_REQUEST_FLAG,\r
+ OC_REST_GET,\r
+ rep,\r
+ queryParametersMap,\r
+ &defaultCallback,\r
+ attributeHandler,\r
+ &defaultObserveCallback,\r
+ &defaultDeleteCallback,\r
+ uri());\r
+\r
+ return (result == OC_EH_OK) ? OC_STACK_OK : OC_STACK_ERROR;\r
+}\r
+\r
+// Client app's request to Post to a resource.\r
+OCStackResult OCResource::post(const OCRepresentation& rep,\r
+ const QueryParamsMap& queryParametersMap,\r
+ PostCallback attributeHandler)\r
+{\r
+ OC_UNUSED(queryParametersMap);\r
+\r
+ OCEntityHandlerResult result = MockEntityHandler(\r
+ OC_REQUEST_FLAG,\r
+ OC_REST_POST,\r
+ rep,\r
+ queryParametersMap,\r
+ attributeHandler,\r
+ &defaultCallback,\r
+ &defaultObserveCallback,\r
+ &defaultDeleteCallback,\r
+ uri());\r
+\r
+ return (result == OC_EH_OK) ? OC_STACK_OK : OC_STACK_ERROR;\r
+}\r
+\r
+// Client app's request to observe a resource.\r
+OCStackResult OCResource::observe(ObserveType observeType,\r
+ const QueryParamsMap& queryParametersMap,\r
+ ObserveCallback observeHandler)\r
+{\r
+ OC_UNUSED(queryParametersMap);\r
+\r
+ OCRepresentation rep;\r
+ OCEntityHandlerResult result = MockEntityHandler(\r
+ OC_OBSERVE_FLAG,\r
+ (observeType == ObserveType::Observe) ?\r
+ OC_REST_OBSERVE : OC_REST_OBSERVE_ALL,\r
+ rep,\r
+ queryParametersMap,\r
+ &defaultCallback,\r
+ &defaultCallback,\r
+ observeHandler,\r
+ &defaultDeleteCallback,\r
+ uri());\r
+\r
+ return (result == OC_EH_OK) ? OC_STACK_OK : OC_STACK_ERROR;\r
+}\r
+\r
+// Client app's request to cancel observe request.\r
+OCStackResult OCResource::cancelObserve()\r
+{\r
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);\r
+\r
+ for (auto request : g_requestList)\r
+ {\r
+ PendingRequest::Ptr pendingRequest = request.second;\r
+ if ((pendingRequest->method == OC_REST_OBSERVE) ||\r
+ (pendingRequest->method == OC_REST_OBSERVE_ALL))\r
+ {\r
+ if (pendingRequest->mockOCResource->m_uri.compare(uri()) == 0)\r
+ {\r
+ g_requestList.erase(pendingRequest->requestNumber);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return OC_STACK_OK;\r
+}\r
+\r
+// Is resource observable.\r
+bool OCResource::isObservable() const\r
+{\r
+ return (m_property & OC_OBSERVABLE) == OC_OBSERVABLE;\r
+}\r
+\r
+// Host address of the resource.\r
+std::string OCResource::host() const\r
+{\r
+ std::ostringstream ss;\r
+ ss << m_devAddr.addr;\r
+ return ss.str();\r
+}\r
+\r
+// Host address of the resource.\r
+std::string OCResource::setHost(const std::string& host)\r
+{\r
+ OC_UNUSED(host);\r
+\r
+ g_mockCompleteAddress.copy(m_devAddr.addr, sizeof(m_devAddr.addr));\r
+ m_devAddr.addr[g_mockCompleteAddress.length()] = NULL;\r
+ return host;\r
+}\r
+\r
+// Resource types implemented by resource.\r
+std::vector<std::string> OCResource::getResourceTypes() const\r
+{\r
+ return m_resourceTypes;\r
+}\r
+\r
+// Resource interfaces implemented by resource.\r
+std::vector<std::string> OCResource::getResourceInterfaces() const\r
+{\r
+ return m_interfaces;\r
+}\r
+\r
+// URI of the resource.\r
+std::string OCResource::uri() const\r
+{\r
+ return m_uri;\r
+}\r
+\r
+// ID of reosurce.\r
+std::string OCResource::sid() const\r
+{\r
+ return this->uniqueIdentifier().m_representation;\r
+}\r
+\r
+// See: OCResourceRequest.h declaration of this function prototype as friend function.\r
+// Function prototype must match that.\r
+void formResourceRequest(OCEntityHandlerFlag flag,\r
+ OCEntityHandlerRequest* entityHandlerRequest,\r
+ std::shared_ptr<OCResourceRequest> pRequest)\r
+{\r
+ if(pRequest && entityHandlerRequest)\r
+ {\r
+ pRequest->setRequestHandle(entityHandlerRequest->requestHandle);\r
+ pRequest->setResourceHandle(entityHandlerRequest->resource);\r
+ pRequest->setMessageID(entityHandlerRequest->messageID);\r
+ }\r
+\r
+ if(flag & OC_REQUEST_FLAG)\r
+ {\r
+ pRequest->setRequestHandlerFlag(OC::RequestHandlerFlag::RequestFlag);\r
+\r
+ if(entityHandlerRequest)\r
+ {\r
+ if(OC_REST_GET == entityHandlerRequest->method)\r
+ {\r
+ pRequest->setRequestType(OC::PlatformCommands::GET);\r
+ }\r
+ else if(OC_REST_PUT == entityHandlerRequest->method)\r
+ {\r
+ pRequest->setRequestType(OC::PlatformCommands::PUT);\r
+ pRequest->setPayload(entityHandlerRequest->payload);\r
+ }\r
+ else if(OC_REST_POST == entityHandlerRequest->method)\r
+ {\r
+ pRequest->setRequestType(OC::PlatformCommands::POST);\r
+ pRequest->setPayload(entityHandlerRequest->payload);\r
+ }\r
+ else if(OC_REST_DELETE == entityHandlerRequest->method)\r
+ {\r
+ pRequest->setRequestType(OC::PlatformCommands::DELETE);\r
+ }\r
+ }\r
+ }\r
+\r
+ if(flag & OC_OBSERVE_FLAG)\r
+ {\r
+ pRequest->setRequestHandlerFlag(\r
+ OC::RequestHandlerFlag::RequestFlag | OC::RequestHandlerFlag::ObserverFlag);\r
+\r
+ if(entityHandlerRequest)\r
+ {\r
+ OC::ObservationInfo observationInfo;\r
+ observationInfo.action = (OC::ObserveAction) entityHandlerRequest->obsInfo.action;\r
+ observationInfo.obsId = entityHandlerRequest->obsInfo.obsId;\r
+ pRequest->setObservationInfo(observationInfo);\r
+ }\r
+ }\r
+\r
+ QueryParamsMap* queryParams = reinterpret_cast<QueryParamsMap*>(entityHandlerRequest->query);\r
+ pRequest->setQueryParams(*queryParams);\r
+\r
+}\r
+\r
+// Set payload to the OCResourceRequest sent to the server app.\r
+void OCResourceRequest::setPayload(OCPayload* payload)\r
+{\r
+ MessageContainer info;\r
+\r
+ if(payload == nullptr)\r
+ {\r
+ return;\r
+ }\r
+\r
+ if(payload->type != PAYLOAD_TYPE_REPRESENTATION)\r
+ {\r
+ throw std::logic_error("Wrong payload type");\r
+ return;\r
+ }\r
+\r
+ info.setPayload(payload);\r
+\r
+ const std::vector<OCRepresentation>& reps = info.representations();\r
+ if(reps.size() > 0)\r
+ {\r
+ std::vector<OCRepresentation>::const_iterator itr = reps.begin();\r
+ std::vector<OCRepresentation>::const_iterator back = reps.end();\r
+ m_representation = *itr;\r
+ ++itr;\r
+\r
+ for(;itr != back; ++itr)\r
+ {\r
+ m_representation.addChild(*itr);\r
+ }\r
+ }\r
+}\r
+\r
+OCResourceIdentifier::OCResourceIdentifier(const std::string& wireServerIdentifier,\r
+ const std::string& resourceUri)\r
+ :m_representation(wireServerIdentifier), m_resourceUri(resourceUri)\r
+{\r
+}\r
+\r
+OCResourceIdentifier OCResource::uniqueIdentifier() const\r
+{\r
+ return m_resourceId;\r
+}\r
+\r
+\r
+// Every callback to server app is performed by this function.\r
+OCEntityHandlerResult MockEntityHandler(OCEntityHandlerFlag flag,\r
+ OCMethod method,\r
+ const OCRepresentation& rep,\r
+ const QueryParamsMap& queryParametersMap,\r
+ PostCallback postCallback,\r
+ GetCallback getCallback,\r
+ ObserveCallback observeCallback,\r
+ DeleteCallback deleteCallback,\r
+ const std::string& uri)\r
+{\r
+ size_t requestNumber;\r
+ MockOCResource::Ptr mockOCResource = nullptr;\r
+ {\r
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);\r
+ if (g_resourceList.find(uri) == g_resourceList.end())\r
+ {\r
+ return OC_EH_ERROR;\r
+ }\r
+\r
+ mockOCResource = g_resourceList[uri];\r
+ requestNumber = ++g_requestId;\r
+ }\r
+\r
+ auto pendingRequest = std::make_shared<PendingRequest>();\r
+ if (pendingRequest == nullptr)\r
+ {\r
+ return OC_EH_ERROR;\r
+ }\r
+\r
+ pendingRequest->requestNumber = requestNumber;\r
+ pendingRequest->mockOCResource = mockOCResource;\r
+ pendingRequest->method = method;\r
+ pendingRequest->postCallback = postCallback;\r
+ pendingRequest->getCallback = getCallback;\r
+ pendingRequest->observeCallback = observeCallback;\r
+ pendingRequest->deleteCallback = deleteCallback;\r
+ {\r
+ // Store the request for response.\r
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);\r
+ g_requestList[requestNumber] = pendingRequest;\r
+ }\r
+\r
+ auto pRequest = std::make_shared<OC::OCResourceRequest>();\r
+ if (pRequest == nullptr)\r
+ {\r
+ return OC_EH_ERROR;\r
+ }\r
+\r
+ MessageContainer ocInfo;\r
+ ocInfo.addRepresentation(rep);\r
+ for(const OCRepresentation& r : rep.getChildren())\r
+ {\r
+ ocInfo.addRepresentation(r);\r
+ }\r
+\r
+ OCPayload* payload = reinterpret_cast<OCPayload*>(ocInfo.getPayload());\r
+\r
+ OCEntityHandlerRequest entityHandlerRequest = {0};\r
+ entityHandlerRequest.requestHandle = reinterpret_cast<void*>(pendingRequest->requestNumber);\r
+ entityHandlerRequest.resource = nullptr;\r
+ entityHandlerRequest.messageID = 0;\r
+ entityHandlerRequest.method = method;\r
+ entityHandlerRequest.payload = payload;\r
+\r
+ if (flag & OC_OBSERVE_FLAG)\r
+ {\r
+ std::lock_guard<std::recursive_mutex> lock(g_globalMutex);\r
+ entityHandlerRequest.obsInfo.action = OC_OBSERVE_REGISTER;\r
+ entityHandlerRequest.obsInfo.obsId = ++g_observationId;\r
+ pendingRequest->observationId = entityHandlerRequest.obsInfo.obsId;\r
+ }\r
+\r
+ // Pass QueryParamsMap directly to formResourceRequest() which has access\r
+ // to pRequest->setQueryParams().\r
+ QueryParamsMap localCopy = queryParametersMap;\r
+ entityHandlerRequest.query = reinterpret_cast<char*>(&localCopy);\r
+\r
+ formResourceRequest(flag, &entityHandlerRequest, pRequest);\r
+ pRequest->setResourceUri(uri);\r
+\r
+ std::thread callEntityHandlerThread(mockOCResource->m_entityHandler, pRequest);\r
+ callEntityHandlerThread.detach();\r
+ return OC_EH_OK;\r
+}\r
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "OCPlatform_impl.h"
+#include <OCPlatform.h>
+#include <OCResource.h>
+#include <string>
+#include "ipcatestdata.h"
+
+using namespace OC;
+
+ // OCPlatform_impl is friend class of OCResource.
+ // Every OCResource object is created via this function.
+
+ IClientWrapper::Ptr g_mockClientWrapper = std::shared_ptr<IClientWrapper>();
+ extern PlatformConfig g_platformConfig;
+ OCResource::Ptr OCPlatform_impl::constructResourceObject(
+ const std::string& host,
+ const std::string& uri,
+ OCConnectivityType connectivityType,
+ bool isObservable,
+ const std::vector<std::string>& resourceTypes,
+ const std::vector<std::string>& interfaces)
+ {
+ uint8_t resourceProperty = 0;
+
+ if (isObservable)
+ {
+ resourceProperty = (resourceProperty | OC_OBSERVABLE);
+ }
+
+ return std::shared_ptr<OCResource>(new OCResource(
+ g_mockClientWrapper,
+ host,
+ uri,
+ "",
+ connectivityType,
+ resourceProperty,
+ resourceTypes,
+ interfaces));
+ }
+
+ OCPlatform_impl::OCPlatform_impl(const PlatformConfig& config) :
+ m_cfg { config },
+ m_WrapperInstance { make_unique<WrapperFactory>() },
+ m_csdkLock { std::make_shared<std::recursive_mutex>() }
+ {
+ }
+
+ OCPlatform_impl::~OCPlatform_impl(void)
+ {
+ }
+
+ OCPlatform_impl& OCPlatform_impl::Instance()
+ {
+ static OCPlatform_impl platform(g_platformConfig);
+ return platform;
+ }
+
+ OCResource::Ptr OCPlatform::constructResourceObject(const std::string& host,
+ const std::string& uri,
+ OCConnectivityType connectivityType,
+ bool isObservable,
+ const std::vector<std::string>& resourceTypes,
+ const std::vector<std::string>& interfaces)
+ {
+ return OCPlatform_impl::Instance().constructResourceObject(host,
+ uri, connectivityType,
+ isObservable,
+ resourceTypes, interfaces);
+ }
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "TestElevatorClient.h"
+#include "ipcatestdata.h"
+
+#define VERBOSE_INFO 0 // set to 1 for extra output.
+
+using namespace OC;
+using namespace std::placeholders;
+
+ElevatorClient::ElevatorClient()
+{
+ m_elevatorResource = nullptr;
+}
+
+ElevatorClient::~ElevatorClient()
+{
+}
+
+void ElevatorClient::OnObserveCallback(
+ const HeaderOptions headerOptions,
+ const OCRepresentation &rep,
+ const int &eCode,
+ const int &sequenceNumber)
+{
+ OC_UNUSED(sequenceNumber);
+ OC_UNUSED(eCode);
+
+ int newCurrentFloor, newTargetFloor, newDirection;
+
+ if (rep.getValue(ELEVATOR_PROPERTY_CURRENT_FLOOR, newCurrentFloor) == true)
+ {
+ m_notifiedCurrentFloor = newCurrentFloor;
+ }
+
+ if (rep.getValue(ELEVATOR_PROPERTY_TARGET_FLOOR, newTargetFloor) == true)
+ {
+ m_notifiedTargetFloor = newTargetFloor;
+ }
+
+ if (rep.getValue(ELEVATOR_PROPERTY_DIRECTION, newDirection) == true)
+ {
+ m_notifiedDirection = newDirection;
+ }
+}
+
+int ElevatorClient::GetObservedCurrentFloor()
+{
+ return m_notifiedCurrentFloor;
+}
+
+bool ElevatorClient::StartObservation()
+{
+ OCStackResult result = m_elevatorResource->observe(
+ ObserveType::Observe,
+ QueryParamsMap(),
+ std::bind(&ElevatorClient::OnObserveCallback,
+ this, _1, _2, _3, _4));
+ return result == OC_STACK_OK ? true : false;
+}
+
+bool ElevatorClient::StopObservation()
+{
+ OCStackResult result = m_elevatorResource->cancelObserve();
+ return result == OC_STACK_OK ? true : false;
+}
+
+const int DEFAULT_WAITTIME = 2000;
+bool ElevatorClient::WaitForCallback(int waitingTime = DEFAULT_WAITTIME)
+{
+ std::unique_lock<std::mutex> lock { syncMutex };
+
+ if (syncCV.wait_for(lock, std::chrono::milliseconds{ waitingTime }) != std::cv_status::timeout)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void ElevatorClient::SignalCompletion()
+{
+ syncCV.notify_all();
+}
+
+// Callback handler on GET request
+void ElevatorClient::OnGet(const HeaderOptions& headerOptions,
+ const OCRepresentation& rep,
+ const int eCode)
+{
+ OC_UNUSED(headerOptions);
+ OC_UNUSED(eCode);
+
+ if (eCode == OC_STACK_OK)
+ {
+ ReadRepresentation(rep);
+ }
+ else
+ {
+ printf("OnGet:: received error [0x%x]\r\n", eCode);
+ }
+
+ SignalCompletion();
+}
+
+// Callback handler on PUT request
+void ElevatorClient::OnPut(const HeaderOptions& headerOptions,
+ const OCRepresentation& rep,
+ const int eCode)
+{
+ OC_UNUSED(headerOptions);
+
+ if (eCode == OC_STACK_OK || eCode == OC_STACK_RESOURCE_CHANGED)
+ {
+ ReadRepresentation(rep);
+ }
+ else
+ {
+ printf ("PUT request failed, error: 0x%x\r\n", eCode);
+ }
+
+ SignalCompletion();
+}
+
+void ElevatorClient::ReadRepresentation(const OCRepresentation& rep)
+{
+ m_targetFloor = rep.getValue<int>(ELEVATOR_PROPERTY_TARGET_FLOOR);
+ m_currentFloor = rep.getValue<int>(ELEVATOR_PROPERTY_CURRENT_FLOOR);
+ m_direction = rep.getValue<int>(ELEVATOR_PROPERTY_DIRECTION);
+}
+
+std::recursive_mutex theMutex;
+
+void ElevatorClient::PrintResource(std::shared_ptr<OCResource> resource)
+{
+#if (VERBOSE_INFO == 1)
+ std::lock_guard<std::recursive_mutex> lock(theMutex);
+ std::string resourcePath;
+ std::string hostAddress;
+ std::cout << "ElevatorClient::PrintResource:" << std::endl;
+ std::cout << "Resource URI: " << resource->uri() << std::endl;
+ std::cout << "Device URI: " << resource->host() << std::endl;
+ std::cout << "Resource Types: " << std::endl;
+ for(auto &rt : resource->getResourceTypes())
+ std::cout << " " << rt << std::endl;
+ std::cout << "List of resource interfaces: " << std::endl;
+ for(auto &ri : resource->getResourceInterfaces())
+ std::cout << " " << ri << std::endl;
+ std::cout << std::endl;
+#else
+ OC_UNUSED(resource);
+#endif
+}
+
+// Temporarily store the found resource pointers until their device name is found.
+// Key is device URI (e.g., "coap://[fe80::5828:93a8:d53e:4222%7]:62744")
+std::map<std::string, std::shared_ptr<OCResource>> OCFDevices;
+
+void ElevatorClient::OnDeviceInfoCallback(const OCRepresentation& rep)
+{
+ std::lock_guard<std::recursive_mutex> lock(theMutex);
+ std::string deviceName;
+ rep.getValue("n", deviceName);
+
+ if (m_elevatorResource == nullptr && deviceName.compare(m_targetElevatorName) == 0)
+ {
+ m_elevatorResource = OCFDevices[rep.getHost()];
+ OCFDevices.clear(); // free rest of the resources.
+ PrintResource(m_elevatorResource);
+ }
+}
+
+void ElevatorClient::PrintOCRep(const OCRepresentation& rep)
+{
+#if (VERBOSE_INFO == 1)
+ std::lock_guard<std::recursive_mutex> lock(theMutex);
+ std::cout << "++++++++++ PrintOCRep() ++++++++++++" << std::endl;
+ std::cout << "For device URI: " << rep.getHost() << std::endl;
+ std::cout << "Resoure URI: " << rep.getUri() << std::endl;
+ OCRepresentation::const_iterator itr= rep.begin();
+ OCRepresentation::const_iterator endItr = rep.end();
+ for(;itr!=endItr;++itr)
+ {
+ std::string value = (*itr).getValue<std::string>();
+ std::cout << " = ElevatorClient:: Attribute name: " << itr->attrname() << std::endl;
+ std::cout << " ElevatorClient:: Attribute type: " << itr->type() << std::endl;
+ std::cout << " ElevatorClient:: Attribute value: ";
+ switch(itr->type())
+ {
+ case AttributeType::Null:
+ {
+ std::cout << "nullptr" << std::endl;
+ break;
+ }
+
+ case AttributeType::String:
+ {
+ std::cout << ((*itr).getValue<std::string>()).c_str() << std::endl;
+ break;
+ }
+
+ case AttributeType::Integer:
+ {
+ std::cout << (*itr).getValue<int>() << std::endl;
+ break;
+ }
+
+ default:
+ {
+ std::cout << "unrecognized type" << std::endl;
+ break;
+ }
+ }
+
+ }
+ std::cout << "---------- PrintOCRep() ------------" << std::endl << std::endl;
+#else
+ OC_UNUSED(rep);
+#endif
+}
+
+void ElevatorClient::OnPlatformInfoCallback(const OCRepresentation& rep)
+{
+ OC_UNUSED(rep);
+ std::lock_guard<std::recursive_mutex> lock(theMutex);
+ PrintOCRep(rep);
+}
+
+// Callback to found resources
+void ElevatorClient::OnResourceFound(std::shared_ptr<OCResource> resource)
+{
+ std::lock_guard<std::recursive_mutex> lock(theMutex);
+
+ // Target elevator already found.
+ if (m_elevatorResource != nullptr)
+ {
+ return;
+ }
+
+ std::vector<std::string> resourceTypes = resource->getResourceTypes();
+
+ if (resourceTypes.size() != 1)
+ {
+ return;
+ }
+
+ bool matchTargetResourceType = false;
+
+ for (auto const& rt : resourceTypes)
+ {
+ if (rt.compare(ELEVATOR_RESOURCE_TYPE) == 0)
+ {
+ matchTargetResourceType = true;
+ break;
+ }
+ }
+
+ if (matchTargetResourceType == false)
+ {
+ return;
+ }
+
+ if (OCFDevices.find(resource->host()) != OCFDevices.end())
+ {
+ return; // have seen this resource from this host.
+ }
+
+ OCFDevices[resource->host()] = resource;
+
+ // Get the device name for match with m_targetElevatorName.
+ OCPlatform::getDeviceInfo(
+ resource->host(),
+ OC_RSRVD_DEVICE_URI,
+ CT_DEFAULT,
+ std::bind(&ElevatorClient::OnDeviceInfoCallback, this, _1));
+
+
+ OCPlatform::getPlatformInfo(
+ resource->host(),
+ OC_RSRVD_PLATFORM_URI,
+ CT_DEFAULT,
+ std::bind(&ElevatorClient::OnPlatformInfoCallback, this, _1));
+}
+
+// each elevator in unit test has unique device name to differentiate it from the others.
+bool ElevatorClient::FindElevator(std::string elevatorName)
+{
+ std::string defaultElevatorResourceType = ELEVATOR_RESOURCE_TYPE;
+ std::ostringstream deviceUri;
+ m_targetElevatorName = elevatorName;
+
+ deviceUri << OC_RSRVD_WELL_KNOWN_URI << "?rt=" << defaultElevatorResourceType.c_str();
+
+ OCConnectivityType connectivityType = CT_ADAPTER_IP;
+
+ OCStackResult result = OCPlatform::findResource(
+ "",
+ deviceUri.str(),
+ connectivityType,
+ std::bind(&ElevatorClient::OnResourceFound, this, _1));
+
+ if (result == OC_STACK_OK)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool ElevatorClient::IsElevatorFound()
+{
+ return m_elevatorResource != nullptr;
+}
+
+void ElevatorClient::SetTargetFloor(int targetFloor)
+{
+ if(m_elevatorResource)
+ {
+ OCRepresentation rep;
+ rep[ELEVATOR_PROPERTY_TARGET_FLOOR] = targetFloor;
+
+ m_elevatorResource->post(
+ rep,
+ QueryParamsMap(),
+ std::bind(&ElevatorClient::OnPut, this, _1, _2, _3));
+
+ WaitForCallback(); // wait for completion.
+ }
+}
+
+bool ElevatorClient::GetTargetFloor(int* targetFlr)
+{
+ m_elevatorResource->get(QueryParamsMap(), std::bind(&ElevatorClient::OnGet, this, _1, _2, _3));
+ if (WaitForCallback())
+ {
+ *targetFlr = m_targetFloor;
+ return true;
+ }
+ else
+ {
+ *targetFlr = -1;
+ return false;
+ }
+}
+
+bool ElevatorClient::GetCurrentFloor(int* currFloor)
+{
+ m_elevatorResource->get(QueryParamsMap(), std::bind(&ElevatorClient::OnGet, this, _1, _2, _3));
+ if (WaitForCallback())
+ {
+ *currFloor = m_currentFloor;
+ return true;
+ }
+ else
+ {
+ *currFloor = -1;
+ return false;
+ }
+}
+
+bool ElevatorClient::GetDirection(int* dir)
+{
+ m_elevatorResource->get(QueryParamsMap(), std::bind(&ElevatorClient::OnGet, this, _1, _2, _3));
+ if (WaitForCallback())
+ {
+ *dir = m_direction;
+ return true;
+ }
+ else
+ {
+ *dir = -1;
+ return false;
+ }
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+#ifndef _ELEVATOR_CLIENT_H
+#define _ELEVATOR_CLIENT_H
+
+#include <string>
+#include <thread>
+#include <chrono>
+#include <mutex>
+#include <condition_variable>
+
+#include "OCPlatform.h"
+#include "OCApi.h"
+
+using namespace OC;
+
+class ElevatorClient
+{
+public:
+ ElevatorClient();
+ ~ElevatorClient();
+
+ bool FindElevator(std::string targetElevatorName);
+ bool IsElevatorFound();
+
+ void SetTargetFloor(int targetFloor);
+
+ bool GetTargetFloor(int* targetFlr);
+ bool GetCurrentFloor(int* currFloor);
+ bool GetDirection(int* dir);
+
+ bool StartObservation();
+ bool StopObservation();
+ int GetObservedCurrentFloor();
+
+private:
+ // Mutex is used togeter with the conditional_variable for waiting async OnGet and OnPut
+ // callbacks.
+ std::mutex syncMutex;
+ std::condition_variable syncCV;
+ bool WaitForCallback(int waitingTime); // return false if wait timeout.
+ void SignalCompletion();
+
+ std::shared_ptr<OCResource> m_elevatorResource;
+
+ void OnObserveCallback(
+ const HeaderOptions headerOptions,
+ const OCRepresentation &rep,
+ const int &eCode,
+ const int &sequenceNumber);
+
+ void OnResourceFound(std::shared_ptr<OCResource> resource);
+ void OnDeviceInfoCallback(const OCRepresentation& rep);
+ void OnPlatformInfoCallback(const OCRepresentation& rep);
+ void OnGet(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode);
+ void OnPut(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode);
+ void ReadRepresentation(const OCRepresentation& rep);
+ void PrintResource(std::shared_ptr<OCResource> resource);
+ void PrintOCRep(const OCRepresentation& rep);
+
+ // Target server has this device name.
+ std::string m_targetElevatorName;
+
+ // Last known property values from server.
+ int m_targetFloor;
+ int m_currentFloor;
+ int m_direction;
+
+ // Last known notified values from server.
+ int m_notifiedTargetFloor;
+ int m_notifiedCurrentFloor;
+ int m_notifiedDirection;
+
+};
+
+#endif // _ELEVATOR_CLIENT_H
\ No newline at end of file
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "logger.h"
+#include "TestElevatorServer.h"
+#include "ipcatestdata.h"
+
+using namespace OC;
+using namespace std::placeholders;
+
+#define TAG "TestElevatorServer.cpp"
+
+// Initialize Persistent Storage for security database
+FILE* elevatorServer_fopen(const char *path, const char *mode)
+{
+ OC_UNUSED(path);
+ return fopen("IPCAUnitTest.dat", mode);
+}
+
+OCPersistentStorage elevatorServerPS = {elevatorServer_fopen, fread, fwrite, fclose, unlink};
+
+static char* ELEVATOR_MAINTENANCE_PATH = "/oic/mnt";
+
+//
+// Class ElevatorServer implementation.
+//
+ElevatorServer::ElevatorServer() :
+ m_engineThread(),
+ m_elevatorResourceHandle(nullptr),
+ m_elevatorCOResourceHandle(nullptr),
+ m_elevatorMaintenanceHandle(nullptr),
+ m_elevatorCreateRelativeResource(nullptr),
+ m_elevatorDeleteResource(nullptr)
+{
+ m_isRunning = false;
+ m_targetFloor = m_currentFloor = 1;
+ m_direction = ElevatorDirection::Stopped;
+ m_relativePathResourceCreateCount = 0;
+ m_explicitPathResourceCreateCount = 0;
+ m_deleteResourceCount = 0;
+}
+
+ElevatorServer::~ElevatorServer()
+{
+}
+
+// Return all properties in response.
+OCStackResult ElevatorServer::SendResponse(std::shared_ptr<OCResourceRequest> request,
+ OCEntityHandlerResult result)
+{
+ // Values to return.
+ OCRepresentation responseRep;
+ responseRep[ELEVATOR_PROPERTY_CURRENT_FLOOR] = GetCurrentFloor();
+ responseRep[ELEVATOR_PROPERTY_TARGET_FLOOR] = GetTargetFloor();
+ responseRep[ELEVATOR_PROPERTY_DIRECTION] = (int)GetElevatorDirection();
+
+ // Prepare the response.
+ auto pResponse = std::make_shared<OC::OCResourceResponse>();
+ pResponse->setRequestHandle(request->getRequestHandle());
+ pResponse->setResourceHandle(request->getResourceHandle());
+ pResponse->setResourceRepresentation(responseRep);
+ pResponse->setResponseResult(result);
+
+ // Send the response.
+ return OCPlatform::sendResponse(pResponse);
+}
+
+OCStackResult ElevatorServer::SendMaintenanceResponse(std::shared_ptr<OCResourceRequest> request)
+{
+ // Values to return.
+ OCRepresentation responseRep;
+ responseRep["fr"] = false;
+ responseRep["rb"] = false;
+
+ // Prepare the response.
+ auto pResponse = std::make_shared<OC::OCResourceResponse>();
+ pResponse->setRequestHandle(request->getRequestHandle());
+ pResponse->setResourceHandle(request->getResourceHandle());
+ pResponse->setResourceRepresentation(responseRep);
+ pResponse->setResponseResult(OC_EH_OK);
+
+ // Send the response.
+ return OCPlatform::sendResponse(pResponse);
+}
+
+// Callback handler for elevator resource.
+OCEntityHandlerResult ElevatorServer::ElevatorEntityHandler(
+ std::shared_ptr<OCResourceRequest> request)
+{
+ OCEntityHandlerResult ehResult = OC_EH_ERROR;
+
+ if (request->getResourceUri() == ELEVATOR_CO_RESOURCE_PATH)
+ {
+ return OC_EH_FORBIDDEN;
+ }
+
+ if (request)
+ {
+ std::string resourceUri = request->getResourceUri();
+
+ // Get the request type and request flag
+ std::string requestType = request->getRequestType();
+ int requestFlag = request->getRequestHandlerFlag();
+
+ if (requestFlag & RequestHandlerFlag::RequestFlag)
+ {
+ // If the request type is GET
+ if (requestType == OC::PlatformCommands::GET)
+ {
+ if (resourceUri.compare(ELEVATOR_RESOURCE_PATH) == 0)
+ {
+ if (SendResponse(request) == OC_STACK_OK)
+ {
+ ehResult = OC_EH_OK;
+ }
+ }
+ else
+ if (resourceUri.compare(ELEVATOR_MAINTENANCE_PATH) == 0)
+ {
+ if (SendMaintenanceResponse(request) == OC_STACK_OK)
+ {
+ ehResult = OC_EH_OK;
+ }
+ }
+ }
+ else if (requestType == OC::PlatformCommands::POST)
+ {
+ OCRepresentation requestRep = request->getResourceRepresentation();
+
+ if (resourceUri.compare(ELEVATOR_RESOURCE_PATH) == 0)
+ {
+ QueryParamsMap queryMaps = request->getQueryParameters();
+ auto interfaceQuery = queryMaps.find("if");
+ if ((interfaceQuery != queryMaps.end()) &&
+ (interfaceQuery->second.compare(ELEVATOR_RESOURCE_MADE_UP_INTERFACE) == 0))
+ {
+ m_IncorrectInterfaceCount++;
+ if (OC_STACK_OK == SendResponse(request, OC_EH_ERROR))
+ {
+ ehResult = OC_EH_OK;
+ }
+ }
+ else
+ {
+ // Target floor can be set.
+ int targetFloor;
+ if (requestRep.getValue(ELEVATOR_PROPERTY_TARGET_FLOOR, targetFloor))
+ {
+ SetTargetFloor((int)targetFloor);
+ if (OC_STACK_OK == SendResponse(request))
+ {
+ ehResult = OC_EH_OK;
+ }
+ }
+ }
+
+ }
+ else
+ if (resourceUri.compare(ELEVATOR_MAINTENANCE_PATH) == 0)
+ {
+ bool action;
+
+ if (requestRep.getValue("rb", action))
+ {
+ std::cout << "ElevatorServer: Reboot request received." << std::endl;
+ }
+
+ if (requestRep.getValue("fr", action))
+ {
+ std::cout << "ElevatorServer: Factory reset request received." << std::endl;
+ }
+
+ if (SendMaintenanceResponse(request) == OC_STACK_OK)
+ {
+ ehResult = OC_EH_OK;
+ }
+
+ ehResult = OC_EH_OK;
+ }
+ if (resourceUri.compare(ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH) == 0)
+ {
+ m_relativePathResourceCreateCount++;
+
+ // Prepare the response.
+ auto pResponse = std::make_shared<OC::OCResourceResponse>();
+ pResponse->setRequestHandle(request->getRequestHandle());
+ pResponse->setResourceHandle(request->getResourceHandle());
+ pResponse->setNewResourceUri(ELEVATOR_RESOURCE_NEW_RESOURCE_PATH);
+ pResponse->setResponseResult(OC_EH_RESOURCE_CREATED);
+
+ // Send the response.
+ OCPlatform::sendResponse(pResponse);
+ ehResult = OC_EH_OK;
+ }
+
+ }
+ else if (requestType == OC::PlatformCommands::PUT)
+ {
+ m_explicitPathResourceCreateCount++;
+ ehResult = OC_EH_OK;
+ }
+ else if (requestType == OC::PlatformCommands::DELETE)
+ {
+ if (resourceUri.compare(ELEVATOR_RESOURCE_DELETE_PATH) == 0)
+ {
+ m_deleteResourceCount++;
+
+ // Prepare the response.
+ auto pResponse = std::make_shared<OC::OCResourceResponse>();
+ pResponse->setRequestHandle(request->getRequestHandle());
+ pResponse->setResourceHandle(request->getResourceHandle());
+ pResponse->setResponseResult(OC_EH_RESOURCE_DELETED);
+
+ // Send the response.
+ OCPlatform::sendResponse(pResponse);
+ ehResult = OC_EH_OK;
+ }
+ }
+ }
+
+ if (requestFlag & RequestHandlerFlag::ObserverFlag)
+ {
+ ObservationInfo observationInfo = request->getObservationInfo();
+ if (ObserveAction::ObserveRegister == observationInfo.action)
+ {
+ OIC_LOG_V(INFO, TAG, "ElevatorEntityHandler(): new observer ID: %d",
+ observationInfo.obsId);
+ m_observers.push_back(observationInfo.obsId);
+ }
+ else if (ObserveAction::ObserveUnregister == observationInfo.action)
+ {
+ OIC_LOG_V(INFO, TAG, "ElevatorEntityHandler(): removing observer ID: %d",
+ observationInfo.obsId);
+ m_observers.erase(std::remove(
+ m_observers.begin(),
+ m_observers.end(),
+ observationInfo.obsId),
+ m_observers.end());
+ }
+
+ ehResult = OC_EH_OK;
+ }
+ }
+
+ return ehResult;
+}
+
+
+// Copy from std::string to char array. Return true if source is truncated at dest.
+bool CopyStringToBuffer(std::string& source, char* dest, size_t destSize)
+{
+ bool isTruncated = false;
+ size_t copied = source.copy(dest, destSize, 0);
+ if (copied == destSize)
+ {
+ copied -= 1; // make room for null
+ isTruncated = true;
+ }
+
+ // std::string copy does not include null.
+ dest[copied] = 0x00;
+ return isTruncated;
+}
+
+bool ElevatorServer::Start(std::string& elevatorName)
+{
+ // OCPlatform needs only 1 time initialization.
+ static bool OCFInitialized = false;
+ if (false == OCFInitialized)
+ {
+ PlatformConfig Configuration {
+ ServiceType::InProc,
+ ModeType::Both,
+ "0.0.0.0", // By setting to "0.0.0.0", it binds to all available
+ // interfaces
+ 0, // Uses randomly available port
+ QualityOfService::NaQos,
+ &elevatorServerPS
+ };
+
+ OCPlatform::Configure(Configuration);
+ OCFInitialized = true;
+ }
+
+ if (false == m_isRunning)
+ {
+ std::string resourceTypeName(ELEVATOR_RESOURCE_TYPE);
+ std::string resourcePath(ELEVATOR_RESOURCE_PATH);
+
+ m_name = elevatorName;
+
+ // Start with known state.
+ m_targetFloor = m_currentFloor = 1;
+ m_direction = ElevatorDirection::Stopped;
+
+ // Start the engine thread.
+ m_isRunning = true;
+ m_engineThread = std::thread(&ElevatorServer::Engine, this);
+
+ // Device Info.
+ char devName[256];
+ char resTypeName[256];
+ CopyStringToBuffer(m_name, devName, 256);
+ CopyStringToBuffer(resourceTypeName, resTypeName, 256);
+ OCStringLL types { nullptr, resTypeName };
+ OCDeviceInfo deviceInfo = { devName, &types, "0.0.1", nullptr };
+
+ std::vector<std::string> dataModelVersions = {
+ ELEVATOR_DATA_MODEL_VERSION_1,
+ ELEVATOR_DATA_MODEL_VERSION_2,
+ ELEVATOR_DATA_MODEL_VERSION_3};
+
+
+ // Platform Info
+ char* platformId = ELEVATOR_PLATFORM_ID;
+ char manufacturerName[] = "Elevator Manufacturer";
+ char manufacturerUrl[] = "http://www.example.com/elevator";
+ char modelNumber[] = "Elevator Model Number";
+ char dateManufacture[] = "2017-02-28";
+ char platformVersion[] = "Elevator Platform Version";
+ char osVersion[] = "Elevator OS Version";
+ char hardwareVersion[] = "Elevator Hardware Version";
+ char firmwareVersion[] = "Elevator Firmware Version";
+ char supportURL[] = "http://www.example.com/elevator/support";
+
+ OCPlatformInfo platformInfo = {
+ platformId,
+ manufacturerName,
+ manufacturerUrl,
+ modelNumber,
+ dateManufacture,
+ platformVersion,
+ osVersion,
+ hardwareVersion,
+ firmwareVersion,
+ supportURL,
+ nullptr};
+
+ // Register elevator's platformInfo, deviceInfo, and resource.
+ if (OC_STACK_OK != OCPlatform::registerPlatformInfo(platformInfo))
+ {
+ return false;
+ }
+
+ if (OC_STACK_OK != OCPlatform::registerDeviceInfo(deviceInfo))
+ {
+ return false;
+ }
+
+ // additional info for device info.
+ if (OC_STACK_OK != OCPlatform::setPropertyValue(
+ PAYLOAD_TYPE_DEVICE,
+ OC_RSRVD_PROTOCOL_INDEPENDENT_ID,
+ ELEVATOR_PLATFORM_INDEPENDENT_ID))
+ {
+ return false;
+ }
+
+ if (OC_STACK_OK != OCPlatform::setPropertyValue(
+ PAYLOAD_TYPE_DEVICE,
+ OC_RSRVD_DATA_MODEL_VERSION,
+ dataModelVersions))
+ {
+ return false;
+ }
+
+ OCStackResult result = OCPlatform::registerResource(
+ m_elevatorResourceHandle,
+ resourcePath,
+ resourceTypeName,
+ DEFAULT_INTERFACE,
+ std::bind(&ElevatorServer::ElevatorEntityHandler, this, _1),
+ OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
+ if (result != OC_STACK_OK)
+ {
+ return false;
+ }
+
+ std::string maintenanceResourcePath(ELEVATOR_MAINTENANCE_PATH);
+ std::string mainenanceResourceType(OC_RSRVD_RESOURCE_TYPE_MAINTENANCE);
+
+ result = OCPlatform::registerResource(
+ m_elevatorMaintenanceHandle,
+ maintenanceResourcePath,
+ mainenanceResourceType,
+ DEFAULT_INTERFACE,
+ std::bind(&ElevatorServer::ElevatorEntityHandler, this, _1),
+ OC_DISCOVERABLE | OC_OBSERVABLE);
+
+ if (result != OC_STACK_OK)
+ {
+ return false;
+ }
+
+ std::string COresourceTypeName(ELEVATOR_CO_RESOURCE_TYPE);
+ std::string COresourcePath(ELEVATOR_CO_RESOURCE_PATH);
+ result = OCPlatform::registerResource(
+ m_elevatorCOResourceHandle,
+ COresourcePath,
+ COresourceTypeName,
+ ELEVATOR_CO_PRIVATE_INTERFACE,
+ std::bind(&ElevatorServer::ElevatorEntityHandler, this, _1),
+ OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
+
+ if (result != OC_STACK_OK)
+ {
+ return false;
+ }
+
+
+ std::string createRelativeResourcePath(ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH);
+ std::string createRelativeResourceType(ELEVATOR_RESOURCE_CREATE_RELATIVE_PATH_TYPE);
+ result = OCPlatform::registerResource(
+ m_elevatorCreateRelativeResource,
+ createRelativeResourcePath,
+ createRelativeResourceType,
+ DEFAULT_INTERFACE,
+ std::bind(&ElevatorServer::ElevatorEntityHandler, this, _1),
+ OC_DISCOVERABLE | OC_OBSERVABLE);
+
+ if (result != OC_STACK_OK)
+ {
+ return false;
+ }
+
+ std::string deleteResourcePath(ELEVATOR_RESOURCE_DELETE_PATH);
+ std::string deleteResourceType(ELEVATOR_RESOURCE_DELETE_TYPE);
+ result = OCPlatform::registerResource(
+ m_elevatorDeleteResource,
+ deleteResourcePath,
+ deleteResourceType,
+ DEFAULT_INTERFACE,
+ std::bind(&ElevatorServer::ElevatorEntityHandler, this, _1),
+ OC_DISCOVERABLE | OC_OBSERVABLE);
+
+ if (result != OC_STACK_OK)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ // It's already running.
+ return true;
+}
+
+void ElevatorServer::Stop()
+{
+ if (true == m_isRunning)
+ {
+ // Unregister OCF resources.
+ OCPlatform::unregisterResource(m_elevatorResourceHandle);
+ m_elevatorResourceHandle = nullptr;
+
+ OCPlatform::unregisterResource(m_elevatorCOResourceHandle);
+ m_elevatorCOResourceHandle = nullptr;
+
+ OCPlatform::unregisterResource(m_elevatorMaintenanceHandle);
+ m_elevatorMaintenanceHandle = nullptr;
+
+ OCPlatform::unregisterResource(m_elevatorCreateRelativeResource);
+ m_elevatorCreateRelativeResource = nullptr;
+
+ OCPlatform::unregisterResource(m_elevatorDeleteResource);
+ m_elevatorDeleteResource = nullptr;
+
+ // Signal the m_engineThread to stop and wait for it to exit.
+ m_isRunning = false;
+ if (m_engineThread.joinable())
+ {
+ m_engineThread.join();
+ }
+ }
+}
+
+void ElevatorServer::SetTargetFloor(int floor)
+{
+ m_targetFloor = floor;
+}
+
+int ElevatorServer::GetTargetFloor()
+{
+ return m_targetFloor;
+}
+
+int ElevatorServer::GetCurrentFloor()
+{
+ return m_currentFloor;
+}
+
+ElevatorDirection ElevatorServer::GetElevatorDirection()
+{
+ return m_direction;
+}
+
+void ElevatorServer::Engine(ElevatorServer* elevator)
+{
+ while (elevator->m_isRunning == true)
+ {
+ elevator->MoveElevator();
+ std::this_thread::sleep_for(std::chrono::seconds(0));
+ }
+}
+
+void ElevatorServer::NotifyObservers(std::string propertyName, int value)
+{
+ if (m_observers.size() == 0)
+ {
+ return;
+ }
+
+ OIC_LOG_V(INFO, TAG, "NotifyObservers(): notifying observer of property:: %s",
+ propertyName.c_str());
+
+ OCRepresentation rep;
+ rep[propertyName.c_str()] = value;
+
+ // Prepare the response.
+ auto response = std::make_shared<OC::OCResourceResponse>();
+ response->setResourceRepresentation(rep, DEFAULT_INTERFACE);
+
+ OCStackResult result = OCPlatform::notifyListOfObservers(
+ m_elevatorResourceHandle,
+ m_observers,
+ response);
+
+ if (OC_STACK_NO_OBSERVERS == result)
+ {
+ std::cout << "ElevatorServer:: failed notifyListOfObservers: result = ";
+ std::cout << result << std::endl;
+ }
+
+}
+
+void ElevatorServer::MoveElevator()
+{
+ int dwTargetFloor = m_targetFloor;
+ int incrementValue;
+
+ if (m_currentFloor == dwTargetFloor)
+ {
+ return;
+ }
+
+ if (m_currentFloor < dwTargetFloor)
+ {
+ m_direction = ElevatorDirection::Up;
+ incrementValue = 1;
+ }
+ else
+ {
+ m_direction = ElevatorDirection::Down;
+ incrementValue = -1;
+ }
+
+ NotifyObservers(ELEVATOR_PROPERTY_DIRECTION, m_direction);
+
+ while (m_currentFloor != dwTargetFloor)
+ {
+ const int delayBetweenFloorInSecond = 0;
+ m_currentFloor += incrementValue;
+ NotifyObservers(ELEVATOR_PROPERTY_CURRENT_FLOOR, m_currentFloor);
+ std::this_thread::sleep_for(std::chrono::seconds(delayBetweenFloorInSecond));
+ }
+
+ m_direction = ElevatorDirection::Stopped;
+ NotifyObservers(ELEVATOR_PROPERTY_DIRECTION, m_direction);
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * Copyright 2017 Microsoft
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef _ELEVATOR_SERVER_H
+#define _ELEVATOR_SERVER_H
+
+#include <string>
+#include "OCPlatform.h"
+#include "OCApi.h"
+
+using namespace OC;
+
+typedef enum
+{
+ Stopped = 0,
+ Up,
+ Down
+} ElevatorDirection;
+
+class ElevatorServer
+{
+public:
+ ElevatorServer();
+ ~ElevatorServer();
+
+ // Start stop the thread processing the elevator movement. Also register/unregister the
+ // elevator from IoTivity.
+ bool Start(std::string& elevatorName);
+ void Stop();
+
+ // Target floor is set by caller.
+ void SetTargetFloor(int floor);
+ int GetTargetFloor();
+
+ // Current floor is set by elevator.
+ int GetCurrentFloor();
+ ElevatorDirection GetElevatorDirection();
+
+ size_t GetRelativePathResourceCreateCount() { return m_relativePathResourceCreateCount; }
+ size_t GetExplicitPathResourceCreateCount() { return m_explicitPathResourceCreateCount; }
+ size_t GetDeleteResourceCount() { return m_deleteResourceCount; }
+ size_t GetIncorrectInterfaceCount() { return m_IncorrectInterfaceCount; }
+
+private:
+ // List of observers, when client app calls resource->Observer().
+ ObservationIds m_observers;
+
+ // Send notification to observers when property values change.
+ void NotifyObservers(std::string propertyName, int value);
+
+ // Elevator has one resource.
+ OCResourceHandle m_elevatorResourceHandle; // The elevator resource.
+ OCResourceHandle m_elevatorCOResourceHandle; // CO resource.
+ OCResourceHandle m_elevatorMaintenanceHandle;
+ OCResourceHandle m_elevatorCreateRelativeResource; // Resource that handles pretent create.
+ OCResourceHandle m_elevatorDeleteResource; // Resource that handles pretend delete.
+
+ int m_targetFloor; // where elevator needs to be.
+ int m_currentFloor; // where elevator is.
+ ElevatorDirection m_direction; // current direction of the elevator.
+
+ // Thread moving the elevator.
+ std::thread m_engineThread;
+ bool m_isRunning;
+ static void Engine(ElevatorServer* elevator);
+
+ // Move current floor to target floor.
+ void MoveElevator();
+
+ // Helper function to send response for a request.
+ OCStackResult SendResponse(std::shared_ptr<OCResourceRequest> request,
+ OCEntityHandlerResult result = OC_EH_OK);
+ OCStackResult SendMaintenanceResponse(std::shared_ptr<OCResourceRequest> request);
+
+ // OCF callback for this elevator.
+ OCEntityHandlerResult ElevatorEntityHandler(std::shared_ptr<OCResourceRequest> request);
+
+ // Elevator device details.
+ std::string m_name;
+
+ // Elevator platform details.
+ std::string m_platformID;
+ std::string m_modelNumber;
+ std::string m_platformVersion;
+ std::string m_serialNumber;
+ std::string m_specVersion;
+ std::string m_defaultLanguage;
+ std::string m_manufacturerName;
+ std::string m_manufacturerUrl;
+ std::string m_dateOfManufacture;
+ std::string m_operatingSystemVersion;
+ std::string m_hardwareVersion;
+ std::string m_firmwareVersion;
+ std::string m_supportUrl;
+ std::string m_systemTime;
+
+ // Elevator new resource request count.
+ size_t m_relativePathResourceCreateCount;
+ size_t m_explicitPathResourceCreateCount;
+
+ // Elevator delete resource count.
+ size_t m_deleteResourceCount;
+
+ // Number of times entity handler is called with incorrect resource interface.
+ size_t m_IncorrectInterfaceCount;
+};
+
+#endif // _ELEVATOR_SERVER_H
# Build liboc
SConscript('src/SConscript')
+if target_os in ['windows']:
+ # Build IoTivity Procedural Client API
+ SConscript('IPCA/SConscript')
+
if target_os not in ['arduino','darwin','ios','android']:
# Build examples
SConscript('examples/SConscript')
/** To represent resource type with platform.*/
#define OC_RSRVD_RESOURCE_TYPE_PLATFORM "oic.wk.p"
+/** To represent resource type with maintenance.*/
+#define OC_RSRVD_RESOURCE_TYPE_MAINTENANCE "oic.wk.mnt"
+
/** To represent resource type with collection.*/
#define OC_RSRVD_RESOURCE_TYPE_COLLECTION "oic.wk.col"
OCDeleteUuidList
OCDiscoverOwnedDevices
OCDiscoverSingleDevice
+OCDiscoverSingleDeviceInUnicast
OCDiscoverUnownedDevices
OCDoOwnershipTransfer
OCGetACLResource
OCResetDevice
OCResetSVRDB
OCSaveTrustCertChain
+OCSelectOwnershipTransferMethod
OCSetOwnerTransferCallbackData
OCUnlinkDevices
OCSetOxmAllowStatus
if (env.get('SECURED') == '1') and (target_os != 'windows'):
SConscript('provisioning/unittests/SConscript', 'test_env')
+ if target_os in ['windows']:
+ # Build IPCA unit tests
+ SConscript('IPCA/unittests/SConscript', 'test_env')
+
# Build C unit tests
SConscript('csdk/unittests/SConscript', 'test_env')