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::GetRandomU32();
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 std::lock_guard<std::mutex> lock(ctxFreeMutex);
175 HCtxForward ctx = nullptr;
176 if (!ctxIn) {
177 if (!(ctx = (HCtxForward)AdminContext(OP_QUERY, id, nullptr))) {
178 WRITE_LOG(LOG_DEBUG, "Query id:%u failed", id);
179 return;
180 }
181 } else {
182 ctx = ctxIn;
183 }
184 WRITE_LOG(LOG_DEBUG, "FreeContext id:%u, bNotifyRemote:%d, finish:%d",
185 ctx->id, bNotifyRemote, ctx->finish);
186 if (ctx->finish) {
187 return;
188 }
189 if (bNotifyRemote) {
190 SendToTask(ctx->id, CMD_FORWARD_FREE_CONTEXT, nullptr, 0);
191 }
192 uv_close_cb funcHandleClose = [](uv_handle_t *handle) -> void {
193 HCtxForward ctx = (HCtxForward)handle->data;
194 ctx->thisClass->FreeContextCallBack(ctx);
195 };
196 switch (ctx->type) {
197 case FORWARD_TCP:
198 case FORWARD_JDWP:
199 case FORWARD_ARK:
200 Base::TryCloseHandle((uv_handle_t *)&ctx->tcp, true, funcHandleClose);
201 break;
202 case FORWARD_ABSTRACT:
203 case FORWARD_RESERVED:
204 case FORWARD_FILESYSTEM:
205 Base::TryCloseHandle((uv_handle_t *)&ctx->pipe, true, funcHandleClose);
206 break;
207 case FORWARD_DEVICE: {
208 FreeJDWP(ctx);
209 break;
210 }
211 default:
212 break;
213 }
214 ctx->finish = true;
215 }
216
SendToTask(const uint32_t cid, const uint16_t command, uint8_t *bufPtr, const int bufSize)217 bool HdcForwardBase::SendToTask(const uint32_t cid, const uint16_t command, uint8_t *bufPtr, const int bufSize)
218 {
219 StartTraceScope("HdcForwardBase::SendToTask");
220 bool ret = false;
221 // usually MAX_SIZE_IOBUF*2 from HdcFileDescriptor maxIO
222 if (bufSize > Base::GetMaxBufSizeStable() * BUF_MULTIPLE) {
223 WRITE_LOG(LOG_FATAL, "SendToTask bufSize:%d", bufSize);
224 return false;
225 }
226 auto newBuf = new uint8_t[bufSize + BUF_EXTEND_SIZE];
227 if (!newBuf) {
228 return false;
229 }
230 *reinterpret_cast<uint32_t *>(newBuf) = htonl(cid);
231 if (bufSize > 0 && bufPtr != nullptr && memcpy_s(newBuf + BUF_EXTEND_SIZE, bufSize, bufPtr, bufSize) != EOK) {
232 delete[] newBuf;
233 return false;
234 }
235 ret = SendToAnother(command, newBuf, bufSize + BUF_EXTEND_SIZE);
236 delete[] newBuf;
237 return ret;
238 }
239
240 // Forward flow is small and frequency is fast
AllocForwardBuf(uv_handle_t *handle, size_t sizeSuggested, uv_buf_t *buf)241 void HdcForwardBase::AllocForwardBuf(uv_handle_t *handle, size_t sizeSuggested, uv_buf_t *buf)
242 {
243 size_t size = sizeSuggested;
244 if (size > MAX_USBFFS_BULK) {
245 size = MAX_USBFFS_BULK;
246 }
247 buf->base = (char *)new char[size];
248 if (buf->base) {
249 buf->len = (size > 0) ? (size - 1) : 0;
250 } else {
251 WRITE_LOG(LOG_WARN, "AllocForwardBuf == null");
252 }
253 }
254
ReadForwardBuf(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)255 void HdcForwardBase::ReadForwardBuf(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
256 {
257 HCtxForward ctx = (HCtxForward)stream->data;
258 if (nread < 0) {
259 WRITE_LOG(LOG_INFO, "ReadForwardBuf nread:%zd id:%u", nread, ctx->id);
260 ctx->thisClass->FreeContext(ctx, 0, true);
261 delete[] buf->base;
262 return;
263 }
264 if (nread == 0) {
265 WRITE_LOG(LOG_INFO, "ReadForwardBuf nread:0 id:%u", ctx->id);
266 delete[] buf->base;
267 return;
268 }
269 ctx->thisClass->SendToTask(ctx->id, CMD_FORWARD_DATA, (uint8_t *)buf->base, nread);
270 // clear
271 delete[] buf->base;
272 }
273
ConnectTarget(uv_connect_t *connection, int status)274 void HdcForwardBase::ConnectTarget(uv_connect_t *connection, int status)
275 {
276 HCtxForward ctx = (HCtxForward)connection->data;
277 HdcForwardBase *thisClass = ctx->thisClass;
278 delete connection;
279 if (status < 0) {
280 constexpr int bufSize = 1024;
281 char buf[bufSize] = { 0 };
282 uv_err_name_r(status, buf, bufSize);
283 WRITE_LOG(LOG_WARN, "Forward connect result:%d error:%s", status, buf);
284 }
285 thisClass->SetupPointContinue(ctx, status);
286 }
287
CheckNodeInfo(const char *nodeInfo, string as[2])288 bool HdcForwardBase::CheckNodeInfo(const char *nodeInfo, string as[2])
289 {
290 string str = nodeInfo;
291 size_t strLen = str.size();
292 if (strLen < 1) {
293 return false;
294 }
295 size_t pos = str.find(':');
296 if (pos != string::npos) {
297 if (pos == 0 || pos == strLen - 1) {
298 return false;
299 }
300 as[0] = str.substr(0, pos);
301 as[1] = str.substr(pos + 1);
302 } else {
303 return false;
304 }
305 if (as[0] == "tcp") {
306 if (as[1].size() > std::to_string(MAX_IP_PORT).size()) {
307 return false;
308 }
309 int port = atoi(as[1].c_str());
310 if (port <= 0 || port > MAX_IP_PORT) {
311 return false;
312 }
313 }
314 return true;
315 }
316
SetupPointContinue(HCtxForward ctx, int status)317 bool HdcForwardBase::SetupPointContinue(HCtxForward ctx, int status)
318 {
319 if (ctx->checkPoint) {
320 // send to active
321 uint8_t flag = status > 0;
322 SendToTask(ctx->id, CMD_FORWARD_CHECK_RESULT, &flag, 1);
323 FreeContext(ctx, 0, false);
324 return true;
325 }
326 if (status < 0) {
327 FreeContext(ctx, 0, true);
328 return false;
329 }
330 // send to active
331 if (!SendToTask(ctx->id, CMD_FORWARD_ACTIVE_MASTER, nullptr, 0)) {
332 WRITE_LOG(LOG_FATAL, "SetupPointContinue SendToTask failed id:%u", ctx->id);
333 FreeContext(ctx, 0, true);
334 return false;
335 }
336 return DoForwardBegin(ctx);
337 }
338
DetechForwardType(HCtxForward ctxPoint)339 bool HdcForwardBase::DetechForwardType(HCtxForward ctxPoint)
340 {
341 string &sFType = ctxPoint->localArgs[0];
342 string &sNodeCfg = ctxPoint->localArgs[1];
343 // string to enum
344 if (sFType == "tcp") {
345 ctxPoint->type = FORWARD_TCP;
346 } else if (sFType == "dev") {
347 ctxPoint->type = FORWARD_DEVICE;
348 } else if (sFType == "localabstract") {
349 // daemon shell: /system/bin/socat abstract-listen:linux-abstract -
350 // daemon shell: /system/bin/socat - abstract-connect:linux-abstract
351 // host: hdc fport tcp:8080 localabstract:linux-abstract
352 ctxPoint->type = FORWARD_ABSTRACT;
353 } else if (sFType == "localreserved") {
354 sNodeCfg = harmonyReservedSocketPrefix + sNodeCfg;
355 ctxPoint->type = FORWARD_RESERVED;
356 } else if (sFType == "localfilesystem") {
357 sNodeCfg = filesystemSocketPrefix + sNodeCfg;
358 ctxPoint->type = FORWARD_FILESYSTEM;
359 } else if (sFType == "jdwp") {
360 ctxPoint->type = FORWARD_JDWP;
361 } else if (sFType == "ark") {
362 ctxPoint->type = FORWARD_ARK;
363 } else {
364 return false;
365 }
366 return true;
367 }
368
SetupTCPPoint(HCtxForward ctxPoint)369 bool HdcForwardBase::SetupTCPPoint(HCtxForward ctxPoint)
370 {
371 string &sNodeCfg = ctxPoint->localArgs[1];
372 int port = atoi(sNodeCfg.c_str());
373 ctxPoint->tcp.data = ctxPoint;
374 uv_tcp_init(loopTask, &ctxPoint->tcp);
375 struct sockaddr_in addr;
376 if (ctxPoint->masterSlave) {
377 uv_ip4_addr("127.0.0.1", port, &addr); // loop interface
378 uv_tcp_bind(&ctxPoint->tcp, (const struct sockaddr *)&addr, 0);
379 if (uv_listen((uv_stream_t *)&ctxPoint->tcp, UV_LISTEN_LBACKOG, ListenCallback)) {
380 ctxPoint->lastError = "TCP Port listen failed at " + sNodeCfg;
381 return false;
382 }
383 } else {
384 uv_ip4_addr("127.0.0.1", port, &addr); // loop interface
385 uv_connect_t *conn = new(std::nothrow) uv_connect_t();
386 if (conn == nullptr) {
387 WRITE_LOG(LOG_FATAL, "SetupTCPPoint new conn failed");
388 return false;
389 }
390 conn->data = ctxPoint;
391 uv_tcp_connect(conn, (uv_tcp_t *)&ctxPoint->tcp, (const struct sockaddr *)&addr, ConnectTarget);
392 }
393 return true;
394 }
395
SetupDevicePoint(HCtxForward ctxPoint)396 bool HdcForwardBase::SetupDevicePoint(HCtxForward ctxPoint)
397 {
398 uint8_t flag = 1;
399 string &sNodeCfg = ctxPoint->localArgs[1];
400 string resolvedPath = Base::CanonicalizeSpecPath(sNodeCfg);
401 if ((ctxPoint->fd = open(resolvedPath.c_str(), O_RDWR)) < 0) {
402 ctxPoint->lastError = "Open unix-dev failed";
403 flag = -1;
404 }
405 auto funcRead = [&](const void *a, uint8_t *b, const int c) -> bool {
406 HCtxForward ctx = (HCtxForward)a;
407 return SendToTask(ctx->id, CMD_FORWARD_DATA, b, c);
408 };
409 auto funcFinish = [&](const void *a, const bool b, const string c) -> bool {
410 HCtxForward ctx = (HCtxForward)a;
411 WRITE_LOG(LOG_DEBUG, "funcFinish id:%u ret:%d reason:%s", ctx->id, b, c.c_str());
412 FreeContext(ctx, 0, true);
413 return false;
414 };
415 ctxPoint->fdClass = new(std::nothrow) HdcFileDescriptor(loopTask, ctxPoint->fd, ctxPoint, funcRead,
416 funcFinish, true);
417 if (ctxPoint->fdClass == nullptr) {
418 WRITE_LOG(LOG_FATAL, "SetupDevicePoint new ctxPoint->fdClass failed");
419 return false;
420 }
421 SetupPointContinue(ctxPoint, flag);
422 return true;
423 }
424
LocalAbstractConnect(uv_pipe_t *pipe, string &sNodeCfg)425 bool HdcForwardBase::LocalAbstractConnect(uv_pipe_t *pipe, string &sNodeCfg)
426 {
427 bool abstractRet = false;
428 #ifndef _WIN32
429 int s = 0;
430 do {
431 if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
432 break;
433 }
434 fcntl(s, F_SETFD, FD_CLOEXEC);
435 struct sockaddr_un addr;
436 Base::ZeroStruct(addr);
437 int addrLen = sNodeCfg.size() + offsetof(struct sockaddr_un, sun_path) + 1;
438 addr.sun_family = AF_LOCAL;
439 addr.sun_path[0] = 0;
440
441 if (memcpy_s(addr.sun_path + 1, sizeof(addr.sun_path) - 1, sNodeCfg.c_str(), sNodeCfg.size()) != EOK) {
442 break;
443 };
444 struct timeval timeout = { 3, 0 };
445 setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
446 if (connect(s, reinterpret_cast<struct sockaddr *>(&addr), addrLen) < 0) {
447 WRITE_LOG(LOG_FATAL, "LocalAbstractConnect failed errno:%d", errno);
448 break;
449 }
450 if (uv_pipe_open(pipe, s)) {
451 break;
452 }
453 abstractRet = true;
454 } while (false);
455 if (!abstractRet) {
456 Base::CloseFd(s);
457 }
458 #endif
459 return abstractRet;
460 }
461
SetupFilePoint(HCtxForward ctxPoint)462 bool HdcForwardBase::SetupFilePoint(HCtxForward ctxPoint)
463 {
464 string &sNodeCfg = ctxPoint->localArgs[1];
465 ctxPoint->pipe.data = ctxPoint;
466 uv_pipe_init(loopTask, &ctxPoint->pipe, 0);
467 if (ctxPoint->masterSlave) {
468 if (ctxPoint->type == FORWARD_RESERVED || ctxPoint->type == FORWARD_FILESYSTEM) {
469 unlink(sNodeCfg.c_str());
470 }
471 if (uv_pipe_bind(&ctxPoint->pipe, sNodeCfg.c_str())) {
472 ctxPoint->lastError = "Unix pipe bind failed";
473 return false;
474 }
475 if (uv_listen((uv_stream_t *)&ctxPoint->pipe, UV_LISTEN_LBACKOG, ListenCallback)) {
476 ctxPoint->lastError = "Unix pipe listen failed";
477 return false;
478 }
479 } else {
480 if (ctxPoint->type == FORWARD_ABSTRACT) {
481 bool abstractRet = LocalAbstractConnect(&ctxPoint->pipe, sNodeCfg);
482 SetupPointContinue(ctxPoint, abstractRet ? 0 : -1);
483 if (!abstractRet) {
484 ctxPoint->lastError = "LocalAbstractConnect failed";
485 return false;
486 }
487 } else {
488 uv_connect_t *connect = new(std::nothrow) uv_connect_t();
489 if (connect == nullptr) {
490 WRITE_LOG(LOG_FATAL, "SetupFilePoint new connect failed");
491 return false;
492 }
493 connect->data = ctxPoint;
494 uv_pipe_connect(connect, &ctxPoint->pipe, sNodeCfg.c_str(), ConnectTarget);
495 }
496 }
497 return true;
498 }
499
SetupPoint(HCtxForward ctxPoint)500 bool HdcForwardBase::SetupPoint(HCtxForward ctxPoint)
501 {
502 bool ret = true;
503 if (!DetechForwardType(ctxPoint)) {
504 return false;
505 }
506 switch (ctxPoint->type) {
507 case FORWARD_TCP:
508 if (!SetupTCPPoint(ctxPoint)) {
509 ret = false;
510 };
511 break;
512 #ifndef _WIN32
513 case FORWARD_DEVICE:
514 if (!SetupDevicePoint(ctxPoint)) {
515 ret = false;
516 };
517 break;
518 case FORWARD_JDWP:
519 if (!SetupJdwpPoint(ctxPoint)) {
520 ret = false;
521 };
522 break;
523 case FORWARD_ABSTRACT:
524 case FORWARD_RESERVED:
525 case FORWARD_FILESYSTEM:
526 if (!SetupFilePoint(ctxPoint)) {
527 ret = false;
528 };
529 break;
530 #else
531 case FORWARD_DEVICE:
532 case FORWARD_JDWP:
533 case FORWARD_ABSTRACT:
534 case FORWARD_RESERVED:
535 case FORWARD_FILESYSTEM:
536 ctxPoint->lastError = "Not supoort forward-type";
537 ret = false;
538 break;
539 #endif
540 default:
541 ctxPoint->lastError = "Not supoort forward-type";
542 ret = false;
543 break;
544 }
545 return ret;
546 }
547
BeginForward(const string &command, string &sError)548 bool HdcForwardBase::BeginForward(const string &command, string &sError)
549 {
550 bool ret = false;
551 int argc = 0;
552 char bufString[BUF_SIZE_SMALL] = "";
553 HCtxForward ctxPoint = (HCtxForward)MallocContext(true);
554 if (!ctxPoint) {
555 WRITE_LOG(LOG_FATAL, "MallocContext failed");
556 return false;
557 }
558 char **argv = Base::SplitCommandToArgs(command.c_str(), &argc);
559 if (argv == nullptr) {
560 WRITE_LOG(LOG_FATAL, "SplitCommandToArgs failed");
561 return false;
562 }
563 while (true) {
564 if (argc < CMD_ARG1_COUNT) {
565 break;
566 }
567 if (strlen(argv[0]) > BUF_SIZE_SMALL || strlen(argv[1]) > BUF_SIZE_SMALL) {
568 break;
569 }
570 if (!CheckNodeInfo(argv[0], ctxPoint->localArgs)) {
571 break;
572 }
573 if (!CheckNodeInfo(argv[1], ctxPoint->remoteArgs)) {
574 break;
575 }
576 ctxPoint->remoteParamenters = argv[1];
577 if (!SetupPoint(ctxPoint)) {
578 break;
579 }
580
581 ret = true;
582 break;
583 }
584 sError = ctxPoint->lastError;
585 if (ret) {
586 // First 8-byte parameter bit
587 int maxBufSize = sizeof(bufString) - forwardParameterBufSize;
588 if (snprintf_s(bufString + forwardParameterBufSize, maxBufSize, maxBufSize - 1, "%s", argv[1]) > 0) {
589 SendToTask(ctxPoint->id, CMD_FORWARD_CHECK, reinterpret_cast<uint8_t *>(bufString),
590 forwardParameterBufSize + strlen(bufString + forwardParameterBufSize) + 1);
591 taskCommand = command;
592 }
593 }
594 delete[](reinterpret_cast<char *>(argv));
595 return ret;
596 }
597
FilterCommand(uint8_t *bufCmdIn, uint32_t *idOut, uint8_t **pContentBuf)598 inline bool HdcForwardBase::FilterCommand(uint8_t *bufCmdIn, uint32_t *idOut, uint8_t **pContentBuf)
599 {
600 *pContentBuf = bufCmdIn + DWORD_SERIALIZE_SIZE;
601 *idOut = ntohl(*reinterpret_cast<uint32_t *>(bufCmdIn));
602 return true;
603 }
604
SlaveConnect(uint8_t *bufCmd, const int bufSize, bool bCheckPoint, string &sError)605 bool HdcForwardBase::SlaveConnect(uint8_t *bufCmd, const int bufSize, bool bCheckPoint, string &sError)
606 {
607 if (bufSize <= DWORD_SERIALIZE_SIZE + forwardParameterBufSize) {
608 WRITE_LOG(LOG_FATAL, "Illegal payloadSize, shorter than forward header");
609 return false;
610 }
611 bool ret = false;
612 char *content = nullptr;
613 uint32_t idSlaveOld = 0;
614 HCtxForward ctxPoint = (HCtxForward)MallocContext(false);
615 if (!ctxPoint) {
616 WRITE_LOG(LOG_FATAL, "MallocContext failed");
617 return false;
618 }
619 idSlaveOld = ctxPoint->id;
620 ctxPoint->checkPoint = bCheckPoint;
621 // refresh another id,8byte param
622 FilterCommand(bufCmd, &ctxPoint->id, reinterpret_cast<uint8_t **>(&content));
623 AdminContext(OP_UPDATE, idSlaveOld, ctxPoint);
624 content += forwardParameterBufSize;
625 if (!CheckNodeInfo(content, ctxPoint->localArgs)) {
626 WRITE_LOG(LOG_FATAL, "SlaveConnect CheckNodeInfo failed content:%s", content);
627 goto Finish;
628 }
629 if (!DetechForwardType(ctxPoint)) {
630 WRITE_LOG(LOG_FATAL, "SlaveConnect DetechForwardType failed content:%s", content);
631 goto Finish;
632 }
633 WRITE_LOG(LOG_DEBUG, "id:%u type:%d", ctxPoint->id, ctxPoint->type);
634 if (ctxPoint->type == FORWARD_ARK) {
635 if (ctxPoint->checkPoint) {
636 if (!SetupArkPoint(ctxPoint)) {
637 sError = ctxPoint->lastError;
638 WRITE_LOG(LOG_FATAL, "SlaveConnect SetupArkPoint failed content:%s", content);
639 goto Finish;
640 }
641 } else {
642 SetupPointContinue(ctxPoint, 0);
643 }
644 ret = true;
645 } else {
646 if (!ctxPoint->checkPoint) {
647 if (!SetupPoint(ctxPoint)) {
648 sError = ctxPoint->lastError;
649 WRITE_LOG(LOG_FATAL, "SlaveConnect SetupPoint failed content:%s", content);
650 goto Finish;
651 }
652 } else {
653 SetupPointContinue(ctxPoint, 0);
654 }
655 ret = true;
656 }
657 Finish:
658 if (!ret) {
659 FreeContext(ctxPoint, 0, true);
660 }
661 return ret;
662 }
663
DoForwardBegin(HCtxForward ctx)664 bool HdcForwardBase::DoForwardBegin(HCtxForward ctx)
665 {
666 switch (ctx->type) {
667 case FORWARD_TCP:
668 case FORWARD_JDWP: // jdwp use tcp ->socketpair->jvm
669 uv_tcp_nodelay((uv_tcp_t *)&ctx->tcp, 1);
670 uv_read_start((uv_stream_t *)&ctx->tcp, AllocForwardBuf, ReadForwardBuf);
671 break;
672 case FORWARD_ARK:
673 WRITE_LOG(LOG_DEBUG, "DoForwardBegin ark socketpair id:%u fds[0]:%d", ctx->id, fds[0]);
674 uv_tcp_init(loopTask, &ctx->tcp);
675 uv_tcp_open(&ctx->tcp, fds[0]);
676 uv_tcp_nodelay((uv_tcp_t *)&ctx->tcp, 1);
677 uv_read_start((uv_stream_t *)&ctx->tcp, AllocForwardBuf, ReadForwardBuf);
678 break;
679 case FORWARD_ABSTRACT:
680 case FORWARD_RESERVED:
681 case FORWARD_FILESYSTEM:
682 uv_read_start((uv_stream_t *)&ctx->pipe, AllocForwardBuf, ReadForwardBuf);
683 break;
684 case FORWARD_DEVICE: {
685 ctx->fdClass->StartWorkOnThread();
686 break;
687 }
688 default:
689 break;
690 }
691 ctx->ready = true;
692 return true;
693 }
694
AdminContext(const uint8_t op, const uint32_t id, HCtxForward hInput)695 void *HdcForwardBase::AdminContext(const uint8_t op, const uint32_t id, HCtxForward hInput)
696 {
697 ctxPointMutex.lock();
698 void *hRet = nullptr;
699 map<uint32_t, HCtxForward> &mapCtx = mapCtxPoint;
700 switch (op) {
701 case OP_ADD:
702 mapCtx[id] = hInput;
703 break;
704 case OP_REMOVE:
705 mapCtx.erase(id);
706 break;
707 case OP_QUERY:
708 if (mapCtx.count(id)) {
709 hRet = mapCtx[id];
710 }
711 break;
712 case OP_UPDATE:
713 mapCtx.erase(id);
714 mapCtx[hInput->id] = hInput;
715 break;
716 default:
717 break;
718 }
719 ctxPointMutex.unlock();
720 return hRet;
721 }
722
SendCallbackForwardBuf(uv_write_t *req, int status)723 void HdcForwardBase::SendCallbackForwardBuf(uv_write_t *req, int status)
724 {
725 ContextForwardIO *ctxIO = (ContextForwardIO *)req->data;
726 HCtxForward ctx = reinterpret_cast<HCtxForward>(ctxIO->ctxForward);
727 if (status < 0 && !ctx->finish) {
728 WRITE_LOG(LOG_DEBUG, "SendCallbackForwardBuf ctx->type:%d, status:%d finish", ctx->type, status);
729 ctx->thisClass->FreeContext(ctx, 0, true);
730 }
731 delete[] ctxIO->bufIO;
732 delete ctxIO;
733 delete req;
734 }
735
SendForwardBuf(HCtxForward ctx, uint8_t *bufPtr, const int size)736 int HdcForwardBase::SendForwardBuf(HCtxForward ctx, uint8_t *bufPtr, const int size)
737 {
738 int nRet = 0;
739 if (size > static_cast<int>(HDC_BUF_MAX_BYTES - 1)) {
740 WRITE_LOG(LOG_WARN, "SendForwardBuf size:%d > HDC_BUF_MAX_BYTES, ctxId:%u", size, ctx->id);
741 return -1;
742 }
743 if (size <= 0) {
744 WRITE_LOG(LOG_WARN, "SendForwardBuf failed size:%d, ctxId:%u", size, ctx->id);
745 return -1;
746 }
747 auto pDynBuf = new(std::nothrow) uint8_t[size];
748 if (!pDynBuf) {
749 WRITE_LOG(LOG_WARN, "SendForwardBuf new DynBuf failed size:%d, ctxId:%u", size, ctx->id);
750 return -1;
751 }
752 (void)memcpy_s(pDynBuf, size, bufPtr, size);
753 if (ctx->type == FORWARD_DEVICE) {
754 nRet = ctx->fdClass->WriteWithMem(pDynBuf, size);
755 } else {
756 auto ctxIO = new ContextForwardIO();
757 if (!ctxIO) {
758 WRITE_LOG(LOG_WARN, "SendForwardBuf new ContextForwardIO failed, ctxId:%u", ctx->id);
759 delete[] pDynBuf;
760 return -1;
761 }
762 ctxIO->ctxForward = ctx;
763 ctxIO->bufIO = pDynBuf;
764 if (ctx->type == FORWARD_TCP || ctx->type == FORWARD_JDWP || ctx->type == FORWARD_ARK) {
765 nRet = Base::SendToStreamEx((uv_stream_t *)&ctx->tcp, pDynBuf, size, nullptr,
766 (void *)SendCallbackForwardBuf, (void *)ctxIO);
767 } else {
768 // FORWARD_ABSTRACT, FORWARD_RESERVED, FORWARD_FILESYSTEM,
769 nRet = Base::SendToStreamEx((uv_stream_t *)&ctx->pipe, pDynBuf, size, nullptr,
770 (void *)SendCallbackForwardBuf, (void *)ctxIO);
771 }
772 if (nRet < 0) {
773 WRITE_LOG(LOG_WARN, "SendForwardBuf SendToStreamEx ret:%d, size:%d ctxId:%u type:%d",
774 nRet, size, ctx->id, ctx->type);
775 }
776 }
777 return nRet;
778 }
779
CommandForwardCheckResult(HCtxForward ctx, uint8_t *payload)780 bool HdcForwardBase::CommandForwardCheckResult(HCtxForward ctx, uint8_t *payload)
781 {
782 bool ret = true;
783 bool bCheck = static_cast<bool>(payload);
784 LogMsg(bCheck ? MSG_OK : MSG_FAIL, "Forwardport result:%s", bCheck ? "OK" : "Failed");
785 if (bCheck) {
786 string mapInfo = taskInfo->serverOrDaemon ? "1|" : "0|";
787 mapInfo += taskCommand;
788 ctx->ready = true;
789 ServerCommand(CMD_FORWARD_SUCCESS, reinterpret_cast<uint8_t *>(const_cast<char *>(mapInfo.c_str())),
790 mapInfo.size() + 1);
791 } else {
792 ret = false;
793 FreeContext(ctx, 0, false);
794 }
795 return ret;
796 }
797
ForwardCommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)798 bool HdcForwardBase::ForwardCommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
799 {
800 if (payloadSize <= DWORD_SERIALIZE_SIZE && command != CMD_FORWARD_FREE_CONTEXT
801 && command != CMD_FORWARD_ACTIVE_MASTER) {
802 WRITE_LOG(LOG_FATAL, "Illegal payloadSize, shorter than forward command header");
803 return false;
804 }
805 bool ret = true;
806 uint8_t *pContent = nullptr;
807 int sizeContent = 0;
808 uint32_t id = 0;
809 HCtxForward ctx = nullptr;
810 FilterCommand(payload, &id, &pContent);
811 sizeContent = payloadSize - DWORD_SERIALIZE_SIZE;
812 if (!(ctx = (HCtxForward)AdminContext(OP_QUERY, id, nullptr))) {
813 WRITE_LOG(LOG_WARN, "Query id:%u failed", id);
814 return true;
815 }
816 switch (command) {
817 case CMD_FORWARD_CHECK_RESULT: {
818 ret = CommandForwardCheckResult(ctx, pContent);
819 break;
820 }
821 case CMD_FORWARD_ACTIVE_MASTER: {
822 ret = DoForwardBegin(ctx);
823 break;
824 }
825 case CMD_FORWARD_DATA: {
826 if (ctx->finish) {
827 break;
828 }
829 if (SendForwardBuf(ctx, pContent, sizeContent) < 0) {
830 WRITE_LOG(LOG_WARN, "ForwardCommandDispatch SendForwardBuf rc < 0, ctxid:%u", ctx->id);
831 FreeContext(ctx, 0, true);
832 }
833 break;
834 }
835 case CMD_FORWARD_FREE_CONTEXT: {
836 FreeContext(ctx, 0, false);
837 break;
838 }
839 default:
840 ret = false;
841 break;
842 }
843 if (!ret) {
844 if (ctx) {
845 FreeContext(ctx, 0, true);
846 } else {
847 WRITE_LOG(LOG_DEBUG, "ctx==nullptr raw free");
848 TaskFinish();
849 }
850 }
851 return ret;
852 }
853
CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)854 bool HdcForwardBase::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
855 {
856 if (command != CMD_FORWARD_DATA) {
857 WRITE_LOG(LOG_WARN, "CommandDispatch command:%d payloadSize:%d", command, payloadSize);
858 }
859 bool ret = true;
860 string sError;
861 // prepare
862 if (command == CMD_FORWARD_INIT) {
863 string strCommand(reinterpret_cast<char *>(payload), payloadSize);
864 if (!BeginForward(strCommand, sError)) {
865 ret = false;
866 goto Finish;
867 }
868 return true;
869 } else if (command == CMD_FORWARD_CHECK) {
870 // Detect remote if it's reachable
871 if (!SlaveConnect(payload, payloadSize, true, sError)) {
872 ret = false;
873 goto Finish;
874 }
875 return true;
876 } else if (command == CMD_FORWARD_ACTIVE_SLAVE) {
877 // slave connect target port when activating
878 if (!SlaveConnect(payload, payloadSize, false, sError)) {
879 ret = false;
880 goto Finish;
881 }
882 return true;
883 }
884 if (!ForwardCommandDispatch(command, payload, payloadSize)) {
885 ret = false;
886 goto Finish;
887 }
888 Finish:
889 if (!ret) {
890 if (!sError.size()) {
891 LogMsg(MSG_FAIL, "Forward parament failed");
892 } else {
893 LogMsg(MSG_FAIL, const_cast<char *>(sError.c_str()));
894 WRITE_LOG(LOG_WARN, const_cast<char *>(sError.c_str()));
895 }
896 }
897 return ret;
898 }
899 } // namespace Hdc
900