Add MDGManager class to replace with Iotivity
authorSangyoon Jang <jeremy.jang@samsung.com>
Tue, 12 Jun 2018 01:20:55 +0000 (10:20 +0900)
committer장상윤/Tizen Platform Lab(SR)/Engineer/삼성전자 <jeremy.jang@samsung.com>
Fri, 22 Jun 2018 07:12:23 +0000 (16:12 +0900)
MDGManager class is wrapper class using mdg APIs.
This class replace Iotivity class.

Change-Id: I30a2c980e82f0be73caecd468726571d8da5841a
Signed-off-by: Sangyoon Jang <jeremy.jang@samsung.com>
14 files changed:
CMakeLists.txt
packaging/capmgr.spec
src/capmgr/CMakeLists.txt
src/capmgr/capmgr.cc
src/capmgr/main.cc
src/common/CMakeLists.txt
src/common/capability_manager.cc
src/common/dbus_service.cc
src/common/dbus_service.h
src/common/iotivity.cc [deleted file]
src/common/iotivity.h [deleted file]
src/common/mdg_manager.cc [new file with mode: 0644]
src/common/mdg_manager.h [new file with mode: 0644]
src/common/utils/glist_range.h [new file with mode: 0644]

index 369c043448a6025e189210c004b4fb45b0336fd9..a73efa4a0dd592250f6e7d18f06a202290b3aa93 100644 (file)
@@ -30,8 +30,8 @@ PKG_CHECK_MODULES(BUNDLE_DEPS REQUIRED bundle)
 PKG_CHECK_MODULES(DLOG_DEPS REQUIRED dlog)
 PKG_CHECK_MODULES(GIO_DEPS REQUIRED gio-2.0)
 PKG_CHECK_MODULES(GLIB_DEPS REQUIRED glib-2.0)
-PKG_CHECK_MODULES(IOTIVITY_DEPS REQUIRED iotivity)
 PKG_CHECK_MODULES(JSONCPP_DEPS REQUIRED jsoncpp)
+PKG_CHECK_MODULES(MDG_DEPS REQUIRED capi-network-mdg)
 PKG_CHECK_MODULES(PKGMGR_DEPS REQUIRED pkgmgr)
 PKG_CHECK_MODULES(PKGMGR_INFO_DEPS REQUIRED pkgmgr-info)
 PKG_CHECK_MODULES(SQLITE_DEPS REQUIRED sqlite3)
@@ -39,7 +39,5 @@ PKG_CHECK_MODULES(SQLITE_DEPS REQUIRED sqlite3)
 FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options)
 FIND_PACKAGE(GTest REQUIRED)
 
-INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/oic_svr_db_capmgr.dat DESTINATION ${SVR_DB_DIR})
-
 ADD_SUBDIRECTORY(src)
 ADD_SUBDIRECTORY(tools)
index 316f21fcd4ab66561c540b0384b5d4bc5eecde59..17bd10a9821c45465a64e39c97090b43353aa0ea 100644 (file)
@@ -1,6 +1,3 @@
-%define svr_db_dir %{TZ_SYS_GLOBALUSER_DATA}/capmgr
-%define svr_db_path %{svr_db_dir}/oic_svr_db_capmgr.dat
-
 Name:       capmgr
 Summary:    Capability Manager
 Version:    0.0.1
@@ -21,9 +18,9 @@ BuildRequires:  pkgconfig(bundle)
 BuildRequires:  pkgconfig(dlog)
 BuildRequires:  pkgconfig(gio-2.0)
 BuildRequires:  pkgconfig(glib-2.0)
-BuildRequires:  pkgconfig(iotivity)
 BuildRequires:  pkgconfig(jsoncpp)
 BuildRequires:  pkgconfig(libtzplatform-config)
+BuildRequires:  pkgconfig(capi-network-mdg)
 BuildRequires:  pkgconfig(pkgmgr)
 BuildRequires:  pkgconfig(pkgmgr-info)
 BuildRequires:  pkgconfig(sqlite3)
@@ -44,9 +41,7 @@ cp %{SOURCE1001} .
 
 %build
 MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
-%cmake . -DSVR_DB_DIR=%{svr_db_dir} \
-         -DSVR_DB_PATH=%{svr_db_path} \
-         -DUNITDIR=%{_unitdir} \
+%cmake . -DUNITDIR=%{_unitdir} \
          -DFULLVER=%{version} \
          -DMAJORVER=${MAJORVER}
 
@@ -69,8 +64,6 @@ ln -sf ../%{name}.service %{buildroot}%{_unitdir}/multi-user.target.wants/
 /sbin/ldconfig
 systemctl daemon-reload
 
-chsmack -a System %{svr_db_path}
-
 %files
 %manifest %{name}.manifest
 %license LICENSE
@@ -82,10 +75,6 @@ chsmack -a System %{svr_db_path}
 %{_unitdir}/%{name}.service
 %{_unitdir}/multi-user.target.wants/%{name}.service
 
