Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2025 Project CHIP Authors
4 : * Copyright (c) 2013-2018 Nest Labs, Inc.
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 : * This file implements Inet::TCPEndPoint using sockets.
21 : */
22 :
23 : #include <inet/TCPEndPointImplSockets.h>
24 :
25 : #include <inet/InetFaultInjection.h>
26 : #include <inet/arpa-inet-compatibility.h>
27 :
28 : #include <lib/support/CodeUtils.h>
29 : #include <lib/support/SafeInt.h>
30 : #include <lib/support/logging/CHIPLogging.h>
31 : #include <system/SystemFaultInjection.h>
32 :
33 : #include <stdio.h>
34 : #include <string.h>
35 : #include <utility>
36 :
37 : #include <errno.h>
38 : #include <fcntl.h>
39 : #include <net/if.h>
40 : #include <netinet/tcp.h>
41 : #include <sys/ioctl.h>
42 : #include <sys/select.h>
43 : #include <sys/socket.h>
44 : #include <unistd.h>
45 :
46 : // SOCK_CLOEXEC not defined on all platforms, e.g. iOS/macOS:
47 : #ifndef SOCK_CLOEXEC
48 : #define SOCK_CLOEXEC 0
49 : #endif
50 :
51 : #if defined(SOL_TCP)
52 : // socket option level for Linux and BSD systems.
53 : #define TCP_SOCKOPT_LEVEL SOL_TCP
54 : #else
55 : // socket option level for macOS & iOS systems.
56 : #define TCP_SOCKOPT_LEVEL IPPROTO_TCP
57 : #endif
58 :
59 : #if defined(TCP_KEEPIDLE)
60 : // socket option for Linux and BSD systems.
61 : #define TCP_IDLE_INTERVAL_OPT_NAME TCP_KEEPIDLE
62 : #else
63 : // socket option for macOS & iOS systems.
64 : #define TCP_IDLE_INTERVAL_OPT_NAME TCP_KEEPALIVE
65 : #endif
66 :
67 : namespace chip {
68 : namespace Inet {
69 :
70 24 : CHIP_ERROR TCPEndPointImplSockets::BindImpl(IPAddressType addrType, const IPAddress & addr, uint16_t port, bool reuseAddr)
71 : {
72 24 : CHIP_ERROR res = GetSocket(addrType);
73 :
74 48 : if (res == CHIP_NO_ERROR && reuseAddr)
75 : {
76 1 : int n = 1;
77 1 : setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
78 :
79 : #ifdef SO_REUSEPORT
80 : // Enable SO_REUSEPORT. This permits coexistence between an
81 : // untargetted CHIP client and other services that listen on
82 : // a CHIP port on a specific address (such as a CHIP client
83 : // with TARGETED_LISTEN or TCP proxying services). Note that
84 : // one of the costs of this implementation is the
85 : // non-deterministic connection dispatch when multple clients
86 : // listen on the address with the same degreee of selectivity,
87 : // e.g. two untargetted-listen CHIP clients, or two
88 : // targeted-listen CHIP clients with the same node id.
89 :
90 1 : if (setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &n, sizeof(n)) != 0)
91 : {
92 0 : ChipLogError(Inet, "SO_REUSEPORT: %d", errno);
93 : }
94 : #endif // defined(SO_REUSEPORT)
95 : }
96 :
97 48 : if (res == CHIP_NO_ERROR)
98 : {
99 : SockAddr sa;
100 23 : memset(&sa, 0, sizeof(sa));
101 23 : socklen_t sockaddrsize = 0;
102 :
103 23 : if (addrType == IPAddressType::kIPv6)
104 : {
105 13 : sa.in6.sin6_family = AF_INET6;
106 13 : sa.in6.sin6_port = htons(port);
107 13 : sa.in6.sin6_flowinfo = 0;
108 13 : sa.in6.sin6_addr = addr.ToIPv6();
109 13 : sa.in6.sin6_scope_id = 0;
110 :
111 13 : sockaddrsize = sizeof(sa.in6);
112 : }
113 : #if INET_CONFIG_ENABLE_IPV4
114 10 : else if (addrType == IPAddressType::kIPv4)
115 : {
116 10 : sa.in.sin_family = AF_INET;
117 10 : sa.in.sin_port = htons(port);
118 10 : sa.in.sin_addr = addr.ToIPv4();
119 :
120 10 : sockaddrsize = sizeof(sa.in);
121 : }
122 : #endif // INET_CONFIG_ENABLE_IPV4
123 : else
124 : {
125 0 : res = INET_ERROR_WRONG_ADDRESS_TYPE;
126 : }
127 :
128 46 : if (res == CHIP_NO_ERROR)
129 : {
130 : // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): GetSocket calls ensure mSocket is valid
131 23 : if (bind(mSocket, &sa.any, sockaddrsize) != 0)
132 : {
133 0 : res = CHIP_ERROR_POSIX(errno);
134 : }
135 : }
136 : }
137 :
138 24 : return res;
139 : }
140 :
141 23 : CHIP_ERROR TCPEndPointImplSockets::ListenImpl(uint16_t backlog)
142 : {
143 23 : if (listen(mSocket, backlog) != 0)
144 : {
145 0 : return CHIP_ERROR_POSIX(errno);
146 : }
147 :
148 : // Enable non-blocking mode for the socket.
149 23 : int flags = fcntl(mSocket, F_GETFL, 0);
150 23 : fcntl(mSocket, F_SETFL, flags | O_NONBLOCK);
151 :
152 : // Wait for ability to read on this endpoint.
153 23 : CHIP_ERROR res = static_cast<System::LayerSockets &>(GetSystemLayer())
154 23 : .SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this));
155 46 : if (res == CHIP_NO_ERROR)
156 : {
157 23 : res = static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingRead(mWatch);
158 : }
159 :
160 23 : return res;
161 : }
162 :
163 17 : CHIP_ERROR TCPEndPointImplSockets::ConnectImpl(const IPAddress & addr, uint16_t port, InterfaceId intfId)
164 : {
165 17 : IPAddressType addrType = addr.Type();
166 :
167 17 : ReturnErrorOnFailure(GetSocket(addrType));
168 :
169 17 : if (!intfId.IsPresent())
170 : {
171 : // The behavior when connecting to an IPv6 link-local address without specifying an outbound
172 : // interface is ambiguous. So prevent it in all cases.
173 17 : if (addr.IsIPv6LinkLocal())
174 : {
175 0 : return INET_ERROR_WRONG_ADDRESS_TYPE;
176 : }
177 : }
178 : else
179 : {
180 : // Try binding to the interface
181 :
182 : // If destination is link-local then there is no need to bind to
183 : // interface or address on the interface.
184 :
185 0 : if (!addr.IsIPv6LinkLocal())
186 : {
187 : #ifdef SO_BINDTODEVICE
188 : struct ::ifreq ifr;
189 0 : memset(&ifr, 0, sizeof(ifr));
190 :
191 0 : ReturnErrorOnFailure(intfId.GetInterfaceName(ifr.ifr_name, sizeof(ifr.ifr_name)));
192 :
193 : // Attempt to bind to the interface using SO_BINDTODEVICE which requires privileged access.
194 : // If the permission is denied(EACCES) because CHIP is running in a context
195 : // that does not have privileged access, choose a source address on the
196 : // interface to bind the connetion to.
197 0 : int r = setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
198 0 : if (r < 0 && errno != EACCES)
199 : {
200 0 : return CHIP_ERROR_POSIX(errno);
201 : }
202 :
203 0 : if (r < 0)
204 : #endif // SO_BINDTODEVICE
205 : {
206 : // Attempting to initiate a connection via a specific interface is not allowed.
207 : // The only way to do this is to bind the local to an address on the desired
208 : // interface.
209 0 : ReturnErrorOnFailure(BindSrcAddrFromIntf(addrType, intfId));
210 : }
211 : }
212 : }
213 :
214 : // Disable generation of SIGPIPE.
215 : #ifdef SO_NOSIGPIPE
216 : int n = 1;
217 : setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &n, sizeof(n));
218 : #endif // defined(SO_NOSIGPIPE)
219 :
220 : // Enable non-blocking mode for the socket.
221 17 : int flags = fcntl(mSocket, F_GETFL, 0);
222 17 : fcntl(mSocket, F_SETFL, flags | O_NONBLOCK);
223 :
224 17 : socklen_t sockaddrsize = 0;
225 :
226 : SockAddr sa;
227 17 : memset(&sa, 0, sizeof(sa));
228 :
229 17 : if (addrType == IPAddressType::kIPv6)
230 : {
231 9 : sa.in6.sin6_family = AF_INET6;
232 9 : sa.in6.sin6_port = htons(port);
233 9 : sa.in6.sin6_flowinfo = 0;
234 9 : sa.in6.sin6_addr = addr.ToIPv6();
235 9 : sa.in6.sin6_scope_id = intfId.GetPlatformInterface();
236 9 : sockaddrsize = sizeof(sockaddr_in6);
237 : }
238 : #if INET_CONFIG_ENABLE_IPV4
239 8 : else if (addrType == IPAddressType::kIPv4)
240 : {
241 8 : sa.in.sin_family = AF_INET;
242 8 : sa.in.sin_port = htons(port);
243 8 : sa.in.sin_addr = addr.ToIPv4();
244 8 : sockaddrsize = sizeof(sockaddr_in);
245 : }
246 : #endif // INET_CONFIG_ENABLE_IPV4
247 : else
248 : {
249 0 : return INET_ERROR_WRONG_ADDRESS_TYPE;
250 : }
251 :
252 : // NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions): GetSocket calls ensure mSocket is valid
253 17 : int conRes = connect(mSocket, &sa.any, sockaddrsize);
254 :
255 17 : if (conRes == -1 && errno != EINPROGRESS)
256 : {
257 0 : CHIP_ERROR res = CHIP_ERROR_POSIX(errno);
258 0 : DoClose(res, true);
259 0 : return res;
260 : }
261 :
262 17 : ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer())
263 : .SetCallback(mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(this)));
264 :
265 17 : TCPEndPointHandle handle(this);
266 17 : if (conRes == 0)
267 : {
268 0 : mState = State::kConnected;
269 : // Wait for ability to read on this endpoint.
270 0 : ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingRead(mWatch));
271 0 : if (OnConnectComplete != nullptr)
272 : {
273 0 : OnConnectComplete(handle, CHIP_NO_ERROR);
274 : }
275 : }
276 : else
277 : {
278 17 : mState = State::kConnecting;
279 : // Wait for ability to write on this endpoint.
280 17 : ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingWrite(mWatch));
281 : }
282 :
283 17 : return CHIP_NO_ERROR;
284 17 : }
285 :
286 29 : CHIP_ERROR TCPEndPointImplSockets::GetPeerInfo(IPAddress * retAddr, uint16_t * retPort) const
287 : {
288 29 : return GetSocketInfo(getpeername, retAddr, retPort);
289 : }
290 :
291 1 : CHIP_ERROR TCPEndPointImplSockets::GetLocalInfo(IPAddress * retAddr, uint16_t * retPort) const
292 : {
293 1 : return GetSocketInfo(getsockname, retAddr, retPort);
294 : }
295 :
296 30 : CHIP_ERROR TCPEndPointImplSockets::GetSocketInfo(int getname(int, sockaddr *, socklen_t *), IPAddress * retAddr,
297 : uint16_t * retPort) const
298 : {
299 30 : VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
300 :
301 : SockAddr sa;
302 28 : memset(&sa, 0, sizeof(sa));
303 28 : socklen_t saLen = sizeof(sa);
304 :
305 28 : if (getname(mSocket, &sa.any, &saLen) != 0)
306 : {
307 0 : return CHIP_ERROR_POSIX(errno);
308 : }
309 :
310 28 : if (sa.any.sa_family == AF_INET6)
311 : {
312 16 : *retAddr = IPAddress(sa.in6.sin6_addr);
313 16 : *retPort = ntohs(sa.in6.sin6_port);
314 16 : return CHIP_NO_ERROR;
315 : }
316 :
317 : #if INET_CONFIG_ENABLE_IPV4
318 12 : if (sa.any.sa_family == AF_INET)
319 : {
320 12 : *retAddr = IPAddress(sa.in.sin_addr);
321 12 : *retPort = ntohs(sa.in.sin_port);
322 12 : return CHIP_NO_ERROR;
323 : }
324 : #endif // INET_CONFIG_ENABLE_IPV4
325 :
326 0 : return CHIP_ERROR_INCORRECT_STATE;
327 : }
328 :
329 22 : CHIP_ERROR TCPEndPointImplSockets::GetInterfaceId(InterfaceId * retInterface)
330 : {
331 22 : VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
332 :
333 : SockAddr sa;
334 22 : memset(&sa, 0, sizeof(sa));
335 22 : socklen_t saLen = sizeof(sa);
336 :
337 22 : if (getpeername(mSocket, &sa.any, &saLen) != 0)
338 : {
339 0 : return CHIP_ERROR_POSIX(errno);
340 : }
341 :
342 22 : if (sa.any.sa_family == AF_INET6)
343 : {
344 12 : if (IPAddress(sa.in6.sin6_addr).IsIPv6LinkLocal())
345 : {
346 0 : *retInterface = InterfaceId(sa.in6.sin6_scope_id);
347 : }
348 : else
349 : {
350 : // TODO: Is there still a meaningful interface id in this case?
351 12 : *retInterface = InterfaceId::Null();
352 : }
353 12 : return CHIP_NO_ERROR;
354 : }
355 :
356 : #if INET_CONFIG_ENABLE_IPV4
357 10 : if (sa.any.sa_family == AF_INET)
358 : {
359 : // No interface id available for IPv4 sockets.
360 10 : *retInterface = InterfaceId::Null();
361 10 : return CHIP_NO_ERROR;
362 : }
363 : #endif // INET_CONFIG_ENABLE_IPV4
364 :
365 0 : *retInterface = InterfaceId::Null();
366 0 : return INET_ERROR_WRONG_ADDRESS_TYPE;
367 : }
368 :
369 11 : CHIP_ERROR TCPEndPointImplSockets::SendQueuedImpl(bool queueWasEmpty)
370 : {
371 11 : if (queueWasEmpty)
372 : {
373 : // Wait for ability to write on this endpoint.
374 11 : return static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingWrite(mWatch);
375 : }
376 0 : return CHIP_NO_ERROR;
377 : }
378 :
379 30 : CHIP_ERROR TCPEndPointImplSockets::EnableNoDelay()
380 : {
381 30 : VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
382 :
383 : #ifdef TCP_NODELAY
384 : // Disable TCP Nagle buffering by setting TCP_NODELAY socket option to true
385 30 : int val = 1;
386 30 : if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_NODELAY, &val, sizeof(val)) != 0)
387 : {
388 0 : return CHIP_ERROR_POSIX(errno);
389 : }
390 : #endif // defined(TCP_NODELAY)
391 :
392 30 : return CHIP_NO_ERROR;
393 : }
394 :
395 31 : CHIP_ERROR TCPEndPointImplSockets::EnableKeepAlive(uint16_t interval, uint16_t timeoutCount)
396 : {
397 31 : VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
398 :
399 : // Set the idle interval
400 30 : int val = interval;
401 30 : if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_IDLE_INTERVAL_OPT_NAME, &val, sizeof(val)) != 0)
402 : {
403 0 : return CHIP_ERROR_POSIX(errno);
404 : }
405 :
406 : // Set the probe retransmission interval.
407 30 : val = interval;
408 30 : if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_KEEPINTVL, &val, sizeof(val)) != 0)
409 : {
410 0 : return CHIP_ERROR_POSIX(errno);
411 : }
412 :
413 : // Set the probe timeout count
414 30 : val = timeoutCount;
415 30 : if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_KEEPCNT, &val, sizeof(val)) != 0)
416 : {
417 0 : return CHIP_ERROR_POSIX(errno);
418 : }
419 :
420 : // Enable keepalives for the connection.
421 30 : val = 1; // enable
422 30 : if (setsockopt(mSocket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) != 0)
423 : {
424 0 : return CHIP_ERROR_POSIX(errno);
425 : }
426 :
427 30 : return CHIP_NO_ERROR;
428 : }
429 :
430 1 : CHIP_ERROR TCPEndPointImplSockets::DisableKeepAlive()
431 : {
432 1 : VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
433 :
434 : // Disable keepalives on the connection.
435 0 : int val = 0; // disable
436 0 : if (setsockopt(mSocket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) != 0)
437 : {
438 0 : return CHIP_ERROR_POSIX(errno);
439 : }
440 :
441 0 : return CHIP_NO_ERROR;
442 : }
443 :
444 10 : CHIP_ERROR TCPEndPointImplSockets::AckReceive(size_t len)
445 : {
446 10 : VerifyOrReturnError(IsConnected(), CHIP_ERROR_INCORRECT_STATE);
447 :
448 : // nothing to do for sockets case
449 9 : return CHIP_NO_ERROR;
450 : }
451 :
452 0 : CHIP_ERROR TCPEndPointImplSockets::SetUserTimeoutImpl(uint32_t userTimeoutMillis)
453 : {
454 : #if defined(TCP_USER_TIMEOUT)
455 : // Set the user timeout
456 0 : uint32_t val = userTimeoutMillis;
457 0 : if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_USER_TIMEOUT, &val, sizeof(val)) != 0)
458 : {
459 0 : return CHIP_ERROR_POSIX(errno);
460 : }
461 0 : return CHIP_NO_ERROR;
462 : #else // TCP_USER_TIMEOUT
463 : return CHIP_ERROR_NOT_IMPLEMENTED;
464 : #endif // defined(TCP_USER_TIMEOUT)
465 : }
466 :
467 11 : CHIP_ERROR TCPEndPointImplSockets::DriveSendingImpl()
468 : {
469 11 : CHIP_ERROR err = CHIP_NO_ERROR;
470 :
471 : #ifdef MSG_NOSIGNAL
472 11 : const int sendFlags = MSG_NOSIGNAL;
473 : #else
474 : const int sendFlags = 0;
475 : #endif
476 :
477 : // Pretend send() fails in the while loop below
478 11 : INET_FAULT_INJECT(FaultInjection::kFault_Send, {
479 : err = CHIP_ERROR_POSIX(EIO);
480 : DoClose(err, false);
481 : return err;
482 : });
483 :
484 11 : TCPEndPointHandle handle(this);
485 24 : while (!mSendQueue.IsNull())
486 : {
487 13 : size_t bufLen = mSendQueue->DataLength();
488 :
489 13 : ssize_t lenSentRaw = send(mSocket, mSendQueue->Start(), bufLen, sendFlags);
490 :
491 13 : if (lenSentRaw == -1)
492 : {
493 0 : if (errno != EAGAIN && errno != EWOULDBLOCK)
494 : {
495 0 : err = (errno == EPIPE) ? INET_ERROR_PEER_DISCONNECTED : CHIP_ERROR_POSIX(errno);
496 : }
497 0 : break;
498 : }
499 :
500 13 : if (lenSentRaw < 0 || bufLen < static_cast<size_t>(lenSentRaw))
501 : {
502 0 : err = CHIP_ERROR_INCORRECT_STATE;
503 0 : break;
504 : }
505 :
506 13 : size_t lenSent = static_cast<size_t>(lenSentRaw);
507 :
508 : // Mark the connection as being active.
509 13 : MarkActive();
510 :
511 13 : if (lenSent < bufLen)
512 : {
513 0 : mSendQueue->ConsumeHead(lenSent);
514 : }
515 : else
516 : {
517 13 : mSendQueue.FreeHead();
518 13 : if (mSendQueue.IsNull())
519 : {
520 : // Do not wait for ability to write on this endpoint.
521 11 : err = static_cast<System::LayerSockets &>(GetSystemLayer()).ClearCallbackOnPendingWrite(mWatch);
522 22 : if (err != CHIP_NO_ERROR)
523 : {
524 0 : break;
525 : }
526 : }
527 : }
528 :
529 13 : if (OnDataSent != nullptr)
530 : {
531 0 : OnDataSent(handle, lenSent);
532 : }
533 :
534 : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
535 13 : mBytesWrittenSinceLastProbe += lenSent;
536 :
537 13 : bool isProgressing = false;
538 :
539 13 : err = CheckConnectionProgress(isProgressing);
540 26 : if (err != CHIP_NO_ERROR)
541 : {
542 0 : break;
543 : }
544 :
545 13 : if (!mUserTimeoutTimerRunning)
546 : {
547 : // Timer was not running before this write. So, start
548 : // the timer.
549 :
550 9 : StartTCPUserTimeoutTimer();
551 : }
552 4 : else if (isProgressing)
553 : {
554 : // Progress is being made. So, shift the timer
555 : // forward if it was started.
556 :
557 4 : RestartTCPUserTimeoutTimer();
558 : }
559 : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
560 :
561 13 : if (lenSent < bufLen)
562 : {
563 0 : break;
564 : }
565 : }
566 :
567 22 : if (err == CHIP_NO_ERROR)
568 : {
569 : // If we're in the SendShutdown state and the send queue is now empty, shutdown writing on the socket.
570 11 : if (mState == State::kSendShutdown && mSendQueue.IsNull())
571 : {
572 0 : if (shutdown(mSocket, SHUT_WR) != 0)
573 : {
574 0 : err = CHIP_ERROR_POSIX(errno);
575 : }
576 : }
577 : }
578 :
579 11 : return err;
580 11 : }
581 :
582 17 : void TCPEndPointImplSockets::HandleConnectCompleteImpl()
583 : {
584 : // Wait for ability to read or write on this endpoint.
585 17 : CHIP_ERROR err = static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingRead(mWatch);
586 34 : if (err == CHIP_NO_ERROR)
587 : {
588 17 : err = static_cast<System::LayerSockets &>(GetSystemLayer()).RequestCallbackOnPendingWrite(mWatch);
589 : }
590 34 : if (err != CHIP_NO_ERROR)
591 : {
592 0 : DoClose(err, false);
593 0 : return;
594 : }
595 : }
596 :
597 60 : void TCPEndPointImplSockets::DoCloseImpl(CHIP_ERROR err, State oldState)
598 : {
599 : struct linger lingerStruct;
600 :
601 : // If the socket hasn't been closed already...
602 60 : if (mSocket != kInvalidSocketFd)
603 : {
604 : // If entering the Closed state
605 : // OR if entering the Closing state, and there's no unsent data in the send queue
606 : // THEN close the socket.
607 55 : if (mState == State::kClosed || (mState == State::kClosing && mSendQueue.IsNull()))
608 : {
609 : // If aborting the connection, ensure we send a TCP RST.
610 87 : if (IsConnected(oldState) && err != CHIP_NO_ERROR)
611 : {
612 26 : lingerStruct.l_onoff = 1;
613 26 : lingerStruct.l_linger = 0;
614 :
615 26 : if (setsockopt(mSocket, SOL_SOCKET, SO_LINGER, &lingerStruct, sizeof(lingerStruct)) != 0)
616 : {
617 0 : ChipLogError(Inet, "SO_LINGER: %d", errno);
618 : }
619 : }
620 :
621 55 : TEMPORARY_RETURN_IGNORED static_cast<System::LayerSockets &>(GetSystemLayer()).StopWatchingSocket(&mWatch);
622 55 : close(mSocket);
623 55 : mSocket = kInvalidSocketFd;
624 : }
625 : }
626 60 : }
627 :
628 : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
629 0 : void TCPEndPointImplSockets::TCPUserTimeoutHandler()
630 : {
631 : // Set the timer running flag to false
632 0 : mUserTimeoutTimerRunning = false;
633 :
634 0 : bool isProgressing = false;
635 0 : CHIP_ERROR err = CheckConnectionProgress(isProgressing);
636 :
637 0 : if (err == CHIP_NO_ERROR && mLastTCPKernelSendQueueLen != 0)
638 : {
639 : // There is data in the TCP Send Queue
640 0 : if (isProgressing)
641 : {
642 : // Data is flowing, so restart the UserTimeout timer
643 : // to shift it forward while also resetting the max
644 : // poll count.
645 :
646 0 : StartTCPUserTimeoutTimer();
647 : }
648 : else
649 : {
650 : // Close the connection as the TCP UserTimeout has expired
651 0 : err = INET_ERROR_TCP_USER_TIMEOUT;
652 : }
653 : }
654 :
655 0 : if (err != CHIP_NO_ERROR)
656 : {
657 : // Close the connection as the TCP UserTimeout has expired
658 0 : DoClose(err, false);
659 : }
660 0 : }
661 : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
662 :
663 0 : CHIP_ERROR TCPEndPointImplSockets::BindSrcAddrFromIntf(IPAddressType addrType, InterfaceId intfId)
664 : {
665 : // If we are trying to make a TCP connection over a 'specified target interface',
666 : // then we bind the TCPEndPoint to an IP address on that target interface
667 : // and use that address as the source address for that connection. This is
668 : // done in the event that directly binding the connection to the target
669 : // interface is not allowed due to insufficient privileges.
670 0 : VerifyOrReturnError(mState != State::kBound, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
671 :
672 0 : bool ipAddrFound = false;
673 0 : for (InterfaceAddressIterator addrIter; addrIter.HasCurrent(); addrIter.Next())
674 : {
675 : IPAddress curAddr;
676 0 : if ((addrIter.GetInterfaceId() == intfId) && (addrIter.GetAddress(curAddr) == CHIP_NO_ERROR))
677 : {
678 : // Search for an IPv4 address on the TargetInterface
679 :
680 : #if INET_CONFIG_ENABLE_IPV4
681 0 : if (addrType == IPAddressType::kIPv4)
682 : {
683 0 : if (curAddr.IsIPv4())
684 : {
685 : // Bind to the IPv4 address of the TargetInterface
686 0 : ipAddrFound = true;
687 0 : ReturnErrorOnFailure(Bind(IPAddressType::kIPv4, curAddr, 0, true));
688 :
689 0 : break;
690 : }
691 : }
692 : #endif // INET_CONFIG_ENABLE_IPV4
693 0 : if (addrType == IPAddressType::kIPv6)
694 : {
695 : // Select an IPv6 address on the interface that is not
696 : // a link local or a multicast address.
697 : // TODO: Define a proper IPv6GlobalUnicast address checker.
698 0 : if (!curAddr.IsIPv4() && !curAddr.IsIPv6LinkLocal() && !curAddr.IsMulticast())
699 : {
700 : // Bind to the IPv6 address of the TargetInterface
701 0 : ipAddrFound = true;
702 0 : ReturnErrorOnFailure(Bind(IPAddressType::kIPv6, curAddr, 0, true));
703 :
704 0 : break;
705 : }
706 : }
707 : }
708 0 : }
709 :
710 0 : VerifyOrReturnError(ipAddrFound, CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
711 :
712 0 : return CHIP_NO_ERROR;
713 : }
714 :
715 41 : CHIP_ERROR TCPEndPointImplSockets::GetSocket(IPAddressType addrType)
716 : {
717 41 : if (mSocket == kInvalidSocketFd)
718 : {
719 : int family;
720 41 : if (addrType == IPAddressType::kIPv6)
721 : {
722 22 : family = PF_INET6;
723 : #if INET_CONFIG_ENABLE_IPV4
724 : }
725 19 : else if (addrType == IPAddressType::kIPv4)
726 : {
727 18 : family = PF_INET;
728 : #endif // INET_CONFIG_ENABLE_IPV4
729 : }
730 : else
731 : {
732 1 : return INET_ERROR_WRONG_ADDRESS_TYPE;
733 : }
734 40 : mSocket = ::socket(family, SOCK_STREAM | SOCK_CLOEXEC, 0);
735 40 : if (mSocket == -1)
736 : {
737 0 : return CHIP_ERROR_POSIX(errno);
738 : }
739 0 : auto connectionCleanup = ScopeExit([&]() {
740 0 : close(mSocket);
741 0 : mSocket = kInvalidSocketFd;
742 40 : });
743 40 : ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer()).StartWatchingSocket(mSocket, &mWatch));
744 : auto watchCleanup = ScopeExit(
745 40 : [&]() { TEMPORARY_RETURN_IGNORED static_cast<System::LayerSockets &>(GetSystemLayer()).StopWatchingSocket(&mWatch); });
746 40 : mAddrType = addrType;
747 :
748 : // If creating an IPv6 socket, tell the kernel that it will be IPv6 only. This makes it
749 : // posible to bind two sockets to the same port, one for IPv4 and one for IPv6.
750 : #ifdef IPV6_V6ONLY
751 40 : if (family == PF_INET6)
752 : {
753 22 : int one = 1;
754 22 : setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
755 : }
756 : #endif // defined(IPV6_V6ONLY)
757 :
758 : // On systems that support it, disable the delivery of SIGPIPE signals when writing to a closed
759 : // socket.
760 : #ifdef SO_NOSIGPIPE
761 : {
762 : int one = 1;
763 : int res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
764 : if (res != 0)
765 : {
766 : ChipLogError(Inet, "SO_NOSIGPIPE: %d", errno);
767 : }
768 : }
769 : #endif // defined(SO_NOSIGPIPE)
770 40 : watchCleanup.release();
771 40 : connectionCleanup.release();
772 40 : }
773 0 : else if (mAddrType != addrType)
774 : {
775 0 : return CHIP_ERROR_INCORRECT_STATE;
776 : }
777 :
778 40 : return CHIP_NO_ERROR;
779 : }
780 :
781 : // static
782 52 : void TCPEndPointImplSockets::HandlePendingIO(System::SocketEvents events, intptr_t data)
783 : {
784 52 : reinterpret_cast<TCPEndPointImplSockets *>(data)->HandlePendingIO(events);
785 52 : }
786 :
787 52 : void TCPEndPointImplSockets::HandlePendingIO(System::SocketEvents events)
788 : {
789 : // Prevent the end point from being freed while in the middle of a callback.
790 52 : TCPEndPointHandle handle(this);
791 :
792 : // If in the Listening state, and the app is ready to receive a connection, and there is a connection
793 : // ready to be received on the socket, process the incoming connection.
794 52 : if (mState == State::kListening)
795 : {
796 17 : if (OnConnectionReceived != nullptr && events.Has(System::SocketEventFlags::kRead))
797 : {
798 17 : CHIP_ERROR error = HandleIncomingConnection();
799 34 : if (error != CHIP_NO_ERROR && OnAcceptError != nullptr)
800 : {
801 2 : OnAcceptError(handle, error);
802 : }
803 : }
804 : }
805 :
806 : // If in the processes of initiating a connection...
807 35 : else if (mState == State::kConnecting)
808 : {
809 : // The socket being writable indicates the connection has completed (successfully or otherwise).
810 17 : if (events.Has(System::SocketEventFlags::kWrite))
811 : {
812 : #ifndef __MBED__
813 : // Get the connection result from the socket.
814 : int osConRes;
815 17 : socklen_t optLen = sizeof(osConRes);
816 17 : if (getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &osConRes, &optLen) != 0)
817 : {
818 0 : osConRes = errno;
819 : }
820 : #else // __MBED__
821 : // On Mbed OS, connect blocks and never returns EINPROGRESS
822 : // The socket option SO_ERROR is not available.
823 : int osConRes = 0;
824 : #endif // !__MBED__
825 17 : CHIP_ERROR conRes = CHIP_ERROR_POSIX(osConRes);
826 :
827 : // Process the connection result.
828 17 : HandleConnectComplete(conRes);
829 : }
830 : }
831 :
832 : else
833 : {
834 : // If in a state where sending is allowed, and there is data to be sent, and the socket is ready for
835 : // writing, drive outbound data into the connection.
836 18 : if (IsConnected() && !mSendQueue.IsNull() && events.Has(System::SocketEventFlags::kWrite))
837 : {
838 0 : TEMPORARY_RETURN_IGNORED DriveSending();
839 : }
840 :
841 : // If in a state were receiving is allowed, and the app is ready to receive data, and data is ready
842 : // on the socket, receive inbound data from the connection.
843 36 : if ((mState == State::kConnected || mState == State::kSendShutdown) && mReceiveEnabled && OnDataReceived != nullptr &&
844 18 : events.Has(System::SocketEventFlags::kRead))
845 : {
846 16 : ReceiveData();
847 : }
848 : }
849 52 : }
850 :
851 16 : void TCPEndPointImplSockets::ReceiveData()
852 : {
853 16 : System::PacketBufferHandle rcvBuf;
854 16 : bool isNewBuf = true;
855 :
856 16 : if (mRcvQueue.IsNull())
857 : {
858 16 : rcvBuf = System::PacketBufferHandle::New(kMaxReceiveMessageSize, 0);
859 : }
860 : else
861 : {
862 0 : rcvBuf = mRcvQueue->Last();
863 0 : if (rcvBuf->AvailableDataLength() == 0)
864 : {
865 0 : rcvBuf = System::PacketBufferHandle::New(kMaxReceiveMessageSize, 0);
866 : }
867 : else
868 : {
869 0 : isNewBuf = false;
870 0 : rcvBuf->CompactHead();
871 : }
872 : }
873 :
874 16 : if (rcvBuf.IsNull())
875 : {
876 0 : DoClose(CHIP_ERROR_NO_MEMORY, false);
877 0 : return;
878 : }
879 :
880 : // Attempt to receive data from the socket.
881 16 : ssize_t rcvLen = recv(mSocket, rcvBuf->Start() + rcvBuf->DataLength(), rcvBuf->AvailableDataLength(), 0);
882 :
883 : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
884 : CHIP_ERROR err;
885 16 : bool isProgressing = false;
886 :
887 16 : err = CheckConnectionProgress(isProgressing);
888 32 : if (err != CHIP_NO_ERROR)
889 : {
890 0 : DoClose(err, false);
891 :
892 0 : return;
893 : }
894 :
895 16 : if (mLastTCPKernelSendQueueLen == 0)
896 : {
897 : // If the output queue has been flushed then stop the timer.
898 :
899 16 : StopTCPUserTimeoutTimer();
900 : }
901 0 : else if (isProgressing && mUserTimeoutTimerRunning)
902 : {
903 : // Progress is being made. So, shift the timer
904 : // forward if it was started.
905 0 : RestartTCPUserTimeoutTimer();
906 : }
907 : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
908 16 : TCPEndPointHandle handle(this);
909 : // If an error occurred, abort the connection.
910 16 : if (rcvLen < 0)
911 : {
912 5 : int systemErrno = errno;
913 5 : if (systemErrno == EAGAIN)
914 : {
915 : // Note: in this case, we opt to not retry the recv call,
916 : // and instead we expect that the read flags will get
917 : // reset correctly upon a subsequent return from the
918 : // select call.
919 0 : ChipLogError(Inet, "recv: EAGAIN, will retry");
920 :
921 0 : return;
922 : }
923 :
924 5 : DoClose(CHIP_ERROR_POSIX(systemErrno), false);
925 : }
926 : else
927 : {
928 : // Mark the connection as being active.
929 11 : MarkActive();
930 :
931 : // If the peer closed their end of the connection...
932 11 : if (rcvLen == 0)
933 : {
934 : // If in the Connected state and the app has provided an OnPeerClose callback,
935 : // enter the ReceiveShutdown state. Providing an OnPeerClose callback allows
936 : // the app to decide whether to keep the send side of the connection open after
937 : // the peer has closed. If no OnPeerClose is provided, we assume that the app
938 : // wants to close both directions and automatically enter the Closing state.
939 2 : if (mState == State::kConnected && OnPeerClose != nullptr)
940 : {
941 0 : mState = State::kReceiveShutdown;
942 : }
943 : else
944 : {
945 2 : mState = State::kClosing;
946 : }
947 : // Do not wait for ability to read on this endpoint.
948 2 : (void) static_cast<System::LayerSockets &>(GetSystemLayer()).ClearCallbackOnPendingRead(mWatch);
949 : // Call the app's OnPeerClose.
950 2 : if (OnPeerClose != nullptr)
951 : {
952 0 : OnPeerClose(handle);
953 : }
954 : }
955 :
956 : // Otherwise, add the new data onto the receive queue.
957 : else
958 : {
959 9 : VerifyOrDie(rcvLen > 0);
960 9 : size_t newDataLength = rcvBuf->DataLength() + static_cast<size_t>(rcvLen);
961 9 : if (isNewBuf)
962 : {
963 9 : rcvBuf->SetDataLength(newDataLength);
964 9 : rcvBuf.RightSize();
965 9 : if (mRcvQueue.IsNull())
966 : {
967 9 : mRcvQueue = std::move(rcvBuf);
968 : }
969 : else
970 : {
971 0 : mRcvQueue->AddToEnd(std::move(rcvBuf));
972 : }
973 : }
974 : else
975 : {
976 0 : rcvBuf->SetDataLength(newDataLength, mRcvQueue);
977 : }
978 : }
979 : }
980 :
981 : // Drive any received data into the app.
982 16 : DriveReceiving(handle);
983 16 : }
984 :
985 17 : CHIP_ERROR TCPEndPointImplSockets::HandleIncomingConnection()
986 : {
987 : IPAddress peerAddr;
988 : uint16_t peerPort;
989 :
990 : SockAddr sa;
991 17 : memset(&sa, 0, sizeof(sa));
992 17 : socklen_t saLen = sizeof(sa);
993 :
994 : // Accept the new connection.
995 17 : int conSocket = accept(mSocket, &sa.any, &saLen);
996 2 : auto failureCleanup = ScopeExit([&] {
997 2 : if (conSocket != -1)
998 : {
999 2 : close(conSocket);
1000 : }
1001 17 : });
1002 :
1003 17 : if (conSocket == -1)
1004 : {
1005 0 : if (errno == EAGAIN || errno == EWOULDBLOCK)
1006 : {
1007 0 : return CHIP_NO_ERROR;
1008 : }
1009 :
1010 0 : return CHIP_ERROR_POSIX(errno);
1011 : }
1012 :
1013 : #ifdef __APPLE__
1014 : // On Darwin, if the client closes the connection just as it is being accepted, it is
1015 : // possible for accept() to return a socket but saLen is 0. Ignore the connection.
1016 : VerifyOrReturnError(saLen != 0, CHIP_NO_ERROR);
1017 : #endif
1018 :
1019 : // If there's no callback available, fail with an error.
1020 17 : VerifyOrReturnError(OnConnectionReceived != nullptr, CHIP_ERROR_NO_CONNECTION_HANDLER);
1021 :
1022 : // Extract the peer's address information.
1023 17 : if (sa.any.sa_family == AF_INET6)
1024 : {
1025 9 : peerAddr = IPAddress(sa.in6.sin6_addr);
1026 9 : peerPort = ntohs(sa.in6.sin6_port);
1027 : }
1028 : #if INET_CONFIG_ENABLE_IPV4
1029 8 : else if (sa.any.sa_family == AF_INET)
1030 : {
1031 8 : peerAddr = IPAddress(sa.in.sin_addr);
1032 8 : peerPort = ntohs(sa.in.sin_port);
1033 : }
1034 : #endif // INET_CONFIG_ENABLE_IPV4
1035 : else
1036 : {
1037 0 : return CHIP_ERROR_INCORRECT_STATE;
1038 : }
1039 :
1040 : #if INET_CONFIG_TEST
1041 17 : if (TCPEndPoint::sForceEarlyFailureIncomingConnection)
1042 : {
1043 2 : return CHIP_ERROR_INCORRECT_STATE;
1044 : }
1045 : #endif
1046 :
1047 : // Attempt to allocate an end point object.
1048 15 : TCPEndPointHandle connectEndPoint;
1049 15 : ReturnErrorOnFailure(GetEndPointManager().NewEndPoint(connectEndPoint));
1050 15 : auto & conEP = static_cast<TCPEndPointImplSockets &>(*connectEndPoint);
1051 :
1052 : // If all went well...
1053 : // Put the new end point into the Connected state.
1054 15 : ReturnErrorOnFailure(static_cast<System::LayerSockets &>(GetSystemLayer()).StartWatchingSocket(conSocket, &conEP.mWatch));
1055 :
1056 15 : failureCleanup.release(); // Transfer ownership of socket to conEp
1057 15 : conEP.mSocket = conSocket;
1058 15 : conEP.mState = State::kConnected;
1059 : #if INET_CONFIG_ENABLE_IPV4
1060 15 : conEP.mAddrType = (sa.any.sa_family == AF_INET6) ? IPAddressType::kIPv6 : IPAddressType::kIPv4;
1061 : #else // !INET_CONFIG_ENABLE_IPV4
1062 : conEP.mAddrType = IPAddressType::kIPv6;
1063 : #endif // !INET_CONFIG_ENABLE_IPV4
1064 :
1065 : // Wait for ability to read on this endpoint.
1066 15 : auto & conEPLayer = static_cast<System::LayerSockets &>(conEP.GetSystemLayer());
1067 15 : ReturnErrorOnFailure(conEPLayer.SetCallback(conEP.mWatch, HandlePendingIO, reinterpret_cast<intptr_t>(&conEP)));
1068 :
1069 15 : ReturnErrorOnFailure(conEPLayer.RequestCallbackOnPendingRead(conEP.mWatch));
1070 :
1071 : // Call the app's callback function.
1072 15 : TCPEndPointHandle handle(this);
1073 15 : OnConnectionReceived(handle, connectEndPoint, peerAddr, peerPort);
1074 :
1075 15 : return CHIP_NO_ERROR;
1076 17 : }
1077 :
1078 : #if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1079 : /**
1080 : * This function probes the TCP output queue and checks if data is successfully
1081 : * being transferred to the other end.
1082 : */
1083 29 : CHIP_ERROR TCPEndPointImplSockets::CheckConnectionProgress(bool & isProgressing)
1084 : {
1085 29 : int currPendingBytesRaw = 0;
1086 : uint32_t currPendingBytes; // Will be initialized once we know it's safe.
1087 :
1088 : // Fetch the bytes pending successful transmission in the TCP out queue.
1089 :
1090 : #ifdef __APPLE__
1091 : socklen_t len = sizeof(currPendingBytesRaw);
1092 : if (getsockopt(mSocket, SOL_SOCKET, SO_NWRITE, &currPendingBytesRaw, &len) < 0)
1093 : #else
1094 29 : if (ioctl(mSocket, TIOCOUTQ, &currPendingBytesRaw) < 0)
1095 : #endif
1096 : {
1097 0 : return CHIP_ERROR_POSIX(errno);
1098 : }
1099 :
1100 29 : if (!CanCastTo<uint32_t>(currPendingBytesRaw))
1101 : {
1102 0 : return CHIP_ERROR_INCORRECT_STATE;
1103 : }
1104 :
1105 29 : currPendingBytes = static_cast<uint32_t>(currPendingBytesRaw);
1106 :
1107 29 : if ((currPendingBytes != 0) && (mBytesWrittenSinceLastProbe + mLastTCPKernelSendQueueLen == currPendingBytes))
1108 : {
1109 : // No progress has been made
1110 :
1111 0 : isProgressing = false;
1112 : }
1113 : else
1114 : {
1115 : // Data is flowing successfully
1116 :
1117 29 : isProgressing = true;
1118 : }
1119 :
1120 : // Reset the value of the bytes written since the last probe into the tcp
1121 : // outqueue was made and update the last tcp outqueue sample.
1122 :
1123 29 : mBytesWrittenSinceLastProbe = 0;
1124 :
1125 29 : mLastTCPKernelSendQueueLen = currPendingBytes;
1126 :
1127 29 : return CHIP_NO_ERROR;
1128 : }
1129 : #endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1130 :
1131 : } // namespace Inet
1132 : } // namespace chip
|