1 /*
2  *  Copyright (c) 2021, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <openthread/config.h>
30 
31 #include "test_platform.h"
32 #include "test_util.hpp"
33 
34 #include "common/arg_macros.hpp"
35 #include "common/array.hpp"
36 #include "common/as_core_type.hpp"
37 #include "common/time.hpp"
38 #include "instance/instance.hpp"
39 #include "net/dns_dso.hpp"
40 
41 namespace ot {
42 
43 #if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
44 
45 extern "C" {
46 
47 static uint32_t    sNow = 0;
48 static uint32_t    sAlarmTime;
49 static bool        sAlarmOn = false;
50 static otInstance *sInstance;
51 
52 // Logs a message and adds current time (sNow) as "<hours>:<min>:<secs>.<msec>"
53 #define Log(...)                                                                                          \
54     printf("%02u:%02u:%02u.%03u " OT_FIRST_ARG(__VA_ARGS__) "\n", (sNow / 36000000), (sNow / 60000) % 60, \
55            (sNow / 1000) % 60, sNow % 1000 OT_REST_ARGS(__VA_ARGS__))
56 
otPlatAlarmMilliStop(otInstance *)57 void otPlatAlarmMilliStop(otInstance *) { sAlarmOn = false; }
58 
otPlatAlarmMilliStartAt(otInstance *,uint32_t aT0,uint32_t aDt)59 void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
60 {
61     sAlarmOn   = true;
62     sAlarmTime = aT0 + aDt;
63 
64     Log(" otPlatAlarmMilliStartAt(time:%u.%03u, dt:%u.%03u)", sAlarmTime / 1000, sAlarmTime % 1000,
65         (sAlarmTime - sNow) / 1000, (sAlarmTime - sNow) % 1000);
66 }
67 
otPlatAlarmMilliGetNow(void)68 uint32_t otPlatAlarmMilliGetNow(void) { return sNow; }
69 
70 } // extern "C"
71 
AdvanceTime(uint32_t aDuration)72 void AdvanceTime(uint32_t aDuration)
73 {
74     uint32_t time = sNow + aDuration;
75 
76     Log(" AdvanceTime for %u.%03u", aDuration / 1000, aDuration % 1000);
77 
78     while (TimeMilli(sAlarmTime) <= TimeMilli(time))
79     {
80         sNow = sAlarmTime;
81         otPlatAlarmMilliFired(sInstance);
82     }
83 
84     sNow = time;
85 }
86 
87 namespace Dns {
88 
89 OT_TOOL_PACKED_BEGIN
90 class TestTlv : public Dso::Tlv
91 {
92 public:
93     static constexpr Type kType = 0xf800;
94 
Init(uint8_t aValue)95     void Init(uint8_t aValue)
96     {
97         Tlv::Init(kType, sizeof(*this) - sizeof(Tlv));
98         mValue = aValue;
99     }
100 
IsValid(void) const101     bool    IsValid(void) const { return GetSize() >= sizeof(*this); }
GetValue(void) const102     uint8_t GetValue(void) const { return mValue; }
103 
104 private:
105     uint8_t mValue;
106 
107 } OT_TOOL_PACKED_END;
108 
109 extern "C" void otPlatDsoSend(otPlatDsoConnection *aConnection, otMessage *aMessage);
110 
111 class Connection : public Dso::Connection
112 {
113     friend void otPlatDsoSend(otPlatDsoConnection *aConnection, otMessage *aMessage);
114 
115 public:
Connection(Instance & aInstance,const char * aName,const Ip6::SockAddr & aLocalSockAddr,const Ip6::SockAddr & aPeerSockAddr)116     explicit Connection(Instance            &aInstance,
117                         const char          *aName,
118                         const Ip6::SockAddr &aLocalSockAddr,
119                         const Ip6::SockAddr &aPeerSockAddr)
120         : Dso::Connection(aInstance, aPeerSockAddr, sCallbacks)
121         , mName(aName)
122         , mLocalSockAddr(aLocalSockAddr)
123     {
124         ClearTestFlags();
125     }
126 
GetName(void) const127     const char          *GetName(void) const { return mName; }
GetLocalSockAddr(void) const128     const Ip6::SockAddr &GetLocalSockAddr(void) const { return mLocalSockAddr; }
129 
ClearTestFlags(void)130     void ClearTestFlags(void)
131     {
132         mDidGetConnectedSignal          = false;
133         mDidGetSessionEstablishedSignal = false;
134         mDidGetDisconnectSignal         = false;
135         mDidSendMessage                 = false;
136         mDidReceiveMessage              = false;
137         mDidProcessRequest              = false;
138         mDidProcessUnidirectional       = false;
139         mDidProcessResponse             = false;
140     }
141 
DidGetConnectedSignal(void) const142     bool DidGetConnectedSignal(void) const { return mDidGetConnectedSignal; }
DidGetSessionEstablishedSignal(void) const143     bool DidGetSessionEstablishedSignal(void) const { return mDidGetSessionEstablishedSignal; }
DidGetDisconnectSignal(void) const144     bool DidGetDisconnectSignal(void) const { return mDidGetDisconnectSignal; }
DidSendMessage(void) const145     bool DidSendMessage(void) const { return mDidSendMessage; }
DidReceiveMessage(void) const146     bool DidReceiveMessage(void) const { return mDidReceiveMessage; }
DidProcessRequest(void) const147     bool DidProcessRequest(void) const { return mDidProcessRequest; }
DidProcessUnidirectional(void) const148     bool DidProcessUnidirectional(void) const { return mDidProcessUnidirectional; }
DidProcessResponse(void) const149     bool DidProcessResponse(void) const { return mDidProcessResponse; }
150 
GetLastRxTestTlvValue(void) const151     uint8_t               GetLastRxTestTlvValue(void) const { return mLastRxTestTlvValue; }
GetLastRxResponseCode(void) const152     Dns::Header::Response GetLastRxResponseCode(void) const { return mLastRxResponseCode; }
153 
SendTestRequestMessage(uint8_t aValue=0,uint32_t aResponseTimeout=Dso::kResponseTimeout)154     void SendTestRequestMessage(uint8_t aValue = 0, uint32_t aResponseTimeout = Dso::kResponseTimeout)
155     {
156         MessageId messageId;
157 
158         mLastTxTestTlvValue = aValue;
159         SuccessOrQuit(SendRequestMessage(PrepareTestMessage(aValue), messageId, aResponseTimeout));
160     }
161 
SendTestUnidirectionalMessage(uint8_t aValue=0)162     void SendTestUnidirectionalMessage(uint8_t aValue = 0)
163     {
164         mLastTxTestTlvValue = aValue;
165         SuccessOrQuit(SendUnidirectionalMessage(PrepareTestMessage(aValue)));
166     }
167 
168 private:
PrepareTestMessage(uint8_t aValue)169     Message &PrepareTestMessage(uint8_t aValue)
170     {
171         TestTlv  testTlv;
172         Message *message = NewMessage();
173 
174         VerifyOrQuit(message != nullptr);
175         testTlv.Init(aValue);
176         SuccessOrQuit(message->Append(testTlv));
177 
178         return *message;
179     }
180 
ParseTestMessage(const Message & aMessage)181     void ParseTestMessage(const Message &aMessage)
182     {
183         TestTlv  testTlv;
184         Dso::Tlv tlv;
185         uint16_t offset = aMessage.GetOffset();
186 
187         // Test message MUST only contain Test TLV and Encryption
188         // Padding TLV.
189 
190         SuccessOrQuit(aMessage.Read(offset, testTlv));
191         VerifyOrQuit(testTlv.GetType() == TestTlv::kType);
192         VerifyOrQuit(testTlv.IsValid());
193         offset += testTlv.GetSize();
194         mLastRxTestTlvValue = testTlv.GetValue();
195 
196         SuccessOrQuit(aMessage.Read(offset, tlv));
197         VerifyOrQuit(tlv.GetType() == Dso::Tlv::kEncryptionPaddingType);
198         offset += tlv.GetSize();
199 
200         VerifyOrQuit(offset == aMessage.GetLength());
201     }
202 
SendTestResponseMessage(MessageId aResponseId,uint8_t aValue)203     void SendTestResponseMessage(MessageId aResponseId, uint8_t aValue)
204     {
205         mLastTxTestTlvValue = aValue;
206         SuccessOrQuit(SendResponseMessage(PrepareTestMessage(aValue), aResponseId));
207     }
208 
209     //---------------------------------------------------------------------
210     // Callback methods
211 
HandleConnected(void)212     void HandleConnected(void) { mDidGetConnectedSignal = true; }
HandleSessionEstablished(void)213     void HandleSessionEstablished(void) { mDidGetSessionEstablishedSignal = true; }
HandleDisconnected(void)214     void HandleDisconnected(void) { mDidGetDisconnectSignal = true; }
215 
ProcessRequestMessage(MessageId aMessageId,const Message & aMessage,Dso::Tlv::Type aPrimaryTlvType)216     Error ProcessRequestMessage(MessageId aMessageId, const Message &aMessage, Dso::Tlv::Type aPrimaryTlvType)
217     {
218         Error error = kErrorNone;
219 
220         Log(" ProcessRequestMessage(primaryTlv:0x%04x) on %s", aPrimaryTlvType, mName);
221         mDidProcessRequest = true;
222 
223         VerifyOrExit(aPrimaryTlvType == TestTlv::kType, error = kErrorNotFound);
224         ParseTestMessage(aMessage);
225         SendTestResponseMessage(aMessageId, mLastRxTestTlvValue);
226 
227     exit:
228         return error;
229     }
230 
ProcessUnidirectionalMessage(const Message & aMessage,Dso::Tlv::Type aPrimaryTlvType)231     Error ProcessUnidirectionalMessage(const Message &aMessage, Dso::Tlv::Type aPrimaryTlvType)
232     {
233         Log(" ProcessUnidirectionalMessage(primaryTlv:0x%04x) on %s", aPrimaryTlvType, mName);
234         mDidProcessUnidirectional = true;
235 
236         if (aPrimaryTlvType == TestTlv::kType)
237         {
238             ParseTestMessage(aMessage);
239         }
240 
241         return kErrorNone;
242     }
243 
ProcessResponseMessage(const Dns::Header & aHeader,const Message & aMessage,Dso::Tlv::Type aResponseTlvType,Dso::Tlv::Type aRequestTlvType)244     Error ProcessResponseMessage(const Dns::Header &aHeader,
245                                  const Message     &aMessage,
246                                  Dso::Tlv::Type     aResponseTlvType,
247                                  Dso::Tlv::Type     aRequestTlvType)
248     {
249         Error error = kErrorNone;
250 
251         mDidProcessResponse = true;
252         mLastRxResponseCode = aHeader.GetResponseCode();
253         Log(" ProcessResponseMessage(responseTlv:0x%04x) on %s (response-Code:%u) ", aResponseTlvType, mName,
254             mLastRxResponseCode);
255 
256         VerifyOrExit(mLastRxResponseCode == Dns::Header::kResponseSuccess);
257 
258         // During test we only expect a Test TLV response with
259         // a matching TLV value to what was sent last.
260 
261         VerifyOrQuit(aResponseTlvType == TestTlv::kType);
262         VerifyOrQuit(aRequestTlvType == TestTlv::kType);
263         ParseTestMessage(aMessage);
264         VerifyOrQuit(mLastRxTestTlvValue == mLastTxTestTlvValue);
265 
266     exit:
267         return error;
268     }
269 
HandleConnected(Dso::Connection & aConnection)270     static void HandleConnected(Dso::Connection &aConnection)
271     {
272         static_cast<Connection &>(aConnection).HandleConnected();
273     }
274 
HandleSessionEstablished(Dso::Connection & aConnection)275     static void HandleSessionEstablished(Dso::Connection &aConnection)
276     {
277         static_cast<Connection &>(aConnection).HandleSessionEstablished();
278     }
279 
HandleDisconnected(Dso::Connection & aConnection)280     static void HandleDisconnected(Dso::Connection &aConnection)
281     {
282         static_cast<Connection &>(aConnection).HandleDisconnected();
283     }
284 
ProcessRequestMessage(Dso::Connection & aConnection,MessageId aMessageId,const Message & aMessage,Dso::Tlv::Type aPrimaryTlvType)285     static Error ProcessRequestMessage(Dso::Connection &aConnection,
286                                        MessageId        aMessageId,
287                                        const Message   &aMessage,
288                                        Dso::Tlv::Type   aPrimaryTlvType)
289     {
290         return static_cast<Connection &>(aConnection).ProcessRequestMessage(aMessageId, aMessage, aPrimaryTlvType);
291     }
292 
ProcessUnidirectionalMessage(Dso::Connection & aConnection,const Message & aMessage,Dso::Tlv::Type aPrimaryTlvType)293     static Error ProcessUnidirectionalMessage(Dso::Connection &aConnection,
294                                               const Message   &aMessage,
295                                               Dso::Tlv::Type   aPrimaryTlvType)
296     {
297         return static_cast<Connection &>(aConnection).ProcessUnidirectionalMessage(aMessage, aPrimaryTlvType);
298     }
299 
ProcessResponseMessage(Dso::Connection & aConnection,const Dns::Header & aHeader,const Message & aMessage,Dso::Tlv::Type aResponseTlvType,Dso::Tlv::Type aRequestTlvType)300     static Error ProcessResponseMessage(Dso::Connection   &aConnection,
301                                         const Dns::Header &aHeader,
302                                         const Message     &aMessage,
303                                         Dso::Tlv::Type     aResponseTlvType,
304                                         Dso::Tlv::Type     aRequestTlvType)
305     {
306         return static_cast<Connection &>(aConnection)
307             .ProcessResponseMessage(aHeader, aMessage, aResponseTlvType, aRequestTlvType);
308     }
309 
310     const char           *mName;
311     Ip6::SockAddr         mLocalSockAddr;
312     bool                  mDidGetConnectedSignal;
313     bool                  mDidGetSessionEstablishedSignal;
314     bool                  mDidGetDisconnectSignal;
315     bool                  mDidSendMessage;
316     bool                  mDidReceiveMessage;
317     bool                  mDidProcessRequest;
318     bool                  mDidProcessUnidirectional;
319     bool                  mDidProcessResponse;
320     uint8_t               mLastTxTestTlvValue;
321     uint8_t               mLastRxTestTlvValue;
322     Dns::Header::Response mLastRxResponseCode;
323 
324     static Callbacks sCallbacks;
325 };
326 
327 Dso::Connection::Callbacks Connection::sCallbacks(Connection::HandleConnected,
328                                                   Connection::HandleSessionEstablished,
329                                                   Connection::HandleDisconnected,
330                                                   Connection::ProcessRequestMessage,
331                                                   Connection::ProcessUnidirectionalMessage,
332                                                   Connection::ProcessResponseMessage);
333 
334 static constexpr uint16_t kMaxConnections = 5;
335 
336 static Array<Connection *, kMaxConnections> sConnections;
337 
FindPeerConnection(const Connection & aConnetion)338 static Connection *FindPeerConnection(const Connection &aConnetion)
339 {
340     Connection *peerConn = nullptr;
341 
342     for (Connection *conn : sConnections)
343     {
344         if (conn->GetLocalSockAddr() == aConnetion.GetPeerSockAddr())
345         {
346             peerConn = conn;
347             break;
348         }
349     }
350 
351     return peerConn;
352 }
353 
354 extern "C" {
355 
356 static bool sDsoListening = false;
357 
358 // This test flag indicates whether the `otPlatDso` API should
359 // forward a sent message to the peer connection. It can be set to
360 // `false` to drop the messages to test timeout behaviors on the
361 // peer.
362 static bool sTestDsoForwardMessageToPeer = true;
363 
364 // This test flag indicate whether when disconnecting a connection
365 // (using `otPlatDsoDisconnect()` to signal the peer connection about
366 // the disconnect. Default behavior is set to `true`. It can be set
367 // to `false` to test certain timeout behavior on peer side.
368 static bool sTestDsoSignalDisconnectToPeer = true;
369 
otPlatDsoEnableListening(otInstance *,bool aEnable)370 void otPlatDsoEnableListening(otInstance *, bool aEnable)
371 {
372     Log(" otPlatDsoEnableListening(%s)", aEnable ? "true" : "false");
373     sDsoListening = aEnable;
374 }
375 
otPlatDsoConnect(otPlatDsoConnection * aConnection,const otSockAddr * aPeerSockAddr)376 void otPlatDsoConnect(otPlatDsoConnection *aConnection, const otSockAddr *aPeerSockAddr)
377 {
378     Connection          &conn         = *static_cast<Connection *>(aConnection);
379     Connection          *peerConn     = nullptr;
380     const Ip6::SockAddr &peerSockAddr = AsCoreType(aPeerSockAddr);
381 
382     Log(" otPlatDsoConnect(%s, aPeer:0x%04x)", conn.GetName(), peerSockAddr.GetPort());
383 
384     VerifyOrQuit(conn.GetPeerSockAddr() == peerSockAddr);
385     VerifyOrQuit(conn.GetState() == Connection::kStateConnecting);
386 
387     if (!sDsoListening)
388     {
389         Log("   Server is not listening");
390         ExitNow();
391     }
392 
393     peerConn = static_cast<Connection *>(otPlatDsoAccept(otPlatDsoGetInstance(aConnection), aPeerSockAddr));
394 
395     if (peerConn == nullptr)
396     {
397         Log("   Request rejected");
398         ExitNow();
399     }
400 
401     Log("   Request accepted");
402     VerifyOrQuit(peerConn->GetState() == Connection::kStateConnecting);
403 
404     Log("   Signalling `Connected` on peer connection (%s)", peerConn->GetName());
405     otPlatDsoHandleConnected(peerConn);
406 
407     Log("   Signalling `Connected` on connection (%s)", conn.GetName());
408     otPlatDsoHandleConnected(aConnection);
409 
410 exit:
411     return;
412 }
413 
otPlatDsoSend(otPlatDsoConnection * aConnection,otMessage * aMessage)414 void otPlatDsoSend(otPlatDsoConnection *aConnection, otMessage *aMessage)
415 {
416     Connection &conn     = *static_cast<Connection *>(aConnection);
417     Connection *peerConn = nullptr;
418 
419     Log(" otPlatDsoSend(%s), message-len:%u", conn.GetName(), AsCoreType(aMessage).GetLength());
420 
421     VerifyOrQuit(conn.GetState() != Connection::kStateDisconnected);
422     VerifyOrQuit(conn.GetState() != Connection::kStateConnecting);
423     conn.mDidSendMessage = true;
424 
425     if (sTestDsoForwardMessageToPeer)
426     {
427         peerConn = FindPeerConnection(conn);
428         VerifyOrQuit(peerConn != nullptr);
429 
430         VerifyOrQuit(peerConn->GetState() != Connection::kStateDisconnected);
431         VerifyOrQuit(peerConn->GetState() != Connection::kStateConnecting);
432 
433         Log("   Sending the message to peer connection (%s)", peerConn->GetName());
434 
435         peerConn->mDidReceiveMessage = true;
436         otPlatDsoHandleReceive(peerConn, aMessage);
437     }
438     else
439     {
440         Log("   Dropping the message");
441     }
442 }
443 
otPlatDsoDisconnect(otPlatDsoConnection * aConnection,otPlatDsoDisconnectMode aMode)444 void otPlatDsoDisconnect(otPlatDsoConnection *aConnection, otPlatDsoDisconnectMode aMode)
445 {
446     Connection &conn     = *static_cast<Connection *>(aConnection);
447     Connection *peerConn = nullptr;
448 
449     Log(" otPlatDsoDisconnect(%s, mode:%s)", conn.GetName(),
450         (aMode == OT_PLAT_DSO_DISCONNECT_MODE_GRACEFULLY_CLOSE) ? "close" : "abort");
451 
452     VerifyOrQuit(conn.GetState() == Connection::kStateDisconnected);
453 
454     if (sTestDsoSignalDisconnectToPeer)
455     {
456         peerConn = FindPeerConnection(conn);
457 
458         if (peerConn == nullptr)
459         {
460             Log("   No peer connection found");
461         }
462         else if (peerConn->GetState() == Connection::kStateDisconnected)
463         {
464             Log("   Peer connection (%s) already disconnected", peerConn->GetName());
465         }
466         else
467         {
468             Log("   Signaling `Disconnected` on peer connection (%s)", peerConn->GetName());
469             otPlatDsoHandleDisconnected(peerConn, aMode);
470         }
471     }
472 }
473 
474 } // extern "C"
475 
AcceptConnection(Instance & aInstance,const Ip6::SockAddr & aPeerSockAddr)476 Dso::Connection *AcceptConnection(Instance &aInstance, const Ip6::SockAddr &aPeerSockAddr)
477 {
478     OT_UNUSED_VARIABLE(aInstance);
479 
480     Connection *rval = nullptr;
481 
482     Log("  AcceptConnection(peer:0x%04x)", aPeerSockAddr.GetPort());
483 
484     for (Connection *conn : sConnections)
485     {
486         if (conn->GetLocalSockAddr() == aPeerSockAddr)
487         {
488             VerifyOrQuit(conn->GetState() == Connection::kStateDisconnected);
489             rval = conn;
490             break;
491         }
492     }
493 
494     if (rval != nullptr)
495     {
496         Log("   Accepting and returning connection %s", rval->GetName());
497     }
498     else
499     {
500         Log("   Rejecting");
501     }
502 
503     return rval;
504 }
505 
506 static constexpr uint8_t kKeepAliveTestIterations = 3;
507 
VerifyKeepAliveExchange(Connection & aClientConn,Connection & aServerConn,uint32_t aKeepAliveInterval,uint8_t aNumIterations=kKeepAliveTestIterations)508 static void VerifyKeepAliveExchange(Connection &aClientConn,
509                                     Connection &aServerConn,
510                                     uint32_t    aKeepAliveInterval,
511                                     uint8_t     aNumIterations = kKeepAliveTestIterations)
512 {
513     for (uint8_t n = 0; n < aNumIterations; n++)
514     {
515         Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
516         Log("Test Keep Alive message exchange, iter %d", n + 1);
517 
518         aClientConn.ClearTestFlags();
519         aServerConn.ClearTestFlags();
520 
521         AdvanceTime(aKeepAliveInterval - 1);
522         VerifyOrQuit(!aClientConn.DidSendMessage());
523         VerifyOrQuit(!aServerConn.DidReceiveMessage());
524         Log("No message before keep alive timeout");
525 
526         AdvanceTime(1);
527         VerifyOrQuit(aClientConn.DidSendMessage());
528         VerifyOrQuit(aServerConn.DidReceiveMessage());
529         Log("KeepAlive message exchanged after keep alive time elapses");
530     }
531 }
532 
TestDso(void)533 void TestDso(void)
534 {
535     static constexpr uint16_t kPortA = 0xaaaa;
536     static constexpr uint16_t kPortB = 0xbbbb;
537 
538     static constexpr Dso::Tlv::Type kUnknownTlvType = 0xf801;
539 
540     static constexpr uint32_t kRetryDelayInterval  = TimeMilli::SecToMsec(3600);
541     static constexpr uint32_t kLongResponseTimeout = Dso::kResponseTimeout + TimeMilli::SecToMsec(17);
542 
543     Instance             &instance = *static_cast<Instance *>(testInitInstance());
544     Ip6::SockAddr         serverSockAddr(kPortA);
545     Ip6::SockAddr         clientSockAddr(kPortB);
546     Connection            serverConn(instance, "serverConn", serverSockAddr, clientSockAddr);
547     Connection            clientConn(instance, "clinetConn", clientSockAddr, serverSockAddr);
548     Message              *message;
549     Dso::Tlv              tlv;
550     Connection::MessageId messageId;
551 
552     sNow      = 0;
553     sInstance = &instance;
554 
555     SuccessOrQuit(sConnections.PushBack(&serverConn));
556     SuccessOrQuit(sConnections.PushBack(&clientConn));
557 
558     VerifyOrQuit(serverConn.GetPeerSockAddr() == clientSockAddr);
559     VerifyOrQuit(clientConn.GetPeerSockAddr() == serverSockAddr);
560 
561     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
562     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
563 
564     instance.Get<Dso>().StartListening(AcceptConnection);
565 
566     VerifyOrQuit(instance.Get<Dso>().FindClientConnection(clientSockAddr) == nullptr);
567     VerifyOrQuit(instance.Get<Dso>().FindServerConnection(clientSockAddr) == nullptr);
568     VerifyOrQuit(instance.Get<Dso>().FindClientConnection(serverSockAddr) == nullptr);
569     VerifyOrQuit(instance.Get<Dso>().FindServerConnection(serverSockAddr) == nullptr);
570 
571     Log("-------------------------------------------------------------------------------------------");
572     Log("Connect from client to server");
573 
574     clientConn.Connect();
575 
576     VerifyOrQuit(clientConn.GetState() == Connection::kStateConnectedButSessionless);
577     VerifyOrQuit(serverConn.GetState() == Connection::kStateConnectedButSessionless);
578 
579     VerifyOrQuit(clientConn.IsClient());
580     VerifyOrQuit(!clientConn.IsServer());
581 
582     VerifyOrQuit(!serverConn.IsClient());
583     VerifyOrQuit(serverConn.IsServer());
584 
585     // Note that we find connection with a peer address
586     VerifyOrQuit(instance.Get<Dso>().FindClientConnection(serverSockAddr) == &clientConn);
587     VerifyOrQuit(instance.Get<Dso>().FindServerConnection(serverSockAddr) == nullptr);
588     VerifyOrQuit(instance.Get<Dso>().FindClientConnection(clientSockAddr) == nullptr);
589     VerifyOrQuit(instance.Get<Dso>().FindServerConnection(clientSockAddr) == &serverConn);
590 
591     VerifyOrQuit(clientConn.DidGetConnectedSignal());
592     VerifyOrQuit(!clientConn.DidGetSessionEstablishedSignal());
593     VerifyOrQuit(!clientConn.DidGetDisconnectSignal());
594 
595     VerifyOrQuit(serverConn.DidGetConnectedSignal());
596     VerifyOrQuit(!serverConn.DidGetSessionEstablishedSignal());
597     VerifyOrQuit(!serverConn.DidGetDisconnectSignal());
598 
599     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
600     Log("Send keep alive message to establish connection");
601 
602     clientConn.ClearTestFlags();
603     serverConn.ClearTestFlags();
604 
605     SuccessOrQuit(clientConn.SendKeepAliveMessage());
606 
607     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
608     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
609 
610     VerifyOrQuit(!clientConn.DidGetConnectedSignal());
611     VerifyOrQuit(clientConn.DidGetSessionEstablishedSignal());
612     VerifyOrQuit(!clientConn.DidGetDisconnectSignal());
613 
614     VerifyOrQuit(!serverConn.DidGetConnectedSignal());
615     VerifyOrQuit(serverConn.DidGetSessionEstablishedSignal());
616     VerifyOrQuit(!serverConn.DidGetDisconnectSignal());
617 
618     VerifyOrQuit(clientConn.GetKeepAliveInterval() == Dso::kDefaultTimeout);
619     VerifyOrQuit(clientConn.GetInactivityTimeout() == Dso::kDefaultTimeout);
620     VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kDefaultTimeout);
621     VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kDefaultTimeout);
622 
623     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
624     Log("Close connection");
625 
626     clientConn.ClearTestFlags();
627     serverConn.ClearTestFlags();
628 
629     clientConn.Disconnect(Connection::kGracefullyClose, Connection::kReasonInactivityTimeout);
630 
631     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
632     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout);
633 
634     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
635     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed);
636 
637     VerifyOrQuit(!clientConn.DidGetConnectedSignal());
638     VerifyOrQuit(!clientConn.DidGetSessionEstablishedSignal());
639     VerifyOrQuit(!clientConn.DidGetDisconnectSignal());
640 
641     VerifyOrQuit(!serverConn.DidGetConnectedSignal());
642     VerifyOrQuit(!serverConn.DidGetSessionEstablishedSignal());
643     VerifyOrQuit(serverConn.DidGetDisconnectSignal());
644 
645     VerifyOrQuit(instance.Get<Dso>().FindClientConnection(clientSockAddr) == nullptr);
646     VerifyOrQuit(instance.Get<Dso>().FindServerConnection(clientSockAddr) == nullptr);
647     VerifyOrQuit(instance.Get<Dso>().FindClientConnection(serverSockAddr) == nullptr);
648     VerifyOrQuit(instance.Get<Dso>().FindServerConnection(serverSockAddr) == nullptr);
649 
650     Log("-------------------------------------------------------------------------------------------");
651     Log("Connection timeout when server is not listening");
652 
653     instance.Get<Dso>().StopListening();
654 
655     clientConn.ClearTestFlags();
656 
657     clientConn.Connect();
658     VerifyOrQuit(clientConn.GetState() == Connection::kStateConnecting);
659     VerifyOrQuit(instance.Get<Dso>().FindClientConnection(serverSockAddr) == &clientConn);
660     VerifyOrQuit(instance.Get<Dso>().FindServerConnection(serverSockAddr) == nullptr);
661 
662     AdvanceTime(Dso::kConnectingTimeout);
663 
664     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
665     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonFailedToConnect);
666     VerifyOrQuit(instance.Get<Dso>().FindClientConnection(serverSockAddr) == nullptr);
667     VerifyOrQuit(instance.Get<Dso>().FindServerConnection(serverSockAddr) == nullptr);
668 
669     VerifyOrQuit(!clientConn.DidGetConnectedSignal());
670     VerifyOrQuit(!clientConn.DidGetSessionEstablishedSignal());
671     VerifyOrQuit(clientConn.DidGetDisconnectSignal());
672 
673     Log("-------------------------------------------------------------------------------------------");
674     Log("Keep Alive Timeout behavior");
675 
676     // Keep Alive timeout smaller than min value should be rejected.
677     VerifyOrQuit(clientConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kMinKeepAliveInterval - 1) == kErrorInvalidArgs);
678 
679     instance.Get<Dso>().StartListening(AcceptConnection);
680     SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kMinKeepAliveInterval));
681 
682     VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval);
683     VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kInfiniteTimeout);
684 
685     clientConn.Connect();
686     SuccessOrQuit(clientConn.SendKeepAliveMessage());
687     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
688     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
689 
690     VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval);
691     VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kInfiniteTimeout);
692     VerifyOrQuit(clientConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval);
693     VerifyOrQuit(clientConn.GetInactivityTimeout() == Dso::kInfiniteTimeout);
694 
695     VerifyKeepAliveExchange(clientConn, serverConn, Dso::kMinKeepAliveInterval);
696 
697     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
698     Log("Change Keep Alive interval on server");
699 
700     clientConn.ClearTestFlags();
701     serverConn.ClearTestFlags();
702 
703     SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kDefaultTimeout));
704 
705     VerifyOrQuit(serverConn.DidSendMessage());
706     VerifyOrQuit(clientConn.DidReceiveMessage());
707     VerifyOrQuit(!clientConn.DidSendMessage());
708 
709     VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kDefaultTimeout);
710     VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kInfiniteTimeout);
711     VerifyOrQuit(clientConn.GetKeepAliveInterval() == Dso::kDefaultTimeout);
712     VerifyOrQuit(clientConn.GetInactivityTimeout() == Dso::kInfiniteTimeout);
713 
714     VerifyKeepAliveExchange(clientConn, serverConn, Dso::kDefaultTimeout);
715 
716     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
717     Log("Keep Alive timer clear on message send or receive");
718 
719     clientConn.ClearTestFlags();
720     serverConn.ClearTestFlags();
721 
722     AdvanceTime(Dso::kDefaultTimeout / 2);
723 
724     clientConn.SendTestUnidirectionalMessage();
725     VerifyOrQuit(clientConn.DidSendMessage());
726     VerifyOrQuit(serverConn.DidReceiveMessage());
727     VerifyOrQuit(!serverConn.DidSendMessage());
728     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
729     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
730     Log("Sent unidirectional message (client->server) at half the keep alive interval");
731     VerifyKeepAliveExchange(clientConn, serverConn, Dso::kDefaultTimeout, 1);
732 
733     clientConn.ClearTestFlags();
734     serverConn.ClearTestFlags();
735 
736     AdvanceTime(Dso::kDefaultTimeout / 2);
737 
738     serverConn.SendTestUnidirectionalMessage();
739     VerifyOrQuit(serverConn.DidSendMessage());
740     VerifyOrQuit(clientConn.DidReceiveMessage());
741     VerifyOrQuit(!clientConn.DidSendMessage());
742     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
743     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
744     Log("Sent unidirectional message (server->client) at half the keep alive interval");
745     VerifyKeepAliveExchange(clientConn, serverConn, Dso::kDefaultTimeout, 1);
746 
747     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
748     Log("Keep Alive timeout on server");
749 
750     clientConn.ClearTestFlags();
751     serverConn.ClearTestFlags();
752 
753     Log("Drop all sent message (drop Keep Alive msg from client->server)");
754     sTestDsoForwardMessageToPeer = false;
755 
756     AdvanceTime(Dso::kDefaultTimeout);
757     VerifyOrQuit(clientConn.DidSendMessage());
758     VerifyOrQuit(!serverConn.DidReceiveMessage());
759     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
760     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
761 
762     Log("Sever waits for twice the interval before Keep Alive timeout");
763     AdvanceTime(Dso::kDefaultTimeout);
764 
765     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
766     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonKeepAliveTimeout);
767 
768     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
769     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonPeerAborted);
770     Log("Server aborted connection on Keep Alive timeout");
771     sTestDsoForwardMessageToPeer = true;
772 
773     Log("-------------------------------------------------------------------------------------------");
774     Log("Inactivity Timeout behavior");
775 
776     SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kMinKeepAliveInterval));
777 
778     VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval);
779     VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kDefaultTimeout);
780 
781     clientConn.Connect();
782     SuccessOrQuit(clientConn.SendKeepAliveMessage());
783     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
784     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
785 
786     VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval);
787     VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kDefaultTimeout);
788     VerifyOrQuit(clientConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval);
789     VerifyOrQuit(clientConn.GetInactivityTimeout() == Dso::kDefaultTimeout);
790 
791     Log("Sending a unidirectional message should clear inactivity timer");
792     AdvanceTime(Dso::kDefaultTimeout / 2);
793     clientConn.SendTestUnidirectionalMessage();
794 
795     AdvanceTime(Dso::kDefaultTimeout - 1);
796     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
797     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
798     Log("Client keeps the connection up to the inactivity timeout");
799 
800     AdvanceTime(1);
801     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
802     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout);
803     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
804     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed);
805     Log("Client closes the connection gracefully on inactivity timeout");
806 
807     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
808     Log("Increasing inactivity timeout in middle");
809 
810     clientConn.Connect();
811     SuccessOrQuit(clientConn.SendKeepAliveMessage());
812     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
813     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
814 
815     AdvanceTime(TimeMilli::SecToMsec(10));
816     Log("After 10 sec elapses, change the inactivity timeout from 15 to 20 sec");
817     SuccessOrQuit(serverConn.SetTimeouts(TimeMilli::SecToMsec(20), Dso::kMinKeepAliveInterval));
818 
819     AdvanceTime(TimeMilli::SecToMsec(10) - 1);
820     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
821     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
822     Log("Client keeps the connection up to new 20 sec inactivity timeout");
823 
824     AdvanceTime(1);
825     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
826     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout);
827     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
828     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed);
829     Log("Client closes the connection gracefully on inactivity timeout of 20 sec");
830 
831     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
832     Log("Decreasing inactivity timeout in middle");
833 
834     clientConn.Connect();
835     SuccessOrQuit(clientConn.SendKeepAliveMessage());
836     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
837     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
838 
839     AdvanceTime(TimeMilli::SecToMsec(10));
840     Log("After 10 sec elapses, change the inactivity timeout from 15 to 10 sec");
841     SuccessOrQuit(serverConn.SetTimeouts(TimeMilli::SecToMsec(10), Dso::kMinKeepAliveInterval));
842 
843     AdvanceTime(0);
844     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
845     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout);
846     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
847     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed);
848     Log("Client closes the connection gracefully on new shorter inactivity timeout of 10 sec");
849 
850     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
851     Log("Changing inactivity timeout from infinite to finite");
852 
853     SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kInfiniteTimeout));
854     clientConn.Connect();
855     SuccessOrQuit(clientConn.SendKeepAliveMessage());
856     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
857     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
858 
859     AdvanceTime(TimeMilli::SecToMsec(6));
860     Log("After 6 sec, change the inactivity to infinite");
861     SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kInfiniteTimeout));
862 
863     AdvanceTime(TimeMilli::SecToMsec(4));
864     Log("After 4 sec, change the inactivity timeout from infinite to 20 sec");
865     SuccessOrQuit(serverConn.SetTimeouts(TimeMilli::SecToMsec(20), Dso::kInfiniteTimeout));
866 
867     AdvanceTime(TimeMilli::SecToMsec(10) - 1);
868     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
869     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
870 
871     AdvanceTime(1);
872     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
873     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout);
874     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
875     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed);
876     Log("Client closes the connection gracefully after 20 sec since last activity");
877 
878     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
879     Log("Tracking activity while inactivity timeout is infinite");
880 
881     SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kInfiniteTimeout));
882     clientConn.Connect();
883     SuccessOrQuit(clientConn.SendKeepAliveMessage());
884     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
885     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
886 
887     AdvanceTime(TimeMilli::SecToMsec(7));
888     Log("After 7 sec, send a test message, this clears inactivity timer");
889     serverConn.SendTestUnidirectionalMessage();
890 
891     AdvanceTime(TimeMilli::SecToMsec(10));
892     Log("After 10 sec, change the inactivity timeout from infinite to 15 sec");
893     SuccessOrQuit(serverConn.SetTimeouts(TimeMilli::SecToMsec(15), Dso::kInfiniteTimeout));
894 
895     AdvanceTime(TimeMilli::SecToMsec(5) - 1);
896     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
897     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
898 
899     AdvanceTime(1);
900     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
901     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout);
902     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
903     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed);
904     Log("Client closes the connection gracefully after 15 sec since last activity");
905 
906     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
907     Log("Inactivity timeout on server");
908 
909     clientConn.Connect();
910     SuccessOrQuit(clientConn.SendKeepAliveMessage());
911     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
912     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
913 
914     SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kInfiniteTimeout));
915 
916     Log("Wait for inactivity timeout and ensure client disconnect");
917     Log("Configure test for client not to signal its disconnect to server");
918     sTestDsoSignalDisconnectToPeer = false;
919 
920     AdvanceTime(Dso::kDefaultTimeout);
921     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
922     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout);
923     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
924     sTestDsoSignalDisconnectToPeer = true;
925 
926     Log("Server should disconnect after twice the inactivity timeout");
927     AdvanceTime(Dso::kDefaultTimeout - 1);
928     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
929     AdvanceTime(1);
930     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
931     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout);
932 
933     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
934     Log("Server reducing inactivity timeout to expired (on server)");
935 
936     clientConn.Connect();
937     SuccessOrQuit(clientConn.SendKeepAliveMessage());
938     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
939     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
940     SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kInfiniteTimeout));
941 
942     AdvanceTime(TimeMilli::SecToMsec(10));
943     Log("After 11 sec elapses, change the inactivity timeout from 15 to 2 sec");
944     SuccessOrQuit(serverConn.SetTimeouts(TimeMilli::SecToMsec(2), Dso::kMinKeepAliveInterval));
945 
946     sTestDsoSignalDisconnectToPeer = false;
947     AdvanceTime(0);
948     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
949     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout);
950     sTestDsoSignalDisconnectToPeer = true;
951     Log("Client closes the connection gracefully on expired timeout");
952     Log("Configure test for client not to signal its disconnect to server");
953 
954     AdvanceTime(Dso::kMinServerInactivityWaitTime - 1);
955     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
956     AdvanceTime(1);
957     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
958     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout);
959     Log("Server wait for kMinServerInactivityWaitTime (5 sec) before closing on expired timeout");
960 
961     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
962     Log("Long-lived operation");
963 
964     clientConn.Connect();
965     SuccessOrQuit(clientConn.SendKeepAliveMessage());
966     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
967     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
968     SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kInfiniteTimeout));
969 
970     clientConn.SetLongLivedOperation(true);
971     serverConn.SetLongLivedOperation(true);
972 
973     AdvanceTime(2 * Dso::kDefaultTimeout);
974     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
975     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
976 
977     clientConn.SetLongLivedOperation(false);
978     AdvanceTime(0);
979     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
980     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
981 
982     Log("-------------------------------------------------------------------------------------------");
983     Log("Request, response, and unidirectional message exchange");
984 
985     SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kDefaultTimeout));
986     clientConn.Connect();
987 
988     VerifyOrQuit(clientConn.GetState() == Connection::kStateConnectedButSessionless);
989     VerifyOrQuit(serverConn.GetState() == Connection::kStateConnectedButSessionless);
990 
991     clientConn.ClearTestFlags();
992     serverConn.ClearTestFlags();
993 
994     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
995     Log("Establish connection using test message request/response");
996     clientConn.SendTestRequestMessage();
997 
998     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
999     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
1000     VerifyOrQuit(serverConn.DidProcessRequest());
1001     VerifyOrQuit(clientConn.DidProcessResponse());
1002 
1003     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1004     Log("Send unidirectional test message");
1005 
1006     serverConn.ClearTestFlags();
1007     clientConn.SendTestUnidirectionalMessage(0x10);
1008     VerifyOrQuit(serverConn.DidProcessUnidirectional());
1009     VerifyOrQuit(serverConn.GetLastRxTestTlvValue() == 0x10);
1010 
1011     clientConn.ClearTestFlags();
1012     serverConn.SendTestUnidirectionalMessage(0x20);
1013     VerifyOrQuit(clientConn.DidProcessUnidirectional());
1014     VerifyOrQuit(clientConn.GetLastRxTestTlvValue() == 0x20);
1015 
1016     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1017     Log("Exchange request and response");
1018 
1019     clientConn.ClearTestFlags();
1020     serverConn.ClearTestFlags();
1021     serverConn.SendTestRequestMessage(0x30);
1022     VerifyOrQuit(clientConn.DidProcessRequest());
1023     VerifyOrQuit(!clientConn.DidProcessResponse());
1024     VerifyOrQuit(!serverConn.DidProcessRequest());
1025     VerifyOrQuit(serverConn.DidProcessResponse());
1026     VerifyOrQuit(serverConn.GetLastRxTestTlvValue() == 0x30);
1027     VerifyOrQuit(clientConn.GetLastRxTestTlvValue() == 0x30);
1028 
1029     clientConn.ClearTestFlags();
1030     serverConn.ClearTestFlags();
1031     clientConn.SendTestRequestMessage(0x40);
1032     VerifyOrQuit(!clientConn.DidProcessRequest());
1033     VerifyOrQuit(clientConn.DidProcessResponse());
1034     VerifyOrQuit(serverConn.DidProcessRequest());
1035     VerifyOrQuit(!serverConn.DidProcessResponse());
1036     VerifyOrQuit(serverConn.GetLastRxTestTlvValue() == 0x40);
1037     VerifyOrQuit(clientConn.GetLastRxTestTlvValue() == 0x40);
1038 
1039     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
1040     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
1041 
1042     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1043     Log("Send unknown TLV request");
1044 
1045     clientConn.ClearTestFlags();
1046     serverConn.ClearTestFlags();
1047 
1048     message = clientConn.NewMessage();
1049     VerifyOrQuit(message != nullptr);
1050     tlv.Init(kUnknownTlvType, 0);
1051     SuccessOrQuit(message->Append(tlv));
1052     SuccessOrQuit(clientConn.SendRequestMessage(*message, messageId));
1053 
1054     VerifyOrQuit(!clientConn.DidProcessRequest());
1055     VerifyOrQuit(clientConn.DidProcessResponse());
1056     VerifyOrQuit(serverConn.DidProcessRequest());
1057     VerifyOrQuit(!serverConn.DidProcessResponse());
1058     VerifyOrQuit(clientConn.GetLastRxResponseCode() == Dns::Header::kDsoTypeNotImplemented);
1059     Log("Received a response with DSO Type Unknown error code");
1060 
1061     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
1062     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
1063 
1064     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1065     Log("Send unknown TLV unidirectional");
1066 
1067     clientConn.ClearTestFlags();
1068     serverConn.ClearTestFlags();
1069 
1070     message = clientConn.NewMessage();
1071     VerifyOrQuit(message != nullptr);
1072     tlv.Init(kUnknownTlvType, 0);
1073     SuccessOrQuit(message->Append(tlv));
1074     SuccessOrQuit(clientConn.SendUnidirectionalMessage(*message));
1075     VerifyOrQuit(serverConn.DidProcessUnidirectional());
1076     Log("Unknown TLV unidirectional is correctly ignored");
1077     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
1078     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
1079 
1080     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1081     Log("Send malformed/invalid request");
1082 
1083     clientConn.ClearTestFlags();
1084     serverConn.ClearTestFlags();
1085 
1086     message = clientConn.NewMessage();
1087     VerifyOrQuit(message != nullptr);
1088     tlv.Init(Dso::Tlv::kEncryptionPaddingType, 0);
1089     SuccessOrQuit(message->Append(tlv));
1090 
1091     SuccessOrQuit(serverConn.SendRequestMessage(*message, messageId));
1092     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
1093     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
1094     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonPeerMisbehavior);
1095     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerAborted);
1096     VerifyOrQuit(clientConn.DidGetDisconnectSignal());
1097     VerifyOrQuit(serverConn.DidGetDisconnectSignal());
1098     Log("Client aborted on invalid request message");
1099 
1100     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1101     Log("Response timeout during session establishment");
1102 
1103     clientConn.ClearTestFlags();
1104     serverConn.ClearTestFlags();
1105 
1106     SuccessOrQuit(serverConn.SetTimeouts(Dso::kResponseTimeout, Dso::kInfiniteTimeout));
1107     clientConn.Connect();
1108     VerifyOrQuit(clientConn.GetState() == Connection::kStateConnectedButSessionless);
1109     VerifyOrQuit(serverConn.GetState() == Connection::kStateConnectedButSessionless);
1110 
1111     sTestDsoForwardMessageToPeer = false;
1112     clientConn.SendTestRequestMessage();
1113     sTestDsoForwardMessageToPeer = true;
1114 
1115     VerifyOrQuit(clientConn.GetState() == Connection::kStateEstablishingSession);
1116     VerifyOrQuit(serverConn.GetState() == Connection::kStateConnectedButSessionless);
1117 
1118     sTestDsoSignalDisconnectToPeer = false;
1119     AdvanceTime(Dso::kResponseTimeout);
1120     sTestDsoSignalDisconnectToPeer = true;
1121     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
1122     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonResponseTimeout);
1123     VerifyOrQuit(clientConn.DidGetDisconnectSignal());
1124     VerifyOrQuit(serverConn.GetState() == Connection::kStateConnectedButSessionless);
1125     Log("Client disconnected after response timeout");
1126 
1127     AdvanceTime(Dso::kResponseTimeout);
1128     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
1129     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout);
1130     VerifyOrQuit(serverConn.DidGetDisconnectSignal());
1131     Log("Server disconnected after twice the inactivity timeout");
1132 
1133     Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1134     Log("Response timeout after session establishment");
1135 
1136     clientConn.ClearTestFlags();
1137     serverConn.ClearTestFlags();
1138 
1139     SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kInfiniteTimeout));
1140     clientConn.Connect();
1141     SuccessOrQuit(clientConn.SendKeepAliveMessage());
1142     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
1143     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
1144 
1145     sTestDsoForwardMessageToPeer = false;
1146     serverConn.SendTestRequestMessage();
1147     sTestDsoForwardMessageToPeer = true;
1148 
1149     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
1150     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
1151 
1152     AdvanceTime(Dso::kResponseTimeout - 1);
1153     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
1154     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
1155 
1156     AdvanceTime(1);
1157     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
1158     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
1159     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonResponseTimeout);
1160     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonPeerAborted);
1161     VerifyOrQuit(serverConn.DidGetDisconnectSignal());
1162     VerifyOrQuit(clientConn.DidGetDisconnectSignal());
1163 
1164     clientConn.ClearTestFlags();
1165     serverConn.ClearTestFlags();
1166 
1167     SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kInfiniteTimeout));
1168     clientConn.Connect();
1169     SuccessOrQuit(clientConn.SendKeepAliveMessage());
1170     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
1171     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
1172 
1173     sTestDsoForwardMessageToPeer = false;
1174     serverConn.SendTestRequestMessage(0, kLongResponseTimeout);
1175     sTestDsoForwardMessageToPeer = true;
1176 
1177     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
1178     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
1179 
1180     AdvanceTime(kLongResponseTimeout - 1);
1181     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
1182     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
1183 
1184     AdvanceTime(1);
1185     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
1186     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
1187     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonResponseTimeout);
1188     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonPeerAborted);
1189     VerifyOrQuit(serverConn.DidGetDisconnectSignal());
1190     VerifyOrQuit(clientConn.DidGetDisconnectSignal());
1191 
1192     Log("-------------------------------------------------------------------------------------------");
1193     Log("Retry Delay message");
1194 
1195     clientConn.ClearTestFlags();
1196     serverConn.ClearTestFlags();
1197 
1198     SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kInfiniteTimeout));
1199     clientConn.Connect();
1200     SuccessOrQuit(clientConn.SendKeepAliveMessage());
1201     VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished);
1202     VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished);
1203 
1204     SuccessOrQuit(serverConn.SendRetryDelayMessage(kRetryDelayInterval, Dns::Header::kResponseServerFailure));
1205 
1206     VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected);
1207     VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected);
1208     VerifyOrQuit(clientConn.DidGetDisconnectSignal());
1209     VerifyOrQuit(serverConn.DidGetDisconnectSignal());
1210     VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonServerRetryDelayRequest);
1211     VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed);
1212 
1213     VerifyOrQuit(clientConn.GetRetryDelay() == kRetryDelayInterval);
1214     VerifyOrQuit(clientConn.GetRetryDelayErrorCode() == Dns::Header::kResponseServerFailure);
1215 
1216     Log("End of test");
1217 
1218     testFreeInstance(&instance);
1219 }
1220 
1221 } // namespace Dns
1222 
1223 #endif // OPENTHREAD_CONFIG_DNS_DSO_ENABLE
1224 
1225 } // namespace ot
1226 
main(void)1227 int main(void)
1228 {
1229 #if OPENTHREAD_CONFIG_DNS_DSO_ENABLE
1230     ot::Dns::TestDso();
1231     printf("All tests passed\n");
1232 #else
1233     printf("DSO feature is not enabled\n");
1234 #endif
1235 
1236     return 0;
1237 }
1238