Added secserver and secserverobserver - demo apps for local notification tests
authorAndriy Gudz <a.gudz@samsung.com>
Wed, 10 May 2017 06:01:20 +0000 (09:01 +0300)
committerAndriy Gudz <a.gudz@samsung.com>
Wed, 10 May 2017 06:01:20 +0000 (09:01 +0300)
demo/iot-es/scripts/gbs.conf
demo/iot-es/src/CMakeLists.txt
demo/iot-es/src/master/CMakeLists.txt
demo/iot-es/src/master/mediator_cpp.cpp
demo/iot-es/src/master/oic_svr_db_client.dat [deleted file]
demo/iot-es/src/secserver/CMakeLists.txt [new file with mode: 0644]
demo/iot-es/src/secserver/notification_resource.cpp [new file with mode: 0644]
demo/iot-es/src/secserver/notification_resource.h [new file with mode: 0644]
demo/iot-es/src/secserver/secserver.cpp [new file with mode: 0644]
demo/iot-es/src/secserverobserver/CMakeLists.txt [new file with mode: 0644]
demo/iot-es/src/secserverobserver/secserverobserver.cpp [new file with mode: 0644]

index da18238..006a7bf 100644 (file)
@@ -25,31 +25,27 @@ url=http://10.103.211.119/releases/tizen-3.0-product-main2017/product/KantM/TIZE
 
 [profile.Main2017_KantM]
 obs = obs.tizentv
-repos = repo.product_Main2017_KantM, repo.srk_Main2017, repo.base_Main2017, repo.local_Main2017
+repos = repo.base_Main2017, repo.srk_Main2017, repo.product_Main2017_KantM, repo.local_Main2017
 buildroot = ~/GBS_ROOT_3.0
 
 ############################################# Profile [profile.tzmb_3.0_TM2]
 
-[profile.tzmb_3.0_TM2]
-obs = obs.tizen_org
-repos = repo.tzmb_3.0_TM2_base, repo.tzmb_3.0_TM2_srk, repo.tzmb_4.0_unified
-buildroot = ~/GBS_ROOT_3.0_TM2
-
 [repo.tzmb_3.0_TM2_base]
-url = http://download.tizen.org/snapshots/tizen/base/tizen-base_20170421.1/repos/arm64/packages/
+#url = http://download.tizen.org/snapshots/tizen/base/tizen-base_20170421.1/repos/arm64/packages/
+url = http://download.tizen.org/snapshots/tizen/base/latest/repos/arm64/packages/
 [repo.tzmb_3.0_TM2_srk]
 url = http://106.125.46.44/repo/tm2/packages/
 [repo.tzmb_4.0_unified]
-url = http://download.tizen.org/snapshots/tizen/unified/tizen-unified_20170421.1/repos/standard/packages/
+#url = http://download.tizen.org/snapshots/tizen/unified/tizen-unified_20170421.1/repos/standard/packages/
+url = http://download.tizen.org/snapshots/tizen/unified/latest/repos/standard/packages/
 
+[profile.tzmb_3.0_TM2]
+obs = obs.tizen_org
+repos = repo.tzmb_3.0_TM2_base, repo.tzmb_3.0_TM2_srk, repo.tzmb_4.0_unified
+buildroot = ~/GBS_ROOT_3.0_TM2
 
 ############################################# Profile [profile.tzmb_3.0_TM1]
 
-[profile.tzmb_3.0_TM1]
-obs = obs.tizen_org
-repos = repo.tzmb_3.0_TM1_base, repo.tzmb_3.0_TM1_srk, repo.tzmb_3.0_TM1
-buildroot = ~/GBS_ROOT_3.0_TM1
-
 [repo.tzmb_3.0_TM1_base]
 url = http://download.tizen.org/snapshots/tizen/base/latest/repos/arm/packages/
 [repo.tzmb_3.0_TM1_srk]
@@ -57,5 +53,7 @@ url = http://106.125.46.44/repo/tm1/packages/
 [repo.tzmb_3.0_TM1]
 url = http://download.tizen.org/snapshots/tizen/mobile/latest/repos/arm-wayland/packages/
 
-
-
+[profile.tzmb_3.0_TM1]
+obs = obs.tizen_org
+repos = repo.tzmb_3.0_TM1_base, repo.tzmb_3.0_TM1_srk, repo.tzmb_4.0_unified
+buildroot = ~/GBS_ROOT_3.0_TM1
index 99920bc..4f13be0 100644 (file)
@@ -82,3 +82,5 @@ endif()
 add_subdirectory(slave)
 #add_subdirectory(simple)
 add_subdirectory(authcode)
