Coverage Report

Created: 2026-08-14 07:41

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