| /* |
| * Copyright (c) 2021, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <openthread/config.h> |
| |
| #include "test_platform.h" |
| #include "test_util.hpp" |
| |
| #include "common/arg_macros.hpp" |
| #include "common/array.hpp" |
| #include "common/as_core_type.hpp" |
| #include "common/time.hpp" |
| #include "instance/instance.hpp" |
| #include "net/dns_dso.hpp" |
| |
| namespace ot { |
| |
| #if OPENTHREAD_CONFIG_DNS_DSO_ENABLE |
| |
| extern "C" { |
| |
| static uint32_t sNow = 0; |
| static uint32_t sAlarmTime; |
| static bool sAlarmOn = false; |
| static otInstance *sInstance; |
| |
| // Logs a message and adds current time (sNow) as "<hours>:<min>:<secs>.<msec>" |
| #define Log(...) \ |
| printf("%02u:%02u:%02u.%03u " OT_FIRST_ARG(__VA_ARGS__) "\n", (sNow / 36000000), (sNow / 60000) % 60, \ |
| (sNow / 1000) % 60, sNow % 1000 OT_REST_ARGS(__VA_ARGS__)) |
| |
| void otPlatAlarmMilliStop(otInstance *) { sAlarmOn = false; } |
| |
| void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt) |
| { |
| sAlarmOn = true; |
| sAlarmTime = aT0 + aDt; |
| |
| Log(" otPlatAlarmMilliStartAt(time:%u.%03u, dt:%u.%03u)", sAlarmTime / 1000, sAlarmTime % 1000, |
| (sAlarmTime - sNow) / 1000, (sAlarmTime - sNow) % 1000); |
| } |
| |
| uint32_t otPlatAlarmMilliGetNow(void) { return sNow; } |
| |
| } // extern "C" |
| |
| void AdvanceTime(uint32_t aDuration) |
| { |
| uint32_t time = sNow + aDuration; |
| |
| Log(" AdvanceTime for %u.%03u", aDuration / 1000, aDuration % 1000); |
| |
| while (TimeMilli(sAlarmTime) <= TimeMilli(time)) |
| { |
| sNow = sAlarmTime; |
| otPlatAlarmMilliFired(sInstance); |
| } |
| |
| sNow = time; |
| } |
| |
| namespace Dns { |
| |
| OT_TOOL_PACKED_BEGIN |
| class TestTlv : public Dso::Tlv |
| { |
| public: |
| static constexpr Type kType = 0xf800; |
| |
| void Init(uint8_t aValue) |
| { |
| Tlv::Init(kType, sizeof(*this) - sizeof(Tlv)); |
| mValue = aValue; |
| } |
| |
| bool IsValid(void) const { return GetSize() >= sizeof(*this); } |
| uint8_t GetValue(void) const { return mValue; } |
| |
| private: |
| uint8_t mValue; |
| |
| } OT_TOOL_PACKED_END; |
| |
| extern "C" void otPlatDsoSend(otPlatDsoConnection *aConnection, otMessage *aMessage); |
| |
| class Connection : public Dso::Connection |
| { |
| friend void otPlatDsoSend(otPlatDsoConnection *aConnection, otMessage *aMessage); |
| |
| public: |
| explicit Connection(Instance &aInstance, |
| const char *aName, |
| const Ip6::SockAddr &aLocalSockAddr, |
| const Ip6::SockAddr &aPeerSockAddr) |
| : Dso::Connection(aInstance, aPeerSockAddr, sCallbacks) |
| , mName(aName) |
| , mLocalSockAddr(aLocalSockAddr) |
| { |
| ClearTestFlags(); |
| } |
| |
| const char *GetName(void) const { return mName; } |
| const Ip6::SockAddr &GetLocalSockAddr(void) const { return mLocalSockAddr; } |
| |
| void ClearTestFlags(void) |
| { |
| mDidGetConnectedSignal = false; |
| mDidGetSessionEstablishedSignal = false; |
| mDidGetDisconnectSignal = false; |
| mDidSendMessage = false; |
| mDidReceiveMessage = false; |
| mDidProcessRequest = false; |
| mDidProcessUnidirectional = false; |
| mDidProcessResponse = false; |
| } |
| |
| bool DidGetConnectedSignal(void) const { return mDidGetConnectedSignal; } |
| bool DidGetSessionEstablishedSignal(void) const { return mDidGetSessionEstablishedSignal; } |
| bool DidGetDisconnectSignal(void) const { return mDidGetDisconnectSignal; } |
| bool DidSendMessage(void) const { return mDidSendMessage; } |
| bool DidReceiveMessage(void) const { return mDidReceiveMessage; } |
| bool DidProcessRequest(void) const { return mDidProcessRequest; } |
| bool DidProcessUnidirectional(void) const { return mDidProcessUnidirectional; } |
| bool DidProcessResponse(void) const { return mDidProcessResponse; } |
| |
| uint8_t GetLastRxTestTlvValue(void) const { return mLastRxTestTlvValue; } |
| Dns::Header::Response GetLastRxResponseCode(void) const { return mLastRxResponseCode; } |
| |
| void SendTestRequestMessage(uint8_t aValue = 0, uint32_t aResponseTimeout = Dso::kResponseTimeout) |
| { |
| MessageId messageId; |
| |
| mLastTxTestTlvValue = aValue; |
| SuccessOrQuit(SendRequestMessage(PrepareTestMessage(aValue), messageId, aResponseTimeout)); |
| } |
| |
| void SendTestUnidirectionalMessage(uint8_t aValue = 0) |
| { |
| mLastTxTestTlvValue = aValue; |
| SuccessOrQuit(SendUnidirectionalMessage(PrepareTestMessage(aValue))); |
| } |
| |
| private: |
| Message &PrepareTestMessage(uint8_t aValue) |
| { |
| TestTlv testTlv; |
| Message *message = NewMessage(); |
| |
| VerifyOrQuit(message != nullptr); |
| testTlv.Init(aValue); |
| SuccessOrQuit(message->Append(testTlv)); |
| |
| return *message; |
| } |
| |
| void ParseTestMessage(const Message &aMessage) |
| { |
| TestTlv testTlv; |
| Dso::Tlv tlv; |
| uint16_t offset = aMessage.GetOffset(); |
| |
| // Test message MUST only contain Test TLV and Encryption |
| // Padding TLV. |
| |
| SuccessOrQuit(aMessage.Read(offset, testTlv)); |
| VerifyOrQuit(testTlv.GetType() == TestTlv::kType); |
| VerifyOrQuit(testTlv.IsValid()); |
| offset += testTlv.GetSize(); |
| mLastRxTestTlvValue = testTlv.GetValue(); |
| |
| SuccessOrQuit(aMessage.Read(offset, tlv)); |
| VerifyOrQuit(tlv.GetType() == Dso::Tlv::kEncryptionPaddingType); |
| offset += tlv.GetSize(); |
| |
| VerifyOrQuit(offset == aMessage.GetLength()); |
| } |
| |
| void SendTestResponseMessage(MessageId aResponseId, uint8_t aValue) |
| { |
| mLastTxTestTlvValue = aValue; |
| SuccessOrQuit(SendResponseMessage(PrepareTestMessage(aValue), aResponseId)); |
| } |
| |
| //--------------------------------------------------------------------- |
| // Callback methods |
| |
| void HandleConnected(void) { mDidGetConnectedSignal = true; } |
| void HandleSessionEstablished(void) { mDidGetSessionEstablishedSignal = true; } |
| void HandleDisconnected(void) { mDidGetDisconnectSignal = true; } |
| |
| Error ProcessRequestMessage(MessageId aMessageId, const Message &aMessage, Dso::Tlv::Type aPrimaryTlvType) |
| { |
| Error error = kErrorNone; |
| |
| Log(" ProcessRequestMessage(primaryTlv:0x%04x) on %s", aPrimaryTlvType, mName); |
| mDidProcessRequest = true; |
| |
| VerifyOrExit(aPrimaryTlvType == TestTlv::kType, error = kErrorNotFound); |
| ParseTestMessage(aMessage); |
| SendTestResponseMessage(aMessageId, mLastRxTestTlvValue); |
| |
| exit: |
| return error; |
| } |
| |
| Error ProcessUnidirectionalMessage(const Message &aMessage, Dso::Tlv::Type aPrimaryTlvType) |
| { |
| Log(" ProcessUnidirectionalMessage(primaryTlv:0x%04x) on %s", aPrimaryTlvType, mName); |
| mDidProcessUnidirectional = true; |
| |
| if (aPrimaryTlvType == TestTlv::kType) |
| { |
| ParseTestMessage(aMessage); |
| } |
| |
| return kErrorNone; |
| } |
| |
| Error ProcessResponseMessage(const Dns::Header &aHeader, |
| const Message &aMessage, |
| Dso::Tlv::Type aResponseTlvType, |
| Dso::Tlv::Type aRequestTlvType) |
| { |
| Error error = kErrorNone; |
| |
| mDidProcessResponse = true; |
| mLastRxResponseCode = aHeader.GetResponseCode(); |
| Log(" ProcessResponseMessage(responseTlv:0x%04x) on %s (response-Code:%u) ", aResponseTlvType, mName, |
| mLastRxResponseCode); |
| |
| VerifyOrExit(mLastRxResponseCode == Dns::Header::kResponseSuccess); |
| |
| // During test we only expect a Test TLV response with |
| // a matching TLV value to what was sent last. |
| |
| VerifyOrQuit(aResponseTlvType == TestTlv::kType); |
| VerifyOrQuit(aRequestTlvType == TestTlv::kType); |
| ParseTestMessage(aMessage); |
| VerifyOrQuit(mLastRxTestTlvValue == mLastTxTestTlvValue); |
| |
| exit: |
| return error; |
| } |
| |
| static void HandleConnected(Dso::Connection &aConnection) |
| { |
| static_cast<Connection &>(aConnection).HandleConnected(); |
| } |
| |
| static void HandleSessionEstablished(Dso::Connection &aConnection) |
| { |
| static_cast<Connection &>(aConnection).HandleSessionEstablished(); |
| } |
| |
| static void HandleDisconnected(Dso::Connection &aConnection) |
| { |
| static_cast<Connection &>(aConnection).HandleDisconnected(); |
| } |
| |
| static Error ProcessRequestMessage(Dso::Connection &aConnection, |
| MessageId aMessageId, |
| const Message &aMessage, |
| Dso::Tlv::Type aPrimaryTlvType) |
| { |
| return static_cast<Connection &>(aConnection).ProcessRequestMessage(aMessageId, aMessage, aPrimaryTlvType); |
| } |
| |
| static Error ProcessUnidirectionalMessage(Dso::Connection &aConnection, |
| const Message &aMessage, |
| Dso::Tlv::Type aPrimaryTlvType) |
| { |
| return static_cast<Connection &>(aConnection).ProcessUnidirectionalMessage(aMessage, aPrimaryTlvType); |
| } |
| |
| static Error ProcessResponseMessage(Dso::Connection &aConnection, |
| const Dns::Header &aHeader, |
| const Message &aMessage, |
| Dso::Tlv::Type aResponseTlvType, |
| Dso::Tlv::Type aRequestTlvType) |
| { |
| return static_cast<Connection &>(aConnection) |
| .ProcessResponseMessage(aHeader, aMessage, aResponseTlvType, aRequestTlvType); |
| } |
| |
| const char *mName; |
| Ip6::SockAddr mLocalSockAddr; |
| bool mDidGetConnectedSignal; |
| bool mDidGetSessionEstablishedSignal; |
| bool mDidGetDisconnectSignal; |
| bool mDidSendMessage; |
| bool mDidReceiveMessage; |
| bool mDidProcessRequest; |
| bool mDidProcessUnidirectional; |
| bool mDidProcessResponse; |
| uint8_t mLastTxTestTlvValue; |
| uint8_t mLastRxTestTlvValue; |
| Dns::Header::Response mLastRxResponseCode; |
| |
| static Callbacks sCallbacks; |
| }; |
| |
| Dso::Connection::Callbacks Connection::sCallbacks(Connection::HandleConnected, |
| Connection::HandleSessionEstablished, |
| Connection::HandleDisconnected, |
| Connection::ProcessRequestMessage, |
| Connection::ProcessUnidirectionalMessage, |
| Connection::ProcessResponseMessage); |
| |
| static constexpr uint16_t kMaxConnections = 5; |
| |
| static Array<Connection *, kMaxConnections> sConnections; |
| |
| static Connection *FindPeerConnection(const Connection &aConnetion) |
| { |
| Connection *peerConn = nullptr; |
| |
| for (Connection *conn : sConnections) |
| { |
| if (conn->GetLocalSockAddr() == aConnetion.GetPeerSockAddr()) |
| { |
| peerConn = conn; |
| break; |
| } |
| } |
| |
| return peerConn; |
| } |
| |
| extern "C" { |
| |
| static bool sDsoListening = false; |
| |
| // This test flag indicates whether the `otPlatDso` API should |
| // forward a sent message to the peer connection. It can be set to |
| // `false` to drop the messages to test timeout behaviors on the |
| // peer. |
| static bool sTestDsoForwardMessageToPeer = true; |
| |
| // This test flag indicate whether when disconnecting a connection |
| // (using `otPlatDsoDisconnect()` to signal the peer connection about |
| // the disconnect. Default behavior is set to `true`. It can be set |
| // to `false` to test certain timeout behavior on peer side. |
| static bool sTestDsoSignalDisconnectToPeer = true; |
| |
| void otPlatDsoEnableListening(otInstance *, bool aEnable) |
| { |
| Log(" otPlatDsoEnableListening(%s)", aEnable ? "true" : "false"); |
| sDsoListening = aEnable; |
| } |
| |
| void otPlatDsoConnect(otPlatDsoConnection *aConnection, const otSockAddr *aPeerSockAddr) |
| { |
| Connection &conn = *static_cast<Connection *>(aConnection); |
| Connection *peerConn = nullptr; |
| const Ip6::SockAddr &peerSockAddr = AsCoreType(aPeerSockAddr); |
| |
| Log(" otPlatDsoConnect(%s, aPeer:0x%04x)", conn.GetName(), peerSockAddr.GetPort()); |
| |
| VerifyOrQuit(conn.GetPeerSockAddr() == peerSockAddr); |
| VerifyOrQuit(conn.GetState() == Connection::kStateConnecting); |
| |
| if (!sDsoListening) |
| { |
| Log(" Server is not listening"); |
| ExitNow(); |
| } |
| |
| peerConn = static_cast<Connection *>(otPlatDsoAccept(otPlatDsoGetInstance(aConnection), aPeerSockAddr)); |
| |
| if (peerConn == nullptr) |
| { |
| Log(" Request rejected"); |
| ExitNow(); |
| } |
| |
| Log(" Request accepted"); |
| VerifyOrQuit(peerConn->GetState() == Connection::kStateConnecting); |
| |
| Log(" Signalling `Connected` on peer connection (%s)", peerConn->GetName()); |
| otPlatDsoHandleConnected(peerConn); |
| |
| Log(" Signalling `Connected` on connection (%s)", conn.GetName()); |
| otPlatDsoHandleConnected(aConnection); |
| |
| exit: |
| return; |
| } |
| |
| void otPlatDsoSend(otPlatDsoConnection *aConnection, otMessage *aMessage) |
| { |
| Connection &conn = *static_cast<Connection *>(aConnection); |
| Connection *peerConn = nullptr; |
| |
| Log(" otPlatDsoSend(%s), message-len:%u", conn.GetName(), AsCoreType(aMessage).GetLength()); |
| |
| VerifyOrQuit(conn.GetState() != Connection::kStateDisconnected); |
| VerifyOrQuit(conn.GetState() != Connection::kStateConnecting); |
| conn.mDidSendMessage = true; |
| |
| if (sTestDsoForwardMessageToPeer) |
| { |
| peerConn = FindPeerConnection(conn); |
| VerifyOrQuit(peerConn != nullptr); |
| |
| VerifyOrQuit(peerConn->GetState() != Connection::kStateDisconnected); |
| VerifyOrQuit(peerConn->GetState() != Connection::kStateConnecting); |
| |
| Log(" Sending the message to peer connection (%s)", peerConn->GetName()); |
| |
| peerConn->mDidReceiveMessage = true; |
| otPlatDsoHandleReceive(peerConn, aMessage); |
| } |
| else |
| { |
| Log(" Dropping the message"); |
| } |
| } |
| |
| void otPlatDsoDisconnect(otPlatDsoConnection *aConnection, otPlatDsoDisconnectMode aMode) |
| { |
| Connection &conn = *static_cast<Connection *>(aConnection); |
| Connection *peerConn = nullptr; |
| |
| Log(" otPlatDsoDisconnect(%s, mode:%s)", conn.GetName(), |
| (aMode == OT_PLAT_DSO_DISCONNECT_MODE_GRACEFULLY_CLOSE) ? "close" : "abort"); |
| |
| VerifyOrQuit(conn.GetState() == Connection::kStateDisconnected); |
| |
| if (sTestDsoSignalDisconnectToPeer) |
| { |
| peerConn = FindPeerConnection(conn); |
| |
| if (peerConn == nullptr) |
| { |
| Log(" No peer connection found"); |
| } |
| else if (peerConn->GetState() == Connection::kStateDisconnected) |
| { |
| Log(" Peer connection (%s) already disconnected", peerConn->GetName()); |
| } |
| else |
| { |
| Log(" Signaling `Disconnected` on peer connection (%s)", peerConn->GetName()); |
| otPlatDsoHandleDisconnected(peerConn, aMode); |
| } |
| } |
| } |
| |
| } // extern "C" |
| |
| Dso::Connection *AcceptConnection(Instance &aInstance, const Ip6::SockAddr &aPeerSockAddr) |
| { |
| OT_UNUSED_VARIABLE(aInstance); |
| |
| Connection *rval = nullptr; |
| |
| Log(" AcceptConnection(peer:0x%04x)", aPeerSockAddr.GetPort()); |
| |
| for (Connection *conn : sConnections) |
| { |
| if (conn->GetLocalSockAddr() == aPeerSockAddr) |
| { |
| VerifyOrQuit(conn->GetState() == Connection::kStateDisconnected); |
| rval = conn; |
| break; |
| } |
| } |
| |
| if (rval != nullptr) |
| { |
| Log(" Accepting and returning connection %s", rval->GetName()); |
| } |
| else |
| { |
| Log(" Rejecting"); |
| } |
| |
| return rval; |
| } |
| |
| static constexpr uint8_t kKeepAliveTestIterations = 3; |
| |
| static void VerifyKeepAliveExchange(Connection &aClientConn, |
| Connection &aServerConn, |
| uint32_t aKeepAliveInterval, |
| uint8_t aNumIterations = kKeepAliveTestIterations) |
| { |
| for (uint8_t n = 0; n < aNumIterations; n++) |
| { |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Test Keep Alive message exchange, iter %d", n + 1); |
| |
| aClientConn.ClearTestFlags(); |
| aServerConn.ClearTestFlags(); |
| |
| AdvanceTime(aKeepAliveInterval - 1); |
| VerifyOrQuit(!aClientConn.DidSendMessage()); |
| VerifyOrQuit(!aServerConn.DidReceiveMessage()); |
| Log("No message before keep alive timeout"); |
| |
| AdvanceTime(1); |
| VerifyOrQuit(aClientConn.DidSendMessage()); |
| VerifyOrQuit(aServerConn.DidReceiveMessage()); |
| Log("KeepAlive message exchanged after keep alive time elapses"); |
| } |
| } |
| |
| void TestDso(void) |
| { |
| static constexpr uint16_t kPortA = 0xaaaa; |
| static constexpr uint16_t kPortB = 0xbbbb; |
| |
| static constexpr Dso::Tlv::Type kUnknownTlvType = 0xf801; |
| |
| static constexpr uint32_t kRetryDelayInterval = TimeMilli::SecToMsec(3600); |
| static constexpr uint32_t kLongResponseTimeout = Dso::kResponseTimeout + TimeMilli::SecToMsec(17); |
| |
| Instance &instance = *static_cast<Instance *>(testInitInstance()); |
| Ip6::SockAddr serverSockAddr(kPortA); |
| Ip6::SockAddr clientSockAddr(kPortB); |
| Connection serverConn(instance, "serverConn", serverSockAddr, clientSockAddr); |
| Connection clientConn(instance, "clinetConn", clientSockAddr, serverSockAddr); |
| Message *message; |
| Dso::Tlv tlv; |
| Connection::MessageId messageId; |
| |
| sNow = 0; |
| sInstance = &instance; |
| |
| SuccessOrQuit(sConnections.PushBack(&serverConn)); |
| SuccessOrQuit(sConnections.PushBack(&clientConn)); |
| |
| VerifyOrQuit(serverConn.GetPeerSockAddr() == clientSockAddr); |
| VerifyOrQuit(clientConn.GetPeerSockAddr() == serverSockAddr); |
| |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| |
| instance.Get<Dso>().StartListening(AcceptConnection); |
| |
| VerifyOrQuit(instance.Get<Dso>().FindClientConnection(clientSockAddr) == nullptr); |
| VerifyOrQuit(instance.Get<Dso>().FindServerConnection(clientSockAddr) == nullptr); |
| VerifyOrQuit(instance.Get<Dso>().FindClientConnection(serverSockAddr) == nullptr); |
| VerifyOrQuit(instance.Get<Dso>().FindServerConnection(serverSockAddr) == nullptr); |
| |
| Log("-------------------------------------------------------------------------------------------"); |
| Log("Connect from client to server"); |
| |
| clientConn.Connect(); |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateConnectedButSessionless); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateConnectedButSessionless); |
| |
| VerifyOrQuit(clientConn.IsClient()); |
| VerifyOrQuit(!clientConn.IsServer()); |
| |
| VerifyOrQuit(!serverConn.IsClient()); |
| VerifyOrQuit(serverConn.IsServer()); |
| |
| // Note that we find connection with a peer address |
| VerifyOrQuit(instance.Get<Dso>().FindClientConnection(serverSockAddr) == &clientConn); |
| VerifyOrQuit(instance.Get<Dso>().FindServerConnection(serverSockAddr) == nullptr); |
| VerifyOrQuit(instance.Get<Dso>().FindClientConnection(clientSockAddr) == nullptr); |
| VerifyOrQuit(instance.Get<Dso>().FindServerConnection(clientSockAddr) == &serverConn); |
| |
| VerifyOrQuit(clientConn.DidGetConnectedSignal()); |
| VerifyOrQuit(!clientConn.DidGetSessionEstablishedSignal()); |
| VerifyOrQuit(!clientConn.DidGetDisconnectSignal()); |
| |
| VerifyOrQuit(serverConn.DidGetConnectedSignal()); |
| VerifyOrQuit(!serverConn.DidGetSessionEstablishedSignal()); |
| VerifyOrQuit(!serverConn.DidGetDisconnectSignal()); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Send keep alive message to establish connection"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| VerifyOrQuit(!clientConn.DidGetConnectedSignal()); |
| VerifyOrQuit(clientConn.DidGetSessionEstablishedSignal()); |
| VerifyOrQuit(!clientConn.DidGetDisconnectSignal()); |
| |
| VerifyOrQuit(!serverConn.DidGetConnectedSignal()); |
| VerifyOrQuit(serverConn.DidGetSessionEstablishedSignal()); |
| VerifyOrQuit(!serverConn.DidGetDisconnectSignal()); |
| |
| VerifyOrQuit(clientConn.GetKeepAliveInterval() == Dso::kDefaultTimeout); |
| VerifyOrQuit(clientConn.GetInactivityTimeout() == Dso::kDefaultTimeout); |
| VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kDefaultTimeout); |
| VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kDefaultTimeout); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Close connection"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| clientConn.Disconnect(Connection::kGracefullyClose, Connection::kReasonInactivityTimeout); |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout); |
| |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed); |
| |
| VerifyOrQuit(!clientConn.DidGetConnectedSignal()); |
| VerifyOrQuit(!clientConn.DidGetSessionEstablishedSignal()); |
| VerifyOrQuit(!clientConn.DidGetDisconnectSignal()); |
| |
| VerifyOrQuit(!serverConn.DidGetConnectedSignal()); |
| VerifyOrQuit(!serverConn.DidGetSessionEstablishedSignal()); |
| VerifyOrQuit(serverConn.DidGetDisconnectSignal()); |
| |
| VerifyOrQuit(instance.Get<Dso>().FindClientConnection(clientSockAddr) == nullptr); |
| VerifyOrQuit(instance.Get<Dso>().FindServerConnection(clientSockAddr) == nullptr); |
| VerifyOrQuit(instance.Get<Dso>().FindClientConnection(serverSockAddr) == nullptr); |
| VerifyOrQuit(instance.Get<Dso>().FindServerConnection(serverSockAddr) == nullptr); |
| |
| Log("-------------------------------------------------------------------------------------------"); |
| Log("Connection timeout when server is not listening"); |
| |
| instance.Get<Dso>().StopListening(); |
| |
| clientConn.ClearTestFlags(); |
| |
| clientConn.Connect(); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateConnecting); |
| VerifyOrQuit(instance.Get<Dso>().FindClientConnection(serverSockAddr) == &clientConn); |
| VerifyOrQuit(instance.Get<Dso>().FindServerConnection(serverSockAddr) == nullptr); |
| |
| AdvanceTime(Dso::kConnectingTimeout); |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonFailedToConnect); |
| VerifyOrQuit(instance.Get<Dso>().FindClientConnection(serverSockAddr) == nullptr); |
| VerifyOrQuit(instance.Get<Dso>().FindServerConnection(serverSockAddr) == nullptr); |
| |
| VerifyOrQuit(!clientConn.DidGetConnectedSignal()); |
| VerifyOrQuit(!clientConn.DidGetSessionEstablishedSignal()); |
| VerifyOrQuit(clientConn.DidGetDisconnectSignal()); |
| |
| Log("-------------------------------------------------------------------------------------------"); |
| Log("Keep Alive Timeout behavior"); |
| |
| // Keep Alive timeout smaller than min value should be rejected. |
| VerifyOrQuit(clientConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kMinKeepAliveInterval - 1) == kErrorInvalidArgs); |
| |
| instance.Get<Dso>().StartListening(AcceptConnection); |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kMinKeepAliveInterval)); |
| |
| VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval); |
| VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kInfiniteTimeout); |
| |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval); |
| VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kInfiniteTimeout); |
| VerifyOrQuit(clientConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval); |
| VerifyOrQuit(clientConn.GetInactivityTimeout() == Dso::kInfiniteTimeout); |
| |
| VerifyKeepAliveExchange(clientConn, serverConn, Dso::kMinKeepAliveInterval); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Change Keep Alive interval on server"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kDefaultTimeout)); |
| |
| VerifyOrQuit(serverConn.DidSendMessage()); |
| VerifyOrQuit(clientConn.DidReceiveMessage()); |
| VerifyOrQuit(!clientConn.DidSendMessage()); |
| |
| VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kDefaultTimeout); |
| VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kInfiniteTimeout); |
| VerifyOrQuit(clientConn.GetKeepAliveInterval() == Dso::kDefaultTimeout); |
| VerifyOrQuit(clientConn.GetInactivityTimeout() == Dso::kInfiniteTimeout); |
| |
| VerifyKeepAliveExchange(clientConn, serverConn, Dso::kDefaultTimeout); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Keep Alive timer clear on message send or receive"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| AdvanceTime(Dso::kDefaultTimeout / 2); |
| |
| clientConn.SendTestUnidirectionalMessage(); |
| VerifyOrQuit(clientConn.DidSendMessage()); |
| VerifyOrQuit(serverConn.DidReceiveMessage()); |
| VerifyOrQuit(!serverConn.DidSendMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| Log("Sent unidirectional message (client->server) at half the keep alive interval"); |
| VerifyKeepAliveExchange(clientConn, serverConn, Dso::kDefaultTimeout, 1); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| AdvanceTime(Dso::kDefaultTimeout / 2); |
| |
| serverConn.SendTestUnidirectionalMessage(); |
| VerifyOrQuit(serverConn.DidSendMessage()); |
| VerifyOrQuit(clientConn.DidReceiveMessage()); |
| VerifyOrQuit(!clientConn.DidSendMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| Log("Sent unidirectional message (server->client) at half the keep alive interval"); |
| VerifyKeepAliveExchange(clientConn, serverConn, Dso::kDefaultTimeout, 1); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Keep Alive timeout on server"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| Log("Drop all sent message (drop Keep Alive msg from client->server)"); |
| sTestDsoForwardMessageToPeer = false; |
| |
| AdvanceTime(Dso::kDefaultTimeout); |
| VerifyOrQuit(clientConn.DidSendMessage()); |
| VerifyOrQuit(!serverConn.DidReceiveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| Log("Sever waits for twice the interval before Keep Alive timeout"); |
| AdvanceTime(Dso::kDefaultTimeout); |
| |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonKeepAliveTimeout); |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonPeerAborted); |
| Log("Server aborted connection on Keep Alive timeout"); |
| sTestDsoForwardMessageToPeer = true; |
| |
| Log("-------------------------------------------------------------------------------------------"); |
| Log("Inactivity Timeout behavior"); |
| |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kMinKeepAliveInterval)); |
| |
| VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval); |
| VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kDefaultTimeout); |
| |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| VerifyOrQuit(serverConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval); |
| VerifyOrQuit(serverConn.GetInactivityTimeout() == Dso::kDefaultTimeout); |
| VerifyOrQuit(clientConn.GetKeepAliveInterval() == Dso::kMinKeepAliveInterval); |
| VerifyOrQuit(clientConn.GetInactivityTimeout() == Dso::kDefaultTimeout); |
| |
| Log("Sending a unidirectional message should clear inactivity timer"); |
| AdvanceTime(Dso::kDefaultTimeout / 2); |
| clientConn.SendTestUnidirectionalMessage(); |
| |
| AdvanceTime(Dso::kDefaultTimeout - 1); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| Log("Client keeps the connection up to the inactivity timeout"); |
| |
| AdvanceTime(1); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed); |
| Log("Client closes the connection gracefully on inactivity timeout"); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Increasing inactivity timeout in middle"); |
| |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| AdvanceTime(TimeMilli::SecToMsec(10)); |
| Log("After 10 sec elapses, change the inactivity timeout from 15 to 20 sec"); |
| SuccessOrQuit(serverConn.SetTimeouts(TimeMilli::SecToMsec(20), Dso::kMinKeepAliveInterval)); |
| |
| AdvanceTime(TimeMilli::SecToMsec(10) - 1); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| Log("Client keeps the connection up to new 20 sec inactivity timeout"); |
| |
| AdvanceTime(1); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed); |
| Log("Client closes the connection gracefully on inactivity timeout of 20 sec"); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Decreasing inactivity timeout in middle"); |
| |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| AdvanceTime(TimeMilli::SecToMsec(10)); |
| Log("After 10 sec elapses, change the inactivity timeout from 15 to 10 sec"); |
| SuccessOrQuit(serverConn.SetTimeouts(TimeMilli::SecToMsec(10), Dso::kMinKeepAliveInterval)); |
| |
| AdvanceTime(0); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed); |
| Log("Client closes the connection gracefully on new shorter inactivity timeout of 10 sec"); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Changing inactivity timeout from infinite to finite"); |
| |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kInfiniteTimeout)); |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| AdvanceTime(TimeMilli::SecToMsec(6)); |
| Log("After 6 sec, change the inactivity to infinite"); |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kInfiniteTimeout)); |
| |
| AdvanceTime(TimeMilli::SecToMsec(4)); |
| Log("After 4 sec, change the inactivity timeout from infinite to 20 sec"); |
| SuccessOrQuit(serverConn.SetTimeouts(TimeMilli::SecToMsec(20), Dso::kInfiniteTimeout)); |
| |
| AdvanceTime(TimeMilli::SecToMsec(10) - 1); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| AdvanceTime(1); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed); |
| Log("Client closes the connection gracefully after 20 sec since last activity"); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Tracking activity while inactivity timeout is infinite"); |
| |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kInfiniteTimeout)); |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| AdvanceTime(TimeMilli::SecToMsec(7)); |
| Log("After 7 sec, send a test message, this clears inactivity timer"); |
| serverConn.SendTestUnidirectionalMessage(); |
| |
| AdvanceTime(TimeMilli::SecToMsec(10)); |
| Log("After 10 sec, change the inactivity timeout from infinite to 15 sec"); |
| SuccessOrQuit(serverConn.SetTimeouts(TimeMilli::SecToMsec(15), Dso::kInfiniteTimeout)); |
| |
| AdvanceTime(TimeMilli::SecToMsec(5) - 1); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| AdvanceTime(1); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed); |
| Log("Client closes the connection gracefully after 15 sec since last activity"); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Inactivity timeout on server"); |
| |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kInfiniteTimeout)); |
| |
| Log("Wait for inactivity timeout and ensure client disconnect"); |
| Log("Configure test for client not to signal its disconnect to server"); |
| sTestDsoSignalDisconnectToPeer = false; |
| |
| AdvanceTime(Dso::kDefaultTimeout); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| sTestDsoSignalDisconnectToPeer = true; |
| |
| Log("Server should disconnect after twice the inactivity timeout"); |
| AdvanceTime(Dso::kDefaultTimeout - 1); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| AdvanceTime(1); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Server reducing inactivity timeout to expired (on server)"); |
| |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kInfiniteTimeout)); |
| |
| AdvanceTime(TimeMilli::SecToMsec(10)); |
| Log("After 11 sec elapses, change the inactivity timeout from 15 to 2 sec"); |
| SuccessOrQuit(serverConn.SetTimeouts(TimeMilli::SecToMsec(2), Dso::kMinKeepAliveInterval)); |
| |
| sTestDsoSignalDisconnectToPeer = false; |
| AdvanceTime(0); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout); |
| sTestDsoSignalDisconnectToPeer = true; |
| Log("Client closes the connection gracefully on expired timeout"); |
| Log("Configure test for client not to signal its disconnect to server"); |
| |
| AdvanceTime(Dso::kMinServerInactivityWaitTime - 1); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| AdvanceTime(1); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout); |
| Log("Server wait for kMinServerInactivityWaitTime (5 sec) before closing on expired timeout"); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Long-lived operation"); |
| |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kInfiniteTimeout)); |
| |
| clientConn.SetLongLivedOperation(true); |
| serverConn.SetLongLivedOperation(true); |
| |
| AdvanceTime(2 * Dso::kDefaultTimeout); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| clientConn.SetLongLivedOperation(false); |
| AdvanceTime(0); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| |
| Log("-------------------------------------------------------------------------------------------"); |
| Log("Request, response, and unidirectional message exchange"); |
| |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kDefaultTimeout, Dso::kDefaultTimeout)); |
| clientConn.Connect(); |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateConnectedButSessionless); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateConnectedButSessionless); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Establish connection using test message request/response"); |
| clientConn.SendTestRequestMessage(); |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.DidProcessRequest()); |
| VerifyOrQuit(clientConn.DidProcessResponse()); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Send unidirectional test message"); |
| |
| serverConn.ClearTestFlags(); |
| clientConn.SendTestUnidirectionalMessage(0x10); |
| VerifyOrQuit(serverConn.DidProcessUnidirectional()); |
| VerifyOrQuit(serverConn.GetLastRxTestTlvValue() == 0x10); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.SendTestUnidirectionalMessage(0x20); |
| VerifyOrQuit(clientConn.DidProcessUnidirectional()); |
| VerifyOrQuit(clientConn.GetLastRxTestTlvValue() == 0x20); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Exchange request and response"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| serverConn.SendTestRequestMessage(0x30); |
| VerifyOrQuit(clientConn.DidProcessRequest()); |
| VerifyOrQuit(!clientConn.DidProcessResponse()); |
| VerifyOrQuit(!serverConn.DidProcessRequest()); |
| VerifyOrQuit(serverConn.DidProcessResponse()); |
| VerifyOrQuit(serverConn.GetLastRxTestTlvValue() == 0x30); |
| VerifyOrQuit(clientConn.GetLastRxTestTlvValue() == 0x30); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| clientConn.SendTestRequestMessage(0x40); |
| VerifyOrQuit(!clientConn.DidProcessRequest()); |
| VerifyOrQuit(clientConn.DidProcessResponse()); |
| VerifyOrQuit(serverConn.DidProcessRequest()); |
| VerifyOrQuit(!serverConn.DidProcessResponse()); |
| VerifyOrQuit(serverConn.GetLastRxTestTlvValue() == 0x40); |
| VerifyOrQuit(clientConn.GetLastRxTestTlvValue() == 0x40); |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Send unknown TLV request"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| message = clientConn.NewMessage(); |
| VerifyOrQuit(message != nullptr); |
| tlv.Init(kUnknownTlvType, 0); |
| SuccessOrQuit(message->Append(tlv)); |
| SuccessOrQuit(clientConn.SendRequestMessage(*message, messageId)); |
| |
| VerifyOrQuit(!clientConn.DidProcessRequest()); |
| VerifyOrQuit(clientConn.DidProcessResponse()); |
| VerifyOrQuit(serverConn.DidProcessRequest()); |
| VerifyOrQuit(!serverConn.DidProcessResponse()); |
| VerifyOrQuit(clientConn.GetLastRxResponseCode() == Dns::Header::kDsoTypeNotImplemented); |
| Log("Received a response with DSO Type Unknown error code"); |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Send unknown TLV unidirectional"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| message = clientConn.NewMessage(); |
| VerifyOrQuit(message != nullptr); |
| tlv.Init(kUnknownTlvType, 0); |
| SuccessOrQuit(message->Append(tlv)); |
| SuccessOrQuit(clientConn.SendUnidirectionalMessage(*message)); |
| VerifyOrQuit(serverConn.DidProcessUnidirectional()); |
| Log("Unknown TLV unidirectional is correctly ignored"); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Send malformed/invalid request"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| message = clientConn.NewMessage(); |
| VerifyOrQuit(message != nullptr); |
| tlv.Init(Dso::Tlv::kEncryptionPaddingType, 0); |
| SuccessOrQuit(message->Append(tlv)); |
| |
| SuccessOrQuit(serverConn.SendRequestMessage(*message, messageId)); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonPeerMisbehavior); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerAborted); |
| VerifyOrQuit(clientConn.DidGetDisconnectSignal()); |
| VerifyOrQuit(serverConn.DidGetDisconnectSignal()); |
| Log("Client aborted on invalid request message"); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Response timeout during session establishment"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kResponseTimeout, Dso::kInfiniteTimeout)); |
| clientConn.Connect(); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateConnectedButSessionless); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateConnectedButSessionless); |
| |
| sTestDsoForwardMessageToPeer = false; |
| clientConn.SendTestRequestMessage(); |
| sTestDsoForwardMessageToPeer = true; |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateEstablishingSession); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateConnectedButSessionless); |
| |
| sTestDsoSignalDisconnectToPeer = false; |
| AdvanceTime(Dso::kResponseTimeout); |
| sTestDsoSignalDisconnectToPeer = true; |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonResponseTimeout); |
| VerifyOrQuit(clientConn.DidGetDisconnectSignal()); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateConnectedButSessionless); |
| Log("Client disconnected after response timeout"); |
| |
| AdvanceTime(Dso::kResponseTimeout); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonInactivityTimeout); |
| VerifyOrQuit(serverConn.DidGetDisconnectSignal()); |
| Log("Server disconnected after twice the inactivity timeout"); |
| |
| Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); |
| Log("Response timeout after session establishment"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kInfiniteTimeout)); |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| sTestDsoForwardMessageToPeer = false; |
| serverConn.SendTestRequestMessage(); |
| sTestDsoForwardMessageToPeer = true; |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| AdvanceTime(Dso::kResponseTimeout - 1); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| AdvanceTime(1); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonResponseTimeout); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonPeerAborted); |
| VerifyOrQuit(serverConn.DidGetDisconnectSignal()); |
| VerifyOrQuit(clientConn.DidGetDisconnectSignal()); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kInfiniteTimeout)); |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| sTestDsoForwardMessageToPeer = false; |
| serverConn.SendTestRequestMessage(0, kLongResponseTimeout); |
| sTestDsoForwardMessageToPeer = true; |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| AdvanceTime(kLongResponseTimeout - 1); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| AdvanceTime(1); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonResponseTimeout); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonPeerAborted); |
| VerifyOrQuit(serverConn.DidGetDisconnectSignal()); |
| VerifyOrQuit(clientConn.DidGetDisconnectSignal()); |
| |
| Log("-------------------------------------------------------------------------------------------"); |
| Log("Retry Delay message"); |
| |
| clientConn.ClearTestFlags(); |
| serverConn.ClearTestFlags(); |
| |
| SuccessOrQuit(serverConn.SetTimeouts(Dso::kInfiniteTimeout, Dso::kInfiniteTimeout)); |
| clientConn.Connect(); |
| SuccessOrQuit(clientConn.SendKeepAliveMessage()); |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateSessionEstablished); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateSessionEstablished); |
| |
| SuccessOrQuit(serverConn.SendRetryDelayMessage(kRetryDelayInterval, Dns::Header::kResponseServerFailure)); |
| |
| VerifyOrQuit(clientConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(serverConn.GetState() == Connection::kStateDisconnected); |
| VerifyOrQuit(clientConn.DidGetDisconnectSignal()); |
| VerifyOrQuit(serverConn.DidGetDisconnectSignal()); |
| VerifyOrQuit(clientConn.GetDisconnectReason() == Connection::kReasonServerRetryDelayRequest); |
| VerifyOrQuit(serverConn.GetDisconnectReason() == Connection::kReasonPeerClosed); |
| |
| VerifyOrQuit(clientConn.GetRetryDelay() == kRetryDelayInterval); |
| VerifyOrQuit(clientConn.GetRetryDelayErrorCode() == Dns::Header::kResponseServerFailure); |
| |
| Log("End of test"); |
| |
| testFreeInstance(&instance); |
| } |
| |
| } // namespace Dns |
| |
| #endif // OPENTHREAD_CONFIG_DNS_DSO_ENABLE |
| |
| } // namespace ot |
| |
| int main(void) |
| { |
| #if OPENTHREAD_CONFIG_DNS_DSO_ENABLE |
| ot::Dns::TestDso(); |
| printf("All tests passed\n"); |
| #else |
| printf("DSO feature is not enabled\n"); |
| #endif |
| |
| return 0; |
| } |