cmd_send.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  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. mUsingCRMP = 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 IsUsingCRMP() const { return mUsingCRMP; }
  68. void SetUsingCRMP(bool value) { mUsingCRMP = 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 mUsingCRMP;
  80. } gSendArguments;
  81. class MockAppDelegate : public Messaging::ExchangeDelegate
  82. {
  83. public:
  84. void OnMessageReceived(Messaging::ExchangeContext * ec, const PacketHeader & packetHeader, const PayloadHeader & payloadHeader,
  85. System::PacketBufferHandle && buffer) override
  86. {
  87. uint32_t respTime = System::Timer::GetCurrentEpoch();
  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->Close();
  93. gExchangeCtx = nullptr;
  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. char * requestData = nullptr;
  109. uint32_t size = 0;
  110. // Discard any existing exchange context. Effectively we can only have one exchange with
  111. // a single node at any one time.
  112. if (gExchangeCtx != nullptr)
  113. {
  114. gExchangeCtx->Abort();
  115. gExchangeCtx = nullptr;
  116. }
  117. // Create a new exchange context.
  118. gExchangeCtx = gExchangeManager.NewContext({ kTestDeviceNodeId, 0, gAdminId }, &gMockAppDelegate);
  119. VerifyOrExit(gExchangeCtx != nullptr, err = CHIP_ERROR_NO_MEMORY);
  120. size = gSendArguments.GetPayloadSize();
  121. VerifyOrExit(size <= kMaxPayloadSize, err = CHIP_ERROR_INVALID_MESSAGE_LENGTH);
  122. requestData = static_cast<char *>(chip::Platform::MemoryAlloc(size));
  123. VerifyOrExit(requestData != nullptr, err = CHIP_ERROR_NO_MEMORY);
  124. snprintf(requestData, size, "CHIP Message");
  125. payloadBuf = MessagePacketBuffer::NewWithData(requestData, size);
  126. VerifyOrExit(!payloadBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
  127. if (gSendArguments.IsUsingCRMP())
  128. {
  129. sendFlags.Set(Messaging::SendMessageFlags::kNone);
  130. }
  131. else
  132. {
  133. sendFlags.Set(Messaging::SendMessageFlags::kNoAutoRequestAck);
  134. }
  135. gExchangeCtx->SetResponseTimeout(kResponseTimeOut);
  136. sendFlags.Set(Messaging::SendMessageFlags::kExpectResponse);
  137. gSendArguments.SetLastSendTime(System::Timer::GetCurrentEpoch());
  138. streamer_printf(stream, "\nSend CHIP message with payload size: %d bytes to Node: %" PRIu64 "\n", size, kTestDeviceNodeId);
  139. err = gExchangeCtx->SendMessage(Protocols::Id(VendorId::Common, gSendArguments.GetProtocolId()),
  140. gSendArguments.GetMessageType(), std::move(payloadBuf), sendFlags);
  141. if (err != CHIP_NO_ERROR)
  142. {
  143. gExchangeCtx->Abort();
  144. gExchangeCtx = nullptr;
  145. }
  146. exit:
  147. if (requestData != nullptr)
  148. {
  149. chip::Platform::MemoryFree(requestData);
  150. }
  151. if (err != CHIP_NO_ERROR)
  152. {
  153. streamer_printf(stream, "Send CHIP message failed, err: %s\n", ErrorStr(err));
  154. }
  155. return err;
  156. }
  157. CHIP_ERROR EstablishSecureSession(streamer_t * stream, Transport::PeerAddress & peerAddress)
  158. {
  159. CHIP_ERROR err = CHIP_NO_ERROR;
  160. Optional<Transport::PeerAddress> peerAddr;
  161. SecurePairingUsingTestSecret * testSecurePairingSecret = chip::Platform::New<SecurePairingUsingTestSecret>();
  162. VerifyOrExit(testSecurePairingSecret != nullptr, err = CHIP_ERROR_NO_MEMORY);
  163. peerAddr = Optional<Transport::PeerAddress>::Value(peerAddress);
  164. // Attempt to connect to the peer.
  165. err = gSessionManager.NewPairing(peerAddr, kTestDeviceNodeId, testSecurePairingSecret, SecureSession::SessionRole::kInitiator,
  166. gAdminId);
  167. exit:
  168. if (err != CHIP_NO_ERROR)
  169. {
  170. streamer_printf(stream, "Establish secure session failed, err: %s\n", ErrorStr(err));
  171. gSendArguments.SetLastSendTime(System::Timer::GetCurrentEpoch());
  172. }
  173. else
  174. {
  175. streamer_printf(stream, "Establish secure session succeeded\n");
  176. }
  177. return err;
  178. }
  179. void ProcessCommand(streamer_t * stream, char * destination)
  180. {
  181. CHIP_ERROR err = CHIP_NO_ERROR;
  182. Transport::AdminPairingTable admins;
  183. Transport::PeerAddress peerAddress;
  184. Transport::AdminPairingInfo * adminInfo = nullptr;
  185. if (!chip::Inet::IPAddress::FromString(destination, gDestAddr))
  186. {
  187. streamer_printf(stream, "Invalid CHIP Server IP address: %s\n", destination);
  188. ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
  189. }
  190. adminInfo = admins.AssignAdminId(gAdminId, kTestControllerNodeId);
  191. VerifyOrExit(adminInfo != nullptr, err = CHIP_ERROR_NO_MEMORY);
  192. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  193. err = gTCPManager.Init(Transport::TcpListenParameters(&DeviceLayer::InetLayer)
  194. .SetAddressType(gDestAddr.Type())
  195. .SetListenPort(gSendArguments.GetPort() + 1));
  196. VerifyOrExit(err == CHIP_NO_ERROR, streamer_printf(stream, "Failed to init TCP manager error: %s\n", ErrorStr(err)));
  197. #endif
  198. err = gUDPManager.Init(Transport::UdpListenParameters(&DeviceLayer::InetLayer)
  199. .SetAddressType(gDestAddr.Type())
  200. .SetListenPort(gSendArguments.GetPort() + 1));
  201. VerifyOrExit(err == CHIP_NO_ERROR, streamer_printf(stream, "Failed to init UDP manager error: %s\n", ErrorStr(err)));
  202. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  203. if (gSendArguments.IsUsingTCP())
  204. {
  205. peerAddress = Transport::PeerAddress::TCP(gDestAddr, gSendArguments.GetPort());
  206. err =
  207. gSessionManager.Init(kTestControllerNodeId, &DeviceLayer::SystemLayer, &gTCPManager, &admins, &gMessageCounterManager);
  208. SuccessOrExit(err);
  209. }
  210. else
  211. #endif
  212. {
  213. peerAddress = Transport::PeerAddress::UDP(gDestAddr, gSendArguments.GetPort(), INET_NULL_INTERFACEID);
  214. err =
  215. gSessionManager.Init(kTestControllerNodeId, &DeviceLayer::SystemLayer, &gUDPManager, &admins, &gMessageCounterManager);
  216. SuccessOrExit(err);
  217. }
  218. err = gExchangeManager.Init(&gSessionManager);
  219. SuccessOrExit(err);
  220. err = gMessageCounterManager.Init(&gExchangeManager);
  221. SuccessOrExit(err);
  222. // Start the CHIP connection to the CHIP server.
  223. err = EstablishSecureSession(stream, peerAddress);
  224. SuccessOrExit(err);
  225. err = SendMessage(stream);
  226. SuccessOrExit(err);
  227. // TODO:#5496: Use condition_varible to suspend the current thread and wake it up when response arrive.
  228. sleep(2);
  229. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  230. gTCPManager.Disconnect(peerAddress);
  231. gTCPManager.Close();
  232. #endif
  233. gUDPManager.Close();
  234. gExchangeManager.Shutdown();
  235. gSessionManager.Shutdown();
  236. exit:
  237. if ((err != CHIP_NO_ERROR))
  238. {
  239. streamer_printf(stream, "Send failed with error: %s\n", ErrorStr(err));
  240. }
  241. }
  242. void PrintUsage(streamer_t * stream)
  243. {
  244. streamer_printf(stream, "Usage: send [options] <destination>\n\nOptions:\n");
  245. // Need to split the help info to prevent overflowing the streamer_printf
  246. // buffer (CONSOLE_DEFAULT_MAX_LINE 256)
  247. streamer_printf(stream, " -h print help information\n");
  248. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  249. streamer_printf(stream, " -u use UDP (default)\n");
  250. streamer_printf(stream, " -t use TCP\n");
  251. #endif
  252. streamer_printf(stream, " -P <protocol> protocol ID\n");
  253. streamer_printf(stream, " -T <type> message type\n");
  254. streamer_printf(stream, " -p <port> server port number\n");
  255. streamer_printf(stream, " -r <1|0> enable or disable CRMP\n");
  256. streamer_printf(stream, " -s <size> payload size in bytes\n");
  257. }
  258. int cmd_send(int argc, char ** argv)
  259. {
  260. streamer_t * sout = streamer_get();
  261. int ret = 0;
  262. int optIndex = 0;
  263. gSendArguments.Reset();
  264. while (optIndex < argc && argv[optIndex][0] == '-')
  265. {
  266. switch (argv[optIndex][1])
  267. {
  268. case 'h':
  269. PrintUsage(sout);
  270. return 0;
  271. #if INET_CONFIG_ENABLE_TCP_ENDPOINT
  272. case 'u':
  273. gSendArguments.SetUsingTCP(false);
  274. break;
  275. case 't':
  276. gSendArguments.SetUsingTCP(true);
  277. break;
  278. #endif
  279. case 'P':
  280. if (++optIndex >= argc || argv[optIndex][0] == '-')
  281. {
  282. streamer_printf(sout, "Invalid argument specified for -P\n");
  283. return -1;
  284. }
  285. else
  286. {
  287. gSendArguments.SetProtocolId(atol(argv[optIndex]));
  288. }
  289. break;
  290. case 'T':
  291. if (++optIndex >= argc || argv[optIndex][0] == '-')
  292. {
  293. streamer_printf(sout, "Invalid argument specified for -T\n");
  294. return -1;
  295. }
  296. else
  297. {
  298. gSendArguments.SetMessageType(atoi(argv[optIndex]));
  299. }
  300. break;
  301. case 'p':
  302. if (++optIndex >= argc || argv[optIndex][0] == '-')
  303. {
  304. streamer_printf(sout, "Invalid argument specified for -p\n");
  305. return -1;
  306. }
  307. else
  308. {
  309. gSendArguments.SetPort(atol(argv[optIndex]));
  310. }
  311. break;
  312. case 's':
  313. if (++optIndex >= argc || argv[optIndex][0] == '-')
  314. {
  315. streamer_printf(sout, "Invalid argument specified for -s\n");
  316. return -1;
  317. }
  318. else
  319. {
  320. gSendArguments.SetPayloadSize(atol(argv[optIndex]));
  321. }
  322. break;
  323. case 'r':
  324. if (++optIndex >= argc || argv[optIndex][0] == '-')
  325. {
  326. streamer_printf(sout, "Invalid argument specified for -r\n");
  327. return -1;
  328. }
  329. else
  330. {
  331. int arg = atoi(argv[optIndex]);
  332. if (arg == 0)
  333. {
  334. gSendArguments.SetUsingCRMP(false);
  335. }
  336. else if (arg == 1)
  337. {
  338. gSendArguments.SetUsingCRMP(true);
  339. }
  340. else
  341. {
  342. ret = -1;
  343. }
  344. }
  345. break;
  346. default:
  347. ret = -1;
  348. }
  349. optIndex++;
  350. }
  351. if (optIndex >= argc)
  352. {
  353. streamer_printf(sout, "Missing IP address\n");
  354. ret = -1;
  355. }
  356. if (ret == 0)
  357. {
  358. streamer_printf(sout, "IP address: %s\n", argv[optIndex]);
  359. ProcessCommand(sout, argv[optIndex]);
  360. }
  361. return ret;
  362. }
  363. } // namespace
  364. static shell_command_t cmds_send[] = {
  365. { &cmd_send, "send", "Send raw CHIP message" },
  366. };
  367. void cmd_send_init()
  368. {
  369. Engine::Root().RegisterCommands(cmds_send, ArraySize(cmds_send));
  370. }