Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2023-2025 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file defines the CHIP Active Connection object that maintains TCP connections.
22 : */
23 :
24 : #pragma once
25 :
26 : #include <functional>
27 : #include <inet/IPAddress.h>
28 : #include <inet/InetInterface.h>
29 : #include <inet/TCPEndPoint.h>
30 : #include <lib/core/CHIPCore.h>
31 : #include <lib/core/ReferenceCounted.h>
32 : #include <lib/support/ReferenceCountedPtr.h>
33 : #include <transport/raw/PeerAddress.h>
34 : #include <transport/raw/TCPConfig.h>
35 :
36 : namespace chip {
37 : namespace Transport {
38 :
39 : // Forward declaration of friend class for test access.
40 : template <size_t kActiveConnectionsSize, size_t kPendingPacketSize>
41 : class TCPBaseTestAccess;
42 :
43 : /**
44 : * The State of the TCP connection
45 : */
46 : enum class TCPState : uint8_t
47 : {
48 : kNotReady = 0, /**< State before initialization. */
49 : kInitialized = 1, /**< State after class is listening and ready. */
50 : kConnecting = 3, /**< Connection with peer has been initiated. */
51 : kConnected = 4, /**< Connected with peer and ready for Send/Receive. */
52 : kClosed = 5, /**< Connection is closed. */
53 : };
54 :
55 : struct AppTCPConnectionCallbackCtxt;
56 :
57 : // Templatized to force inlining
58 : template <typename State>
59 : class ActiveTCPConnectionStateDeleter
60 : {
61 : public:
62 29 : inline static void Release(State * entry) { entry->mReleaseConnection(*entry); }
63 : };
64 :
65 : /**
66 : * State for each active TCP connection
67 : */
68 : class ActiveTCPConnectionHandle;
69 : struct ActiveTCPConnectionState
70 : : public ReferenceCountedProtected<ActiveTCPConnectionState, ActiveTCPConnectionStateDeleter<ActiveTCPConnectionState>>
71 : {
72 : using ReleaseFnType = std::function<void(ActiveTCPConnectionState & connection)>;
73 :
74 350 : bool InUse() const { return !mEndPoint.IsNull(); }
75 :
76 230 : bool IsConnected() const { return (!mEndPoint.IsNull() && mConnectionState == TCPState::kConnected); }
77 :
78 0 : bool IsConnecting() const { return (!mEndPoint.IsNull() && mConnectionState == TCPState::kConnecting); }
79 :
80 : inline bool operator==(const ActiveTCPConnectionHandle & other) const;
81 : inline bool operator!=(const ActiveTCPConnectionHandle & other) const;
82 :
83 : // Peer Node Address
84 : PeerAddress mPeerAddr;
85 :
86 : // Buffers received but not yet consumed.
87 : System::PacketBufferHandle mReceived;
88 :
89 : // Current state of the connection
90 : TCPState mConnectionState;
91 :
92 : // A pointer to an application-specific state object. It should
93 : // represent an object that is at a layer above the SessionManager. The
94 : // SessionManager would accept this object at the time of connecting to
95 : // the peer, and percolate it down to the TransportManager that then,
96 : // should store this state in the corresponding connection object that
97 : // is created.
98 : // At various connection events, this state is passed back to the
99 : // corresponding application.
100 : AppTCPConnectionCallbackCtxt * mAppState = nullptr;
101 :
102 : // KeepAlive interval in seconds
103 : uint16_t mTCPKeepAliveIntervalSecs = CHIP_CONFIG_TCP_KEEPALIVE_INTERVAL_SECS;
104 : uint16_t mTCPMaxNumKeepAliveProbes = CHIP_CONFIG_MAX_TCP_KEEPALIVE_PROBES;
105 :
106 : // This is bad and should not normally be done; we are explicitly closing the TCP connection
107 : // instead of gracefully releasing our reference, which will theoretically cause anyone
108 : // holding a reference (who should have a listener for connection closing) to release their reference
109 : void ForceDisconnect() { mReleaseConnection(*this); }
110 :
111 : private:
112 : template <size_t kActiveConnectionsSize, size_t kPendingPacketSize>
113 : friend class TCP;
114 : friend class TCPBase;
115 : friend class ActiveTCPConnectionStateDeleter<ActiveTCPConnectionState>;
116 : friend class ActiveTCPConnectionHandle;
117 : // Allow tests to access private members.
118 : template <size_t kActiveConnectionsSize, size_t kPendingPacketSize>
119 : friend class TCPBaseTestAccess;
120 :
121 : // Associated endpoint.
122 : Inet::TCPEndPointHandle mEndPoint;
123 : ReleaseFnType mReleaseConnection;
124 :
125 242 : void Init(Inet::TCPEndPointHandle endPoint, const PeerAddress & peerAddr, ReleaseFnType releaseConnection)
126 : {
127 242 : mEndPoint = endPoint;
128 242 : mPeerAddr = peerAddr;
129 242 : mReceived = nullptr;
130 242 : mAppState = nullptr;
131 242 : mReleaseConnection = releaseConnection;
132 242 : }
133 :
134 30 : void Free()
135 : {
136 30 : mPeerAddr = PeerAddress::Uninitialized();
137 30 : mEndPoint = nullptr;
138 30 : mReceived = nullptr;
139 30 : mAppState = nullptr;
140 30 : mReleaseConnection = [](auto &) {};
141 30 : }
142 : };
143 :
144 : /**
145 : * A holder for ActiveTCPConnectionState which properly ref-counts on ctor/copy/dtor.
146 : */
147 : class ActiveTCPConnectionHandle : public ReferenceCountedPtr<ActiveTCPConnectionState>
148 : {
149 : friend class TCPBase;
150 : friend struct ActiveTCPConnectionState;
151 :
152 : public:
153 : using ReferenceCountedPtr<ActiveTCPConnectionState>::ReferenceCountedPtr;
154 :
155 : // For printing
156 0 : inline operator const void *() const { return mRefCounted; }
157 : };
158 :
159 0 : inline bool ActiveTCPConnectionState::operator==(const ActiveTCPConnectionHandle & other) const
160 : {
161 0 : return this == other.mRefCounted;
162 : }
163 : inline bool ActiveTCPConnectionState::operator!=(const ActiveTCPConnectionHandle & other) const
164 : {
165 : return this != other.mRefCounted;
166 : }
167 :
168 : // Functors for callbacks into higher layers
169 : using OnTCPConnectionReceivedCallback = void (*)(ActiveTCPConnectionState & conn);
170 :
171 : using OnTCPConnectionCompleteCallback = void (*)(ActiveTCPConnectionHandle & conn, CHIP_ERROR conErr);
172 :
173 : using OnTCPConnectionClosedCallback = void (*)(ActiveTCPConnectionState & conn, CHIP_ERROR conErr);
174 :
175 : /*
176 : * Application callback state that is passed down at connection establishment
177 : * stage.
178 : * */
179 : struct AppTCPConnectionCallbackCtxt
180 : {
181 : void * appContext = nullptr; // A pointer to an application context object.
182 : OnTCPConnectionReceivedCallback connReceivedCb = nullptr;
183 : OnTCPConnectionCompleteCallback connCompleteCb = nullptr;
184 : OnTCPConnectionClosedCallback connClosedCb = nullptr;
185 : };
186 :
187 : } // namespace Transport
188 : } // namespace chip
|