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::GetMaxBufSizeStable() * 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,const int bufSize,bool bCheckPoint,string & sError)604 bool HdcForwardBase::SlaveConnect(uint8_t *bufCmd, const int bufSize, bool bCheckPoint, string &sError)
605 {
606 if (bufSize <= DWORD_SERIALIZE_SIZE + forwardParameterBufSize) {
607 WRITE_LOG(LOG_FATAL, "Illegal payloadSize, shorter than forward header");
608 return false;
609 }
610 bool ret = false;
611 char *content = nullptr;
612 uint32_t idSlaveOld = 0;
613 HCtxForward ctxPoint = (HCtxForward)MallocContext(false);
614 if (!ctxPoint) {
615 WRITE_LOG(LOG_FATAL, "MallocContext failed");
616 return false;
617 }
618 idSlaveOld = ctxPoint->id;
619 ctxPoint->checkPoint = bCheckPoint;
620 // refresh another id,8byte param
621 FilterCommand(bufCmd, &ctxPoint->id, reinterpret_cast<uint8_t **>(&content));
622 AdminContext(OP_UPDATE, idSlaveOld, ctxPoint);
623 content += forwardParameterBufSize;
624 if (!CheckNodeInfo(content, ctxPoint->localArgs)) {
625 WRITE_LOG(LOG_FATAL, "SlaveConnect CheckNodeInfo failed content:%s", content);
626 goto Finish;
627 }
628 if (!DetechForwardType(ctxPoint)) {
629 WRITE_LOG(LOG_FATAL, "SlaveConnect DetechForwardType failed content:%s", content);
630 goto Finish;
631 }
632 WRITE_LOG(LOG_DEBUG, "id:%u type:%d", ctxPoint->id, ctxPoint->type);
633 if (ctxPoint->type == FORWARD_ARK) {
634 if (ctxPoint->checkPoint) {
635 if (!SetupArkPoint(ctxPoint)) {
636 sError = ctxPoint->lastError;
637 WRITE_LOG(LOG_FATAL, "SlaveConnect SetupArkPoint failed content:%s", content);
638 goto Finish;
639 }
640 } else {
641 SetupPointContinue(ctxPoint, 0);
642 }
643 ret = true;
644 } else {
645 if (!ctxPoint->checkPoint) {
646 if (!SetupPoint(ctxPoint)) {
647 sError = ctxPoint->lastError;
648 WRITE_LOG(LOG_FATAL, "SlaveConnect SetupPoint failed content:%s", content);
649 goto Finish;
650 }
651 } else {
652 SetupPointContinue(ctxPoint, 0);
653 }
654 ret = true;
655 }
656 Finish:
657 if (!ret) {
658 FreeContext(ctxPoint, 0, true);
659 }
660 return ret;
661 }
662
DoForwardBegin(HCtxForward ctx)663 bool HdcForwardBase::DoForwardBegin(HCtxForward ctx)
664 {
665 switch (ctx->type) {
666 case FORWARD_TCP:
667 case FORWARD_JDWP: // jdwp use tcp ->socketpair->jvm
668 uv_tcp_nodelay((uv_tcp_t *)&ctx->tcp, 1);
669 uv_read_start((uv_stream_t *)&ctx->tcp, AllocForwardBuf, ReadForwardBuf);
670 break;
671 case FORWARD_ARK:
672 WRITE_LOG(LOG_DEBUG, "DoForwardBegin ark socketpair id:%u fds[0]:%d", ctx->id, fds[0]);
673 uv_tcp_init(loopTask, &ctx->tcp);
674 uv_tcp_open(&ctx->tcp, fds[0]);
675 uv_tcp_nodelay((uv_tcp_t *)&ctx->tcp, 1);
676 uv_read_start((uv_stream_t *)&ctx->tcp, AllocForwardBuf, ReadForwardBuf);
677 break;
678 case FORWARD_ABSTRACT:
679 case FORWARD_RESERVED:
680 case FORWARD_FILESYSTEM:
681 uv_read_start((uv_stream_t *)&ctx->pipe, AllocForwardBuf, ReadForwardBuf);
682 break;
683 case FORWARD_DEVICE: {
684 ctx->fdClass->StartWorkOnThread();
685 break;
686 }
687 default:
688 break;
689 }
690 ctx->ready = true;
691 return true;
692 }
693
AdminContext(const uint8_t op,const uint32_t id,HCtxForward hInput)694 void *HdcForwardBase::AdminContext(const uint8_t op, const uint32_t id, HCtxForward hInput)
695 {
696 ctxPointMutex.lock();
697 void *hRet = nullptr;
698 map<uint32_t, HCtxForward> &mapCtx = mapCtxPoint;
699 switch (op) {
700 case OP_ADD:
701 mapCtx[id] = hInput;
702 break;
703 case OP_REMOVE:
704 mapCtx.erase(id);
705 break;
706 case OP_QUERY:
707 if (mapCtx.count(id)) {
708 hRet = mapCtx[id];
709 }
710 break;
711 case OP_UPDATE:
712 mapCtx.erase(id);
713 mapCtx[hInput->id] = hInput;
714 break;
715 default:
716 break;
717 }
718 ctxPointMutex.unlock();
719 return hRet;
720 }
721
SendCallbackForwardBuf(uv_write_t * req,int status)722 void HdcForwardBase::SendCallbackForwardBuf(uv_write_t *req, int status)
723 {
724 ContextForwardIO *ctxIO = (ContextForwardIO *)req->data;
725 HCtxForward ctx = reinterpret_cast<HCtxForward>(ctxIO->ctxForward);
726 if (status < 0 && !ctx->finish) {
727 WRITE_LOG(LOG_DEBUG, "SendCallbackForwardBuf ctx->type:%d, status:%d finish", ctx->type, status);
728 ctx->thisClass->FreeContext(ctx, 0, true);
729 }
730 delete[] ctxIO->bufIO;
731 delete ctxIO;
732 delete req;
733 }
734
SendForwardBuf(HCtxForward ctx,uint8_t * bufPtr,const int size)735 int HdcForwardBase::SendForwardBuf(HCtxForward ctx, uint8_t *bufPtr, const int size)
736 {
737 int nRet = 0;
738 if (size > static_cast<int>(HDC_BUF_MAX_BYTES - 1)) {
739 WRITE_LOG(LOG_WARN, "SendForwardBuf size:%d > HDC_BUF_MAX_BYTES", size);
740 return -1;
741 }
742 if (size <= 0) {
743 WRITE_LOG(LOG_WARN, "SendForwardBuf failed size:%d", size);
744 return -1;
745 }
746 auto pDynBuf = new(std::nothrow) uint8_t[size];
747 if (!pDynBuf) {
748 return -1;
749 }
750 (void)memcpy_s(pDynBuf, size, bufPtr, size);
751 if (ctx->type == FORWARD_DEVICE) {
752 nRet = ctx->fdClass->WriteWithMem(pDynBuf, size);
753 } else {
754 auto ctxIO = new ContextForwardIO();
755 if (!ctxIO) {
756 delete[] pDynBuf;
757 return -1;
758 }
759 ctxIO->ctxForward = ctx;
760 ctxIO->bufIO = pDynBuf;
761 if (ctx->type == FORWARD_TCP || ctx->type == FORWARD_JDWP || ctx->type == FORWARD_ARK) {
762 nRet = Base::SendToStreamEx((uv_stream_t *)&ctx->tcp, pDynBuf, size, nullptr,
763 (void *)SendCallbackForwardBuf, (void *)ctxIO);
764 } else {
765 // FORWARD_ABSTRACT, FORWARD_RESERVED, FORWARD_FILESYSTEM,
766 nRet = Base::SendToStreamEx((uv_stream_t *)&ctx->pipe, pDynBuf, size, nullptr,
767 (void *)SendCallbackForwardBuf, (void *)ctxIO);
768 }
769 }
770 return nRet;
771 }
772
CommandForwardCheckResult(HCtxForward ctx,uint8_t * payload)773 bool HdcForwardBase::CommandForwardCheckResult(HCtxForward ctx, uint8_t *payload)
774 {
775 bool ret = true;
776 bool bCheck = static_cast<bool>(payload);
777 LogMsg(bCheck ? MSG_OK : MSG_FAIL, "Forwardport result:%s", bCheck ? "OK" : "Failed");
778 if (bCheck) {
779 string mapInfo = taskInfo->serverOrDaemon ? "1|" : "0|";
780 mapInfo += taskCommand;
781 ctx->ready = true;
782 ServerCommand(CMD_FORWARD_SUCCESS, reinterpret_cast<uint8_t *>(const_cast<char *>(mapInfo.c_str())),
783 mapInfo.size() + 1);
784 } else {
785 ret = false;
786 FreeContext(ctx, 0, false);
787 }
788 return ret;
789 }
790
ForwardCommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)791 bool HdcForwardBase::ForwardCommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
792 {
793 if (payloadSize <= DWORD_SERIALIZE_SIZE && command != CMD_FORWARD_FREE_CONTEXT
794 && command != CMD_FORWARD_ACTIVE_MASTER) {
795 WRITE_LOG(LOG_FATAL, "Illegal payloadSize, shorter than forward command header");
796 return false;
797 }
798 bool ret = true;
799 uint8_t *pContent = nullptr;
800 int sizeContent = 0;
801 uint32_t id = 0;
802 HCtxForward ctx = nullptr;
803 FilterCommand(payload, &id, &pContent);
804 sizeContent = payloadSize - DWORD_SERIALIZE_SIZE;
805 if (!(ctx = (HCtxForward)AdminContext(OP_QUERY, id, nullptr))) {
806 WRITE_LOG(LOG_WARN, "Query id:%u failed", id);
807 return true;
808 }
809 switch (command) {
810 case CMD_FORWARD_CHECK_RESULT: {
811 ret = CommandForwardCheckResult(ctx, pContent);
812 break;
813 }
814 case CMD_FORWARD_ACTIVE_MASTER: {
815 ret = DoForwardBegin(ctx);
816 break;
817 }
818 case CMD_FORWARD_DATA: {
819 if (ctx->finish) {
820 break;
821 }
822 if (SendForwardBuf(ctx, pContent, sizeContent) < 0) {
823 FreeContext(ctx, 0, true);
824 }
825 break;
826 }
827 case CMD_FORWARD_FREE_CONTEXT: {
828 FreeContext(ctx, 0, false);
829 break;
830 }
831 default:
832 ret = false;
833 break;
834 }
835 if (!ret) {
836 if (ctx) {
837 FreeContext(ctx, 0, true);
838 } else {
839 WRITE_LOG(LOG_DEBUG, "ctx==nullptr raw free");
840 TaskFinish();
841 }
842 }
843 return ret;
844 }
845
CommandDispatch(const uint16_t command,uint8_t * payload,const int payloadSize)846 bool HdcForwardBase::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize)
847 {
848 if (command != CMD_FORWARD_DATA) {
849 WRITE_LOG(LOG_WARN, "CommandDispatch command:%d payloadSize:%d", command, payloadSize);
850 }
851 bool ret = true;
852 string sError;
853 // prepare
854 if (command == CMD_FORWARD_INIT) {
855 string strCommand(reinterpret_cast<char *>(payload), payloadSize);
856 if (!BeginForward(strCommand, sError)) {
857 ret = false;
858 goto Finish;
859 }
860 return true;
861 } else if (command == CMD_FORWARD_CHECK) {
862 // Detect remote if it's reachable
863 if (!SlaveConnect(payload, payloadSize, true, sError)) {
864 ret = false;
865 goto Finish;
866 }
867 return true;
868 } else if (command == CMD_FORWARD_ACTIVE_SLAVE) {
869 // slave connect target port when activating
870 if (!SlaveConnect(payload, payloadSize, false, sError)) {
871 ret = false;
872 goto Finish;
873 }
874 return true;
875 }
876 if (!ForwardCommandDispatch(command, payload, payloadSize)) {
877 ret = false;
878 goto Finish;
879 }
880 Finish:
881 if (!ret) {
882 if (!sError.size()) {
883 LogMsg(MSG_FAIL, "Forward parament failed");
884 } else {
885 LogMsg(MSG_FAIL, const_cast<char *>(sError.c_str()));
886 WRITE_LOG(LOG_WARN, const_cast<char *>(sError.c_str()));
887 }
888 }
889 return ret;
890 }
891 } // namespace Hdc
892