3 * Copyright (c) 2020-2021 Project CHIP Authors
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
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.
31 #include <core/CHIPCore.h>
32 #include <inet/IPAddress.h>
33 #include <inet/IPEndPointBasis.h>
34 #include <inet/InetInterface.h>
35 #include <inet/TCPEndPoint.h>
36 #include <support/CodeUtils.h>
37 #include <transport/raw/Base.h>
42 /** Defines listening parameters for setting up a TCP transport */
43 class TcpListenParameters
46 explicit TcpListenParameters(Inet::InetLayer * layer) : mLayer(layer) {}
47 TcpListenParameters(const TcpListenParameters &) = default;
48 TcpListenParameters(TcpListenParameters &&) = default;
50 Inet::InetLayer * GetInetLayer() { return mLayer; }
52 Inet::IPAddressType GetAddressType() const { return mAddressType; }
53 TcpListenParameters & SetAddressType(Inet::IPAddressType type)
60 uint16_t GetListenPort() const { return mListenPort; }
61 TcpListenParameters & SetListenPort(uint16_t port)
68 Inet::InterfaceId GetInterfaceId() const { return mInterfaceId; }
69 TcpListenParameters & SetInterfaceId(Inet::InterfaceId id)
77 Inet::InetLayer * mLayer = nullptr; ///< Associated inet layer
78 Inet::IPAddressType mAddressType = Inet::kIPAddressType_IPv6; ///< type of listening socket
79 uint16_t mListenPort = CHIP_PORT; ///< TCP listen port
80 Inet::InterfaceId mInterfaceId = INET_NULL_INTERFACEID; ///< Interface to listen on
84 * Packets scheduled for sending once a connection has been established.
88 PeerAddress peerAddress; // where the packet is being sent to
89 System::PacketBufferHandle packetBuffer; // what data needs to be sent
92 /** Implements a transport using TCP. */
93 class DLL_EXPORT TCPBase : public Base
96 * The State of the TCP connection
100 kNotReady = 0, /**< State before initialization. */
101 kInitialized = 1, /**< State after class is listening and ready. */
106 * State for each active connection
108 struct ActiveConnectionState
110 void Init(Inet::TCPEndPoint * endPoint)
112 mEndPoint = endPoint;
122 bool InUse() const { return mEndPoint != nullptr; }
124 // Associated endpoint.
125 Inet::TCPEndPoint * mEndPoint;
127 // Buffers received but not yet consumed.
128 System::PacketBufferHandle mReceived;
132 TCPBase(ActiveConnectionState * activeConnectionsBuffer, size_t bufferSize, PendingPacket * packetBuffers,
133 size_t packetsBuffersSize) :
134 mActiveConnections(activeConnectionsBuffer),
135 mActiveConnectionsSize(bufferSize), mPendingPackets(packetBuffers), mPendingPacketsSize(packetsBuffersSize)
137 // activeConnectionsBuffer must be initialized by the caller.
138 for (size_t i = 0; i < mPendingPacketsSize; ++i)
140 mPendingPackets[i].peerAddress = PeerAddress::Uninitialized();
141 // In the typical case, the TCPBase constructor is invoked from the TCP constructor on its mPendingPackets,
142 // which has not yet been initialized. That means we can't do a normal move assignment or construction of
143 // the PacketBufferHandle, since that would call PacketBuffer::Free on the uninitialized data.
144 new (&mPendingPackets[i].packetBuffer) System::PacketBufferHandle();
150 * Initialize a TCP transport on a given port.
152 * @param params TCP configuration parameters for this transport
155 * Generally send and receive ports should be the same and equal to CHIP_PORT.
156 * The class allows separate definitions to allow local execution of several
159 CHIP_ERROR Init(TcpListenParameters & params);
161 CHIP_ERROR SendMessage(const PacketHeader & header, const PeerAddress & address, System::PacketBufferHandle msgBuf) override;
163 void Disconnect(const PeerAddress & address) override;
165 bool CanSendToPeer(const PeerAddress & address) override
167 return (mState == State::kInitialized) && (address.GetTransportType() == Type::kTcp) &&
168 (address.GetIPAddress().Type() == mEndpointType);
172 * Helper method to determine if IO processing is still required for a TCP transport
173 * before everything is cleaned up (socket closing is async, so after calling 'Close' on
174 * the transport, some time may be needed to actually be able to close.)
176 bool HasActiveConnections() const;
179 * Close all active connections.
181 void CloseActiveConnections();
184 friend class TCPTest;
187 * Find an active connection to the given peer or return nullptr if
188 * no active connection exists.
190 ActiveConnectionState * FindActiveConnection(const PeerAddress & addr);
191 ActiveConnectionState * FindActiveConnection(const Inet::TCPEndPoint * endPoint);
194 * Sends the specified message once a connection has been established.
196 * @param addr - what peer to connect to
197 * @param msg - what buffer to send once a connection has been established.
199 * Ownership of msg is taken over and will be freed at some unspecified time
200 * in the future (once connection succeeds/fails).
202 CHIP_ERROR SendAfterConnect(const PeerAddress & addr, System::PacketBufferHandle msg);
205 * Process a single received buffer from the specified peer address.
207 * @param endPoint the source end point from which the data comes from
208 * @param peerAddress the peer the data is coming from
209 * @param buffer the actual data
211 * Ownership of buffer is taken over and will be freed (or re-enqueued to the endPoint receive queue)
212 * as needed during processing.
214 CHIP_ERROR ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddress,
215 System::PacketBufferHandle buffer);
218 * Process a single message of the specified size from a buffer.
220 * @param[in] peerAddress The peer the data is coming from.
221 * @param[in,out] state The connection state, which contains the message. On entry, the payload points to the message
222 * body (after the length). On exit, it points after the message (or the queue is null, if there
224 * @param[in] messageSize Size of the single message.
226 CHIP_ERROR ProcessSingleMessage(const PeerAddress & peerAddress, ActiveConnectionState * state, uint16_t messageSize);
228 // Callback handler for TCPEndPoint. TCP message receive handler.
229 // @see TCPEndpoint::OnDataReceivedFunct
230 static INET_ERROR OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle buffer);
232 // Callback handler for TCPEndPoint. Called when a connection has been completed.
233 // @see TCPEndpoint::OnConnectCompleteFunct
234 static void OnConnectionComplete(Inet::TCPEndPoint * endPoint, INET_ERROR err);
236 // Callback handler for TCPEndPoint. Called when a connection has been closed.
237 // @see TCPEndpoint::OnConnectionClosedFunct
238 static void OnConnectionClosed(Inet::TCPEndPoint * endPoint, INET_ERROR err);
240 // Callback handler for TCPEndPoint. Callend when a peer closes the connection.
241 // @see TCPEndpoint::OnPeerCloseFunct
242 static void OnPeerClosed(Inet::TCPEndPoint * endPoint);
244 // Callback handler for TCPEndPoint. Called when a connection is received on the listening port.
245 // @see TCPEndpoint::OnConnectionReceivedFunct
246 static void OnConnectionReceived(Inet::TCPEndPoint * listenEndPoint, Inet::TCPEndPoint * endPoint,
247 const Inet::IPAddress & peerAddress, uint16_t peerPort);
249 // Called on accept error
250 // @see TCPEndpoint::OnAcceptErrorFunct
251 static void OnAcceptError(Inet::TCPEndPoint * endPoint, INET_ERROR err);
253 Inet::TCPEndPoint * mListenSocket = nullptr; ///< TCP socket used by the transport
254 Inet::IPAddressType mEndpointType = Inet::IPAddressType::kIPAddressType_Unknown; ///< Socket listening type
255 State mState = State::kNotReady; ///< State of the TCP transport
257 // Number of active and 'pending connection' endpoints
258 size_t mUsedEndPointCount = 0;
260 // Currently active connections
261 ActiveConnectionState * mActiveConnections;
262 const size_t mActiveConnectionsSize;
264 // Data to be sent when connections succeed
265 PendingPacket * mPendingPackets;
266 const size_t mPendingPacketsSize;
269 template <size_t kActiveConnectionsSize, size_t kPendingPacketSize>
270 class TCP : public TCPBase
273 TCP() : TCPBase(mConnectionsBuffer, kActiveConnectionsSize, mPendingPackets, kPendingPacketSize)
275 for (size_t i = 0; i < kActiveConnectionsSize; ++i)
277 mConnectionsBuffer[i].Init(nullptr);
282 friend class TCPTest;
283 TCPBase::ActiveConnectionState mConnectionsBuffer[kActiveConnectionsSize];
284 PendingPacket mPendingPackets[kPendingPacketSize];
287 } // namespace Transport