Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / transport / raw / tests / TestTCP.cpp
1 /*
2  *
3  *    Copyright (c) 2020-2021 Project CHIP Authors
4  *    All rights reserved.
5  *
6  *    Licensed under the Apache License, Version 2.0 (the "License");
7  *    you may not use this file except in compliance with the License.
8  *    You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *    Unless required by applicable law or agreed to in writing, software
13  *    distributed under the License is distributed on an "AS IS" BASIS,
14  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *    See the License for the specific language governing permissions and
16  *    limitations under the License.
17  */
18
19 /**
20  *    @file
21  *      This file implements unit tests for the TcpTransport implementation.
22  */
23
24 #include "NetworkTestHelpers.h"
25
26 #include <core/CHIPCore.h>
27 #include <core/CHIPEncoding.h>
28 #include <support/CHIPMem.h>
29 #include <support/CodeUtils.h>
30 #include <support/UnitTestRegistration.h>
31 #include <system/SystemLayer.h>
32 #include <system/SystemObject.h>
33 #include <transport/TransportMgr.h>
34 #include <transport/raw/TCP.h>
35
36 #include <nlbyteorder.h>
37 #include <nlunit-test.h>
38
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <utility>
43
44 using namespace chip;
45 using namespace chip::Inet;
46
47 static int Initialize(void * aContext);
48 static int Finalize(void * aContext);
49
50 namespace chip {
51 namespace Transport {
52 class TCPTest
53 {
54 public:
55     static void CheckProcessReceivedBuffer(nlTestSuite * inSuite, void * inContext);
56 };
57 } // namespace Transport
58 } // namespace chip
59
60 namespace {
61
62 constexpr size_t kMaxTcpActiveConnectionCount = 4;
63 constexpr size_t kMaxTcpPendingPackets        = 4;
64 constexpr uint16_t kPacketSizeBytes           = static_cast<uint16_t>(sizeof(uint16_t));
65
66 using TCPImpl = Transport::TCP<kMaxTcpActiveConnectionCount, kMaxTcpPendingPackets>;
67
68 constexpr NodeId kSourceNodeId      = 123654;
69 constexpr NodeId kDestinationNodeId = 111222333;
70 constexpr uint32_t kMessageId       = 18;
71
72 using TestContext = chip::Test::IOContext;
73 TestContext sContext;
74
75 const char PAYLOAD[] = "Hello!";
76
77 class MockTransportMgrDelegate : public chip::TransportMgrDelegate
78 {
79 public:
80     typedef int (*MessageReceivedCallback)(const uint8_t * message, size_t length, int count, void * data);
81
82     MockTransportMgrDelegate(nlTestSuite * inSuite, TestContext & inContext) :
83         mSuite(inSuite), mContext(inContext), mCallback(nullptr), mCallbackData(nullptr)
84     {}
85     ~MockTransportMgrDelegate() override {}
86
87     void SetCallback(MessageReceivedCallback callback = nullptr, void * callback_data = nullptr)
88     {
89         mCallback     = callback;
90         mCallbackData = callback_data;
91     }
92     void OnMessageReceived(const PacketHeader & header, const Transport::PeerAddress & source,
93                            System::PacketBufferHandle msgBuf) override
94     {
95         NL_TEST_ASSERT(mSuite, header.GetSourceNodeId() == Optional<NodeId>::Value(kSourceNodeId));
96         NL_TEST_ASSERT(mSuite, header.GetDestinationNodeId() == Optional<NodeId>::Value(kDestinationNodeId));
97         NL_TEST_ASSERT(mSuite, header.GetMessageId() == kMessageId);
98
99         if (mCallback)
100         {
101             int err = mCallback(msgBuf->Start(), msgBuf->DataLength(), mReceiveHandlerCallCount, mCallbackData);
102             NL_TEST_ASSERT(mSuite, err == 0);
103         }
104
105         mReceiveHandlerCallCount++;
106     }
107
108     void InitializeMessageTest(TCPImpl & tcp, const IPAddress & addr)
109     {
110         CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(&mContext.GetInetLayer()).SetAddressType(addr.Type()));
111         NL_TEST_ASSERT(mSuite, err == CHIP_NO_ERROR);
112
113         mTransportMgrBase.SetSecureSessionMgr(this);
114         mTransportMgrBase.SetRendezvousSession(this);
115         mTransportMgrBase.Init(&tcp);
116
117         mReceiveHandlerCallCount = 0;
118     }
119
120     void SingleMessageTest(TCPImpl & tcp, const IPAddress & addr)
121     {
122         chip::System::PacketBufferHandle buffer = chip::System::PacketBufferHandle::NewWithData(PAYLOAD, sizeof(PAYLOAD));
123         NL_TEST_ASSERT(mSuite, !buffer.IsNull());
124
125         PacketHeader header;
126         header.SetSourceNodeId(kSourceNodeId).SetDestinationNodeId(kDestinationNodeId).SetMessageId(kMessageId);
127
128         SetCallback([](const uint8_t * message, size_t length, int count, void * data) { return memcmp(message, data, length); },
129                     const_cast<void *>(static_cast<const void *>(PAYLOAD)));
130
131         // Should be able to send a message to itself by just calling send.
132         CHIP_ERROR err = tcp.SendMessage(header, Transport::PeerAddress::TCP(addr), std::move(buffer));
133         if (err == System::MapErrorPOSIX(EADDRNOTAVAIL))
134         {
135             // TODO(#2698): the underlying system does not support IPV6. This early return
136             // should be removed and error should be made fatal.
137             printf("%s:%u: System does NOT support IPV6.\n", __FILE__, __LINE__);
138             return;
139         }
140
141         NL_TEST_ASSERT(mSuite, err == CHIP_NO_ERROR);
142
143         mContext.DriveIOUntil(5000 /* ms */, [this]() { return mReceiveHandlerCallCount != 0; });
144         NL_TEST_ASSERT(mSuite, mReceiveHandlerCallCount == 1);
145
146         SetCallback(nullptr);
147     }
148
149     void FinalizeMessageTest(TCPImpl & tcp, const IPAddress & addr)
150     {
151         // Disconnect and wait for seeing peer close
152         tcp.Disconnect(Transport::PeerAddress::TCP(addr));
153         mContext.DriveIOUntil(5000 /* ms */, [&tcp]() { return !tcp.HasActiveConnections(); });
154     }
155
156     int mReceiveHandlerCallCount = 0;
157
158 private:
159     nlTestSuite * mSuite;
160     TestContext & mContext;
161     MessageReceivedCallback mCallback;
162     void * mCallbackData;
163     TransportMgrBase mTransportMgrBase;
164 };
165
166 /////////////////////////// Init test
167
168 void CheckSimpleInitTest(nlTestSuite * inSuite, void * inContext, Inet::IPAddressType type)
169 {
170     TestContext & ctx = *reinterpret_cast<TestContext *>(inContext);
171
172     TCPImpl tcp;
173
174     CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(&ctx.GetInetLayer()).SetAddressType(type));
175
176     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
177 }
178
179 #if INET_CONFIG_ENABLE_IPV4
180 void CheckSimpleInitTest4(nlTestSuite * inSuite, void * inContext)
181 {
182     CheckSimpleInitTest(inSuite, inContext, kIPAddressType_IPv4);
183 }
184 #endif
185
186 void CheckSimpleInitTest6(nlTestSuite * inSuite, void * inContext)
187 {
188     CheckSimpleInitTest(inSuite, inContext, kIPAddressType_IPv6);
189 }
190
191 /////////////////////////// Messaging test
192
193 void CheckMessageTest(nlTestSuite * inSuite, void * inContext, const IPAddress & addr)
194 {
195     TestContext & ctx = *reinterpret_cast<TestContext *>(inContext);
196     TCPImpl tcp;
197
198     MockTransportMgrDelegate gMockTransportMgrDelegate(inSuite, ctx);
199     gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr);
200     gMockTransportMgrDelegate.SingleMessageTest(tcp, addr);
201     gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr);
202 }
203
204 void CheckMessageTest4(nlTestSuite * inSuite, void * inContext)
205 {
206     IPAddress addr;
207     IPAddress::FromString("127.0.0.1", addr);
208     CheckMessageTest(inSuite, inContext, addr);
209 }
210
211 void CheckMessageTest6(nlTestSuite * inSuite, void * inContext)
212 {
213     IPAddress addr;
214     IPAddress::FromString("::1", addr);
215     CheckMessageTest(inSuite, inContext, addr);
216 }
217
218 // Generates a packet buffer or a chain of packet buffers for a single message.
219 struct TestData
220 {
221     // `sizes[]` is a zero-terminated sequence of packet buffer sizes.
222     // If total length supplied is not large enough for at least the PacketHeader and length field,
223     // the last buffer will be made larger.
224     TestData() : mHandle(), mPayload(nullptr), mTotalLength(0), mMessageLength(0), mMessageOffset(0) {}
225     ~TestData() { Free(); }
226     bool Init(const uint16_t sizes[]);
227     void Free();
228     bool IsValid() { return !mHandle.IsNull() && (mPayload != nullptr); }
229
230     chip::System::PacketBufferHandle mHandle;
231     uint8_t * mPayload;
232     size_t mTotalLength;
233     size_t mMessageLength;
234     size_t mMessageOffset;
235 };
236
237 bool TestData::Init(const uint16_t sizes[])
238 {
239     Free();
240
241     PacketHeader header;
242     header.SetSourceNodeId(kSourceNodeId).SetDestinationNodeId(kDestinationNodeId).SetMessageId(kMessageId);
243     const size_t headerLength = header.EncodeSizeBytes();
244
245     // Determine the total length.
246     mTotalLength    = 0;
247     int bufferCount = 0;
248     for (; sizes[bufferCount] != 0; ++bufferCount)
249     {
250         mTotalLength += sizes[bufferCount];
251     }
252     --bufferCount;
253     uint16_t additionalLength = 0;
254     if (headerLength + kPacketSizeBytes > mTotalLength)
255     {
256         additionalLength = static_cast<uint16_t>((headerLength + kPacketSizeBytes) - mTotalLength);
257         mTotalLength += additionalLength;
258     }
259     if (mTotalLength > UINT16_MAX)
260     {
261         return false;
262     }
263     uint16_t messageLength = static_cast<uint16_t>(mTotalLength - kPacketSizeBytes);
264
265     // Build the test payload.
266     uint8_t * payload = static_cast<uint8_t *>(chip::Platform::MemoryCalloc(1, mTotalLength));
267     if (payload == nullptr)
268     {
269         return false;
270     }
271     chip::Encoding::LittleEndian::Put16(payload, messageLength);
272     uint16_t headerSize;
273     CHIP_ERROR err = header.Encode(payload + kPacketSizeBytes, messageLength, &headerSize);
274     if (err != CHIP_NO_ERROR)
275     {
276         return false;
277     }
278     mMessageLength = messageLength - headerSize;
279     mMessageOffset = kPacketSizeBytes + headerSize;
280     // Fill the rest of the payload with a recognizable pattern.
281     for (size_t i = mMessageOffset; i < mTotalLength; ++i)
282     {
283         payload[i] = static_cast<uint8_t>(i);
284     }
285     // When we get the message back, the header will have been removed.
286
287     // Allocate the buffer chain.
288     System::PacketBufferHandle head = chip::System::PacketBufferHandle::New(sizes[0], 0 /* reserve */);
289     for (int i = 1; i <= bufferCount; ++i)
290     {
291         uint16_t size = sizes[i];
292         if (i == bufferCount)
293         {
294             size = static_cast<uint16_t>(size + additionalLength);
295         }
296         chip::System::PacketBufferHandle buffer = chip::System::PacketBufferHandle::New(size, 0 /* reserve */);
297         if (buffer.IsNull())
298         {
299             return false;
300         }
301         head.AddToEnd(std::move(buffer));
302     }
303
304     // Write the test payload to the buffer chain.
305     System::PacketBufferHandle iterator = head.Retain();
306     uint8_t * writePayload              = payload;
307     size_t writeLength                  = mTotalLength;
308     while (writeLength > 0)
309     {
310         if (iterator.IsNull())
311         {
312             return false;
313         }
314         size_t lAvailableLengthInCurrentBuf = iterator->AvailableDataLength();
315         size_t lToWriteToCurrentBuf         = lAvailableLengthInCurrentBuf;
316         if (writeLength < lToWriteToCurrentBuf)
317         {
318             lToWriteToCurrentBuf = writeLength;
319         }
320         if (lToWriteToCurrentBuf != 0)
321         {
322             memcpy(iterator->Start(), writePayload, lToWriteToCurrentBuf);
323             iterator->SetDataLength(static_cast<uint16_t>(iterator->DataLength() + lToWriteToCurrentBuf), head);
324             writePayload += lToWriteToCurrentBuf;
325             writeLength -= lToWriteToCurrentBuf;
326         }
327         iterator.Advance();
328     }
329
330     mHandle  = std::move(head);
331     mPayload = payload;
332     return true;
333 }
334
335 void TestData::Free()
336 {
337     chip::Platform::MemoryFree(mPayload);
338     mPayload       = nullptr;
339     mHandle        = nullptr;
340     mTotalLength   = 0;
341     mMessageLength = 0;
342     mMessageOffset = 0;
343 }
344
345 int TestDataCallbackCheck(const uint8_t * message, size_t length, int count, void * data)
346 {
347     if (data == nullptr)
348     {
349         return -1;
350     }
351     TestData * currentData = static_cast<TestData *>(data) + count;
352     if (currentData->mPayload == nullptr)
353     {
354         return -2;
355     }
356     if (currentData->mMessageLength != length)
357     {
358         return -3;
359     }
360     if (memcmp(currentData->mPayload + currentData->mMessageOffset, message, length) != 0)
361     {
362         return -4;
363     }
364     return 0;
365 }
366
367 } // namespace
368
369 void chip::Transport::TCPTest::CheckProcessReceivedBuffer(nlTestSuite * inSuite, void * inContext)
370 {
371     TestContext & ctx = *reinterpret_cast<TestContext *>(inContext);
372     TCPImpl tcp;
373
374     IPAddress addr;
375     IPAddress::FromString("::1", addr);
376
377     MockTransportMgrDelegate gMockTransportMgrDelegate(inSuite, ctx);
378     gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr);
379
380     // Send a packet to get TCP going, so that we can find a TCPEndPoint to pass to ProcessReceivedBuffer.
381     // (The current TCPEndPoint implementation is not effectively mockable.)
382     gMockTransportMgrDelegate.SingleMessageTest(tcp, addr);
383
384     Transport::PeerAddress lPeerAddress    = Transport::PeerAddress::TCP(addr);
385     TCPBase::ActiveConnectionState * state = tcp.FindActiveConnection(lPeerAddress);
386     NL_TEST_ASSERT(inSuite, state != nullptr);
387     Inet::TCPEndPoint * lEndPoint = state->mEndPoint;
388     NL_TEST_ASSERT(inSuite, lEndPoint != nullptr);
389
390     CHIP_ERROR err = CHIP_NO_ERROR;
391     TestData testData[2];
392     gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, testData);
393
394     // Test a single packet buffer.
395     gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0;
396     NL_TEST_ASSERT(inSuite, testData[0].Init((const uint16_t[]){ 111, 0 }));
397     err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle));
398     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
399     NL_TEST_ASSERT(inSuite, gMockTransportMgrDelegate.mReceiveHandlerCallCount == 1);
400
401     // Test a message in a chain of three packet buffers. The message length is split accross buffers.
402     gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0;
403     NL_TEST_ASSERT(inSuite, testData[0].Init((const uint16_t[]){ 1, 122, 123, 0 }));
404     err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle));
405     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
406     NL_TEST_ASSERT(inSuite, gMockTransportMgrDelegate.mReceiveHandlerCallCount == 1);
407
408     // Test two messages in a chain.
409     gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0;
410     NL_TEST_ASSERT(inSuite, testData[0].Init((const uint16_t[]){ 131, 0 }));
411     NL_TEST_ASSERT(inSuite, testData[1].Init((const uint16_t[]){ 132, 0 }));
412     testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle));
413     err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle));
414     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
415     NL_TEST_ASSERT(inSuite, gMockTransportMgrDelegate.mReceiveHandlerCallCount == 2);
416
417     // Test a chain of two messages, each a chain.
418     gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0;
419     NL_TEST_ASSERT(inSuite, testData[0].Init((const uint16_t[]){ 141, 142, 0 }));
420     NL_TEST_ASSERT(inSuite, testData[1].Init((const uint16_t[]){ 143, 144, 0 }));
421     testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle));
422     err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle));
423     NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR);
424     NL_TEST_ASSERT(inSuite, gMockTransportMgrDelegate.mReceiveHandlerCallCount == 2);
425
426     // Test a message that is too large to coalesce into a single packet buffer.
427     gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0;
428     gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, &testData[1]);
429     NL_TEST_ASSERT(inSuite, testData[0].Init((const uint16_t[]){ 51, System::PacketBuffer::kMaxSizeWithoutReserve, 0 }));
430     // Sending only the first buffer of the long chain. This should be enough to trigger the error.
431     System::PacketBufferHandle head = testData[0].mHandle.PopHead();
432     err                             = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(head));
433     NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_MESSAGE_TOO_LONG);
434     NL_TEST_ASSERT(inSuite, gMockTransportMgrDelegate.mReceiveHandlerCallCount == 0);
435
436     gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr);
437 }
438
439 // Test Suite
440 /**
441  *  Test Suite that lists all the test functions.
442  */
443 // clang-format off
444 static const nlTest sTests[] =
445 {
446 #if INET_CONFIG_ENABLE_IPV4
447     NL_TEST_DEF("Simple Init Test IPV4",        CheckSimpleInitTest4),
448     NL_TEST_DEF("Message Self Test IPV4",       CheckMessageTest4),
449 #endif
450
451     NL_TEST_DEF("Simple Init Test IPV6",        CheckSimpleInitTest6),
452     NL_TEST_DEF("Message Self Test IPV6",       CheckMessageTest6),
453     NL_TEST_DEF("ProcessReceivedBuffer Test",   chip::Transport::TCPTest::CheckProcessReceivedBuffer),
454
455     NL_TEST_SENTINEL()
456 };
457 // clang-format on
458
459 // clang-format off
460 static nlTestSuite sSuite =
461 {
462     "Test-CHIP-Tcp",
463     &sTests[0],
464     Initialize,
465     Finalize
466 };
467 // clang-format on
468
469 /**
470  *  Initialize the test suite.
471  */
472 static int Initialize(void * aContext)
473 {
474     CHIP_ERROR err = reinterpret_cast<TestContext *>(aContext)->Init(&sSuite);
475     return (err == CHIP_NO_ERROR) ? SUCCESS : FAILURE;
476 }
477
478 /**
479  *  Finalize the test suite.
480  */
481 static int Finalize(void * aContext)
482 {
483     CHIP_ERROR err = reinterpret_cast<TestContext *>(aContext)->Shutdown();
484     return (err == CHIP_NO_ERROR) ? SUCCESS : FAILURE;
485 }
486
487 int TestTCP()
488 {
489     // Run test suit against one context
490     nlTestRunner(&sSuite, &sContext);
491
492     return (nlTestRunnerStats(&sSuite));
493 }
494
495 CHIP_REGISTER_TEST_SUITE(TestTCP);