Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2023 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/AutoRelease.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 23 : inline static void Release(State * entry) { entry->mReleaseConnection(*entry); }
63 : };
64 :
65 : /**
66 : * State for each active TCP connection
67 : */
68 : class ActiveTCPConnectionHolder;
69 : struct ActiveTCPConnectionState
70 : : public ReferenceCounted<ActiveTCPConnectionState, ActiveTCPConnectionStateDeleter<ActiveTCPConnectionState>, 0, uint16_t>
71 : {
72 : using ReleaseFnType = std::function<void(ActiveTCPConnectionState & connection)>;
73 :
74 215 : bool InUse() const { return mEndPoint != nullptr; }
75 :
76 170 : bool IsConnected() const { return (mEndPoint != nullptr && mConnectionState == TCPState::kConnected); }
77 :
78 0 : bool IsConnecting() const { return (mEndPoint != nullptr && mConnectionState == TCPState::kConnecting); }
79 :
80 : inline bool operator==(const ActiveTCPConnectionHolder & other) const;
81 : inline bool operator!=(const ActiveTCPConnectionHolder & 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 : // Allow tests to access private members.
117 : template <size_t kActiveConnectionsSize, size_t kPendingPacketSize>
118 : friend class TCPBaseTestAccess;
119 :
120 : // Associated endpoint.
121 : Inet::TCPEndPoint * mEndPoint;
122 : ReleaseFnType mReleaseConnection;
123 :
124 132 : void Init(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddr, ReleaseFnType releaseConnection)
125 : {
126 132 : mEndPoint = endPoint;
127 132 : mPeerAddr = peerAddr;
128 132 : mReceived = nullptr;
129 132 : mAppState = nullptr;
130 132 : mReleaseConnection = releaseConnection;
131 132 : }
132 :
133 24 : void Free()
134 : {
135 24 : if (mEndPoint)
136 : {
137 24 : mEndPoint->Free();
138 : }
139 24 : mPeerAddr = PeerAddress::Uninitialized();
140 24 : mEndPoint = nullptr;
141 24 : mReceived = nullptr;
142 24 : mAppState = nullptr;
143 24 : mReleaseConnection = [](auto &) {};
144 24 : }
145 : };
146 :
147 : /**
148 : * A holder for ActiveTCPConnectionState which properly ref-counts on ctor/copy/dtor.
149 : */
150 : class ActiveTCPConnectionHolder : private AutoRelease<ActiveTCPConnectionState>
151 : {
152 : friend class TCPBase;
153 : friend struct ActiveTCPConnectionState;
154 :
155 : public:
156 : using AutoRelease<ActiveTCPConnectionState>::operator->;
157 : using AutoRelease<ActiveTCPConnectionState>::IsNull;
158 : using AutoRelease<ActiveTCPConnectionState>::Release;
159 :
160 135921 : ActiveTCPConnectionHolder() : AutoRelease<ActiveTCPConnectionState>(nullptr) {}
161 75 : ActiveTCPConnectionHolder(ActiveTCPConnectionState * releasable) :
162 75 : AutoRelease<ActiveTCPConnectionState>(releasable ? releasable->Retain() : nullptr)
163 75 : {}
164 :
165 0 : ActiveTCPConnectionHolder(const ActiveTCPConnectionHolder & src) : ActiveTCPConnectionHolder(src.mReleasable) {}
166 :
167 102 : inline AutoRelease & operator=(const ActiveTCPConnectionHolder & src)
168 : {
169 102 : if (mReleasable != src.mReleasable)
170 : {
171 92 : Set(src.IsNull() ? nullptr : src.mReleasable->Retain());
172 : }
173 102 : return *this;
174 : }
175 :
176 36 : inline bool operator==(const ActiveTCPConnectionHolder & other) const { return mReleasable == other.mReleasable; }
177 0 : inline bool operator!=(const ActiveTCPConnectionHolder & other) const { return mReleasable != other.mReleasable; }
178 0 : inline bool operator==(const ActiveTCPConnectionState & other) const { return mReleasable == &other; }
179 : inline bool operator!=(const ActiveTCPConnectionState & other) const { return mReleasable != &other; }
180 :
181 : // For printing
182 0 : inline operator const void *() const { return mReleasable; }
183 : };
184 :
185 0 : inline bool ActiveTCPConnectionState::operator==(const ActiveTCPConnectionHolder & other) const
186 : {
187 0 : return this == other.mReleasable;
188 : }
189 : inline bool ActiveTCPConnectionState::operator!=(const ActiveTCPConnectionHolder & other) const
190 : {
191 : return this != other.mReleasable;
192 : }
193 :
194 : // Functors for callbacks into higher layers
195 : using OnTCPConnectionReceivedCallback = void (*)(ActiveTCPConnectionState & conn);
196 :
197 : using OnTCPConnectionCompleteCallback = void (*)(ActiveTCPConnectionHolder & conn, CHIP_ERROR conErr);
198 :
199 : using OnTCPConnectionClosedCallback = void (*)(ActiveTCPConnectionState & conn, CHIP_ERROR conErr);
200 :
201 : /*
202 : * Application callback state that is passed down at connection establishment
203 : * stage.
204 : * */
205 : struct AppTCPConnectionCallbackCtxt
206 : {
207 : void * appContext = nullptr; // A pointer to an application context object.
208 : OnTCPConnectionReceivedCallback connReceivedCb = nullptr;
209 : OnTCPConnectionCompleteCallback connCompleteCb = nullptr;
210 : OnTCPConnectionClosedCallback connClosedCb = nullptr;
211 : };
212 :
213 : } // namespace Transport
214 : } // namespace chip
|