[NBS] NBS Native implementation
authorKamil Lysik <k.lysik@samsung.com>
Wed, 4 Feb 2015 08:55:25 +0000 (09:55 +0100)
committerPawel Sikorski <p.sikorski@samsung.com>
Tue, 10 Feb 2015 15:54:20 +0000 (00:54 +0900)
[Verification]
TCT pass: 24/25

Change-Id: I378e81df677ed17863ebb40b8e558c420ab27c9f
Signed-off-by: Kamil Lysik <k.lysik@samsung.com>
src/networkbearerselection/networkbearerselection.gyp
src/networkbearerselection/networkbearerselection_api.js
src/networkbearerselection/networkbearerselection_extension.h
src/networkbearerselection/networkbearerselection_instance.cc
src/networkbearerselection/networkbearerselection_instance.h
src/networkbearerselection/networkbearerselection_manager.cc [new file with mode: 0644]
src/networkbearerselection/networkbearerselection_manager.h [new file with mode: 0644]

index 54b2c4801675528b21a799c8260560de5b7cf863..c868701f2f74c7ad77bf6a978dd9885197954102 100644 (file)
@@ -9,6 +9,7 @@
       'variables': {
         'packages': [
           'icu-i18n',
+          'capi-network-connection',
         ],
       },
       'sources': [
@@ -17,6 +18,8 @@
         'networkbearerselection_extension.h',
         'networkbearerselection_instance.cc',
         'networkbearerselection_instance.h',
+        'networkbearerselection_manager.cc',
+        'networkbearerselection_manager.h',
       ],
       'conditions': [
         [ 'tizen == 1', {
index 1643385357c46b427fea7dea0d872854fcef2dea..d7374ced0789680135bd05dba5180649d9fcd5fe 100644 (file)
@@ -55,26 +55,26 @@ NetworkBearerSelection.prototype.requestRouteToHost = function(networkType, doma
     {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true}
   ]);
 
+  var id = nextCallbackId();
+
   var nativeParam = {
     networkType: args.networkType,
-    domainName: args.domainName
+    domainName: args.domainName,
+    id: id
   };
 
-  var result = native_.callSync('NetworkBearerSelection_requestRouteToHost', nativeParam);
-
-  if (native_.isFailure(result)) {
-    native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
-  }
-
-  var id = nextCallbackId();
-
-  native_.addListener('NetworkBearerSelectionCallback_' + id, _networkBearerSelectionCallback);
-
   callbacks[id] = {
     onsuccess: args.successCallback.onsuccess,
     ondisconnected: args.successCallback.ondisconnected,
     onerror: args.errorCallback
   };
+
+  native_.addListener('NetworkBearerSelectionCallback_' + id, _networkBearerSelectionCallback);
+  var result = native_.callSync('NetworkBearerSelection_requestRouteToHost', nativeParam);
+
+  if (native_.isFailure(result)) {
+    native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+  }
 };
 
 NetworkBearerSelection.prototype.releaseRouteToHost = function(networkType, domainName, successCallback, errorCallback) {
index 73011a756474d3b39f81fd489545e8db962a7813..bd5034d0450ae69776543e37cf541a887237054f 100644 (file)
@@ -16,4 +16,4 @@ class NetworkBearerSelectionExtension : public common::Extension {
   virtual common::Instance* CreateInstance();
 };
 
-#endif // NETWORKBEARERSELECTION_NETWORKBEARERSELECTION_EXTENSION_H_
+#endif  // NETWORKBEARERSELECTION_NETWORKBEARERSELECTION_EXTENSION_H_
index 9d5d4cfcda1bf8385e180a25cda8dad562a10c4e..4ac386f33378323d49172339472f157521a60e38 100644 (file)
@@ -9,6 +9,7 @@
 #include "common/picojson.h"
 #include "common/logger.h"
 #include "common/platform_exception.h"
+#include "common/task-queue.h"
 
 namespace extension {
 namespace networkbearerselection {
@@ -17,97 +18,155 @@ namespace {
 // The privileges that required in NetworkBearerSelection API
 const std::string kPrivilegeNetworkBearerSelection = "";
 
-} // namespace
+}  // namespace
 
 using namespace common;
 using namespace extension::networkbearerselection;
 
 NetworkBearerSelectionInstance::NetworkBearerSelectionInstance() {
   using namespace std::placeholders;
-  #define REGISTER_SYNC(c,x) \
-    RegisterSyncHandler(c, std::bind(&NetworkBearerSelectionInstance::x, this, _1, _2));
-  REGISTER_SYNC("NetworkBearerSelection_requestRouteToHost", NetworkBearerSelectionRequestRouteToHost);
-  REGISTER_SYNC("NetworkBearerSelection_releaseRouteToHost", NetworkBearerSelectionReleaseRouteToHost);
-  #undef REGISTER_SYNC
-}
-
-NetworkBearerSelectionInstance::~NetworkBearerSelectionInstance() {
+#define REGISTER_SYNC(c, x) \
+  RegisterSyncHandler(      \
+      c, std::bind(&NetworkBearerSelectionInstance::x, this, _1, _2));
+#define REGISTER_ASYNC(c, x) \
+  RegisterHandler(           \
+      c, std::bind(&NetworkBearerSelectionInstance::x, this, _1, _2));
+  REGISTER_SYNC("NetworkBearerSelection_requestRouteToHost",
+                NetworkBearerSelectionRequestRouteToHost);
+  REGISTER_ASYNC("NetworkBearerSelection_releaseRouteToHost",
+                 NetworkBearerSelectionReleaseRouteToHost);
+#undef REGISTER_SYNC
+#undef REGISTER_ASYNC
+
+  NetworkBearerSelectionManager::GetInstance()->AddListener(this);
 }
 
+NetworkBearerSelectionInstance::~NetworkBearerSelectionInstance() {}
 
-enum NetworkBearerSelectionCallbacks {
-  NetworkBearerSelectionRequestRouteToHostCallback,
-  NetworkBearerSelectionReleaseRouteToHostCallback
-};
-
-static void ReplyAsync(NetworkBearerSelectionInstance* instance, NetworkBearerSelectionCallbacks cbfunc,
-                       int callbackId, bool isSuccess, picojson::object& param) {
-  param["callbackId"] = picojson::value(static_cast<double>(callbackId));
-  param["status"] = picojson::value(isSuccess ? "success" : "error");
-
-  // insert result for async callback to param
-  switch(cbfunc) {
-    case NetworkBearerSelectionRequestRouteToHostCallback: {
-      // do something...
-      break;
-    }
-    case NetworkBearerSelectionReleaseRouteToHostCallback: {
-      // do something...
-      break;
-    }
-    default: {
-      LoggerE("Invalid Callback Type");
-      return;
-    }
+#define CHECK_EXIST(args, name, out)                                       \
+  if (!args.contains(name)) {                                              \
+    ReportError(TypeMismatchException(name " is required argument"), out); \
+    return;                                                                \
   }
 
-  picojson::value result = picojson::value(param);
-
-  instance->PostMessage(result.serialize().c_str());
-}
-
-#define CHECK_EXIST(args, name, out) \
-    if (!args.contains(name)) {\
-      ReportError(TypeMismatchException(name" is required argument"), out);\
-      return;\
-    }
-
-
-void NetworkBearerSelectionInstance::NetworkBearerSelectionRequestRouteToHost(const picojson::value& args, picojson::object& out) {
-  CHECK_EXIST(args, "callbackId", out)
+void NetworkBearerSelectionInstance::NetworkBearerSelectionRequestRouteToHost(
+    const picojson::value& args,
+    picojson::object& out) {
+  LoggerD("enter");
   CHECK_EXIST(args, "domainName", out)
+  CHECK_EXIST(args, "id", out)
 
-  int callbackId = static_cast<int>(args.get("callbackId").get<double>());
   const std::string& domainName = args.get("domainName").get<std::string>();
+  const int listenerId = static_cast<int>(args.get("id").get<double>());
 
-  // implement it
+  auto get = [=]()->void {
+    NetworkBearerSelectionManager::GetInstance()->requestRouteToHost(
+        domainName);
+  };
 
-  // call ReplyAsync in later (Asynchronously)
+  listenerMap.insert(std::make_pair(domainName, listenerId));
 
-  // if success
-  // ReportSuccess(out);
-  // if error
-  // ReportError(out);
+  common::TaskQueue::GetInstance().Async(get);
+  ReportSuccess(out);
 }
-void NetworkBearerSelectionInstance::NetworkBearerSelectionReleaseRouteToHost(const picojson::value& args, picojson::object& out) {
+
+void NetworkBearerSelectionInstance::NetworkBearerSelectionReleaseRouteToHost(
+    const picojson::value& args,
+    picojson::object& out) {
+  LoggerD("enter");
   CHECK_EXIST(args, "callbackId", out)
   CHECK_EXIST(args, "domainName", out)
-
-  int callbackId = static_cast<int>(args.get("callbackId").get<double>());
+  const double callback_id = args.get("callbackId").get<double>();
   const std::string& domainName = args.get("domainName").get<std::string>();
 
-  // implement it
+  auto get = [ this, callback_id ](bool status)->void {
+    LoggerD("enter");
+    picojson::value response = picojson::value(picojson::object());
+    picojson::object& obj = response.get<picojson::object>();
+    if (status)
+      ReportSuccess(obj);
+    else
+      ReportError(UnknownException("PLATFORM ERROR"), obj);
+    obj["callbackId"] = picojson::value(callback_id);
+    PostMessage(response.serialize().c_str());
+  };
+
+  auto reply = [=](bool status)->void {
+    LoggerD("enter");
+    common::TaskQueue::GetInstance().Async(std::bind(get, status));
+  };
+
+  bool status =
+      NetworkBearerSelectionManager::GetInstance()->releaseRouteToHost(
+          domainName, reply);
+  if (status) {
+    ReportSuccess(out);
+  } else {
+    ReportError(out);
+  }
+}
 
-  // call ReplyAsync in later (Asynchronously)
+void NetworkBearerSelectionInstance::onNBSSuccess(
+    const std::string& domain_name) {
+  LoggerD("enter");
+  picojson::value event = picojson::value(picojson::object());
+  picojson::object& obj = event.get<picojson::object>();
+  obj["domainName"] = picojson::value(domain_name);
+  obj["state"] = picojson::value("Success");
+
+  auto iterRange = listenerMap.equal_range(domain_name);
+  for (auto iter = iterRange.first; iter != iterRange.second; ++iter) {
+    auto listenerId = (*iter).second;
+    obj["listenerId"] = picojson::value("NetworkBearerSelectionCallback_" +
+                                        std::to_string(listenerId));
+    obj["id"] = picojson::value(static_cast<double>(listenerId));
+    LoggerD("Posting: %s", event.serialize().c_str());
+    PostMessage(event.serialize().c_str());
+  }
+}
 
-  // if success
-  // ReportSuccess(out);
-  // if error
-  // ReportError(out);
+void NetworkBearerSelectionInstance::onNBSError(const std::string& domain_name,
+                                                const std::string& info) {
+  LoggerD("enter");
+  picojson::value event = picojson::value(picojson::object());
+  picojson::object& obj = event.get<picojson::object>();
+  ReportError(UnknownException(info), obj);
+  obj["domainName"] = picojson::value(domain_name);
+  obj["state"] = picojson::value("Error");
+
+  auto iterRange = listenerMap.equal_range(domain_name);
+  for (auto iter = iterRange.first; iter != iterRange.second; ++iter) {
+    auto listenerId = (*iter).second;
+    obj["listenerId"] = picojson::value("NetworkBearerSelectionCallback_" +
+                                        std::to_string(listenerId));
+    obj["id"] = picojson::value(static_cast<double>(listenerId));
+    LoggerD("Posting: %s", event.serialize().c_str());
+    PostMessage(event.serialize().c_str());
+  }
+  listenerMap.erase(domain_name);
 }
 
+void NetworkBearerSelectionInstance::onNBSDisconnect(
+    const std::string& domain_name) {
+  LoggerD("enter");
+  picojson::value event = picojson::value(picojson::object());
+  picojson::object& obj = event.get<picojson::object>();
+  obj["domainName"] = picojson::value(domain_name);
+  obj["state"] = picojson::value("Disconnected");
+
+  auto iterRange = listenerMap.equal_range(domain_name);
+  for (auto iter = iterRange.first; iter != iterRange.second; ++iter) {
+    auto listenerId = (*iter).second;
+    obj["listenerId"] = picojson::value("NetworkBearerSelectionCallback_" +
+                                        std::to_string(listenerId));
+    obj["id"] = picojson::value(static_cast<double>(listenerId));
+    LoggerD("Posting: %s", event.serialize().c_str());
+    PostMessage(event.serialize().c_str());
+  }
+  listenerMap.erase(domain_name);
+}
 
 #undef CHECK_EXIST
 
-} // namespace networkbearerselection
-} // namespace extension
+}  // namespace networkbearerselection
+}  // namespace extension
index 4aa27494e44ef7eb75542eeff986aba74e0c91c8..5231925313c9346dc0fe9a6f2aeea61628d37b7f 100644 (file)
@@ -6,21 +6,33 @@
 #define NETWORKBEARERSELECTION_NETWORKBEARERSELECTION_INSTANCE_H_
 
 #include "common/extension.h"
+#include "networkbearerselection_manager.h"
+#include <map>
 
 namespace extension {
 namespace networkbearerselection {
 
-class NetworkBearerSelectionInstance : public common::ParsedInstance {
+class NetworkBearerSelectionInstance : public common::ParsedInstance,
+                                       public NetworkBearerSelectionListener {
  public:
   NetworkBearerSelectionInstance();
   virtual ~NetworkBearerSelectionInstance();
 
  private:
-  void NetworkBearerSelectionRequestRouteToHost(const picojson::value& args, picojson::object& out);
-  void NetworkBearerSelectionReleaseRouteToHost(const picojson::value& args, picojson::object& out);
+  void NetworkBearerSelectionRequestRouteToHost(const picojson::value& args,
+                                                picojson::object& out);
+  void NetworkBearerSelectionReleaseRouteToHost(const picojson::value& args,
+                                                picojson::object& out);
+
+  virtual void onNBSSuccess(const std::string& domain_name);
+  virtual void onNBSError(const std::string& domain_name,
+                          const std::string& info);
+  virtual void onNBSDisconnect(const std::string& domain_name);
+
+  std::multimap<std::string, int> listenerMap;
 };
 
-} // namespace networkbearerselection
-} // namespace extension
+}  // namespace networkbearerselection
+}  // namespace extension
 
-#endif // NETWORKBEARERSELECTION_NETWORKBEARERSELECTION_INSTANCE_H_
+#endif  // NETWORKBEARERSELECTION_NETWORKBEARERSELECTION_INSTANCE_H_
diff --git a/src/networkbearerselection/networkbearerselection_manager.cc b/src/networkbearerselection/networkbearerselection_manager.cc
new file mode 100644 (file)
index 0000000..316802d
--- /dev/null
@@ -0,0 +1,408 @@
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "networkbearerselection_manager.h"
+#include "common/logger.h"
+
+#include <netdb.h>
+#include <arpa/inet.h>
+
+namespace extension {
+namespace networkbearerselection {
+
+namespace {
+const char* kPlatformError = "Platform error";
+const char* kInvalidValuesError = "Invalid values error";
+}
+
+struct NetworkBearerSelectionRequestEvent {
+  std::string domain_name;
+  NetworkBearerSelectionRequestEvent(const std::string& dm) : domain_name(dm) {}
+};
+
+struct NetworkBearerSelectionReleaseEvent {
+  std::string domain_name;
+  NetworkBearerSelectionManager::ReleaseReplyCallback callback;
+  NetworkBearerSelectionReleaseEvent(
+      const std::string& dm,
+      const NetworkBearerSelectionManager::ReleaseReplyCallback& cb)
+      : domain_name(dm), callback(cb) {}
+};
+
+void NetworkBearerSelectionManager::AddListener(
+    NetworkBearerSelectionListener* listener) {
+  m_listeners.push_back(listener);
+}
+
+NetworkBearerSelectionManager* NetworkBearerSelectionManager::GetInstance() {
+  static NetworkBearerSelectionManager instance;
+  return &instance;
+}
+
+NetworkBearerSelectionManager::NetworkBearerSelectionManager()
+    : m_connectionHandle(nullptr),
+      m_profileHandle(nullptr),
+      m_connectionState(ConnectionState::Unknown),
+      m_isConnectionOpen(false) {
+  int ret = connection_create(&m_connectionHandle);
+
+  if (CONNECTION_ERROR_NONE == ret) {
+    LoggerD("Client registration success");
+  } else {
+    LoggerE("Client registration failed");
+    m_connectionHandle = nullptr;
+  }
+}
+
+NetworkBearerSelectionManager::~NetworkBearerSelectionManager() {
+  if (m_connectionHandle != nullptr) {
+    LoggerD("Client deregistration success");
+    if (m_profileHandle) {
+      connection_profile_destroy(m_profileHandle);
+      m_profileHandle = nullptr;
+    }
+    connection_destroy(m_connectionHandle);
+  } else {
+    LoggerE("Client deregistration failed");
+  }
+}
+
+void NetworkBearerSelectionManager::connection_state_changed_callback(
+    connection_profile_state_e state,
+    void* user_data) {
+  LoggerD("enter");
+  if (user_data != nullptr) {
+    LoggerD("Callback registration Succeeded");
+    if (state == CONNECTION_PROFILE_STATE_ASSOCIATION) {
+      LoggerD("association state");
+      return;
+    }
+    NetworkBearerSelectionRequestEvent* event =
+        static_cast<NetworkBearerSelectionRequestEvent*>(user_data);
+    std::string domain_name = event->domain_name;
+    delete event;
+    NetworkBearerSelectionManager::GetInstance()->deregistStateChangeListener(domain_name);
+    if (state == CONNECTION_PROFILE_STATE_DISCONNECTED) {
+      NetworkBearerSelectionManager::GetInstance()->makeDisconnectCallback(
+          domain_name);
+    }
+  }
+}
+
+void NetworkBearerSelectionManager::connection_profile_opened_callback(
+    connection_error_e result,
+    void* user_data) {
+  LoggerD("enter");
+  if (user_data == nullptr) {
+    LoggerD("Error: null passed in profile open callback");
+    return;
+  }
+
+  NetworkBearerSelectionRequestEvent* event =
+      static_cast<NetworkBearerSelectionRequestEvent*>(user_data);
+  std::string domain_name = event->domain_name;
+  delete event;
+
+  if (result == CONNECTION_ERROR_NONE) {
+    LoggerD("Connection open Succeeded");
+    if (user_data != nullptr) {
+      NetworkBearerSelectionManager::GetInstance()->registStateChangeListener(
+          domain_name);
+    }
+  } else {
+    LoggerD("Connection open Failed");
+    NetworkBearerSelectionManager::GetInstance()->makeErrorCallback(
+        domain_name, kPlatformError);
+  }
+}
+
+void NetworkBearerSelectionManager::connection_closed_callback(
+    connection_error_e result,
+    void* user_data) {
+  LoggerD("enter");
+  if (user_data == nullptr) {
+    LoggerD("Error: null passed in profile open callback");
+    return;
+  }
+
+  NetworkBearerSelectionReleaseEvent* event =
+      static_cast<NetworkBearerSelectionReleaseEvent*>(user_data);
+  std::string domain_name = event->domain_name;
+  ReleaseReplyCallback callback = event->callback;
+  delete event;
+
+  if (result == CONNECTION_ERROR_NONE) {
+    LoggerD("Connection close Succeeded");
+    if (user_data != nullptr) {
+      NetworkBearerSelectionManager::GetInstance()->deregistStateChangeListener(
+          domain_name);
+      callback(true);
+    }
+  } else {
+    callback(false);
+  }
+}
+
+void NetworkBearerSelectionManager::connection_closed_callback2(
+    connection_error_e result,
+    void* user_data) {
+  LoggerD("enter");
+  if (result == CONNECTION_ERROR_NONE) {
+    LoggerD("Connection close Succeeded");
+  }
+}
+
+void NetworkBearerSelectionManager::requestRouteToHost(
+    const std::string& domain_name) {
+  LoggerD("NetworkBearerSelectionManager::requestRouteToHost");
+  connection_profile_h profileHandle;
+
+  if (m_connectionState == ConnectionState::Connected) {
+    LoggerD("connection is already opened.");
+    for (std::list<std::string>::iterator it = m_domainNames.begin();
+         it != m_domainNames.end();
+         it++) {
+      if (*it == domain_name) {
+        LoggerD("Same domain name is exist in list.");
+        makeSuccessCallback(domain_name);
+        return;
+      }
+    }
+  }
+
+  if (m_profileHandle) {
+    connection_profile_destroy(m_profileHandle);
+    m_profileHandle = nullptr;
+  }
+
+  if (connection_get_default_cellular_service_profile(
+          m_connectionHandle,
+          CONNECTION_CELLULAR_SERVICE_TYPE_INTERNET,
+          &m_profileHandle) != CONNECTION_ERROR_NONE) {
+    LoggerE("Fail to get profile handle");
+    makeErrorCallback(domain_name, kPlatformError);
+    return;
+  }
+
+  char* defaultProfileName_c = nullptr;
+  std::string defaultProfileName;
+
+  connection_profile_get_name(m_profileHandle, &defaultProfileName_c);
+  if (defaultProfileName_c == nullptr) {
+    LoggerE("default profile is not exist.");
+    makeErrorCallback(domain_name, kPlatformError);
+    return;
+  }
+  defaultProfileName = defaultProfileName_c;
+  free(defaultProfileName_c);
+  defaultProfileName_c = nullptr;
+
+  if (connection_get_current_profile(m_connectionHandle, &profileHandle) !=
+      CONNECTION_ERROR_NONE) {
+    LoggerE("Fail to get current profile handle");
+    makeErrorCallback(domain_name, kPlatformError);
+    return;
+  }
+
+  char* currentProfileName_c = nullptr;
+  std::string currentProfileName;
+  if (connection_profile_get_name(profileHandle, &currentProfileName_c) !=
+      CONNECTION_ERROR_NONE) {
+    LoggerE("Fail to get current profile name");
+    makeErrorCallback(domain_name, kPlatformError);
+    return;
+  }
+
+  if (currentProfileName_c == nullptr) {
+    LoggerE("current profile is not exist.");
+    makeErrorCallback(domain_name, kPlatformError);
+    return;
+  }
+  currentProfileName = currentProfileName_c;
+  free(currentProfileName_c);
+  currentProfileName_c = nullptr;
+
+  if (defaultProfileName != currentProfileName) {
+    NetworkBearerSelectionRequestEvent* event =
+        new NetworkBearerSelectionRequestEvent(domain_name);
+    if (connection_open_profile(m_connectionHandle,
+                                m_profileHandle,
+                                connection_profile_opened_callback,
+                                event) != CONNECTION_ERROR_NONE) {
+      LoggerE("Connection open Failed");
+      delete event;
+      makeErrorCallback(domain_name, kPlatformError);
+    } else {
+      m_isConnectionOpen = true;
+    }
+  } else {
+    registStateChangeListener(domain_name);
+  }
+}
+
+bool NetworkBearerSelectionManager::releaseRouteToHost(
+    const std::string& domain_name,
+    const ReleaseReplyCallback& reply_cb) {
+  LoggerD("enter");
+  for (std::list<std::string>::iterator it = m_domainNames.begin();
+       it != m_domainNames.end();
+       it++) {
+    if (*it == domain_name) {
+      LoggerD("Same domain name is exist in list.");
+      m_domainNames.remove(domain_name);
+      LoggerD("list size : %i", m_domainNames.size());
+      if (m_domainNames.size() == 0) {
+        if (!m_profileHandle) {
+          // TODO: ALREADY_IN_USE EXCEPTION
+          return false;
+        }
+
+        if (connection_profile_unset_state_changed_cb(m_profileHandle) !=
+            CONNECTION_ERROR_NONE) {
+          LoggerE("unset callback is failed");
+          if (m_profileHandle) {
+            connection_profile_destroy(m_profileHandle);
+            m_profileHandle = NULL;
+          }
+          return true;
+        }
+
+        if (m_isConnectionOpen) {
+          NetworkBearerSelectionReleaseEvent* event =
+              new NetworkBearerSelectionReleaseEvent(domain_name, reply_cb);
+          if (connection_close_profile(m_connectionHandle,
+                                       m_profileHandle,
+                                       connection_closed_callback,
+                                       event) != CONNECTION_ERROR_NONE) {
+            LoggerE("connection close failed");
+            delete event;
+            reply_cb(false);
+          } else {
+            m_isConnectionOpen = false;
+            deregistStateChangeListener(domain_name);
+          }
+        } else {
+          reply_cb(true);
+        }
+      }
+      return true;
+    }
+  }
+
+  // TODO: INVALID_ARGUMENT_EXCEPTION
+  return false;
+}
+
+void NetworkBearerSelectionManager::registStateChangeListener(
+    const std::string& domain_name) {
+  LoggerD("enter");
+  char* interfaceName = nullptr;
+  char* hostAddr = nullptr;
+  struct hostent* host_entry;
+
+  if (connection_profile_get_network_interface_name(
+          m_profileHandle, &interfaceName) != CONNECTION_ERROR_NONE) {
+    LoggerD("Fail to get interface name!");
+    if (m_profileHandle) {
+      connection_profile_destroy(m_profileHandle);
+      m_profileHandle = nullptr;
+    }
+    makeErrorCallback(domain_name, kPlatformError);
+  } else {
+    LoggerD("Interface name : %s", interfaceName);
+  }
+
+  LoggerD("Domain name to be resolved: %s", domain_name.c_str());
+
+  host_entry = gethostbyname(domain_name.c_str());
+
+  if (!host_entry) {
+    LoggerD("gethostbyname is failed");
+    makeErrorCallback(domain_name, kInvalidValuesError);
+    if (connection_close_profile(m_connectionHandle,
+                                 m_profileHandle,
+                                 connection_closed_callback2,
+                                 nullptr) != CONNECTION_ERROR_NONE) {
+      LoggerD("connection close failed");
+      makeErrorCallback(domain_name, kPlatformError);
+    }
+    if (m_profileHandle) {
+      connection_profile_destroy(m_profileHandle);
+      m_profileHandle = nullptr;
+    }
+    return;
+  }
+
+  hostAddr = inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[0]);
+  LoggerD("hostAddr : %s", hostAddr);
+
+  NetworkBearerSelectionRequestEvent* event =
+      new NetworkBearerSelectionRequestEvent(domain_name);
+  if (connection_profile_set_state_changed_cb(m_profileHandle,
+                                              connection_state_changed_callback,
+                                              event) != CONNECTION_ERROR_NONE) {
+    LoggerE("Callback register is failed.");
+    if (m_profileHandle) {
+      connection_profile_destroy(m_profileHandle);
+      m_profileHandle = nullptr;
+    }
+    delete event;
+  } else {
+    if (connection_add_route(m_connectionHandle, interfaceName, hostAddr) !=
+        CONNECTION_ERROR_NONE) {
+      LoggerE("add route is failed.");
+      connection_profile_unset_state_changed_cb(m_profileHandle);
+      makeErrorCallback(domain_name, kPlatformError);
+    } else {
+      LoggerD("add route is successed.");
+      m_domainNames.push_back(domain_name);
+      makeSuccessCallback(domain_name);
+    }
+  }
+}
+
+void NetworkBearerSelectionManager::deregistStateChangeListener(
+    const std::string& domain_name) {
+  LoggerD("enter");
+  if (m_profileHandle) {
+    connection_profile_unset_state_changed_cb(m_profileHandle);
+    connection_profile_destroy(m_profileHandle);
+    m_profileHandle = NULL;
+  }
+  m_domainNames.remove(domain_name);
+  m_connectionState = ConnectionState::Disconnected;
+}
+
+void NetworkBearerSelectionManager::makeSuccessCallback(
+    const std::string& domain_name) {
+  LoggerD("enter");
+  for (NetworkBearerSelectionListener* listener : m_listeners)
+    listener->onNBSSuccess(domain_name);
+}
+
+void NetworkBearerSelectionManager::makeErrorCallback(
+    const std::string& domain_name,
+    const char* info) {
+  LoggerD("enter");
+  std::string l_info = info;
+  makeErrorCallback(domain_name, l_info);
+}
+
+void NetworkBearerSelectionManager::makeErrorCallback(
+    const std::string& domain_name,
+    const std::string& info) {
+  LoggerD("enter");
+  for (NetworkBearerSelectionListener* listener : m_listeners)
+    listener->onNBSError(domain_name, info);
+}
+
+void NetworkBearerSelectionManager::makeDisconnectCallback(
+    const std::string& domain_name) {
+  LoggerD("enter");
+  for (NetworkBearerSelectionListener* listener : m_listeners)
+    listener->onNBSDisconnect(domain_name);
+}
+
+}  // namespace networkbearerselection
+}  // namespace extension
diff --git a/src/networkbearerselection/networkbearerselection_manager.h b/src/networkbearerselection/networkbearerselection_manager.h
new file mode 100644 (file)
index 0000000..863a71b
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright 2015 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NETWORKBEARERSELECTION_NETWORKBEARERSELECTION_MANAGER_H_
+#define NETWORKBEARERSELECTION_NETWORKBEARERSELECTION_MANAGER_H_
+
+#include <string>
+#include <list>
+#include <functional>
+#include <device/callback.h>
+#include <net_connection.h>
+
+namespace extension {
+namespace networkbearerselection {
+
+enum class ConnectionState {
+  Unknown,
+  Connected,
+  Disconnected,
+  ConnectionFailed
+};
+
+enum class NetworkType {
+  Cellular,
+  Unknown
+};
+
+class NetworkBearerSelectionListener {
+ public:
+  virtual void onNBSSuccess(const std::string& domain_name) = 0;
+  virtual void onNBSError(const std::string& domain_name,
+                          const std::string& info) = 0;
+  virtual void onNBSDisconnect(const std::string& domain_name) = 0;
+};
+
+class NetworkBearerSelectionManager {
+ public:
+  typedef std::function<void(bool)> ReleaseReplyCallback;
+  void AddListener(NetworkBearerSelectionListener* listener);
+
+  void requestRouteToHost(const std::string& domain_name);
+  bool releaseRouteToHost(const std::string& domain_name,
+                          const ReleaseReplyCallback& reply_cb);
+
+  static NetworkBearerSelectionManager* GetInstance();
+
+  NetworkBearerSelectionManager(const NetworkBearerSelectionManager&) = delete;
+  NetworkBearerSelectionManager& operator=(
+      const NetworkBearerSelectionManager&) = delete;
+
+ private:
+  static void connection_state_changed_callback(
+      connection_profile_state_e state,
+      void* user_data);
+  static void connection_profile_opened_callback(connection_error_e result,
+                                                 void* user_data);
+  static void connection_closed_callback(connection_error_e result,
+                                         void* user_data);
+  static void connection_closed_callback2(connection_error_e result,
+                                          void* user_data);
+
+  void registStateChangeListener(const std::string& domain_name);
+  void deregistStateChangeListener(const std::string& domain_name);
+
+  void makeSuccessCallback(const std::string& domain_name);
+  void makeErrorCallback(const std::string& domain_name, const char* info);
+  void makeErrorCallback(const std::string& domain_name,
+                         const std::string& info);
+  void makeDisconnectCallback(const std::string& domain_name);
+
+  NetworkBearerSelectionManager();
+  ~NetworkBearerSelectionManager();
+
+  std::list<NetworkBearerSelectionListener*> m_listeners;
+
+  connection_h m_connectionHandle;
+  connection_profile_h m_profileHandle;
+  std::list<std::string> m_domainNames;
+  ConnectionState m_connectionState;
+  bool m_isConnectionOpen;
+};
+
+}  // namespace networkbearerselection
+}  // namespace extension
+
+#endif  // NETWORKBEARERSELECTION_NETWORKBEARERSELECTION_MANAGER_H_