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/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::EndPointManager<Inet::TCPEndPoint> * endPointManager) : mEndPointManager(endPointManager) {} 47 : TcpListenParameters(const TcpListenParameters &) = default; 48 : TcpListenParameters(TcpListenParameters &&) = default; 49 : 50 5 : Inet::EndPointManager<Inet::TCPEndPoint> * GetEndPointManager() { return mEndPointManager; } 51 : 52 10 : Inet::IPAddressType GetAddressType() const { return mAddressType; } 53 : TcpListenParameters & SetAddressType(Inet::IPAddressType type) 54 : { 55 : mAddressType = type; 56 : 57 : return *this; 58 : } 59 : 60 5 : uint16_t GetListenPort() const { return mListenPort; } 61 : TcpListenParameters & SetListenPort(uint16_t port) 62 : { 63 : mListenPort = port; 64 : 65 : return *this; 66 : } 67 : 68 5 : 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::EndPointManager<Inet::TCPEndPoint> * mEndPointManager; ///< Associated endpoint factory 78 : Inet::IPAddressType mAddressType = Inet::IPAddressType::kIPv6; ///< type of listening socket 79 : uint16_t mListenPort = CHIP_PORT; ///< TCP listen port 80 : Inet::InterfaceId mInterfaceId = Inet::InterfaceId::Null(); ///< Interface to listen on 81 : }; 82 : 83 : /** 84 : * Packets scheduled for sending once a connection has been established. 85 : */ 86 : struct PendingPacket 87 : { 88 : PendingPacket(const PeerAddress & peerAddress, System::PacketBufferHandle && packetBuffer) : 89 : mPeerAddress(peerAddress), mPacketBuffer(std::move(packetBuffer)) 90 : {} 91 : 92 : PeerAddress mPeerAddress; // where the packet is being sent to 93 : System::PacketBufferHandle mPacketBuffer; // what data needs to be sent 94 : }; 95 : 96 : /** Implements a transport using TCP. */ 97 : class DLL_EXPORT TCPBase : public Base 98 : { 99 : /** 100 : * The State of the TCP connection 101 : */ 102 : enum class State 103 : { 104 : kNotReady = 0, /**< State before initialization. */ 105 : kInitialized = 1, /**< State after class is listening and ready. */ 106 : }; 107 : 108 : protected: 109 : /** 110 : * State for each active connection 111 : */ 112 : struct ActiveConnectionState 113 : { 114 0 : void Init(Inet::TCPEndPoint * endPoint) 115 : { 116 0 : mEndPoint = endPoint; 117 0 : mReceived = nullptr; 118 0 : } 119 : 120 6 : void Free() 121 : { 122 6 : mEndPoint->Free(); 123 6 : mEndPoint = nullptr; 124 6 : mReceived = nullptr; 125 6 : } 126 67 : bool InUse() const { return mEndPoint != nullptr; } 127 : 128 : // Associated endpoint. 129 : Inet::TCPEndPoint * mEndPoint; 130 : 131 : // Buffers received but not yet consumed. 132 : System::PacketBufferHandle mReceived; 133 : }; 134 : 135 : public: 136 : using PendingPacketPoolType = PoolInterface<PendingPacket, const PeerAddress &, System::PacketBufferHandle &&>; 137 : TCPBase(ActiveConnectionState * activeConnectionsBuffer, size_t bufferSize, PendingPacketPoolType & packetBuffers) : 138 : mActiveConnections(activeConnectionsBuffer), mActiveConnectionsSize(bufferSize), mPendingPackets(packetBuffers) 139 : { 140 : // activeConnectionsBuffer must be initialized by the caller. 141 : } 142 : ~TCPBase() override; 143 : 144 : /** 145 : * Initialize a TCP transport on a given port. 146 : * 147 : * @param params TCP configuration parameters for this transport 148 : * 149 : * @details 150 : * Generally send and receive ports should be the same and equal to CHIP_PORT. 151 : * The class allows separate definitions to allow local execution of several 152 : * Nodes. 153 : */ 154 : CHIP_ERROR Init(TcpListenParameters & params); 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 : void Disconnect(const PeerAddress & address) override; 164 : 165 0 : bool CanSendToPeer(const PeerAddress & address) override 166 : { 167 0 : return (mState == State::kInitialized) && (address.GetTransportType() == Type::kTcp) && 168 0 : (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 : // Release an active connection (corresponding to the passed TCPEndPoint) 229 : // from the pool. 230 : void ReleaseActiveConnection(Inet::TCPEndPoint * endPoint); 231 : 232 : // Callback handler for TCPEndPoint. TCP message receive handler. 233 : // @see TCPEndpoint::OnDataReceivedFunct 234 : static CHIP_ERROR OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle && buffer); 235 : 236 : // Callback handler for TCPEndPoint. Called when a connection has been completed. 237 : // @see TCPEndpoint::OnConnectCompleteFunct 238 : static void OnConnectionComplete(Inet::TCPEndPoint * endPoint, CHIP_ERROR err); 239 : 240 : // Callback handler for TCPEndPoint. Called when a connection has been closed. 241 : // @see TCPEndpoint::OnConnectionClosedFunct 242 : static void OnConnectionClosed(Inet::TCPEndPoint * endPoint, CHIP_ERROR err); 243 : 244 : // Callback handler for TCPEndPoint. Callend when a peer closes the connection. 245 : // @see TCPEndpoint::OnPeerCloseFunct 246 : static void OnPeerClosed(Inet::TCPEndPoint * endPoint); 247 : 248 : // Callback handler for TCPEndPoint. Called when a connection is received on the listening port. 249 : // @see TCPEndpoint::OnConnectionReceivedFunct 250 : static void OnConnectionReceived(Inet::TCPEndPoint * listenEndPoint, Inet::TCPEndPoint * endPoint, 251 : const Inet::IPAddress & peerAddress, uint16_t peerPort); 252 : 253 : // Called on accept error 254 : // @see TCPEndpoint::OnAcceptErrorFunct 255 : static void OnAcceptError(Inet::TCPEndPoint * endPoint, CHIP_ERROR err); 256 : 257 : Inet::TCPEndPoint * mListenSocket = nullptr; ///< TCP socket used by the transport 258 : Inet::IPAddressType mEndpointType = Inet::IPAddressType::kUnknown; ///< Socket listening type 259 : State mState = State::kNotReady; ///< State of the TCP transport 260 : 261 : // Number of active and 'pending connection' endpoints 262 : size_t mUsedEndPointCount = 0; 263 : 264 : // Currently active connections 265 : ActiveConnectionState * mActiveConnections; 266 : const size_t mActiveConnectionsSize; 267 : 268 : // Data to be sent when connections succeed 269 : PendingPacketPoolType & mPendingPackets; 270 : }; 271 : 272 : template <size_t kActiveConnectionsSize, size_t kPendingPacketSize> 273 : class TCP : public TCPBase 274 : { 275 : public: 276 : TCP() : TCPBase(mConnectionsBuffer, kActiveConnectionsSize, mPendingPackets) 277 : { 278 : for (size_t i = 0; i < kActiveConnectionsSize; ++i) 279 : { 280 : mConnectionsBuffer[i].Init(nullptr); 281 : } 282 : } 283 : ~TCP() override { mPendingPackets.ReleaseAll(); } 284 : 285 : private: 286 : friend class TCPTest; 287 : TCPBase::ActiveConnectionState mConnectionsBuffer[kActiveConnectionsSize]; 288 : PoolImpl<PendingPacket, kPendingPacketSize, ObjectPoolMem::kInline, PendingPacketPoolType::Interface> mPendingPackets; 289 : }; 290 : 291 : } // namespace Transport 292 : } // namespace chip