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 1 : TcpListenParameters(const TcpListenParameters &) = default;
54 : TcpListenParameters(TcpListenParameters &&) = default;
55 :
56 16 : Inet::EndPointManager<Inet::TCPEndPoint> * GetEndPointManager() { return mEndPointManager; }
57 :
58 31 : 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 30 : 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 15 : Inet::InterfaceId GetInterfaceId() const { return mInterfaceId; }
75 : TcpListenParameters & SetInterfaceId(Inet::InterfaceId id)
76 : {
77 : mInterfaceId = id;
78 :
79 : return *this;
80 : }
81 :
82 2 : bool IsServerListenEnabled() const { return mServerListenEnabled; }
83 0 : TcpListenParameters & SetServerListenEnabled(bool listenEnable)
84 : {
85 0 : mServerListenEnabled = listenEnable;
86 :
87 0 : return *this;
88 : }
89 :
90 : private:
91 : Inet::EndPointManager<Inet::TCPEndPoint> * mEndPointManager; ///< Associated endpoint factory
92 : Inet::IPAddressType mAddressType = Inet::IPAddressType::kIPv6; ///< type of listening socket
93 : uint16_t mListenPort = CHIP_PORT; ///< TCP listen port
94 : Inet::InterfaceId mInterfaceId = Inet::InterfaceId::Null(); ///< Interface to listen on
95 : bool mServerListenEnabled = true; ///< TCP Server mode enabled
96 : };
97 :
98 : /**
99 : * Packets scheduled for sending once a connection has been established.
100 : */
101 : struct PendingPacket
102 : {
103 0 : PendingPacket(const PeerAddress & peerAddress, System::PacketBufferHandle && packetBuffer) :
104 0 : mPeerAddress(peerAddress), mPacketBuffer(std::move(packetBuffer))
105 0 : {}
106 :
107 : PeerAddress mPeerAddress; // where the packet is being sent to
108 : System::PacketBufferHandle mPacketBuffer; // what data needs to be sent
109 : };
110 :
111 : /** Implements a transport using TCP. */
112 : class DLL_EXPORT TCPBase : public Base
113 : {
114 :
115 : protected:
116 : enum class ShouldAbort : uint8_t
117 : {
118 : Yes,
119 : No
120 : };
121 :
122 : enum class SuppressCallback : uint8_t
123 : {
124 : Yes,
125 : No
126 : };
127 :
128 : public:
129 : using PendingPacketPoolType = PoolInterface<PendingPacket, const PeerAddress &, System::PacketBufferHandle &&>;
130 1 : TCPBase(ActiveTCPConnectionState * activeConnectionsBuffer, size_t bufferSize, PendingPacketPoolType & packetBuffers) :
131 1 : mActiveConnections(activeConnectionsBuffer), mActiveConnectionsSize(bufferSize), mPendingPackets(packetBuffers)
132 : {
133 : // activeConnectionsBuffer must be initialized by the caller.
134 1 : }
135 : ~TCPBase() override;
136 :
137 : /**
138 : * Initialize a TCP transport on a given port.
139 : *
140 : * @param params TCP configuration parameters for this transport
141 : *
142 : * @details
143 : * Generally send and receive ports should be the same and equal to CHIP_PORT.
144 : * The class allows separate definitions to allow local execution of several
145 : * Nodes.
146 : */
147 : CHIP_ERROR Init(TcpListenParameters & params);
148 :
149 : /**
150 : * Set the timeout (in milliseconds) for the node to wait for the TCP
151 : * connection attempt to complete.
152 : *
153 : */
154 : void SetConnectTimeout(const uint32_t connTimeoutMsecs) { mConnectTimeout = connTimeoutMsecs; }
155 :
156 : /**
157 : * Close the open endpoint without destroying the object
158 : */
159 : void Close() override;
160 :
161 : CHIP_ERROR SendMessage(const PeerAddress & address, System::PacketBufferHandle && msgBuf) override;
162 :
163 : /*
164 : * Connect to the given peerAddress over TCP.
165 : *
166 : * @param address The address of the peer.
167 : *
168 : * @param appState Context passed in by the application to be sent back
169 : * via the connection attempt complete callback when
170 : * connection attempt with peer completes.
171 : *
172 : * @param outPeerConnState Pointer to pointer to the active TCP connection state. This is
173 : * an output parameter that is allocated by the
174 : * transport layer and held by the caller object.
175 : * This allows the caller object to abort the
176 : * connection attempt if the caller object dies
177 : * before the attempt completes.
178 : *
179 : */
180 : CHIP_ERROR TCPConnect(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState,
181 : Transport::ActiveTCPConnectionState ** outPeerConnState) override;
182 :
183 : void TCPDisconnect(const PeerAddress & address) override;
184 :
185 : // Close an active connection (corresponding to the passed
186 : // ActiveTCPConnectionState object)
187 : // and release from the pool.
188 : void TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = false) override;
189 :
190 0 : bool CanSendToPeer(const PeerAddress & address) override
191 : {
192 0 : return (mState == TCPState::kInitialized) && (address.GetTransportType() == Type::kTcp) &&
193 0 : (address.GetIPAddress().Type() == mEndpointType);
194 : }
195 :
196 : const Optional<PeerAddress> GetConnectionPeerAddress(const Inet::TCPEndPoint * con)
197 : {
198 : ActiveTCPConnectionState * activeConState = FindActiveConnection(con);
199 :
200 : return activeConState != nullptr ? MakeOptional<PeerAddress>(activeConState->mPeerAddr) : Optional<PeerAddress>::Missing();
201 : }
202 :
203 : /**
204 : * Helper method to determine if IO processing is still required for a TCP transport
205 : * before everything is cleaned up (socket closing is async, so after calling 'Close' on
206 : * the transport, some time may be needed to actually be able to close.)
207 : */
208 : bool HasActiveConnections() const;
209 :
210 : /**
211 : * Close all active connections.
212 : */
213 : void CloseActiveConnections();
214 :
215 : private:
216 : // Allow tests to access private members.
217 : template <size_t kActiveConnectionsSize, size_t kPendingPacketSize>
218 : friend class TCPBaseTestAccess;
219 :
220 : /**
221 : * Allocate an unused connection from the pool
222 : *
223 : */
224 : ActiveTCPConnectionState * AllocateConnection();
225 : /**
226 : * Find an active connection to the given peer or return nullptr if
227 : * no active connection exists.
228 : */
229 : ActiveTCPConnectionState * FindActiveConnection(const PeerAddress & addr);
230 : ActiveTCPConnectionState * FindActiveConnection(const Inet::TCPEndPoint * endPoint);
231 :
232 : /**
233 : * Find an allocated connection that matches the corresponding TCPEndPoint.
234 : */
235 : ActiveTCPConnectionState * FindInUseConnection(const Inet::TCPEndPoint * endPoint);
236 :
237 : /**
238 : * Sends the specified message once a connection has been established.
239 : *
240 : * @param addr - what peer to connect to
241 : * @param msg - what buffer to send once a connection has been established.
242 : *
243 : * Ownership of msg is taken over and will be freed at some unspecified time
244 : * in the future (once connection succeeds/fails).
245 : */
246 : CHIP_ERROR SendAfterConnect(const PeerAddress & addr, System::PacketBufferHandle && msg);
247 :
248 : /**
249 : * Process a single received buffer from the specified peer address.
250 : *
251 : * @param endPoint the source end point from which the data comes from
252 : * @param peerAddress the peer the data is coming from
253 : * @param buffer the actual data
254 : *
255 : * Ownership of buffer is taken over and will be freed (or re-enqueued to the endPoint receive queue)
256 : * as needed during processing.
257 : */
258 : CHIP_ERROR ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddress,
259 : System::PacketBufferHandle && buffer);
260 :
261 : /**
262 : * Process a single message of the specified size from a buffer.
263 : *
264 : * @param[in] peerAddress The peer the data is coming from.
265 : * @param[in,out] state The connection state, which contains the message. On entry, the payload points to the message
266 : * body (after the length). On exit, it points after the message (or the queue is null, if there
267 : * is no other data).
268 : * @param[in] messageSize Size of the single message.
269 : */
270 : CHIP_ERROR ProcessSingleMessage(const PeerAddress & peerAddress, ActiveTCPConnectionState * state, size_t messageSize);
271 :
272 : /**
273 : * Initiate a connection to the given peer. On connection completion,
274 : * HandleTCPConnectComplete callback would be called.
275 : *
276 : */
277 : CHIP_ERROR StartConnect(const PeerAddress & addr, AppTCPConnectionCallbackCtxt * appState,
278 : Transport::ActiveTCPConnectionState ** outPeerConnState);
279 :
280 : /**
281 : * Gracefully Close or Abort a given connection.
282 : *
283 : */
284 : void CloseConnectionInternal(ActiveTCPConnectionState * connection, CHIP_ERROR err, SuppressCallback suppressCallback);
285 :
286 : // Close the listening socket endpoint
287 : void CloseListeningSocket();
288 :
289 : // Callback handler for TCPEndPoint. TCP message receive handler.
290 : // @see TCPEndpoint::OnDataReceivedFunct
291 : static CHIP_ERROR HandleTCPEndPointDataReceived(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle && buffer);
292 :
293 : // Callback handler for TCPEndPoint. Called when a connection has been completed.
294 : // @see TCPEndpoint::OnConnectCompleteFunct
295 : static void HandleTCPEndPointConnectComplete(Inet::TCPEndPoint * endPoint, CHIP_ERROR err);
296 :
297 : // Callback handler for TCPEndPoint. Called when a connection has been closed.
298 : // @see TCPEndpoint::OnConnectionClosedFunct
299 : static void HandleTCPEndPointConnectionClosed(Inet::TCPEndPoint * endPoint, CHIP_ERROR err);
300 :
301 : // Callback handler for TCPEndPoint. Called when a connection is received on the listening port.
302 : // @see TCPEndpoint::OnConnectionReceivedFunct
303 : static void HandleIncomingConnection(Inet::TCPEndPoint * listenEndPoint, Inet::TCPEndPoint * endPoint,
304 : const Inet::IPAddress & peerAddress, uint16_t peerPort);
305 :
306 : // Callback handler for handling accept error
307 : // @see TCPEndpoint::OnAcceptErrorFunct
308 : static void HandleAcceptError(Inet::TCPEndPoint * endPoint, CHIP_ERROR err);
309 :
310 : Inet::TCPEndPoint * mListenSocket = nullptr; ///< TCP socket used by the transport
311 : Inet::IPAddressType mEndpointType = Inet::IPAddressType::kUnknown; ///< Socket listening type
312 : TCPState mState = TCPState::kNotReady; ///< State of the TCP transport
313 :
314 : // The configured timeout for the connection attempt to the peer, before
315 : // giving up.
316 : uint32_t mConnectTimeout = CHIP_CONFIG_TCP_CONNECT_TIMEOUT_MSECS;
317 :
318 : // Number of active and 'pending connection' endpoints
319 : size_t mUsedEndPointCount = 0;
320 :
321 : // Currently active connections
322 : ActiveTCPConnectionState * mActiveConnections;
323 : const size_t mActiveConnectionsSize;
324 :
325 : // Data to be sent when connections succeed
326 : PendingPacketPoolType & mPendingPackets;
327 : };
328 :
329 : template <size_t kActiveConnectionsSize, size_t kPendingPacketSize>
330 : class TCP : public TCPBase
331 : {
332 : public:
333 5 : TCP() : TCPBase(mConnectionsBuffer, kActiveConnectionsSize, mPendingPackets)
334 : {
335 5 : for (size_t i = 0; i < kActiveConnectionsSize; ++i)
336 : {
337 4 : mConnectionsBuffer[i].Init(nullptr, PeerAddress::Uninitialized());
338 : }
339 1 : }
340 :
341 5 : ~TCP() override { mPendingPackets.ReleaseAll(); }
342 :
343 : private:
344 : ActiveTCPConnectionState mConnectionsBuffer[kActiveConnectionsSize];
345 : PoolImpl<PendingPacket, kPendingPacketSize, ObjectPoolMem::kInline, PendingPacketPoolType::Interface> mPendingPackets;
346 : };
347 :
348 : } // namespace Transport
349 : } // namespace chip
|