#include <mdg.h>
#include <mdg_internal.h>
#include <sys/types.h>
+#include <unistd.h>
#include <cstring>
#include <map>
+#include <mutex>
#include <string>
#include <vector>
namespace {
const int kRequestTimeout = 5;
+const int kRequestWaitingSec = 1;
const char kGroupName[] = "capmgrgroup";
const char kChannelId[] = "capmgrchannel";
const char kPIN[] = "12341234";
}
void SendDataFinishCb(int result, void* user_data) {
- LOG(INFO) << "SendDataFinishCb called."
+ LOG(INFO) << "SendDataFinishCb called. "
<< "result: " << result;
}
namespace capmgr {
MDGManager::MDGManager(CapabilityManager* capmgr)
- : ConnectionManager(capmgr), mdg_handle_(nullptr), device_list_(nullptr),
- group_list_(nullptr) {
+ : ConnectionManager(capmgr), mdg_handle_(nullptr), group_handle_(nullptr),
+ device_list_(nullptr) {
if (!Initialize())
LOG(ERROR) << "Failed to initialize";
}
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);
+ if (!CreateGroup()) {
+ LOG(ERROR) << "Failed to create capmgr group";
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
+void MDGManager::ChannelCb(int result, char* device_id, char* channel_id,
+ unsigned char* arg, int len, void* user_data) {
+ LOG(INFO) << "ChannelCb called. "
+ << "result: " << result
<< ", device_id: " << device_id
- << ", ret: " << ret;
+ << ", channel_id: " << channel_id
+ << ", len: " << len;
MDGManager* mdgmgr = static_cast<MDGManager*>(user_data);
- if (!strcmp(cmd, kSendDataCmd)) {
- unsigned char* p = arg;
- Command cmd;
- memcpy(&cmd, p, sizeof(Command));
- p = p + sizeof(Command);
- size_t datasize;
- memcpy(&datasize, p, sizeof(size_t));
- p = p + sizeof(size_t);
- 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;
- RemoteDeviceManager::RegisterRemoteDevice(device_id, caps);
- } else if (cmd == Command::SEND_APPCONTROL) {
- unsigned char* data = p;
- int r = AppControlManager::LaunchApplication(data, datasize);
- if (r != 0)
- LOG(ERROR) << "Failed to launch application: " << ret;
- }
+ unsigned char* p = arg;
+ Command cmd;
+ memcpy(&cmd, p, sizeof(Command));
+ p = p + sizeof(Command);
+ size_t datasize;
+ memcpy(&datasize, p, sizeof(size_t));
+ p = p + sizeof(size_t);
+ if (cmd == Command::EXCHANGE_CAPS) {
+ // including terminating null byte
+ char* caps_raw = new char[datasize + 1];
+ memcpy(caps_raw, p, datasize);
+ caps_raw[datasize] = '\0';
+ std::string caps_str = std::string(caps_raw);
+ delete caps_raw;
+ std::vector<Capability> caps =
+ mdgmgr->capmgr_->UnpackCapabilities(caps_str);
+ LOG(INFO) << "Received " << caps.size() << " capabilities from device "
+ << device_id;
+ RemoteDeviceManager::RegisterRemoteDevice(device_id, caps);
+ } else if (cmd == Command::SEND_APPCONTROL) {
+ unsigned char* data = p;
+ int r = AppControlManager::LaunchApplication(data, datasize);
+ if (r != 0)
+ LOG(ERROR) << "Failed to launch application: " << r;
}
}
bool MDGManager::GroupFoundCb(mdg_group_type_e type, mdg_group_h group,
void* user_data) {
+ if (type != MDG_GROUP_TYPE_LOCAL)
+ return true;
+
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_LOCAL)
- LOG(INFO) << "Found group type LOCAL: " << group_name;
- else
- LOG(INFO) << "Found group type REMOTE: " << group_name
- << " (" << group_addr << ")";
+ ret = strcmp(group_name, kGroupName);
+ free(group_name);
- // 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);
+ if (ret == 0) {
+ ret = mdg_group_info_clone(&mdgmgr->group_handle_, group);
+ if (ret != MDG_ERROR_NONE)
+ LOG(ERROR) << "Failed to clone group info: " << MDGErrorToString(ret);
+ }
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;
- }
+ mdgmgr->FindDevices();
+}
- mdg_group_type_e group_type;
- ret = mdg_group_info_get_type(group, &group_type);
- if (ret != MDG_ERROR_NONE)
- continue;
- // if group is local, we don't need to join
- if (group_type == MDG_GROUP_TYPE_LOCAL) {
- LOG(INFO) << "Found my group. I'm the owner device";
- return;
- }
+void MDGManager::GroupInviteFinishCb(int result, mdg_device_h invited_device,
+ void* user_data) {
+ LOG(INFO) << "GroupInviteFinishCb called. "
+ << "result: " << result;
- 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_addr;
- int ret = mdg_device_info_get_addr(device, &device_addr);
- 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_addr, 25)) {
- owner_device = device;
- free(device_addr);
- break;
- }
- free(device_addr);
- }
- free(group_addr);
+ // This callback maybe called in different thread
+ std::mutex lock;
+ std::lock_guard<std::mutex> guard(lock);
- if (!owner_device) {
- LOG(ERROR) << "Cannot request invite. Cannot find proper device";
- return;
- }
+ mdg_device_h dev_clone;
+ int ret = mdg_device_info_clone(&dev_clone, invited_device);
+ if (ret != MDG_ERROR_NONE) {
+ LOG(ERROR) << "Failed to clone device info: " << MDGErrorToString(ret);
+ 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;
- }
+ // need to check dup?
+ MDGManager* mdgmgr = static_cast<MDGManager*>(user_data);
+ mdgmgr->device_list_ = g_list_append(mdgmgr->device_list_, dev_clone);
+}
+
+bool MDGManager::DeviceFoundCb(mdg_device_h device, void* user_data) {
+ char* device_id;
+ bool is_invited;
+ char* device_addr;
+ char* model_name;
+
+ int 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_is_invited(device, &is_invited);
+ if (ret != MDG_ERROR_NONE) {
+ LOG(ERROR) << "Failed to get is_invited: " << MDGErrorToString(ret);
+ free(device_id);
+ return true;
}
- LOG(INFO) << "Group not found. Create one";
- ret = mdg_group_create(mdgmgr->mdg_handle_, const_cast<char*>(kGroupName));
+ ret = mdg_device_info_get_addr(device, &device_addr);
+ if (ret != MDG_ERROR_NONE) {
+ LOG(ERROR) << "Failed to get device_addr: " << 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 model_name: " << MDGErrorToString(ret);
+ free(device_addr);
+ free(device_id);
+ return true;
+ }
+
+ LOG(INFO) << "Found not invited device. Invite this device. "
+ << "device_id: " << device_id
+ << ", is_invited: " << is_invited
+ << ", device_addr: " << device_addr
+ << ", model_name: " << model_name;
+
+ free(model_name);
+ free(device_addr);
+ free(device_id);
+
+ MDGManager* mdgmgr = static_cast<MDGManager*>(user_data);
+ ret = mdg_group_invite_device(mdgmgr->mdg_handle_, mdgmgr->group_handle_,
+ device, const_cast<char*>(kPIN), &MDGManager::GroupInviteFinishCb,
+ user_data);
if (ret != MDG_ERROR_NONE)
- LOG(ERROR) << "Failed to create group: " << MDGErrorToString(ret);
+ LOG(ERROR) << "Failed to invite device: " << MDGErrorToString(ret);
+
+ return true;
}
-bool MDGManager::DeviceFoundCb(mdg_device_h device, void* user_data) {
+void MDGManager::DeviceFinishCb(int result, void* user_data) {
+ LOG(INFO) << "Find device finished: " << result;
+
+ int ret;
+ MDGManager* mdgmgr = static_cast<MDGManager*>(user_data);
+ do {
+ ret = mdg_device_find(mdgmgr->mdg_handle_, kRequestTimeout, true,
+ &MDGManager::InvitedDeviceFoundCb, &MDGManager::InvitedDeviceFinishCb,
+ user_data);
+ if (ret != MDG_ERROR_IN_PROGRESS) {
+ LOG(INFO) << "Some request in progress, wait and retry in 1 second";
+ sleep(kRequestWaitingSec);
+ } else if (ret != MDG_ERROR_NONE) {
+ LOG(ERROR) << "Failed to find invited device: " << MDGErrorToString(ret);
+ }
+ } while (ret == MDG_ERROR_IN_PROGRESS);
+}
+
+bool MDGManager::InvitedDeviceFoundCb(mdg_device_h device, void* user_data) {
char* device_id;
+ bool is_invited;
char* device_addr;
char* model_name;
return true;
}
+ ret = mdg_device_info_is_invited(device, &is_invited);
+ if (ret != MDG_ERROR_NONE) {
+ LOG(ERROR) << "Failed to get is_invited: " << MDGErrorToString(ret);
+ free(device_id);
+ return true;
+ }
+
ret = mdg_device_info_get_addr(device, &device_addr);
if (ret != MDG_ERROR_NONE) {
LOG(ERROR) << "Failed to get device id: " << MDGErrorToString(ret);
return true;
}
- LOG(INFO) << "Found device. "
+ LOG(INFO) << "Found invited device. "
<< "device_id: " << device_id
+ << ", is_invited: " << is_invited
<< ", device_addr: " << device_addr
<< ", model_name: " << model_name;
+ // critical section: appending device list
+ std::mutex lock;
+ std::lock_guard<std::mutex> guard(lock);
+
// need to check dup;
MDGManager* mdgmgr = static_cast<MDGManager*>(user_data);
mdg_device_h dev_clone = nullptr;
return true;
}
-void MDGManager::DeviceFinishCb(int result, void* user_data) {
- LOG(INFO) << "Find device finished: " << result;
+void MDGManager::InvitedDeviceFinishCb(int result, void* user_data) {
+ LOG(INFO) << "Find invited device finished: " << result;
MDGManager* mdgmgr = static_cast<MDGManager*>(user_data);
- mdgmgr->CreateOrJoinGroup();
+ LOG(INFO) << "Found " << g_list_length(mdgmgr->device_list_)
+ << " invited devices";
}
-bool MDGManager::CreateOrJoinGroup() {
- int ret = mdg_group_find(mdg_handle_, kRequestTimeout,
+bool MDGManager::CreateGroup() {
+ int ret = mdg_group_create(mdg_handle_, const_cast<char*>(kGroupName));
+ if (ret == MDG_ERROR_NONE) {
+ LOG(INFO) << "Group for capmgr registered";
+ } else if (ret == MDG_ERROR_ALREADY_REGISTERED) {
+ LOG(INFO) << "Group for capmgr already registered";
+ } else {
+ LOG(ERROR) << "Failed to create group: " << MDGErrorToString(ret);
+ return false;
+ }
+
+ 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);
bool MDGManager::SendData(const std::string& device_id, Command cmd,
const unsigned char* data, size_t len) {
+ LOG(INFO) << "SendData to " << device_id;
+
mdg_device_h device = nullptr;
for (auto& dev : GListRange<mdg_device_h>(device_list_)) {
char* dev_id;
- int ret = mdg_device_info_get_device_id(device, &dev_id);
+ int ret = mdg_device_info_get_device_id(dev, &dev_id);
if (ret != MDG_ERROR_NONE)
continue;
ret = strcmp(dev_id, device_id.c_str());
}
void MDGManager::RegisterEndpoint() {
+ int ret = mdg_device_regist_channel(mdg_handle_,
+ const_cast<char*>(kChannelId), &MDGManager::ChannelCb, this);
+ if (ret == MDG_ERROR_NONE)
+ LOG(INFO) << "Channel for capmgr registered";
+ else if (ret == MDG_ERROR_ALREADY_REGISTERED)
+ LOG(INFO) << "Channel for capmgr already registered";
+ else
+ LOG(ERROR) << "Failed to regist channel: " << MDGErrorToString(ret);
}
void MDGManager::ExchangeCapabilities() {
std::string caps = capmgr_->PackCapabilities();
unsigned char* caps_data = new unsigned char[caps.size()];
- // FIXME: pass device_id?
- SendData({}, Command::EXCHANGE_CAPS, caps_data, caps.size());
+ memcpy(caps_data, caps.c_str(), caps.size());
+ LOG(INFO) << "Send my capabilities to "
+ << g_list_length(device_list_)
+ << " devices";
+ for (const auto& device : GListRange<mdg_device_h>(device_list_)) {
+ char* device_id;
+ int ret = mdg_device_info_get_device_id(device, &device_id);
+ if (ret != MDG_ERROR_NONE) {
+ LOG(ERROR) << "Failed to get device id: " << MDGErrorToString(ret);
+ continue;
+ }
+ SendData(device_id, Command::EXCHANGE_CAPS, caps_data, caps.size());
+ free(device_id);
+ }
delete caps_data;
}