+add_subdirectory(secserver)
+add_subdirectory(secserverobserver)
index 70317f6..698c695 100644 (file)
@@ -27,7 +27,6 @@ target_link_libraries(${PROJECT_NAME}
        authcode
 )
 
-install(FILES oic_svr_db_client.dat DESTINATION "${INSTALL_DIR}/master")
 install(TARGETS ${ProjectId} DESTINATION "${INSTALL_DIR}/master")
 
 message(STATUS "Configuring: " ${ProjectId})
index 9863e59..fda2db4 100755 (executable)
@@ -35,8 +35,6 @@
 #define ES_SAMPLE_APP_TAG "ES_SAMPLE_APP_TAG"
 #define DECLARE_MENU(FUNC, ...) { #FUNC, FUNC }
 
-#define JSON_DB_PATH "./oic_svr_db_client.dat"
-
 using namespace std;
 using namespace OC;
 using namespace OIC::Service;
@@ -58,6 +56,7 @@ static std::string accessToken;//("3fb2b6a6596f712becf4c41031cd141432d7e2c7");
 static std::string cloudId;
 
 
+vector<string> presVector;
 
 typedef void (*Runner)();
 
@@ -67,11 +66,73 @@ condition_variable  g_callbackLock;
 
 void printRepresentation(OCRepresentation);
 
+static string psPath;
+
+static FILE* client_open(const char*, const char *mode)
+{
+    if(psPath.size() == 0)
+        logic_error("Persistant storage path empty");
+    return fopen(psPath.c_str(), mode);
+}
+
+static void setPersStoragePath()
+{
+    char SVR_DB_FILE_PATH[1000] = {0};
+    ssize_t size = readlink("/proc/self/exe", SVR_DB_FILE_PATH, sizeof(SVR_DB_FILE_PATH));
+    if (size == 0 || size == sizeof(SVR_DB_FILE_PATH))
+        return throw runtime_error("readlink error");
+    psPath = string(SVR_DB_FILE_PATH) + "_ps.dat";
+}
+
 void deviceInfoHandler(const OCRepresentation& rep)
 {
     printRepresentation(rep);
 }
 
+void fillPresVector(OCRepresentation rep)
+{
+    for (auto itr = rep.begin(); itr != rep.end(); ++itr)
+    {
+        string attrName(itr->attrname());
+        if (attrName == "di")
+            presVector.push_back(itr->getValueToString());
+        if (itr->type() == AttributeType::Vector)
+        {
+            switch (itr->base_type())
+            {
+            case AttributeType::OCRepresentation:
+                for (auto itr2 : (*itr).getValue<vector<OCRepresentation> >())
+                {
+                    fillPresVector(itr2);
+                }
+                break;
+
+            case AttributeType::Integer:
+                for (auto itr2 : (*itr).getValue<vector<int> >())
+                {
+                    cout << "\t\t" << itr2 << endl;
+                }
+                break;
+
+            case AttributeType::String:
+                for (auto itr2 : (*itr).getValue<vector<string> >())
+                {
+                    cout << "\t\t" << itr2 << endl;
+                }
+                break;
+
+            default:
+                cout << "Unhandled base type " << itr->base_type() << endl;
+                break;
+            }
+        }
+        else if (itr->type() == AttributeType::OCRepresentation)
+        {
+            fillPresVector((*itr).getValue<OCRepresentation>());
+        }
+    }
+}
+
 void printRepresentation(OCRepresentation rep)
 {
     for (auto itr = rep.begin(); itr != rep.end(); ++itr)
@@ -295,7 +356,6 @@ void provisionCloudProperty(std::shared_ptr<RemoteEnrollee> remoteEnrollee)
     }
 }
 
-
 void onObserve(const HeaderOptions /*headerOptions*/, const OCRepresentation &rep,
                const int &eCode, const int &sequenceNumber)
 {
@@ -310,6 +370,7 @@ void onObserve(const HeaderOptions /*headerOptions*/, const OCRepresentation &re
 
             cout << "OBSERVE RESULT:" << endl;
             printRepresentation(rep);
+            fillPresVector(rep);
         }
         else
         {
@@ -328,6 +389,7 @@ void onObserve(const HeaderOptions /*headerOptions*/, const OCRepresentation &re
     {
         cout << "Exception: " << e.what() << " in onObserve" << endl;
     }
+    g_callbackLock.notify_all();
 }
 
 // Callback to found resources
@@ -348,15 +410,28 @@ void foundES(std::shared_ptr<OC::OCResource> resource)
     }
 }
 
