easy-setup/enrollee/inc
json_policy/inc
easy-setup/mediator/richsdk/inc
+ ../secserver
)
#add_subdirectory(easy-setup/enrollee)
add_subdirectory(easy-setup/mediator/richsdk)
-#add_subdirectory(IoT)
FILE(GLOB CTRL_APP_SUPPORT_SRCS ctrl_app/src/*.cpp)
#pragma GCC diagnostic pop
#include <logging.h>
+#include "notification_resource.h"
+
using namespace std;
using namespace OC;
#define TAG "NetworkManager"
const std::string SIGNUP = "Sign up";
const std::string SIGNIN = "Sign in";
const std::string SIGNOUT = "Sign out";
+const std::string NOTIF_FIND = "Notification findResource()";
+const std::string NOTIF_REQUEST = string(OC_RSRVD_WELL_KNOWN_URI) + "?rt=" + NOTIFICATION_TYPE;
+
const std::string REP_LIST{"prslist"};
void printRepresentation(OCRepresentation rep)
{
const std::string IoTivity::DEFAULT_PROVIDER = "samsung";
-const int IoTivity::DEFAULT_TIMEOUT = 10;
+const int IoTivity::DEFAULT_TIMEOUT = 5;
struct Params
{
throw IoTInternalError(message + " error:" + std::to_string(resultCode), EC_IOTIVITY_ERROR);
}
+void IoTivity::guardUnauthorized()
+{
+ if (!signedIn)
+ throw IoTInternalError("UNAUTHORIZED error", EC_UNAUTHORIZED);
+}
+
void IoTivity::signIn(const std::string& host, const std::string& login, const std::string& password)
{
if (host.empty() || login.empty() || password.empty())
guardErrorCode(accountMgr->signUp(DEFAULT_PROVIDER, authcode, signUpCb), SIGNUP);
- condVar.wait_for(lock, std::chrono::seconds(10));
+ condVar.wait_for(lock, std::chrono::seconds(DEFAULT_TIMEOUT));
guardTimeout(signUpTimeout, SIGNUP);
guardSignErrorCode(resultCodeCb, SIGNUP);
guardErrorCode(accountMgr->signIn(oAuthCred.userId, oAuthCred.accessToken, signInCb), SIGNIN);
- condVar.wait_for(lock, std::chrono::seconds(10));
+ condVar.wait_for(lock, std::chrono::seconds(DEFAULT_TIMEOUT));
guardTimeout(signInTimeout, SIGNIN);
guardSignErrorCode(resultCodeCb, SIGNIN);
};
guardErrorCode(accountMgr->signOut(oAuthCred.accessToken, signOutCb), SIGNOUT);
- condVar.wait_for(lock, std::chrono::seconds(10));
+ condVar.wait_for(lock, std::chrono::seconds(DEFAULT_TIMEOUT));
guardTimeout(signOutTimeout, SIGNOUT);
guardSignErrorCode(resultCodeCb, SIGNOUT);
}
-void IoTivity::subscribeNotifications(NotificationCallback callback)
+void IoTivity::subscribeNotifications(NM_NotificationCb callback, void* user_data)
{
- throw IoTInternalError("subscribeNotifications() not implemented", EC_NOT_IMPLEMENTED_YET);
+ guardUnauthorized();
+
+ std::mutex mtx;
+ std::mutex curResourceLock;
+ std::unique_lock<std::mutex> lock(mtx);
+ std::condition_variable condVar;
+
+ bool findResourceTimeout = true;
+
+ std::shared_ptr<OCResource> curResource;
+
+ auto observCb = [callback, user_data](const HeaderOptions,
+ const OCRepresentation & rep,
+ const int& eCode,
+ const int& sequenceNumber)
+ {
+ string messageString = rep.getValueToString("message");
+ NM_NotificationData data
+ {
+ rep.getValue<int>("code"),
+ messageString.c_str(),
+ rep.getValue<int>("time")
+ };
+ callback(data, user_data);
+ };
+
+ auto foundCb = [&](std::shared_ptr<OCResource> resource)
+ {
+ lock_guard<std::mutex> lock(curResourceLock);
+ findResourceTimeout = false;
+ std::string resourceURI = resource->uri();
+ std::string resourceDuid = resource->sid();
+ std::stringstream searchedUri;
+ searchedUri << "/oic/route/" << resourceDuid << NOTIFICATION_URI;
+
+ //cout << searchedUri.str() << endl << flush;
+
+ if(searchedUri.str() == resourceURI && !curResource)
+ {
+ std::string resourceHost = resource->host();
+
+ curResource = resource;
+ cout << "\tFound: " << resourceURI << " "
+ << resourceHost << " " << resourceDuid << endl << flush;
+ resource->observe(ObserveType::ObserveAll, QueryParamsMap(), observCb);
+ condVar.notify_all();
+ }
+ };
+
+ auto errorCb = [&](const std::string & resourceUri, const int ecode)
+ {
+ findResourceTimeout = false;
+ cout << "Error" << resourceUri << " " << ecode << endl << flush;
+ condVar.notify_all();
+ };
+
+ guardErrorCode(OCPlatform::findResource(oAuthCred.host, NOTIF_REQUEST, CT_DEFAULT, foundCb, errorCb), NOTIF_FIND);
+
+ condVar.wait_for(lock, std::chrono::seconds(DEFAULT_TIMEOUT));
+ guardTimeout(findResourceTimeout, NOTIF_FIND);
}
void IoTivity::unsubscribeNotifications()
{
+ guardUnauthorized();
throw IoTInternalError("unsubscribeNotifications() not implemented", EC_NOT_IMPLEMENTED_YET);
}
{
return EC_NOT_IMPLEMENTED_YET;
}
+
+NM_ErrorCode NM_subscribeNotifications(NM_hContext ctx, NM_NotificationCb callback, void* user_data)
+{
+ if (ctx == nullptr) return EC_NULL_POINTER;
+ try
+ {
+ ctx->instance->subscribeNotifications(callback, user_data);
+ }
+ catch (NMexception& e)
+ {
+ LOG_E(TAG, "Subscribe notifications error: %s", e.what());
+ return (NM_ErrorCode) e.errorCode();
+ }
+ catch (std::exception& e)
+ {
+ LOG_E(TAG, "Subscribe notifications error: %s", e.what());
+ return EC_INTERNAL_ERROR;
+ }
+
+ return EC_OK;
+}
+
+void NM_unsubscribeNotifications(NM_hContext ctx)
+{
+ if (ctx == nullptr) return;
+ try
+ {
+ ctx->instance->unsubscribeNotifications();
+ }
+ catch (NMexception& e)
+ {
+ LOG_E(TAG, "Unsubscribe notifications error: %s, error code %d", e.what(), e.errorCode());
+ }
+ catch (std::exception& e)
+ {
+ LOG_E(TAG, "Unsubscribe notifications error: %s", e.what());
+ }
+}
typedef std::function<void(const std::string&, bool)> PresenceHook;
-typedef std::function<void(const std::string)> NotificationCallback;
-
/**
* @brief The OAuthCredential struct contains information about current session with cloud server. Filled after signIn().
*/
std::string getDeviceID();
/**
- * @brief subscribeNotifications subscribes to secure server notifications.
+ * @brief subscribeNotifications subscribes to secure server notifications
* Only one subscription allowed.
* @param callback method to receive notifications after subscription
+ * @param user_data pointer to the user defined data
*/
- void subscribeNotifications(NotificationCallback callback);
+ void subscribeNotifications(NM_NotificationCb callback, void* user_data);
/**
* @brief unsubscribeNotifications unsubscribes to current secure server notifications
std::string getPersistentStoragePath();
private:
+ void guardUnauthorized();
+
static const std::string DEFAULT_PROVIDER;
static const int DEFAULT_TIMEOUT;
EC_ITEM_NOT_FOUND,
EC_TIMEOUT_ERROR,
EC_IOTIVITY_ERROR,
+ EC_UNAUTHORIZED,
// ...
} NM_ErrorCode;
DeviceState state;
} NM_DeviceInfo;
+typedef struct
+{
+ int code;
+ const char* message;
+ int time;
+} NM_NotificationData;
+
#define NULL_HANDLE (void*)0
typedef struct NM_Context* NM_hContext;
typedef void (*NM_deviceEnumerationCb)(NM_hDeviceList dev_list, const char* id, void* user_data);
/**
+ * @brief Callback to subscribe on notifications from secure server
+ * @param data [in] notification details: code number, message string, time
+ */
+typedef void (*NM_NotificationCb)(NM_NotificationData data, void* user_data);
+
+/**
* @brief IoTivity initialization
* @param ctx context handle for internal data storage
* @return error code
*/
//NM_ErrorCode NM_setDevicePolicy(NM_hDeviceList dev_list, const char* dev_id, const char* policy);
+/**
+ * @brief subscribeNotifications subscribes to secure server notifications.
+ * Triggered by secure server to notify user.
+ * @param ctx context handle for internal data storage
+ * @param callback method to receive notifications after subscription
+ * @param user_data pointer to the user defined data
+ * @return error code
+ */
+NM_ErrorCode NM_subscribeNotifications(NM_hContext ctx, NM_NotificationCb callback, void* user_data);
+
+/**
+ * @brief unsubscribeNotifications unsubscribes to current secure server notifications
+ * @param ctx context handle for internal data storage
+ */
+void NM_unsubscribeNotifications(NM_hContext ctx);
+
#ifdef __cplusplus
}
#endif
+/**
+ * @brief Tests for iotivity.h API methods
+ * @date Created 12.05.2017
+ * @author Created 2017 in Samsung Ukraine R&D Center (SURC) under a contract
+ * between LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
+ * and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea).
+ * Copyright: (c) Samsung Electronics Co, Ltd 2017. All rights reserved.
+ * @author Mail to: <A HREF="mailto:a.gudz@samsung.com">Andriy Gudz, a.gudz@samsung.com</A>
+ */
#include <iostream>
#include <stdexcept>
+#include <mutex>
+#include <condition_variable>
#include <gtest/gtest.h>
std::string password("password");
std::string host("coap+tcp://106.125.46.44:5683");
- ASSERT_ANY_THROW(IoTivity::getInstance()->signIn("", login, password));
- ASSERT_ANY_THROW(IoTivity::getInstance()->signIn(host, "", password));
- ASSERT_ANY_THROW(IoTivity::getInstance()->signIn(host, login, ""));
+ auto iot = IoTivity::getInstance();
+
+ ASSERT_ANY_THROW(iot->signIn("", login, password));
+ ASSERT_ANY_THROW(iot->signIn(host, "", password));
+ ASSERT_ANY_THROW(iot->signIn(host, login, ""));
}
-static void notificationCb(std::string notifMessage) {
- cout << "notificationCb()" << endl << flush;
+static std::condition_variable notificationCV;
+static bool callbackFired = false;
+static char* callbackUserDataCheck = NULL;
+
+static void notificationCb(NM_NotificationData data, void* user_data)
+{
+ callbackFired = true;
+ callbackUserDataCheck = (char*) user_data;
+ notificationCV.notify_all();
}
/**
- * Test check correct work of IoTivity::subscribeNotifications()
+ * Test checks correct work of IoTivity::subscribeNotifications()
+ * 1. Check correct sign in
+ * 2. Call subscribe method and wait 3 sec for notification callback
+ * 3. Check correct sign out
+ * 4. Check callback was called
+ * 5. Check user data was transferd
*/
TEST(test_IoT, notificationCorrect)
{
std::string login("login");
std::string password("password");
std::string host("coap+tcp://106.125.46.44:5683");
+ char userDataCheck[] = "userDataCheck";
+
+ static std::mutex notificationMtx;
+ static std::unique_lock<std::mutex> notificationLock(notificationMtx);
+
+ auto iot = IoTivity::getInstance();
+
+ ASSERT_NO_THROW(iot->signIn(host, login, password));
+ EXPECT_NO_THROW(iot->subscribeNotifications(notificationCb, userDataCheck));
+ notificationCV.wait_for(notificationLock, std::chrono::seconds(3));
+ EXPECT_NO_THROW(iot->signOut());
- ASSERT_NO_THROW(IoTivity::getInstance()->signIn(host, login, password));
- EXPECT_ANY_THROW(IoTivity::getInstance()->subscribeNotifications(notificationCb));
- EXPECT_NO_THROW(IoTivity::getInstance()->signOut());
+ ASSERT_TRUE(callbackFired);
+ ASSERT_EQ(userDataCheck, callbackUserDataCheck);
}
/**
+/**
+ * @brief Tests for nmlib.h API methods
+ * @date Created 12.05.2017
+ * @author Created 2017 in Samsung Ukraine R&D Center (SURC) under a contract
+ * between LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
+ * and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea).
+ * Copyright: (c) Samsung Electronics Co, Ltd 2017. All rights reserved.
+ * @author Mail to: <A HREF="mailto:a.gudz@samsung.com">Andriy Gudz, a.gudz@samsung.com</A>
+ */
#include <iostream>
#include <stdexcept>
+#include <mutex>
+#include <condition_variable>
#include <gtest/gtest.h>
#include "nmlib.h"
-#include "iotivity.h"
+
+using namespace std;
/**
* Performs init, signin, sign out and cleanup
ASSERT_NO_THROW(NM_cleanup(&ctx));
}
+
+static std::condition_variable notificationCV;
+static bool callbackFired = false;
+static char* callbackUserDataCheck = NULL;
+
+static void notificationCb(NM_NotificationData data, void* user_data)
+{
+ cout << "notificationCb() " << data.code << " "
+ << data.message << " "
+ << data.time << " "
+ << endl << flush;
+ callbackFired = true;
+ callbackUserDataCheck = (char*) user_data;
+ notificationCV.notify_all();
+}
+
+/**
+ * Test checks correct work of IoTivity::subscribeNotifications()
+ * 1. Check correct sign in
+ * 2. Call subscribe method and wait no more than 3 sec for notification callback
+ * 3. Check callback was called
+ * 4. Check user data was transferd
+ */
+TEST(test_nmlibapi, notificationCorrect)
+{
+ std::string login("login");
+ std::string password("password");
+ std::string host("coap+tcp://106.125.46.44:5683");
+ char userDataCheck[] = "userDataCheck";
+
+ static std::mutex notificationMtx;
+ static std::unique_lock<std::mutex> notificationLock(notificationMtx);
+
+ NM_hContext ctx;
+ ASSERT_EQ(EC_OK, NM_init(&ctx));
+
+ /* 1. Check correct sign in */
+ ASSERT_EQ(EC_OK, NM_signIn(ctx, host.c_str(), login.c_str(), password.c_str()));
+
+ /* 2. Call subscribe method and wait no more than 3 sec for notification callback */
+ ASSERT_EQ(EC_OK, NM_subscribeNotifications(ctx, notificationCb, userDataCheck));
+ notificationCV.wait_for(notificationLock, std::chrono::seconds(3));
+ NM_signOut(ctx);
+
+ /* 3. Check callback was called */
+ ASSERT_TRUE(callbackFired);
+
+ /* 4. Check user data was transferd */
+ ASSERT_EQ(userDataCheck, callbackUserDataCheck);
+}