cmd_send.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /*
  2. *
  3. * Copyright (c) 2021 Project CHIP Authors
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. #include <errno.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <lib/core/CHIPCore.h>
  21. #include <lib/shell/Engine.h>
  22. #include <lib/support/CodeUtils.h>
  23. #include <lib/support/ErrorStr.h>
  24. #include <messaging/ExchangeMgr.h>
  25. #include <platform/CHIPDeviceLayer.h>
  26. #include <protocols/secure_channel/PASESession.h>
  27. #include <system/SystemPacketBuffer.h>
  28. #include <transport/SecureSessionMgr.h>
  29. #include <transport/raw/TCP.h>
  30. #include <transport/raw/UDP.h>
  31. #include <ChipShellCollection.h>
  32. #include <Globals.h>
  33. using namespace chip;
  34. using namespace Shell;
  35. using namespace Logging;
  36. namespace {
  37. Messaging::ExchangeContext * gExchangeCtx = nullptr;
  38. class SendArguments
  39. {
  40. public:
  41. void Reset()
  42. {
  43. mProtocolId = 0x0002;
  44. mMessageType = 1;
  45. mLastSendTime = 0;
  46. mPayloadSize = 32;
  47. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  48. mUsingTCP = false;
  49. #endif
  50. mUsingMRP = true;
  51. mPort = CHIP_PORT;
  52. }
  53. uint64_t GetLastSendTime() const { return mLastSendTime; }
  54. void SetLastSendTime(uint64_t value) { mLastSendTime = value; }
  55. uint16_t GetProtocolId() const { return mProtocolId; }
  56. void SetProtocolId(uint16_t value) { mProtocolId = value; }
  57. uint32_t GetPayloadSize() const { return mPayloadSize; }
  58. void SetPayloadSize(uint32_t value) { mPayloadSize = value; }
  59. uint16_t GetPort() const { return mPort; }
  60. void SetPort(uint16_t value) { mPort = value; }
  61. uint8_t GetMessageType() const { return mMessageType; }
  62. void SetMessageType(uint8_t type) { mMessageType = type; }
  63. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  64. bool IsUsingTCP() const { return mUsingTCP; }
  65. void SetUsingTCP(bool value) { mUsingTCP = value; }
  66. #endif
  67. bool IsUsingMRP() const { return mUsingMRP; }
  68. void SetUsingMRP(bool value) { mUsingMRP = value; }
  69. private:
  70. // The last time a CHIP message was attempted to be sent.
  71. uint64_t mLastSendTime;
  72. uint32_t mPayloadSize;
  73. uint16_t mProtocolId;
  74. uint16_t mPort;
  75. uint8_t mMessageType;
  76. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  77. bool mUsingTCP;
  78. #endif
  79. bool mUsingMRP;
  80. } gSendArguments;
  81. class MockAppDelegate : public Messaging::ExchangeDelegate
  82. {
  83. public:
  84. CHIP_ERROR OnMessageReceived(Messaging::ExchangeContext * ec, const PacketHeader & packetHeader,
  85. const PayloadHeader & payloadHeader, System::PacketBufferHandle && buffer) override
  86. {
  87. uint32_t respTime = System::Clock::GetMonotonicMilliseconds();
  88. uint32_t transitTime = respTime - gSendArguments.GetLastSendTime();
  89. streamer_t * sout = streamer_get();
  90. streamer_printf(sout, "Response received: len=%u time=%.3fms\n", buffer->DataLength(),
  91. static_cast<double>(transitTime) / 1000);
  92. gExchangeCtx = nullptr;
  93. return CHIP_NO_ERROR;
  94. }
  95. void OnResponseTimeout(Messaging::ExchangeContext * ec) override
  96. {
  97. streamer_t * sout = streamer_get();
  98. streamer_printf(sout, "No response received\n");
  99. gExchangeCtx->Close();
  100. gExchangeCtx = nullptr;
  101. }
  102. } gMockAppDelegate;
  103. CHIP_ERROR SendMessage(streamer_t * stream)
  104. {
  105. CHIP_ERROR err = CHIP_NO_ERROR;
  106. Messaging::SendFlags sendFlags;
  107. System::PacketBufferHandle payloadBuf;
  108. uint32_t payloadSize = gSendArguments.GetPayloadSize();
  109. // Discard any existing exchange context. Effectively we can only have one exchange with
  110. // a single node at any one time.
  111. if (gExchangeCtx != nullptr)
  112. {
  113. gExchangeCtx->Abort();
  114. gExchangeCtx = nullptr;
  115. }
  116. // Create a new exchange context.
  117. gExchangeCtx = gExchangeManager.NewContext({ kTestDeviceNodeId, 0, gAdminId }, &gMockAppDelegate);
  118. VerifyOrExit(gExchangeCtx != nullptr, err = CHIP_ERROR_NO_MEMORY);
  119. payloadBuf = MessagePacketBuffer::New(payloadSize);
  120. VerifyOrExit(!payloadBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
  121. memset(payloadBuf->Start(), 0, payloadSize);
  122. payloadBuf->SetDataLength(payloadSize);
  123. if (gSendArguments.IsUsingMRP())
  124. {
  125. sendFlags.Set(Messaging::SendMessageFlags::kNone);
  126. }
  127. else
  128. {
  129. sendFlags.Set(Messaging::SendMessageFlags::kNoAutoRequestAck);
  130. }
  131. gExchangeCtx->SetResponseTimeout(kResponseTimeOut);
  132. sendFlags.Set(Messaging::SendMessageFlags::kExpectResponse);
  133. gSendArguments.SetLastSendTime(System::Clock::GetMonotonicMilliseconds());
  134. streamer_printf(stream, "\nSend CHIP message with payload size: %d bytes to Node: %" PRIu64 "\n", payloadSize,
  135. kTestDeviceNodeId);
  136. err = gExchangeCtx->SendMessage(Protocols::Id(VendorId::Common, gSendArguments.GetProtocolId()),
  137. gSendArguments.GetMessageType(), std::move(payloadBuf), sendFlags);
  138. if (err != CHIP_NO_ERROR)
  139. {
  140. gExchangeCtx->Abort();
  141. gExchangeCtx = nullptr;
  142. }
  143. exit:
  144. if (err != CHIP_NO_ERROR)
  145. {
  146. streamer_printf(stream, "Send CHIP message failed, err: %s\n", ErrorStr(err));
  147. }
  148. return err;
  149. }
  150. CHIP_ERROR EstablishSecureSession(streamer_t * stream, Transport::PeerAddress & peerAddress)
  151. {
  152. CHIP_ERROR err = CHIP_NO_ERROR;
  153. Optional<Transport::PeerAddress> peerAddr;
  154. SecurePairingUsingTestSecret * testSecurePairingSecret = chip::Platform::New<SecurePairingUsingTestSecret>();
  155. VerifyOrExit(testSecurePairingSecret != nullptr, err = CHIP_ERROR_NO_MEMORY);
  156. peerAddr = Optional<Transport::PeerAddress>::Value(peerAddress);
  157. // Attempt to connect to the peer.
  158. err = gSessionManager.NewPairing(peerAddr, kTestDeviceNodeId, testSecurePairingSecret, SecureSession::SessionRole::kInitiator,
  159. gAdminId);
  160. exit:
  161. if (err != CHIP_NO_ERROR)
  162. {
  163. streamer_printf(stream, "Establish secure session failed, err: %s\n", ErrorStr(err));
  164. gSendArguments.SetLastSendTime(System::Clock::GetMonotonicMilliseconds());
  165. }
  166. else
  167. {
  168. streamer_printf(stream, "Establish secure session succeeded\n");
  169. }
  170. return err;
  171. }
  172. void ProcessCommand(streamer_t * stream, char * destination)
  173. {
  174. CHIP_ERROR err = CHIP_NO_ERROR;
  175. Transport::AdminPairingTable admins;
  176. Transport::PeerAddress peerAddress;
  177. Transport::AdminPairingInfo * adminInfo = nullptr;
  178. if (!chip::Inet::IPAddress::FromString(destination, gDestAddr))
  179. {
  180. streamer_printf(stream, "Invalid CHIP Server IP address: %s\n", destination);
  181. ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
  182. }
  183. adminInfo = admins.AssignAdminId(gAdminId, kTestControllerNodeId);
  184. VerifyOrExit(adminInfo != nullptr, err = CHIP_ERROR_NO_MEMORY);
  185. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  186. err = gTCPManager.Init(Transport::TcpListenParameters(&DeviceLayer::InetLayer)
  187. .SetAddressType(gDestAddr.Type())
  188. .SetListenPort(gSendArguments.GetPort() + 1));
  189. VerifyOrExit(err == CHIP_NO_ERROR, streamer_printf(stream, "Failed to init TCP manager error: %s\n", ErrorStr(err)));
  190. #endif
  191. err = gUDPManager.Init(Transport::UdpListenParameters(&DeviceLayer::InetLayer)
  192. .SetAddressType(gDestAddr.Type())
  193. .SetListenPort(gSendArguments.GetPort() + 1));
  194. VerifyOrExit(err == CHIP_NO_ERROR, streamer_printf(stream, "Failed to init UDP manager error: %s\n", ErrorStr(err)));
  195. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  196. if (gSendArguments.IsUsingTCP())
  197. {
  198. peerAddress = Transport::PeerAddress::TCP(gDestAddr, gSendArguments.GetPort());
  199. err =
  200. gSessionManager.Init(kTestControllerNodeId, &DeviceLayer::SystemLayer, &gTCPManager, &admins, &gMessageCounterManager);
  201. SuccessOrExit(err);
  202. }
  203. else
  204. #endif
  205. {
  206. peerAddress = Transport::PeerAddress::UDP(gDestAddr, gSendArguments.GetPort(), INET_NULL_INTERFACEID);
  207. err =
  208. gSessionManager.Init(kTestControllerNodeId, &DeviceLayer::SystemLayer, &gUDPManager, &admins, &gMessageCounterManager);
  209. SuccessOrExit(err);
  210. }
  211. err = gExchangeManager.Init(&gSessionManager);
  212. SuccessOrExit(err);
  213. err = gMessageCounterManager.Init(&gExchangeManager);
  214. SuccessOrExit(err);
  215. // Start the CHIP connection to the CHIP server.
  216. err = EstablishSecureSession(stream, peerAddress);
  217. SuccessOrExit(err);
  218. err = SendMessage(stream);
  219. SuccessOrExit(err);
  220. // TODO:#5496: Use condition_varible to suspend the current thread and wake it up when response arrive.
  221. sleep(2);
  222. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  223. gTCPManager.Disconnect(peerAddress);
  224. gTCPManager.Close();
  225. #endif
  226. gUDPManager.Close();
  227. gExchangeManager.Shutdown();
  228. gSessionManager.Shutdown();
  229. exit:
  230. if ((err != CHIP_NO_ERROR))
  231. {
  232. streamer_printf(stream, "Send failed with error: %s\n", ErrorStr(err));
  233. }
  234. }
  235. void PrintUsage(streamer_t * stream)
  236. {
  237. streamer_printf(stream, "Usage: send [options] <destination>\n\nOptions:\n");
  238. // Need to split the help info to prevent overflowing the streamer_printf
  239. // buffer (CONSOLE_DEFAULT_MAX_LINE 256)
  240. streamer_printf(stream, " -h print help information\n");
  241. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  242. streamer_printf(stream, " -u use UDP (default)\n");
  243. streamer_printf(stream, " -t use TCP\n");
  244. #endif
  245. streamer_printf(stream, " -P <protocol> protocol ID\n");
  246. streamer_printf(stream, " -T <type> message type\n");
  247. streamer_printf(stream, " -p <port> server port number\n");
  248. streamer_printf(stream, " -r <1|0> enable or disable MRP\n");
  249. streamer_printf(stream, " -s <size> application payload size in bytes\n");
  250. }
  251. CHIP_ERROR cmd_send(int argc, char ** argv)
  252. {
  253. streamer_t * sout = streamer_get();
  254. int optIndex = 0;
  255. gSendArguments.Reset();
  256. while (optIndex < argc && argv[optIndex][0] == '-')
  257. {
  258. switch (argv[optIndex][1])
  259. {
  260. case 'h':
  261. PrintUsage(sout);
  262. return CHIP_NO_ERROR;
  263. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  264. case 'u':
  265. gSendArguments.SetUsingTCP(false);
  266. break;
  267. case 't':
  268. gSendArguments.SetUsingTCP(true);
  269. break;
  270. #endif
  271. case 'P':
  272. if (++optIndex >= argc || argv[optIndex][0] == '-')
  273. {
  274. streamer_printf(sout, "Invalid argument specified for -P\n");
  275. return CHIP_ERROR_INVALID_ARGUMENT;
  276. }
  277. else
  278. {
  279. gSendArguments.SetProtocolId(atol(argv[optIndex]));
  280. }
  281. break;
  282. case 'T':
  283. if (++optIndex >= argc || argv[optIndex][0] == '-')
  284. {
  285. streamer_printf(sout, "Invalid argument specified for -T\n");
  286. return CHIP_ERROR_INVALID_ARGUMENT;
  287. }
  288. else
  289. {
  290. gSendArguments.SetMessageType(atoi(argv[optIndex]));
  291. }
  292. break;
  293. case 'p':
  294. if (++optIndex >= argc || argv[optIndex][0] == '-')
  295. {
  296. streamer_printf(sout, "Invalid argument specified for -p\n");
  297. return CHIP_ERROR_INVALID_ARGUMENT;
  298. }
  299. else
  300. {
  301. gSendArguments.SetPort(atol(argv[optIndex]));
  302. }
  303. break;
  304. case 's':
  305. if (++optIndex >= argc || argv[optIndex][0] == '-')
  306. {
  307. streamer_printf(sout, "Invalid argument specified for -s\n");
  308. return CHIP_ERROR_INVALID_ARGUMENT;
  309. }
  310. else
  311. {
  312. gSendArguments.SetPayloadSize(atol(argv[optIndex]));
  313. }
  314. break;
  315. case 'r':
  316. if (++optIndex >= argc || argv[optIndex][0] == '-')
  317. {
  318. streamer_printf(sout, "Invalid argument specified for -r\n");
  319. return CHIP_ERROR_INVALID_ARGUMENT;
  320. }
  321. else
  322. {
  323. int arg = atoi(argv[optIndex]);
  324. if (arg == 0)
  325. {
  326. gSendArguments.SetUsingMRP(false);
  327. }
  328. else if (arg == 1)
  329. {
  330. gSendArguments.SetUsingMRP(true);
  331. }
  332. else
  333. {
  334. return CHIP_ERROR_INVALID_ARGUMENT;
  335. }
  336. }
  337. break;
  338. default:
  339. return CHIP_ERROR_INVALID_ARGUMENT;
  340. }
  341. optIndex++;
  342. }
  343. if (optIndex >= argc)
  344. {
  345. streamer_printf(sout, "Missing IP address\n");
  346. return CHIP_ERROR_INVALID_ARGUMENT;
  347. }
  348. streamer_printf(sout, "IP address: %s\n", argv[optIndex]);
  349. ProcessCommand(sout, argv[optIndex]);
  350. return CHIP_NO_ERROR;
  351. }
  352. } // namespace
  353. static shell_command_t cmds_send[] = {
  354. { &cmd_send, "send", "Send raw CHIP message" },
  355. };
  356. void cmd_send_init()
  357. {
  358. Engine::Root().RegisterCommands(cmds_send, ArraySize(cmds_send));
  359. }