Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / transport / raw / TCP.h
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 <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>
38
39 namespace chip {
40 namespace Transport {
41
42 /** Defines listening parameters for setting up a TCP transport */
43 class TcpListenParameters
44 {
45 public:
46     explicit TcpListenParameters(Inet::InetLayer * layer) : mLayer(layer) {}
47     TcpListenParameters(const TcpListenParameters &) = default;
48     TcpListenParameters(TcpListenParameters &&)      = default;
49
50     Inet::InetLayer * GetInetLayer() { return mLayer; }
51
52     Inet::IPAddressType GetAddressType() const { return mAddressType; }
53     TcpListenParameters & SetAddressType(Inet::IPAddressType type)
54     {
55         mAddressType = type;
56
57         return *this;
58     }
59
60     uint16_t GetListenPort() const { return mListenPort; }
61     TcpListenParameters & SetListenPort(uint16_t port)
62     {
63         mListenPort = port;
64
65         return *this;
66     }
67
68     Inet::InterfaceId GetInterfaceId() const { return mInterfaceId; }
69     TcpListenParameters & SetInterfaceId(Inet::InterfaceId id)
70     {
71         mInterfaceId = id;
72
73         return *this;
74     }
75
76 private:
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
81 };
82
83 /**
84  * Packets scheduled for sending once a connection has been established.
85  */
86 struct PendingPacket
87 {
88     PeerAddress peerAddress;                 // where the packet is being sent to
89     System::PacketBufferHandle packetBuffer; // what data needs to be sent
90 };
91
92 /** Implements a transport using TCP. */
93 class DLL_EXPORT TCPBase : public Base
94 {
95     /**
96      *  The State of the TCP connection
97      */
98     enum class State
99     {
100         kNotReady    = 0, /**< State before initialization. */
101         kInitialized = 1, /**< State after class is listening and ready. */
102     };
103
104 protected:
105     /**
106      *  State for each active connection
107      */
108     struct ActiveConnectionState
109     {
110         void Init(Inet::TCPEndPoint * endPoint)
111         {
112             mEndPoint = endPoint;
113             mReceived = nullptr;
114         }
115
116         void Free()
117         {
118             mEndPoint->Free();
119             mEndPoint = nullptr;
120             mReceived = nullptr;
121         }
122         bool InUse() const { return mEndPoint != nullptr; }
123
124         // Associated endpoint.
125         Inet::TCPEndPoint * mEndPoint;
126
127         // Buffers received but not yet consumed.
128         System::PacketBufferHandle mReceived;
129     };
130
131 public:
132     TCPBase(ActiveConnectionState * activeConnectionsBuffer, size_t bufferSize, PendingPacket * packetBuffers,
133             size_t packetsBuffersSize) :
134         mActiveConnections(activeConnectionsBuffer),
135         mActiveConnectionsSize(bufferSize), mPendingPackets(packetBuffers), mPendingPacketsSize(packetsBuffersSize)
136     {
137         // activeConnectionsBuffer must be initialized by the caller.
138         for (size_t i = 0; i < mPendingPacketsSize; ++i)
139         {
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();
145         }
146     }
147     ~TCPBase() override;
148
149     /**
150      * Initialize a TCP transport on a given port.
151      *
152      * @param params        TCP configuration parameters for this transport
153      *
154      * @details
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
157      *   Nodes.
158      */
159     CHIP_ERROR Init(TcpListenParameters & params);
160
161     CHIP_ERROR SendMessage(const PacketHeader & header, const PeerAddress & address, System::PacketBufferHandle msgBuf) override;
162
163     void Disconnect(const PeerAddress & address) override;
164
165     bool CanSendToPeer(const PeerAddress & address) override
166     {
167         return (mState == State::kInitialized) && (address.GetTransportType() == Type::kTcp) &&
168             (address.GetIPAddress().Type() == mEndpointType);
169     }
170
171     /**
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.)
175      */
176     bool HasActiveConnections() const;
177
178     /**
179      * Close all active connections.
180      */
181     void CloseActiveConnections();
182
183 private:
184     friend class TCPTest;
185
186     /**
187      * Find an active connection to the given peer or return nullptr if
188      * no active connection exists.
189      */
190     ActiveConnectionState * FindActiveConnection(const PeerAddress & addr);
191     ActiveConnectionState * FindActiveConnection(const Inet::TCPEndPoint * endPoint);
192
193     /**
194      * Sends the specified message once a connection has been established.
195      *
196      * @param addr - what peer to connect to
197      * @param msg - what buffer to send once a connection has been established.
198      *
199      * Ownership of msg is taken over and will be freed at some unspecified time
200      * in the future (once connection succeeds/fails).
201      */
202     CHIP_ERROR SendAfterConnect(const PeerAddress & addr, System::PacketBufferHandle msg);
203
204     /**
205      * Process a single received buffer from the specified peer address.
206      *
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
210      *
211      * Ownership of buffer is taken over and will be freed (or re-enqueued to the endPoint receive queue)
212      * as needed during processing.
213      */
214     CHIP_ERROR ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddress,
215                                      System::PacketBufferHandle buffer);
216
217     /**
218      * Process a single message of the specified size from a buffer.
219      *
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
223      *                              is no other data).
224      * @param[in]     messageSize   Size of the single message.
225      */
226     CHIP_ERROR ProcessSingleMessage(const PeerAddress & peerAddress, ActiveConnectionState * state, uint16_t messageSize);
227
228     // Callback handler for TCPEndPoint. TCP message receive handler.
229     // @see TCPEndpoint::OnDataReceivedFunct
230     static INET_ERROR OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle buffer);
231
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);
235
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);
239
240     // Callback handler for TCPEndPoint. Callend when a peer closes the connection.
241     // @see TCPEndpoint::OnPeerCloseFunct
242     static void OnPeerClosed(Inet::TCPEndPoint * endPoint);
243
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);
248
249     // Called on accept error
250     // @see TCPEndpoint::OnAcceptErrorFunct
251     static void OnAcceptError(Inet::TCPEndPoint * endPoint, INET_ERROR err);
252
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
256
257     // Number of active and 'pending connection' endpoints
258     size_t mUsedEndPointCount = 0;
259
260     // Currently active connections
261     ActiveConnectionState * mActiveConnections;
262     const size_t mActiveConnectionsSize;
263
264     // Data to be sent when connections succeed
265     PendingPacket * mPendingPackets;
266     const size_t mPendingPacketsSize;
267 };
268
269 template <size_t kActiveConnectionsSize, size_t kPendingPacketSize>
270 class TCP : public TCPBase
271 {
272 public:
273     TCP() : TCPBase(mConnectionsBuffer, kActiveConnectionsSize, mPendingPackets, kPendingPacketSize)
274     {
275         for (size_t i = 0; i < kActiveConnectionsSize; ++i)
276         {
277             mConnectionsBuffer[i].Init(nullptr);
278         }
279     }
280
281 private:
282     friend class TCPTest;
283     TCPBase::ActiveConnectionState mConnectionsBuffer[kActiveConnectionsSize];
284     PendingPacket mPendingPackets[kPendingPacketSize];
285 };
286
287 } // namespace Transport
288 } // namespace chip