Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file defines the CHIP Connection object that maintains TCP connections.
22 : * It binds to any available local addr and port and begins listening.
23 : */
24 :
25 : #pragma once
26 :
27 : #include <algorithm>
28 : #include <new>
29 : #include <utility>
30 :
31 : #include <inet/IPAddress.h>
32 : #include <inet/InetInterface.h>
33 : #include <inet/TCPEndPoint.h>
34 : #include <lib/core/CHIPCore.h>
35 : #include <lib/support/CodeUtils.h>
36 : #include <lib/support/PoolWrapper.h>
37 : #include <transport/raw/ActiveTCPConnectionState.h>
38 : #include <transport/raw/Base.h>
39 : #include <transport/raw/TCPConfig.h>
40 :
41 : namespace chip {
42 : namespace Transport {
43 :
44 : // Forward declaration of friend class for test access.
45 : template <size_t kActiveConnectionsSize, size_t kPendingPacketSize>
46 : class TCPBaseTestAccess;
47 :
48 : /** Defines listening parameters for setting up a TCP transport */
49 : class TcpListenParameters
50 : {
51 : public:
52 1 : explicit TcpListenParameters(Inet::EndPointManager<Inet::TCPEndPoint> * endPointManager) : mEndPointManager(endPointManager) {}
53 : TcpListenParameters(const TcpListenParameters &) = default;
54 : TcpListenParameters(TcpListenParameters &&) = default;
55 :
56 13 : Inet::EndPointManager<Inet::TCPEndPoint> * GetEndPointManager() { return mEndPointManager; }
57 :
58 26 : Inet::IPAddressType GetAddressType() const { return mAddressType; }
59 1 : TcpListenParameters & SetAddressType(Inet::IPAddressType type)
60 : {
61 1 : mAddressType = type;
62 :
63 1 : return *this;
64 : }
65 :
66 13 : uint16_t GetListenPort() const { return mListenPort; }
67 1 : TcpListenParameters & SetListenPort(uint16_t port)
68 : {
69 1 : mListenPort = port;
70 :
71 1 : return *this;
72 : }
73 :
74 13 : Inet::InterfaceId GetInterfaceId() const { return mInterfaceId; }
75 : TcpListenParameters & SetInterfaceId(Inet::InterfaceId id)
76 : {
77 : mInterfaceId = id;
78 :
79 : return *this;
80 : }
81 :
82 : private:
83 : Inet::EndPointManager<Inet::TCPEndPoint> * mEndPointManager; ///< Associated endpoint factory
84 : Inet::IPAddressType mAddressType = Inet::IPAddressType::kIPv6; ///< type of listening socket
85 : uint16_t mListenPort = CHIP_PORT; ///< TCP listen port
86 : Inet::InterfaceId mInterfaceId = Inet::InterfaceId::Null(); ///< Interface to listen on
87 : };
88 :
89 : /**
90 : * Packets scheduled for sending once a connection has been established.
91 : */
92 : struct PendingPacket
93 : {
94 0 : PendingPacket(const PeerAddress & peerAddress, System::PacketBufferHandle && packetBuffer) :
95 0 : mPeerAddress(peerAddress), mPacketBuffer(std::move(packetBuffer))
96 0 : {}
97 :
98 : PeerAddress mPeerAddress; // where the packet is being sent to
99 : System::PacketBufferHandle mPacketBuffer; // what data needs to be sent
100 : };
101 :
102 : /** Implements a transport using TCP. */
103 : class DLL_EXPORT TCPBase : public Base
104 : {
105 :
106 : protected:
107 : enum class ShouldAbort : uint8_t
108 : {
109 : Yes,
110 : No
111 : };
112 :
113 : enum class SuppressCallback : uint8_t
114 : {
115 : Yes,
116 : No
117 : };
118 :
119 : public:
120 : using PendingPacketPoolType = PoolInterface<PendingPacket, const PeerAddress &, System::PacketBufferHandle &&>;
121 1 : TCPBase(ActiveTCPConnectionState * activeConnectionsBuffer, size_t bufferSize, PendingPacketPoolType & packetBuffers) :
122 1 : mActiveConnections(activeConnectionsBuffer), mActiveConnectionsSize(bufferSize), mPendingPackets(packetBuffers)
123 : {
124 : // activeConnectionsBuffer must be initialized by the caller.
125 1 : }
126 : ~TCPBase() override;
127 :
128 : /**
129 : * Initialize a TCP transport on a given port.
130 : *
131 : * @param params TCP configuration parameters for this transport
132 : *
133 : * @details
134 : * Generally send and receive ports should be the same and equal to CHIP_PORT.
135 : * The class allows separate definitions to allow local execution of several
136 : * Nodes.
137 : */
138 : CHIP_ERROR Init(TcpListenParameters & params);
139 :
140 : /**
141 : * Set the timeout (in milliseconds) for the node to wait for the TCP
142 : * connection attempt to complete.
143 : *
144 : */
145 : void SetConnectTimeout(const uint32_t connTimeoutMsecs) { mConnectTimeout = connTimeoutMsecs; }
146 :
147 : /**
148 : * Close the open endpoint without destroying the object
149 : */
150 : void Close() override;
151 :
152 : CHIP_ERROR SendMessage(const PeerAddress & address, System::PacketBufferHandle && msgBuf) override;
153 :
154 : /*
155 : * Connect to the given peerAddress over TCP.
156 : *
157 : * @param address The address of the peer.
158 : *
159 : * @param appState Context passed in by the application to be sent back
160 : * via the connection attempt complete callback when
161 : * connection attempt with peer completes.
162 : *
163 : * @param outPeerConnState Pointer to pointer to the active TCP connection state. This is
164 : * an output parameter that is allocated by the
165 : * transport layer and held by the caller object.
166 : * This allows the caller object to abort the
167 : * connection attempt if the caller object dies
168 : * before the attempt completes.
169 : *
170 : */
171 : CHIP_ERROR TCPConnect(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState,
172 : Transport::ActiveTCPConnectionState ** outPeerConnState) override;
173 :
174 : void TCPDisconnect(const PeerAddress & address) override;
175 :
176 : // Close an active connection (corresponding to the passed
177 : // ActiveTCPConnectionState object)
178 : // and release from the pool.
179 : void TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = false) override;
180 :
181 0 : bool CanSendToPeer(const PeerAddress & address) override
182 : {
183 0 : return (mState == TCPState::kInitialized) && (address.GetTransportType() == Type::kTcp) &&
184 0 : (address.GetIPAddress().Type() == mEndpointType);
185 : }
186 :
187 : const Optional<PeerAddress> GetConnectionPeerAddress(const Inet::TCPEndPoint * con)
188 : {
189 : ActiveTCPConnectionState * activeConState = FindActiveConnection(con);
190 :
191 : return activeConState != nullptr ? MakeOptional<PeerAddress>(activeConState->mPeerAddr) : Optional<PeerAddress>::Missing();
192 : }
193 :
194 : /**
195 : * Helper method to determine if IO processing is still required for a TCP transport
196 : * before everything is cleaned up (socket closing is async, so after calling 'Close' on
197 : * the transport, some time may be needed to actually be able to close.)
198 : */
199 : bool HasActiveConnections() const;
200 :
201 : /**
202 : * Close all active connections.
203 : */
204 : void CloseActiveConnections();
205 :
206 : private:
207 : // Allow tests to access private members.
208 : template <size_t kActiveConnectionsSize, size_t kPendingPacketSize>
209 : friend class TCPBaseTestAccess;
210 :
211 : /**
212 : * Allocate an unused connection from the pool
213 : *
214 : */
215 : ActiveTCPConnectionState * AllocateConnection();
216 : /**
217 : * Find an active connection to the given peer or return nullptr if
218 : * no active connection exists.
219 : */
220 : ActiveTCPConnectionState * FindActiveConnection(const PeerAddress & addr);
221 : ActiveTCPConnectionState * FindActiveConnection(const Inet::TCPEndPoint * endPoint);
222 :
223 : /**
224 : * Find an allocated connection that matches the corresponding TCPEndPoint.
225 : */
226 : ActiveTCPConnectionState * FindInUseConnection(const Inet::TCPEndPoint * endPoint);
227 :
228 : /**
229 : * Sends the specified message once a connection has been established.
230 : *
231 : * @param addr - what peer to connect to
232 : * @param msg - what buffer to send once a connection has been established.
233 : *
234 : * Ownership of msg is taken over and will be freed at some unspecified time
235 : * in the future (once connection succeeds/fails).
236 : */
237 : CHIP_ERROR SendAfterConnect(const PeerAddress & addr, System::PacketBufferHandle && msg);
238 :
239 : /**
240 : * Process a single received buffer from the specified peer address.
241 : *
242 : * @param endPoint the source end point from which the data comes from
243 : * @param peerAddress the peer the data is coming from
244 : * @param buffer the actual data
245 : *
246 : * Ownership of buffer is taken over and will be freed (or re-enqueued to the endPoint receive queue)
247 : * as needed during processing.
248 : */
249 : CHIP_ERROR ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddress,
250 : System::PacketBufferHandle && buffer);
251 :
252 : /**
253 : * Process a single message of the specified size from a buffer.
254 : *
255 : * @param[in] peerAddress The peer the data is coming from.
256 : * @param[in,out] state The connection state, which contains the message. On entry, the payload points to the message
257 : * body (after the length). On exit, it points after the message (or the queue is null, if there
258 : * is no other data).
259 : * @param[in] messageSize Size of the single message.
260 : */
261 : CHIP_ERROR ProcessSingleMessage(const PeerAddress & peerAddress, ActiveTCPConnectionState * state, size_t messageSize);
262 :
263 : /**
264 : * Initiate a connection to the given peer. On connection completion,
265 : * HandleTCPConnectComplete callback would be called.
266 : *
267 : */
268 : CHIP_ERROR StartConnect(const PeerAddress & addr, AppTCPConnectionCallbackCtxt * appState,
269 : Transport::ActiveTCPConnectionState ** outPeerConnState);
270 :
271 : /**
272 : * Gracefully Close or Abort a given connection.
273 : *
274 : */
275 : void CloseConnectionInternal(ActiveTCPConnectionState * connection, CHIP_ERROR err, SuppressCallback suppressCallback);
276 :
277 : // Close the listening socket endpoint
278 : void CloseListeningSocket();
279 :
280 : // Callback handler for TCPEndPoint. TCP message receive handler.
281 : // @see TCPEndpoint::OnDataReceivedFunct
282 : static CHIP_ERROR HandleTCPEndPointDataReceived(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle && buffer);
283 :
284 : // Callback handler for TCPEndPoint. Called when a connection has been completed.
285 : // @see TCPEndpoint::OnConnectCompleteFunct
286 : static void HandleTCPEndPointConnectComplete(Inet::TCPEndPoint * endPoint, CHIP_ERROR err);
287 :
288 : // Callback handler for TCPEndPoint. Called when a connection has been closed.
289 : // @see TCPEndpoint::OnConnectionClosedFunct
290 : static void HandleTCPEndPointConnectionClosed(Inet::TCPEndPoint * endPoint, CHIP_ERROR err);
291 :
292 : // Callback handler for TCPEndPoint. Called when a connection is received on the listening port.
293 : // @see TCPEndpoint::OnConnectionReceivedFunct
294 : static void HandleIncomingConnection(Inet::TCPEndPoint * listenEndPoint, Inet::TCPEndPoint * endPoint,
295 : const Inet::IPAddress & peerAddress, uint16_t peerPort);
296 :
297 : // Callback handler for handling accept error
298 : // @see TCPEndpoint::OnAcceptErrorFunct
299 : static void HandleAcceptError(Inet::TCPEndPoint * endPoint, CHIP_ERROR err);
300 :
301 : Inet::TCPEndPoint * mListenSocket = nullptr; ///< TCP socket used by the transport
302 : Inet::IPAddressType mEndpointType = Inet::IPAddressType::kUnknown; ///< Socket listening type
303 : TCPState mState = TCPState::kNotReady; ///< State of the TCP transport
304 :
305 : // The configured timeout for the connection attempt to the peer, before
306 : // giving up.
307 : uint32_t mConnectTimeout = CHIP_CONFIG_TCP_CONNECT_TIMEOUT_MSECS;
308 :
309 : // Number of active and 'pending connection' endpoints
310 : size_t mUsedEndPointCount = 0;
311 :
312 : // Currently active connections
313 : ActiveTCPConnectionState * mActiveConnections;
314 : const size_t mActiveConnectionsSize;
315 :
316 : // Data to be sent when connections succeed
317 : PendingPacketPoolType & mPendingPackets;
318 : };
319 :
320 : template <size_t kActiveConnectionsSize, size_t kPendingPacketSize>
321 : class TCP : public TCPBase
322 : {
323 : public:
324 5 : TCP() : TCPBase(mConnectionsBuffer, kActiveConnectionsSize, mPendingPackets)
325 : {
326 5 : for (size_t i = 0; i < kActiveConnectionsSize; ++i)
327 : {
328 4 : mConnectionsBuffer[i].Init(nullptr, PeerAddress::Uninitialized());
329 : }
330 1 : }
331 :
332 5 : ~TCP() override { mPendingPackets.ReleaseAll(); }
333 :
334 : private:
335 : ActiveTCPConnectionState mConnectionsBuffer[kActiveConnectionsSize];
336 : PoolImpl<PendingPacket, kPendingPacketSize, ObjectPoolMem::kInline, PendingPacketPoolType::Interface> mPendingPackets;
337 : };
338 :
339 : } // namespace Transport
340 : } // namespace chip
|