3 * Copyright (c) 2020-2021 Project CHIP Authors
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * This file implements a chip-echo-requester, for the
23 * The CHIP Echo Protocol implements two simple methods, in the
24 * style of ICMP ECHO REQUEST and ECHO REPLY, in which a sent
25 * payload is turned around by the responder and echoed back to
32 #include <core/CHIPCore.h>
33 #include <platform/CHIPDeviceLayer.h>
34 #include <protocols/echo/Echo.h>
35 #include <support/ErrorStr.h>
36 #include <system/SystemPacketBuffer.h>
37 #include <transport/PASESession.h>
38 #include <transport/SecureSessionMgr.h>
39 #include <transport/raw/TCP.h>
40 #include <transport/raw/UDP.h>
46 #define ECHO_CLIENT_PORT (CHIP_PORT + 1)
50 // Max value for the number of EchoRequests sent.
51 constexpr size_t kMaxEchoCount = 3;
53 // The CHIP Echo interval time in milliseconds.
54 constexpr int32_t gEchoInterval = 1000;
56 constexpr chip::Transport::AdminId gAdminId = 0;
58 // The EchoClient object.
59 chip::Protocols::Echo::EchoClient gEchoClient;
61 chip::TransportMgr<chip::Transport::UDP> gUDPManager;
62 chip::TransportMgr<chip::Transport::TCP<kMaxTcpActiveConnectionCount, kMaxTcpPendingPackets>> gTCPManager;
63 chip::SecureSessionMgr gSessionManager;
64 chip::Inet::IPAddress gDestAddr;
66 // The last time a CHIP Echo was attempted to be sent.
67 uint64_t gLastEchoTime = 0;
69 // True, if the EchoClient is waiting for an EchoResponse
70 // after sending an EchoRequest, false otherwise.
71 bool gWaitingForEchoResp = false;
73 // Count of the number of EchoRequests sent.
74 uint64_t gEchoCount = 0;
76 // Count of the number of EchoResponses received.
77 uint64_t gEchoRespCount = 0;
81 bool EchoIntervalExpired(void)
83 uint64_t now = chip::System::Timer::GetCurrentEpoch();
85 return (now >= gLastEchoTime + gEchoInterval);
88 CHIP_ERROR SendEchoRequest(void)
90 CHIP_ERROR err = CHIP_NO_ERROR;
91 const char kRequestFormat[] = "Echo Message %" PRIu64 "\n";
92 char requestData[(sizeof kRequestFormat) + 20 /* uint64_t decimal digits */];
93 snprintf(requestData, sizeof requestData, kRequestFormat, gEchoCount);
94 chip::System::PacketBufferHandle payloadBuf = chip::MessagePacketBuffer::NewWithData(requestData, strlen(requestData));
96 if (payloadBuf.IsNull())
98 printf("Unable to allocate packet buffer\n");
99 return CHIP_ERROR_NO_MEMORY;
102 gLastEchoTime = chip::System::Timer::GetCurrentEpoch();
104 printf("\nSend echo request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId);
106 err = gEchoClient.SendEchoRequest(std::move(payloadBuf), chip::Messaging::SendFlags(chip::Messaging::SendMessageFlags::kNone));
108 if (err == CHIP_NO_ERROR)
110 gWaitingForEchoResp = true;
115 printf("Send echo request failed, err: %s\n", chip::ErrorStr(err));
121 CHIP_ERROR EstablishSecureSession()
123 CHIP_ERROR err = CHIP_NO_ERROR;
125 chip::Optional<chip::Transport::PeerAddress> peerAddr;
126 chip::SecurePairingUsingTestSecret * testSecurePairingSecret = chip::Platform::New<chip::SecurePairingUsingTestSecret>();
127 VerifyOrExit(testSecurePairingSecret != nullptr, err = CHIP_ERROR_NO_MEMORY);
131 peerAddr = chip::Optional<chip::Transport::PeerAddress>::Value(chip::Transport::PeerAddress::TCP(gDestAddr, CHIP_PORT));
135 peerAddr = chip::Optional<chip::Transport::PeerAddress>::Value(
136 chip::Transport::PeerAddress::UDP(gDestAddr, CHIP_PORT, INET_NULL_INTERFACEID));
139 // Attempt to connect to the peer.
140 err = gSessionManager.NewPairing(peerAddr, chip::kTestDeviceNodeId, testSecurePairingSecret,
141 chip::SecureSessionMgr::PairingDirection::kInitiator, gAdminId);
144 if (err != CHIP_NO_ERROR)
146 printf("Establish secure session failed, err: %s\n", chip::ErrorStr(err));
147 gLastEchoTime = chip::System::Timer::GetCurrentEpoch();
151 printf("Establish secure session succeeded\n");
157 void HandleEchoResponseReceived(chip::Messaging::ExchangeContext * ec, chip::System::PacketBufferHandle payload)
159 uint32_t respTime = chip::System::Timer::GetCurrentEpoch();
160 uint32_t transitTime = respTime - gLastEchoTime;
162 gWaitingForEchoResp = false;
165 printf("Echo Response: %" PRIu64 "/%" PRIu64 "(%.2f%%) len=%u time=%.3fms\n", gEchoRespCount, gEchoCount,
166 static_cast<double>(gEchoRespCount) * 100 / gEchoCount, payload->DataLength(), static_cast<double>(transitTime) / 1000);
171 int main(int argc, char * argv[])
173 CHIP_ERROR err = CHIP_NO_ERROR;
175 chip::Transport::AdminPairingTable admins;
176 chip::Transport::AdminPairingInfo * adminInfo = nullptr;
180 printf("Missing Echo Server IP address\n");
181 ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
186 printf("Too many arguments specified!\n");
187 ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
190 if ((argc == 3) && (strcmp(argv[2], "--tcp") == 0))
195 if (!chip::Inet::IPAddress::FromString(argv[1], gDestAddr))
197 printf("Invalid Echo Server IP address: %s\n", argv[1]);
198 ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
203 adminInfo = admins.AssignAdminId(gAdminId, chip::kTestControllerNodeId);
204 VerifyOrExit(adminInfo != nullptr, err = CHIP_ERROR_NO_MEMORY);
208 err = gTCPManager.Init(chip::Transport::TcpListenParameters(&chip::DeviceLayer::InetLayer)
209 .SetAddressType(chip::Inet::kIPAddressType_IPv4)
210 .SetListenPort(ECHO_CLIENT_PORT));
213 err = gSessionManager.Init(chip::kTestControllerNodeId, &chip::DeviceLayer::SystemLayer, &gTCPManager, &admins);
218 err = gUDPManager.Init(chip::Transport::UdpListenParameters(&chip::DeviceLayer::InetLayer)
219 .SetAddressType(chip::Inet::kIPAddressType_IPv4)
220 .SetListenPort(ECHO_CLIENT_PORT));
223 err = gSessionManager.Init(chip::kTestControllerNodeId, &chip::DeviceLayer::SystemLayer, &gUDPManager, &admins);
227 err = gExchangeManager.Init(chip::kTestControllerNodeId, &gUDPManager, &gSessionManager);
230 // Start the CHIP connection to the CHIP echo responder.
231 err = EstablishSecureSession();
234 // TODO: temprary create a SecureSessionHandle from node id to unblock end-to-end test. Complete solution is tracked in PR:4451
235 err = gEchoClient.Init(&gExchangeManager, { chip::kTestDeviceNodeId, 0, gAdminId });
238 // Arrange to get a callback whenever an Echo Response is received.
239 gEchoClient.SetEchoResponseReceived(HandleEchoResponseReceived);
241 // Connection has been established. Now send the EchoRequests.
242 for (unsigned int i = 0; i < kMaxEchoCount; i++)
244 err = SendEchoRequest();
245 if (err != CHIP_NO_ERROR)
247 printf("Send request failed: %s\n", chip::ErrorStr(err));
251 // Wait for response until the Echo interval.
252 while (!EchoIntervalExpired())
257 // Check if expected response was received.
258 if (gWaitingForEchoResp)
260 printf("No response received\n");
261 gWaitingForEchoResp = false;
265 gEchoClient.Shutdown();
270 if ((err != CHIP_NO_ERROR) || (gEchoRespCount != kMaxEchoCount))
272 printf("ChipEchoClient failed: %s\n", chip::ErrorStr(err));