* 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.h"
#include "connect_validation.h"
#include "host_updater.h"
#include "runtime_config.h"
#include "server_cmd_log.h"
#include "subserver/subserver_manager.h"
namespace Hdc {
HdcServer::HdcServer(bool serverOrDaemonIn)
: HdcSessionBase(serverOrDaemonIn)
{
clsTCPClt = nullptr;
clsUSBClt = nullptr;
#ifdef HDC_SUPPORT_UART
clsUARTClt = nullptr;
#endif
clsServerForClient = nullptr;
lastErrorNum = 0;
uv_rwlock_init(&daemonAdmin);
uv_rwlock_init(&forwardAdmin);
}
HdcServer::~HdcServer()
{
WRITE_LOG(LOG_DEBUG, "~HdcServer");
uv_rwlock_destroy(&daemonAdmin);
uv_rwlock_destroy(&forwardAdmin);
}
void HdcServer::ClearInstanceResource()
{
TryStopInstance();
Base::TryCloseLoop(&loopMain, "HdcServer::~HdcServer");
if (clsTCPClt) {
delete clsTCPClt;
clsTCPClt = nullptr;
}
if (clsUSBClt) {
delete clsUSBClt;
clsUSBClt = nullptr;
}
#ifdef HDC_SUPPORT_UART
if (clsUARTClt) {
delete clsUARTClt;
clsUARTClt = nullptr;
}
#endif
if (clsServerForClient) {
delete (static_cast<HdcServerForClient *>(clsServerForClient));
}
}
void HdcServer::TryStopInstance()
{
ClearSessions();
if (clsTCPClt) {
clsTCPClt->Stop();
}
if (clsUSBClt) {
clsUSBClt->Stop();
}
#ifdef HDC_SUPPORT_UART
if (clsUARTClt) {
clsUARTClt->Stop();
}
#endif
if (clsServerForClient) {
((HdcServerForClient *)clsServerForClient)->Stop();
}
ReMainLoopForInstanceClear();
ClearMapDaemonInfo();
}
static bool InitialServerForClient(void* clsServerForClient)
{
int rc = (static_cast<HdcServerForClient *>(clsServerForClient))->Initial();
if (rc != RET_SUCCESS) {
WRITE_LOG(LOG_FATAL, "clsServerForClient Initial failed");
static constexpr int listenPortError = -3;
if (rc == listenPortError && RuntimeConfig::Instance().isSubserver) {
SubserverManager::ExitProcess(SubserverStatus::PORT_LISTEN_FAIL);
}
return false;
}
return true;
}
bool HdcServer::Initial(const char *listenString)
{
bool ret = false;
if (!RuntimeConfig::Instance().isSubserver && Base::ProgramMutex(false) != 0) {
WRITE_LOG(LOG_FATAL, "Other instance already running, program mutex failed");
return false;
}
Base::RemoveLogFile();
#ifdef HDC_SUPPORT_ENCRYPT_PRIVATE_KEY
if (!HdcAuth::CheckPrivateKeyFile()) {
WRITE_LOG(LOG_FATAL, "Private key file not found, please check your installation.");
return false;
}
#endif
do {
clsServerForClient = new HdcServerForClient(true, listenString, this, &loopMain);
if (!InitialServerForClient(clsServerForClient)) {
break;
}
HdcHostUSB::InitLogging(ctxUSB);
clsTCPClt = new HdcHostTCP(true, this);
clsUSBClt = new HdcHostUSB(true, this, ctxUSB);
if (clsUSBClt->Initial() != RET_SUCCESS) {
WRITE_LOG(LOG_FATAL, "clsUSBClt Initial failed");
break;
}
if (!clsServerForClient || !clsTCPClt || !clsUSBClt) {
WRITE_LOG(LOG_FATAL, "Class init failed");
break;
}
#ifdef HDC_SUPPORT_UART
clsUARTClt = new HdcHostUART(*this);
if (!clsUARTClt) {
WRITE_LOG(LOG_FATAL, "Class init failed");
break;
}
if (clsUARTClt->Initial() != RET_SUCCESS) {
WRITE_LOG(LOG_FATAL, "clsUARTClt Class init failed.");
break;
}
#endif
Base::ProcessCmdLogs();
ret = true;
} while (0);
if (!ret) {
ClearInstanceResource();
}
return ret;
}
bool HdcServer::PullupServerWin32(const char *path, const char *listenString)
{
bool retVal = false;
#ifdef _WIN32
char buf[BUF_SIZE_SMALL] = "";
char shortPath[MAX_PATH] = "";
std::string strPath = Base::UnicodeToUtf8(path, true);
int ret = GetShortPathName(strPath.c_str(), shortPath, MAX_PATH);
std::string runPath = shortPath;
if (ret == 0) {
int err = GetLastError();
constexpr int bufSize = 1024;
char buffer[bufSize] = { 0 };
strerror_s(buffer, bufSize, err);
if (Base::GetCaller() == Base::Caller::CLIENT) {
WRITE_LOG(LOG_WARN, "GetShortPath path:[%s] errmsg:%s", path, buffer);
} else {
WRITE_LOG(LOG_WARN, "GetShortPath path:[%s] errmsg:%s",
Hdc::MaskString(string(path)).c_str(), buffer);
}
string uvPath = path;
runPath = uvPath.substr(uvPath.find_last_of("/\\") + 1);
}
if (Base::GetCaller() == Base::Caller::CLIENT) {
WRITE_LOG(LOG_DEBUG, "server shortpath:[%s] runPath:[%s]", shortPath, runPath.c_str());
} else {
WRITE_LOG(LOG_DEBUG, "server shortpath:[%s] runPath:[%s]",
Hdc::MaskString(string(shortPath)).c_str(), Hdc::MaskString(runPath).c_str());
}
if (sprintf_s(buf, sizeof(buf), "dummy -l %d -s %s -m", Base::GetLogLevelByEnv(), listenString) < 0) {
return retVal;
}
if (Base::GetCaller() == Base::Caller::CLIENT) {
WRITE_LOG(LOG_DEBUG, "Run server in debug-forground, cmd:%s, args:%s", runPath.c_str(), buf);
} else {
WRITE_LOG(LOG_DEBUG, "Run server in debug-forground, cmd:%s, args:%s",
Hdc::MaskString(runPath).c_str(), Hdc::MaskString(string(buf)).c_str());
}
STARTUPINFO si = {};
si.cb = sizeof(STARTUPINFO);
PROCESS_INFORMATION pi = {};
#ifndef HDC_DEBUG
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
#endif
if (!CreateProcess(runPath.c_str(), buf, nullptr, nullptr, false, CREATE_NEW_CONSOLE, nullptr, nullptr, &si, &pi)) {
if (Base::GetCaller() == Base::Caller::SERVER) {
WRITE_LOG(LOG_WARN, "CreateProcess failed with cmd:%s, args:%s, Error Code %d",
Hdc::MaskString(runPath).c_str(), buf, GetLastError());
} else {
WRITE_LOG(LOG_WARN, "CreateProcess failed with cmd:%s, args:%s, Error Code %d",
runPath.c_str(), buf, GetLastError());
}
retVal = false;
} else {
retVal = true;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
#endif
return retVal;
}
bool HdcServer::PullupServer(const char *listenString)
{
char path[BUF_SIZE_SMALL] = "";
size_t nPathSize = sizeof(path);
int ret = uv_exepath(path, &nPathSize);
if (ret < 0) {
constexpr int bufSize = 1024;
char buf[bufSize] = { 0 };
uv_err_name_r(ret, buf, bufSize);
WRITE_LOG(LOG_WARN, "uvexepath ret:%d error:%s", ret, buf);
return false;
}
#if defined(FEATURE_HOST_LOG_COMPRESS) || defined(HOST_OHOS)
Base::CreateLogDir();
#endif
#ifdef _WIN32
if (!PullupServerWin32(path, listenString)) {
return false;
}
#else
pid_t pc = fork();
if (pc < 0) {
return false;
} else if (pc == 0) {
Base::CloseOpenFd();
Base::g_isBackgroundServer = true;
execl(path, "hdc", "-m", "-s", listenString, nullptr);
_exit(0);
}
#endif
uv_sleep(TIME_BASE);
return true;
}
void HdcServer::ClearMapDaemonInfo()
{
map<string, HDaemonInfo>::iterator iter;
uv_rwlock_rdlock(&daemonAdmin);
for (iter = mapDaemon.begin(); iter != mapDaemon.end();) {
HDaemonInfo hDi = iter->second;
delete hDi;
++iter;
}
uv_rwlock_rdunlock(&daemonAdmin);
uv_rwlock_wrlock(&daemonAdmin);
mapDaemon.clear();
uv_rwlock_wrunlock(&daemonAdmin);
}
void HdcServer::BuildDaemonVisableLine(HDaemonInfo hdi, bool fullDisplay, string &out)
{
if (fullDisplay) {
string sConn = conTypeDetail[CONN_UNKNOWN];
if (hdi->connType < CONN_UNKNOWN) {
sConn = conTypeDetail[hdi->connType];
}
string sStatus = conStatusDetail[STATUS_UNKNOW];
if (hdi->connStatus < STATUS_UNAUTH) {
if (hdi->connStatus == STATUS_CONNECTED && hdi->daemonAuthStatus == DAEOMN_UNAUTHORIZED) {
sStatus = conStatusDetail[STATUS_UNAUTH];
} else {
sStatus = conStatusDetail[hdi->connStatus];
}
}
string devname = hdi->devName;
if (devname.empty()) {
devname = "unknown...";
}
out = Base::StringFormat("%s\t\t%s\t%s\t%s\n", hdi->connectKey.c_str(), sConn.c_str(), sStatus.c_str(),
devname.c_str());
} else {
if (hdi->connStatus == STATUS_CONNECTED) {
out = Base::StringFormat("%s", hdi->connectKey.c_str());
if (hdi->daemonAuthStatus == DAEOMN_UNAUTHORIZED) {
out.append("\tUnauthorized");
}
out.append("\n");
}
}
}
string HdcServer::GetDaemonMapList(uint8_t opType)
{
string ret;
bool fullDisplay = false;
if (opType == OP_GET_STRLIST_FULL) {
fullDisplay = true;
}
uv_rwlock_rdlock(&daemonAdmin);
map<string, HDaemonInfo>::iterator iter;
string echoLine;
for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
HDaemonInfo di = iter->second;
if (!di) {
continue;
}
echoLine = "";
BuildDaemonVisableLine(di, fullDisplay, echoLine);
ret += echoLine;
}
uv_rwlock_rdunlock(&daemonAdmin);
return ret;
}
void HdcServer::GetDaemonMapOnlyOne(HDaemonInfo &hDaemonInfoInOut)
{
uv_rwlock_rdlock(&daemonAdmin);
string key;
for (auto &i : mapDaemon) {
if (i.second->connStatus == STATUS_CONNECTED) {
if (key == STRING_EMPTY) {
key = i.first;
} else {
key = STRING_EMPTY;
break;
}
}
}
if (key.size() > 0) {
hDaemonInfoInOut = mapDaemon[key];
}
uv_rwlock_rdunlock(&daemonAdmin);
}
void HdcServer::AdminDaemonMapForWait(const string &connectKey, HDaemonInfo &hDaemonInfoInOut)
{
map<string, HDaemonInfo>::iterator iter;
for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
HDaemonInfo di = iter->second;
if (di->connStatus == STATUS_CONNECTED) {
if (!connectKey.empty() && connectKey != di->connectKey) {
continue;
}
hDaemonInfoInOut = di;
return;
}
}
return;
}
string HdcServer::AdminDaemonMap(uint8_t opType, const string &connectKey, HDaemonInfo &hDaemonInfoInOut)
{
StartTraceScope("HdcServer::AdminDaemonMap");
string sRet;
switch (opType) {
case OP_ADD: {
HDaemonInfo pdiNew = new(std::nothrow) HdcDaemonInformation();
if (pdiNew == nullptr) {
WRITE_LOG(LOG_FATAL, "AdminDaemonMap new pdiNew failed");
break;
}
*pdiNew = *hDaemonInfoInOut;
uv_rwlock_wrlock(&daemonAdmin);
if (!mapDaemon[hDaemonInfoInOut->connectKey]) {
mapDaemon[hDaemonInfoInOut->connectKey] = pdiNew;
}
uv_rwlock_wrunlock(&daemonAdmin);
break;
}
case OP_GET_STRLIST:
case OP_GET_STRLIST_FULL: {
sRet = GetDaemonMapList(opType);
break;
}
case OP_QUERY: {
uv_rwlock_rdlock(&daemonAdmin);
if (mapDaemon.count(connectKey)) {
hDaemonInfoInOut = mapDaemon[connectKey];
}
uv_rwlock_rdunlock(&daemonAdmin);
break;
}
case OP_REMOVE: {
uv_rwlock_wrlock(&daemonAdmin);
if (mapDaemon.count(connectKey)) {
HDaemonInfo hDaemonInfo = mapDaemon[connectKey];
mapDaemon.erase(connectKey);
if (hDaemonInfo != nullptr) {
delete hDaemonInfo;
}
}
uv_rwlock_wrunlock(&daemonAdmin);
break;
}
case OP_GET_ANY: {
uv_rwlock_rdlock(&daemonAdmin);
map<string, HDaemonInfo>::iterator iter;
for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
HDaemonInfo di = iter->second;
if (di->connStatus == STATUS_READY || di->connStatus == STATUS_CONNECTED) {
hDaemonInfoInOut = di;
break;
}
}
uv_rwlock_rdunlock(&daemonAdmin);
break;
}
case OP_WAIT_FOR_ANY: {
uv_rwlock_rdlock(&daemonAdmin);
AdminDaemonMapForWait(connectKey, hDaemonInfoInOut);
uv_rwlock_rdunlock(&daemonAdmin);
break;
}
case OP_GET_ONLY: {
GetDaemonMapOnlyOne(hDaemonInfoInOut);
break;
}
case OP_UPDATE: {
uv_rwlock_wrlock(&daemonAdmin);
HDaemonInfo hdi = mapDaemon[hDaemonInfoInOut->connectKey];
if (hdi) {
*mapDaemon[hDaemonInfoInOut->connectKey] = *hDaemonInfoInOut;
}
uv_rwlock_wrunlock(&daemonAdmin);
break;
}
default:
break;
}
return sRet;
}
void HdcServer::NotifyInstanceSessionFree(HSession hSession, bool freeOrClear)
{
HDaemonInfo hdiOld = nullptr;
AdminDaemonMap(OP_QUERY, hSession->connectKey, hdiOld);
if (hdiOld == nullptr) {
WRITE_LOG(LOG_FATAL, "NotifyInstanceSessionFree hdiOld nullptr");
return;
}
if (!freeOrClear) {
HdcDaemonInformation diNew = *hdiOld;
diNew.inited = false;
diNew.connStatus = STATUS_OFFLINE;
diNew.hSession = nullptr;
HDaemonInfo hdiNew = &diNew;
AdminDaemonMap(OP_UPDATE, hSession->connectKey, hdiNew);
CleanForwardMap(hSession->sessionId);
}
}
void HdcServer::OnUSBDisconnectExit()
{
if (RuntimeConfig::Instance().isSubserver) {
SubserverManager::ExitProcess(SubserverStatus::USB_DISCONNECT);
}
}
void HdcServer::GetDaemonAuthType(HSession hSession, SessionHandShake &handshake)
{
* check if daemon support RSA_3072_SHA512 for auth
* it the value is not RSA_3072_SHA512, we use old auth algorithm
* Notice, If deamon is old version 'handshake.buf' will be 'hSession->tokenRSA',
* the length of hSession->tokenRSA less than min len(TLV_MIN_LEN), so there no
* problem
*/
std::map<string, string> tlvmap;
hSession->verifyType = AuthVerifyType::RSA_ENCRYPT;
std::string sessionIdMaskStr = Hdc::MaskSessionIdToString(hSession->sessionId);
if (!Base::TlvToStringMap(handshake.buf, tlvmap)) {
WRITE_LOG(LOG_INFO, "the deamon maybe old version for %s session, so use rsa encrypt",
sessionIdMaskStr.c_str());
return;
}
auto authIt = tlvmap.find(TAG_AUTH_TYPE);
if (authIt == tlvmap.end() || authIt->second != std::to_string(AuthVerifyType::RSA_3072_SHA512)) {
WRITE_LOG(LOG_FATAL, "the buf is invalid for %s session, so use rsa encrypt", sessionIdMaskStr.c_str());
return;
}
#ifdef HOST_OHOS
int connectValidationStatus = HdcValidation::GetConnectValidationParam();
if (connectValidationStatus == VALIDATION_HDC_HOST || connectValidationStatus == VALIDATION_HDC_HOST_AND_DAEMON) {
auto it = tlvmap.find(TAG_SUPPORT_FEATURE);
if (it != tlvmap.end()) {
std::vector<std::string> features;
WRITE_LOG(LOG_INFO, "peer support features are %s for session %u",
it->second.c_str(), sessionIdMaskStr.c_str());
Base::SplitString(it->second, ",", features);
hSession->supportConnValidation = Base::IsSupportFeature(features, FEATURE_CONN_VALIDATION);
}
}
#endif
hSession->verifyType = AuthVerifyType::RSA_3072_SHA512;
WRITE_LOG(LOG_INFO, "daemon auth type is rsa_3072_sha512 for %s session", sessionIdMaskStr.c_str());
}
bool HdcServer::HandleAuthPubkeyMsg(HSession hSession, SessionHandShake &handshake)
{
WRITE_LOG(LOG_INFO, "recive get publickey cmd");
GetDaemonAuthType(hSession, handshake);
int connectValidation = 0;
#ifdef HOST_OHOS
connectValidation = HdcValidation::GetConnectValidationParam();
WRITE_LOG(LOG_FATAL, "connectValidation %d", connectValidation);
#endif
if (connectValidation == VALIDATION_HDC_HOST || connectValidation == VALIDATION_HDC_HOST_AND_DAEMON) {
if (!HdcValidation::GetPublicKeyHashInfo(handshake.buf)) {
WRITE_LOG(LOG_FATAL, "load public key failed");
return false;
}
} else {
if (!HdcAuth::GetPublicKeyinfo(handshake.buf)) {
WRITE_LOG(LOG_FATAL, "load public key failed");
lastErrorNum = 0x000005;
return false;
}
}
handshake.authType = AUTH_PUBLICKEY;
string bufString = SerialStruct::SerializeToString(handshake);
Send(hSession->sessionId, 0, CMD_KERNEL_HANDSHAKE,
reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
WRITE_LOG(LOG_INFO, "send pubkey over");
return true;
}
bool HdcServer::HandleAuthSignatureMsg(HSession hSession, SessionHandShake &handshake)
{
int connectValidation = 0;
#ifdef HOST_OHOS
connectValidation = HdcValidation::GetConnectValidationParam();
#endif
if (connectValidation == VALIDATION_HDC_HOST || connectValidation == VALIDATION_HDC_HOST_AND_DAEMON) {
std::string pemStr;
HdcValidation::GetPrivateKeyInfo(pemStr);
if (!HdcValidation::RsaSignAndBase64(handshake.buf, hSession->verifyType, pemStr)) {
WRITE_LOG(LOG_FATAL, "sign failed");
return false;
}
} else {
if (!HdcAuth::RsaSignAndBase64(handshake.buf, hSession->verifyType)) {
WRITE_LOG(LOG_FATAL, "sign failed");
return false;
}
}
handshake.authType = AUTH_SIGNATURE;
string bufString = SerialStruct::SerializeToString(handshake);
Send(hSession->sessionId, 0, CMD_KERNEL_HANDSHAKE,
reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
WRITE_LOG(LOG_INFO, "response auth signture success");
return true;
}
bool HdcServer::HandServerAuth(HSession hSession, SessionHandShake &handshake)
{
switch (handshake.authType) {
case AUTH_PUBLICKEY: {
return HandleAuthPubkeyMsg(hSession, handshake);
}
case AUTH_SIGNATURE: {
return HandleAuthSignatureMsg(hSession, handshake);
}
#ifdef HDC_SUPPORT_ENCRYPT_TCP
case AUTH_SSL_TLS_PSK: {
if (hSession->classSSL == nullptr && !ServerSessionSSLInit(hSession, handshake)) {
WRITE_LOG(LOG_FATAL, "SSL init failed");
return false;
}
return ServerSSLHandshake(hSession, handshake);
}
#endif
default:
WRITE_LOG(LOG_FATAL, "invalid auth type %d", handshake.authType);
return false;
}
}
void HdcServer::UpdateHdiInfo(Hdc::HdcSessionBase::SessionHandShake &handshake, HSession &hSession)
{
HDaemonInfo hdiOld = nullptr;
if (hSession == nullptr) {
WRITE_LOG(LOG_FATAL, "Invalid paramter, hSession is null");
return;
}
AdminDaemonMap(OP_QUERY, hSession->connectKey, hdiOld);
if (!hdiOld) {
return;
}
HdcDaemonInformation diNew = *hdiOld;
HDaemonInfo hdiNew = &diNew;
hdiNew->inited = false;
hdiNew->connStatus = STATUS_CONNECTED;
WRITE_LOG(LOG_INFO, "handshake info is : %s", handshake.ToDebugString().c_str());
WRITE_LOG(LOG_INFO, "handshake.buf = %s", handshake.buf.c_str());
if (handshake.version < "Ver: 3.0.0b") {
if (!handshake.buf.empty()) {
hdiNew->devName = handshake.buf;
}
} else {
std::map<string, string> tlvmap;
if (Base::TlvToStringMap(handshake.buf, tlvmap)) {
if (tlvmap.find(TAG_DEVNAME) != tlvmap.end()) {
hdiNew->devName = tlvmap[TAG_DEVNAME];
if (Base::GetCaller() == Base::Caller::CLIENT) {
WRITE_LOG(LOG_INFO, "devname = %s", hdiNew->devName.c_str());
} else {
WRITE_LOG(LOG_INFO, "devname = %s", Hdc::MaskString(hdiNew->devName).c_str());
}
}
if (tlvmap.find(TAG_EMGMSG) != tlvmap.end()) {
hdiNew->emgmsg = tlvmap[TAG_EMGMSG];
WRITE_LOG(LOG_INFO, "emgmsg = %s", hdiNew->emgmsg.c_str());
}
if (tlvmap.find(TAG_DAEOMN_AUTHSTATUS) != tlvmap.end()) {
hdiNew->daemonAuthStatus = tlvmap[TAG_DAEOMN_AUTHSTATUS];
WRITE_LOG(LOG_INFO, "daemonauthstatus = %s", hdiNew->daemonAuthStatus.c_str());
}
if (tlvmap.find(TAG_FEATURE_SHELL_OPT) != tlvmap.end()) {
hdiNew->daemonFeature[TAG_FEATURE_SHELL_OPT] = tlvmap[TAG_FEATURE_SHELL_OPT];
WRITE_LOG(LOG_INFO, "shellOpt = %s", hdiNew->daemonFeature[TAG_FEATURE_SHELL_OPT].c_str());
}
ParsePeerSupportFeatures(hSession, tlvmap);
} else {
WRITE_LOG(LOG_FATAL, "TlvToStringMap failed");
}
}
hdiNew->version = handshake.version;
AdminDaemonMap(OP_UPDATE, hSession->connectKey, hdiNew);
}
#ifdef HDC_SUPPORT_ENCRYPT_TCP
bool HdcServer::ServerSSLHandshake(HSession hSession, SessionHandShake &handshake)
{
if (hSession->classSSL == nullptr) {
WRITE_LOG(LOG_DEBUG, "ssl is nullptr");
return false;
}
HdcSSLBase *hssl = static_cast<HdcSSLBase *>(hSession->classSSL);
if (hssl == nullptr) {
WRITE_LOG(LOG_WARN, "hssl is null");
return false;
}
if (handshake.buf.size() != 0) {
uint8_t *payload = reinterpret_cast<uint8_t*>(handshake.buf.data());
int payloadSize = handshake.buf.size();
int retw = hssl->DoBIOWrite(payload, payloadSize);
if (retw != payloadSize) {
WRITE_LOG(LOG_DEBUG, "BIO_write failed");
return false;
}
}
vector<uint8_t> buf;
int ret = hssl->PerformHandshake(buf);
if (ret == RET_SUCCESS) {
if (buf.size() == 0) {
WRITE_LOG(LOG_WARN, "SSL PerformHandshake failed, buffer data size is 0");
return false;
}
handshake.buf.assign(buf.begin(), buf.end());
string bufString = SerialStruct::SerializeToString(handshake);
Send(hSession->sessionId, 0, CMD_KERNEL_HANDSHAKE,
reinterpret_cast<uint8_t *>(const_cast<char *>(bufString.c_str())), bufString.size());
}
if (ret == RET_SSL_HANDSHAKE_FINISHED) {
hssl->SetHandshakeLabel(hSession);
WRITE_LOG(LOG_DEBUG, "ssl handshake finished, SetHandshakeLabel");
if (!hssl->ClearPsk()) {
WRITE_LOG(LOG_WARN, "clear Pre Shared Key failed");
ret = ERR_GENERIC;
}
}
fill(buf.begin(), buf.end(), 0);
return ret >= RET_SUCCESS;
}
bool HdcServer::ServerSessionSSLInit(HSession hSession, SessionHandShake &handshake)
{
WRITE_LOG(LOG_INFO, "ServerSession SSL Init");
int payloadSize = handshake.buf.size();
uint8_t *payload = reinterpret_cast<uint8_t*>(handshake.buf.data());
if (payloadSize < BUF_SIZE_PSK) {
WRITE_LOG(LOG_WARN, "Encrypted Pre-Shared-Key payloadSize is %d", payloadSize);
return false;
}
std::unique_ptr<unsigned char[]> out(std::make_unique<unsigned char[]>(BUF_SIZE_DEFAULT2));
if (!out) {
WRITE_LOG(LOG_WARN, "new buffer failed");
return false;
}
if (memset_s(out.get(), BUF_SIZE_DEFAULT2, 0, BUF_SIZE_DEFAULT2) != EOK) {
WRITE_LOG(LOG_WARN, "ServerSessionSSLInit memset_s failed");
return false;
}
SSLInfoPtr hSSLInfo = new (std::nothrow) HdcSSLInfo();
if (!hSSLInfo) {
WRITE_LOG(LOG_WARN, "new SSLInfoPtr failed");
return false;
}
HdcSSLBase::SetSSLInfo(hSSLInfo, hSession);
hSession->classSSL = new (std::nothrow) HdcHostSSL(hSSLInfo);
delete hSSLInfo;
HdcSSLBase *hssl = static_cast<HdcSSLBase *>(hSession->classSSL);
if (!hssl) {
WRITE_LOG(LOG_WARN, "new HdcHostSSL failed");
return false;
}
int outLen = hssl->RsaPrikeyDecrypt(reinterpret_cast<const unsigned char*>(payload),
payloadSize, out.get(), BUF_SIZE_DEFAULT2);
if (outLen <= 0) {
WRITE_LOG(LOG_WARN, "RsaPrivatekeyDecrypt failed, sid:%s",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
return false;
}
if (!hssl->InputPsk(out.get(), outLen)) {
WRITE_LOG(LOG_WARN, "InputPsk failed, sid:%s",
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
return false;
}
int initRet = hssl->InitSSL();
if (initRet != RET_SUCCESS) {
WRITE_LOG(LOG_WARN, "InitSSL failed");
return false;
}
handshake.buf.clear();
return true;
}
#endif
bool HdcServer::ServerSessionHandshake(HSession hSession, uint8_t *payload, int payloadSize)
{
string s = string(reinterpret_cast<char *>(payload), payloadSize);
Hdc::HdcSessionBase::SessionHandShake handshake;
SerialStruct::ParseFromString(handshake, s);
#ifdef HDC_DEBUG
WRITE_LOG(LOG_DEBUG, "handshake.banner:%s, payload:%s(%d)", handshake.banner.c_str(), s.c_str(), payloadSize);
#endif
if (handshake.banner == HANDSHAKE_FAILED.c_str()) {
WRITE_LOG(LOG_FATAL, "Handshake failed");
return false;
}
if (handshake.banner != HANDSHAKE_MESSAGE.c_str()) {
WRITE_LOG(LOG_DEBUG, "Hello failed");
return false;
}
if (handshake.authType != AUTH_OK) {
if (!HandServerAuth(hSession, handshake)) {
WRITE_LOG(LOG_WARN, "Auth failed");
return false;
}
return true;
}
UpdateHdiInfo(handshake, hSession);
hSession->handshakeOK = true;
return true;
}
bool HdcServer::FetchCommand(HSession hSession, const uint32_t channelId, const uint16_t command, uint8_t *payload,
const int payloadSize)
{
bool ret = true;
HdcServerForClient *sfc = static_cast<HdcServerForClient *>(clsServerForClient);
if (command == CMD_KERNEL_HANDSHAKE) {
ret = ServerSessionHandshake(hSession, payload, payloadSize);
WRITE_LOG(LOG_INFO, "Session handshake %s connType:%d sid:%s", ret ? "successful" : "failed",
hSession->connType, Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
return ret;
}
if (command == CMD_HEARTBEAT_MSG) {
std::string str = hSession->heartbeat.HandleRecvHeartbeatMsg(payload, payloadSize);
WRITE_LOG(LOG_INFO, "recv %s for session %s", str.c_str(),
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
return ret;
}
HChannel hChannel = sfc->AdminChannel(OP_QUERY_REF, channelId, nullptr);
if (!hChannel) {
if (command == CMD_KERNEL_CHANNEL_CLOSE) {
WRITE_LOG(LOG_WARN, "Die channelId :%lu recv CMD_KERNEL_CHANNEL_CLOSE", channelId);
} else {
WRITE_LOG(LOG_DEBUG, "channelId :%lu die", channelId);
}
uint8_t flag = 0;
Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &flag, 1);
return ret;
}
if (hChannel->isDead) {
WRITE_LOG(LOG_FATAL, "FetchCommand channelId:%u isDead", channelId);
uint8_t flag = 0;
Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &flag, 1);
--hChannel->ref;
return ret;
}
switch (command) {
case CMD_KERNEL_ECHO_RAW: {
sfc->EchoClientRaw(hChannel, payload, payloadSize);
break;
}
case CMD_KERNEL_ECHO: {
MessageLevel level = static_cast<MessageLevel>(*payload);
string s(reinterpret_cast<char *>(payload + 1), payloadSize - 1);
sfc->EchoClient(hChannel, level, s.c_str());
WRITE_LOG(LOG_INFO, "CMD_KERNEL_ECHO size:%d cid:%u sid:%s", payloadSize - 1, channelId,
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
break;
}
case CMD_KERNEL_CHANNEL_CLOSE: {
WRITE_LOG(LOG_INFO, "CMD_KERNEL_CHANNEL_CLOSE cid:%u sid:%s", channelId,
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
ClearOwnTasks(hSession, channelId);
sfc->PushAsyncMessage(channelId, ASYNC_FREE_CHANNEL, nullptr, 0);
if (*payload != 0) {
--(*payload);
Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, payload, 1);
}
break;
}
case CMD_FORWARD_SUCCESS: {
HdcForwardInformation di;
HForwardInfo pdiNew = &di;
pdiNew->channelId = channelId;
pdiNew->sessionId = hSession->sessionId;
pdiNew->connectKey = hSession->connectKey;
pdiNew->forwardDirection = (reinterpret_cast<char *>(payload))[0] == '1';
pdiNew->taskString = hSession->connectKey + "|" + reinterpret_cast<char *>(payload);
AdminForwardMap(OP_ADD, STRING_EMPTY, pdiNew);
#ifdef __OHOS__
if (hChannel->isUds) {
Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkUds);
} else {
Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP);
}
#else
Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP);
#endif
break;
}
case CMD_FILE_INIT:
case CMD_FILE_CHECK:
case CMD_FILE_BEGIN:
case CMD_FILE_DATA:
case CMD_FILE_FINISH:
case CMD_FILE_MODE:
case CMD_DIR_MODE:
case CMD_APP_INIT:
case CMD_APP_CHECK:
case CMD_APP_BEGIN:
case CMD_APP_DATA:
case CMD_APP_FINISH:
if (hChannel->fromClient) {
sfc->SendCommandToClient(hChannel, command, payload, payloadSize);
break;
}
default: {
HSession hSessionByQuery = AdminSession(OP_QUERY, hChannel->targetSessionId, nullptr);
if (!hSessionByQuery) {
ret = false;
break;
}
ret = DispatchTaskData(hSessionByQuery, channelId, command, payload, payloadSize);
break;
}
}
--hChannel->ref;
return ret;
}
void HdcServer::BuildForwardVisableLine(bool fullOrSimble, HForwardInfo hfi, string &echo)
{
string buf;
if (fullOrSimble) {
std::string taskString = hfi->taskString;
size_t pos = taskString.rfind("|");
if (pos != std::string::npos && pos + 1 < taskString.length()) {
taskString = taskString.substr(pos + 1);
} else {
WRITE_LOG(LOG_WARN, "Invalid taskString %s", Hdc::MaskString(taskString).c_str());
return;
}
buf = Base::StringFormat("%s %s %s\n", hfi->connectKey.c_str(), taskString.c_str(),
hfi->forwardDirection ? "[Forward]" : "[Reverse]");
} else {
buf = Base::StringFormat("%s\n", hfi->taskString.c_str());
}
echo += buf;
}
string HdcServer::AdminForwardMap(uint8_t opType, const string &taskString, HForwardInfo &hForwardInfoInOut)
{
string sRet;
switch (opType) {
case OP_ADD: {
HForwardInfo pfiNew = new(std::nothrow) HdcForwardInformation();
if (pfiNew == nullptr) {
WRITE_LOG(LOG_FATAL, "AdminForwardMap new pfiNew failed");
break;
}
*pfiNew = *hForwardInfoInOut;
uv_rwlock_wrlock(&forwardAdmin);
if (!mapForward[hForwardInfoInOut->taskString]) {
mapForward[hForwardInfoInOut->taskString] = pfiNew;
}
uv_rwlock_wrunlock(&forwardAdmin);
break;
}
case OP_GET_STRLIST:
case OP_GET_STRLIST_FULL: {
uv_rwlock_rdlock(&forwardAdmin);
map<string, HForwardInfo>::iterator iter;
for (iter = mapForward.begin(); iter != mapForward.end(); ++iter) {
HForwardInfo di = iter->second;
if (!di) {
continue;
}
BuildForwardVisableLine(opType == OP_GET_STRLIST_FULL, di, sRet);
}
uv_rwlock_rdunlock(&forwardAdmin);
break;
}
case OP_QUERY: {
uv_rwlock_rdlock(&forwardAdmin);
if (mapForward.count(taskString)) {
hForwardInfoInOut = mapForward[taskString];
}
uv_rwlock_rdunlock(&forwardAdmin);
break;
}
case OP_REMOVE: {
uv_rwlock_wrlock(&forwardAdmin);
if (mapForward.count(taskString)) {
HForwardInfo hForwardInfo = mapForward[taskString];
mapForward.erase(taskString);
if (hForwardInfo != nullptr) {
delete hForwardInfo;
}
}
uv_rwlock_wrunlock(&forwardAdmin);
break;
}
default:
break;
}
return sRet;
}
void HdcServer::CleanForwardMap(uint32_t sessionId)
{
uv_rwlock_wrlock(&forwardAdmin);
map<string, HForwardInfo>::iterator iter;
for (iter = mapForward.begin(); iter != mapForward.end();) {
HForwardInfo di = iter->second;
if (!di) {
continue;
}
if (sessionId == 0 || sessionId == di->sessionId) {
iter = mapForward.erase(iter);
} else {
iter++;
}
}
uv_rwlock_wrunlock(&forwardAdmin);
}
void HdcServer::UsbPreConnect(uv_timer_t *handle)
{
HSession hSession = (HSession)handle->data;
bool stopLoop = false;
HdcServer *hdcServer = (HdcServer *)hSession->classInstance;
CALLSTAT_GUARD(hdcServer->loopMainStatus, handle->loop, "HdcServer::UsbPreConnect");
while (true) {
WRITE_LOG(LOG_DEBUG, "HdcServer::UsbPreConnect");
HDaemonInfo pDi = nullptr;
if (hSession->connectKey == "any") {
hdcServer->AdminDaemonMap(OP_GET_ANY, hSession->connectKey, pDi);
} else {
hdcServer->AdminDaemonMap(OP_QUERY, hSession->connectKey, pDi);
}
if (!pDi || !pDi->usbMountPoint.size()) {
break;
}
HdcHostUSB *hdcHostUSB = (HdcHostUSB *)hSession->classModule;
hdcHostUSB->ConnectDetectDaemon(hSession, pDi);
stopLoop = true;
break;
}
if (stopLoop && !uv_is_closing((const uv_handle_t *)handle)) {
uv_close((uv_handle_t *)handle, Base::CloseTimerCallback);
}
}
#ifdef HDC_SUPPORT_UART
void HdcServer::UartPreConnect(uv_timer_t *handle)
{
WRITE_LOG(LOG_DEBUG, "%s", __FUNCTION__);
HSession hSession = (HSession)handle->data;
bool stopLoop = false;
HdcServer *hdcServer = (HdcServer *)hSession->classInstance;
const int uartConnectRetryMax = 100;
while (true) {
if (hSession->hUART->retryCount > uartConnectRetryMax) {
WRITE_LOG(LOG_DEBUG, "%s failed because max retry limit %d", __FUNCTION__,
hSession->hUART->retryCount);
hdcServer->FreeSession(hSession->sessionId);
stopLoop = true;
break;
}
hSession->hUART->retryCount++;
HDaemonInfo pDi = nullptr;
WRITE_LOG(LOG_DEBUG, "%s query %s", __FUNCTION__, hSession->ToDebugString().c_str());
hdcServer->AdminDaemonMap(OP_QUERY, hSession->connectKey, pDi);
if (!pDi) {
WRITE_LOG(LOG_DEBUG, "%s not found", __FUNCTION__);
break;
}
HdcHostUART *hdcHostUART = (HdcHostUART *)hSession->classModule;
hdcHostUART->ConnectDaemonByUart(hSession, pDi);
WRITE_LOG(LOG_DEBUG, "%s ConnectDaemonByUart done", __FUNCTION__);
stopLoop = true;
break;
}
if (stopLoop) {
uv_close((uv_handle_t *)handle, Base::CloseTimerCallback);
}
}
void HdcServer::CreatConnectUart(HSession hSession)
{
uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
if (waitTimeDoCmd == nullptr) {
WRITE_LOG(LOG_FATAL, "CreatConnectUart new waitTimeDoCmd failed");
return;
}
uv_timer_init(&loopMain, waitTimeDoCmd);
waitTimeDoCmd->data = hSession;
uv_timer_start(waitTimeDoCmd, UartPreConnect, UV_TIMEOUT, UV_REPEAT);
}
#endif
int HdcServer::CreateConnect(const string &connectKey, bool isCheck)
{
uint8_t connType = 0;
if (connectKey.find(":") != std::string::npos) {
connType = CONN_TCP;
}
#ifdef HDC_SUPPORT_UART
else if (connectKey.find("COM") == 0 ||
connectKey.find("/dev/ttyUSB") == 0 ||
connectKey.find("/dev/cu.") == 0) {
connType = CONN_SERIAL;
}
#endif
else {
return ERR_NO_SUPPORT;
}
HDaemonInfo hdi = nullptr;
if (connectKey == "any") {
return RET_SUCCESS;
}
AdminDaemonMap(OP_QUERY, connectKey, hdi);
if (hdi == nullptr) {
HdcDaemonInformation di = {};
di.connectKey = connectKey;
di.connType = connType;
di.connStatus = STATUS_UNKNOW;
di.inited = false;
HDaemonInfo pDi = reinterpret_cast<HDaemonInfo>(&di);
AdminDaemonMap(OP_ADD, "", pDi);
AdminDaemonMap(OP_QUERY, connectKey, hdi);
}
if (!hdi || hdi->connStatus == STATUS_CONNECTED) {
WRITE_LOG(LOG_FATAL, "Connected return");
return ERR_GENERIC;
}
if (hdi->inited == true) {
WRITE_LOG(LOG_FATAL, "Connection is inited");
return ERR_GENERIC;
}
HSession hSession = nullptr;
if (connType == CONN_TCP) {
hSession = clsTCPClt->ConnectDaemon(connectKey, isCheck);
} else if (connType == CONN_SERIAL) {
#ifdef HDC_SUPPORT_UART
clsUARTClt->SetCheckFlag(isCheck);
hSession = clsUARTClt->ConnectDaemon(connectKey);
#endif
} else {
hSession = MallocSession(true, CONN_USB, clsUSBClt);
if (!hSession) {
WRITE_LOG(LOG_FATAL, "CreateConnect malloc usb session failed %s", Hdc::MaskString(connectKey).c_str());
return ERR_BUF_ALLOC;
}
hSession->connectKey = connectKey;
uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t;
if (waitTimeDoCmd == nullptr) {
WRITE_LOG(LOG_FATAL, "CreateConnect new waitTimeDoCmd failed");
FreeSession(hSession->sessionId);
return ERR_GENERIC;
}
uv_timer_init(&loopMain, waitTimeDoCmd);
waitTimeDoCmd->data = hSession;
uv_timer_start(waitTimeDoCmd, UsbPreConnect, UV_TIMEOUT, UV_REPEAT);
}
if (!hSession) {
WRITE_LOG(LOG_FATAL, "CreateConnect hSession nullptr");
return ERR_BUF_ALLOC;
}
HDaemonInfo hdiQuery = nullptr;
AdminDaemonMap(OP_QUERY, connectKey, hdiQuery);
if (hdiQuery) {
HdcDaemonInformation diNew = *hdiQuery;
diNew.hSession = hSession;
diNew.inited = true;
HDaemonInfo hdiNew = &diNew;
AdminDaemonMap(OP_UPDATE, hdiQuery->connectKey, hdiNew);
}
return RET_SUCCESS;
}
#ifdef HOST_OHOS
void HdcServer::AttachChannelInnerForUds(HSession hSession, const uint32_t channelId)
{
int ret = 0;
HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
HChannel hChannel = hSfc->AdminChannel(OP_QUERY_REF, channelId, nullptr);
if (!hChannel) {
WRITE_LOG(LOG_DEBUG, "AttachChannelInnerForUds hChannel null channelId:%u", channelId);
return;
}
uv_pipe_init(&hSession->childLoop, &hChannel->hChildWorkUds, 0);
hChannel->hChildWorkUds.data = hChannel;
hChannel->loopStatus = &hSession->childLoopStatus;
hChannel->targetSessionId = hSession->sessionId;
hSession->commandCount++;
if ((ret = uv_pipe_open((uv_pipe_t *)&hChannel->hChildWorkUds, hChannel->fdChildWorkTCP)) < 0) {
constexpr int bufSize = 1024;
char buf[bufSize] = { 0 };
uv_err_name_r(ret, buf, bufSize);
WRITE_LOG(LOG_WARN, "Hdcserver AttachChannel uv_tcp_open failed %s, channelid:%d fdChildWorkTCP:%d",
buf, hChannel->channelId, hChannel->fdChildWorkTCP);
Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkUds);
--hChannel->ref;
return;
}
Base::SetUdsOptions((uv_pipe_t *)&hChannel->hChildWorkUds);
uv_read_start((uv_stream_t *)&hChannel->hChildWorkUds, hSfc->AllocCallback, hSfc->ReadStream);
--hChannel->ref;
WRITE_LOG(LOG_INFO, "AttachChannelInnerForUds");
};
void HdcServer::DetachChannelInnerForUds(HSession hSession, const uint32_t channelId)
{
HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr);
if (!hChannel) {
ClearOwnTasks(hSession, channelId);
uint8_t count = 0;
Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
WRITE_LOG(LOG_WARN, "DetachChannelInnerForUds hChannel null channelId:%u", channelId);
return;
}
if (hChannel->childCleared) {
WRITE_LOG(LOG_DEBUG, "Childchannel has already freed, cid:%u", channelId);
return;
}
ClearOwnTasks(hSession, channelId);
uint8_t count = 0;
Send(hSession->sessionId, hChannel->channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
WRITE_LOG(LOG_DEBUG, "Childchannel begin close, cid:%u, sid:%s", hChannel->channelId,
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
if (uv_is_closing((const uv_handle_t *)&hChannel->hChildWorkUds)) {
Base::DoNextLoop(&hSession->childLoop, hChannel, [](const uint8_t flag, string &msg, const void *data) {
HChannel hChannel = (HChannel)data;
hChannel->childCleared = true;
WRITE_LOG(LOG_DEBUG, "Childchannel free direct, cid:%u", hChannel->channelId);
});
} else {
if (hChannel->hChildWorkUds.loop == NULL) {
WRITE_LOG(LOG_DEBUG, "Childchannel loop is null, cid:%u", hChannel->channelId);
}
Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkUds, [](uv_handle_t *handle) -> void {
HChannel hChannel = (HChannel)handle->data;
hChannel->childCleared = true;
WRITE_LOG(LOG_DEBUG, "Childchannel free callback, cid:%u", hChannel->channelId);
});
}
};
void HdcServer::AttachChannel(HSession hSession, const uint32_t channelId)
{
HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
if (hSfc == nullptr) {
WRITE_LOG(LOG_DEBUG, "HdcServerForClient is null");
return;
}
HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr);
if (!hChannel) {
WRITE_LOG(LOG_DEBUG, "AttachChannel hChannel null channelId:%u", channelId);
return;
}
if (hChannel->isUds) {
AttachChannelInnerForUds(hSession, channelId);
} else {
AttachChannelInnerForTcp(hSession, channelId);
}
}
void HdcServer::DetachChannel(HSession hSession, const uint32_t channelId)
{
HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
if (hSfc == nullptr) {
WRITE_LOG(LOG_DEBUG, "HdcServerForClient is null");
return;
}
HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr);
if (!hChannel) {
ClearOwnTasks(hSession, channelId);
uint8_t count = 0;
Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
WRITE_LOG(LOG_WARN, "DetachChannel hChannel null channelId:%u", channelId);
return;
}
if (hChannel->childCleared) {
WRITE_LOG(LOG_DEBUG, "Childchannel has already freed, cid:%u", channelId);
return;
}
if (hChannel->isUds) {
DetachChannelInnerForUds(hSession, channelId);
} else {
DetachChannelInnerForTcp(hSession, channelId);
}
}
#else
void HdcServer::AttachChannel(HSession hSession, const uint32_t channelId)
{
AttachChannelInnerForTcp(hSession, channelId);
}
void HdcServer::DetachChannel(HSession hSession, const uint32_t channelId)
{
DetachChannelInnerForTcp(hSession, channelId);
}
#endif
void HdcServer::AttachChannelInnerForTcp(HSession hSession, const uint32_t channelId)
{
int ret = 0;
HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
HChannel hChannel = hSfc->AdminChannel(OP_QUERY_REF, channelId, nullptr);
if (!hChannel) {
WRITE_LOG(LOG_DEBUG, "AttachChannel hChannel null channelId:%u", channelId);
return;
}
uv_tcp_init(&hSession->childLoop, &hChannel->hChildWorkTCP);
hChannel->hChildWorkTCP.data = hChannel;
hChannel->loopStatus = &hSession->childLoopStatus;
hChannel->targetSessionId = hSession->sessionId;
hSession->commandCount++;
if ((ret = uv_tcp_open((uv_tcp_t *)&hChannel->hChildWorkTCP, hChannel->fdChildWorkTCP)) < 0) {
constexpr int bufSize = 1024;
char buf[bufSize] = { 0 };
uv_err_name_r(ret, buf, bufSize);
WRITE_LOG(LOG_WARN, "Hdcserver AttachChannel uv_tcp_open failed %s, channelid:%d fdChildWorkTCP:%d",
buf, hChannel->channelId, hChannel->fdChildWorkTCP);
Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP);
--hChannel->ref;
return;
}
Base::SetTcpOptions((uv_tcp_t *)&hChannel->hChildWorkTCP);
uv_read_start((uv_stream_t *)&hChannel->hChildWorkTCP, hSfc->AllocCallback, hSfc->ReadStream);
--hChannel->ref;
};
void HdcServer::DetachChannelInnerForTcp(HSession hSession, const uint32_t channelId)
{
HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr);
if (!hChannel) {
ClearOwnTasks(hSession, channelId);
uint8_t count = 0;
Send(hSession->sessionId, channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
WRITE_LOG(LOG_WARN, "DetachChannel hChannel null channelId:%u", channelId);
return;
}
if (hChannel->childCleared) {
WRITE_LOG(LOG_DEBUG, "Childchannel has already freed, cid:%u", channelId);
return;
}
ClearOwnTasks(hSession, channelId);
uint8_t count = 0;
Send(hSession->sessionId, hChannel->channelId, CMD_KERNEL_CHANNEL_CLOSE, &count, 1);
WRITE_LOG(LOG_DEBUG, "Childchannel begin close, cid:%u, sid:%s", hChannel->channelId,
Hdc::MaskSessionIdToString(hSession->sessionId).c_str());
if (uv_is_closing((const uv_handle_t *)&hChannel->hChildWorkTCP)) {
Base::DoNextLoop(&hSession->childLoop, hChannel, [](const uint8_t flag, string &msg, const void *data) {
HChannel hChannel = (HChannel)data;
hChannel->childCleared = true;
WRITE_LOG(LOG_DEBUG, "Childchannel free direct, cid:%u", hChannel->channelId);
});
} else {
if (hChannel->hChildWorkTCP.loop == NULL) {
WRITE_LOG(LOG_DEBUG, "Childchannel loop is null, cid:%u", hChannel->channelId);
}
Base::TryCloseHandle((uv_handle_t *)&hChannel->hChildWorkTCP, [](uv_handle_t *handle) -> void {
HChannel hChannel = (HChannel)handle->data;
hChannel->childCleared = true;
WRITE_LOG(LOG_DEBUG, "Childchannel free callback, cid:%u", hChannel->channelId);
});
}
};
bool HdcServer::ServerCommand(const uint32_t sessionId, const uint32_t channelId, const uint16_t command,
uint8_t *bufPtr, const int size)
{
HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
HChannel hChannel = hSfc->AdminChannel(OP_QUERY, channelId, nullptr);
HSession hSession = AdminSession(OP_QUERY, sessionId, nullptr);
if (!hChannel || !hSession) {
return false;
}
return FetchCommand(hSession, channelId, command, bufPtr, size);
}
bool HdcServer::RedirectToTask(HTaskInfo hTaskInfo, HSession , const uint32_t ,
const uint16_t command, uint8_t *payload, const int payloadSize)
{
bool ret = true;
hTaskInfo->ownerSessionClass = this;
switch (command) {
case CMD_UNITY_BUGREPORT_INIT:
case CMD_UNITY_BUGREPORT_DATA:
ret = TaskCommandDispatch<HdcHostUnity>(hTaskInfo, TYPE_UNITY, command, payload, payloadSize);
break;
case CMD_FILE_INIT:
case CMD_FILE_BEGIN:
case CMD_FILE_CHECK:
case CMD_FILE_DATA:
case CMD_FILE_FINISH:
case CMD_FILE_MODE:
case CMD_DIR_MODE:
ret = TaskCommandDispatch<HdcFile>(hTaskInfo, TASK_FILE, command, payload, payloadSize);
break;
case CMD_FORWARD_INIT:
case CMD_FORWARD_CHECK:
case CMD_FORWARD_CHECK_RESULT:
case CMD_FORWARD_ACTIVE_MASTER:
case CMD_FORWARD_ACTIVE_SLAVE:
case CMD_FORWARD_DATA:
case CMD_FORWARD_FREE_CONTEXT:
ret = TaskCommandDispatch<HdcHostForward>(hTaskInfo, TASK_FORWARD, command, payload, payloadSize);
break;
case CMD_APP_INIT:
case CMD_APP_SIDELOAD:
case CMD_APP_BEGIN:
case CMD_APP_FINISH:
case CMD_APP_UNINSTALL:
ret = TaskCommandDispatch<HdcHostApp>(hTaskInfo, TASK_APP, command, payload, payloadSize);
break;
case CMD_FLASHD_UPDATE_INIT:
case CMD_FLASHD_FLASH_INIT:
case CMD_FLASHD_CHECK:
case CMD_FLASHD_BEGIN:
case CMD_FLASHD_DATA:
case CMD_FLASHD_FINISH:
case CMD_FLASHD_ERASE:
case CMD_FLASHD_FORMAT:
case CMD_FLASHD_PROGRESS:
ret = TaskCommandDispatch<HostUpdater>(hTaskInfo, TASK_FLASHD, command, payload, payloadSize);
break;
default:
break;
}
return ret;
}
bool HdcServer::RemoveInstanceTask(const uint8_t op, HTaskInfo hTask)
{
bool ret = true;
switch (hTask->taskType) {
case TYPE_SHELL:
WRITE_LOG(LOG_DEBUG, "Server not enable unity/shell");
break;
case TYPE_UNITY:
ret = DoTaskRemove<HdcHostUnity>(hTask, op);
break;
case TASK_FILE:
ret = DoTaskRemove<HdcFile>(hTask, op);
break;
case TASK_FORWARD:
ret = DoTaskRemove<HdcHostForward>(hTask, op);
break;
case TASK_APP:
ret = DoTaskRemove<HdcHostApp>(hTask, op);
break;
case TASK_FLASHD:
ret = DoTaskRemove<HostUpdater>(hTask, op);
break;
default:
ret = false;
break;
}
return ret;
}
void HdcServer::EchoToClientsForSession(uint32_t targetSessionId, const string &echo)
{
HdcServerForClient *hSfc = static_cast<HdcServerForClient *>(clsServerForClient);
WRITE_LOG(LOG_INFO, "%s:%u %s", __FUNCTION__, targetSessionId, echo.c_str());
hSfc->EchoToAllChannelsViaSessionId(targetSessionId, echo);
}
void HdcServer::PrintCmdLogEx(const string& cmdStr)
{
if (cmdStr.empty()) {
return;
}
Hdc::ServerCmdLog::GetInstance().PushCmdLogStr(cmdStr);
}
#ifdef HOST_OHOS
void HdcServer::SessionSoftReset()
{
uv_rwlock_rdlock(&daemonAdmin);
map<string, HDaemonInfo>::iterator iter;
for (iter = mapDaemon.begin(); iter != mapDaemon.end(); ++iter) {
HDaemonInfo di = iter->second;
if (di == nullptr) {
continue;
}
string devname = di->devName;
if (devname.empty()) {
continue;
}
if (di->connType == CONN_USB) {
HSession hSession = di->hSession;
if (hSession == nullptr) {
continue;
}
clsUSBClt->SendSoftResetToDaemon(hSession, 0);
}
}
uv_rwlock_rdunlock(&daemonAdmin);
}
#endif
}