Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / messaging / tests / echo / echo_requester.cpp
1 /*
2  *
3  *    Copyright (c) 2020-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
18 /**
19  *    @file
20  *      This file implements a chip-echo-requester, for the
21  *      CHIP Echo Protocol.
22  *
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
26  *      the originator.
27  *
28  */
29
30 #include "common.h"
31
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>
41
42 #include <inttypes.h>
43 #include <stdio.h>
44 #include <string.h>
45
46 #define ECHO_CLIENT_PORT (CHIP_PORT + 1)
47
48 namespace {
49
50 // Max value for the number of EchoRequests sent.
51 constexpr size_t kMaxEchoCount = 3;
52
53 // The CHIP Echo interval time in milliseconds.
54 constexpr int32_t gEchoInterval = 1000;
55
56 constexpr chip::Transport::AdminId gAdminId = 0;
57
58 // The EchoClient object.
59 chip::Protocols::Echo::EchoClient gEchoClient;
60
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;
65
66 // The last time a CHIP Echo was attempted to be sent.
67 uint64_t gLastEchoTime = 0;
68
69 // True, if the EchoClient is waiting for an EchoResponse
70 // after sending an EchoRequest, false otherwise.
71 bool gWaitingForEchoResp = false;
72
73 // Count of the number of EchoRequests sent.
74 uint64_t gEchoCount = 0;
75
76 // Count of the number of EchoResponses received.
77 uint64_t gEchoRespCount = 0;
78
79 bool gUseTCP = false;
80
81 bool EchoIntervalExpired(void)
82 {
83     uint64_t now = chip::System::Timer::GetCurrentEpoch();
84
85     return (now >= gLastEchoTime + gEchoInterval);
86 }
87
88 CHIP_ERROR SendEchoRequest(void)
89 {
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));
95
96     if (payloadBuf.IsNull())
97     {
98         printf("Unable to allocate packet buffer\n");
99         return CHIP_ERROR_NO_MEMORY;
100     }
101
102     gLastEchoTime = chip::System::Timer::GetCurrentEpoch();
103
104     printf("\nSend echo request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId);
105
106     err = gEchoClient.SendEchoRequest(std::move(payloadBuf), chip::Messaging::SendFlags(chip::Messaging::SendMessageFlags::kNone));
107
108     if (err == CHIP_NO_ERROR)
109     {
110         gWaitingForEchoResp = true;
111         gEchoCount++;
112     }
113     else
114     {
115         printf("Send echo request failed, err: %s\n", chip::ErrorStr(err));
116     }
117
118     return err;
119 }
120
121 CHIP_ERROR EstablishSecureSession()
122 {
123     CHIP_ERROR err = CHIP_NO_ERROR;
124
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);
128
129     if (gUseTCP)
130     {
131         peerAddr = chip::Optional<chip::Transport::PeerAddress>::Value(chip::Transport::PeerAddress::TCP(gDestAddr, CHIP_PORT));
132     }
133     else
134     {
135         peerAddr = chip::Optional<chip::Transport::PeerAddress>::Value(
136             chip::Transport::PeerAddress::UDP(gDestAddr, CHIP_PORT, INET_NULL_INTERFACEID));
137     }
138
139     // Attempt to connect to the peer.
140     err = gSessionManager.NewPairing(peerAddr, chip::kTestDeviceNodeId, testSecurePairingSecret,
141                                      chip::SecureSessionMgr::PairingDirection::kInitiator, gAdminId);
142
143 exit:
144     if (err != CHIP_NO_ERROR)
145     {
146         printf("Establish secure session failed, err: %s\n", chip::ErrorStr(err));
147         gLastEchoTime = chip::System::Timer::GetCurrentEpoch();
148     }
149     else
150     {
151         printf("Establish secure session succeeded\n");
152     }
153
154     return err;
155 }
156
157 void HandleEchoResponseReceived(chip::Messaging::ExchangeContext * ec, chip::System::PacketBufferHandle payload)
158 {
159     uint32_t respTime    = chip::System::Timer::GetCurrentEpoch();
160     uint32_t transitTime = respTime - gLastEchoTime;
161
162     gWaitingForEchoResp = false;
163     gEchoRespCount++;
164
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);
167 }
168
169 void RunPinging()
170 {
171     CHIP_ERROR err = CHIP_NO_ERROR;
172
173     // Connection has been established. Now send the EchoRequests.
174     for (unsigned int i = 0; i < kMaxEchoCount; i++)
175     {
176         err = SendEchoRequest();
177         if (err != CHIP_NO_ERROR)
178         {
179             printf("Send request failed: %s\n", chip::ErrorStr(err));
180             break;
181         }
182
183         // Wait for response until the Echo interval.
184         while (!EchoIntervalExpired())
185         {
186             sleep(1);
187         }
188
189         // Check if expected response was received.
190         if (gWaitingForEchoResp)
191         {
192             printf("No response received\n");
193             gWaitingForEchoResp = false;
194         }
195     }
196 }
197
198 } // namespace
199
200 int main(int argc, char * argv[])
201 {
202     CHIP_ERROR err = CHIP_NO_ERROR;
203
204     chip::Transport::AdminPairingTable admins;
205     chip::Transport::AdminPairingInfo * adminInfo = nullptr;
206
207     if (argc <= 1)
208     {
209         printf("Missing Echo Server IP address\n");
210         ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
211     }
212
213     if (argc > 3)
214     {
215         printf("Too many arguments specified!\n");
216         ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
217     }
218
219     if ((argc == 3) && (strcmp(argv[2], "--tcp") == 0))
220     {
221         gUseTCP = true;
222     }
223
224     if (!chip::Inet::IPAddress::FromString(argv[1], gDestAddr))
225     {
226         printf("Invalid Echo Server IP address: %s\n", argv[1]);
227         ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
228     }
229
230     InitializeChip();
231
232     chip::DeviceLayer::PlatformMgr().StartEventLoopTask();
233
234     adminInfo = admins.AssignAdminId(gAdminId, chip::kTestControllerNodeId);
235     VerifyOrExit(adminInfo != nullptr, err = CHIP_ERROR_NO_MEMORY);
236
237     if (gUseTCP)
238     {
239         err = gTCPManager.Init(chip::Transport::TcpListenParameters(&chip::DeviceLayer::InetLayer)
240                                    .SetAddressType(chip::Inet::kIPAddressType_IPv4)
241                                    .SetListenPort(ECHO_CLIENT_PORT));
242         SuccessOrExit(err);
243
244         err = gSessionManager.Init(chip::kTestControllerNodeId, &chip::DeviceLayer::SystemLayer, &gTCPManager, &admins);
245         SuccessOrExit(err);
246     }
247     else
248     {
249         err = gUDPManager.Init(chip::Transport::UdpListenParameters(&chip::DeviceLayer::InetLayer)
250                                    .SetAddressType(chip::Inet::kIPAddressType_IPv4)
251                                    .SetListenPort(ECHO_CLIENT_PORT));
252         SuccessOrExit(err);
253
254         err = gSessionManager.Init(chip::kTestControllerNodeId, &chip::DeviceLayer::SystemLayer, &gUDPManager, &admins);
255         SuccessOrExit(err);
256     }
257
258     err = gExchangeManager.Init(&gSessionManager);
259     SuccessOrExit(err);
260
261     // Start the CHIP connection to the CHIP echo responder.
262     err = EstablishSecureSession();
263     SuccessOrExit(err);
264
265     // TODO: temprary create a SecureSessionHandle from node id to unblock end-to-end test. Complete solution is tracked in PR:4451
266     err = gEchoClient.Init(&gExchangeManager, { chip::kTestDeviceNodeId, 0, gAdminId });
267     SuccessOrExit(err);
268
269     // Arrange to get a callback whenever an Echo Response is received.
270     gEchoClient.SetEchoResponseReceived(HandleEchoResponseReceived);
271
272     RunPinging();
273
274     gEchoClient.Shutdown();
275
276     ShutdownChip();
277
278 exit:
279     if ((err != CHIP_NO_ERROR) || (gEchoRespCount != kMaxEchoCount))
280     {
281         printf("ChipEchoClient failed: %s\n", chip::ErrorStr(err));
282         exit(EXIT_FAILURE);
283     }
284
285     return EXIT_SUCCESS;
286 }