Sample client for IoTivity Cloud feature
authorJee Hyeok Kim <jihyeok13.kim@samsung.com>
Fri, 4 Mar 2016 02:41:40 +0000 (11:41 +0900)
committerJee Hyeok Kim <jihyeok13.kim@samsung.com>
Mon, 7 Mar 2016 01:20:34 +0000 (01:20 +0000)
Change-Id: I7221324f6423b1b86c5a89aa228645f4f4b79221
Signed-off-by: Jee Hyeok Kim <jihyeok13.kim@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/5229
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
SConstruct
build_common/SConscript
cloud/SConscript [new file with mode: 0644]
cloud/samples/client/README [new file with mode: 0644]
cloud/samples/client/SConscript [new file with mode: 0644]
cloud/samples/client/cloud_connector.c [new file with mode: 0644]
cloud/samples/client/cloud_connector.h [new file with mode: 0644]
cloud/samples/client/sample_device.cpp [new file with mode: 0644]

index 0ebc436..1e8ebfb 100644 (file)
@@ -65,6 +65,9 @@ SConscript(build_dir + 'service/SConscript')
 # Build "plugin interface" sub-project
 SConscript(build_dir + 'plugins/SConscript')
 
+# Build "cloud" sub-project
+SConscript(build_dir + 'cloud/SConscript')
+
 # Append targets information to the help information, to see help info, execute command line:
 #     $ scon [options] -h
 env.PrintTargets()
