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