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