• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "forward.h"
16 #include "base.h"
17 
18 namespace Hdc {
HdcForwardBase(HTaskInfo hTaskInfo)19 HdcForwardBase::HdcForwardBase(HTaskInfo hTaskInfo)
20     : HdcTaskBase(hTaskInfo)
21 {
22     fds[0] = -1;
23     fds[1] = -1;
24 }
25 
~HdcForwardBase()26 HdcForwardBase::~HdcForwardBase()
27 {
28     WRITE_LOG(LOG_DEBUG, "~HdcForwardBase channelId:%u", taskInfo->channelId);
29 };
30 
ReadyForRelease()31 bool HdcForwardBase::ReadyForRelease()
32 {
33     if (!HdcTaskBase::ReadyForRelease()) {
34         WRITE_LOG(LOG_WARN, "not ready for release channelId:%u", taskInfo->channelId);
35         return false;
36     }
37     return true;
38 }
39 
StopTask()40 void HdcForwardBase::StopTask()
41 {
42     ctxPointMutex.lock();
43     vector<HCtxForward> ctxs;
44     map<uint32_t, HCtxForward>::iterator iter;
45     for (iter = mapCtxPoint.begin(); iter != mapCtxPoint.end(); ++iter) {
46         HCtxForward ctx = iter->second;
47         ctxs.push_back(ctx);
48     }
49     // FREECONTEXT in the STOP is triggered by the other party sector, no longer notifying each other.
50     mapCtxPoint.clear();
51     ctxPointMutex.unlock();
52     for (auto ctx: ctxs) {
53         FreeContext(ctx, 0, false);
54     }
55 }
56 
OnAccept(uv_stream_t * server,HCtxForward ctxClient,uv_stream_t * client)57 void HdcForwardBase::OnAccept(uv_stream_t *server, HCtxForward ctxClient, uv_stream_t *client)
58 {
59     HCtxForward ctxListen = (HCtxForward)server->data;
60     char buf[BUF_SIZE_DEFAULT] = { 0 };
61     bool ret = false;
62     while (true) {
63         if (uv_accept(server, client)) {
64             WRITE_LOG(LOG_FATAL, "uv_accept id:%u type:%d remoteParamenters:%s",
65                 ctxListen->id, ctxListen->type, ctxListen->remoteParamenters.c_str());
66             break;
67         }
68         ctxClient->type = ctxListen->type;
69         ctxClient->remoteParamenters = ctxListen->remoteParamenters;
70         int maxSize = sizeof(buf) - forwardParameterBufSize;
71         // clang-format off
72         if (snprintf_s(buf + forwardParameterBufSize, maxSize, maxSize - 1, "%s",
73                        ctxClient->remoteParamenters.c_str()) < 0) {
74             break;
75         }
76         WRITE_LOG(LOG_DEBUG, "OnAccept id:%u type:%d remoteParamenters:%s",
77             ctxClient->id, ctxClient->type, ctxClient->remoteParamenters.c_str());
78         SendToTask(ctxClient->id, CMD_FORWARD_ACTIVE_SLAVE, reinterpret_cast<uint8_t *>(buf),
79                    strlen(buf + forwardParameterBufSize) + 9); // 9: pre 8bytes preserve for param bits
80         ret = true;
81         break;
82     }
83     if (!ret) {
84         FreeContext(ctxClient, 0, false);
85     }
86 }
87 
ListenCallback(uv_stream_t * server,const int status)88 void HdcForwardBase::ListenCallback(uv_stream_t *server, const int status)
89 {
90     HCtxForward ctxListen = (HCtxForward)server->data;
91     HdcForwardBase *thisClass = ctxListen->thisClass;
92     uv_stream_t *client = nullptr;
93 
94     if (status == -1 || !ctxListen->ready) {
95         WRITE_LOG(LOG_FATAL, "ListenCallback status:%d id:%u ready:%d",
96             status, ctxListen->id, ctxListen->ready);
97         thisClass->FreeContext(ctxListen, 0, false);
98         thisClass->TaskFinish();
99         return;
100     }
101     HCtxForward ctxClient = (HCtxForward)thisClass->MallocContext(true);
102     if (!ctxClient) {
103         return;
104     }
105     if (ctxListen->type == FORWARD_TCP) {
106         uv_tcp_init(ctxClient->thisClass->loopTask, &ctxClient->tcp);
107         client = (uv_stream_t *)&ctxClient->tcp;
108     } else {
109         // FORWARD_ABSTRACT, FORWARD_RESERVED, FORWARD_FILESYSTEM,
110         uv_pipe_init(ctxClient->thisClass->loopTask, &ctxClient->pipe, 0);
111         client = (uv_stream_t *)&ctxClient->pipe;
112     }
113     thisClass->OnAccept(server, ctxClient, client);
114 }
115 
MallocContext(bool masterSlave)116 void *HdcForwardBase::MallocContext(bool masterSlave)
117 {
118     HCtxForward ctx = nullptr;
119     if ((ctx = new ContextForward()) == nullptr) {
120         return nullptr;
121     }
122     ctx->id = Base::GetRuntimeMSec();
123     ctx->masterSlave = masterSlave;
124     ctx->thisClass = this;
125     ctx->fdClass = nullptr;
126     ctx->tcp.data = ctx;
127     ctx->pipe.data = ctx;
128     AdminContext(OP_ADD, ctx->id, ctx);
129     refCount++;
130     return ctx;
131 }
132 
FreeContextCallBack(HCtxForward ctx)133 void HdcForwardBase::FreeContextCallBack(HCtxForward ctx)
134 {
135     Base::DoNextLoop(loopTask, ctx, [this](const uint8_t flag, string &msg, const void *data) {
136         HCtxForward ctx = (HCtxForward)data;
137         AdminContext(OP_REMOVE, ctx->id, nullptr);
138         if (ctx != nullptr) {
139             WRITE_LOG(LOG_DEBUG, "Finally to delete id:%u", ctx->id);
140             delete ctx;
141             ctx = nullptr;
142         }
143         if (refCount > 0) {
144             --refCount;
145         }
146     });
147 }
148 
FreeJDWP(HCtxForward ctx)149 void HdcForwardBase::FreeJDWP(HCtxForward ctx)
150 {
151     Base::CloseFd(ctx->fd);
152     if (ctx->fdClass) {
153         ctx->fdClass->StopWorkOnThread(false, nullptr);
154 
155         auto funcReqClose = [](uv_idle_t *handle) -> void {
156             uv_close_cb funcIdleHandleClose = [](uv_handle_t *handle) -> void {
157                 HCtxForward ctx = (HCtxForward)handle->data;
158                 ctx->thisClass->FreeContextCallBack(ctx);
159                 delete (uv_idle_t *)handle;
160             };
161             HCtxForward context = (HCtxForward)handle->data;
162             if (context->fdClass->ReadyForRelease()) {
163                 delete context->fdClass;
164                 context->fdClass = nullptr;
165                 Base::TryCloseHandle((uv_handle_t *)handle, funcIdleHandleClose);
166             }
167         };
168         Base::IdleUvTask(loopTask, ctx, funcReqClose);
169     }
170 }
171 
FreeContext(HCtxForward ctxIn,const uint32_t id,bool bNotifyRemote)172 void HdcForwardBase::FreeContext(HCtxForward ctxIn, const uint32_t id, bool bNotifyRemote)
173 {
174     WRITE_LOG(LOG_DEBUG, "FreeContext id:%u, bNotifyRemote:%d", id, bNotifyRemote);
175     std::lock_guard<std::mutex> lock(ctxFreeMutex);
176     HCtxForward ctx = nullptr;
177     if (!ctxIn) {
178         if (!(ctx = (HCtxForward)AdminContext(OP_QUERY, id, nullptr))) {
179             WRITE_LOG(LOG_DEBUG, "Query id:%u failed", id);
180             return;
181         }
182     } else {
183         ctx = ctxIn;
184     }
185     if (ctx->finish) {
186         return;
187     }
188     if (bNotifyRemote) {
189         SendToTask(ctx->id, CMD_FORWARD_FREE_CONTEXT, nullptr, 0);
190     }
191     uv_close_cb funcHandleClose = [](uv_handle_t *handle) -> void {
192         HCtxForward ctx = (HCtxForward)handle->data;
193         ctx->thisClass->FreeContextCallBack(ctx);
194     };
195     switch (ctx->type) {
196         case FORWARD_TCP:
197         case FORWARD_JDWP:
198         case FORWARD_ARK:
199             Base::TryCloseHandle((uv_handle_t *)&ctx->tcp, true, funcHandleClose);
200             break;
201         case FORWARD_ABSTRACT:
202         case FORWARD_RESERVED:
203         case FORWARD_FILESYSTEM:
204             Base::TryCloseHandle((uv_handle_t *)&ctx->pipe, true, funcHandleClose);
205             break;
206         case FORWARD_DEVICE: {
207             FreeJDWP(ctx);
208             break;
209         }
210         default:
211             break;
212     }
213     ctx->finish = true;
214 }
215 
SendToTask(const uint32_t cid,const uint16_t command,uint8_t * bufPtr,const int bufSize)216 bool HdcForwardBase::SendToTask(const uint32_t cid, const uint16_t command, uint8_t *bufPtr, const int bufSize)
217 {
218     StartTraceScope("HdcForwardBase::SendToTask");
219     bool ret = false;
220     // usually MAX_SIZE_IOBUF*2 from HdcFileDescriptor maxIO
221     if (bufSize > Base::GetMaxBufSize() * BUF_MULTIPLE) {
222         WRITE_LOG(LOG_FATAL, "SendToTask bufSize:%d", bufSize);
223         return false;
224     }
225     auto newBuf = new uint8_t[bufSize + BUF_EXTEND_SIZE];
226     if (!newBuf) {
227         return false;
228     }
229     *reinterpret_cast<uint32_t *>(newBuf) = htonl(cid);
230     if (bufSize > 0 && bufPtr != nullptr && memcpy_s(newBuf + BUF_EXTEND_SIZE, bufSize, bufPtr, bufSize) != EOK) {
231         delete[] newBuf;
232         return false;
233     }
234     ret = SendToAnother(command, newBuf, bufSize + BUF_EXTEND_SIZE);
235     delete[] newBuf;
236     return ret;
237 }
238 
239 // Forward flow is small and frequency is fast
AllocForwardBuf(uv_handle_t * handle,size_t sizeSuggested,uv_buf_t * buf)240 void HdcForwardBase::AllocForwardBuf(uv_handle_t *handle, size_t sizeSuggested, uv_buf_t *buf)
241 {
242     size_t size = sizeSuggested;
243     if (size > MAX_USBFFS_BULK) {
244         size = MAX_USBFFS_BULK;
245     }
246     buf->base = (char *)new char[size];
247     if (buf->base) {
248         buf->len = (size > 0) ? (size - 1) : 0;
249     } else {
250         WRITE_LOG(LOG_WARN, "AllocForwardBuf == null");
251     }
252 }
253 
ReadForwardBuf(uv_stream_t * stream,ssize_t nread,const uv_buf_t * buf)254 void HdcForwardBase::ReadForwardBuf(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
255 {
256     HCtxForward ctx = (HCtxForward)stream->data;
257     if (nread < 0) {
258         WRITE_LOG(LOG_INFO, "ReadForwardBuf nread:%zd id:%u", nread, ctx->id);
259         ctx->thisClass->FreeContext(ctx, 0, true);
260         delete[] buf->base;
261         return;
262     }
263     if (nread == 0) {
264         WRITE_LOG(LOG_INFO, "ReadForwardBuf nread:0 id:%u", ctx->id);
265         delete[] buf->base;
266         return;
267     }
268     ctx->thisClass->SendToTask(ctx->id, CMD_FORWARD_DATA, (uint8_t *)buf->base, nread);
269     // clear
270     delete[] buf->base;
271 }
272 
ConnectTarget(uv_connect_t * connection,int status)273 void HdcForwardBase::ConnectTarget(uv_connect_t *connection, int status)
274 {
275     HCtxForward ctx = (HCtxForward)connection->data;
276     HdcForwardBase *thisClass = ctx->thisClass;
277     delete connection;
278     if (status < 0) {
279         constexpr int bufSize = 1024;
280         char buf[bufSize] = { 0 };
281         uv_err_name_r(status, buf, bufSize);
282         WRITE_LOG(LOG_WARN, "Forward connect result:%d error:%s", status, buf);
283     }
284     thisClass->SetupPointContinue(ctx, status);
285 }
286 
CheckNodeInfo(const char * nodeInfo,string as[2])287 bool HdcForwardBase::CheckNodeInfo(const char *nodeInfo, string as[2])
288 {
289     string str = nodeInfo;
290     size_t strLen = str.size();
291     if (strLen < 1) {
292         return false;
293     }
294     size_t pos = str.find(':');
295     if (pos != string::npos) {
296         if (pos == 0 || pos == strLen - 1) {
297             return false;
298         }
299         as[0] = str.substr(0, pos);
300         as[1] = str.substr(pos + 1);
301     } else {
302         return false;
303     }
304     if (as[0] == "tcp") {
305         if (as[1].size() > std::to_string(MAX_IP_PORT).size()) {
306             return false;
307         }
308         int port = atoi(as[1].c_str());
309         if (port <= 0 || port > MAX_IP_PORT) {
310             return false;
311         }
312     }
313     return true;
314 }
315 
SetupPointContinue(HCtxForward ctx,int status)316 bool HdcForwardBase::SetupPointContinue(HCtxForward ctx, int status)
317 {
318     if (ctx->checkPoint) {
319         // send to active
320         uint8_t flag = status > 0;
321         SendToTask(ctx->id, CMD_FORWARD_CHECK_RESULT, &flag, 1);
322         FreeContext(ctx, 0, false);
323         return true;
324     }
325     if (status < 0) {
326         FreeContext(ctx, 0, true);
327         return false;
328     }
329     // send to active
330     if (!SendToTask(ctx->id, CMD_FORWARD_ACTIVE_MASTER, nullptr, 0)) {
331         WRITE_LOG(LOG_FATAL, "SetupPointContinue SendToTask failed id:%u", ctx->id);
332         FreeContext(ctx, 0, true);
333         return false;
334     }
335     return DoForwardBegin(ctx);
336 }
337 
DetechForwardType(HCtxForward ctxPoint)338 bool HdcForwardBase::DetechForwardType(HCtxForward ctxPoint)
339 {
340     string &sFType = ctxPoint->localArgs[0];
341     string &sNodeCfg = ctxPoint->localArgs[1];
342     // string to enum
343     if (sFType == "tcp") {
344         ctxPoint->type = FORWARD_TCP;
345     } else if (sFType == "dev") {
346         ctxPoint->type = FORWARD_DEVICE;
347     } else if (sFType == "localabstract") {
348         // daemon shell: /system/bin/socat abstract-listen:linux-abstract -
349         // daemon shell: /system/bin/socat - abstract-connect:linux-abstract
350         // host:   hdc fport tcp:8080 localabstract:linux-abstract
351         ctxPoint->type = FORWARD_ABSTRACT;
352     } else if (sFType == "localreserved") {
353         sNodeCfg = harmonyReservedSocketPrefix + sNodeCfg;
354         ctxPoint->type = FORWARD_RESERVED;
355     } else if (sFType == "localfilesystem") {
356         sNodeCfg = filesystemSocketPrefix + sNodeCfg;
357         ctxPoint->type = FORWARD_FILESYSTEM;
358     } else if (sFType == "jdwp") {
359         ctxPoint->type = FORWARD_JDWP;
360     } else if (sFType == "ark") {
361         ctxPoint->type = FORWARD_ARK;
362     } else {
363         return false;
364     }
365     return true;
366 }
367 
SetupTCPPoint(HCtxForward ctxPoint)368 bool HdcForwardBase::SetupTCPPoint(HCtxForward ctxPoint)
369 {
370     string &sNodeCfg = ctxPoint->localArgs[1];
371     int port = atoi(sNodeCfg.c_str());
372     ctxPoint->tcp.data = ctxPoint;
373     uv_tcp_init(loopTask, &ctxPoint->tcp);
374     struct sockaddr_in addr;
375     if (ctxPoint->masterSlave) {
376         uv_ip4_addr("127.0.0.1", port, &addr);  // loop interface
377         uv_tcp_bind(&ctxPoint->tcp, (const struct sockaddr *)&addr, 0);
378         if (uv_listen((uv_stream_t *)&ctxPoint->tcp, UV_LISTEN_LBACKOG, ListenCallback)) {
379             ctxPoint->lastError = "TCP Port listen failed at " + sNodeCfg;
380             return false;
381         }
382     } else {
383         uv_ip4_addr("127.0.0.1", port, &addr);  // loop interface
384         uv_connect_t *conn = new(std::nothrow) uv_connect_t();
385         if (conn == nullptr) {
386             WRITE_LOG(LOG_FATAL, "SetupTCPPoint new conn failed");
387             return false;
388         }
389         conn->data = ctxPoint;
390         uv_tcp_connect(conn, (uv_tcp_t *)&ctxPoint->tcp, (const struct sockaddr *)&addr, ConnectTarget);
391     }
392     return true;
393 }
394 
SetupDevicePoint(HCtxForward ctxPoint)395 bool HdcForwardBase::SetupDevicePoint(HCtxForward ctxPoint)
396 {
397     uint8_t flag = 1;
398     string &sNodeCfg = ctxPoint->localArgs[1];
399     string resolvedPath = Base::CanonicalizeSpecPath(sNodeCfg);
400     if ((ctxPoint->fd = open(resolvedPath.c_str(), O_RDWR)) < 0) {
401         ctxPoint->lastError = "Open unix-dev failed";
402         flag = -1;
403     }
404     auto funcRead = [&](const void *a, uint8_t *b, const int c) -> bool {
405         HCtxForward ctx = (HCtxForward)a;
406         return SendToTask(ctx->id, CMD_FORWARD_DATA, b, c);
407     };
408     auto funcFinish = [&](const void *a, const bool b, const string c) -> bool {
409         HCtxForward ctx = (HCtxForward)a;
410         WRITE_LOG(LOG_DEBUG, "funcFinish id:%u ret:%d reason:%s", ctx->id, b, c.c_str());
411         FreeContext(ctx, 0, true);
412         return false;
413     };
414     ctxPoint->fdClass = new(std::nothrow) HdcFileDescriptor(loopTask, ctxPoint->fd, ctxPoint, funcRead,
415                                                             funcFinish, true);
416     if (ctxPoint->fdClass == nullptr) {
417         WRITE_LOG(LOG_FATAL, "SetupDevicePoint new ctxPoint->fdClass failed");
418         return false;
419     }
420     SetupPointContinue(ctxPoint, flag);
421     return true;
422 }
423 
LocalAbstractConnect(uv_pipe_t * pipe,string & sNodeCfg)424 bool HdcForwardBase::LocalAbstractConnect(uv_pipe_t *pipe, string &sNodeCfg)
425 {
426     bool abstractRet = false;
427 #ifndef _WIN32
428     int s = 0;
429     do {
430         if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
431             break;
432         }
433         fcntl(s, F_SETFD, FD_CLOEXEC);
434         struct sockaddr_un addr;
435         Base::ZeroStruct(addr);
436         int addrLen = sNodeCfg.size() + offsetof(struct sockaddr_un, sun_path) + 1;
437         addr.sun_family = AF_LOCAL;
438         addr.sun_path[0] = 0;
439 
440         if (memcpy_s(addr.sun_path + 1, sizeof(addr.sun_path) - 1, sNodeCfg.c_str(), sNodeCfg.size()) != EOK) {
441             break;
442         };
443         struct timeval timeout = { 3, 0 };
444         setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
445         if (connect(s, reinterpret_cast<struct sockaddr *>(&addr), addrLen) < 0) {
446             WRITE_LOG(LOG_FATAL, "LocalAbstractConnect failed errno:%d", errno);
447             break;
448         }
449         if (uv_pipe_open(pipe, s)) {
450             break;
451         }
452         abstractRet = true;
453     } while (false);
454     if (!abstractRet) {
455         Base::CloseFd(s);
456     }
457 #endif
458     return abstractRet;
459 }
460 
SetupFilePoint(HCtxForward ctxPoint)461 bool HdcForwardBase::SetupFilePoint(HCtxForward ctxPoint)
462 {
463     string &sNodeCfg = ctxPoint->localArgs[1];
464     ctxPoint->pipe.data = ctxPoint;
465     uv_pipe_init(loopTask, &ctxPoint->pipe, 0);
466     if (ctxPoint->masterSlave) {
467         if (ctxPoint->type == FORWARD_RESERVED || ctxPoint->type == FORWARD_FILESYSTEM) {
468             unlink(sNodeCfg.c_str());
469         }
470         if (uv_pipe_bind(&ctxPoint->pipe, sNodeCfg.c_str())) {
471             ctxPoint->lastError = "Unix pipe bind failed";
472             return false;
473         }
474         if (uv_listen((uv_stream_t *)&ctxPoint->pipe, UV_LISTEN_LBACKOG, ListenCallback)) {
475             ctxPoint->lastError = "Unix pipe listen failed";
476             return false;
477         }
478     } else {
479         if (ctxPoint->type == FORWARD_ABSTRACT) {
480             bool abstractRet = LocalAbstractConnect(&ctxPoint->pipe, sNodeCfg);
481             SetupPointContinue(ctxPoint, abstractRet ? 0 : -1);
482             if (!abstractRet) {
483                 ctxPoint->lastError = "LocalAbstractConnect failed";
484                 return false;
485             }
486         } else {
487             uv_connect_t *connect = new(std::nothrow) uv_connect_t();
488             if (connect == nullptr) {
489                 WRITE_LOG(LOG_FATAL, "SetupFilePoint new connect failed");
490                 return false;
491             }
492             connect->data = ctxPoint;
493             uv_pipe_connect(connect, &ctxPoint->pipe, sNodeCfg.c_str(), ConnectTarget);
494         }
495     }
496     return true;
497 }
498 
SetupPoint(HCtxForward ctxPoint)499 bool HdcForwardBase::SetupPoint(HCtxForward ctxPoint)
500 {
501     bool ret = true;
502     if (!DetechForwardType(ctxPoint)) {
503         return false;
504     }
505     switch (ctxPoint->type) {
506         case FORWARD_TCP:
507             if (!SetupTCPPoint(ctxPoint)) {
508                 ret = false;
509             };
510             break;
511 #ifndef _WIN32
512         case FORWARD_DEVICE:
513             if (!SetupDevicePoint(ctxPoint)) {
514                 ret = false;
515             };
516             break;
517         case FORWARD_JDWP:
518             if (!SetupJdwpPoint(ctxPoint)) {
519                 ret = false;
520             };
521             break;
522         case FORWARD_ABSTRACT:
523         case FORWARD_RESERVED:
524         case FORWARD_FILESYSTEM:
525             if (!SetupFilePoint(ctxPoint)) {
526                 ret = false;
527             };
528             break;
529 #else
530         case FORWARD_DEVICE:
531         case FORWARD_JDWP:
532         case FORWARD_ABSTRACT:
533         case FORWARD_RESERVED:
534         case FORWARD_FILESYSTEM:
535             ctxPoint->lastError = "Not supoort forward-type";
536             ret = false;
537             break;
538 #endif
539         default:
540             ctxPoint->lastError = "Not supoort forward-type";
541             ret = false;
542             break;
543     }
544     return ret;
545 }
546 
BeginForward(const string & command,string & sError)547 bool HdcForwardBase::BeginForward(const string &command, string &sError)
548 {
549     bool ret = false;
550     int argc = 0;
551     char bufString[BUF_SIZE_SMALL] = "";
552     HCtxForward ctxPoint = (HCtxForward)MallocContext(true);
553     if (!ctxPoint) {
554         WRITE_LOG(LOG_FATAL, "MallocContext failed");
555         return false;
556     }
557     char **argv = Base::SplitCommandToArgs(command.c_str(), &argc);
558     if (argv == nullptr) {
559         WRITE_LOG(LOG_FATAL, "SplitCommandToArgs failed");
560         return false;
561     }
562     while (true) {
563         if (argc < CMD_ARG1_COUNT) {
564             break;
565         }
566         if (strlen(argv[0]) > BUF_SIZE_SMALL || strlen(argv[1]) > BUF_SIZE_SMALL) {
567             break;
568         }
569         if (!CheckNodeInfo(argv[0], ctxPoint->localArgs)) {
570             break;
571         }
572         if (!CheckNodeInfo(argv[1], ctxPoint->remoteArgs)) {
573             break;
574         }
575         ctxPoint->remoteParamenters = argv[1];
576         if (!SetupPoint(ctxPoint)) {
577             break;
578         }
579 
580         ret = true;
581         break;
582     }
583     sError = ctxPoint->lastError;
584     if (ret) {
585         // First 8-byte parameter bit
586         int maxBufSize = sizeof(bufString) - forwardParameterBufSize;
587         if (snprintf_s(bufString + forwardParameterBufSize, maxBufSize, maxBufSize - 1, "%s", argv[1]) > 0) {
588             SendToTask(ctxPoint->id, CMD_FORWARD_CHECK, reinterpret_cast<uint8_t *>(bufString),
589                        forwardParameterBufSize + strlen(bufString + forwardParameterBufSize) + 1);
590             taskCommand = command;
591         }
592     }
593     delete[](reinterpret_cast<char *>(argv));
594     return ret;
595 }
596 
FilterCommand(uint8_t * bufCmdIn,uint32_t * idOut,uint8_t ** pContentBuf)597 inline bool HdcForwardBase::FilterCommand(uint8_t *bufCmdIn, uint32_t *idOut, uint8_t **pContentBuf)
598 {
599     *pContentBuf = bufCmdIn + DWORD_SERIALIZE_SIZE;
600     *idOut = ntohl(*reinterpret_cast<uint32_t *>(bufCmdIn));
601     return true;
602 }
603 
SlaveConnect(uint8_t * bufCmd,bool bCheckPoint,string & sError)604 bool HdcForwardBase::SlaveConnect(uint8_t *bufCmd, bool bCheckPoint, string &sError)
605 {
606     bool ret = false;
607     char *content = nullptr;
608     uint32_t idSlaveOld = 0;
609     HCtxForward ctxPoint = (HCtxForward)MallocContext(false);
610     if (!ctxPoint) {
611         WRITE_LOG(LOG_FATAL, "MallocContext failed");
612         return false;
613     }
614     idSlaveOld = ctxPoint->id;
615     ctxPoint->checkPoint = bCheckPoint;
616     // refresh another id,8byte param
617     FilterCommand(bufCmd, &ctxPoint->id, reinterpret_cast<uint8_t **>(&content));
618     AdminContext(OP_UPDATE, idSlaveOld, ctxPoint);
619     content += forwardParameterBufSize;
620     if (!CheckNodeInfo(content, ctxPoint->localArgs)) {
621         WRITE_LOG(LOG_FATAL, "SlaveConnect CheckNodeInfo failed content:%s", content);
622         goto Finish;
623     }
624     if (!DetechForwardType(ctxPoint)) {
625         WRITE_LOG(LOG_FATAL, "SlaveConnect DetechForwardType failed content:%s", content);
626         goto Finish;
627     }
628     WRITE_LOG(LOG_DEBUG, "id:%u type:%d", ctxPoint->id, ctxPoint->type);
629     if (ctxPoint->type == FORWARD_ARK) {
630         if (ctxPoint->checkPoint) {
631             if (!SetupArkPoint(ctxPoint)) {
632                 sError = ctxPoint->lastError;
633                 WRITE_LOG(LOG_FATAL, "SlaveConnect SetupArkPoint failed content:%s", content);
634                 goto Finish;
635             }
636         } else {
637             SetupPointContinue(ctxPoint, 0);
638         }
639         ret = true;
640     } else {
641         if (!ctxPoint->checkPoint) {
642             if (!SetupPoint(ctxPoint)) {
643                 sError = ctxPoint->lastError;
644                 WRITE_LOG(LOG_FATAL, "SlaveConnect SetupPoint failed content:%s", content);
645                 goto Finish;
646             }
647         } else {
648             SetupPointContinue(ctxPoint, 0);
649         }
650         ret = true;
651     }
652 Finish:
653     if (!ret) {
654         FreeContext(ctxPoint, 0, true);
655     }
656     return ret;
657 }
658 
DoForwardBegin(HCtxForward ctx)659 bool HdcForwardBase::DoForwardBegin(HCtxForward ctx)
660 {
661     switch (ctx->type) {
662         case FORWARD_TCP:
663         case FORWARD_JDWP:  // jdwp use tcp ->socketpair->jvm
664             uv_tcp_nodelay((uv_tcp_t *)&ctx->tcp, 1);
665             uv_read_start((uv_stream_t *)&ctx->tcp, AllocForwardBuf, ReadForwardBuf);
666             break;
667         case FORWARD_ARK:
668             WRITE_LOG(LOG_DEBUG, "DoForwardBegin ark socketpair id:%u fds[0]:%d", ctx->id, fds[0]);
669             uv_tcp_init(loopTask, &ctx->tcp);
670             uv_tcp_open(&ctx->tcp, fds[0]);
671             uv_tcp_nodelay((uv_tcp_t *)&ctx->tcp, 1);
672             uv_read_start((uv_stream_t *)&ctx->tcp, AllocForwardBuf, ReadForwardBuf);
673             break;
674         case FORWARD_ABSTRACT:
675         case FORWARD_RESERVED:
676         case FORWARD_FILESYSTEM:
677             uv_read_start((uv_stream_t *)&ctx->pipe, AllocForwardBuf, ReadForwardBuf);
678             break;
679         case FORWARD_DEVICE: {
680             ctx->fdClass->StartWorkOnThread();
681             break;
682         }
683         default:
684             break;
685     }
686     ctx->ready = true;
687     return true;
688 }
689 
AdminContext(const uint8_t op,const uint32_t id,HCtxForward hInput)690 void *HdcForwardBase::AdminContext(const uint8_t op, const uint32_t id, HCtxForward hInput)
691 {
692     ctxPointMutex.lock();
693     void *hRet = nullptr;
694     map<uint32_t, HCtxForward> &mapCtx = mapCtxPoint;
695     switch (op) {
696         case OP_ADD:
697             mapCtx[id] = hInput;
698             break;
699         case OP_REMOVE:
700             mapCtx.erase(id);
701             break;
702         case OP_QUERY:
703             if (mapCtx.count(id)) {
704                 hRet = mapCtx[id];
705             }
706             break;
707         case OP_UPDATE:
708             mapCtx.erase(id);
709             mapCtx[hInput->id] = hInput;
710             break;
711         default:
712             break;
713     }
714     ctxPointMutex.unlock();
715     return hRet;
716 }
717 
SendCallbackForwardBuf(uv_write_t * req,int status)718 void HdcForwardBase::SendCallbackForwardBuf(uv_write_t *req, int status)
719 {
720     ContextForwardIO *ctxIO = (ContextForwardIO *)req->data;
721     HCtxForward ctx = reinterpret_cast<HCtxForward>(ctxIO->ctxForward);
722     if (status < 0 && !ctx->finish) {
723         WRITE_LOG(LOG_DEBUG, "SendCallbackForwardBuf ctx->type:%d, status:%d finish", ctx->type, status);
724         ctx->thisClass->FreeContext(ctx, 0, true);
725     }
726     delete[] ctxIO->bufIO;
727     delete ctxIO;
728     delete req;
729 }
730 
SendForwardBuf(HCtxForward ctx,uint8_t * bufPtr,const int size)731 int HdcForwardBase::SendForwardBuf(HCtxForward ctx, uint8_t *bufPtr, const int size)
732 {
733     int nRet = 0;
734     if (size > static_cast<int>(HDC_BUF_MAX_BYTES - 1)) {
735         WRITE_LOG(LOG_WARN, "SendForwardBuf size:%d > HDC_BUF_MAX_BYTES", size);
736         return -1;
737     }
738     if (size <= 0) {
739         WRITE_LOG(LOG_WARN, "SendForwardBuf failed size:%d", size);
740         return -1;
741     }
742     auto pDynBuf = new(std::nothrow) uint8_t[size];
743     if (!pDynBuf) {
744         return -1;
745     }
746     (void)memcpy_s(pDynBuf, size, bufPtr, size);
747     if (ctx->type == FORWARD_DEVICE) {
748         nRet = ctx->fdClass->WriteWithMem(pDynBuf, size);
749     } else {
750         auto ctxIO = new ContextForwardIO();
751         if (!ctxIO) {
752             delete[] pDynBuf;
753             return -1;
754         }
755         ctxIO->ctxForward = ctx;
756         ctxIO->bufIO = pDynBuf;
757         if (ctx->type == FORWARD_TCP || ctx->type == FORWARD_JDWP || ctx->type == FORWARD_ARK) {
758             nRet = Base::SendToStreamEx((uv_stream_t *)&ctx->tcp, pDynBuf, size, nullptr,
759                                         (void *)SendCallbackForwardBuf, (void *)ctxIO);
760         } else {
761             // FORWARD_ABSTRACT, FORWARD_RESERVED, FORWARD_FILESYSTEM,
762             nRet = Base::SendToStreamEx((uv_stream_t *)&ctx->pipe, pDynBuf, size, nullptr,
763                                         (void *)SendCallbackForwardBuf, (void *)ctxIO);
764         }
765     }
766     return nRet;
767 }
768 
CommandForwardCheckResult(HCtxForward ctx,uint8_t * payload)769 bool HdcForwardBase::CommandForwardCheckResult(HCtxForward ctx, uint8_t *payload)
770 {
771     bool ret = true;
772     bool bCheck = static_cast<bool>(payload);
773     LogMsg(bCheck ? MSG_OK : MSG_FAIL, "Forwardport result:%s", bCheck ? "OK" : "Failed");
774     if (bCheck) {
775         string mapInfo = taskInfo->serverOrDaemon ? "1|" : "0|";
776         mapInfo += taskCommand;
777         ctx->ready = true;
778         ServerCommand(CMD_FORWARD_SUCCESS, reinterpret_cast<uint8_t *>(const_cast<char *>(mapInfo.c_str())),
779                       mapInfo.size() + 1);
780     } else {
781         ret = false;
782         FreeContext(ctx, 0, false);
783     }
784     return ret;
785 }
786 
ForwardCommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)787 bool HdcForwardBase::ForwardCommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
788 {
789     bool ret = true;
790     uint8_t *pContent = nullptr;
791     int sizeContent = 0;
792     uint32_t id = 0;
793     HCtxForward ctx = nullptr;
794     FilterCommand(payload, &id, &pContent);
795     sizeContent = payloadSize - DWORD_SERIALIZE_SIZE;
796     if (!(ctx = (HCtxForward)AdminContext(OP_QUERY, id, nullptr))) {
797         WRITE_LOG(LOG_WARN, "Query id:%u failed", id);
798         return true;
799     }
800     switch (command) {
801         case CMD_FORWARD_CHECK_RESULT: {
802             ret = CommandForwardCheckResult(ctx, pContent);
803             break;
804         }
805         case CMD_FORWARD_ACTIVE_MASTER: {
806             ret = DoForwardBegin(ctx);
807             break;
808         }
809         case CMD_FORWARD_DATA: {
810             if (ctx->finish) {
811                 break;
812             }
813             if (SendForwardBuf(ctx, pContent, sizeContent) < 0) {
814                 FreeContext(ctx, 0, true);
815             }
816             break;
817         }
818         case CMD_FORWARD_FREE_CONTEXT: {
819             FreeContext(ctx, 0, false);
820             break;
821         }
822         default:
823             ret = false;
824             break;
825     }
826     if (!ret) {
827         if (ctx) {
828             FreeContext(ctx, 0, true);
829         } else {
830             WRITE_LOG(LOG_DEBUG, "ctx==nullptr raw free");
831             TaskFinish();
832         }
833     }
834     return ret;
835 }
836 
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)837 bool HdcForwardBase::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
838 {
839     if (command != CMD_FORWARD_DATA) {
840         WRITE_LOG(LOG_DEBUG, "CommandDispatch command:%d payloadSize:%d", command, payloadSize);
841     }
842     bool ret = true;
843     string sError;
844     // prepare
845     if (command == CMD_FORWARD_INIT) {
846         string strCommand(reinterpret_cast<char *>(payload), payloadSize);
847         if (!BeginForward(strCommand, sError)) {
848             ret = false;
849             goto Finish;
850         }
851         return true;
852     } else if (command == CMD_FORWARD_CHECK) {
853         // Detect remote if it's reachable
854         if (!SlaveConnect(payload, true, sError)) {
855             ret = false;
856             goto Finish;
857         }
858         return true;
859     } else if (command == CMD_FORWARD_ACTIVE_SLAVE) {
860         // slave connect target port when activating
861         if (!SlaveConnect(payload, false, sError)) {
862             ret = false;
863             goto Finish;
864         }
865         return true;
866     }
867     if (!ForwardCommandDispatch(command, payload, payloadSize)) {
868         ret = false;
869         goto Finish;
870     }
871 Finish:
872     if (!ret) {
873         if (!sError.size()) {
874             LogMsg(MSG_FAIL, "Forward parament failed");
875         } else {
876             LogMsg(MSG_FAIL, const_cast<char *>(sError.c_str()));
877             WRITE_LOG(LOG_WARN, const_cast<char *>(sError.c_str()));
878         }
879     }
880     return ret;
881 }
882 }  // namespace Hdc
883