* Copyright (C) 2021 Huawei Device Co., Ltd.
* 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.
*/
#include "server_for_client.h"
#ifndef TEST_HASH
#include "hdc_hash_gen.h"
#endif
#include "server.h"
#include "subserver/subserver_manager.h"
#ifdef __OHOS__
#include <sys/un.h>
#include "system_depend.h"
#endif
#include "host_shell_option.h"
#ifdef HDC_SUPPORT_REPORT_COMMAND_EVENT
#include "command_event_report.h"
#endif
namespace Hdc {
static const int MAX_CONNECT_DEVICE_RETRY_COUNT = 100;
#ifdef __OHOS__
static const int MAX_CONNECTIONS_COUNT = 16;
static const std::string SYS_PARAM_ENTERPRISE_HDC_DISABLE = "persist.edm.hdc_remote_disable";
static const int ENTERPRISE_HDC_DISABLE_ERR = -11;
#endif
HdcServerForClient::HdcServerForClient(const bool serverOrClient, const string &addrString, void *pClsServer,
uv_loop_t *loopMainIn)
: HdcChannelBase(serverOrClient, addrString, loopMainIn)
{
clsServer = pClsServer;
}
HdcServerForClient::~HdcServerForClient()
{
WRITE_LOG(LOG_DEBUG, "~HdcServerForClient");
}
void HdcServerForClient::Stop()
{
Base::TryCloseHandle((uv_handle_t *)&tcpListen);
#ifdef __OHOS__
Base::TryCloseHandle((uv_handle_t *)&udsListen);
#endif
}
uint16_t HdcServerForClient::GetTCPListenPort()
{
return channelPort;
}
#ifdef __OHOS__
void HdcServerForClient::AcceptUdsClient(uv_stream_t *server, int status)
{
StartTraceScope("HdcServerForClient::AcceptUdsClient");
HdcServerForClient *thisClass = (HdcServerForClient *)(((uv_pipe_t *)server)->data);
if (thisClass == nullptr) {
WRITE_LOG(LOG_FATAL, "HdcServerForClient is null");
return;
}
CALLSTAT_GUARD(thisClass->loopMainStatus, server->loop, "HdcServerForClient::AcceptUdsClient");
HChannel hChannel = new (std::nothrow) HdcChannel();
if (hChannel == nullptr) {
WRITE_LOG(LOG_FATAL, "AcceptUdsClient new channel fail");
return;
}
hChannel->isUds = true;
uint32_t uid = thisClass->MallocChannel(&hChannel);
hChannel->startTime = Base::GetRuntimeMSec();
int rc = 0;
if ((rc = uv_accept(server, (uv_stream_t *)&hChannel->hWorkUds)) < 0) {
WRITE_LOG(LOG_FATAL, "AcceptUdsClient uv_accept error rc:%d uid:%u", rc, uid);
thisClass->FreeChannel(uid);
return;
}
WRITE_LOG(LOG_DEBUG, "AcceptUdsClient uid:%u", uid);
int bufMaxSize = 0;
uv_recv_buffer_size((uv_handle_t *)&hChannel->hWorkUds, &bufMaxSize);
auto funcChannelHeaderAlloc = [](uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf) -> void {
HChannel context = (HChannel)handle->data;
Base::ReallocBuf(&context->ioBuf, &context->bufSize, Base::GetMaxBufSize() * BUF_EXTEND_SIZE);
buf->base = (char *)context->ioBuf + context->availTailIndex;
#ifdef HDC_VERSION_CHECK
buf->len = sizeof(struct ChannelHandShake) + DWORD_SERIALIZE_SIZE;
#else
buf->len = offsetof(struct ChannelHandShake, version) + DWORD_SERIALIZE_SIZE;
#endif
};
uv_read_start((uv_stream_t *)&hChannel->hWorkUds, funcChannelHeaderAlloc, ReadStream);
struct ChannelHandShake handShake = {};
if (EOK == strcpy_s(handShake.banner, sizeof(handShake.banner), HANDSHAKE_MESSAGE.c_str())) {
handShake.banner[BANNER_FEATURE_TAG_OFFSET] = HUGE_BUF_TAG;
handShake.banner[SERVICE_KILL_OFFSET] = SERVICE_KILL_TAG;
handShake.channelId = htonl(hChannel->channelId);
string ver = Base::GetVersion() + HDC_MSG_HASH;
WRITE_LOG(LOG_DEBUG, "Server ver:%s", ver.c_str());
if (EOK != strcpy_s(handShake.version, sizeof(handShake.version), ver.c_str())) {
WRITE_LOG(LOG_FATAL, "strcpy_s failed");
return;
}
#ifdef HDC_VERSION_CHECK
thisClass->Send(hChannel->channelId, (uint8_t *)&handShake, sizeof(struct ChannelHandShake));
#else
thisClass->Send(hChannel->channelId, reinterpret_cast<uint8_t *>(&handShake),
offsetof(struct ChannelHandShake, version));
#endif
}
}
#endif
void HdcServerForClient::AcceptClient(uv_stream_t *server, int )
{
StartTraceScope("HdcServerForClient::AcceptClient");
uv_tcp_t *pServTCP = (uv_tcp_t *)server;
HdcServerForClient *thisClass = (HdcServerForClient *)pServTCP->data;
CALLSTAT_GUARD(thisClass->loopMainStatus, server->loop, "HdcServerForClient::AcceptClient");
#ifdef HOST_OHOS
HChannel hChannel = new (std::nothrow) HdcChannel();
if (hChannel == nullptr) {
WRITE_LOG(LOG_FATAL, "AcceptClient new channel fail");
return;
}
#else
HChannel hChannel = nullptr;
#endif
uint32_t uid = thisClass->MallocChannel(&hChannel);
if (!hChannel) {
WRITE_LOG(LOG_FATAL, "AcceptClient hChannel is nullptr");
return;
}
hChannel->startTime = Base::GetRuntimeMSec();
int rc = uv_accept(server, (uv_stream_t *)&hChannel->hWorkTCP);
if (rc < 0) {
WRITE_LOG(LOG_FATAL, "AcceptClient uv_accept error rc:%d uid:%u", rc, uid);
thisClass->FreeChannel(uid);
return;
}
WRITE_LOG(LOG_DEBUG, "AcceptClient uid:%u", uid);
int bufMaxSize = 0;
uv_recv_buffer_size((uv_handle_t *)&hChannel->hWorkTCP, &bufMaxSize);
auto funcChannelHeaderAlloc = [](uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf) -> void {
HChannel context = (HChannel)handle->data;
Base::ReallocBuf(&context->ioBuf, &context->bufSize, Base::GetMaxBufSize() * BUF_EXTEND_SIZE);
buf->base = (char *)context->ioBuf + context->availTailIndex;
#ifdef HDC_VERSION_CHECK
buf->len = sizeof(struct ChannelHandShake) + DWORD_SERIALIZE_SIZE;
#else
buf->len = offsetof(struct ChannelHandShake, version) + DWORD_SERIALIZE_SIZE;
#endif
};
uv_read_start((uv_stream_t *)&hChannel->hWorkTCP, funcChannelHeaderAlloc, ReadStream);
struct ChannelHandShake handShake = {};
if (EOK == strcpy_s(handShake.banner, sizeof(handShake.banner), HANDSHAKE_MESSAGE.c_str())) {
handShake.banner[BANNER_FEATURE_TAG_OFFSET] = HUGE_BUF_TAG;
#ifdef HOST_OHOS
handShake.banner[SERVICE_KILL_OFFSET] = SERVICE_KILL_TAG;
#endif
handShake.channelId = htonl(hChannel->channelId);
string ver = Base::GetVersion() + HDC_MSG_HASH;
WRITE_LOG(LOG_DEBUG, "Server ver:%s", ver.c_str());
if (EOK != strcpy_s(handShake.version, sizeof(handShake.version), ver.c_str())) {
WRITE_LOG(LOG_FATAL, "strcpy_s failed");
return;
}
#ifdef HDC_VERSION_CHECK
thisClass->Send(hChannel->channelId, (uint8_t *)&handShake, sizeof(struct ChannelHandShake));
#else
thisClass->Send(hChannel->channelId, reinterpret_cast<uint8_t *>(&handShake),
offsetof(struct ChannelHandShake, version));
#endif
}
}
#ifdef __OHOS__
bool HdcServerForClient::SetUdsListen()
{
udsListen.data = this;
int ret = -1;
ret = uv_pipe_init(loopMain, &udsListen, 0);
(void)unlink(UDS_PATH.c_str());
if ((ret = uv_pipe_bind(&udsListen, UDS_PATH.c_str())) != 0) {
WRITE_LOG(LOG_WARN, "bind uds addr fail! ret:%d", ret);
return false;
}
uv_fs_t req = {};
ret = uv_fs_chmod(nullptr, &req, UDS_PATH.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
nullptr);
if (ret < 0) {
char buffer[BUF_SIZE_DEFAULT] = { 0 };
uv_strerror_r(ret, buffer, BUF_SIZE_DEFAULT);
WRITE_LOG(LOG_WARN, "uv_fs_chmod uds failed %s", buffer);
uv_fs_req_cleanup(&req);
return false;
}
uv_fs_req_cleanup(&req);
if ((ret = uv_listen((uv_stream_t *)&udsListen, MAX_CONNECTIONS_COUNT, AcceptUdsClient)) != 0) {
WRITE_LOG(LOG_WARN, "uds listen fail! ret:%d", ret);
return false;
}
return true;
}
#endif
bool HdcServerForClient::SetTCPListen()
{
char buffer[BUF_SIZE_DEFAULT] = { 0 };
tcpListen.data = this;
struct sockaddr_in6 addr;
uv_tcp_init(loopMain, &tcpListen);
if (Base::GetCaller() == Base::Caller::SERVER) {
WRITE_LOG(LOG_DEBUG, "channelHost %s, port: %d", Hdc::MaskString(channelHost).c_str(), channelPort);
} else {
WRITE_LOG(LOG_DEBUG, "channelHost %s, port: %d", channelHost.c_str(), channelPort);
}
int rc = uv_ip6_addr(channelHost.c_str(), channelPort, &addr);
if (rc != 0) {
uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT);
WRITE_LOG(LOG_FATAL, "uv_ip6_addr %d %s", rc, buffer);
return false;
}
rc = uv_tcp_bind(&tcpListen, (const struct sockaddr *)&addr, 0);
if (rc != 0) {
WRITE_LOG(LOG_WARN, "uv_tcp_bind ipv6 %d", rc);
if (rc == -EAFNOSUPPORT) {
size_t index = channelHost.find(IPV4_MAPPING_PREFIX);
size_t size = IPV4_MAPPING_PREFIX.size();
if (index != std::string::npos) {
struct sockaddr_in addr4v;
std::string ipv4 = channelHost.substr(index + size);
uv_ip4_addr(ipv4.c_str(), channelPort, &addr4v);
rc = uv_tcp_bind(&tcpListen, (const struct sockaddr *)&addr4v, 0);
if (rc != 0) {
uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT);
if (Base::GetCaller() == Base::Caller::SERVER) {
WRITE_LOG(LOG_FATAL, "uv_tcp_bind ipv4 %s failed %d %s",
Hdc::MaskString(ipv4).c_str(), rc, buffer);
} else {
WRITE_LOG(LOG_FATAL, "uv_tcp_bind ipv4 %s failed %d %s",
ipv4.c_str(), rc, buffer);
}
return false;
}
}
} else {
uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT);
WRITE_LOG(LOG_FATAL, "uv_tcp_bind %d %s", rc, buffer);
return false;
}
}
int backLog = 128;
rc = uv_listen((uv_stream_t *)&tcpListen, backLog, (uv_connection_cb)AcceptClient);
if (rc != 0) {
uv_strerror_r(rc, buffer, BUF_SIZE_DEFAULT);
WRITE_LOG(LOG_FATAL, "uv_listen %d %s", rc, buffer);
return false;
}
return true;
}
int HdcServerForClient::Initial()
{
if (!clsServer) {
WRITE_LOG(LOG_FATAL, "Module client initial failed");
return -1;
}
#ifndef __OHOS__
if (!channelHostPort.size() || !channelHost.size() || !channelPort) {
WRITE_LOG(LOG_FATAL, "Listen string initial failed");
return -2;
}
if (!SetTCPListen()) {
WRITE_LOG(LOG_FATAL, "SetTCPListen failed");
int listenError = -3;
return listenError;
}
#else
if (!channelHostPort.size() || !channelHost.size() || !channelPort) {
WRITE_LOG(LOG_FATAL, "Listen string initial failed");
} else {
if (!SetTCPListen()) {
WRITE_LOG(LOG_FATAL, "SetTCPListen failed");
}
}
if (!SetUdsListen()) {
WRITE_LOG(LOG_FATAL, "SetUdsListen failed");
int listenError = -3;
return listenError;
}
#endif
return 0;
}
void HdcServerForClient::EchoClient(HChannel hChannel, MessageLevel level, const char *msg, ...)
{
StartTraceScope("HdcServerForClient::EchoClient");
string logInfo = "";
switch (level) {
case MSG_FAIL:
logInfo = MESSAGE_FAIL;
break;
case MSG_INFO:
logInfo = MESSAGE_INFO;
break;
default:
break;
}
va_list vaArgs;
va_start(vaArgs, msg);
string log = logInfo + Base::StringFormat(msg, vaArgs);
va_end(vaArgs);
if (log.back() != '\n') {
log += "\r\n";
}
SendChannel(hChannel, const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(log.c_str())), log.size());
}
void HdcServerForClient::EchoClientRaw(const HChannel hChannel, uint8_t *payload, const int payloadSize)
{
SendChannel(hChannel, payload, payloadSize);
}
void HdcServerForClient::SendCommandToClient(const HChannel hChannel, const uint16_t commandFlag,
uint8_t *payload, const int payloadSize)
{
if (Base::CanPrintCmd(commandFlag)) {
WRITE_LOG(LOG_INFO, "SendCommandToClient cid:%u sid:%s commandID:%u payloadSize:%d",
hChannel->channelId, Hdc::MaskSessionIdToString(hChannel->targetSessionId).c_str(),
commandFlag, payloadSize);
}
SendChannelWithCmd(hChannel, commandFlag, payload, payloadSize);
}
bool HdcServerForClient::SendToDaemon(HChannel hChannel, const uint16_t commandFlag, uint8_t *bufPtr, const int bufSize)
{
StartTraceScope("HdcServerForClient::SendToDaemon");
HDaemonInfo hdi = nullptr;
bool ret = false;
HdcServer *ptrServer = (HdcServer *)clsServer;
if (Base::CanPrintCmd(commandFlag)) {
WRITE_LOG(LOG_INFO, "SendToDaemon cid:%u sid:%s key:%s commandID:%u sizeSend:%d", hChannel->channelId,
Hdc::MaskSessionIdToString(hChannel->targetSessionId).c_str(),
Hdc::MaskString(hChannel->connectKey).c_str(), commandFlag, bufSize);
}
while (true) {
ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi);
if (hdi == nullptr) {
WRITE_LOG(LOG_FATAL, "SendToDaemon hdi nullptr");
break;
}
if (hdi->connStatus != STATUS_CONNECTED) {
WRITE_LOG(LOG_FATAL, "SendToDaemon not connected");
break;
}
if (!hdi->hSession) {
WRITE_LOG(LOG_FATAL, "SendToDaemon hdi->hSession nullptr");
break;
}
if (ptrServer->Send(hdi->hSession->sessionId, hChannel->channelId, commandFlag, bufPtr, bufSize) < 0) {
WRITE_LOG(LOG_FATAL, "SendToDaemon Send failed channelId:%u", hChannel->channelId);
break;
}
ret = true;
break;
}
return ret;
}
void HdcServerForClient::OrderFindTargets(HChannel hChannel)
{
int count = 0;
EchoClient(hChannel, MSG_INFO, "Please add HDC server's firewall ruler to allow udp incoming, udpport:%d",
DEFAULT_PORT);
HdcServer *ptrServer = (HdcServer *)clsServer;
ptrServer->clsTCPClt->FindLanDaemon();
list<string> &lst = ptrServer->clsTCPClt->lstDaemonResult;
HdcDaemonInformation di;
while (!lst.empty()) {
di = {};
++count;
di.connectKey = lst.front();
di.connType = CONN_TCP;
di.connStatus = STATUS_READY;
di.inited = false;
HDaemonInfo pDi = reinterpret_cast<HDaemonInfo>(&di);
ptrServer->AdminDaemonMap(OP_ADD, STRING_EMPTY, pDi);
lst.pop_front();
}
EchoClient(hChannel, MSG_INFO, "Broadcast find daemon, total:%d", count);
#ifdef UNIT_TEST
string bufString = std::to_string(count);
Base::WriteBinFile((UT_TMP_PATH + "/base-discover.result").c_str(), (uint8_t *)bufString.c_str(), bufString.size(),
true);
#endif
}
static bool IsDisconnect(HDaemonInfo hdi, uint16_t count)
{
if (hdi == nullptr) {
return true;
}
#ifdef HDC_SUPPORT_UART
if (hdi->connType == CONN_SERIAL) {
const uint16_t maxRetryCount = 500;
if (count > maxRetryCount) {
WRITE_LOG(LOG_INFO, "uart retry count:%u", count);
return true;
}
return false;
}
#endif
HSession hSession = hdi->hSession;
if (hSession == nullptr) {
WRITE_LOG(LOG_INFO, "hSession is nullptr connKey:%s", Hdc::MaskString(hdi->connectKey).c_str());
return true;
}
if (!hSession->isRunningOk) {
WRITE_LOG(LOG_INFO, "isRunningOk is false sessionId:%s",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
return true;
}
return false;
}
void HdcServerForClient::OrderConnecTargetResult(uv_timer_t *req)
{
HChannel hChannel = (HChannel)req->data;
HdcServerForClient *thisClass = (HdcServerForClient *)hChannel->clsChannel;
HdcServer *ptrServer = (HdcServer *)thisClass->clsServer;
bool bConnectOK = false;
bool bExitRepet = false;
HDaemonInfo hdi = nullptr;
string sRet;
string target = std::string(hChannel->bufStd + 2);
if (target == "any") {
ptrServer->AdminDaemonMap(OP_GET_ANY, target, hdi);
} else {
ptrServer->AdminDaemonMap(OP_QUERY, target, hdi);
}
if (hdi && hdi->connStatus == STATUS_CONNECTED) {
bConnectOK = true;
}
if (bConnectOK) {
bExitRepet = true;
if (hChannel->isCheck) {
WRITE_LOG(LOG_INFO, "check device success and remove %s", Hdc::MaskString(hChannel->key).c_str());
thisClass->CommandRemoveSession(hChannel, hChannel->key.c_str());
thisClass->EchoClient(hChannel, MSG_OK, const_cast<char *>(hdi->version.c_str()));
} else {
sRet = "Connect OK";
thisClass->EchoClient(hChannel, MSG_OK, const_cast<char *>(sRet.c_str()));
}
} else {
uint16_t *bRetryCount = reinterpret_cast<uint16_t *>(hChannel->bufStd);
++(*bRetryCount);
if (hChannel->connectLocalDevice && *bRetryCount > MAX_CONNECT_DEVICE_RETRY_COUNT) {
bExitRepet = true;
} else {
bExitRepet = IsDisconnect(hdi, *bRetryCount);
}
if (bExitRepet) {
sRet = "Connect failed";
thisClass->EchoClient(hChannel, MSG_FAIL, const_cast<char *>(sRet.c_str()));
hdi->inited = false;
hdi->connStatus = STATUS_OFFLINE;
ptrServer->AdminDaemonMap(OP_UPDATE, target, hdi);
WRITE_LOG(LOG_INFO, "channelId:%u target:%s STATUS_OFFLINE",
hChannel->channelId, Hdc::MaskString(target).c_str());
}
}
if (bExitRepet) {
thisClass->FreeChannel(hChannel->channelId);
Base::TryCloseHandle((const uv_handle_t *)req, Base::CloseTimerCallback);
}
}
bool HdcServerForClient::NewConnectTry(void *ptrServer, HChannel hChannel, const string &connectKey, bool isCheck)
{
#ifdef HDC_DEBUG
WRITE_LOG(LOG_ALL, "%s %s", __FUNCTION__, Hdc::MaskString(connectKey).c_str());
#endif
int childRet = ((HdcServer *)ptrServer)->CreateConnect(connectKey, isCheck);
bool ret = false;
int connectError = -2;
constexpr uint8_t bufOffsetTwo = 2;
constexpr uint8_t bufOffsetThree = 3;
if (childRet == -1) {
EchoClient(hChannel, MSG_INFO, "Target is connected, repeat operation");
} else if (childRet == connectError) {
EchoClient(hChannel, MSG_FAIL, "CreateConnect failed");
WRITE_LOG(LOG_FATAL, "CreateConnect failed");
} else {
size_t pos = connectKey.find(":");
if (pos != std::string::npos) {
string ip = connectKey.substr(0, pos);
if (ip == "127.0.0.1") {
hChannel->connectLocalDevice = true;
}
}
(void)memset_s(hChannel->bufStd, sizeof(hChannel->bufStd), 0, sizeof(hChannel->bufStd));
childRet = snprintf_s(hChannel->bufStd + bufOffsetTwo, sizeof(hChannel->bufStd) - bufOffsetTwo,
sizeof(hChannel->bufStd) - bufOffsetThree, "%s",
const_cast<char *>(connectKey.c_str()));
if (childRet > 0) {
Base::TimerUvTask(loopMain, hChannel, OrderConnecTargetResult, UV_START_REPEAT);
ret = true;
}
}
return ret;
}
bool HdcServerForClient::CommandRemoveSession(HChannel hChannel, const char *connectKey)
{
HdcServer *ptrServer = (HdcServer *)clsServer;
HDaemonInfo hdiOld = nullptr;
(reinterpret_cast<HdcServer *>(ptrServer))->AdminDaemonMap(OP_QUERY, connectKey, hdiOld);
if (hdiOld == nullptr || hdiOld->hSession == nullptr) {
EchoClient(hChannel, MSG_FAIL, "No target available");
WRITE_LOG(LOG_FATAL, "CommandRemoveSession No target available");
return false;
}
(reinterpret_cast<HdcServer *>(ptrServer))->FreeSession(hdiOld->hSession->sessionId);
return true;
}
bool HdcServerForClient::CommandReconnectTarget(HChannel hChannel, const char *connectKey)
{
HdcServer *ptrServer = (HdcServer *)clsServer;
string key = connectKey;
if (key.empty()) {
EchoClient(hChannel, MSG_FAIL, "Usage: reconnect <target-key>");
WRITE_LOG(LOG_WARN, "CommandReconnectTarget missing target key");
return false;
}
HDaemonInfo hdiOld = nullptr;
ptrServer->AdminDaemonMap(OP_QUERY, key, hdiOld);
if (hdiOld == nullptr || hdiOld->connStatus != STATUS_CONNECTED) {
EchoClient(hChannel, MSG_FAIL, "Target device %s not available", key.c_str());
WRITE_LOG(LOG_WARN, "CommandReconnectTarget target not found or not connected");
return false;
}
if (hdiOld->connType != CONN_USB) {
EchoClient(hChannel, MSG_FAIL, "Reconnect only supports USB devices");
WRITE_LOG(LOG_WARN, "CommandReconnectTarget non-USB target");
return false;
}
string usbMountPoint = hdiOld->usbMountPoint;
uint32_t sessionId = (hdiOld->hSession != nullptr) ? hdiOld->hSession->sessionId : 0;
if (sessionId > 0) {
ptrServer->FreeSession(sessionId);
}
if (!usbMountPoint.empty() && ptrServer->clsUSBClt != nullptr) {
ptrServer->clsUSBClt->AllowUsbNodeRescan(usbMountPoint);
}
string msg = "Reconnecting " + key + " ...";
EchoClient(hChannel, MSG_OK, msg.c_str());
WRITE_LOG(LOG_INFO, "CommandReconnectTarget key:%s mount:%s",
Hdc::MaskString(key).c_str(), usbMountPoint.c_str());
return true;
}
bool HdcServerForClient::RemoveFportkey(const string &forwardKey)
{
StartTraceScope("HdcServerForClient::RemoveFportkey");
HdcServer *ptrServer = (HdcServer *)clsServer;
HForwardInfo hfi = nullptr;
ptrServer->AdminForwardMap(OP_QUERY, forwardKey, hfi);
if (!hfi) {
WRITE_LOG(LOG_FATAL, "RemoveFportkey hfi nullptr forwardKey:%s", Hdc::MaskString(forwardKey).c_str());
return false;
}
HSession hSession = ptrServer->AdminSession(OP_QUERY, hfi->sessionId, nullptr);
if (!hSession) {
WRITE_LOG(LOG_FATAL, "RemoveFportkey hSession nullptr sessionId:%s",
Hdc::MaskSessionIdToString(hfi->sessionId).c_str());
ptrServer->AdminForwardMap(OP_REMOVE, forwardKey, hfi);
return true;
}
hSession->commandCount++;
ptrServer->ClearOwnTasks(hSession, hfi->channelId);
FreeChannel(hfi->channelId);
hfi = nullptr;
ptrServer->AdminForwardMap(OP_REMOVE, forwardKey, hfi);
return true;
}
void HdcServerForClient::GetTargetList(HChannel hChannel, void *formatCommandInput)
{
TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
HdcServer *ptrServer = (HdcServer *)clsServer;
uint16_t cmd = OP_GET_STRLIST;
if (formatCommand->parameters == "v") {
cmd = OP_GET_STRLIST_FULL;
}
HDaemonInfo hdi = nullptr;
string sRet = ptrServer->AdminDaemonMap(cmd, STRING_EMPTY, hdi);
if (!sRet.length()) {
sRet = EMPTY_ECHO;
}
EchoClient(hChannel, MSG_OK, const_cast<char *>(sRet.c_str()));
#ifdef UNIT_TEST
Base::WriteBinFile((UT_TMP_PATH + "/base-list.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(),
MESSAGE_SUCCESS.size(), true);
#endif
}
bool HdcServerForClient::GetAnyTarget(HChannel hChannel)
{
HdcServer *ptrServer = (HdcServer *)clsServer;
HDaemonInfo hdi = nullptr;
ptrServer->AdminDaemonMap(OP_GET_ANY, STRING_EMPTY, hdi);
if (!hdi) {
EchoClient(hChannel, MSG_FAIL, "No target available");
return false;
}
string connectKey = hdi->connectKey;
bool ret = NewConnectTry(ptrServer, hChannel, connectKey);
#ifdef UNIT_TEST
Base::WriteBinFile((UT_TMP_PATH + "/base-any.result").c_str(), (uint8_t *)MESSAGE_SUCCESS.c_str(),
MESSAGE_SUCCESS.size(), true);
#endif
return ret;
}
bool HdcServerForClient::WaitForAny(HChannel hChannel)
{
HdcServer *ptrServer = (HdcServer *)clsServer;
HDaemonInfo hdi = nullptr;
if (!hChannel->connectKey.empty()) {
ptrServer->AdminDaemonMap(OP_WAIT_FOR_ANY, hChannel->connectKey, hdi);
} else {
ptrServer->AdminDaemonMap(OP_WAIT_FOR_ANY, STRING_EMPTY, hdi);
}
if (!hdi) {
EchoClient(hChannel, MSG_FAIL, "No any connected target");
return false;
}
string key = hdi->connectKey;
EchoClient(hChannel, MSG_OK, "Wait for connected target is %s", key.c_str());
return true;
}
static const std::string& GetSubserverStatusStr(SubserverStatus status)
{
static const std::unordered_map<SubserverStatus, std::string> map = {
{SubserverStatus::CONNECTING, "Subserver started, connecting USB"},
{SubserverStatus::SUBPROCESS_FAIL, "Subprocess launch failed"},
{SubserverStatus::PORT_LISTEN_FAIL, "Port binding failed"},
{SubserverStatus::CONNECT_TIMEOUT, "USB connection timeout"},
{SubserverStatus::INVALID_DEVICE, "Device not found"},
{SubserverStatus::PARAM_ERROR, "Invalid parameters"},
{SubserverStatus::CONNECT_SUCCESS, "Subserver connected successfully"},
{SubserverStatus::USB_DISCONNECT, "USB device disconnected"},
{SubserverStatus::SUBSERVER_ABONDON, "Only main server can spawn subserver"},
{SubserverStatus::SUBSERVER_OTHER_EXIT, "Subserver process exited"}
};
auto it = map.find(status);
if (it == map.end()) {
static const std::string unknownError = "Unknown error";
return unknownError;
}
return it->second;
}
bool HdcServerForClient::ProcessSubserver(HChannel hChannel, const std::string& parameters)
{
HdcServer *ptrServer = (HdcServer *)clsServer;
SubserverStatus status = SubserverManager::Instance().HandleCommand(ptrServer, hChannel, parameters);
const std::string& str = GetSubserverStatusStr(status);
EchoClient(hChannel, MSG_OK, "%s", str.c_str());
return true;
}
bool HdcServerForClient::RemoveForward(HChannel hChannel, const char *parameterString)
{
StartTraceScope("HdcServerForClient::RemoveForward");
HdcServer *ptrServer = (HdcServer *)clsServer;
HForwardInfo hfi = nullptr;
bool ret = false;
std::string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST, hChannel->connectKey, hfi);
vector<string> filterStrings;
Base::SplitString(echo, string("\n"), filterStrings);
for (auto &&s : filterStrings) {
std::string taskString = s;
size_t pos = taskString.rfind("|");
if (pos != string::npos && pos + 1 < taskString.length()) {
taskString = taskString.substr(pos + 1);
} else {
WRITE_LOG(LOG_WARN, "remove forward invalid %s", Hdc::MaskString(taskString).c_str());
ret = false;
break;
}
if (parameterString != nullptr && taskString.compare(parameterString) != 0) {
continue;
}
ret |= RemoveFportkey(s);
}
if (ret) {
EchoClient(hChannel, MSG_OK, "Remove forward ruler success, ruler:%s", parameterString);
} else {
EchoClient(hChannel, MSG_FAIL, "Remove forward ruler failed, ruler is not exist %s", parameterString);
}
return ret;
}
bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandInput)
{
StartTraceScope("HdcServerForClient::DoCommandLocal");
TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
HdcServer *ptrServer = (HdcServer *)clsServer;
bool ret = false;
switch (formatCommand->cmdFlag) {
case CMD_KERNEL_TARGET_DISCOVER: {
OrderFindTargets(hChannel);
hChannel->isSuccess = true;
ret = false;
break;
}
case CMD_KERNEL_TARGET_LIST: {
GetTargetList(hChannel, formatCommandInput);
hChannel->isSuccess = true;
ret = false;
break;
}
case CMD_SERVICE_START: {
PrintLastError(hChannel);
hChannel->isSuccess = true;
ret = false;
break;
}
#ifdef HOST_OHOS
case CMD_SERVER_KILL: {
WRITE_LOG(LOG_FATAL, "CMD_SERVER_KILL command");
ptrServer->SessionSoftReset();
hChannel->isSuccess = true;
EchoClient(hChannel, MSG_OK, "Kill server finish");
_exit(0);
}
#endif
case CMD_CHECK_SERVER: {
WRITE_LOG(LOG_DEBUG, "CMD_CHECK_SERVER command");
ReportServerVersion(hChannel);
hChannel->isSuccess = true;
ret = false;
break;
}
case CMD_WAIT_FOR: {
WRITE_LOG(LOG_DEBUG, "CMD_WAIT_FOR command");
ret = !WaitForAny(hChannel);
hChannel->isSuccess = true;
break;
}
case CMD_KERNEL_TARGET_ANY: {
#ifdef HDC_DEBUG
WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_ANY %s", __FUNCTION__, formatCommand->parameters.c_str());
#endif
ret = GetAnyTarget(hChannel);
hChannel->isSuccess = ret;
break;
}
case CMD_KERNEL_TARGET_CONNECT: {
#ifdef HDC_DEBUG
WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_CONNECT %s", __FUNCTION__, formatCommand->parameters.c_str());
#endif
ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str());
hChannel->isSuccess = ret;
break;
}
case CMD_CHECK_DEVICE: {
WRITE_LOG(LOG_INFO, "%s CMD_CHECK_DEVICE %s", __FUNCTION__, formatCommand->parameters.c_str());
hChannel->isCheck = true;
hChannel->key = formatCommand->parameters.c_str();
ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str(), true);
hChannel->isSuccess = ret;
break;
}
case CMD_KERNEL_TARGET_DISCONNECT: {
CommandRemoveSession(hChannel, formatCommand->parameters.c_str());
hChannel->isSuccess = true;
break;
}
case CMD_KERNEL_TARGET_RECONNECT: {
hChannel->isSuccess = CommandReconnectTarget(hChannel, formatCommand->parameters.c_str());
break;
}
case CMD_FORWARD_LIST: {
HForwardInfo hfi = nullptr;
string echo = ptrServer->AdminForwardMap(OP_GET_STRLIST_FULL, "", hfi);
if (!echo.length()) {
echo = EMPTY_ECHO;
}
EchoClient(hChannel, MSG_OK, const_cast<char *>(echo.c_str()));
hChannel->isSuccess = true;
break;
}
case CMD_FORWARD_REMOVE: {
RemoveForward(hChannel, formatCommand->parameters.c_str());
hChannel->isSuccess = true;
break;
}
case CMD_KERNEL_ENABLE_KEEPALIVE: {
hChannel->keepAlive = true;
ret = true;
hChannel->isSuccess = true;
break;
}
case CMD_SPAWN_SUB: {
ProcessSubserver(hChannel, formatCommand->parameters);
hChannel->isSuccess = true;
ret = true;
break;
}
default: {
EchoClient(hChannel, MSG_FAIL, "ExecuteCommand need connect-key? please confirm a device by help info");
FillChannelResult(hChannel, false, "found no devices");
break;
}
}
return ret;
}
bool HdcServerForClient::TaskCommand(HChannel hChannel, void *formatCommandInput)
{
StartTraceScope("HdcServerForClient::TaskCommand");
TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
HdcServer *ptrServer = (HdcServer *)clsServer;
string cmdFlag;
uint8_t sizeCmdFlag = 0;
if (formatCommand->cmdFlag == CMD_FILE_INIT) {
cmdFlag = "send ";
sizeCmdFlag = 5;
HandleRemote(hChannel, formatCommand->parameters, RemoteType::REMOTE_FILE);
} else if (formatCommand->cmdFlag == CMD_FORWARD_INIT) {
cmdFlag = "fport ";
sizeCmdFlag = 6;
} else if (formatCommand->cmdFlag == CMD_APP_INIT) {
cmdFlag = "install ";
sizeCmdFlag = 8;
HandleRemote(hChannel, formatCommand->parameters, RemoteType::REMOTE_APP);
} else if (formatCommand->cmdFlag == CMD_APP_UNINSTALL) {
cmdFlag = "uninstall ";
sizeCmdFlag = 10;
} else if (formatCommand->cmdFlag == CMD_UNITY_BUGREPORT_INIT) {
cmdFlag = "bugreport ";
sizeCmdFlag = 10;
} else if (formatCommand->cmdFlag == CMD_APP_SIDELOAD) {
cmdFlag = "sideload ";
sizeCmdFlag = 9;
} else if (formatCommand->cmdFlag == CMD_FLASHD_UPDATE_INIT) {
cmdFlag = "update ";
sizeCmdFlag = 7;
} else if (formatCommand->cmdFlag == CMD_FLASHD_FLASH_INIT) {
cmdFlag = "flash ";
sizeCmdFlag = 6;
}
int sizeSend = formatCommand->parameters.size();
if (!strncmp(formatCommand->parameters.c_str(), cmdFlag.c_str(), sizeCmdFlag)) {
HSession hSession = FindAliveSession(hChannel->targetSessionId);
if (!hSession) {
return false;
}
if ((formatCommand->cmdFlag == CMD_FILE_INIT || formatCommand->cmdFlag == CMD_APP_INIT) &&
hChannel->fromClient) {
WRITE_LOG(LOG_INFO, "CMD_FILE_INIT|CMD_APP_INIT command send back to remote client, cid:%u",
hChannel->channelId);
SendChannelWithCmd(hChannel, formatCommand->cmdFlag,
reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
sizeSend - sizeCmdFlag);
return false;
}
ptrServer->DispatchTaskData(hSession, hChannel->channelId, formatCommand->cmdFlag,
reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
sizeSend - sizeCmdFlag);
} else {
SendToDaemon(hChannel, formatCommand->cmdFlag,
reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())) + sizeCmdFlag,
sizeSend - sizeCmdFlag);
}
return true;
}
void HdcServerForClient::HandleRemote(HChannel hChannel, string ¶meters, RemoteType flag)
{
StartTraceScope("HdcServerForClient::HandleRemote");
hChannel->remote = flag;
int argc = 0;
char **argv = Base::SplitCommandToArgs(parameters.c_str(), &argc);
for (int i = 0; i < argc; i++) {
if (argv[i] == CMDSTR_REMOTE_PARAMETER) {
hChannel->fromClient = true;
WRITE_LOG(LOG_DEBUG, "remote client mode channelId:%u", hChannel->channelId);
break;
}
}
if (hChannel->fromClient) {
string remote = CMDSTR_REMOTE_PARAMETER + " ";
if (parameters.find(remote) != std::string::npos) {
parameters.replace(parameters.find(remote), remote.size(), "");
WRITE_LOG(LOG_DEBUG, "parameters: %s", Hdc::MaskString(parameters).c_str());
}
}
delete[](reinterpret_cast<char *>(argv));
}
#ifdef __OHOS__
bool HdcServerForClient::IsServerTransfer(HChannel hChannel, uint16_t cmdFlag, string ¶meters)
{
if (cmdFlag == CMD_FILE_INIT || cmdFlag== CMD_APP_INIT) {
HandleRemote(hChannel, parameters, RemoteType::REMOTE_FILE);
if (!hChannel->fromClient) {
EchoClient(hChannel, MSG_FAIL, "[E005200] Unsupport file command");
return false;
}
}
return true;
}
#endif
bool HdcServerForClient::DoCommandRemote(HChannel hChannel, void *formatCommandInput)
{
StartTraceScope("HdcServerForClient::DoCommandRemote");
TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
bool ret = false;
int sizeSend = formatCommand->parameters.size();
switch (formatCommand->cmdFlag) {
case CMD_SHELL_INIT:
case CMD_SHELL_DATA:
case CMD_UNITY_EXECUTE:
case CMD_UNITY_EXECUTE_EX:
case CMD_UNITY_REMOUNT:
case CMD_UNITY_REBOOT:
case CMD_UNITY_RUNMODE:
case CMD_UNITY_HILOG:
case CMD_UNITY_ROOTRUN:
case CMD_JDWP_TRACK:
case CMD_JDWP_LIST: {
if (!SendToDaemon(hChannel, formatCommand->cmdFlag,
reinterpret_cast<uint8_t *>(const_cast<char *>(formatCommand->parameters.c_str())), sizeSend)) {
break;
}
ret = true;
if (formatCommand->cmdFlag == CMD_SHELL_INIT) {
hChannel->interactiveShellMode = true;
}
break;
}
case CMD_FILE_INIT:
case CMD_FORWARD_INIT:
case CMD_APP_INIT: {
#ifdef __OHOS__
if (!IsServerTransfer(hChannel, formatCommand->cmdFlag, formatCommand->parameters)) {
return false;
}
#endif
}
case CMD_APP_UNINSTALL:
case CMD_UNITY_BUGREPORT_INIT:
case CMD_APP_SIDELOAD:
case CMD_FLASHD_UPDATE_INIT:
case CMD_FLASHD_FLASH_INIT:
case CMD_FLASHD_ERASE:
case CMD_FLASHD_FORMAT: {
TaskCommand(hChannel, formatCommandInput);
ret = true;
break;
}
default:
break;
}
if (!ret) {
EchoClient(hChannel, MSG_FAIL, "[E002106] Failed to communicate with daemon");
}
return ret;
}
bool HdcServerForClient::DoCommand(HChannel hChannel, void *formatCommandInput, HDaemonInfo &hdi)
{
StartTraceScope("HdcServerForClient::DoCommand");
bool ret = false;
TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput;
#ifdef __OHOS__
if ((!hChannel->hChildWorkTCP.loop && !hChannel->hChildWorkUds.loop) ||
#else
if (!hChannel->hChildWorkTCP.loop ||
#endif
formatCommand->cmdFlag == CMD_FORWARD_REMOVE ||
#ifdef HOST_OHOS
formatCommand->cmdFlag == CMD_SERVER_KILL ||
#endif
formatCommand->cmdFlag == CMD_SPAWN_SUB ||
formatCommand->cmdFlag == CMD_SERVICE_START) {
hChannel->commandFlag = formatCommand->cmdFlag;
hChannel->commandParameters = formatCommand->parameters;
ret = DoCommandLocal(hChannel, formatCommandInput);
} else {
if (!CommandMatchDaemonFeature(formatCommand->cmdFlag, hdi)) {
WRITE_LOG(LOG_WARN, "unsupport cmdFlag: %d, due to daemon feature dismatch", formatCommand->cmdFlag);
EchoClient(hChannel, MSG_FAIL, "[E002105] Unsupport command");
return false;
}
if (formatCommand->cmdFlag != CMD_SHELL_DATA) {
hChannel->commandFlag = formatCommand->cmdFlag;
hChannel->commandParameters = formatCommand->parameters;
}
ret = DoCommandRemote(hChannel, formatCommandInput);
}
return ret;
}
HSession HdcServerForClient::FindAliveSessionFromDaemonMap(const HChannel hChannel)
{
StartTraceScope("HdcServerForClient::FindAliveSessionFromDaemonMap");
HSession hSession = nullptr;
HDaemonInfo hdi = nullptr;
HdcServer *ptrServer = (HdcServer *)clsServer;
ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi);
if (!hdi) {
WRITE_LOG(LOG_WARN, "Not match target founded cid:%u", hChannel->channelId);
FillChannelResult(hChannel, false, "no match targets found");
EchoClient(hChannel, MSG_FAIL, "Not match target founded, check connect-key please");
return nullptr;
}
if (hdi->connStatus != STATUS_CONNECTED) {
WRITE_LOG(LOG_WARN, "Device not found or connected cid:%u", hChannel->channelId);
FillChannelResult(hChannel, false, "device not found or connected");
EchoClient(hChannel, MSG_FAIL, "[E001005] Device not found or connected");
return nullptr;
}
if (hdi->hSession == nullptr) {
WRITE_LOG(LOG_WARN, "session is null cid:%u", hChannel->channelId);
FillChannelResult(hChannel, false, "bind target session is null");
EchoClient(hChannel, MSG_FAIL, "Bind tartget session is dead");
return nullptr;
}
if (hdi->hSession->isDead) {
WRITE_LOG(LOG_WARN, "session is dead cid:%u sid:%s", hChannel->channelId,
Hdc::MaskSessionIdToString(hdi->hSession->sessionId).c_str());
FillChannelResult(hChannel, false, "bind target session is dead");
EchoClient(hChannel, MSG_FAIL, "Bind tartget session is dead");
return nullptr;
}
if (!hdi->hSession->handshakeOK) {
WRITE_LOG(LOG_WARN, "hSession handShake is false sid:%s cid:%u",
Hdc::MaskSessionIdToString(hdi->hSession->sessionId).c_str(), hChannel->channelId);
FillChannelResult(hChannel, false, "handshake is not ready");
const string errMsg = "[E000004]:The communication channel is being established.\r\n"\
"Please wait for several seconds and try again.";
EchoClient(hChannel, MSG_FAIL, errMsg.c_str());
return nullptr;
}
hSession = reinterpret_cast<HSession>(hdi->hSession);
return hSession;
}
#ifdef __OHOS__
int HdcServerForClient::BindChannelToSession(HChannel hChannel)
{
StartTraceScope("HdcServerForClient::BindChannelToSession");
if (FindAliveSessionFromDaemonMap(hChannel) == nullptr) {
WRITE_LOG(LOG_FATAL, "Find no alive session channelId:%u", hChannel->channelId);
return ERR_SESSION_NOFOUND;
}
bool isClosing = false;
if (!hChannel->isUds) {
isClosing = uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP);
if (!isClosing && (hChannel->fdChildWorkTCP = Base::DuplicateUvSocket(&hChannel->hWorkTCP)) < 0) {
WRITE_LOG(LOG_FATAL, "Duplicate socket failed channelId:%u", hChannel->channelId);
return ERR_SOCKET_DUPLICATE;
}
} else {
isClosing = uv_is_closing((const uv_handle_t *)&hChannel->hWorkUds);
if (!isClosing && (hChannel->fdChildWorkTCP = Base::DuplicateUvPipe(&hChannel->hWorkUds)) < 0) {
WRITE_LOG(LOG_FATAL, "Duplicate pipe failed channelId:%u", hChannel->channelId);
return ERR_SOCKET_DUPLICATE;
}
}
uv_close_cb funcWorkTcpClose = [](uv_handle_t *handle) -> void {
HChannel hChannel = (HChannel)handle->data;
--hChannel->ref;
};
++hChannel->ref;
if (!isClosing) {
if (!hChannel->isUds) {
uv_close((uv_handle_t *)&hChannel->hWorkTCP, funcWorkTcpClose);
} else {
uv_close((uv_handle_t *)&hChannel->hWorkUds, funcWorkTcpClose);
}
}
Base::DoNextLoop(loopMain, hChannel, [](const uint8_t flag, string &msg, const void *data) {
HChannel hChannel = (HChannel)data;
auto thisClass = (HdcServerForClient *)hChannel->clsChannel;
HSession hSession = nullptr;
if ((hSession = thisClass->FindAliveSessionFromDaemonMap(hChannel)) == nullptr) {
WRITE_LOG(LOG_FATAL, "hSession nullptr channelId:%u", hChannel->channelId);
return;
}
auto ctrl = HdcSessionBase::BuildCtrlString(SP_ATTACH_CHANNEL, hChannel->channelId, nullptr, 0);
Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
});
return RET_SUCCESS;
}
#else
int HdcServerForClient::BindChannelToSession(HChannel hChannel)
{
StartTraceScope("HdcServerForClient::BindChannelToSession");
if (FindAliveSessionFromDaemonMap(hChannel) == nullptr) {
WRITE_LOG(LOG_FATAL, "Find no alive session channelId:%u", hChannel->channelId);
return ERR_SESSION_NOFOUND;
}
bool isClosing = uv_is_closing((const uv_handle_t *)&hChannel->hWorkTCP);
if (!isClosing && (hChannel->fdChildWorkTCP = Base::DuplicateUvSocket(&hChannel->hWorkTCP)) < 0) {
WRITE_LOG(LOG_FATAL, "Duplicate socket failed channelId:%u", hChannel->channelId);
return ERR_SOCKET_DUPLICATE;
}
uv_close_cb funcWorkTcpClose = [](uv_handle_t *handle) -> void {
HChannel hChannel = (HChannel)handle->data;
--hChannel->ref;
};
++hChannel->ref;
if (!isClosing) {
uv_close((uv_handle_t *)&hChannel->hWorkTCP, funcWorkTcpClose);
}
Base::DoNextLoop(loopMain, hChannel, [](const uint8_t flag, string &msg, const void *data) {
HChannel hChannel = (HChannel)data;
auto thisClass = (HdcServerForClient *)hChannel->clsChannel;
HSession hSession = nullptr;
if ((hSession = thisClass->FindAliveSessionFromDaemonMap(hChannel)) == nullptr) {
WRITE_LOG(LOG_FATAL, "hSession nullptr channelId:%u", hChannel->channelId);
return;
}
auto ctrl = HdcSessionBase::BuildCtrlString(SP_ATTACH_CHANNEL, hChannel->channelId, nullptr, 0);
Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
});
return RET_SUCCESS;
}
#endif
bool HdcServerForClient::CheckAutoFillTarget(HChannel hChannel)
{
HdcServer *ptrServer = (HdcServer *)clsServer;
if (!hChannel->connectKey.size()) {
WRITE_LOG(LOG_FATAL, "connectKey.size 0 channelId:%u", hChannel->channelId);
return false;
}
if (hChannel->connectKey == CMDSTR_CONNECT_ANY) {
HDaemonInfo hdiOld = nullptr;
ptrServer->AdminDaemonMap(OP_GET_ONLY, "", hdiOld);
if (!hdiOld) {
WRITE_LOG(LOG_WARN, "No any key found channelId:%u", hChannel->channelId);
return false;
}
if (!hdiOld->hSession) {
WRITE_LOG(LOG_WARN, "hSession is null. channelId:%u", hChannel->channelId);
return false;
}
if (!hdiOld->hSession->handshakeOK) {
WRITE_LOG(LOG_WARN, "hSession handShake is false SessionId:%s",
Hdc::MaskSessionIdToString(hdiOld->hSession->sessionId).c_str());
return false;
}
hChannel->connectKey = hdiOld->connectKey;
return true;
}
return true;
}
int HdcServerForClient::ChannelHandShake(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
{
StartTraceScope("HdcServerForClient::ChannelHandShake");
vector<uint8_t> rebuildHandshake;
rebuildHandshake.insert(rebuildHandshake.end(), bufPtr, bufPtr + bytesIO);
rebuildHandshake.push_back(0x00);
struct ChannelHandShake *handShake = reinterpret_cast<struct ChannelHandShake *>(rebuildHandshake.data());
if (strncmp(handShake->banner, HANDSHAKE_MESSAGE.c_str(), HANDSHAKE_MESSAGE.size())) {
hChannel->availTailIndex = 0;
WRITE_LOG(LOG_DEBUG, "Channel Hello failed");
return ERR_HANDSHAKE_NOTMATCH;
}
if (strlen(handShake->connectKey) > sizeof(handShake->connectKey)) {
hChannel->availTailIndex = 0;
WRITE_LOG(LOG_DEBUG, "Connectkey's size incorrect");
return ERR_HANDSHAKE_CONNECTKEY_FAILED;
}
std::string sessionIdMaskStr = Hdc::MaskSessionIdToString(hChannel->targetSessionId);
WRITE_LOG(LOG_DEBUG, "ServerForClient cid:%u sid:%s handshake finished", hChannel->channelId,
sessionIdMaskStr.c_str());
hChannel->connectKey = handShake->connectKey;
hChannel->handshakeOK = true;
if (handShake->banner[WAIT_TAG_OFFSET] == WAIT_DEVICE_TAG || !CheckAutoFillTarget(hChannel)) {
WRITE_LOG(LOG_WARN, "No target channelId:%u", hChannel->channelId);
return 0;
}
if (BindChannelToSession(hChannel)) {
hChannel->availTailIndex = 0;
WRITE_LOG(LOG_FATAL, "BindChannelToSession failed channelId:%u sid:%s",
hChannel->channelId, sessionIdMaskStr.c_str());
return ERR_GENERIC;
}
return 0;
}
void HdcServerForClient::ReportServerVersion(HChannel hChannel)
{
string version = Base::GetVersion();
SendChannelWithCmd(hChannel, CMD_CHECK_SERVER,
const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(version.c_str())),
version.size());
}
#ifdef __OHOS__
static bool ReportCommandEvent(uint8_t *bufPtr, const int bytesIO, bool isIntercepted)
{
#ifdef HDC_SUPPORT_REPORT_COMMAND_EVENT
if (!DelayedSingleton<CommandEventReport>::GetInstance()->ReportCommandEvent(
std::string(reinterpret_cast<char *>(bufPtr), bytesIO), Base::GetCaller(), isIntercepted)) {
WRITE_LOG(LOG_FATAL,
"[E00C002]Execution intercepted due to inaccessibility of reporting command event.");
return false;
}
#endif
return true;
}
#endif
int HdcServerForClient::ReadChannel(HChannel hChannel, uint8_t *bufPtr, const int bytesIO)
{
StartTraceScope("HdcServerForClient::ReadChannel");
if (!hChannel->handshakeOK) {
return ChannelHandShake(hChannel, bufPtr, bytesIO);
}
#ifdef __OHOS__
bool isIntercepted = IsNeedInterceptCommand();
if (!ReportCommandEvent(bufPtr, bytesIO, isIntercepted)) {
EchoClient(hChannel, MSG_FAIL,
"[E00C002]Execution intercepted due to inaccessibility of reporting command event.");
return ERR_GENERIC;
}
if (isIntercepted) {
EchoClient(hChannel, MSG_FAIL, "[E00C001]Operation restricted by the organization.");
WRITE_LOG(LOG_FATAL, "[E00C001]Server Operation restricted by the organization.");
return ENTERPRISE_HDC_DISABLE_ERR;
}
#endif
HDaemonInfo hdi = nullptr;
HdcServer *ptrServer = (HdcServer *)clsServer;
ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi);
if (hdi && !hdi->emgmsg.empty()) {
EchoClient(hChannel, MSG_FAIL, hdi->emgmsg.c_str());
return ERR_GENERIC;
}
uint16_t command = *reinterpret_cast<uint16_t *>(bufPtr);
if (command != 0 && (hChannel->remote > RemoteType::REMOTE_NONE)) {
if (!SendToDaemon(hChannel, command, bufPtr + sizeof(uint16_t), bytesIO - sizeof(uint16_t))) {
WRITE_LOG(LOG_FATAL, "Client ReadChannel : direct send to daemon failed");
}
return 0;
}
struct TranslateCommand::FormatCommand formatCommand = {};
if (!hChannel->interactiveShellMode) {
string retEcho = String2FormatCommand(reinterpret_cast<char *>(bufPtr), bytesIO, &formatCommand);
if (retEcho.length()) {
if (!strncmp(reinterpret_cast<char *>(bufPtr), CMDSTR_SOFTWARE_HELP.c_str(),
CMDSTR_SOFTWARE_HELP.size()) ||
!strcmp(reinterpret_cast<char *>(bufPtr), CMDSTR_SOFTWARE_VERSION.c_str()) ||
!strcmp(reinterpret_cast<char *>(bufPtr), "flash")) {
EchoClient(hChannel, MSG_OK, retEcho.c_str());
} else {
EchoClient(hChannel, MSG_FAIL, retEcho.c_str());
}
}
WRITE_LOG(LOG_INFO, "ReadChannel cid:%u sid:%s key:%s", hChannel->channelId,
Hdc::MaskSessionIdToString(hChannel->targetSessionId).c_str(),
Hdc::MaskString(hChannel->connectKey).c_str());
if (Hdc::Base::GetCmdLogSwitch()) {
#ifdef SUPPORT_DETAILE_HDC_CMD_LOG
string logBuf = Base::CmdLogStringFormat(hChannel->targetSessionId, (reinterpret_cast<char *>(bufPtr)));
#else
std::string cmdStr = std::to_string(command);
string logBuf = Base::CmdLogStringFormat(hChannel->targetSessionId, cmdStr.c_str());
#endif
if (logBuf.length() > 0) {
ptrServer->PrintCmdLogEx(logBuf);
}
}
if (formatCommand.bJumpDo) {
WRITE_LOG(LOG_FATAL, "ReadChannel bJumpDo true");
return -10;
}
} else {
formatCommand.parameters = string(reinterpret_cast<char *>(bufPtr), bytesIO);
formatCommand.cmdFlag = CMD_SHELL_DATA;
}
if (!DoCommand(hChannel, &formatCommand, hdi)) {
return -3;
}
return bytesIO;
};
HSession HdcServerForClient::FindAliveSession(uint32_t sessionId)
{
StartTraceScope("HdcServerForClient::FindAliveSession");
HdcServer *ptrServer = (HdcServer *)clsServer;
HSession hSession = ptrServer->AdminSession(OP_QUERY, sessionId, nullptr);
if (!hSession || hSession->isDead) {
WRITE_LOG(LOG_FATAL, "FindAliveSession hSession nullptr or isDead sessionId:%s",
Hdc::MaskSessionIdToString(sessionId).c_str());
return nullptr;
} else {
return hSession;
}
}
bool HdcServerForClient::ChannelSendSessionCtrlMsg(vector<uint8_t> &ctrlMsg, uint32_t sessionId)
{
HSession hSession = FindAliveSession(sessionId);
if (!hSession) {
WRITE_LOG(LOG_FATAL, "ChannelSendSessionCtrlMsg hSession nullptr sessionId:%s",
Hdc::MaskSessionIdToString(sessionId).c_str());
return false;
}
int rc = Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrlMsg.data(), ctrlMsg.size());
if (rc <= 0) {
WRITE_LOG(LOG_FATAL, "send ctrlmsg failed sessionId:%s rc:%d",
Hdc::MaskSessionIdToString(sessionId).c_str(), rc);
}
return rc > 0;
}
void HdcServerForClient::PrintLastError(HChannel HChannel)
{
HdcServer *ptrServer = (HdcServer *)clsServer;
uint32_t errorCode = ptrServer->lastErrorNum;
if (errorCode > 0) {
string errorString = GetErrorString(errorCode);
EchoClient(HChannel, MSG_FAIL, "[E%06x]%s", errorCode, errorString.c_str());
ptrServer->lastErrorNum = 0;
}
}
string HdcServerForClient::GetErrorString(uint32_t errorCode)
{
auto map = ErrorStringEnglish.find(errorCode);
if (map != ErrorStringEnglish.end()) {
return map->second;
}
return ErrorStringEnglish.at(0xFFFFFF);
}
bool HdcServerForClient::CommandMatchDaemonFeature(uint16_t cmdFlag, const HDaemonInfo &hdi)
{
StartTraceScope("HdcServerForClient::CommandMatchDaemonFeature");
string cmdFlagStr = std::to_string(cmdFlag);
if (FEATURE_CHECK_SET.find(cmdFlag) == FEATURE_CHECK_SET.end()) {
return true;
}
auto tagMatch = hdi->daemonFeature.find(cmdFlagStr);
if (tagMatch == hdi->daemonFeature.end()) {
return false;
}
return (tagMatch->second == STR_FEATURE_ENABLE);
}
#ifdef __OHOS__
bool HdcServerForClient::IsNeedInterceptCommand()
{
std::string out;
SystemDepend::GetDevItem(SYS_PARAM_ENTERPRISE_HDC_DISABLE.c_str(), out);
if (out.empty() || out == "false") {
return false;
}
return true;
}
#endif
}