-%defattr(-,app_fw,app_fw,-)
-%{svr_db_dir}
-%{svr_db_path}
-
 %files tests
 %{_bindir}/capmgr-ut/*
 /opt/share/capmgr-ut/*
index 3b397eb869233fca09ccd9a3f56a09a7bfa8d504..ea2846fa092d3d6ac3ae79c547a6266e8ea6cc4d 100644 (file)
@@ -6,7 +6,6 @@ ADD_EXECUTABLE(${TARGET_CAPMGR} ${CAPMGR_SRCS})
 APPLY_PKG_CONFIG(${TARGET_CAPMGR} PUBLIC
   DLOG_DEPS
   GLIB_DEPS
-  IOTIVITY_DEPS
 )
 
 TARGET_LINK_LIBRARIES(${TARGET_CAPMGR} PUBLIC ${TARGET_LIB_COMMON})
index 018f9d5276b4908647e0585f541397cebaf6c1b3..9d0fc32da4b79f121b6c0118006870cd3733f6db 100644 (file)
@@ -69,6 +69,7 @@ Capmgr::~Capmgr() {
 bool Capmgr::Initialize() {
   cm_->LoadCapabilities();
   connmgr_->RegisterEndpoint();
+  connmgr_->FindDevices();
 
   DBusService::RegisterMethodHandler("DiscoverUnownedDevices", std::bind(
       &ConnectionManager::FindDevices, connmgr_.get()));
index 3d2a04dfcf8e6eea2d05b0e3eebcca3709a04c63..0f316d757682dc9681b5348e31dd0ee27397611e 100644 (file)
@@ -2,13 +2,11 @@
 // Use of this source code is governed by a apache 2.0 license that can be
 // found in the LICENSE file.
 
-// iotivity headers should be included before boost headers...
-// this makes compilation warning. (redefinition)
-#include "common/iotivity.h"
 #include "common/capability_manager.h"
 #include "capmgr/capmgr.h"
 #include "common/connection_manager.h"
 #include "common/dbus_service.h"
+#include "common/mdg_manager.h"
 #include "common/package_event_listener.h"
 #include "common/utils/logging.h"
 
@@ -17,7 +15,7 @@ int main(int argc, char* argv[]) {
   pkgmgr.SubscribePackageEvent();
 
   capmgr::CapabilityManager* cm = new capmgr::CapabilityManager();
-  capmgr::ConnectionManager* connmgr = new capmgr::Iotivity(cm);
+  capmgr::ConnectionManager* connmgr = new capmgr::MDGManager(cm);
   capmgr::DBusService* dbus = new capmgr::DBusService();
   capmgr::Capmgr capmgr(cm, connmgr, dbus);
   if (!capmgr.Initialize()) {
index db038cacfef3094ff7c82083c760d97ae9f5f18f..877d72c5350cb324025d8ddeaaadb530df4d15ab 100644 (file)
@@ -13,17 +13,13 @@ APPLY_PKG_CONFIG(${TARGET_LIB_COMMON} PUBLIC
   DLOG_DEPS
   GIO_DEPS
   GLIB_DEPS
-  IOTIVITY_DEPS
   JSONCPP_DEPS
+  MDG_DEPS
   PKGMGR_DEPS
   PKGMGR_INFO_DEPS
   SQLITE_DEPS
 )
 
-ADD_DEFINITIONS("-DSVR_DB_DIR=\"${SVR_DB_DIR}\"")
-ADD_DEFINITIONS("-DSVR_DB_PATH=\"${SVR_DB_PATH}\"")
-ADD_DEFINITIONS("-DPM_DB_PATH=\"${SVR_DB_DIR}/pdm.db\"")
-
 SET_TARGET_PROPERTIES(${TARGET_LIB_COMMON} PROPERTIES VERSION ${FULLVER})
 SET_TARGET_PROPERTIES(${TARGET_LIB_COMMON} PROPERTIES SOVERSION ${MAJORVER})
 
index daeda95f8f0d9769bddc579db293564996f920be..ecabc5e3cf5bb18271f6113b65e05973d9183ec6 100644 (file)
@@ -132,6 +132,7 @@ bool CapabilityManager::LoadCapabilities() {
 std::string CapabilityManager::PackCapabilities() {
   Json::Value root;
   Json::Value caps;
+  LOG(INFO) << "Pack " << list_.size() << " capabilities";
   for (const auto& cap : list_)
     caps.append(cap.Serialize());
   root["capabilities"] = caps;
@@ -160,6 +161,8 @@ std::vector<Capability> CapabilityManager::UnpackCapabilities(
     list.emplace_back(caps[i].asString());
   }
 
+  LOG(INFO) << "Unpacked " << list.size() << " capabilities";
+
   return list;
 }
 
index d3334d9fa614e93e2ed7d22457a559b9cf61ca67..2deeeb4c75bb77b215dffe78aacb844cc342960d 100644 (file)
@@ -28,7 +28,9 @@ const char kDBusInstropectionXml[] =
   "      <arg type='v' name='result' direction='out'/>"
   "    </method>"
   "    <method name='SendRemoteAppControl'>"
-  "      <arg type='(sss)' name='appcontrol' direction='in'/>"
+  "      <arg type='s' name='appcontrol' direction='in'/>"
+  "      <arg type='s' name='appid' direction='in'/>"
+  "      <arg type='s' name='pkgid' direction='in'/>"
   "      <arg type='b' name='result' direction='out'/>"
   "    </method>"
   "  </interface>"
@@ -101,7 +103,7 @@ bool DBusService::HandleSendRemoteAppControl(GVariant* params,
   gchar* name;
   gchar* appid;
   gchar* pkgid;
-  g_variant_get(params, "((sss))", &name, &appid, &pkgid);
+  g_variant_get(params, "(sss)", &name, &appid, &pkgid);
 
   Capability cap(name, pkgid, appid);
   LOG(INFO) << "From: " << cap.name();
index 87bc5aa3e750cc809aa67fbc3a88b8c63161959b..c934ee73bfe093c699c03bcf4f412964a5dc54dd 100644 (file)
@@ -38,6 +38,7 @@ class DBusService {
     boost::signals2::signal<bool(Capability*, AppControlHandler)>
         send_app_control_event;
     boost::signals2::signal<void(GVariant**)> get_remote_caps_event;
+    boost::signals2::signal<void(char* data)> send_data_event;
   };
 
   static DBusMethodHandler& EventHandler() {
diff --git a/src/common/iotivity.cc b/src/common/iotivity.cc
deleted file mode 100644 (file)
index 14529e4..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
-// Use of this source code is governed by a apache 2.0 license that can be
-// found in the LICENSE file.
-
-#include "common/iotivity.h"
-
-#include <octypes.h>
-#include <pmtypes.h>
-#include <OCPlatform.h>
-
-#include <boost/algorithm/string/replace.hpp>
-#include <OCProvisioningManager.hpp>
-
-#include <functional>
-#include <iostream>
-#include <string>
-#include <vector>
-
-#include "common/capability.h"
-#include "common/capability_manager.h"
-#include "common/appcontrol_manager.h"
-#include "common/utils/logging.h"
-
-namespace {
-
-const int kDiscoverTimeoutSec = 5;
-const int kUUIDLength = UUID_LENGTH;
-const char kResourceTypeName[] = "capmgr.capabilities";
-
-FILE* ServerFopen(const char* /* unused */, const char* mode) {
-  return fopen(SVR_DB_PATH, mode);
-}
-
-std::string ConvertUUIDtoString(const OicUuid_t& uuid) {
-  std::ostringstream oss;
-  for (int i = 0; i < kUUIDLength; i++)
-    oss << uuid.id[i];
-  return oss.str();
-}
-
-void OtmEventCb(void* /* ctx */, const char* addr, uint16_t port,
-    const char* owner_id, OCOtmEvent_t event) {
-  LOG(INFO) << "Get OTM Event";
-  LOG(INFO) << "Addr: " << addr;
-  LOG(INFO) << "owner_id: " << owner_id;
-  switch (event) {
-    case OC_OTM_READY:
-      LOG(INFO) << "OC_OTM_READY";
-      break;
-    case OC_OTM_STARTED:
-      LOG(INFO) << "OC_OTM_STARTED";
-      break;
-    case OC_OTM_DONE:
-      LOG(INFO) << "OC_OTM_DONE";
-      break;
-    case OC_OTM_ERROR:
-      LOG(INFO) << "OC_OTM_ERROR";
-      break;
-    default:
-      LOG(ERROR) << "Unknown OTM event";
-      break;
-  }
-}
-
-}  // namespace
-
-namespace capmgr {
-
-Iotivity::Iotivity(CapabilityManager* capmgr) : ConnectionManager(capmgr) {
-  OCSetOtmEventHandler(nullptr, OtmEventCb);
-
-  ps_ = {
-    ServerFopen, fread, fwrite, fclose, unlink, nullptr, nullptr
-  };
-
-  OC::PlatformConfig config = OC::PlatformConfig {
-    OC::ServiceType::InProc,
-    OC::ModeType::Both,
-    "0.0.0.0",
-    0,
-    OC::QualityOfService::LowQos,
-    &ps_
-  };
-
-  OC::OCPlatform::Configure(config);
-/*
-  OCStackResult result = SetPlatformInfo(kPlatformId, kManufactureName,
-      kManufacturerLink, kModelNumber, kDateOfManufacture, kPlatformVersion,
-      kOperatingSystemVersion, kHardwareVersion, kFirmwareVersion, kSupportLink,
-      kSystemTime);
-  result = OCPlatform::registerPlatformInfo(platformInfo);
-*/
-}
-Iotivity::~Iotivity() {
-}
-
-void Iotivity::FindDevices() {
-  DiscoverUnownedDevices();
-}
-
-void Iotivity::RegisterEndpoint() {
-  RegisterResource();
-}
-
-void Iotivity::ExchangeCapabilities() {
-  for (const auto& it : resource_list_)
-    GetResource(it.second);
-}
-
-bool Iotivity::SendCapability(Capability* cap,
-    std::function<void(Capability, int)> reply) {
-  PutResource(cap, reply);
-  return 0;
-}
-
-void Iotivity::PutResource(Capability* cap,
-    std::function<void(Capability, int)> putCallback) {
-  LOG(INFO) << "Put Resource";
-  for (const auto& it : resource_list_) {
-    std::shared_ptr<OC::OCResource> resource;
-    resource = it.second;
-    OC::OCRepresentation rep;
-
-    LOG(INFO) << "Putting.." << resource->uri();
-    rep.setValue("capability", cap->Serialize());
-
-    Capability dup(cap->name(), cap->pkgid(), cap->appid());
-    OC::QueryParamsMap queryParamsMap;
-    OCStackResult res = resource->put(rep, queryParamsMap,
-        [=](const OC::HeaderOptions& opts, const OC::OCRepresentation& rep,
-            const int ec) {
-          LOG(INFO) << "From: " << rep.getUri() << " of " << rep.getHost();
-          LOG(INFO) << "PUT RESULT data: " << ec;
-
-          putCallback(dup, ec);
-        });
-
-    LOG(INFO) << "res: " << res;
-  }
-}
-
-void Iotivity::RegisterResource() {
-  std::string uri = "/capmgr/capabilities";
-  uint8_t property = OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE;
-
-  OCStackResult result = OC::OCPlatform::registerResource(resource_,
-      uri, kResourceTypeName, OC::DEFAULT_INTERFACE,
-      std::bind(&Iotivity::EntityCb, this, std::placeholders::_1),
-      property);
-  if (result != OC_STACK_OK)
-    LOG(ERROR) << "OCPlatform::registerResource() failed: " << result;
-
-  LOG(INFO) << "Registered as: " << uri;
-}
-
-void Iotivity::FindResource(const std::string& addr) {
-  OCStackResult result = OC::OCPlatform::findResource(
-      !addr.empty() ? addr : "", OC_RSRVD_WELL_KNOWN_URI,
-      CT_DEFAULT, std::bind(&Iotivity::FindCb, this, std::placeholders::_1));
-  if (result != OC_STACK_OK)
-    LOG(ERROR) << "OCPlatform::findResource() failed: " << result;
-}
-
-void Iotivity::DiscoverUnownedDevices() {
-  if (OC::OCSecure::provisionInit(PM_DB_PATH) != OC_STACK_OK)
-    LOG(ERROR) << "provisionInit() failed!";
-
-  unowned_dev_list_.clear();
-  OCStackResult result =
-      OC::OCSecure::discoverUnownedDevices(kDiscoverTimeoutSec,
-          unowned_dev_list_);
-
-  if (result != OC_STACK_OK)
-    LOG(ERROR) << "discoverUnownedDevices() failed: " << result;
-  else
-    LOG(INFO) << "Discovered " << unowned_dev_list_.size()
-              << " unowned devices";
-
-  OwnershipTransfer();
-}
-
-void Iotivity::OwnershipTransfer() {
-  for (const auto& sec_rsc : unowned_dev_list_) {
-    // get IPv6 address
-    std::string devaddr = sec_rsc->getDevAddr();
-    // percent-encoding
-    boost::replace_all(devaddr, "%", "%25");
-    std::ostringstream oss;
-    oss << "coaps://[" << devaddr << "]:" << sec_rsc->getDevPtr()->securePort;
-    devaddr = oss.str();
-
-    LOG(INFO) << "Do ownership transfer. Address: " << devaddr << ", DeviceID: "
-              << sec_rsc->getDeviceID();
-
-    sec_rsc->doOwnershipTransfer(
-        [this, devaddr](OC::PMResultList_t* result, int hasError) {
-          if (hasError) {
-            LOG(ERROR) << "Failed to ownership transfer :: " << hasError;
-            return;
-          }
-          LOG(INFO) << "Ownership transferred: "
-                    << ConvertUUIDtoString(result->at(0).deviceId);
-          FindResource(devaddr);
-        });
-  }
-}
-
-void Iotivity::GetResource(std::shared_ptr<OC::OCResource> resource) {
-  std::string hostaddr = resource->host();
-  // empty QueryParams
-  OC::QueryParamsMap qmap;
-  resource->get(qmap,
-      [this, hostaddr](const OC::HeaderOptions& opts,
-          const OC::OCRepresentation& rep, const int ec) {
-        if (ec != OC_STACK_OK) {
-          LOG(ERROR) << "GET error";
-          return;
-        }
-
-        std::string data;
-        rep.getValue("data", data);
-
-        LOG(INFO) << "From: " << rep.getUri() << " of " << rep.getHost();
-        LOG(INFO) << "Get RESULT data: " << data;
-
-        // for debug
-        std::vector<Capability> caps = capmgr_->UnpackCapabilities(data);
-        for (const auto& cap : caps)
-          LOG(INFO) << "1: " << cap.name() << ", 2: " << cap.pkgid()
-                    << ", 3: " << cap.appid();
-      });
-}
-
-OCEntityHandlerResult Iotivity::EntityCb(
-    std::shared_ptr<OC::OCResourceRequest> request) {
-  LOG(DEBUG) << "entity cb";
-  if (!request) {
-    LOG(ERROR) << "Invalid OC request";
-    return OC_EH_ERROR;
-  }
-
-  std::string req_type = request->getRequestType();
-  if (req_type == "GET") {
-    LOG(WARNING) << "The request is GET";
-
-    // OC::QueryParamsMap qmap = request->getQueryParameters();
-
-    OC::OCRepresentation rep;
-    rep.setUri("/capmgr/capabilities");
-    std::string capabilities = capmgr_->PackCapabilities();
-    rep.setValue("data", capabilities);
-
-    auto response = std::make_shared<OC::OCResourceResponse>();
-    response->setErrorCode(200);  // ??
-    response->setResponseResult(OC_EH_OK);
-    response->setResourceRepresentation(rep);
-    response->setRequestHandle(request->getRequestHandle());
-    response->setResourceHandle(request->getResourceHandle());
-
-    OCStackResult result = OC::OCPlatform::sendResponse(response);
-    if (result != OC_STACK_OK)
-      LOG(ERROR) << "OCPlatform::sendResponse() error: " << result;
-    else
-      LOG(INFO) << "Sending response done";
-
-    return OC_EH_OK;
-  }
-
-  if (req_type == "PUT") {
-    LOG(WARNING) << "The request is PUT";
-    OC::OCRepresentation rep = request->getResourceRepresentation();
-    int ret;
-
-    std::string cap_data;
-    rep.getValue("capability", cap_data);
-    LOG(INFO) << "capability : " << cap_data;
-
-    Capability cap(cap_data);
-
-    ret = AppControlManager::LaunchApplication(cap);
-    if (ret != 0) {
-      return OC_EH_ERROR;
-    }
-
-    return OC_EH_OK;
-  }
-
-  return OC_EH_OK;
-}
-
-void Iotivity::FindCb(std::shared_ptr<OC::OCResource> resource) {
-  if (!resource) {
-    LOG(ERROR) << "Invalid resource discovered";
-    return;
-  }
-
-  if (resource_list_.find(resource->uniqueIdentifier()) !=
-      resource_list_.end()) {
-    LOG(DEBUG) << "Already discovered. Skip this resource";
-    return;
-  }
-
-  LOG(INFO) << "Resource discovered: " << resource->uri()
-            << ", id: " << resource->uniqueIdentifier()
-            << ", host: " << resource->host();
-  if (resource->uri().find("capmgr") != std::string::npos) {
-    LOG(INFO) << "Found capability resource";
-    resource_list_[resource->uniqueIdentifier()] = resource;
-    GetResource(resource);
-  }
-}
-
-}  // namespace capmgr
diff --git a/src/common/iotivity.h b/src/common/iotivity.h
deleted file mode 100644 (file)
index 00e2b7f..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
-// Use of this source code is governed by a apache 2.0 license that can be
-// found in the LICENSE file.
-
-#ifndef COMMON_IOTIVITY_H_
-#define COMMON_IOTIVITY_H_
-
-#include <octypes.h>
-#include <pmtypes.h>
-#include <OCApi.h>
-#include <OCPlatform.h>
-
-#include <OCProvisioningManager.hpp>
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "common/connection_manager.h"
-
-namespace capmgr {
-
-class CapabilityManager;
-
-class Iotivity : public ConnectionManager {
- public:
-  explicit Iotivity(CapabilityManager* capmgr);
-  ~Iotivity();
-
-  void FindDevices() override;
-  void RegisterEndpoint() override;
-  void ExchangeCapabilities() override;
-  bool SendCapability(
-      Capability* cap, std::function<void(Capability, int)> reply) override;
-
- private:
-  void RegisterResource();
-  void FindResource(const std::string& addr);
-  void PutResource(
-      Capability* cap, std::function<void(Capability, int)> putCallback);
-  void DiscoverUnownedDevices();
-  void OwnershipTransfer();
-  void GetResource(std::shared_ptr<OC::OCResource> resource);
-  OCEntityHandlerResult EntityCb(
-      std::shared_ptr<OC::OCResourceRequest> request);
-  void FindCb(std::shared_ptr<OC::OCResource> resource);
-
-  OCPersistentStorage ps_;
-  OCResourceHandle resource_;
-  std::map<OC::OCResourceIdentifier, std::shared_ptr<OC::OCResource>>
-      resource_list_;
-  OC::DeviceList_t unowned_dev_list_;
-};
-
-}  // namespace capmgr
-
-#endif  // COMMON_IOTIVITY_H_
diff --git a/src/common/mdg_manager.cc b/src/common/mdg_manager.cc
new file mode 100644 (file)
index 0000000..c867900
--- /dev/null
@@ -0,0 +1,348 @@
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#include "common/mdg_manager.h"
+
+#include <glib.h>
+#include <mdg.h>
+#include <mdg_internal.h>
+
+#include <cstring>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "common/appcontrol_manager.h"
+#include "common/capability.h"
+#include "common/capability_manager.h"
+#include "common/utils/glist_range.h"
+#include "common/utils/logging.h"
+
+namespace {
+
+const int kRequestTimeout = 5;
+const char kGroupName[] = "capmgrgroup";
+const char kPIN[] = "12341234";
+const std::map<int, std::string> kMDGErrorString = {
+  {MDG_ERROR_NONE, "MDG_ERROR_NONE"},
+  {MDG_ERROR_IO_ERROR, "MDG_ERROR_IO_ERROR"},
+  {MDG_ERROR_INVALID_PARAMETER, "MDG_ERROR_INVALID_PARAMETER"},
+  {MDG_ERROR_OUT_OF_MEMORY, "MDG_ERROR_OUT_OF_MEMORY"},
+  {MDG_ERROR_PERMISSION_DENIED, "MDG_ERROR_PERMISSION_DENIED"},
+  {MDG_ERROR_NOT_SUPPORTED, "MDG_ERROR_NOT_SUPPORTED"},
+  {MDG_ERROR_NO_DATA, "MDG_ERROR_NO_DATA"},
+  {MDG_ERROR_OPERATION_FAILED, "MDG_ERROR_OPERATION_FAILED"},
+  {MDG_ERROR_ALREADY_REGISTERED, "MDG_ERROR_ALREADY_REGISTERED"},
+  {MDG_ERROR_IN_PROGRESS, "MDG_ERROR_IN_PROGRESS"},
+  {MDG_ERROR_COMM_ERROR, "MDG_ERROR_COMM_ERROR"},
+  {MDG_ERROR_RX, "MDG_ERROR_RX"},
+  {MDG_ERROR_TX, "MDG_ERROR_TX"},
+  {MDG_ERROR_PLUGIN_FAIL, "MDG_ERROR_PLUGIN_FAIL"},
+  {MDG_ERROR_ALREADY_IN_PROGRESS, "MDG_ERROR_ALREADY_IN_PROGRESS"},
+  {MDG_ERROR_NOT_STARTED, "MDG_ERROR_NOT_STARTED"},
+  {MDG_ERROR_ALREADY_INITIALIZED, "MDG_ERROR_ALREADY_INITIALIZED"},
+};
+const char kSendDataCmd[] = "MDGD_REQ_SEND_DATA";
+
+std::string MDGErrorToString(int error) {
+  auto it = kMDGErrorString.find(error);
+  if (it == kMDGErrorString.end())
+    return "MDG_ERROR_UNKNOWN";
+  else
+    return it->second;
+}
+
+void SendDataFinishCb(int result, char *resp_data, void* user_data) {
+  LOG(INFO) << "SendDataFinishCb called."
+            << "result: " << result
+            << ", resp_data: " << resp_data;
+}
+
+}  // namespace
+
+namespace capmgr {
+
+MDGManager::MDGManager(CapabilityManager* capmgr)
+  : ConnectionManager(capmgr), mdg_handle_(nullptr), device_list_(nullptr),
+    group_list_(nullptr) {
+  if (!Initialize())
+    LOG(ERROR) << "Failed to initialize";
+}
+
+MDGManager::~MDGManager() {}
+
+bool MDGManager::Initialize() {
+  int ret = mdg_initialize(&mdg_handle_);
+  if (ret != MDG_ERROR_NONE) {
+    LOG(ERROR) << "Failed to initialize mdg: " << MDGErrorToString(ret);
+    return false;
+  }
+
+  ret = mdg_request_result_callback(mdg_handle_, &MDGManager::RequestCb, this);
+  if (ret != MDG_ERROR_NONE) {
+    LOG(ERROR) << "Failed to set request result callback: "
+               << MDGErrorToString(ret);
+    return false;
+  }
+
+  ret = mdg_device_monitor_start(mdg_handle_, &MDGManager::DeviceMonitorCb,
+      this);
+  if (ret != MDG_ERROR_NONE) {
+    LOG(ERROR) << "Failed to start device monitoring: "
+               << MDGErrorToString(ret);
+    return false;
+  }
+
+  return true;
+}
+
+void MDGManager::RequestCb(char* cmd, char* device_id, unsigned char* arg,
+    int len, int ret, void* user_data) {
+  LOG(INFO) << "RequestCb called. "
+            << "cmd: " << cmd
+            << ", device_id: " << device_id
+            << ", ret: " << ret;
+
+  MDGManager* mdgmgr = static_cast<MDGManager*>(user_data);
+  if (!strcmp(cmd, kSendDataCmd)) {
+    Command cmd;
+    memcpy(&cmd, arg, sizeof(unsigned char));
+    unsigned char* p = arg + sizeof(unsigned char);
+    if (cmd == Command::EXCHANGE_CAPS) {
+      std::string caps_str = std::string(reinterpret_cast<char*>(p));
+      std::vector<Capability> caps =
+          mdgmgr->capmgr_->UnpackCapabilities(caps_str);
+      LOG(INFO) << "Received " << caps.size() << " capabilities from device "
+                << device_id;
+    } else if (cmd == Command::SEND_CAP) {
+      std::string cap_str = std::string(reinterpret_cast<char*>(p));
+      Capability cap(cap_str);
+      int r = AppControlManager::LaunchApplication(cap);
+      if (r != 0)
+        LOG(ERROR) << "Failed to launch application: " << ret;
+    }
+  }
+}
+
+void MDGManager::DeviceMonitorCb(char* uuid, char* group_name,
+    mdg_device_status_e status, void* user_data) {
+  LOG(INFO) << "Device monitored! uuid: " << uuid
+            << ", group_name: " << group_name
+            << ", status: " << status;
+}
+
+bool MDGManager::GroupFoundCb(mdg_group_type_e type, mdg_group_h group,
+    void* user_data) {
+  char* group_name;
+  int ret = mdg_group_info_get_name(group, &group_name);
+  if (ret != MDG_ERROR_NONE) {
+    LOG(ERROR) << "Failed to get group name: " << MDGErrorToString(ret);
+    return false;
+  }
+  char* group_addr;
+  ret = mdg_group_info_get_host_addr(group, &group_addr);
+  if (ret != MDG_ERROR_NONE) {
+    LOG(ERROR) << "Failed to get group host addr: " << MDGErrorToString(ret);
+    free(group_name);
+    return false;
+  }
+
+  if (type == MDG_GROUP_TYPE_MINE)
+    LOG(INFO) << "Found group type MINE: " << group_name;
+  else
+    LOG(INFO) << "Found group type REMOTE: " << group_name
+              << " (" << group_addr << ")";
+
+  // need to check dup;
+  MDGManager* mdgmgr = static_cast<MDGManager*>(user_data);
+  mdgmgr->group_list_ = g_list_append(mdgmgr->group_list_, group);
+
+  free(group_addr);
+  free(group_name);
+
+  return true;
+}
+
+void MDGManager::GroupFinishCb(int result, void* user_data) {
+  LOG(INFO) << "Find group finished: " << result;
+  int ret;
+  MDGManager* mdgmgr = static_cast<MDGManager*>(user_data);
+  // TODO(jeremy.jang): too complicated. need to refactor.
+  for (auto& group : GListRange<mdg_group_h>(mdgmgr->group_list_)) {
+    char* group_name;
+    ret = mdg_group_info_get_name(group, &group_name);
+    if (ret != MDG_ERROR_NONE)
+      continue;
+    if (strcmp(group_name, kGroupName)) {
+      free(group_name);
+      continue;
+    }
+
+    mdg_group_type_e group_type;
+    ret = mdg_group_info_get_type(group, &group_type);
+    if (ret != MDG_ERROR_NONE)
+      continue;
+    // if group is mine, we don't need to join
+    if (group_type == MDG_GROUP_TYPE_MINE) {
+      LOG(INFO) << "Found my group. I'm the owner device";
+      return;
+    }
+
+    char* group_addr;
+    ret = mdg_group_info_get_host_addr(group, &group_addr);
+    if (ret != MDG_ERROR_NONE) {
+      free(group_name);
+      continue;
+    }
+    // request join group (request invite)
+    mdg_device_h owner_device = nullptr;
+    for (auto& device : GListRange<mdg_device_h>(mdgmgr->device_list_)) {
+      char* device_ip;
+      int ret = mdg_device_info_get_ip(device, &device_ip);
+      if (ret != MDG_ERROR_NONE)
+        continue;
+      // request to group owner only
+      // to compare ipv6 address only, discard first 8 chars of gruop_addr:
+      // format of group_addr: coap://[fe80::ae5a:14ff:fe24:b84e%25wlan0]:38720
+      if (!strncmp(group_addr + 8, device_ip, 25)) {
+        owner_device = device;
+        free(device_ip);
+        break;
+      }
+      free(device_ip);
+    }
+    free(group_addr);
+
+    if (!owner_device) {
+      LOG(ERROR) << "Cannot request invite. Cannot find proper device";
+      return;
+    }
+
+    ret = mdg_request_invite_device(mdgmgr->mdg_handle_, group, owner_device,
+        const_cast<char*>(kPIN), nullptr, nullptr);
+    if (ret == MDG_ERROR_NONE) {
+      LOG(INFO) << "Request to owner device to joining group";
+      return;
+    }
+  }
+
+  LOG(INFO) << "Group not found. Create one";
+  ret = mdg_group_create(mdgmgr->mdg_handle_, const_cast<char*>(kGroupName));
+  if (ret != MDG_ERROR_NONE)
+    LOG(ERROR) << "Failed to create group: " << ret;
+}
+
+bool MDGManager::DeviceFoundCb(mdg_device_h device, void* user_data) {
+  mdg_device_type_e device_type;
+  char* device_id;
+  char* device_ip;
+  char* model_name;
+
+  int ret = mdg_device_info_get_device_type(device, &device_type);
+  if (ret != MDG_ERROR_NONE) {
+    LOG(ERROR) << "Failed to get device id: " << MDGErrorToString(ret);
+    return true;
+  }
+
+  ret = mdg_device_info_get_device_id(device, &device_id);
+  if (ret != MDG_ERROR_NONE) {
+    LOG(ERROR) << "Failed to get device id: " << MDGErrorToString(ret);
+    return true;
+  }
+
+  ret = mdg_device_info_get_ip(device, &device_ip);
+  if (ret != MDG_ERROR_NONE) {
+    LOG(ERROR) << "Failed to get device id: " << MDGErrorToString(ret);
+    free(device_id);
+    return true;
+  }
+
+  ret = mdg_device_info_get_model_name(device, &model_name);
+  if (ret != MDG_ERROR_NONE) {
+    LOG(ERROR) << "Failed to get device id: " << MDGErrorToString(ret);
+    free(device_ip);
+    free(device_id);
+    return true;
+  }
+
+  LOG(INFO) << "Found device. "
+            << "device_id: " << device_id
+            << ", device_ip: " << device_ip
+            << ", model_name: " << model_name;
+
+  // need to check dup;
+  MDGManager* mdgmgr = static_cast<MDGManager*>(user_data);
+  mdgmgr->device_list_ = g_list_append(mdgmgr->device_list_, device);
+
+  free(model_name);
+  free(device_ip);
+  free(device_id);
+
+  return true;
+}
+
+void MDGManager::DeviceFinishCb(int result, void* user_data) {
+  LOG(INFO) << "Find device finished: " << result;
+  MDGManager* mdgmgr = static_cast<MDGManager*>(user_data);
+  mdgmgr->CreateOrJoinGroup();
+}
+
+bool MDGManager::CreateOrJoinGroup() {
+  int ret = mdg_group_find(mdg_handle_, kRequestTimeout,
+      &MDGManager::GroupFoundCb, &MDGManager::GroupFinishCb, this);
+  if (ret != MDG_ERROR_NONE) {
+    LOG(ERROR) << "Failed to find group: " << MDGErrorToString(ret);
+    return false;
+  }
+
+  return true;
+}
+
+bool MDGManager::SendData(Command cmd, const std::string& data) {
+  if (!g_list_length(device_list_)) {
+    LOG(ERROR) << "No device in list!";
+    return false;
+  }
+
+  size_t datasize = sizeof(Command) + data.size();
+  unsigned char* buf = new unsigned char[datasize];
+  unsigned char* p = buf;
+
+  memcpy(p, &cmd, sizeof(Command));
+  p = p + sizeof(Command);
+  memcpy(p, data.c_str(), data.size());
+  for (auto& device : GListRange<mdg_device_h>(device_list_)) {
+    int ret = mdg_device_send_data(mdg_handle_, device,
+        buf, datasize, SendDataFinishCb, this);
+    if (ret != MDG_ERROR_NONE)
+      LOG(ERROR) << "Failed to send data: " << MDGErrorToString(ret);
+  }
+
+  delete buf;
+
+  return true;
+}
+
+void MDGManager::FindDevices() {
+  int ret = mdg_device_find(mdg_handle_, kRequestTimeout,
+      &MDGManager::DeviceFoundCb, &MDGManager::DeviceFinishCb, this);
+  if (ret != MDG_ERROR_NONE)
+    LOG(ERROR) << "Failed to find device: " << MDGErrorToString(ret);
+}
+
+void MDGManager::RegisterEndpoint() {
+}
+
+void MDGManager::ExchangeCapabilities() {
+  std::string caps = capmgr_->PackCapabilities();
+  SendData(Command::EXCHANGE_CAPS, caps);
+}
+
+bool MDGManager::SendCapability(Capability* cap,
+    std::function<void(Capability, int)> reply) {
+  std::string cap_str = cap->Serialize();
+  return SendData(Command::SEND_CAP, cap_str);
+}
+
+}  // namespace capmgr
diff --git a/src/common/mdg_manager.h b/src/common/mdg_manager.h
new file mode 100644 (file)
index 0000000..32ff34b
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef COMMON_MDG_MANAGER_H_
+#define COMMON_MDG_MANAGER_H_
+
+#include <glib.h>
+#include <mdg.h>
+
+#include <functional>
+#include <string>
+
+#include "common/connection_manager.h"
+
+namespace capmgr {
+
+class CapabilityManager;
+class Capability;
+
+class MDGManager : public ConnectionManager {
+ public:
+  explicit MDGManager(CapabilityManager* capmgr);
+  ~MDGManager();
+
+  void FindDevices() override;
+  void RegisterEndpoint() override;
+  void ExchangeCapabilities() override;
+  bool SendCapability(
+      Capability* cap, std::function<void(Capability, int)> reply) override;
+
+ private:
+  enum class Command : unsigned char {
+    EXCHANGE_CAPS,
+    SEND_CAP,
+  };
+
+  bool Initialize();
+  bool CreateOrJoinGroup();
+  bool SendData(Command cmd, const std::string& data);
+
+  static void RequestCb(char* cmd, char* device_id, unsigned char* arg,
+      int len, int ret, void* user_data);
+  static void DeviceMonitorCb(char* uuid, char* group_name,
+      mdg_device_status_e status, void* user_data);
+  static bool GroupFoundCb(mdg_group_type_e type, mdg_group_h group,
+      void* user_data);
+  static void GroupFinishCb(int result, void* user_data);
+  static bool DeviceFoundCb(mdg_device_h device, void* user_data);
+  static void DeviceFinishCb(int result, void* user_data);
+
+  mdg_h mdg_handle_;
+  GList* device_list_;
+  GList* group_list_;
+};
+
+}  // namespace capmgr
+
+#endif  // COMMON_MDG_MANAGER_H_
diff --git a/src/common/utils/glist_range.h b/src/common/utils/glist_range.h
new file mode 100644 (file)
index 0000000..ef0d90a
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef COMMON_UTILS_GLIST_RANGE_H_
+#define COMMON_UTILS_GLIST_RANGE_H_
+
+#include <glib.h>
+
+#include <cstddef>
+#include <iterator>
+
+// Range with mutable forward iterator based on GList
+// supporting language foreach construct
+template<typename T>
+class GListRange {
+ public:
+  class Iterator {
+   public:
+    typedef T value_type;
+    typedef T& reference;
+    typedef T* pointer;
+    typedef const T* const_pointer;
+    typedef std::size_t difference_type;
+    typedef std::forward_iterator_tag iterator_category;
+
+    explicit Iterator(std::nullptr_t ptr = nullptr) : ptr_(ptr) { }
+    explicit Iterator(GList* ptr) : ptr_(ptr) { }
+    explicit operator bool() const {
+      return ptr_;
+    }
+    const reference& operator*() const {
+      return reinterpret_cast<const T&>(ptr_->data);
+    }
+    reference& operator*() {
+      return reinterpret_cast<T&>(ptr_->data);
+    }
+    const_pointer operator->() const {
+      return reinterpret_cast<pointer>(&ptr_->data);
+    }
+    pointer operator->() {
+      return reinterpret_cast<pointer>(&ptr_->data);
+    }
+    Iterator& operator++() {
+      ptr_ = g_list_next(ptr_);
+      return *this;
+    }
+    Iterator operator++(int) {
+      Iterator iter(ptr_);
+      ptr_ = g_list_next(ptr_);
+      return iter;
+    }
+    bool operator==(const Iterator& other) const {
+      return ptr_ == other.ptr_;
+    }
+    bool operator!=(const Iterator& other) const {
+      return !this->operator==(other);
+    }
+
+   private:
+    GList* ptr_;
+  };
+
+  explicit GListRange(GList* list) : list_(list) {  }
+  Iterator begin() {
+    return Iterator(list_);
+  }
+  Iterator end() {
+    return Iterator();
+  }
+
+  bool Empty() const noexcept {
+    return !list_;
+  }
+
+  guint Size() const {
+    return g_list_length(list_);
+  }
+
+ private:
+  GList* list_;
+};
+
+#endif  // COMMON_UTILS_GLIST_RANGE_H_