index 1bc81d8..312900e 100644 (file)
@@ -81,6 +81,7 @@ help_vars.Add(EnumVariable('TARGET_OS', 'Target platform', host, host_target_map
 help_vars.Add(BoolVariable('WITH_RA', 'Build with Remote Access module', False))
 help_vars.Add(BoolVariable('WITH_TCP', 'Build with TCP adapter', False))
 help_vars.Add(EnumVariable('WITH_RD', 'Build including Resource Directory', '0', allowed_values=('0', '1')))
+help_vars.Add(BoolVariable('WITH_CLOUD', 'Build including Cloud client sample', False))
 
 help_vars.Add(BoolVariable('SIMULATOR', 'Build with simulator module', False))
 
diff --git a/cloud/SConscript b/cloud/SConscript
new file mode 100644 (file)
index 0000000..2c60f5c
--- /dev/null
@@ -0,0 +1,32 @@
+#******************************************************************
+#
+# Copyright 2016 Samsung Electronics All Rights Reserved.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# 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.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+##
+# 'cloud' sub-project main build script
+#
+##
+Import('env')
+
+target_os = env.get('TARGET_OS')
+
+if target_os in ['linux']:
+    # Build sample cloud client project
+    if env.get('WITH_CLOUD') == True:
+        SConscript('samples/client/SConscript')
\ No newline at end of file
diff --git a/cloud/samples/client/README b/cloud/samples/client/README
new file mode 100644 (file)
index 0000000..5f6dbbb
--- /dev/null
@@ -0,0 +1,25 @@
+To build cloud client sample, add WITH_TCP, TARGET_TRANSPORT=IP and WITH_CLOUD option to build command
+
+ex) scons WITH_TCP=yes TARGET_TRANSPORT=IP WITH_CLOUD=yes
+
+Cloud client runs using CoAP over TCP transport. So you should add WITH_TCP option.
+
+Once you get sample which file name is 'cloud_device', you need 'Auth Code' to register resources on cloud with account scenario.
+
+Cloud stack has sample github oauth2 adaptor.
+
+So you can instantly test sample using 'Auth Code'.
+
+Paste below URL to your browser
+
+https://github.com/login?return_to=%2Flogin%2Foauth%2Fauthorize%3Fclient_id%3Dea9c18f540323b0213d0%26redirect_uri%3Dhttp%253A%252F%252Fwww.example.com%252Foauth_callback%252F
+
+And you'll see login page provided by github, and after logged in, you'll be redirectd to below site.
+
+http://www.example.com/oauth_callback/?code=bf9beb5db17ea476fa46
+
+You can get 'Auth Code', value of '?code' query string.
+
+The 'Auth Code' is one time token. So you need other token to run other device.
+
+Account server has pre-coded admin credential which session is '00000000'. You can use this credential for immediate tests.
\ No newline at end of file
diff --git a/cloud/samples/client/SConscript b/cloud/samples/client/SConscript
new file mode 100644 (file)
index 0000000..ef6e214
--- /dev/null
@@ -0,0 +1,56 @@
+#******************************************************************
+#
+# Copyright 2016 Samsung Electronics All Rights Reserved.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# 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.
+#
+#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+##
+# IoTivity Cloud project sample client build script
+##
+
+Import('env')
+
+lib_env = env.Clone()
+
+cc_sample_app_env = lib_env.Clone()
+
+######################################################################
+# Build flags
+######################################################################
+cc_sample_app_env.AppendUnique(CPPPATH = [
+               '../../../resource/include/',
+               '../../../resource/csdk/stack/include',
+               '../../../resource/c_common/ocrandom/include',
+               '../../../resource/csdk/logger/include',
+               '../../../resource/oc_logger/include'
+               ])
+
+cc_sample_app_env.AppendUnique(CXXFLAGS = ['-O2', '-g', '-Wall', '-Wextra', '-std=c++0x', '-pthread'])
+cc_sample_app_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')])
+cc_sample_app_env.AppendUnique(RPATH = [env.get('BUILD_DIR')])
+cc_sample_app_env.PrependUnique(LIBS = ['oc', 'octbstack'])
+
+######################################################################
+# Source files and Targets
+######################################################################
+cc_sample_src = [
+        'cloud_connector.c',
+        'sample_device.cpp',
+         ]
+
+cc_client = cc_sample_app_env.Program('cloud_device', cc_sample_src)
+cc_sample_app_env.InstallTarget(cc_client, 'cloud_device')
\ No newline at end of file
diff --git a/cloud/samples/client/cloud_connector.c b/cloud/samples/client/cloud_connector.c
new file mode 100644 (file)
index 0000000..4083a5c
--- /dev/null
@@ -0,0 +1,361 @@
+//******************************************************************
+//
+// Copyright 2016 Samsung Electronics All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// 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 "cloud_connector.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "oic_string.h"
+#include "oic_malloc.h"
+
+#include "ocpayload.h"
+
+#include "rdpayload.h"
+
+#define OC_RD_PUBLISH_TTL 86400
+#define DEFAULT_CONTEXT_VALUE 0x99
+
+#define DEFAULT_COAP_TCP_HOST "coap+tcp://"
+#define DEFAULT_COAP_TCP_PORT 5683
+
+#define DEFAULT_COAP_TCP_SECURE_HOST "coaps+tcp://"
+#define DEFAULT_COAP_TCP_SECURE_PORT 5864
+
+#define DEFAULT_AUTH_REGISTER_LOGIN "/oic/auth/?reqtype=register"
+#define DEFAULT_AUTH_LOGIN "/oic/auth/?reqtype=login"
+#define DEFAULT_AUTH_LOGOUT "/oic/auth/?reqtype=logout"
+
+static OCStackResult createStringLL(uint8_t numElements, OCResourceHandle handle,
+                                    const char *(*getValue)(OCResourceHandle handle, uint8_t i), OCStringLL **stringLL)
+{
+    for (uint8_t i = 0; i < numElements; ++i)
+    {
+        const char *value = getValue(handle, i);
+        if (!*stringLL)
+        {
+            *stringLL = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
+            if (!*stringLL)
+            {
+                return OC_STACK_NO_MEMORY;
+            }
+            (*stringLL)->value = OICStrdup(value);
+            if (!(*stringLL)->value)
+            {
+                return OC_STACK_NO_MEMORY;
+            }
+        }
+        else
+        {
+            OCStringLL *cur = *stringLL;
+            while (cur->next)
+            {
+                cur = cur->next;
+            }
+            cur->next = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
+            if (!cur->next)
+            {
+                return OC_STACK_NO_MEMORY;
+            }
+            cur->next->value = OICStrdup(value);
+            if (!cur->next->value)
+            {
+                return OC_STACK_NO_MEMORY;
+            }
+        }
+    }
+    return OC_STACK_OK;
+}
+
+OCStackResult parseHost(const char *host, int *port, char *addr)
+{
+    //Parse addr, port from host
+    if (strstr(host, DEFAULT_COAP_TCP_HOST) != NULL)
+    {
+        *port = DEFAULT_COAP_TCP_PORT;
+        strncpy(addr, host + strlen(DEFAULT_COAP_TCP_HOST),
+                strlen(host) - strlen(DEFAULT_COAP_TCP_HOST));
+    }
+    else if (strstr(host, DEFAULT_COAP_TCP_SECURE_HOST) != NULL)
+    {
+        *port = DEFAULT_COAP_TCP_SECURE_PORT;
+        strncpy(addr, host + strlen(DEFAULT_COAP_TCP_SECURE_HOST),
+                strlen(host) - strlen(DEFAULT_COAP_TCP_SECURE_HOST));
+    }
+    else
+    {
+        return OC_STACK_INVALID_URI;
+    }
+
+    if (strchr(addr, ':') != NULL)
+    {
+        char *strPort = strchr(addr, ':');
+        *port = atoi(strPort + 1);
+        addr[strlen(addr) - strlen(strPort)] = '\0';
+    }
+
+    return OC_STACK_OK;
+}
+
+OCStackResult OCCloudRegisterLogin(const char *host, const char *auth_provider,
+                                   const char *auth_code, OCClientResponseHandler response)
+{
+    char    targetUri[MAX_URI_LENGTH * 2] = { 0, };
+    snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, DEFAULT_AUTH_REGISTER_LOGIN);
+
+    int     port = 0;
+    char    addr[MAX_ADDR_STR_SIZE] = { 0, };
+
+    if (parseHost(host, &port, (char *)&addr) != OC_STACK_OK)
+    {
+        return OC_STACK_INVALID_URI;
+    }
+
+    OCDevAddr authAddr;
+    memset(&authAddr, 0, sizeof(OCDevAddr));
+    OICStrcpy(authAddr.addr, MAX_ADDR_STR_SIZE, addr);
+    authAddr.port = port;
+
+    OCCallbackData cbData;
+    memset(&cbData, 0, sizeof(OCCallbackData));
+    cbData.cb = response;
+    cbData.cd = NULL;
+    cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
+
+    OCRepPayload *registerPayload = OCRepPayloadCreate();
+    if (!registerPayload)
+    {
+        goto no_memory;
+    }
+
+    OCRepPayloadSetPropString(registerPayload, "authprovider", auth_provider);
+    OCRepPayloadSetPropString(registerPayload, "authcode", auth_code);
+
+    return OCDoResource(NULL, OC_REST_POST, targetUri, &authAddr, (OCPayload *)registerPayload,
+                        CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
+
+no_memory:
+    OCRepPayloadDestroy(registerPayload);
+    return OC_STACK_NO_MEMORY;
+}
+
+OCStackResult OCCloudLoginout(const char *host, const char *query, const char *auth_session,
+                              OCClientResponseHandler response)
+{
+    char    targetUri[MAX_URI_LENGTH * 2] = { 0, };
+    snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, query);
+
+    int     port = 0;
+    char    addr[MAX_ADDR_STR_SIZE] = { 0, };
+
+    if (parseHost(host, &port, (char *)&addr) != OC_STACK_OK)
+    {
+        return OC_STACK_INVALID_URI;
+    }
+
+    OCDevAddr authAddr;
+    memset(&authAddr, 0, sizeof(OCDevAddr));
+    OICStrcpy(authAddr.addr, MAX_ADDR_STR_SIZE, addr);
+    authAddr.port = port;
+
+    OCCallbackData cbData;
+    memset(&cbData, 0, sizeof(OCCallbackData));
+    cbData.cb = response;
+    cbData.cd = NULL;
+    cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
+
+    OCRepPayload *loginoutPayload = OCRepPayloadCreate();
+    if (!loginoutPayload)
+    {
+        goto no_memory;
+    }
+
+    OCRepPayloadSetPropString(loginoutPayload, "session", auth_session);
+
+    return OCDoResource(NULL, OC_REST_POST, targetUri, &authAddr, (OCPayload *)loginoutPayload,
+                        CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
+
+no_memory:
+    OCRepPayloadDestroy(loginoutPayload);
+    return OC_STACK_NO_MEMORY;
+}
+
+
+OCStackResult OCCloudLogin(const char *host, const char *auth_session,
+                           OCClientResponseHandler response)
+{
+    return OCCloudLoginout(host, DEFAULT_AUTH_LOGIN, auth_session, response);
+}
+
+OCStackResult OCCloudLogout(const char *host, const char *auth_session,
+                            OCClientResponseHandler response)
+{
+    return OCCloudLoginout(host, DEFAULT_AUTH_LOGOUT, auth_session, response);
+}
+
+OCStackResult OCCloudPublish(const char *host, const char *query,
+                             OCClientResponseHandler response, int numArg, ...)
+{
+    char    targetUri[MAX_URI_LENGTH * 2] = { 0, };
+    snprintf(targetUri, MAX_URI_LENGTH * 2, "%s%s", host, query);
+
+    int     port = 0;
+    char    addr[MAX_ADDR_STR_SIZE] = { 0, };
+
+    if (parseHost(host, &port, (char *)&addr) != OC_STACK_OK)
+    {
+        return OC_STACK_INVALID_URI;
+    }
+
+    OCDevAddr rdAddr;
+    memset(&rdAddr, 0, sizeof(OCDevAddr));
+    OICStrcpy(rdAddr.addr, MAX_ADDR_STR_SIZE, addr);
+    rdAddr.port = port;
+
+    // Gather all resources locally and do publish
+    OCCallbackData cbData;
+    memset(&cbData, 0, sizeof(OCCallbackData));
+    cbData.cb = response;
+    cbData.cd = NULL;
+    cbData.context = (void *)DEFAULT_CONTEXT_VALUE;
+
+    OCTagsPayload *tagsPayload = NULL;
+    OCLinksPayload *linksPayload = NULL;
+    OCStringLL *rt = NULL;
+    OCStringLL *itf = NULL;
+    OCStringLL *mt = NULL;
+
+    OCRDPayload *rdPayload = OCRDPayloadCreate();
+    if (!rdPayload)
+    {
+        goto no_memory;
+    }
+
+    const unsigned char *id = (unsigned char *)OCGetServerInstanceIDString();
+    tagsPayload = OCCopyTagsResources(NULL, id,
+                                      NULL, OC_DISCOVERABLE, 0, 0, NULL, NULL, OC_RD_PUBLISH_TTL);
+    if (!tagsPayload)
+    {
+        goto no_memory;
+    }
+
+    va_list arguments;
+    va_start(arguments, numArg);
+
+    for (int j = 0; j < numArg; j++)
+    {
+        OCResourceHandle handle = va_arg(arguments, OCResourceHandle);
+        if (handle)
+        {
+            rt = itf = mt = NULL;
+            const char *uri = OCGetResourceUri(handle);
+            uint8_t numElement;
+            if (OC_STACK_OK == OCGetNumberOfResourceTypes(handle, &numElement))
+            {
+                OCStackResult res = createStringLL(numElement, handle, OCGetResourceTypeName, &rt);
+                if (res != OC_STACK_OK || !rt)
+                {
+                    goto no_memory;
+                }
+            }
+
+            if (OC_STACK_OK == OCGetNumberOfResourceTypes(handle, &numElement))
+            {
+                OCStackResult res = createStringLL(numElement, handle, OCGetResourceInterfaceName, &itf);
+                if (res != OC_STACK_OK || !itf)
+                {
+                    goto no_memory;
+                }
+            }
+
+            mt = (OCStringLL *)OICCalloc(1, sizeof(OCStringLL));
+            if (!mt)
+            {
+                goto no_memory;
+            }
+            mt->value = OICStrdup("application/cbor");
+            if (!mt->value)
+            {
+                goto no_memory;
+            }
+
+            if (!linksPayload)
+            {
+                linksPayload = OCCopyLinksResources(uri, rt, itf, NULL, 0, NULL,
+                                                    NULL, j, mt);;
+                if (!linksPayload)
+                {
+                    goto no_memory;
+                }
+            }
+            else
+            {
+                OCLinksPayload *temp = linksPayload;
+                while (temp->next)
+                {
+                    temp = temp->next;
+                }
+                temp->next = OCCopyLinksResources(uri, rt, itf, NULL, 0, NULL,
+                                                  NULL, j, mt);
+                if (!temp->next)
+                {
+                    goto no_memory;
+                }
+            }
+            OCFreeOCStringLL(rt);
+            OCFreeOCStringLL(itf);
+            OCFreeOCStringLL(mt);
+        }
+    }
+    va_end(arguments);
+
+    rdPayload->rdPublish = OCCopyCollectionResource(tagsPayload, linksPayload);
+    if (!rdPayload->rdPublish)
+    {
+        goto no_memory;
+    }
+
+    return OCDoResource(NULL, OC_REST_POST, targetUri, &rdAddr, (OCPayload *)rdPayload,
+                        CT_ADAPTER_TCP, OC_LOW_QOS, &cbData, NULL, 0);
+
+no_memory:
+    va_end(arguments);
+    if (rt)
+    {
+        OCFreeOCStringLL(rt);
+    }
+    if (itf)
+    {
+        OCFreeOCStringLL(itf);
+    }
+    if (mt)
+    {
+        OCFreeOCStringLL(mt);
+    }
+    if (tagsPayload)
+    {
+        OCFreeTagsResource(tagsPayload);
+    }
+    if (linksPayload)
+    {
+        OCFreeLinksResource(linksPayload);
+    }
+    OCRDPayloadDestroy(rdPayload);
+    return OC_STACK_NO_MEMORY;
+}
diff --git a/cloud/samples/client/cloud_connector.h b/cloud/samples/client/cloud_connector.h
new file mode 100644 (file)
index 0000000..2f26a5b
--- /dev/null
@@ -0,0 +1,43 @@
+//******************************************************************
+//
+// Copyright 2016 Samsung Electronics All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// 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 _CLOUD_CONNECTOR_H_
+#define _CLOUD_CONNECTOR_H_
+
+#include "ocstack.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+OCStackResult OCCloudRegisterLogin(const char *host, const char *auth_provider,
+                                   const char *auth_code, OCClientResponseHandler response);
+OCStackResult OCCloudLogin(const char *host, const char *auth_session,
+                           OCClientResponseHandler response);
+OCStackResult OCCloudLogout(const char *host, const char *auth_session,
+                            OCClientResponseHandler response);
+OCStackResult OCCloudPublish(const char *host, const char *query,
+                             OCClientResponseHandler response, int numArg, ...);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif
diff --git a/cloud/samples/client/sample_device.cpp b/cloud/samples/client/sample_device.cpp
new file mode 100644 (file)
index 0000000..4ecc23b
--- /dev/null
@@ -0,0 +1,523 @@
+//******************************************************************
+//
+// Copyright 2016 Samsung Electronics All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+///
+/// This sample provides steps to define an interface for a resource
+/// (properties and methods) and host this resource on the server.
+/// Additionally, it'll have a client example to discover it as well.
+///
+#include <memory>
+#include <iostream>
+#include <stdexcept>
+#include <condition_variable>
+#include <map>
+#include <vector>
+#include "OCPlatform.h"
+#include "OCApi.h"
+
+#include "cloud_connector.h"
+
+#define DEFAULT_CONTEXT_VALUE 0x99
+#define DEFAULT_PUBLISH_QUERY "/oic/rd?rt=oic.wk.rdpub"
+#define DEFAULT_DISCOVER_QUERY "/oic/res?rt=core.foo"
+
+using namespace OC;
+
+typedef std::map<OCResourceIdentifier, std::shared_ptr<OCResource>> DiscoveredResourceMap;
+
+DiscoveredResourceMap discoveredResources;
+
+class ResourceClient
+{
+    private:
+        void putResourceInfo(const HeaderOptions & /*headerOptions*/,
+                             const OCRepresentation rep, const OCRepresentation /*rep2*/, const int eCode)
+        {
+            std::cout << "In PutResourceInfo" << std::endl;
+
+            std::cout << "Clientside Put response to get was: " << std::endl;
+            std::cout << "ErrorCode: " << eCode << std::endl;
+
+            if (eCode == 0)
+            {
+                std::cout << "Successful Put.  Attributes sent were: " << std::endl;
+
+                rep.getValue("isFoo", m_isFoo);
+                rep.getValue("barCount", m_barCount);
+
+                std::cout << "\tisFoo: " << m_isFoo << std::endl;
+                std::cout << "\tbarCount: " << m_barCount << std::endl;
+
+                std::cout << "Actual New values are: " << std::endl;
+
+                rep.getValue("isFoo", m_isFoo);
+                rep.getValue("barCount", m_barCount);
+
+                std::cout << "\tisFoo: " << m_isFoo << std::endl;
+                std::cout << "\tbarCount: " << m_barCount << std::endl;
+
+                m_cv.notify_all();
+            }
+        }
+
+        void getResourceInfo(const HeaderOptions & /*headerOptions*/, const OCRepresentation rep,
+                             const int eCode)
+        {
+            std::cout << "In getResourceInfo" << std::endl;
+
+            std::cout << "Clientside response to get was: " << std::endl;
+            std::cout << "Error Code: " << eCode << std::endl;
+
+            if (eCode == 0)
+            {
+                std::cout << "Successful Get.  Attributes are: " << std::endl;
+
+                rep.getValue("isFoo", m_isFoo);
+                rep.getValue("barCount", m_barCount);
+
+                std::cout << "\tisFoo: " << m_isFoo << std::endl;
+                std::cout << "\tbarCount: " << m_barCount << std::endl;
+
+                std::cout << "Doing a put on q/foo" << std::endl;
+                OCRepresentation rep2(rep);
+                m_isFoo = false;
+                m_barCount = 211;
+
+                rep2.setValue("isFoo", m_isFoo);
+                rep2.setValue("barCount", m_barCount);
+
+                m_resource->put(rep2, QueryParamsMap(),
+                                PutCallback(std::bind(&ResourceClient::putResourceInfo, this, std::placeholders::_1,
+                                                      rep2, std::placeholders::_2, std::placeholders::_3)));
+            }
+        }
+
+        void foundResource(std::shared_ptr<OCResource> resource)
+        {
+            std::cout << "In foundResource" << std::endl;
+            std::lock_guard<std::mutex> lock(m_resourceLock);
+
+            if (discoveredResources.find(resource->uniqueIdentifier()) == discoveredResources.end())
+            {
+                std::cout << "Found resource " << resource->uniqueIdentifier() <<
+                          " for the first time on server with ID: " << resource->sid() << std::endl;
+                discoveredResources[resource->uniqueIdentifier()] = resource;
+            }
+            else
+            {
+                std::cout << "Found resource " << resource->uniqueIdentifier() << " again!" << std::endl;
+            }
+
+            if (resource)
+            {
+                std::cout << "Found Resource: " << std::endl;
+                std::cout << "\tHost: " << resource->host() << std::endl;
+                std::cout << "\tURI:  " << resource->uri() << std::endl;
+
+                // Get the resource types
+                std::cout << "\tList of resource types: " << std::endl;
+                for (auto &resourceTypes : resource->getResourceTypes())
+                {
+                    std::cout << "\t\t" << resourceTypes << std::endl;
+                }
+
+                // Get the resource interfaces
+                std::cout << "\tList of resource interfaces: " << std::endl;
+                for (auto &resourceInterfaces : resource->getResourceInterfaces())
+                {
+                    std::cout << "\t\t" << resourceInterfaces << std::endl;
+                }
+
+                std::cout << "found resource OUT" << std::endl;
+
+                m_resource = resource;
+
+                std::cout << "Doing a get on q/foo." << std::endl;
+
+                m_resource->get(QueryParamsMap(),
+                                GetCallback(std::bind(&ResourceClient::getResourceInfo, this,
+                                                      std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)));
+            }
+        }
+
+    public:
+        ResourceClient()
+        {}
+
+        OCStackResult start(std::string hostUri, std::string requestUri)
+        {
+            FindCallback f(std::bind(&ResourceClient::foundResource, this, std::placeholders::_1));
+
+            return OCPlatform::findResource(hostUri, requestUri, CT_ADAPTER_TCP, f);
+        }
+    private:
+        std::mutex m_mutex;
+        std::mutex m_resourceLock;
+        std::condition_variable m_cv;
+        std::shared_ptr<OCResource> m_resource;
+        bool m_isFoo;
+        int m_barCount;
+};
+
+struct FooResource
+{
+    bool m_isFoo;
+    int m_barCount;
+    OCResourceHandle m_resourceHandle;
+    OCResourceHandle m_resourceHandle2;
+    OCRepresentation m_rep;
+
+    FooResource() : m_isFoo(true), m_barCount(0)
+    {
+        m_rep.setValue("isFoo", m_isFoo);
+        m_rep.setValue("barCount", m_barCount);
+    }
+
+    bool createResource(std::string resourceURI)
+    {
+        std::string resourceTypeName = "core.foo";
+        std::string resourceInterface = DEFAULT_INTERFACE;
+
+        m_rep.setUri(resourceURI);
+
+        uint8_t resourceProperty = OC_DISCOVERABLE;
+
+        EntityHandler eh(std::bind(&FooResource::entityHandler,
+                                   this, std::placeholders::_1));
+        OCStackResult result = OCPlatform::registerResource(m_resourceHandle,
+                               resourceURI, resourceTypeName,
+                               resourceInterface,
+                               eh, resourceProperty);
+        if (OC_STACK_OK != result)
+        {
+            std::cout << "Resource creation unsuccessful" << std::endl;
+            return false;
+        }
+
+        return true;
+    }
+
+    OCResourceHandle getHandle()
+    {
+        return m_resourceHandle;
+    }
+
+    OCResourceHandle getHandle2()
+    {
+        return m_resourceHandle2;
+    }
+
+
+    OCRepresentation get()
+    {
+        m_rep.setValue("isFoo", m_isFoo);
+        m_rep.setValue("barCount", m_barCount);
+
+        return m_rep;
+    }
+
+    void put(OCRepresentation &rep)
+    {
+        rep.getValue("isFoo", m_isFoo);
+        rep.getValue("barCount", m_barCount);
+    }
+
+    OCStackResult sendResponse(std::shared_ptr<OCResourceRequest> pRequest)
+    {
+        auto pResponse = std::make_shared<OC::OCResourceResponse>();
+        pResponse->setRequestHandle(pRequest->getRequestHandle());
+        pResponse->setResourceHandle(pRequest->getResourceHandle());
+        pResponse->setResourceRepresentation(get(), "");
+        pResponse->setErrorCode(200);
+        pResponse->setResponseResult(OC_EH_OK);
+
+        return OCPlatform::sendResponse(pResponse);
+    }
+
+    OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
+    {
+        std::cout << "\tConsumer Entity Handler:" << std::endl;
+        OCEntityHandlerResult ehResult = OC_EH_ERROR;
+
+        if (request)
+        {
+            // Note: Most of the handlers are not here, since this is for
+            // demoing client/server co-process existence.
+            // See simpleserver for a more complete example.
+            if (request->getRequestHandlerFlag() == RequestHandlerFlag::RequestFlag)
+            {
+                std::cout << "\t\trequestFlag : Request" << std::endl;
+
+                if (request->getRequestType() == "GET")
+                {
+                    std::cout << "\t\t\trequestType : GET" << std::endl;
+                    if (OC_STACK_OK == sendResponse(request))
+                    {
+                        ehResult = OC_EH_OK;
+                    }
+                }
+                else if (request->getRequestType() == "PUT")
+                {
+                    std::cout << "\t\t\trequestType : PUT" << std::endl;
+
+                    OCRepresentation rep = request->getResourceRepresentation();
+                    put(rep);
+                    if (OC_STACK_OK == sendResponse(request))
+                    {
+                        ehResult = OC_EH_OK;
+                    }
+                }
+                else
+                {
+                    std::cout << "\t\t\trequestType : UNSUPPORTED: " <<
+                              request->getRequestType() << std::endl;
+                }
+            }
+            else
+            {
+                std::cout << "\t\trequestFlag : UNSUPPORTED: ";
+
+                if (request->getRequestHandlerFlag() == RequestHandlerFlag::ObserverFlag)
+                {
+                    std::cout << "ObserverFlag" << std::endl;
+                }
+            }
+        }
+        else
+        {
+            std::cout << "Request Invalid!" << std::endl;
+        }
+
+        return ehResult;
+    }
+};
+
+OCStackApplicationResult handlePublishCB(void *ctx,
+        OCDoHandle /*handle*/,
+        OCClientResponse *clientResponse)
+{
+    if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
+    {
+        std::cout << "Invalid Publish callback received" << std::endl;
+    }
+
+    std::cout << "Publish resource response received, code: " << clientResponse->result << std::endl;
+
+    return OC_STACK_KEEP_TRANSACTION;
+}
+
+OCStackApplicationResult handleLoginoutCB(void *ctx,
+        OCDoHandle /*handle*/,
+        OCClientResponse *clientResponse)
+{
+    if (ctx != (void *)DEFAULT_CONTEXT_VALUE)
+    {
+        std::cout << "Invalid Login callback received" << std::endl;
+    }
+
+    std::cout << "Login/out response received code: " << clientResponse->result << std::endl;
+
+    if (clientResponse->payload != NULL &&
+        clientResponse->payload->type == PAYLOAD_TYPE_REPRESENTATION)
+    {
+        std::cout << "PAYLOAD_TYPE_REPRESENTATION received" << std::endl;
+
+        OCRepPayloadValue *val = ((OCRepPayload *)clientResponse->payload)->values;
+
+        while (val)
+        {
+            std::cout << "Name: " << val->name << " Value: " << val->str << std::endl;
+            val = val->next;
+        }
+    }
+
+    return OC_STACK_KEEP_TRANSACTION;
+}
+
+void PrintUsage()
+{
+    std::cout << std::endl;
+    std::cout << "Usage : cloud_device <addr:port> <session>\n";
+    std::cout << "<addr:port>: Cloud Address, \"127.0.0.1:5683\"\n";
+    std::cout <<
+              "<session>: String value, Provided by response of onboarding scenario\n\tor kind of registration portal\n\n";
+    std::cout <<
+              "If you want to go API test mode include device registration,\n\tleave blank to <session> fields\n";
+    std::cout <<
+              "sample: \"cloud_device 127.0.0.1:5683\"\n\t-Enter API testmode\n\n";
+    std::cout <<
+              "sample: \"cloud_device 127.0.0.1:5683 1234567890123456\"\n\t-Enter API testmode using registered session\n\n";
+}
+
+void PublishResources(std::string host, std::string additionalQuery)
+{
+    std::cout << "Running as Server mode" << std::endl;
+
+    FooResource fooRes1, fooRes2;
+
+    if (!fooRes1.createResource("/q/resource_foo1"))
+    {
+        std::cout << "Unable to create resource" << std::endl;
+        return;
+    }
+
+    if (!fooRes2.createResource("/q/resource_foo2"))
+    {
+        std::cout << "Unable to create resource" << std::endl;
+        return;
+    }
+
+    std::string requestQuery = DEFAULT_PUBLISH_QUERY;
+    requestQuery += additionalQuery;
+
+    std::cout << "Publishing resources..." << std::endl;
+    std::cout << host.c_str() << requestQuery.c_str() << std::endl;
+
+    if (OCCloudPublish(host.c_str(), requestQuery.c_str(), &handlePublishCB, 2,
+                       fooRes1.getHandle(), fooRes2.getHandle()) != OC_STACK_OK)
+    {
+        std::cout << "Unable to publish resources to cloud" << std::endl;
+    }
+}
+
+void DiscoverResources(std::string host, std::string additionalQuery)
+{
+    std::cout << "Running as Client mode" << std::endl;
+
+    ResourceClient client;
+    std::string requestQuery = DEFAULT_DISCOVER_QUERY;
+    requestQuery += additionalQuery;
+
+    std::cout << "Finding resources..." << std::endl;
+    std::cout << host.c_str() << requestQuery.c_str() << std::endl;
+
+    if (client.start(host.c_str(), requestQuery.c_str()) != OC_STACK_OK)
+    {
+        std::cout << "Unable to find resources from cloud" << std::endl;
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    std::string host = "coap+tcp://";
+
+    std::string cmdQuery;
+    std::string session;
+
+    PlatformConfig cfg
+    {
+        OC::ServiceType::InProc,
+        OC::ModeType::Both,
+        "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
+        0,         // Uses randomly available port
+        OC::QualityOfService::LowQos
+    };
+
+    OCPlatform::Configure(cfg);
+    FooResource defaultResource;
+    if (!defaultResource.createResource("/q/default"))
+    {
+        std::cout << "Unable to create default resource" << std::endl;
+        return -1;
+    }
+
+    switch (argc)
+    {
+        case 1:
+            PrintUsage();
+            return 0;
+            break;
+
+        case 2:
+            std::cout <<
+                      "1. Login to cloud using OAuth2 auth code and auth provider name(AuthCode'OAuth2' required)" <<
+                      std::endl;
+            std::cout << "2. Login to cloud using session(Session required)" << std::endl;
+            std::cout << "3. Logout from cloud using session(Session required)" << std::endl;
+            std::cout << "s. Running as Resource Server mode" << std::endl;
+            std::cout << "c. Running as Resource Client mode" << std::endl;
+            std::cout << "exit: q" << std::endl;
+            std::cin >> cmdQuery;
+            break;
+
+        case 3:
+            cmdQuery = "2";
+            session = argv[2];
+            break;
+    }
+
+    host += argv[1];
+
+    std::cout << "Host " << host.c_str() << std::endl;
+
+    std::string authProvider;
+    std::string authCode;
+
+    OCStackResult   res = OC_STACK_ERROR;
+
+    while (cmdQuery[0] != 'q')
+    {
+        switch (cmdQuery[0])
+        {
+            case '1':
+                std::cout << "Put auth provider name(ex: github)" << std::endl;
+                std::cin >> authProvider;
+                std::cout << "Put auth code(provided by auth provider)" << std::endl;
+                std::cin >> authCode;
+                std::cout << "Login to cloud using " << authProvider << " " << authCode << std::endl;
+                res = OCCloudRegisterLogin(host.c_str(), authProvider.c_str(), authCode.c_str(),
+                                           handleLoginoutCB);
+                std::cout << "OCCloudRegisterLogin return " << res << std::endl;
+                break;
+
+            case '2':
+                std::cout << "Put session to login" << std::endl;
+                if (session.size() == 0)
+                    std::cin >> session;
+                else
+                    std::cout << session.c_str() << std::endl;
+                res = OCCloudLogin(host.c_str(), session.c_str(), handleLoginoutCB);
+                std::cout << "OCCloudLogin return " << res << std::endl;
+                break;
+
+            case '3':
+                std::cout << "Put session to logout" << std::endl;
+                if (session.size() == 0)
+                    std::cin >> session;
+                else
+                    std::cout << session.c_str() << std::endl;
+                res = OCCloudLogout(host.c_str(), session.c_str(), handleLoginoutCB);
+                std::cout << "OCCloudLogout return" << res << std::endl;
+                break;
+
+            case 's':
+                PublishResources(host, "");
+                break;
+
+            case 'c':
+                DiscoverResources(host, "");
+                break;
+        }
+
+        std::cin >> cmdQuery;
+    }
+
+    return 0;
+}