-static FILE* client_open(const char *UNUSED_PARAM, const char *mode)
+void onSignUp(const HeaderOptions &,
+                      const OCRepresentation &rep,
+                      const int ecode)
 {
-    (void)UNUSED_PARAM;
-    return fopen(JSON_DB_PATH, mode);
-}
+    if (rep.getPayload() != NULL)
+    {
+        printRepresentation(rep);
+    }
 
+    if (ecode == 4)
+    {
+        accessToken = rep.getValueToString("accesstoken");
+        userId = rep.getValueToString("uid");
+        cloudId = rep.getValueToString("sid");
 
+        cout << "onSignUp success" << endl;
+    }
+
+    g_callbackLock.notify_all();
+}
 
-void handleLoginoutCB(const HeaderOptions &,
+void onSignIn(const HeaderOptions &,
                       const OCRepresentation &rep,
                       const int ecode)
 {
@@ -367,14 +442,13 @@ void handleLoginoutCB(const HeaderOptions &,
 
     if (ecode == 4)
     {
-        accessToken = rep.getValueToString("accesstoken");
-        userId = rep.getValueToString("uid");
-        cloudId = rep.getValueToString("sid");
+        cout << "onSignIn success" << endl;
     }
 
     g_callbackLock.notify_all();
 }
 
+
 void foundDevice(shared_ptr<OC::OCResource> resource)
 {
     vector<string> rt = resource->getResourceTypes();
@@ -399,12 +473,15 @@ void presenceDevice(OCStackResult , const unsigned int i, const string &str)
     cout << "Presence received, i=" << i << " str=" << str << endl;
 }
 
-
+void onDeleteDevice(const HeaderOptions&, const int eCode) {
+    cout << "onDeleteDevice " << onDeleteDevice << endl;
+}
 
 int main()
 {
     try
     {
+        setPersStoragePath();
         std::cout << "IoTivity configuring..." << std::endl << std::flush;
         OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
         PlatformConfig config { OC::ServiceType::InProc, ModeType::Both, "0.0.0.0", 0, OC::QualityOfService::HighQos, &ps };
@@ -424,11 +501,11 @@ int main()
             std::cout << "providerParam=" << providerParam << std::endl << std::flush;
             std::string authcode = authProvider.getAuthCode(login, password);
             std::cout << "authcode=" << authcode << std::endl << std::flush;
-            accountMgr->signUp(providerParam, authcode, &handleLoginoutCB);
+            accountMgr->signUp(providerParam, authcode, &onSignUp);
             g_callbackLock.wait(lock);
         }
 
-        accountMgr->signIn(userId, accessToken, &handleLoginoutCB);
+        accountMgr->signIn(userId, accessToken, &onSignIn);
         g_callbackLock.wait(lock);
 
 
@@ -451,6 +528,18 @@ int main()
 //        cout << "Subscribing resource presence ";
 //        OCPlatform::OCPresenceHandle    handle;
 //        OCStackResult result = OCPlatform::subscribeDevicePresence(handle, host, {  }, CT_DEFAULT, &onObserve);
+//        g_callbackLock.wait(lock);
+
+/* Delete devices example */
+//        for (auto did: presVector) {
+//            cout << "{did:\"" << did << "\"}"<< endl;
+//            string at;
+//            cin >> at;
+//            accountMgr->deleteDevice(at, did, &onDeleteDevice);
+
+//            accountMgr->signIn(userId, accessToken, &onSignIn);
+//            g_callbackLock.wait(lock);
+//        }
 
 /* SHOW ALL DEVICES in lan */
 //        std::string deviceDiscoveryURI = "/oic/d";
diff --git a/demo/iot-es/src/master/oic_svr_db_client.dat b/demo/iot-es/src/master/oic_svr_db_client.dat
deleted file mode 100755 (executable)
index 6f5b6f6..0000000
Binary files a/demo/iot-es/src/master/oic_svr_db_client.dat and /dev/null differ
diff --git a/demo/iot-es/src/secserver/CMakeLists.txt b/demo/iot-es/src/secserver/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5b0ee38
--- /dev/null
@@ -0,0 +1,15 @@
+get_filename_component(ProjectId ${CMAKE_CURRENT_SOURCE_DIR} NAME)
+string(REPLACE " " "_" ProjectId ${ProjectId})
+project(${ProjectId})
+
+set(app ${ProjectId})
+file(GLOB SRCS *.cpp)
+
+add_executable(${app} ${SRCS})
+target_link_libraries(${app}
+       # main iotivity libs
+       oc octbstack oc_logger connectivity_abstraction
+       # concurent support
+       pthread
+)
+install(TARGETS ${app} DESTINATION "${INSTALL_DIR}/secserver")
diff --git a/demo/iot-es/src/secserver/notification_resource.cpp b/demo/iot-es/src/secserver/notification_resource.cpp
new file mode 100644 (file)
index 0000000..9eac629
--- /dev/null
@@ -0,0 +1,143 @@
+#include "notification_resource.h"
+
+namespace PH = std::placeholders;
+
+const std::string NotificationResource::RESOURCE_DEFAULT_MESSAGE = "Empty notification";
+
+NotificationResource::NotificationResource():
+    NotificationResource(true)
+{
+}
+
+NotificationResource::NotificationResource(bool isSecured):
+    mCode(0),
+    mTime(std::time(nullptr)),
+    mMessage(RESOURCE_DEFAULT_MESSAGE),
+    mUri(NOTIFICATION_URI),
+    mResourceHandle(nullptr),
+    mIsSecured(isSecured)
+{
+}
+
+void NotificationResource::registerResource()
+{
+
+    EntityHandler resourceCallback = std::bind(&NotificationResource::entityHandler, this, PH::_1);
+
+    // This will internally create and register the resource.
+    OCStackResult result = OCPlatform::registerResource(
+                               mResourceHandle,
+                               mUri,
+                               NOTIFICATION_TYPE,
+                               DEFAULT_INTERFACE,
+                               resourceCallback,
+                               OC_DISCOVERABLE | OC_OBSERVABLE | (mIsSecured ? OC_SECURE : 0)
+                           );
+
+    if (OC_STACK_OK != result)
+        cout << "Resource creation was unsuccessful\n";
+    else
+        cout << "Notification resource created.\n";
+}
+
+OCResourceHandle NotificationResource::getHandle()
+{
+    return mResourceHandle;
+}
+
+OCRepresentation NotificationResource::getRepr()
+{
+    OCRepresentation mRepr;
+    mRepr.setUri(mUri);
+    mRepr.setValue("time", (int) mTime);
+    mRepr.setValue("code", mCode);
+    mRepr.setValue("message", mMessage);
+    mRepr.setValue("result", 0);
+    return mRepr;
+}
+
+void NotificationResource::set(int code, std::string message)
+{
+    mTime = std::time(nullptr);
+    mCode = code;
+    mMessage = message;
+}
+
+void NotificationResource::get(int& code, std::string& message, std::time_t& time)
+{
+    time = mTime;
+    code = mCode;
+    message = mMessage;
+}
+
+
+//ObservationIds NotificationResource::getObserversList()
+//{
+//    return mObserversList;
+//}
+
+inline std::shared_ptr<OC::OCResourceResponse>
+constructRequest(std::shared_ptr<OC::OCResourceRequest> request, OCRepresentation rep)
+{
+    shared_ptr<OCResourceResponse> pResponse = make_shared<OCResourceResponse>();
+    pResponse->setRequestHandle(request->getRequestHandle());
+    pResponse->setResourceHandle(request->getResourceHandle());
+    pResponse->setErrorCode(200);
+    pResponse->setResponseResult(OC_EH_OK);
+    pResponse->setResourceRepresentation(rep, DEFAULT_INTERFACE);
+    return pResponse;
+}
+
+OCEntityHandlerResult NotificationResource::entityHandler(std::shared_ptr<OCResourceRequest> request)
+{
+    OCEntityHandlerResult ehResult = OC_EH_ERROR;
+    if(!request)
+    {
+        std::cout << "Request invalid" << std::endl;
+        return ehResult;
+    }
+
+    std::cout << "Handling request from client:\n";
+
+    // Get the request type and request flag
+    std::string requestType = request->getRequestType();
+    int requestFlag = request->getRequestHandlerFlag();
+
+    QueryParamsMap queries = request->getQueryParameters();
+
+    if(requestFlag & RequestHandlerFlag::RequestFlag && requestType == "GET")
+    {
+        if(OC_STACK_OK == OCPlatform::sendResponse(constructRequest(request, getRepr())))
+        {
+            ehResult = OC_EH_OK;
+        }
+    }
+
+    if(requestFlag & RequestHandlerFlag::ObserverFlag)
+    {
+        ObservationInfo observationInfo = request->getObservationInfo();
+
+        if(ObserveAction::ObserveRegister == observationInfo.action)
+        {
+            mObserversList.push_back(observationInfo.obsId);
+
+            std::cout << "Client "
+                      << "[" << observationInfo.address
+                      << "]:" << observationInfo.port
+                      << " was registered to observe "
+                      << request->getResourceUri() << "\n";
+        }
+        // Have no idea how to get this flag - ObserveUnregister
+        else if(ObserveAction::ObserveUnregister == observationInfo.action)
+        {
+            mObserversList.erase(std::remove(
+                                     mObserversList.begin(),
+                                     mObserversList.end(),
+                                     observationInfo.obsId),
+                                 mObserversList.end());
+        }
+        ehResult = OC_EH_OK;
+    }
+
+    return ehResult;
+}
diff --git a/demo/iot-es/src/secserver/notification_resource.h b/demo/iot-es/src/secserver/notification_resource.h
new file mode 100644 (file)
index 0000000..d5ed3e4
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef ALERTRESOURCE_H
+#define ALERTRESOURCE_H
+
+#include "OCPlatform.h"
+
+using namespace OC;
+using namespace std;
+
+static const std::string NOTIFICATION_URI = "/secserver/notification";
+static const std::string NOTIFICATION_TYPE = "secserver.notification";
+
+/**
+ * Class that represents /secserver/notification resource.
+ */
+class NotificationResource
+{
+public:
+
+private:
+    static const std::string RESOURCE_DEFAULT_MESSAGE;
+
+    int mCode;
+    std::time_t mTime;
+    std::string mMessage;
+    std::string mUri;
+
+    OCResourceHandle mResourceHandle;
+       ObservationIds mObserversList;
+    bool mIsSecured;
+
+public:
+    /**
+     * Constructor
+     *
+     * @param dbHandler database object for authentication
+     */
+       NotificationResource();
+
+    /**
+     * Constructor
+     *
+     * @param dbHandler database object for authentication
+     * @param isSecure flag indicates that resource is secured
+     */
+       NotificationResource(bool isSecure);
+
+    /**
+     * Register resource to make IOTivity clients to find it
+     */
+    void registerResource();
+
+    /**
+     * Getter for resource mResourceHandle
+     *
+     * @return mResourceHandle object
+     */
+    OCResourceHandle getHandle();
+
+    /**
+     * Gets the updated representation.
+     *
+     * @return representation object
+     */
+    OCRepresentation getRepr();
+
+    /**
+     * Updates internal fields of resource.
+     */
+    void set(int code, std::string message);
+
+    void get(int& code, std::string& message, std::time_t& time);
+
+private:
+    OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request);
+};
+
+#endif // ALERTRESOURCE_H
diff --git a/demo/iot-es/src/secserver/secserver.cpp b/demo/iot-es/src/secserver/secserver.cpp
new file mode 100644 (file)
index 0000000..9b88441
--- /dev/null
@@ -0,0 +1,102 @@
+#include "OCPlatform.h"
+#include "notification_resource.h"
+
+using namespace OC;
+using namespace std;
+namespace PH = std::placeholders;
+
+static string psPath;
+
+static FILE* client_open(const char*, const char *mode)
+{
+    if(psPath.size() == 0)
+        logic_error("Persistant storage path empty");
+    return fopen(psPath.c_str(), mode);
+}
+
+static void setPersStoragePath()
+{
+    char SVR_DB_FILE_PATH[1000] = {0};
+    ssize_t size = readlink("/proc/self/exe", SVR_DB_FILE_PATH, sizeof(SVR_DB_FILE_PATH));
+    if (size == 0 || size == sizeof(SVR_DB_FILE_PATH))
+        return throw runtime_error("readlink error");
+    psPath = string(SVR_DB_FILE_PATH) + "_ps.dat";
+}
+
+void inputNotificationData(int& notifCode, string& notifMessage, time_t& notifTime)
+{
+    std::cout << "\n\nPlease enter new notification [Current: "
+              << notifCode << " \"" << notifMessage << "\" " << notifTime << "]:\n";
+
+    string inputLine;
+    std::getline (std::cin, inputLine);
+
+    std::size_t ending = inputLine.find(" ");
+
+    try
+    {
+        if (inputLine.size() > 0)
+            notifCode = stoi(inputLine);
+
+        if (ending != std::string::npos)
+            notifMessage = inputLine.substr(ending + 1, inputLine.size() - ending);
+    }
+    catch (const std::exception& e)
+    {
+        // nothing
+    }
+}
+
+int main(int argc, char* argv[])
+{
+    setPersStoragePath();
+
+    bool isSecured = false;
+    if (argc >= 2)
+    {
+        int value = atoi(argv[1]);
+
+        // Turn off secure flag if first argument equals 0
+        if (value == 0)
+        {
+            isSecured = false;
+            cout << "Used unsecured resources!\n\n";
+        }
+    }
+
+    OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
+    PlatformConfig cfg { OC::ServiceType::InProc, OC::ModeType::Server,
+                         "0.0.0.0", 0, OC::QualityOfService::LowQos, &ps };
+    OCPlatform::Configure(cfg);
+
+    try
+    {
+        NotificationResource notifResource(isSecured);
+        notifResource.registerResource();
+
+        int notifCode;
+        string notifMessage;
+        time_t notifTime;
+
+        while(true)
+        {
+            notifResource.get(notifCode, notifMessage, notifTime);
+            inputNotificationData(notifCode, notifMessage, notifTime);
+
+            cout << "Sending notif:" << notifCode << " " << notifMessage << "\n";
+
+            notifResource.set(notifCode, notifMessage);
+
+            OCStackResult result = OCPlatform::notifyAllObservers(notifResource.getHandle());
+
+            if(OC_STACK_NO_OBSERVERS == result)
+                cout << "No more observers" << endl;
+        }
+    }
+    catch(OCException &e)
+    {
+        std::cout << "OCException in main : " << e.what() << endl;
+    }
+
+    return 0;
+}
diff --git a/demo/iot-es/src/secserverobserver/CMakeLists.txt b/demo/iot-es/src/secserverobserver/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ba46ba7
--- /dev/null
@@ -0,0 +1,18 @@
+get_filename_component(ProjectId ${CMAKE_CURRENT_SOURCE_DIR} NAME)
+string(REPLACE " " "_" ProjectId ${ProjectId})
+project(${ProjectId})
+
+set(app ${ProjectId})
+file(GLOB SRCS *.cpp)
+
+add_executable(${app} ${SRCS})
+target_link_libraries(${app}
+       # main iotivity libs
+       oc octbstack oc_logger connectivity_abstraction
+
+       # hz
+       coap
+
+       pthread
+)
+install(TARGETS ${app} DESTINATION "${INSTALL_DIR}/secserverobserver")
diff --git a/demo/iot-es/src/secserverobserver/secserverobserver.cpp b/demo/iot-es/src/secserverobserver/secserverobserver.cpp
new file mode 100644 (file)
index 0000000..1790066
--- /dev/null
@@ -0,0 +1,200 @@
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH 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.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+// OCClient.cpp : Defines the entry point for the console application.
+//
+#include "iotivity_config.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+#ifdef HAVE_WINDOWS_H
+#include <Windows.h>
+#endif
+#include <string>
+#include <map>
+#include <cstdlib>
+#include <mutex>
+#include <condition_variable>
+#include "OCPlatform.h"
+#include "OCApi.h"
+#include "../secserver/notification_resource.h"
+
+using namespace OC;
+
+typedef std::map<OCResourceIdentifier, std::shared_ptr<OCResource>> DiscoveredResourceMap;
+
+DiscoveredResourceMap discoveredResources;
+std::shared_ptr<OCResource> curResource;
+std::mutex curResourceLock;
+
+using namespace std;
+
+static string psPath;
+
+static FILE* client_open(const char*, const char *mode)
+{
+    if(psPath.size() == 0)
+        logic_error("Persistant storage path empty");
+    return fopen(psPath.c_str(), mode);
+}
+
+static void setPersStoragePath()
+{
+    char SVR_DB_FILE_PATH[1000] = {0};
+    ssize_t size = readlink("/proc/self/exe", SVR_DB_FILE_PATH, sizeof(SVR_DB_FILE_PATH));
+    if (size == 0 || size == sizeof(SVR_DB_FILE_PATH))
+        return throw runtime_error("readlink error");
+    psPath = string(SVR_DB_FILE_PATH) + "_ps.dat";
+}
+
+void printRepresentation(OCRepresentation rep)
+{
+    for (auto itr = rep.begin(); itr != rep.end(); ++itr)
+    {
+        cout << "\t" << itr->attrname() << ":\t" << itr->getValueToString() << endl;
+        if (itr->type() == AttributeType::Vector)
+        {
+            switch (itr->base_type())
+            {
+            case AttributeType::OCRepresentation:
+                for (auto itr2 : (*itr).getValue<vector<OCRepresentation> >())
+                {
+                    printRepresentation(itr2);
+                }
+                break;
+
+            case AttributeType::Integer:
+                for (auto itr2 : (*itr).getValue<vector<int> >())
+                {
+                    cout << "\t\t" << itr2 << endl;
+                }
+                break;
+
+            case AttributeType::String:
+                for (auto itr2 : (*itr).getValue<vector<string> >())
+                {
+                    cout << "\t\t" << itr2 << endl;
+                }
+                break;
+
+            default:
+                cout << "Unhandled base type " << itr->base_type() << endl;
+                break;
+            }
+        }
+        else if (itr->type() == AttributeType::OCRepresentation)
+        {
+            printRepresentation((*itr).getValue<OCRepresentation>());
+        }
+    }
+}
+
+void onObserve(const HeaderOptions /*headerOptions*/, const OCRepresentation& rep,
+               const int& eCode, const int& sequenceNumber)
+{
+    try
+    {
+        if(eCode == OC_STACK_OK && sequenceNumber <= MAX_SEQUENCE_NUMBER)
+        {
+            if(sequenceNumber == OC_OBSERVE_REGISTER)
+            {
+                std::cout << "Observe registration action is successful" << std::endl;
+            }
+
+            std::cout << "OBSERVE RESULT:" << std::endl;
+            printRepresentation(rep);
+        }
+        else
+        {
+            if(eCode == OC_STACK_OK)
+            {
+                std::cout << "No observe option header is returned in the response." << std::endl;
+                std::cout << "For a registration request, it means the registration failed"
+                          << std::endl;
+            }
+            else
+            {
+                std::cout << "onObserve Response error: " << eCode << std::endl;
+                std::exit(-1);
+            }
+        }
+    }
+    catch(std::exception& e)
+    {
+        std::cout << "Exception: " << e.what() << " in onObserve" << std::endl;
+    }
+
+}
+
+void foundResource(std::shared_ptr<OCResource> resource)
+{
+    try
+    {
+        std::string resourceURI = resource->uri();
+        std::string resourceHost = resource->host();
+        std::string resourceDuid = resource->sid();
+        lock_guard<std::mutex> lock(curResourceLock);
+        if(resourceURI == NOTIFICATION_URI && !curResource)
+        {
+            curResource = resource;
+            cout << "\tFound: " << resourceURI << " " <<
+                 resourceHost << " " << resourceDuid << endl << flush;
+            resource->observe(ObserveType::ObserveAll, QueryParamsMap(), &onObserve);
+        }
+    }
+    catch(std::exception& e)
+    {
+        std::cerr << "Exception in foundResource: " << e.what() << std::endl;
+    }
+}
+
+int main(int argc, char* argv[])
+{
+    setPersStoragePath();
+
+    std::ostringstream requestURI;
+    OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink };
+    PlatformConfig cfg { OC::ServiceType::InProc, OC::ModeType::Both, "0.0.0.0", 0, OC::QualityOfService::HighQos, &ps };
+
+    OCPlatform::Configure(cfg);
+    try
+    {
+        // Find all resources
+        requestURI << OC_RSRVD_WELL_KNOWN_URI << "?rt=" << NOTIFICATION_TYPE;
+
+        OCPlatform::findResource("", requestURI.str(), CT_DEFAULT, &foundResource);
+        std::cout << "Finding Resource... " << std::endl;
+
+        std::mutex blocker;
+        std::condition_variable cv;
+        std::unique_lock<std::mutex> lock(blocker);
+        cv.wait(lock);
+
+    }
+    catch(OCException& e)
+    {
+        oclog() << "Exception in main: " << e.what();
+    }
+
+    return 0;
+}