Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : * All rights reserved.
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : /**
21 : * @file
22 : * This file implements the CHIP Transport object that maintains TCP connections
23 : * to peers. Handles both establishing new connections and accepting peer connection
24 : * requests.
25 : */
26 : #include <transport/raw/TCP.h>
27 :
28 : #include <lib/core/CHIPEncoding.h>
29 : #include <lib/support/CodeUtils.h>
30 : #include <lib/support/logging/CHIPLogging.h>
31 : #include <transport/raw/MessageHeader.h>
32 :
33 : #include <inttypes.h>
34 : #include <limits>
35 :
36 : namespace chip {
37 : namespace Transport {
38 : namespace {
39 :
40 : using namespace chip::Encoding;
41 :
42 : // Packets start with a 32-bit size field.
43 : constexpr size_t kPacketSizeBytes = 4;
44 :
45 : static_assert(System::PacketBuffer::kLargeBufMaxSizeWithoutReserve <= UINT32_MAX, "Cast below could truncate the value");
46 : static_assert(System::PacketBuffer::kLargeBufMaxSizeWithoutReserve >= kPacketSizeBytes,
47 : "Large buffer allocation should be large enough to hold the length field");
48 :
49 : constexpr uint32_t kMaxTCPMessageSize =
50 : static_cast<uint32_t>(System::PacketBuffer::kLargeBufMaxSizeWithoutReserve - kPacketSizeBytes);
51 :
52 : constexpr int kListenBacklogSize = 2;
53 :
54 : } // namespace
55 :
56 16 : TCPBase::~TCPBase()
57 : {
58 : // Call Close to free the listening socket and close all active connections.
59 16 : Close();
60 16 : }
61 :
62 18 : void TCPBase::CloseActiveConnections()
63 : {
64 90 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
65 : {
66 72 : if (mActiveConnections[i].InUse())
67 : {
68 3 : CloseConnectionInternal(&mActiveConnections[i], CHIP_NO_ERROR, SuppressCallback::Yes);
69 : }
70 : }
71 18 : }
72 :
73 16 : CHIP_ERROR TCPBase::Init(TcpListenParameters & params)
74 : {
75 16 : CHIP_ERROR err = CHIP_NO_ERROR;
76 :
77 16 : VerifyOrExit(mState == TCPState::kNotReady, err = CHIP_ERROR_INCORRECT_STATE);
78 :
79 16 : mEndpointType = params.GetAddressType();
80 :
81 : // Primary socket endpoint created to help get EndPointManager handle for creating multiple
82 : // connection endpoints at runtime.
83 16 : err = params.GetEndPointManager()->NewEndPoint(&mListenSocket);
84 16 : SuccessOrExit(err);
85 :
86 16 : if (params.IsServerListenEnabled())
87 : {
88 15 : err = mListenSocket->Bind(params.GetAddressType(), Inet::IPAddress::Any, params.GetListenPort(),
89 15 : params.GetInterfaceId().IsPresent());
90 15 : SuccessOrExit(err);
91 :
92 15 : mListenSocket->mAppState = reinterpret_cast<void *>(this);
93 15 : mListenSocket->OnConnectionReceived = HandleIncomingConnection;
94 15 : mListenSocket->OnAcceptError = HandleAcceptError;
95 :
96 15 : err = mListenSocket->Listen(kListenBacklogSize);
97 15 : SuccessOrExit(err);
98 15 : ChipLogProgress(Inet, "TCP server listening on port %d for incoming connections", params.GetListenPort());
99 : }
100 :
101 16 : mState = TCPState::kInitialized;
102 :
103 16 : exit:
104 16 : if (err != CHIP_NO_ERROR)
105 : {
106 0 : ChipLogError(Inet, "Failed to initialize TCP transport: %" CHIP_ERROR_FORMAT, err.Format());
107 0 : if (mListenSocket)
108 : {
109 0 : mListenSocket->Free();
110 0 : mListenSocket = nullptr;
111 : }
112 : }
113 :
114 16 : return err;
115 : }
116 :
117 18 : void TCPBase::Close()
118 : {
119 18 : if (mListenSocket)
120 : {
121 16 : mListenSocket->Free();
122 16 : mListenSocket = nullptr;
123 : }
124 :
125 18 : CloseActiveConnections();
126 :
127 18 : mState = TCPState::kNotReady;
128 18 : }
129 :
130 22 : ActiveTCPConnectionState * TCPBase::AllocateConnection()
131 : {
132 33 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
133 : {
134 33 : if (!mActiveConnections[i].InUse())
135 : {
136 22 : return &mActiveConnections[i];
137 : }
138 : }
139 :
140 0 : return nullptr;
141 : }
142 :
143 : // Find an ActiveTCPConnectionState corresponding to a peer address
144 7 : ActiveTCPConnectionState * TCPBase::FindActiveConnection(const PeerAddress & address)
145 : {
146 7 : if (address.GetTransportType() != Type::kTcp)
147 : {
148 0 : return nullptr;
149 : }
150 :
151 19 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
152 : {
153 16 : if (!mActiveConnections[i].IsConnected())
154 : {
155 12 : continue;
156 : }
157 : Inet::IPAddress addr;
158 : uint16_t port;
159 4 : mActiveConnections[i].mEndPoint->GetPeerInfo(&addr, &port);
160 :
161 4 : if ((addr == address.GetIPAddress()) && (port == address.GetPort()))
162 : {
163 4 : return &mActiveConnections[i];
164 : }
165 : }
166 :
167 3 : return nullptr;
168 : }
169 :
170 : // Find the ActiveTCPConnectionState for a given TCPEndPoint
171 12 : ActiveTCPConnectionState * TCPBase::FindActiveConnection(const Inet::TCPEndPoint * endPoint)
172 : {
173 17 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
174 : {
175 17 : if (mActiveConnections[i].mEndPoint == endPoint && mActiveConnections[i].IsConnected())
176 : {
177 12 : return &mActiveConnections[i];
178 : }
179 : }
180 0 : return nullptr;
181 : }
182 :
183 20 : ActiveTCPConnectionState * TCPBase::FindInUseConnection(const Inet::TCPEndPoint * endPoint)
184 : {
185 20 : if (endPoint == nullptr)
186 : {
187 0 : return nullptr;
188 : }
189 :
190 29 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
191 : {
192 29 : if (mActiveConnections[i].mEndPoint == endPoint)
193 : {
194 20 : return &mActiveConnections[i];
195 : }
196 : }
197 0 : return nullptr;
198 : }
199 :
200 5 : CHIP_ERROR TCPBase::SendMessage(const Transport::PeerAddress & address, System::PacketBufferHandle && msgBuf)
201 : {
202 : // Sent buffer data format is:
203 : // - packet size as a uint32_t
204 : // - actual data
205 :
206 5 : VerifyOrReturnError(address.GetTransportType() == Type::kTcp, CHIP_ERROR_INVALID_ARGUMENT);
207 5 : VerifyOrReturnError(mState == TCPState::kInitialized, CHIP_ERROR_INCORRECT_STATE);
208 5 : VerifyOrReturnError(kPacketSizeBytes + msgBuf->DataLength() <= System::PacketBuffer::kLargeBufMaxSizeWithoutReserve,
209 : CHIP_ERROR_INVALID_ARGUMENT);
210 :
211 : static_assert(kPacketSizeBytes <= UINT16_MAX);
212 5 : VerifyOrReturnError(msgBuf->EnsureReservedSize(static_cast<uint16_t>(kPacketSizeBytes)), CHIP_ERROR_NO_MEMORY);
213 :
214 5 : msgBuf->SetStart(msgBuf->Start() - kPacketSizeBytes);
215 :
216 5 : uint8_t * output = msgBuf->Start();
217 5 : LittleEndian::Write32(output, static_cast<uint32_t>(msgBuf->DataLength() - kPacketSizeBytes));
218 :
219 : // Reuse existing connection if one exists, otherwise a new one
220 : // will be established
221 5 : ActiveTCPConnectionState * connection = FindActiveConnection(address);
222 :
223 5 : if (connection != nullptr)
224 : {
225 2 : return connection->mEndPoint->Send(std::move(msgBuf));
226 : }
227 :
228 3 : return SendAfterConnect(address, std::move(msgBuf));
229 : }
230 :
231 11 : CHIP_ERROR TCPBase::StartConnect(const PeerAddress & addr, Transport::AppTCPConnectionCallbackCtxt * appState,
232 : Transport::ActiveTCPConnectionState ** outPeerConnState)
233 : {
234 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
235 11 : ActiveTCPConnectionState * activeConnection = nullptr;
236 11 : Inet::TCPEndPoint * endPoint = nullptr;
237 11 : *outPeerConnState = nullptr;
238 11 : ReturnErrorOnFailure(mListenSocket->GetEndPointManager().NewEndPoint(&endPoint));
239 :
240 0 : auto EndPointDeletor = [](Inet::TCPEndPoint * e) { e->Free(); };
241 11 : std::unique_ptr<Inet::TCPEndPoint, decltype(EndPointDeletor)> endPointHolder(endPoint, EndPointDeletor);
242 :
243 11 : endPoint->mAppState = reinterpret_cast<void *>(this);
244 11 : endPoint->OnConnectComplete = HandleTCPEndPointConnectComplete;
245 11 : endPoint->SetConnectTimeout(mConnectTimeout);
246 :
247 11 : activeConnection = AllocateConnection();
248 11 : VerifyOrReturnError(activeConnection != nullptr, CHIP_ERROR_NO_MEMORY);
249 11 : activeConnection->Init(endPoint, addr);
250 11 : activeConnection->mAppState = appState;
251 11 : activeConnection->mConnectionState = TCPState::kConnecting;
252 : // Set the return value of the peer connection state to the allocated
253 : // connection.
254 11 : *outPeerConnState = activeConnection;
255 :
256 11 : ReturnErrorOnFailure(endPoint->Connect(addr.GetIPAddress(), addr.GetPort(), addr.GetInterface()));
257 :
258 11 : mUsedEndPointCount++;
259 :
260 11 : endPointHolder.release();
261 :
262 11 : return CHIP_NO_ERROR;
263 : #else
264 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
265 : #endif
266 11 : }
267 :
268 3 : CHIP_ERROR TCPBase::SendAfterConnect(const PeerAddress & addr, System::PacketBufferHandle && msg)
269 : {
270 : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
271 : // This will initiate a connection to the specified peer
272 3 : bool alreadyConnecting = false;
273 :
274 : // Iterate through the ENTIRE array. If a pending packet for
275 : // the address already exists, this means a connection is pending and
276 : // does NOT need to be re-established.
277 3 : mPendingPackets.ForEachActiveObject([&](PendingPacket * pending) {
278 0 : if (pending->mPeerAddress == addr)
279 : {
280 : // same destination exists.
281 0 : alreadyConnecting = true;
282 0 : pending->mPacketBuffer->AddToEnd(std::move(msg));
283 0 : return Loop::Break;
284 : }
285 0 : return Loop::Continue;
286 : });
287 :
288 : // If already connecting, buffer was just enqueued for more sending
289 3 : if (alreadyConnecting)
290 : {
291 0 : return CHIP_NO_ERROR;
292 : }
293 :
294 : // Ensures sufficient active connections size exist
295 3 : VerifyOrReturnError(mUsedEndPointCount < mActiveConnectionsSize, CHIP_ERROR_NO_MEMORY);
296 :
297 3 : Transport::ActiveTCPConnectionState * peerConnState = nullptr;
298 3 : ReturnErrorOnFailure(StartConnect(addr, nullptr, &peerConnState));
299 :
300 : // enqueue the packet once the connection succeeds
301 3 : VerifyOrReturnError(mPendingPackets.CreateObject(addr, std::move(msg)) != nullptr, CHIP_ERROR_NO_MEMORY);
302 3 : mUsedEndPointCount++;
303 :
304 3 : return CHIP_NO_ERROR;
305 : #else
306 : return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
307 : #endif
308 : }
309 :
310 12 : CHIP_ERROR TCPBase::ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddress,
311 : System::PacketBufferHandle && buffer)
312 : {
313 12 : ActiveTCPConnectionState * state = FindActiveConnection(endPoint);
314 12 : VerifyOrReturnError(state != nullptr, CHIP_ERROR_INTERNAL);
315 12 : state->mReceived.AddToEnd(std::move(buffer));
316 :
317 24 : while (!state->mReceived.IsNull())
318 : {
319 : uint8_t messageSizeBuf[kPacketSizeBytes];
320 14 : CHIP_ERROR err = state->mReceived->Read(messageSizeBuf);
321 14 : if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
322 : {
323 : // We don't have enough data to read the message size. Wait until there's more.
324 2 : return CHIP_NO_ERROR;
325 : }
326 14 : if (err != CHIP_NO_ERROR)
327 : {
328 0 : return err;
329 : }
330 14 : uint32_t messageSize = LittleEndian::Get32(messageSizeBuf);
331 14 : if (messageSize >= kMaxTCPMessageSize)
332 : {
333 : // Message is too big for this node to process. Disconnect from peer.
334 1 : ChipLogError(Inet, "Received TCP message of length %" PRIu32 " exceeds limit.", messageSize);
335 1 : CloseConnectionInternal(state, CHIP_ERROR_MESSAGE_TOO_LONG, SuppressCallback::No);
336 :
337 1 : return CHIP_ERROR_MESSAGE_TOO_LONG;
338 : }
339 : // The subtraction will not underflow because we successfully read kPacketSizeBytes.
340 13 : if (messageSize > (state->mReceived->TotalLength() - kPacketSizeBytes))
341 : {
342 : // We have not yet received the complete message.
343 0 : return CHIP_NO_ERROR;
344 : }
345 :
346 13 : state->mReceived.Consume(kPacketSizeBytes);
347 :
348 13 : if (messageSize == 0)
349 : {
350 : // No payload but considered a valid message. Return success to keep the connection alive.
351 1 : return CHIP_NO_ERROR;
352 : }
353 :
354 12 : ReturnErrorOnFailure(ProcessSingleMessage(peerAddress, state, messageSize));
355 : }
356 :
357 10 : return CHIP_NO_ERROR;
358 : }
359 :
360 12 : CHIP_ERROR TCPBase::ProcessSingleMessage(const PeerAddress & peerAddress, ActiveTCPConnectionState * state, size_t messageSize)
361 : {
362 : // We enter with `state->mReceived` containing at least one full message, perhaps in a chain.
363 : // `state->mReceived->Start()` currently points to the message data.
364 : // On exit, `state->mReceived` will have had `messageSize` bytes consumed, no matter what.
365 12 : System::PacketBufferHandle message;
366 12 : MessageTransportContext msgContext;
367 12 : msgContext.conn = state;
368 :
369 12 : if (state->mReceived->DataLength() == messageSize)
370 : {
371 : // In this case, the head packet buffer contains exactly the message.
372 : // This is common because typical messages fit in a network packet, and are delivered as such.
373 : // Peel off the head to pass upstream, which effectively consumes it from `state->mReceived`.
374 9 : message = state->mReceived.PopHead();
375 : }
376 : else
377 : {
378 : // The message is either longer or shorter than the head buffer.
379 : // In either case, copy the message to a fresh linear buffer to pass upstream. We always copy, rather than provide
380 : // a shared reference to the current buffer, in case upper layers manipulate the buffer in ways that would affect
381 : // our use, e.g. chaining it elsewhere or reusing space beyond the current message.
382 3 : message = System::PacketBufferHandle::New(messageSize, 0);
383 3 : if (message.IsNull())
384 : {
385 0 : return CHIP_ERROR_NO_MEMORY;
386 : }
387 3 : CHIP_ERROR err = state->mReceived->Read(message->Start(), messageSize);
388 3 : state->mReceived.Consume(messageSize);
389 3 : ReturnErrorOnFailure(err);
390 3 : message->SetDataLength(messageSize);
391 : }
392 :
393 12 : HandleMessageReceived(peerAddress, std::move(message), &msgContext);
394 12 : return CHIP_NO_ERROR;
395 12 : }
396 :
397 22 : void TCPBase::CloseConnectionInternal(ActiveTCPConnectionState * connection, CHIP_ERROR err, SuppressCallback suppressCallback)
398 : {
399 : TCPState prevState;
400 :
401 22 : if (connection == nullptr)
402 : {
403 0 : return;
404 : }
405 :
406 22 : if (connection->mConnectionState != TCPState::kClosed && connection->mEndPoint)
407 : {
408 : char addrStr[Transport::PeerAddress::kMaxToStringSize];
409 22 : connection->mPeerAddr.ToString(addrStr);
410 22 : ChipLogProgress(Inet, "Closing connection with peer %s.", addrStr);
411 :
412 22 : if (err == CHIP_NO_ERROR)
413 : {
414 12 : connection->mEndPoint->Close();
415 : }
416 : else
417 : {
418 10 : connection->mEndPoint->Abort();
419 : }
420 :
421 22 : prevState = connection->mConnectionState;
422 22 : connection->mConnectionState = TCPState::kClosed;
423 :
424 22 : if (suppressCallback == SuppressCallback::No)
425 : {
426 10 : if (prevState == TCPState::kConnecting)
427 : {
428 : // Call upper layer connection attempt complete handler
429 0 : HandleConnectionAttemptComplete(connection, err);
430 : }
431 : else
432 : {
433 : // Call upper layer connection closed handler
434 10 : HandleConnectionClosed(connection, err);
435 : }
436 : }
437 :
438 22 : connection->Free();
439 22 : mUsedEndPointCount--;
440 : }
441 : }
442 :
443 5 : CHIP_ERROR TCPBase::HandleTCPEndPointDataReceived(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle && buffer)
444 : {
445 : Inet::IPAddress ipAddress;
446 : uint16_t port;
447 5 : Inet::InterfaceId interfaceId;
448 :
449 5 : endPoint->GetPeerInfo(&ipAddress, &port);
450 5 : endPoint->GetInterfaceId(&interfaceId);
451 5 : PeerAddress peerAddress = PeerAddress::TCP(ipAddress, port, interfaceId);
452 :
453 5 : TCPBase * tcp = reinterpret_cast<TCPBase *>(endPoint->mAppState);
454 5 : CHIP_ERROR err = tcp->ProcessReceivedBuffer(endPoint, peerAddress, std::move(buffer));
455 :
456 5 : if (err != CHIP_NO_ERROR)
457 : {
458 : // Connection could need to be closed at this point
459 0 : ChipLogError(Inet, "Failed to accept received TCP message: %" CHIP_ERROR_FORMAT, err.Format());
460 0 : return CHIP_ERROR_UNEXPECTED_EVENT;
461 : }
462 5 : return CHIP_NO_ERROR;
463 : }
464 :
465 11 : void TCPBase::HandleTCPEndPointConnectComplete(Inet::TCPEndPoint * endPoint, CHIP_ERROR conErr)
466 : {
467 11 : CHIP_ERROR err = CHIP_NO_ERROR;
468 11 : bool foundPendingPacket = false;
469 11 : TCPBase * tcp = reinterpret_cast<TCPBase *>(endPoint->mAppState);
470 : Inet::IPAddress ipAddress;
471 : uint16_t port;
472 11 : Inet::InterfaceId interfaceId;
473 11 : ActiveTCPConnectionState * activeConnection = nullptr;
474 :
475 11 : endPoint->GetPeerInfo(&ipAddress, &port);
476 11 : endPoint->GetInterfaceId(&interfaceId);
477 : char addrStr[Transport::PeerAddress::kMaxToStringSize];
478 11 : PeerAddress addr = PeerAddress::TCP(ipAddress, port, interfaceId);
479 11 : addr.ToString(addrStr);
480 :
481 11 : if (conErr == CHIP_NO_ERROR)
482 : {
483 : // Set the Data received handler when connection completes
484 11 : endPoint->OnDataReceived = HandleTCPEndPointDataReceived;
485 11 : endPoint->OnDataSent = nullptr;
486 11 : endPoint->OnConnectionClosed = HandleTCPEndPointConnectionClosed;
487 :
488 11 : activeConnection = tcp->FindInUseConnection(endPoint);
489 11 : VerifyOrDie(activeConnection != nullptr);
490 :
491 : // Set to Connected state
492 11 : activeConnection->mConnectionState = TCPState::kConnected;
493 :
494 : // Disable TCP Nagle buffering by setting TCP_NODELAY socket option to true.
495 : // This is to expedite transmission of payload data and not rely on the
496 : // network stack's configuration of collating enough data in the TCP
497 : // window to begin transmission.
498 11 : err = endPoint->EnableNoDelay();
499 11 : if (err != CHIP_NO_ERROR)
500 : {
501 0 : tcp->CloseConnectionInternal(activeConnection, err, SuppressCallback::No);
502 0 : return;
503 : }
504 :
505 : // Send any pending packets that are queued for this connection
506 11 : tcp->mPendingPackets.ForEachActiveObject([&](PendingPacket * pending) {
507 3 : if (pending->mPeerAddress == addr)
508 : {
509 3 : foundPendingPacket = true;
510 3 : System::PacketBufferHandle buffer = std::move(pending->mPacketBuffer);
511 3 : tcp->mPendingPackets.ReleaseObject(pending);
512 :
513 3 : if ((conErr == CHIP_NO_ERROR) && (err == CHIP_NO_ERROR))
514 : {
515 3 : err = endPoint->Send(std::move(buffer));
516 : }
517 3 : }
518 3 : return Loop::Continue;
519 : });
520 :
521 : // Set the TCPKeepalive configurations on the established connection
522 11 : endPoint->EnableKeepAlive(activeConnection->mTCPKeepAliveIntervalSecs, activeConnection->mTCPMaxNumKeepAliveProbes);
523 :
524 11 : ChipLogProgress(Inet, "Connection established successfully with %s.", addrStr);
525 :
526 : // Let higher layer/delegate know that connection is successfully
527 : // established
528 11 : tcp->HandleConnectionAttemptComplete(activeConnection, CHIP_NO_ERROR);
529 : }
530 : else
531 : {
532 0 : ChipLogError(Inet, "Connection establishment with %s encountered an error: %" CHIP_ERROR_FORMAT, addrStr, err.Format());
533 0 : endPoint->Free();
534 0 : tcp->mUsedEndPointCount--;
535 : }
536 : }
537 :
538 9 : void TCPBase::HandleTCPEndPointConnectionClosed(Inet::TCPEndPoint * endPoint, CHIP_ERROR err)
539 : {
540 9 : TCPBase * tcp = reinterpret_cast<TCPBase *>(endPoint->mAppState);
541 9 : ActiveTCPConnectionState * activeConnection = tcp->FindInUseConnection(endPoint);
542 :
543 9 : if (activeConnection == nullptr)
544 : {
545 0 : endPoint->Free();
546 0 : return;
547 : }
548 :
549 9 : if (err == CHIP_NO_ERROR && activeConnection->IsConnected())
550 : {
551 9 : err = CHIP_ERROR_CONNECTION_CLOSED_UNEXPECTEDLY;
552 : }
553 :
554 9 : tcp->CloseConnectionInternal(activeConnection, err, SuppressCallback::No);
555 : }
556 :
557 : // Handler for incoming connection requests from peer nodes
558 11 : void TCPBase::HandleIncomingConnection(Inet::TCPEndPoint * listenEndPoint, Inet::TCPEndPoint * endPoint,
559 : const Inet::IPAddress & peerAddress, uint16_t peerPort)
560 : {
561 11 : TCPBase * tcp = reinterpret_cast<TCPBase *>(listenEndPoint->mAppState);
562 11 : ActiveTCPConnectionState * activeConnection = nullptr;
563 11 : Inet::InterfaceId interfaceId;
564 : Inet::IPAddress ipAddress;
565 : uint16_t port;
566 :
567 11 : endPoint->GetPeerInfo(&ipAddress, &port);
568 11 : endPoint->GetInterfaceId(&interfaceId);
569 11 : PeerAddress addr = PeerAddress::TCP(ipAddress, port, interfaceId);
570 :
571 11 : if (tcp->mUsedEndPointCount < tcp->mActiveConnectionsSize)
572 : {
573 11 : activeConnection = tcp->AllocateConnection();
574 :
575 11 : endPoint->mAppState = listenEndPoint->mAppState;
576 11 : endPoint->OnDataReceived = HandleTCPEndPointDataReceived;
577 11 : endPoint->OnDataSent = nullptr;
578 11 : endPoint->OnConnectionClosed = HandleTCPEndPointConnectionClosed;
579 :
580 : // By default, disable TCP Nagle buffering by setting TCP_NODELAY socket option to true
581 11 : endPoint->EnableNoDelay();
582 :
583 : // Update state for the active connection
584 11 : activeConnection->Init(endPoint, addr);
585 11 : tcp->mUsedEndPointCount++;
586 11 : activeConnection->mConnectionState = TCPState::kConnected;
587 :
588 : // Set the TCPKeepalive configurations on the received connection
589 11 : endPoint->EnableKeepAlive(activeConnection->mTCPKeepAliveIntervalSecs, activeConnection->mTCPMaxNumKeepAliveProbes);
590 :
591 : char addrStr[Transport::PeerAddress::kMaxToStringSize];
592 11 : peerAddress.ToString(addrStr);
593 11 : ChipLogProgress(Inet, "Incoming connection established with peer at %s.", addrStr);
594 :
595 : // Call the upper layer handler for incoming connection received.
596 11 : tcp->HandleConnectionReceived(activeConnection);
597 : }
598 : else
599 : {
600 0 : ChipLogError(Inet, "Insufficient connection space to accept new connections.");
601 0 : endPoint->Free();
602 0 : listenEndPoint->OnAcceptError(endPoint, CHIP_ERROR_TOO_MANY_CONNECTIONS);
603 : }
604 11 : }
605 :
606 0 : void TCPBase::HandleAcceptError(Inet::TCPEndPoint * endPoint, CHIP_ERROR err)
607 : {
608 0 : endPoint->Free();
609 0 : ChipLogError(Inet, "Accept error: %" CHIP_ERROR_FORMAT, err.Format());
610 0 : }
611 :
612 8 : CHIP_ERROR TCPBase::TCPConnect(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState,
613 : Transport::ActiveTCPConnectionState ** outPeerConnState)
614 : {
615 8 : VerifyOrReturnError(mState == TCPState::kInitialized, CHIP_ERROR_INCORRECT_STATE);
616 :
617 : // Verify that PeerAddress AddressType is TCP
618 8 : VerifyOrReturnError(address.GetTransportType() == Transport::Type::kTcp, CHIP_ERROR_INVALID_ARGUMENT);
619 :
620 8 : VerifyOrReturnError(mUsedEndPointCount < mActiveConnectionsSize, CHIP_ERROR_NO_MEMORY);
621 :
622 : char addrStr[Transport::PeerAddress::kMaxToStringSize];
623 8 : address.ToString(addrStr);
624 8 : ChipLogProgress(Inet, "Connecting to peer %s.", addrStr);
625 :
626 8 : ReturnErrorOnFailure(StartConnect(address, appState, outPeerConnState));
627 :
628 8 : return CHIP_NO_ERROR;
629 : }
630 :
631 10 : void TCPBase::TCPDisconnect(const PeerAddress & address)
632 : {
633 : // Closes an existing connection
634 50 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
635 : {
636 40 : if (mActiveConnections[i].IsConnected())
637 : {
638 18 : const Inet::IPAddress & ipAddress = mActiveConnections[i].mPeerAddr.GetIPAddress();
639 18 : uint16_t port = mActiveConnections[i].mPeerAddr.GetPort();
640 :
641 : // Ignoring the InterfaceID in the check as it may not have been provided in
642 : // the PeerAddress during connection establishment. The IPAddress and Port
643 : // are the necessary and sufficient set of parameters for searching
644 : // through the connections.
645 18 : if (ipAddress == address.GetIPAddress() && port == address.GetPort() && address.GetTransportType() == Type::kTcp)
646 : {
647 : // NOTE: this leaves the socket in TIME_WAIT.
648 : // Calling Abort() would clean it since SO_LINGER would be set to 0,
649 : // however this seems not to be useful.
650 9 : CloseConnectionInternal(&mActiveConnections[i], CHIP_NO_ERROR, SuppressCallback::Yes);
651 : }
652 : }
653 : }
654 10 : }
655 :
656 0 : void TCPBase::TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort)
657 : {
658 :
659 0 : if (conn == nullptr)
660 : {
661 0 : ChipLogError(Inet, "Failed to Disconnect. Passed in Connection is null.");
662 0 : return;
663 : }
664 :
665 : // This call should be able to disconnect the connection either when it is
666 : // already established, or when it is being set up.
667 0 : if ((conn->IsConnected() && shouldAbort) || conn->IsConnecting())
668 : {
669 0 : CloseConnectionInternal(conn, CHIP_ERROR_CONNECTION_ABORTED, SuppressCallback::Yes);
670 : }
671 :
672 0 : if (conn->IsConnected() && !shouldAbort)
673 : {
674 0 : CloseConnectionInternal(conn, CHIP_NO_ERROR, SuppressCallback::Yes);
675 : }
676 : }
677 :
678 29 : bool TCPBase::HasActiveConnections() const
679 : {
680 105 : for (size_t i = 0; i < mActiveConnectionsSize; i++)
681 : {
682 86 : if (mActiveConnections[i].IsConnected())
683 : {
684 10 : return true;
685 : }
686 : }
687 :
688 19 : return false;
689 : }
690 :
691 : } // namespace Transport
692 : } // namespace chip
|