Coverage Report

Created: 2025-10-26 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openweave-core/src/inet/TCPEndPoint.cpp
Line
Count
Source
1
/*
2
 *
3
 *    Copyright (c) 2013-2018 Nest Labs, Inc.
4
 *    All rights reserved.
5
 *
6
 *    Licensed under the Apache License, Version 2.0 (the "License");
7
 *    you may not use this file except in compliance with the License.
8
 *    You may obtain a copy of the License at
9
 *
10
 *        http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 *    Unless required by applicable law or agreed to in writing, software
13
 *    distributed under the License is distributed on an "AS IS" BASIS,
14
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 *    See the License for the specific language governing permissions and
16
 *    limitations under the License.
17
 */
18
19
/**
20
 *    @file
21
 *      This file implements the <tt>nl::Inet::TCPEndPoint</tt> class,
22
 *      where the Nest Inet Layer encapsulates methods for interacting
23
 *      with TCP transport endpoints (SOCK_DGRAM sockets on Linux and
24
 *      BSD-derived systems) or LwIP TCP protocol control blocks, as
25
 *      the system is configured accordingly.
26
 *
27
 */
28
29
#define __APPLE_USE_RFC_3542
30
31
#ifndef __STDC_LIMIT_MACROS
32
#define __STDC_LIMIT_MACROS
33
#endif
34
35
#include <string.h>
36
#include <stdio.h>
37
38
#include <SystemLayer/SystemFaultInjection.h>
39
40
#include <InetLayer/TCPEndPoint.h>
41
#include <InetLayer/InetLayer.h>
42
#include <InetLayer/InetFaultInjection.h>
43
44
#include <Weave/Support/CodeUtils.h>
45
#include <Weave/Support/logging/WeaveLogging.h>
46
47
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
48
#include <lwip/tcp.h>
49
#include <lwip/tcpip.h>
50
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
51
52
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
53
#include <sys/socket.h>
54
#include <poll.h>
55
#include <net/if.h>
56
#include <sys/ioctl.h>
57
#include <unistd.h>
58
#include <fcntl.h>
59
#include <errno.h>
60
#include <netinet/tcp.h>
61
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
62
63
#include "arpa-inet-compatibility.h"
64
65
// SOCK_CLOEXEC not defined on all platforms, e.g. iOS/MacOS:
66
#ifdef SOCK_CLOEXEC
67
0
#define SOCK_FLAGS SOCK_CLOEXEC
68
#else
69
#define SOCK_FLAGS 0
70
#endif
71
72
#if defined(SOL_TCP)
73
// socket option level for Linux and BSD systems.
74
0
#define TCP_SOCKOPT_LEVEL SOL_TCP
75
#else
76
// socket option level for MacOS & iOS systems.
77
#define TCP_SOCKOPT_LEVEL IPPROTO_TCP
78
#endif
79
80
#if defined(TCP_KEEPIDLE)
81
// socket option for Linux and BSD systems.
82
0
#define TCP_IDLE_INTERVAL_OPT_NAME TCP_KEEPIDLE
83
#else
84
// socket option for MacOS & iOS systems.
85
#define TCP_IDLE_INTERVAL_OPT_NAME TCP_KEEPALIVE
86
#endif
87
88
/*
89
 * This logic to register a null operation callback with the LwIP TCP/IP task
90
 * ensures that the TCP timer loop is started when a connection is established,
91
 * which is necessary to ensure that initial SYN and SYN-ACK packets are
92
 * retransmitted during the 3-way handshake.
93
 */
94
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
95
namespace {
96
97
void nil_tcpip_callback(void * _aContext)
98
{ }
99
100
err_t start_tcp_timers(void)
101
{
102
    return tcpip_callback(nil_tcpip_callback, NULL);
103
}
104
105
} // anonymous namespace
106
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
107
108
namespace nl {
109
namespace Inet {
110
111
using Weave::System::PacketBuffer;
112
113
Weave::System::ObjectPool<TCPEndPoint, INET_CONFIG_NUM_TCP_ENDPOINTS> TCPEndPoint::sPool;
114
115
INET_ERROR TCPEndPoint::Bind(IPAddressType addrType, IPAddress addr, uint16_t port, bool reuseAddr)
116
0
{
117
0
    INET_ERROR res = INET_NO_ERROR;
118
119
0
    if (State != kState_Ready)
120
0
        return INET_ERROR_INCORRECT_STATE;
121
122
0
    if (addr != IPAddress::Any && addr.Type() != kIPAddressType_Any && addr.Type() != addrType)
123
0
        return INET_ERROR_WRONG_ADDRESS_TYPE;
124
125
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
126
127
    // Lock LwIP stack
128
    LOCK_TCPIP_CORE();
129
130
    // Get the appropriate type of PCB.
131
    res = GetPCB(addrType);
132
133
    // Bind the PCB to the specified address/port.
134
    if (res == INET_NO_ERROR)
135
    {
136
        if (reuseAddr)
137
        {
138
            ip_set_option(mTCP, SOF_REUSEADDR);
139
        }
140
141
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
142
143
        ip_addr_t ipAddr;
144
        if (addr != IPAddress::Any)
145
        {
146
            ipAddr = addr.ToLwIPAddr();
147
        }
148
        else if (addrType == kIPAddressType_IPv6)
149
        {
150
            ipAddr = ip6_addr_any;
151
        }
152
#if INET_CONFIG_ENABLE_IPV4
153
        else if (addrType == kIPAddressType_IPv4)
154
        {
155
            ipAddr = ip_addr_any;
156
        }
157
#endif // INET_CONFIG_ENABLE_IPV4
158
        else
159
            res = INET_ERROR_WRONG_ADDRESS_TYPE;
160
        res = Weave::System::MapErrorLwIP(tcp_bind(mTCP, &ipAddr, port));
161
162
#else // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
163
164
        if (addrType == kIPAddressType_IPv6)
165
        {
166
            ip6_addr_t ipv6Addr = addr.ToIPv6();
167
            res = Weave::System::MapErrorLwIP(tcp_bind_ip6(mTCP, &ipv6Addr, port));
168
        }
169
#if INET_CONFIG_ENABLE_IPV4
170
        else if (addrType == kIPAddressType_IPv4)
171
        {
172
            ip_addr_t ipv4Addr = addr.ToIPv4();
173
            res = Weave::System::MapErrorLwIP(tcp_bind(mTCP, &ipv4Addr, port));
174
        }
175
#endif // INET_CONFIG_ENABLE_IPV4
176
        else
177
            res = INET_ERROR_WRONG_ADDRESS_TYPE;
178
179
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
180
    }
181
182
    // Unlock LwIP stack
183
    UNLOCK_TCPIP_CORE();
184
185
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
186
187
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
188
189
0
    res = GetSocket(addrType);
190
191
0
    if (res == INET_NO_ERROR && reuseAddr)
192
0
    {
193
0
        int n = 1;
194
0
        setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
195
196
0
#ifdef SO_REUSEPORT
197
        // Enable SO_REUSEPORT.  This permits coexistence between an
198
        // untargetted Weave client and other services that listen on
199
        // a Weave port on a specific address (such as a Weave client
200
        // with TARGETTED_LISTEN or TCP proxying services).  Note that
201
        // one of the costs of this implementation is the
202
        // non-deterministic connection dispatch when multple clients
203
        // listen on the address wih the same degreee of selectivity,
204
        // e.g. two untargetted-listen Weave clients, or two
205
        // targetted-listen Weave clients with the same node id.
206
207
0
        if (setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &n, sizeof(n)) != 0)
208
0
        {
209
0
            WeaveLogError(Inet, "SO_REUSEPORT: %d", errno);
210
0
        }
211
0
#endif // defined(SO_REUSEPORT)
212
213
0
    }
214
215
0
    if (res == INET_NO_ERROR)
216
0
    {
217
0
        if (addrType == kIPAddressType_IPv6)
218
0
        {
219
0
            struct sockaddr_in6 sa;
220
0
            memset(&sa, 0, sizeof(sa));
221
0
            sa.sin6_family = AF_INET6;
222
0
            sa.sin6_port = htons(port);
223
0
            sa.sin6_flowinfo = 0;
224
0
            sa.sin6_addr = addr.ToIPv6();
225
0
            sa.sin6_scope_id = 0;
226
227
0
            if (bind(mSocket, (const sockaddr *) &sa, (unsigned) sizeof(sa)) != 0)
228
0
                res = Weave::System::MapErrorPOSIX(errno);
229
0
        }
230
0
#if INET_CONFIG_ENABLE_IPV4
231
0
        else if (addrType == kIPAddressType_IPv4)
232
0
        {
233
0
            struct sockaddr_in sa;
234
0
            memset(&sa, 0, sizeof(sa));
235
0
            sa.sin_family = AF_INET;
236
0
            sa.sin_port = htons(port);
237
0
            sa.sin_addr = addr.ToIPv4();
238
239
0
            if (bind(mSocket, (const sockaddr *) &sa, (unsigned) sizeof(sa)) != 0)
240
0
                res = Weave::System::MapErrorPOSIX(errno);
241
0
        }
242
0
#endif // INET_CONFIG_ENABLE_IPV4
243
0
        else
244
0
            res = INET_ERROR_WRONG_ADDRESS_TYPE;
245
0
    }
246
247
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
248
249
0
    if (res == INET_NO_ERROR)
250
0
        State = kState_Bound;
251
252
0
    return res;
253
0
}
254
255
INET_ERROR TCPEndPoint::Listen(uint16_t backlog)
256
0
{
257
0
    INET_ERROR res = INET_NO_ERROR;
258
259
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
260
0
    Weave::System::Layer& lSystemLayer = SystemLayer();
261
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
262
263
0
    if (State != kState_Bound)
264
0
        return INET_ERROR_INCORRECT_STATE;
265
266
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
267
268
    // Start listening for incoming connections.
269
    mTCP = tcp_listen(mTCP);
270
    mLwIPEndPointType = kLwIPEndPointType_TCP;
271
272
    tcp_arg(mTCP, this);
273
274
    tcp_accept(mTCP, LwIPHandleIncomingConnection);
275
276
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
277
278
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
279
280
0
    if (listen(mSocket, backlog) != 0)
281
0
        res = Weave::System::MapErrorPOSIX(errno);
282
283
    // Wake the thread calling select so that it recognizes the new socket.
284
0
    lSystemLayer.WakeSelect();
285
286
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
287
288
0
    if (res == INET_NO_ERROR)
289
0
    {
290
        // Once Listening, bump the reference count.  The corresponding call to Release()
291
        // [or on LwIP, DeferredRelease()] will happen in DoClose().
292
0
        Retain();
293
0
        State = kState_Listening;
294
0
    }
295
296
0
    return res;
297
0
}
298
299
#if INET_CONFIG_TCP_CONN_REPAIR_SUPPORTED
300
301
bool TCPConnRepairInfo::IsValid (void) const
302
{
303
    if (!srcPort || !dstPort || !txSeq || !rxSeq || !sndWl1 || !sndWnd ||
304
        !maxWindow || !rcvWnd || !rcvWup)
305
    {
306
        return false;
307
    }
308
309
    return true;
310
}
311
312
void TCPConnRepairInfo::Dump (void) const
313
{
314
    char srcIPStr[64] = { 0 }, dstIPStr[64] = { 0 };
315
316
    srcIP.ToString(srcIPStr, sizeof(srcIPStr));
317
    dstIP.ToString(dstIPStr, sizeof(dstIPStr));
318
319
    WeaveLogDetail(Inet, "TCP repair src: %s:%d seq %u\n", srcIPStr, srcPort, txSeq);
320
    WeaveLogDetail(Inet, "TCP repair dst: %s:%d seq %u\n", dstIPStr, dstPort, rxSeq);
321
322
    WeaveLogDetail(Inet, "TCP repair opt: snd_wl1 %u snd_wnd %u max_window %u rcv_wnd %u rcv_wup %u\n",
323
                   sndWl1, sndWnd, maxWindow, rcvWnd, rcvWup);
324
325
    WeaveLogDetail(Inet, "TCP repair opt: mss %u snd_wscale %u rcv_wscale %u tcpi_opt %u\n",
326
                   mss, sndWscale, rcvWscale, tcpOptions);
327
328
    WeaveLogDetail(Inet, "local_port(%u), server_port(%u), tx_seq(%u), rx_seq(%u), snd_wl1(%u), snd_wnd(%u), max_window(%u), rcv_wnd(%u), rcv_wup(%u)\n",
329
                   srcPort, dstPort, txSeq, rxSeq, sndWl1, sndWnd,
330
                   maxWindow, rcvWnd, rcvWup);
331
}
332
333
INET_ERROR TCPEndPoint::RepairConnection(const TCPConnRepairInfo &connRepairInfo, InterfaceId intf)
334
{
335
    INET_ERROR res = INET_NO_ERROR;
336
337
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
338
    res = INET_ERROR_NOT_SUPPORTED;
339
    ExitNow();
340
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
341
342
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
343
344
    struct tcp_repair_opt opts[4];
345
    int opCtr = 0;
346
    uint32_t val;
347
348
    if (!connRepairInfo.IsValid())
349
    {
350
        WeaveLogError(Inet, "Not enough info to repair TCP connection\n");
351
        ExitNow(res = INET_ERROR_BAD_ARGS);
352
    }
353
354
    // Dump the contents of the TCP Connection Repair Info
355
    connRepairInfo.Dump();
356
357
    res = GetSocket(connRepairInfo.addrType);
358
    if (res != INET_NO_ERROR)
359
        ExitNow();
360
361
    val = 1;
362
    if (setsockopt(mSocket, SOL_TCP, TCP_REPAIR, &val, sizeof(val)) != 0)
363
    {
364
        WeaveLogError(Inet, "TCP_REPAIR failed: %d", errno);
365
        ExitNow(res = Weave::System::MapErrorPOSIX(errno));
366
    }
367
368
    val = 1;
369
    if (setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != 0)
370
    {
371
        WeaveLogError(Inet, "SO_REUSEADDR failed: %d", errno);
372
        ExitNow(res = Weave::System::MapErrorPOSIX(errno));
373
    }
374
375
    /* ============= Restore TCP properties ==================*/
376
377
    val = TCP_SEND_QUEUE;
378
    if (setsockopt(mSocket, SOL_TCP, TCP_REPAIR_QUEUE, &val, sizeof(val)) != 0)
379
    {
380
        WeaveLogError(Inet, "Repairing TCP_SEND_QUEUE failed: %d", errno);
381
        ExitNow(res = Weave::System::MapErrorPOSIX(errno));
382
    }
383
384
    val = connRepairInfo.txSeq;
385
    WeaveLogDetail(Inet, "Restoring Tx seq: %u", val);
386
    if (setsockopt(mSocket, SOL_TCP, TCP_QUEUE_SEQ, &val, sizeof(val)) != 0)
387
    {
388
        WeaveLogError(Inet, "Tx Seq failed: %d", errno);
389
        ExitNow(res = Weave::System::MapErrorPOSIX(errno));
390
    }
391
392
    val = TCP_RECV_QUEUE;
393
    if (setsockopt(mSocket, SOL_TCP, TCP_REPAIR_QUEUE, &val, sizeof(val)) != 0) {
394
        WeaveLogError(Inet, "Repairing TCP_RECV_QUEUE failed: %d", errno);
395
        ExitNow(res = Weave::System::MapErrorPOSIX(errno));
396
    }
397
398
    val = connRepairInfo.rxSeq;
399
    WeaveLogDetail(Inet, "Restoring Rx seq: %u", val);
400
    if (setsockopt(mSocket, SOL_TCP, TCP_QUEUE_SEQ, &val, sizeof(val)) != 0) {
401
        WeaveLogError(Inet, "Rx Seq failed: %d", errno);
402
        ExitNow(res = Weave::System::MapErrorPOSIX(errno));
403
    }
404
405
    if (connRepairInfo.addrType == kIPAddressType_IPv6)
406
    {
407
        struct sockaddr_in6 serverAddress, localAddress;
408
        memset(&localAddress, 0, sizeof(localAddress));
409
        localAddress.sin6_family = AF_INET6;
410
        localAddress.sin6_addr = connRepairInfo.srcIP.ToIPv6();
411
        localAddress.sin6_port = htons(connRepairInfo.srcPort);
412
413
        memset(&serverAddress, 0, sizeof(serverAddress));
414
        serverAddress.sin6_family = AF_INET6;
415
        serverAddress.sin6_addr = connRepairInfo.dstIP.ToIPv6();
416
        serverAddress.sin6_port = htons(connRepairInfo.dstPort);
417
418
        if (bind(mSocket, (struct sockaddr *) &localAddress, sizeof(localAddress)) != 0)
419
        {
420
            WeaveLogError(Inet, "Bind src address failed: %d", errno);
421
            ExitNow(res = Weave::System::MapErrorPOSIX(errno));
422
        }
423
424
        if (connect(mSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) != 0)
425
        {
426
            WeaveLogError(Inet, "Connect to dst address failed: %d", errno);
427
            ExitNow(res = Weave::System::MapErrorPOSIX(errno));
428
        }
429
    }
430
#if INET_CONFIG_ENABLE_IPV4
431
    else if (connRepairInfo.addrType == kIPAddressType_IPv4)
432
    {
433
        struct sockaddr_in serverAddress, localAddress;
434
        memset(&localAddress, 0, sizeof(localAddress));
435
        localAddress.sin_family = AF_INET;
436
        localAddress.sin_addr = connRepairInfo.srcIP.ToIPv4();
437
        localAddress.sin_port = htons(connRepairInfo.srcPort);
438
439
        memset(&serverAddress, 0, sizeof(serverAddress));
440
        serverAddress.sin_family = AF_INET;
441
        serverAddress.sin_addr = connRepairInfo.dstIP.ToIPv4();
442
        serverAddress.sin_port = htons(connRepairInfo.dstPort);
443
444
        if (bind(mSocket, (struct sockaddr *) &localAddress, sizeof(localAddress)) != 0)
445
        {
446
            WeaveLogError(Inet, "Bind src address failed: %d", errno);
447
            ExitNow(res = Weave::System::MapErrorPOSIX(errno));
448
        }
449
450
        if (connect(mSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) != 0)
451
        {
452
            WeaveLogError(Inet, "Connect to dst address failed: %d", errno);
453
            ExitNow(res = Weave::System::MapErrorPOSIX(errno));
454
        }
455
    }
456
#endif // INET_CONFIG_ENABLE_IPV4
457
    else
458
    {
459
        ExitNow(res = INET_ERROR_WRONG_ADDRESS_TYPE);
460
    }
461
462
    /* Repair tcp options */
463
464
    if (connRepairInfo.tcpOptions & TCPI_OPT_SACK)
465
    {
466
        WeaveLogDetail(Inet, "Turning TCPI_OPT_SACK on\n");
467
        opts[opCtr].opt_code = TCPOPT_SACK_PERMITTED;
468
        opts[opCtr].opt_val = 0;
469
        opCtr++;
470
    }
471
472
    if (connRepairInfo.tcpOptions & TCPI_OPT_WSCALE)
473
    {
474
        WeaveLogDetail(Inet, "Set Send Window Scale to %u\n", connRepairInfo.sndWscale);
475
        WeaveLogDetail(Inet, "Set Receive Window Scale to %u\n", connRepairInfo.rcvWscale);
476
        opts[opCtr].opt_code = TCPOPT_WINDOW;
477
        opts[opCtr].opt_val = connRepairInfo.sndWscale + (connRepairInfo.rcvWscale << 16);
478
        opCtr++;
479
    }
480
481
    if (connRepairInfo.tcpOptions & TCPI_OPT_TIMESTAMPS)
482
    {
483
        WeaveLogDetail(Inet, "Turning TCPI_OPT_TIMESTAMPS on\n");
484
        opts[opCtr].opt_code = TCPOPT_TIMESTAMP;
485
        opts[opCtr].opt_val = 0;
486
        opCtr++;
487
    }
488
489
    WeaveLogDetail(Inet, "Set MSS clamp to %u\n", connRepairInfo.mss);
490
    opts[opCtr].opt_code = TCPOPT_MAXSEG;
491
    opts[opCtr].opt_val = connRepairInfo.mss;
492
    opCtr++;
493
494
    if (setsockopt(mSocket, SOL_TCP, TCP_REPAIR_OPTIONS, opts, opCtr * sizeof(struct tcp_repair_opt)) < 0)
495
    {
496
        WeaveLogError(Inet, "%s: %d: Can't repair tcp options", __func__, __LINE__);
497
        ExitNow(res = Weave::System::MapErrorPOSIX(errno));
498
    }
499
500
    if (connRepairInfo.tcpOptions & TCPI_OPT_TIMESTAMPS)
501
    {
502
        if (setsockopt(mSocket, SOL_TCP, TCP_TIMESTAMP, &connRepairInfo.tsVal, sizeof(connRepairInfo.tsVal)) < 0)
503
        {
504
            WeaveLogError(Inet, "%s: %d: Can't set timestamp", __func__, __LINE__);
505
            ExitNow(res = Weave::System::MapErrorPOSIX(errno));
506
        }
507
    }
508
509
    if (connRepairInfo.maxWindow)
510
    {
511
        /* restore window */
512
        struct tcp_repair_window windowOpt = {
513
            .snd_wl1 = connRepairInfo.sndWl1,
514
            .snd_wnd = connRepairInfo.sndWnd,
515
            .max_window = connRepairInfo.maxWindow,
516
            .rcv_wnd = connRepairInfo.rcvWnd,
517
            .rcv_wup = connRepairInfo.rcvWup,
518
        };
519
520
        if (setsockopt(mSocket, SOL_TCP, TCP_REPAIR_WINDOW, &windowOpt, sizeof(windowOpt)) != 0)
521
        {
522
            WeaveLogError(Inet, "%s: %d: Unable to set window parameters", __func__, __LINE__);
523
            ExitNow(res = Weave::System::MapErrorPOSIX(errno));
524
        }
525
    }
526
527
    val = 0;
528
    if (setsockopt(mSocket, SOL_TCP, TCP_REPAIR, &val, sizeof(val)) != 0)
529
    {
530
        WeaveLogError(Inet, "%s: %d: TCP_REPAIR failed", __func__, __LINE__);
531
        ExitNow(res = Weave::System::MapErrorPOSIX(errno));
532
    }
533
534
    mAddrType = connRepairInfo.addrType;
535
536
    // Bump the ref count on the TCPEndPoint after repairing the socket.
537
    Retain();
538
539
    // Mark state as Connected
540
    State = kState_Connected;
541
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
542
543
exit:
544
545
    return res;
546
}
547
#endif // INET_CONFIG_TCP_CONN_REPAIR_SUPPORTED
548
549
INET_ERROR TCPEndPoint::Connect(IPAddress addr, uint16_t port, InterfaceId intf)
550
0
{
551
0
    INET_ERROR res = INET_NO_ERROR;
552
553
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
554
0
    Weave::System::Layer& lSystemLayer = SystemLayer();
555
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
556
557
0
    if (State != kState_Ready && State != kState_Bound)
558
0
        return INET_ERROR_INCORRECT_STATE;
559
560
0
    IPAddressType addrType = addr.Type();
561
562
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
563
564
    // LwIP does not provides an API for initiating a TCP connection via a specific interface.
565
    // As a work-around, if the destination is an IPv6 link-local address, we bind the PCB
566
    // to the link local address associated with the source interface; however this is only
567
    // viable if the endpoint hasn't already been bound.
568
    if (intf != INET_NULL_INTERFACEID)
569
    {
570
        IPAddress intfLLAddr;
571
        InetLayer& lInetLayer = Layer();
572
573
        if (!addr.IsIPv6LinkLocal() || State == kState_Bound)
574
            return INET_ERROR_NOT_IMPLEMENTED;
575
576
        res = lInetLayer.GetLinkLocalAddr(intf, &intfLLAddr);
577
        if (res != INET_NO_ERROR)
578
            return res;
579
580
        res = Bind(kIPAddressType_IPv6, intfLLAddr, 0, true);
581
        if (res != INET_NO_ERROR)
582
            return res;
583
    }
584
585
    // Lock LwIP stack
586
    LOCK_TCPIP_CORE();
587
588
    res = GetPCB(addrType);
589
590
    if (res == INET_NO_ERROR)
591
    {
592
        tcp_arg(mTCP, this);
593
        tcp_err(mTCP, LwIPHandleError);
594
595
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
596
        ip_addr_t lwipAddr = addr.ToLwIPAddr();
597
        res = Weave::System::MapErrorLwIP(tcp_connect(mTCP, &lwipAddr, port, LwIPHandleConnectComplete));
598
#else // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
599
        if (addrType == kIPAddressType_IPv6)
600
        {
601
            ip6_addr_t lwipAddr = addr.ToIPv6();
602
            res = Weave::System::MapErrorLwIP(tcp_connect_ip6(mTCP, &lwipAddr, port, LwIPHandleConnectComplete));
603
        }
604
#if INET_CONFIG_ENABLE_IPV4
605
        else if (addrType == kIPAddressType_IPv4)
606
        {
607
            ip_addr_t lwipAddr = addr.ToIPv4();
608
            res = Weave::System::MapErrorLwIP(tcp_connect(mTCP, &lwipAddr, port, LwIPHandleConnectComplete));
609
        }
610
#endif // INET_CONFIG_ENABLE_IPV4
611
        else
612
            res = INET_ERROR_WRONG_ADDRESS_TYPE;
613
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
614
615
        // Ensure that TCP timers are started
616
        if (res == INET_NO_ERROR)
617
        {
618
            res = start_tcp_timers();
619
        }
620
621
        if (res == INET_NO_ERROR)
622
        {
623
            State = kState_Connecting;
624
            Retain();
625
        }
626
    }
627
628
    // Unlock LwIP stack
629
    UNLOCK_TCPIP_CORE();
630
631
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
632
633
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
634
635
0
    res = GetSocket(addrType);
636
0
    if (res != INET_NO_ERROR)
637
0
        return res;
638
639
0
    if (intf == INET_NULL_INTERFACEID)
640
0
    {
641
        // The behavior when connecting to an IPv6 link-local address without specifying an outbound
642
        // interface is ambiguous. So prevent it in all cases.
643
0
        if (addr.IsIPv6LinkLocal())
644
0
            return INET_ERROR_WRONG_ADDRESS_TYPE;
645
0
    }
646
0
    else
647
0
    {
648
        // Try binding to the interface
649
650
        // If destination is link-local then there is no need to bind to
651
        // interface or address on the interface.
652
653
0
        if (!addr.IsIPv6LinkLocal())
654
0
        {
655
0
#ifdef SO_BINDTODEVICE
656
0
            struct ::ifreq ifr;
657
0
            memset(&ifr, 0, sizeof(ifr));
658
659
0
            res = GetInterfaceName(intf, ifr.ifr_name, sizeof(ifr.ifr_name));
660
0
            if (res != INET_NO_ERROR)
661
0
                return res;
662
663
            // Attempt to bind to the interface using SO_BINDTODEVICE which requires privileged access.
664
            // If the permission is denied(EACCES) because Weave is running in a context
665
            // that does not have privileged access, choose a source address on the
666
            // interface to bind the connetion to.
667
0
            int r = setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr));
668
0
            if (r < 0 && errno != EACCES)
669
0
            {
670
0
                return res = Weave::System::MapErrorPOSIX(errno);
671
0
            }
672
673
0
            if (r < 0)
674
0
#endif // SO_BINDTODEVICE
675
0
            {
676
                // Attempting to initiate a connection via a specific interface is not allowed.
677
                // The only way to do this is to bind the local to an address on the desired
678
                // interface.
679
0
                res = BindSrcAddrFromIntf(addrType, intf);
680
0
                if (res != INET_NO_ERROR)
681
0
                    return res;
682
0
            }
683
0
        }
684
0
    }
685
686
    // Disable generation of SIGPIPE.
687
#ifdef SO_NOSIGPIPE
688
    int n = 1;
689
    setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &n, sizeof(n));
690
#endif // defined(SO_NOSIGPIPE)
691
692
    // Enable non-blocking mode for the socket.
693
0
    int flags = fcntl(mSocket, F_GETFL, 0);
694
0
    fcntl(mSocket, F_SETFL, flags | O_NONBLOCK);
695
696
0
    int sockaddrsize = 0;
697
0
    const sockaddr *sockaddrptr = NULL;
698
699
0
    union
700
0
    {
701
0
        sockaddr        any;
702
0
        sockaddr_in6    in6;
703
0
#if INET_CONFIG_ENABLE_IPV4
704
0
        sockaddr_in     in;
705
0
#endif // INET_CONFIG_ENABLE_IPV4
706
0
    } sa;
707
0
    memset(&sa, 0, sizeof(sa));
708
709
0
    if (addrType == kIPAddressType_IPv6)
710
0
    {
711
0
        sa.in6.sin6_family = AF_INET6;
712
0
        sa.in6.sin6_port = htons(port);
713
0
        sa.in6.sin6_flowinfo = 0;
714
0
        sa.in6.sin6_addr = addr.ToIPv6();
715
0
        sa.in6.sin6_scope_id = intf;
716
0
        sockaddrsize = sizeof(sockaddr_in6);
717
0
        sockaddrptr = (const sockaddr *) &sa.in6;
718
0
    }
719
0
#if INET_CONFIG_ENABLE_IPV4
720
0
    else if (addrType == kIPAddressType_IPv4)
721
0
    {
722
0
        sa.in.sin_family = AF_INET;
723
0
        sa.in.sin_port = htons(port);
724
0
        sa.in.sin_addr = addr.ToIPv4();
725
0
        sockaddrsize = sizeof(sockaddr_in);
726
0
        sockaddrptr = (const sockaddr *) &sa.in;
727
0
    }
728
0
#endif // INET_CONFIG_ENABLE_IPV4
729
0
    else
730
0
        return INET_ERROR_WRONG_ADDRESS_TYPE;
731
732
0
    int conRes = connect(mSocket, sockaddrptr, sockaddrsize);
733
734
0
    if (conRes == -1 && errno != EINPROGRESS)
735
0
    {
736
0
        res = Weave::System::MapErrorPOSIX(errno);
737
0
        DoClose(res, true);
738
0
        return res;
739
0
    }
740
741
    // Once Connecting or Connected, bump the reference count.  The corresponding Release()
742
    // [or on LwIP, DeferredRelease()] will happen in DoClose().
743
0
    Retain();
744
745
0
    if (conRes == 0)
746
0
    {
747
0
        State = kState_Connected;
748
0
        if (OnConnectComplete != NULL)
749
0
            OnConnectComplete(this, INET_NO_ERROR);
750
0
    }
751
0
    else
752
0
        State = kState_Connecting;
753
754
    // Wake the thread calling select so that it recognizes the new socket.
755
0
    lSystemLayer.WakeSelect();
756
757
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
758
759
0
    StartConnectTimerIfSet();
760
761
0
    return res;
762
0
}
763
764
/**
765
 * @brief   Set timeout for Connect to succeed or return an error.
766
 *
767
 * @param[in]   connTimeoutMsecs
768
 *
769
 * @note
770
 *  Setting a value of zero means use system defaults.
771
 */
772
void TCPEndPoint::SetConnectTimeout(const uint32_t connTimeoutMsecs)
773
0
{
774
0
    mConnectTimeoutMsecs = connTimeoutMsecs;
775
0
}
776
777
void TCPEndPoint::StartConnectTimerIfSet(void)
778
0
{
779
0
    if (mConnectTimeoutMsecs > 0)
780
0
    {
781
0
        Weave::System::Layer& lSystemLayer = SystemLayer();
782
783
0
        lSystemLayer.StartTimer(mConnectTimeoutMsecs, TCPConnectTimeoutHandler, this);
784
0
    }
785
0
}
786
787
void TCPEndPoint::StopConnectTimer(void)
788
0
{
789
0
    Weave::System::Layer& lSystemLayer = SystemLayer();
790
791
0
    lSystemLayer.CancelTimer(TCPConnectTimeoutHandler, this);
792
0
}
793
794
void TCPEndPoint::TCPConnectTimeoutHandler(Weave::System::Layer* aSystemLayer, void* aAppState, Weave::System::Error aError)
795
0
{
796
0
    TCPEndPoint * tcpEndPoint = reinterpret_cast<TCPEndPoint *>(aAppState);
797
798
0
    VerifyOrDie((aSystemLayer != NULL) && (tcpEndPoint != NULL));
799
800
    // Close Connection as we have timed out and Connect has not returned to
801
    // stop this timer.
802
0
    tcpEndPoint->DoClose(INET_ERROR_TCP_CONNECT_TIMEOUT, false);
803
0
}
804
805
INET_ERROR TCPEndPoint::GetPeerInfo(IPAddress *retAddr, uint16_t *retPort) const
806
0
{
807
0
    INET_ERROR res = INET_NO_ERROR;
808
809
0
    if (!IsConnected())
810
0
        return INET_ERROR_INCORRECT_STATE;
811
812
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
813
814
    // Lock LwIP stack
815
    LOCK_TCPIP_CORE();
816
817
    if (mTCP != NULL)
818
    {
819
        *retPort = mTCP->remote_port;
820
821
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
822
        *retAddr = IPAddress::FromLwIPAddr(mTCP->remote_ip);
823
#else // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
824
#if INET_CONFIG_ENABLE_IPV4
825
        *retAddr = PCB_ISIPV6(mTCP) ? IPAddress::FromIPv6(mTCP->remote_ip.ip6) : IPAddress::FromIPv4(mTCP->remote_ip.ip4);
826
#else // !INET_CONFIG_ENABLE_IPV4
827
        *retAddr = IPAddress::FromIPv6(mTCP->remote_ip.ip6);
828
#endif // !INET_CONFIG_ENABLE_IPV4
829
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
830
    }
831
    else
832
        res = INET_ERROR_CONNECTION_ABORTED;
833
834
    // Unlock LwIP stack
835
    UNLOCK_TCPIP_CORE();
836
837
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
838
839
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
840
841
0
    union
842
0
    {
843
0
        sockaddr any;
844
0
        sockaddr_in in;
845
0
        sockaddr_in6 in6;
846
0
    } sa;
847
0
    memset(&sa, 0, sizeof(sa));
848
0
    socklen_t saLen = sizeof(sa);
849
850
0
    if (getpeername(mSocket, &sa.any, &saLen) != 0)
851
0
        return Weave::System::MapErrorPOSIX(errno);
852
853
0
    if (sa.any.sa_family == AF_INET6)
854
0
    {
855
0
        *retAddr = IPAddress::FromIPv6(sa.in6.sin6_addr);
856
0
        *retPort = ntohs(sa.in6.sin6_port);
857
0
    }
858
0
#if INET_CONFIG_ENABLE_IPV4
859
0
    else if (sa.any.sa_family == AF_INET)
860
0
    {
861
0
        *retAddr = IPAddress::FromIPv4(sa.in.sin_addr);
862
0
        *retPort = ntohs(sa.in.sin_port);
863
0
    }
864
0
#endif // INET_CONFIG_ENABLE_IPV4
865
0
    else
866
0
        return INET_ERROR_INCORRECT_STATE;
867
868
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
869
870
0
    return res;
871
0
}
872
873
INET_ERROR TCPEndPoint::GetLocalInfo(IPAddress *retAddr, uint16_t *retPort)
874
0
{
875
0
    INET_ERROR res = INET_NO_ERROR;
876
877
0
    if (!IsConnected())
878
0
        return INET_ERROR_INCORRECT_STATE;
879
880
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
881
882
    // Lock LwIP stack
883
    LOCK_TCPIP_CORE();
884
885
    if (mTCP != NULL)
886
    {
887
        *retPort = mTCP->local_port;
888
889
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
890
        *retAddr = IPAddress::FromLwIPAddr(mTCP->local_ip);
891
#else // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
892
#if INET_CONFIG_ENABLE_IPV4
893
        *retAddr = PCB_ISIPV6(mTCP) ? IPAddress::FromIPv6(mTCP->local_ip.ip6) : IPAddress::FromIPv4(mTCP->local_ip.ip4);
894
#else // !INET_CONFIG_ENABLE_IPV4
895
        *retAddr = IPAddress::FromIPv6(mTCP->local_ip.ip6);
896
#endif // !INET_CONFIG_ENABLE_IPV4
897
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
898
    }
899
    else
900
        res = INET_ERROR_CONNECTION_ABORTED;
901
902
    // Unlock LwIP stack
903
    UNLOCK_TCPIP_CORE();
904
905
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
906
907
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
908
909
0
    union
910
0
    {
911
0
        sockaddr        any;
912
0
        sockaddr_in6    in6;
913
0
#if INET_CONFIG_ENABLE_IPV4
914
0
        sockaddr_in     in;
915
0
#endif // INET_CONFIG_ENABLE_IPV4
916
0
    } sa;
917
918
0
    memset(&sa, 0, sizeof(sa));
919
0
    socklen_t saLen = sizeof(sa);
920
921
0
    if (getsockname(mSocket, &sa.any, &saLen) != 0)
922
0
        return Weave::System::MapErrorPOSIX(errno);
923
924
0
    if (sa.any.sa_family == AF_INET6)
925
0
    {
926
0
        *retAddr = IPAddress::FromIPv6(sa.in6.sin6_addr);
927
0
        *retPort = ntohs(sa.in6.sin6_port);
928
0
    }
929
0
#if INET_CONFIG_ENABLE_IPV4
930
0
    else if (sa.any.sa_family == AF_INET)
931
0
    {
932
0
        *retAddr = IPAddress::FromIPv4(sa.in.sin_addr);
933
0
        *retPort = ntohs(sa.in.sin_port);
934
0
    }
935
0
#endif // INET_CONFIG_ENABLE_IPV4
936
0
    else
937
0
        return INET_ERROR_INCORRECT_STATE;
938
939
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
940
941
0
    return res;
942
0
}
943
944
INET_ERROR TCPEndPoint::Send(PacketBuffer *data, bool push)
945
0
{
946
0
    INET_ERROR res = INET_NO_ERROR;
947
948
0
    if (State != kState_Connected && State != kState_ReceiveShutdown)
949
0
    {
950
0
        PacketBuffer::Free(data);
951
0
        return INET_ERROR_INCORRECT_STATE;
952
0
    }
953
954
0
    if (mSendQueue == NULL)
955
0
        mSendQueue = data;
956
0
    else
957
0
        mSendQueue->AddToEnd(data);
958
959
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
960
961
#if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
962
    if (!mUserTimeoutTimerRunning)
963
    {
964
        // Timer was not running before this send. So, start
965
        // the timer.
966
967
        StartTCPUserTimeoutTimer();
968
    }
969
#endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
970
971
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
972
973
0
    if (push)
974
0
        res = DriveSending();
975
976
0
    return res;
977
0
}
978
979
void TCPEndPoint::DisableReceive()
980
0
{
981
0
    ReceiveEnabled = false;
982
0
}
983
984
void TCPEndPoint::EnableReceive()
985
0
{
986
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
987
0
    Weave::System::Layer& lSystemLayer = SystemLayer();
988
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
989
990
0
    ReceiveEnabled = true;
991
992
0
    DriveReceiving();
993
994
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
995
996
    // Wake the thread calling select so that it can include the socket
997
    // in the select read fd_set.
998
0
    lSystemLayer.WakeSelect();
999
1000
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1001
0
}
1002
1003
/**
1004
 *  TCPEndPoint::EnableNoDelay
1005
 *
1006
 *  @brief
1007
 *    Switch off nagle buffering algorithm in TCP by setting the
1008
 *    TCP_NODELAY socket options.
1009
 *
1010
 */
1011
1012
INET_ERROR TCPEndPoint::EnableNoDelay(void)
1013
0
{
1014
0
    INET_ERROR res = INET_NO_ERROR;
1015
1016
0
    if (!IsConnected())
1017
0
        return INET_ERROR_INCORRECT_STATE;
1018
1019
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1020
    // Lock LwIP stack
1021
    LOCK_TCPIP_CORE();
1022
1023
    if (mTCP != NULL)
1024
        tcp_nagle_disable(mTCP);
1025
    else
1026
        res = INET_ERROR_CONNECTION_ABORTED;
1027
1028
    // Unlock LwIP stack
1029
    UNLOCK_TCPIP_CORE();
1030
1031
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1032
1033
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1034
0
    {
1035
0
        int val;
1036
1037
0
#ifdef TCP_NODELAY
1038
        // Disable TCP Nagle buffering by setting TCP_NODELAY socket option to true
1039
0
        val = 1;
1040
0
        if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_NODELAY, &val, sizeof(val)) != 0)
1041
0
            return Weave::System::MapErrorPOSIX(errno);
1042
0
#endif // defined(TCP_NODELAY)
1043
0
    }
1044
1045
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1046
1047
0
    return res;
1048
0
}
1049
1050
/**
1051
 *  TCPEndPoint::EnableKeepAlive
1052
 *
1053
 *  @brief
1054
 *    Enable TCP keepalive probes on the associated TCP connection.
1055
 *
1056
 *  @param interval
1057
 *    The interval (in seconds) between keepalive probes.  This value also controls
1058
 *    the time between last data packet sent and the transmission of the first keepalive
1059
 *    probe.
1060
 *
1061
 *  @param timeoutCount
1062
 *    The maximum number of unacknowledged probes before the connection will be deemed
1063
 *    to have failed.
1064
 *
1065
 *  @note
1066
 *    This method can only be called when the endpoint is in one of the connected states.
1067
 *
1068
 *    This method can be called multiple times to adjust the keepalive interval or timeout
1069
 *    count.
1070
 */
1071
1072
INET_ERROR TCPEndPoint::EnableKeepAlive(uint16_t interval, uint16_t timeoutCount)
1073
0
{
1074
0
    INET_ERROR res = INET_NO_ERROR;
1075
1076
0
    if (!IsConnected())
1077
0
        return INET_ERROR_INCORRECT_STATE;
1078
1079
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1080
1081
#if LWIP_TCP_KEEPALIVE
1082
1083
    // Lock LwIP stack
1084
    LOCK_TCPIP_CORE();
1085
1086
    if (mTCP != NULL)
1087
    {
1088
        // Set the idle interval
1089
        mTCP->keep_idle = (uint32_t)interval * 1000;
1090
1091
        // Set the probe retransmission interval.
1092
        mTCP->keep_intvl = (uint32_t)interval * 1000;
1093
1094
        // Set the probe timeout count
1095
        mTCP->keep_cnt = timeoutCount;
1096
1097
        // Enable keepalives for the connection.
1098
        ip_set_option(mTCP, SOF_KEEPALIVE);
1099
    }
1100
    else
1101
        res = INET_ERROR_CONNECTION_ABORTED;
1102
1103
    // Unlock LwIP stack
1104
    UNLOCK_TCPIP_CORE();
1105
1106
#else // LWIP_TCP_KEEPALIVE
1107
1108
    res = INET_ERROR_NOT_IMPLEMENTED;
1109
1110
#endif // LWIP_TCP_KEEPALIVE
1111
1112
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1113
1114
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1115
0
    {
1116
0
        int val;
1117
1118
        // Set the idle interval
1119
0
        val = interval;
1120
0
        if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_IDLE_INTERVAL_OPT_NAME, &val, sizeof(val)) != 0)
1121
0
            return Weave::System::MapErrorPOSIX(errno);
1122
1123
        // Set the probe retransmission interval.
1124
0
        val = interval;
1125
0
        if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_KEEPINTVL, &val, sizeof(val)) != 0)
1126
0
            return Weave::System::MapErrorPOSIX(errno);
1127
1128
        // Set the probe timeout count
1129
0
        val = timeoutCount;
1130
0
        if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_KEEPCNT, &val, sizeof(val)) != 0)
1131
0
            return Weave::System::MapErrorPOSIX(errno);
1132
1133
        // Enable keepalives for the connection.
1134
0
        val = 1; // enable
1135
0
        if (setsockopt(mSocket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) != 0)
1136
0
            return Weave::System::MapErrorPOSIX(errno);
1137
0
    }
1138
1139
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1140
1141
0
    return res;
1142
0
}
1143
1144
/**
1145
 *  TCPEndPoint::DisableKeepAlive
1146
 *
1147
 *  @brief
1148
 *    Disable TCP keepalive probes on the associated TCP connection.
1149
 *
1150
 *  @note
1151
 *    This method can only be called when the endpoint is in one of the connected states.
1152
 *
1153
 *    This method does nothing if keepalives have not been enabled on the endpoint.
1154
 */
1155
1156
INET_ERROR TCPEndPoint::DisableKeepAlive()
1157
0
{
1158
0
    INET_ERROR res = INET_NO_ERROR;
1159
1160
0
    if (!IsConnected())
1161
0
        return INET_ERROR_INCORRECT_STATE;
1162
1163
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1164
1165
#if LWIP_TCP_KEEPALIVE
1166
1167
    // Lock LwIP stack
1168
    LOCK_TCPIP_CORE();
1169
1170
    if (mTCP != NULL)
1171
    {
1172
        // Disable keepalives on the connection.
1173
        ip_reset_option(mTCP, SOF_KEEPALIVE);
1174
    }
1175
    else
1176
        res = INET_ERROR_CONNECTION_ABORTED;
1177
1178
    // Unlock LwIP stack
1179
    UNLOCK_TCPIP_CORE();
1180
1181
#else // LWIP_TCP_KEEPALIVE
1182
1183
    res = INET_ERROR_NOT_IMPLEMENTED;
1184
1185
#endif // LWIP_TCP_KEEPALIVE
1186
1187
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1188
1189
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1190
1191
0
    {
1192
0
        int val;
1193
1194
        // Disable keepalives on the connection.
1195
0
        val = 0; // disable
1196
0
        if (setsockopt(mSocket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) != 0)
1197
0
            return Weave::System::MapErrorPOSIX(errno);
1198
0
    }
1199
1200
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1201
1202
0
    return res;
1203
0
}
1204
1205
/**
1206
 *  TCPEndPoint::SetUserTimeout
1207
 *
1208
 *  @brief   Set the TCP user timeout socket option.
1209
 *
1210
 *  @details
1211
 *    When the value is greater than 0, it specifies the maximum amount of
1212
 *    time in milliseconds that transmitted data may remain
1213
 *    unacknowledged before TCP will forcibly close the
1214
 *    corresponding connection. If the option value is specified as 0,
1215
 *    TCP will use the system default.
1216
 *    See RFC 5482, for further details.
1217
 *
1218
 *  @note
1219
 *    This method can only be called when the endpoint is in one of the connected states.
1220
 *
1221
 *    This method can be called multiple times to adjust the keepalive interval or timeout
1222
 *    count.
1223
 */
1224
INET_ERROR TCPEndPoint::SetUserTimeout(uint32_t userTimeoutMillis)
1225
0
{
1226
0
    INET_ERROR res = INET_NO_ERROR;
1227
1228
0
    if (!IsConnected())
1229
0
    {
1230
0
        return INET_ERROR_INCORRECT_STATE;
1231
0
    }
1232
1233
0
#if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1234
1235
    // Store the User timeout configuration if it is being overridden.
1236
1237
0
    mUserTimeoutMillis = userTimeoutMillis;
1238
1239
#else // !INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1240
1241
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1242
1243
#if defined(TCP_USER_TIMEOUT)
1244
        // Set the user timeout
1245
        uint32_t val = userTimeoutMillis;
1246
        if (setsockopt(mSocket, TCP_SOCKOPT_LEVEL, TCP_USER_TIMEOUT, &val, sizeof(val)) != 0)
1247
            return Weave::System::MapErrorPOSIX(errno);
1248
#else // TCP_USER_TIMEOUT
1249
    res = INET_ERROR_NOT_IMPLEMENTED;
1250
#endif // defined(TCP_USER_TIMEOUT)
1251
1252
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1253
1254
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1255
    res = INET_ERROR_NOT_IMPLEMENTED;
1256
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1257
1258
#endif // !INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1259
1260
0
    return res;
1261
0
}
1262
1263
INET_ERROR TCPEndPoint::AckReceive(uint16_t len)
1264
0
{
1265
0
    INET_ERROR res = INET_NO_ERROR;
1266
1267
0
    if (!IsConnected())
1268
0
        return INET_ERROR_INCORRECT_STATE;
1269
1270
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1271
1272
    // Lock LwIP stack
1273
    LOCK_TCPIP_CORE();
1274
1275
    if (mTCP != NULL)
1276
        tcp_recved(mTCP, len);
1277
    else
1278
        res = INET_ERROR_CONNECTION_ABORTED;
1279
1280
    // Unlock LwIP stack
1281
    UNLOCK_TCPIP_CORE();
1282
1283
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1284
1285
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1286
1287
    // nothing to do for sockets case
1288
1289
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1290
1291
0
    return res;
1292
0
}
1293
1294
INET_ERROR TCPEndPoint::PutBackReceivedData(PacketBuffer *data)
1295
0
{
1296
0
    if (!IsConnected())
1297
0
        return INET_ERROR_INCORRECT_STATE;
1298
1299
0
    mRcvQueue = data;
1300
1301
0
    return INET_NO_ERROR;
1302
0
}
1303
1304
uint32_t TCPEndPoint::PendingSendLength()
1305
0
{
1306
0
    if (mSendQueue != NULL)
1307
0
        return mSendQueue->TotalLength();
1308
0
    else
1309
0
        return 0;
1310
0
}
1311
1312
uint32_t TCPEndPoint::PendingReceiveLength()
1313
0
{
1314
0
    if (mRcvQueue != NULL)
1315
0
        return mRcvQueue->TotalLength();
1316
0
    else
1317
0
        return 0;
1318
0
}
1319
1320
INET_ERROR TCPEndPoint::Shutdown()
1321
0
{
1322
0
    INET_ERROR err = INET_NO_ERROR;
1323
1324
0
    if (!IsConnected())
1325
0
        return INET_ERROR_INCORRECT_STATE;
1326
1327
    // If fully connected, enter the SendShutdown state.
1328
0
    if (State == kState_Connected)
1329
0
    {
1330
0
        State = kState_SendShutdown;
1331
0
        DriveSending();
1332
0
    }
1333
1334
    // Otherwise, if the peer has already closed their end of the connection,
1335
0
    else if (State == kState_ReceiveShutdown)
1336
0
        err = DoClose(err, false);
1337
1338
0
    return err;
1339
0
}
1340
1341
INET_ERROR TCPEndPoint::Close()
1342
0
{
1343
    // Clear the receive queue.
1344
0
    PacketBuffer::Free(mRcvQueue);
1345
0
    mRcvQueue = NULL;
1346
1347
    // Suppress closing callbacks, since the application explicitly called Close().
1348
0
    OnConnectionClosed = NULL;
1349
0
    OnPeerClose = NULL;
1350
0
    OnConnectComplete = NULL;
1351
1352
    // Perform a graceful close.
1353
0
    return DoClose(INET_NO_ERROR, true);
1354
0
}
1355
1356
void TCPEndPoint::Abort()
1357
0
{
1358
    // Suppress closing callbacks, since the application explicitly called Abort().
1359
0
    OnConnectionClosed = NULL;
1360
0
    OnPeerClose = NULL;
1361
0
    OnConnectComplete = NULL;
1362
1363
0
    DoClose(INET_ERROR_CONNECTION_ABORTED, true);
1364
0
}
1365
1366
void TCPEndPoint::Free()
1367
0
{
1368
0
    INET_ERROR err;
1369
1370
    // Ensure no callbacks to the app after this point.
1371
0
    OnAcceptError = NULL;
1372
0
    OnConnectComplete = NULL;
1373
0
    OnConnectionReceived = NULL;
1374
0
    OnConnectionClosed = NULL;
1375
0
    OnPeerClose = NULL;
1376
0
    OnDataReceived = NULL;
1377
0
    OnDataSent = NULL;
1378
1379
    // Ensure the end point is Closed or Closing.
1380
0
    err = Close();
1381
0
    if (err != INET_NO_ERROR)
1382
0
        Abort();
1383
1384
    // Release the Retain() that happened when the end point was allocated
1385
    // [on LwIP, the object may still be alive if DoClose() used the
1386
    // EndPointBasis::DeferredFree() method.]
1387
0
    Release();
1388
0
}
1389
1390
#if INET_TCP_IDLE_CHECK_INTERVAL > 0
1391
void TCPEndPoint::SetIdleTimeout(uint32_t timeoutMS)
1392
0
{
1393
0
    uint32_t newIdleTimeout = (timeoutMS + (INET_TCP_IDLE_CHECK_INTERVAL - 1)) / INET_TCP_IDLE_CHECK_INTERVAL;
1394
0
    InetLayer& lInetLayer = Layer();
1395
0
    bool isIdleTimerRunning = lInetLayer.IsIdleTimerRunning();
1396
1397
0
    if (newIdleTimeout > UINT16_MAX)
1398
0
        newIdleTimeout = UINT16_MAX;
1399
0
    mIdleTimeout = mRemainingIdleTime = newIdleTimeout;
1400
1401
0
    if (!isIdleTimerRunning && mIdleTimeout)
1402
0
    {
1403
0
        Weave::System::Layer& lSystemLayer = SystemLayer();
1404
1405
0
        lSystemLayer.StartTimer(INET_TCP_IDLE_CHECK_INTERVAL, InetLayer::HandleTCPInactivityTimer, &lInetLayer);
1406
0
    }
1407
0
}
1408
#endif // INET_TCP_IDLE_CHECK_INTERVAL > 0
1409
1410
bool TCPEndPoint::IsConnected(int state)
1411
0
{
1412
0
    return state == kState_Connected || state == kState_SendShutdown || state == kState_ReceiveShutdown || state == kState_Closing;
1413
0
}
1414
1415
void TCPEndPoint::Init(InetLayer *inetLayer)
1416
0
{
1417
0
    InitEndPointBasis(*inetLayer);
1418
0
    ReceiveEnabled = true;
1419
1420
    // Initialize to zero for using system defaults.
1421
0
    mConnectTimeoutMsecs = 0;
1422
1423
0
#if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1424
0
    mUserTimeoutMillis = INET_CONFIG_DEFAULT_TCP_USER_TIMEOUT_MSEC;
1425
1426
0
    mUserTimeoutTimerRunning = false;
1427
1428
#if INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1429
    mIsTCPSendIdle = true;
1430
1431
    mTCPSendQueuePollPeriodMillis = INET_CONFIG_TCP_SEND_QUEUE_POLL_INTERVAL_MSEC;
1432
1433
    mTCPSendQueueRemainingPollCount = MaxTCPSendQueuePolls();
1434
1435
    OnTCPSendIdleChanged = NULL;
1436
#endif // INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1437
1438
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1439
1440
0
    mBytesWrittenSinceLastProbe = 0;
1441
1442
0
    mLastTCPKernelSendQueueLen = 0;
1443
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1444
1445
0
#endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1446
1447
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1448
    mUnackedLength = 0;
1449
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1450
0
}
1451
1452
INET_ERROR TCPEndPoint::DriveSending()
1453
0
{
1454
0
    INET_ERROR err = INET_NO_ERROR;
1455
1456
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1457
1458
    // Lock LwIP stack
1459
    LOCK_TCPIP_CORE();
1460
1461
    // If the connection hasn't been aborted ...
1462
    if (mTCP != NULL)
1463
    {
1464
        err_t lwipErr;
1465
1466
        // Determine the current send window size. This is the maximum amount we can write to the connection.
1467
        uint16_t sendWindowSize = tcp_sndbuf(mTCP);
1468
1469
        // If there's data to be sent and the send window is open...
1470
        bool canSend = (RemainingToSend() > 0 && sendWindowSize > 0);
1471
        if (canSend)
1472
        {
1473
            // Find first packet buffer with remaining data to send by skipping
1474
            // all sent but un-acked data.
1475
            TCPEndPoint::BufferOffset startOfUnsent = FindStartOfUnsent();
1476
            const Weave::System::PacketBuffer* currentUnsentBuf = startOfUnsent.buffer;
1477
            uint16_t unsentOffset = startOfUnsent.offset;
1478
1479
            // While there's data to be sent and a window to send it in...
1480
            do
1481
            {
1482
                VerifyOrDie(currentUnsentBuf != NULL);
1483
1484
                uint16_t bufDataLen = currentUnsentBuf->DataLength();
1485
1486
                // Get a pointer to the start of unsent data within the first buffer on the unsent queue.
1487
                const uint8_t *sendData = currentUnsentBuf->Start() + unsentOffset;
1488
1489
                // Determine the amount of data to send from the current buffer.
1490
                uint16_t sendLen = bufDataLen - unsentOffset;
1491
                if (sendLen > sendWindowSize)
1492
                    sendLen = sendWindowSize;
1493
1494
                // Call LwIP to queue the data to be sent, telling it if there's more data to come.
1495
                // Data is queued in-place as a reference within the source packet buffer. It is
1496
                // critical that the underlying packet buffer not be freed until the data
1497
                // is acknowledged, otherwise retransmissions could use an invalid
1498
                // backing. Using TCP_WRITE_FLAG_COPY would eliminate this requirement, but overall
1499
                // requires many more memory allocations which may be problematic when very
1500
                // memory-constrained or when using pool-based allocations.
1501
                lwipErr = tcp_write(mTCP, sendData, sendLen, (canSend) ? TCP_WRITE_FLAG_MORE : 0);
1502
                if (lwipErr != ERR_OK)
1503
                {
1504
                    err = Weave::System::MapErrorLwIP(lwipErr);
1505
                    break;
1506
                }
1507
                // Start accounting for the data sent as yet-to-be-acked.
1508
                mUnackedLength += sendLen;
1509
1510
                // Adjust the unsent data offset by the length of data that was written.
1511
                // If the entire buffer has been sent advance to the next one.
1512
                unsentOffset += sendLen;
1513
                if (unsentOffset == bufDataLen)
1514
                {
1515
                    currentUnsentBuf = currentUnsentBuf->Next();
1516
                    unsentOffset = 0;
1517
                }
1518
1519
                // Adjust the remaining window size.
1520
                sendWindowSize -= sendLen;
1521
1522
                // Determine if there's more data to be sent after this buffer.
1523
                canSend = (RemainingToSend() > 0 && sendWindowSize > 0);
1524
            } while (canSend);
1525
1526
            // Call LwIP to send the queued data.
1527
            INET_FAULT_INJECT(FaultInjection::kFault_Send, err = Weave::System::MapErrorLwIP(ERR_RTE));
1528
1529
            if (err == INET_NO_ERROR)
1530
            {
1531
                lwipErr = tcp_output(mTCP);
1532
1533
                if (lwipErr != ERR_OK)
1534
                    err = Weave::System::MapErrorLwIP(lwipErr);
1535
            }
1536
        }
1537
1538
        if (err == INET_NO_ERROR)
1539
        {
1540
            // If in the SendShutdown state and the unsent queue is now empty, shutdown the PCB for sending.
1541
            if (State == kState_SendShutdown && (RemainingToSend() == 0))
1542
            {
1543
                lwipErr = tcp_shutdown(mTCP, 0, 1);
1544
                if (lwipErr != ERR_OK)
1545
                    err = Weave::System::MapErrorLwIP(lwipErr);
1546
            }
1547
        }
1548
    }
1549
1550
    else
1551
        err = INET_ERROR_CONNECTION_ABORTED;
1552
1553
    // Unlock LwIP stack
1554
    UNLOCK_TCPIP_CORE();
1555
1556
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1557
1558
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1559
1560
0
#ifdef MSG_NOSIGNAL
1561
0
    const int sendFlags = MSG_NOSIGNAL;
1562
#else
1563
    const int sendFlags = 0;
1564
#endif
1565
1566
    // Pretend send() fails in the while loop below
1567
0
    INET_FAULT_INJECT(FaultInjection::kFault_Send,
1568
0
                      {
1569
0
                          err = Weave::System::MapErrorPOSIX(EIO);
1570
0
                          DoClose(err, false);
1571
0
                          return err;
1572
0
                      });
1573
1574
0
    while (mSendQueue != NULL)
1575
0
    {
1576
0
        uint16_t bufLen = mSendQueue->DataLength();
1577
1578
0
        ssize_t lenSent = send(mSocket, mSendQueue->Start(), (size_t) bufLen, sendFlags);
1579
1580
0
        if (lenSent == -1)
1581
0
        {
1582
0
            if (errno != EAGAIN && errno != EWOULDBLOCK)
1583
0
                err = (errno == EPIPE) ? INET_ERROR_PEER_DISCONNECTED : Weave::System::MapErrorPOSIX(errno);
1584
0
            break;
1585
0
        }
1586
1587
        // Mark the connection as being active.
1588
0
        MarkActive();
1589
1590
0
        if (lenSent < bufLen)
1591
0
            mSendQueue->ConsumeHead(lenSent);
1592
0
        else
1593
0
            mSendQueue = PacketBuffer::FreeHead(mSendQueue);
1594
1595
0
        if (OnDataSent != NULL)
1596
0
            OnDataSent(this, (uint16_t) lenSent);
1597
1598
#if INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1599
        // TCP Send is not Idle; Set state and notify if needed
1600
1601
        SetTCPSendIdleAndNotifyChange(false);
1602
#endif // INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1603
1604
0
#if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1605
0
        mBytesWrittenSinceLastProbe += lenSent;
1606
1607
0
        bool isProgressing = false;
1608
1609
0
        err = CheckConnectionProgress(isProgressing);
1610
0
        if (err != INET_NO_ERROR)
1611
0
        {
1612
0
            break;
1613
0
        }
1614
1615
0
        if (!mUserTimeoutTimerRunning)
1616
0
        {
1617
            // Timer was not running before this write. So, start
1618
            // the timer.
1619
1620
0
            StartTCPUserTimeoutTimer();
1621
0
        }
1622
0
        else if (isProgressing)
1623
0
        {
1624
            // Progress is being made. So, shift the timer
1625
            // forward if it was started.
1626
1627
0
            RestartTCPUserTimeoutTimer();
1628
0
        }
1629
0
#endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1630
1631
0
        if (lenSent < bufLen)
1632
0
            break;
1633
0
    }
1634
1635
0
    if (err == INET_NO_ERROR)
1636
0
    {
1637
        // If we're in the SendShutdown state and the send queue is now empty, shutdown writing on the socket.
1638
0
        if (State == kState_SendShutdown && mSendQueue == NULL)
1639
0
        {
1640
0
            if (shutdown(mSocket, SHUT_WR) != 0)
1641
0
                err = Weave::System::MapErrorPOSIX(errno);
1642
0
        }
1643
0
    }
1644
1645
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1646
1647
0
    if (err != INET_NO_ERROR)
1648
0
        DoClose(err, false);
1649
1650
0
    WEAVE_SYSTEM_FAULT_INJECT_ASYNC_EVENT();
1651
1652
0
    return err;
1653
0
}
1654
1655
void TCPEndPoint::DriveReceiving()
1656
0
{
1657
    // If there's data in the receive queue and the app is ready to receive it then call the app's callback
1658
    // with the entire receive queue.
1659
0
    if (mRcvQueue != NULL && ReceiveEnabled && OnDataReceived != NULL)
1660
0
    {
1661
0
        PacketBuffer *rcvQueue = mRcvQueue;
1662
0
        mRcvQueue = NULL;
1663
0
        OnDataReceived(this, rcvQueue);
1664
0
    }
1665
1666
    // If the connection is closing, and the receive queue is now empty, call DoClose() to complete
1667
    // the process of closing the connection.
1668
0
    if (State == kState_Closing && mRcvQueue == NULL)
1669
0
        DoClose(INET_NO_ERROR, false);
1670
0
}
1671
1672
void TCPEndPoint::HandleConnectComplete(INET_ERROR err)
1673
0
{
1674
    // If the connect succeeded enter the Connected state and call the app's callback.
1675
0
    if (err == INET_NO_ERROR)
1676
0
    {
1677
        // Stop the TCP Connect timer in case it is still running.
1678
0
        StopConnectTimer();
1679
1680
        // Mark the connection as being active.
1681
0
        MarkActive();
1682
1683
0
        State = kState_Connected;
1684
0
        if (OnConnectComplete != NULL)
1685
0
            OnConnectComplete(this, INET_NO_ERROR);
1686
0
    }
1687
1688
    // Otherwise, close the connection with an error.
1689
0
    else
1690
0
        DoClose(err, false);
1691
0
}
1692
1693
INET_ERROR TCPEndPoint::DoClose(INET_ERROR err, bool suppressCallback)
1694
0
{
1695
0
    int             oldState        = State;
1696
1697
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1698
0
    struct linger   lingerStruct;
1699
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1700
1701
    // If in one of the connected states (Connected, LocalShutdown, PeerShutdown or Closing)
1702
    // AND this is a graceful close (i.e. not prompted by an error)
1703
    // AND there is data waiting to be processed on either the send or receive queues
1704
    // ... THEN enter the Closing state, allowing the queued data to drain,
1705
    // ... OTHERWISE go straight to the Closed state.
1706
0
    if (IsConnected() && err == INET_NO_ERROR && (mSendQueue != NULL || mRcvQueue != NULL))
1707
0
        State = kState_Closing;
1708
0
    else
1709
0
        State = kState_Closed;
1710
1711
    // Stop the Connect timer in case it is still running.
1712
1713
0
    StopConnectTimer();
1714
1715
    // If not making a state transition, return immediately.
1716
0
    if (State == oldState)
1717
0
        return INET_NO_ERROR;
1718
1719
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1720
1721
    // Lock LwIP stack
1722
    LOCK_TCPIP_CORE();
1723
1724
    // If the LwIP PCB hasn't been closed yet...
1725
    if (mTCP != NULL)
1726
    {
1727
        // If the endpoint was a connection endpoint (vs. a listening endpoint)...
1728
        if (oldState != kState_Listening)
1729
        {
1730
            // Prevent further callbacks for incoming data.  This has the effect of instructing
1731
            // LwIP to discard any further data received from the peer.
1732
            tcp_recv(mTCP, NULL);
1733
1734
            // If entering the Closed state...
1735
            if (State == kState_Closed)
1736
            {
1737
                // Prevent further callbacks to the error handler.
1738
                //
1739
                // Note: It is important to understand that LwIP can continue to make callbacks after
1740
                // a PCB has been closed via the tcp_close() API. In particular, LwIP will continue
1741
                // to call the 'data sent' callback to signal the acknowledgment of data that was
1742
                // sent, but not acknowledged, prior to the close call. Additionally, LwIP will call
1743
                // the error callback if the peer fails to respond in a timely manner to the either
1744
                // sent data or the FIN. Unfortunately, there is no callback in the case where the
1745
                // connection closes successfully. Because of this, it is impossible know definitively
1746
                // when LwIP will no longer make callbacks to its user. Thus we must block further
1747
                // callbacks to prevent them from happening after the endpoint has been freed.
1748
                //
1749
                tcp_err(mTCP, NULL);
1750
1751
                // If the endpoint is being closed without error, THEN call tcp_close() to close the underlying
1752
                // TCP connection gracefully, preserving any in-transit send data.
1753
                if (err == INET_NO_ERROR)
1754
                {
1755
                    tcp_close(mTCP);
1756
                }
1757
1758
                // OTHERWISE, call tcp_abort() to abort the TCP connection, discarding any in-transit data.
1759
                else
1760
                {
1761
                    tcp_abort(mTCP);
1762
                }
1763
1764
                // Discard the reference to the PCB to ensure there is no further interaction with it
1765
                // after this point.
1766
                mTCP = NULL;
1767
                mLwIPEndPointType = kLwIPEndPointType_Unknown;
1768
            }
1769
        }
1770
1771
        // OTHERWISE the endpoint was being used for listening, so simply close it.
1772
        else
1773
        {
1774
            tcp_close(mTCP);
1775
1776
            // Discard the reference to the PCB to ensure there is no further interaction with it
1777
            // after this point.
1778
            mTCP = NULL;
1779
            mLwIPEndPointType = kLwIPEndPointType_Unknown;
1780
        }
1781
    }
1782
1783
    // Unlock LwIP stack
1784
    UNLOCK_TCPIP_CORE();
1785
1786
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1787
1788
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1789
1790
    // If the socket hasn't been closed already...
1791
0
    if (mSocket != INET_INVALID_SOCKET_FD)
1792
0
    {
1793
        // If entering the Closed state
1794
        // OR if entering the Closing state, and there's no unsent data in the send queue
1795
        // THEN close the socket.
1796
0
        if (State == kState_Closed ||
1797
0
            (State == kState_Closing && mSendQueue == NULL))
1798
0
        {
1799
0
            Weave::System::Layer& lSystemLayer = SystemLayer();
1800
1801
            // If aborting the connection, ensure we send a TCP RST.
1802
0
            if (IsConnected(oldState) && err != INET_NO_ERROR)
1803
0
            {
1804
0
                lingerStruct.l_onoff = 1;
1805
0
                lingerStruct.l_linger = 0;
1806
1807
0
                if (setsockopt(mSocket, SOL_SOCKET, SO_LINGER, &lingerStruct, sizeof(lingerStruct)) != 0)
1808
0
                    WeaveLogError(Inet, "SO_LINGER: %d", errno);
1809
0
            }
1810
1811
0
            if (close(mSocket) != 0 && err == INET_NO_ERROR)
1812
0
                err = Weave::System::MapErrorPOSIX(errno);
1813
0
            mSocket = INET_INVALID_SOCKET_FD;
1814
1815
            // Wake the thread calling select so that it recognizes the socket is closed.
1816
0
            lSystemLayer.WakeSelect();
1817
0
        }
1818
0
    }
1819
1820
    // Clear any results from select() that indicate pending I/O for the socket.
1821
0
    mPendingIO.Clear();
1822
1823
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1824
1825
0
#if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1826
    // Stop the TCP UserTimeout timer if it is running.
1827
0
    StopTCPUserTimeoutTimer();
1828
0
#endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1829
1830
    // If entering the Closed state...
1831
0
    if (State == kState_Closed)
1832
0
    {
1833
        // Clear clear the send and receive queues.
1834
0
        PacketBuffer::Free(mSendQueue);
1835
0
        mSendQueue = NULL;
1836
0
        PacketBuffer::Free(mRcvQueue);
1837
0
        mRcvQueue = NULL;
1838
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1839
        mUnackedLength = 0;
1840
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1841
1842
        // Call the appropriate app callback if allowed.
1843
0
        if (!suppressCallback)
1844
0
        {
1845
0
            if (oldState == kState_Connecting)
1846
0
            {
1847
0
                if (OnConnectComplete != NULL)
1848
0
                    OnConnectComplete(this, err);
1849
0
            }
1850
0
            else if ((oldState == kState_Connected || oldState == kState_SendShutdown ||
1851
0
                      oldState == kState_ReceiveShutdown || oldState == kState_Closing) &&
1852
0
                     OnConnectionClosed != NULL)
1853
0
                OnConnectionClosed(this, err);
1854
0
        }
1855
1856
        // Decrement the ref count that was added when the connection started (in Connect()) or listening started (in Listen()).
1857
        //
1858
        // When using LwIP, post a callback to Release() rather than calling it directly. Since up-calls
1859
        // from LwIP are delivered as events (via the LwIP* methods), we must ensure that all events have been
1860
        // cleared from the queue before the end point gets freed, otherwise we'll end up accessing freed memory.
1861
        // We achieve this by first preventing further up-calls from LwIP (via the call to tcp_abort() above)
1862
        // and then queuing the Release() call to happen after all existing events have been processed.
1863
        //
1864
0
        if (oldState != kState_Ready && oldState != kState_Bound)
1865
0
        {
1866
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1867
            DeferredFree(kReleaseDeferralErrorTactic_Ignore);
1868
#else // !WEAVE_SYSTEM_CONFIG_USE_LWIP
1869
0
            Release();
1870
0
#endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP
1871
0
        }
1872
0
    }
1873
1874
0
    return err;
1875
0
}
1876
1877
#if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
1878
void TCPEndPoint::TCPUserTimeoutHandler(Weave::System::Layer* aSystemLayer, void* aAppState, Weave::System::Error aError)
1879
0
{
1880
0
    TCPEndPoint * tcpEndPoint = reinterpret_cast<TCPEndPoint *>(aAppState);
1881
1882
0
    VerifyOrDie((aSystemLayer != NULL) && (tcpEndPoint != NULL));
1883
1884
    // Set the timer running flag to false
1885
0
    tcpEndPoint->mUserTimeoutTimerRunning = false;
1886
1887
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1888
0
    INET_ERROR err = INET_NO_ERROR;
1889
0
    bool isProgressing = false;
1890
0
    err = tcpEndPoint->CheckConnectionProgress(isProgressing);
1891
0
    SuccessOrExit(err);
1892
1893
0
    if (tcpEndPoint->mLastTCPKernelSendQueueLen == 0)
1894
0
    {
1895
#if INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1896
        // If the kernel TCP send queue as well as the TCPEndPoint
1897
        // send queue have been flushed then notify application
1898
        // that all data has been acknowledged.
1899
1900
        if (tcpEndPoint->mSendQueue == NULL)
1901
        {
1902
            tcpEndPoint->SetTCPSendIdleAndNotifyChange(true);
1903
        }
1904
#endif // INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1905
0
    }
1906
0
    else
1907
    // There is data in the TCP Send Queue
1908
0
    {
1909
0
        if (isProgressing)
1910
0
        {
1911
            // Data is flowing, so restart the UserTimeout timer
1912
            // to shift it forward while also resetting the max
1913
            // poll count.
1914
1915
0
            tcpEndPoint->StartTCPUserTimeoutTimer();
1916
0
        }
1917
0
        else
1918
0
        {
1919
#if INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1920
            // Data flow is not progressing.
1921
            // Decrement the remaining max TCP send queue polls.
1922
1923
            tcpEndPoint->mTCPSendQueueRemainingPollCount--;
1924
1925
            VerifyOrExit(tcpEndPoint->mTCPSendQueueRemainingPollCount != 0,
1926
                         err = INET_ERROR_TCP_USER_TIMEOUT);
1927
1928
            // Restart timer to poll again
1929
1930
            tcpEndPoint->ScheduleNextTCPUserTimeoutPoll(tcpEndPoint->mTCPSendQueuePollPeriodMillis);
1931
#else
1932
            // Close the connection as the TCP UserTimeout has expired
1933
1934
0
            ExitNow(err = INET_ERROR_TCP_USER_TIMEOUT);
1935
0
#endif // !INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1936
0
        }
1937
0
    }
1938
1939
0
exit:
1940
1941
0
    if (err != INET_NO_ERROR)
1942
0
    {
1943
        // Close the connection as the TCP UserTimeout has expired
1944
1945
0
        tcpEndPoint->DoClose(err, false);
1946
0
    }
1947
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
1948
1949
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1950
    // Close Connection as we have timed out and there is still
1951
    // data not sent out successfully.
1952
1953
    tcpEndPoint->DoClose(INET_ERROR_TCP_USER_TIMEOUT, false);
1954
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1955
1956
0
}
1957
1958
void TCPEndPoint::ScheduleNextTCPUserTimeoutPoll(uint32_t aTimeOut)
1959
0
{
1960
0
    Weave::System::Layer& lSystemLayer = SystemLayer();
1961
1962
0
    lSystemLayer.StartTimer(aTimeOut, TCPUserTimeoutHandler, this);
1963
0
}
1964
1965
#if INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1966
void TCPEndPoint::SetTCPSendIdleAndNotifyChange(bool aIsTCPSendIdle)
1967
{
1968
    if (mIsTCPSendIdle != aIsTCPSendIdle)
1969
    {
1970
        WeaveLogDetail(Inet, "TCP con send channel idle state changed : %s", aIsTCPSendIdle ? "false->true" : "true->false");
1971
1972
        // Set the current Idle state
1973
        mIsTCPSendIdle = aIsTCPSendIdle;
1974
1975
        if (OnTCPSendIdleChanged)
1976
        {
1977
            OnTCPSendIdleChanged(this, mIsTCPSendIdle);
1978
        }
1979
    }
1980
}
1981
#endif // INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1982
1983
void TCPEndPoint::StartTCPUserTimeoutTimer()
1984
0
{
1985
0
    uint32_t timeOut = mUserTimeoutMillis;
1986
1987
#if INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1988
    //Set timeout to the poll interval
1989
1990
    timeOut = mTCPSendQueuePollPeriodMillis;
1991
1992
    // Reset the poll count
1993
1994
    mTCPSendQueueRemainingPollCount = MaxTCPSendQueuePolls();
1995
#endif // INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
1996
1997
0
    ScheduleNextTCPUserTimeoutPoll(timeOut);
1998
1999
0
    mUserTimeoutTimerRunning = true;
2000
0
}
2001
2002
void TCPEndPoint::StopTCPUserTimeoutTimer()
2003
0
{
2004
0
    Weave::System::Layer& lSystemLayer = SystemLayer();
2005
2006
0
    lSystemLayer.CancelTimer(TCPUserTimeoutHandler, this);
2007
2008
0
    mUserTimeoutTimerRunning = false;
2009
0
}
2010
2011
void TCPEndPoint::RestartTCPUserTimeoutTimer()
2012
0
{
2013
0
    StopTCPUserTimeoutTimer();
2014
2015
0
    StartTCPUserTimeoutTimer();
2016
0
}
2017
2018
#endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
2019
2020
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
2021
2022
uint32_t TCPEndPoint::RemainingToSend()
2023
{
2024
    if (mSendQueue == NULL)
2025
    {
2026
        return 0;
2027
    }
2028
    else
2029
    {
2030
        // We can never have reported more unacked data than there is pending
2031
        // in the send queue! This would indicate a critical accounting bug.
2032
        VerifyOrDie(mUnackedLength <= mSendQueue->TotalLength());
2033
2034
        return mSendQueue->TotalLength() - mUnackedLength;
2035
    }
2036
}
2037
2038
TCPEndPoint::BufferOffset TCPEndPoint::FindStartOfUnsent()
2039
{
2040
    // Find first packet buffer with remaining data to send by skipping
2041
    // all sent but un-acked data. This is necessary because of the Consume()
2042
    // call in HandleDataSent(), which potentially releases backing memory for
2043
    // fully-sent packet buffers, causing an invalidation of all possible
2044
    // offsets one might have cached. The TCP acnowledgements may come back
2045
    // with a variety of sizes depending on prior activity, and size of the
2046
    // send window. The only way to ensure we get the correct offsets into
2047
    // unsent data while retaining the buffers that have un-acked data is to
2048
    // traverse all sent-but-unacked data in the chain to reach the beginning
2049
    // of ready-to-send data.
2050
    Weave::System::PacketBuffer* currentUnsentBuf = mSendQueue;
2051
    uint16_t unsentOffset = 0;
2052
    uint32_t leftToSkip = mUnackedLength;
2053
2054
    VerifyOrDie(leftToSkip < mSendQueue->TotalLength());
2055
2056
    while (leftToSkip > 0)
2057
    {
2058
        VerifyOrDie(currentUnsentBuf != NULL);
2059
        uint16_t bufDataLen = currentUnsentBuf->DataLength();
2060
        if (leftToSkip >= bufDataLen)
2061
        {
2062
            // We have more to skip than current packet buffer size.
2063
            // Follow the chain to continue.
2064
            currentUnsentBuf = currentUnsentBuf->Next();
2065
            leftToSkip -= bufDataLen;
2066
        }
2067
        else
2068
        {
2069
            // Done skipping all data, currentUnsentBuf is first packet buffer
2070
            // containing unsent data.
2071
            unsentOffset = leftToSkip;
2072
            leftToSkip = 0;
2073
        }
2074
    }
2075
2076
    TCPEndPoint::BufferOffset startOfUnsent;
2077
    startOfUnsent.buffer = currentUnsentBuf;
2078
    startOfUnsent.offset = unsentOffset;
2079
2080
    return startOfUnsent;
2081
}
2082
2083
INET_ERROR TCPEndPoint::GetPCB(IPAddressType addrType)
2084
{
2085
    // IMMPORTANT: This method MUST be called with the LwIP stack LOCKED!
2086
2087
#if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5
2088
    if (mTCP == NULL)
2089
    {
2090
        switch (addrType)
2091
        {
2092
        case kIPAddressType_IPv6:
2093
            mTCP = tcp_new_ip_type(IPADDR_TYPE_V6);
2094
            break;
2095
2096
#if INET_CONFIG_ENABLE_IPV4
2097
        case kIPAddressType_IPv4:
2098
            mTCP = tcp_new_ip_type(IPADDR_TYPE_V4);
2099
            break;
2100
#endif // INET_CONFIG_ENABLE_IPV4
2101
2102
        default:
2103
            return INET_ERROR_WRONG_ADDRESS_TYPE;
2104
        }
2105
2106
        if (mTCP == NULL)
2107
        {
2108
            return INET_ERROR_NO_MEMORY;
2109
        }
2110
        else
2111
        {
2112
            mLwIPEndPointType = kLwIPEndPointType_TCP;
2113
        }
2114
    }
2115
    else
2116
    {
2117
        switch (IP_GET_TYPE(&mTCP->local_ip))
2118
        {
2119
        case IPADDR_TYPE_V6:
2120
            if (addrType != kIPAddressType_IPv6)
2121
                return INET_ERROR_WRONG_ADDRESS_TYPE;
2122
            break;
2123
2124
#if INET_CONFIG_ENABLE_IPV4
2125
        case IPADDR_TYPE_V4:
2126
            if (addrType != kIPAddressType_IPv4)
2127
                return INET_ERROR_WRONG_ADDRESS_TYPE;
2128
            break;
2129
#endif // INET_CONFIG_ENABLE_IPV4
2130
2131
        default:
2132
            break;
2133
        }
2134
    }
2135
#else // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
2136
    if (mTCP == NULL)
2137
    {
2138
        if (addrType == kIPAddressType_IPv6)
2139
            mTCP = tcp_new_ip6();
2140
#if INET_CONFIG_ENABLE_IPV4
2141
        else if (addrType == kIPAddressType_IPv4)
2142
            mTCP = tcp_new();
2143
#endif // INET_CONFIG_ENABLE_IPV4
2144
        else
2145
            return INET_ERROR_WRONG_ADDRESS_TYPE;
2146
        if (mTCP == NULL)
2147
        {
2148
            return INET_ERROR_NO_MEMORY;
2149
        }
2150
        else
2151
        {
2152
            mLwIPEndPointType = kLwIPEndPointType_TCP;
2153
        }
2154
    }
2155
    else
2156
    {
2157
#if INET_CONFIG_ENABLE_IPV4
2158
        const IPAddressType pcbType = PCB_ISIPV6(mTCP) ? kIPAddressType_IPv6 : kIPAddressType_IPv4;
2159
#else // !INET_CONFIG_ENABLE_IPV4
2160
        const IPAddressType pcbType = kIPAddressType_IPv6;
2161
#endif // !INET_CONFIG_ENABLE_IPV4
2162
        if (addrType != pcbType)
2163
            return INET_ERROR_WRONG_ADDRESS_TYPE;
2164
    }
2165
#endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5
2166
2167
    return INET_NO_ERROR;
2168
}
2169
2170
void TCPEndPoint::HandleDataSent(uint16_t lenSent)
2171
{
2172
    if (IsConnected())
2173
    {
2174
        // Ensure we do not have internal inconsistency in the lwIP, which
2175
        // could cause invalid pointer accesses.
2176
        if (lenSent > mUnackedLength)
2177
        {
2178
            WeaveLogError(Inet, "Got more ACKed bytes (%d) than were pending (%d)", (int)lenSent, (int)mUnackedLength);
2179
            DoClose(INET_ERROR_UNEXPECTED_EVENT, false);
2180
            return;
2181
        }
2182
        else if (mSendQueue == NULL)
2183
        {
2184
            WeaveLogError(Inet, "Got ACK for %d bytes but data backing gone", (int)lenSent);
2185
            DoClose(INET_ERROR_UNEXPECTED_EVENT, false);
2186
            return;
2187
        }
2188
2189
        // Consume data off the head of the send queue equal to the amount of data being acknowledged.
2190
        mSendQueue = mSendQueue->Consume(lenSent);
2191
        mUnackedLength -= lenSent;
2192
2193
#if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
2194
        // Only change the UserTimeout timer if lenSent > 0,
2195
        // indicating progress being made in sending data
2196
        // across.
2197
        if (lenSent > 0)
2198
        {
2199
            if (RemainingToSend() == 0)
2200
            {
2201
                // If the output queue has been flushed then stop the timer.
2202
2203
                StopTCPUserTimeoutTimer();
2204
2205
#if INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
2206
                // Notify up if all outstanding data has been acknowledged
2207
2208
                SetTCPSendIdleAndNotifyChange(true);
2209
#endif // INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
2210
            }
2211
            else
2212
            {
2213
                // Progress is being made. So, shift the timer
2214
                // forward if it was started.
2215
                RestartTCPUserTimeoutTimer();
2216
            }
2217
        }
2218
#endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
2219
2220
        // Mark the connection as being active.
2221
        MarkActive();
2222
2223
        // If requested, call the app's OnDataSent callback.
2224
        if (OnDataSent != NULL)
2225
            OnDataSent(this, lenSent);
2226
2227
        // If unsent data exists, attempt to send it now...
2228
        if (RemainingToSend() > 0)
2229
            DriveSending();
2230
2231
        // If in the closing state and the send queue is now empty, attempt to transition to closed.
2232
        if ((State == kState_Closing) && (RemainingToSend() == 0))
2233
            DoClose(INET_NO_ERROR, false);
2234
    }
2235
}
2236
2237
void TCPEndPoint::HandleDataReceived(PacketBuffer *buf)
2238
{
2239
    // Only receive new data while in the Connected or SendShutdown states.
2240
    if (State == kState_Connected || State == kState_SendShutdown)
2241
    {
2242
        // Mark the connection as being active.
2243
        MarkActive();
2244
2245
        // If we received a data buffer, queue it on the receive queue.  If there's already data in
2246
        // the queue, compact the data into the head buffer.
2247
        if (buf != NULL)
2248
        {
2249
            if (mRcvQueue == NULL)
2250
                mRcvQueue = buf;
2251
            else
2252
            {
2253
                mRcvQueue->AddToEnd(buf);
2254
                mRcvQueue->CompactHead();
2255
            }
2256
        }
2257
2258
        // Otherwise buf == NULL means the other side closed the connection, so ...
2259
        else {
2260
2261
            // If in the Connected state and the app has provided an OnPeerClose callback,
2262
            // enter the ReceiveShutdown state.  Providing an OnPeerClose callback allows
2263
            // the app to decide whether to keep the send side of the connection open after
2264
            // the peer has closed. If no OnPeerClose is provided, we assume that the app
2265
            // wants to close both directions and automatically enter the Closing state.
2266
            if (State == kState_Connected && OnPeerClose != NULL)
2267
                State = kState_ReceiveShutdown;
2268
            else
2269
                State = kState_Closing;
2270
2271
            // Call the app's OnPeerClose.
2272
            if (OnPeerClose != NULL)
2273
                OnPeerClose(this);
2274
        }
2275
2276
        // Drive the received data into the app.
2277
        DriveReceiving();
2278
    }
2279
    else
2280
        PacketBuffer::Free(buf);
2281
}
2282
2283
void TCPEndPoint::HandleIncomingConnection(TCPEndPoint *conEP)
2284
{
2285
    INET_ERROR err = INET_NO_ERROR;
2286
    IPAddress peerAddr;
2287
    uint16_t peerPort;
2288
2289
    if (State == kState_Listening)
2290
    {
2291
        // If there's no callback available, fail with an error.
2292
        if (OnConnectionReceived == NULL)
2293
            err = INET_ERROR_NO_CONNECTION_HANDLER;
2294
2295
        // Extract the peer's address information.
2296
        if (err == INET_NO_ERROR)
2297
            err = conEP->GetPeerInfo(&peerAddr, &peerPort);
2298
2299
        // If successful, call the app's callback function.
2300
        if (err == INET_NO_ERROR)
2301
            OnConnectionReceived(this, conEP, peerAddr, peerPort);
2302
2303
        // Otherwise clean up and call the app's error callback.
2304
        else if (OnAcceptError != NULL)
2305
            OnAcceptError(this, err);
2306
    }
2307
    else
2308
        err = INET_ERROR_INCORRECT_STATE;
2309
2310
    // If something failed above, abort and free the connection end point.
2311
    if (err != INET_NO_ERROR)
2312
        conEP->Free();
2313
}
2314
2315
void TCPEndPoint::HandleError(INET_ERROR err)
2316
{
2317
    if (State == kState_Listening)
2318
    {
2319
        if (OnAcceptError != NULL)
2320
            OnAcceptError(this, err);
2321
    }
2322
    else
2323
        DoClose(err, false);
2324
}
2325
2326
err_t TCPEndPoint::LwIPHandleConnectComplete(void *arg, struct tcp_pcb *tpcb, err_t lwipErr)
2327
{
2328
    err_t res = ERR_OK;
2329
2330
    if (arg != NULL)
2331
    {
2332
        INET_ERROR              conErr;
2333
        TCPEndPoint*            ep              = static_cast<TCPEndPoint*>(arg);
2334
        Weave::System::Layer&   lSystemLayer    = ep->SystemLayer();
2335
2336
        if (lwipErr == ERR_OK)
2337
        {
2338
            // Setup LwIP callback functions for data transmission.
2339
            tcp_recv(ep->mTCP, LwIPHandleDataReceived);
2340
            tcp_sent(ep->mTCP, LwIPHandleDataSent);
2341
        }
2342
2343
        // Post callback to HandleConnectComplete.
2344
        conErr = Weave::System::MapErrorLwIP(lwipErr);
2345
        if (lSystemLayer.PostEvent(*ep, kInetEvent_TCPConnectComplete, (uintptr_t)conErr) != INET_NO_ERROR)
2346
            res = ERR_ABRT;
2347
    }
2348
    else
2349
        res = ERR_ABRT;
2350
2351
    if (res != ERR_OK)
2352
        tcp_abort(tpcb);
2353
2354
    return res;
2355
}
2356
2357
err_t TCPEndPoint::LwIPHandleIncomingConnection(void *arg, struct tcp_pcb *tpcb, err_t lwipErr)
2358
{
2359
    INET_ERROR err = Weave::System::MapErrorLwIP(lwipErr);
2360
2361
    if (arg != NULL)
2362
    {
2363
        TCPEndPoint*            listenEP        = static_cast<TCPEndPoint*>(arg);
2364
        TCPEndPoint*            conEP           = NULL;
2365
        Weave::System::Layer&   lSystemLayer    = listenEP->SystemLayer();
2366
2367
        // Tell LwIP we've accepted the connection so it can decrement the listen PCB's pending_accepts counter.
2368
        tcp_accepted(listenEP->mTCP);
2369
2370
        // If we did in fact receive a connection, rather than an error, attempt to allocate an end point object.
2371
        //
2372
        // NOTE: Although most of the LwIP callbacks defer the real work to happen on the endpoint's thread
2373
        // (by posting events to the thread's event queue) we can't do that here because as soon as this
2374
        // function returns, LwIP is free to begin calling callbacks on the new PCB. For that to work we need
2375
        // to have an end point associated with the PCB.
2376
        //
2377
        if (err == INET_NO_ERROR)
2378
        {
2379
            InetLayer& lInetLayer = listenEP->Layer();
2380
2381
            err = lInetLayer.NewTCPEndPoint(&conEP);
2382
        }
2383
2384
        // Ensure that TCP timers have been started
2385
        if (err == INET_NO_ERROR)
2386
        {
2387
            err = start_tcp_timers();
2388
        }
2389
2390
        // If successful in allocating an end point...
2391
        if (err == INET_NO_ERROR)
2392
        {
2393
            // Put the new end point into the Connected state.
2394
            conEP->State = kState_Connected;
2395
            conEP->mTCP = tpcb;
2396
            conEP->mLwIPEndPointType = kLwIPEndPointType_TCP;
2397
            conEP->Retain();
2398
2399
            // Setup LwIP callback functions for the new PCB.
2400
            tcp_arg(tpcb, conEP);
2401
            tcp_recv(tpcb, LwIPHandleDataReceived);
2402
            tcp_sent(tpcb, LwIPHandleDataSent);
2403
            tcp_err(tpcb, LwIPHandleError);
2404
2405
            // Post a callback to the HandleConnectionReceived() function, passing it the new end point.
2406
            if (lSystemLayer.PostEvent(*listenEP, kInetEvent_TCPConnectionReceived, (uintptr_t)conEP) != INET_NO_ERROR)
2407
            {
2408
                err = INET_ERROR_CONNECTION_ABORTED;
2409
                conEP->Release(); // for the Retain() above
2410
                conEP->Release();// for the Retain() in NewTCPEndPoint()
2411
            }
2412
        }
2413
2414
        // Otherwise, there was an error accepting the connection, so post a callback to the HandleError function.
2415
        else
2416
            lSystemLayer.PostEvent(*listenEP, kInetEvent_TCPError, (uintptr_t)err);
2417
    }
2418
    else
2419
        err = INET_ERROR_CONNECTION_ABORTED;
2420
2421
    if (err != INET_NO_ERROR && tpcb != NULL)
2422
    {
2423
        tcp_abort(tpcb);
2424
        return ERR_ABRT;
2425
    }
2426
    else
2427
    {
2428
        return ERR_OK;
2429
    }
2430
}
2431
2432
err_t TCPEndPoint::LwIPHandleDataReceived(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
2433
{
2434
    err_t res = ERR_OK;
2435
2436
    if (arg != NULL)
2437
    {
2438
        TCPEndPoint* ep = static_cast<TCPEndPoint*>(arg);
2439
        Weave::System::Layer& lSystemLayer = ep->SystemLayer();
2440
2441
        // Post callback to HandleDataReceived.
2442
        if (lSystemLayer.PostEvent(*ep, kInetEvent_TCPDataReceived, (uintptr_t)p) != INET_NO_ERROR)
2443
            res = ERR_ABRT;
2444
    }
2445
    else
2446
        res = ERR_ABRT;
2447
2448
    if (res != ERR_OK)
2449
        tcp_abort(tpcb);
2450
2451
    return res;
2452
}
2453
2454
err_t TCPEndPoint::LwIPHandleDataSent(void *arg, struct tcp_pcb *tpcb, u16_t len)
2455
{
2456
    err_t res = ERR_OK;
2457
2458
    if (arg != NULL)
2459
    {
2460
        TCPEndPoint* ep = static_cast<TCPEndPoint*>(arg);
2461
        Weave::System::Layer& lSystemLayer = ep->SystemLayer();
2462
2463
        // Post callback to HandleDataReceived.
2464
        if (lSystemLayer.PostEvent(*ep, kInetEvent_TCPDataSent, (uintptr_t)len) != INET_NO_ERROR)
2465
            res = ERR_ABRT;
2466
    }
2467
    else
2468
        res = ERR_ABRT;
2469
2470
    if (res != ERR_OK)
2471
        tcp_abort(tpcb);
2472
2473
    return res;
2474
}
2475
2476
void TCPEndPoint::LwIPHandleError(void *arg, err_t lwipErr)
2477
{
2478
    if (arg != NULL)
2479
    {
2480
        TCPEndPoint* ep = static_cast<TCPEndPoint*>(arg);
2481
        Weave::System::Layer& lSystemLayer = ep->SystemLayer();
2482
2483
        // At this point LwIP has already freed the PCB.  Since the thread that owns the TCPEndPoint may
2484
        // try to use the PCB before it receives the TCPError event posted below, we set the PCB to NULL
2485
        // as a means to signal the other thread that the connection has been aborted.  The implication
2486
        // of this is that the mTCP field is shared state between the two threads and thus must only be
2487
        // accessed with the LwIP lock held.
2488
        ep->mTCP = NULL;
2489
        ep->mLwIPEndPointType = kLwIPEndPointType_Unknown;
2490
2491
        // Post callback to HandleError.
2492
        INET_ERROR err = Weave::System::MapErrorLwIP(lwipErr);
2493
        lSystemLayer.PostEvent(*ep, kInetEvent_TCPError, (uintptr_t)err);
2494
    }
2495
}
2496
2497
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
2498
2499
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
2500
2501
INET_ERROR TCPEndPoint::BindSrcAddrFromIntf(IPAddressType addrType, InterfaceId intf)
2502
0
{
2503
0
    INET_ERROR err = INET_NO_ERROR;
2504
2505
    // If we are trying to make a TCP connection over a 'specified target interface',
2506
    // then we bind the TCPEndPoint to an IP address on that target interface
2507
    // and use that address as the source address for that connection. This is
2508
    // done in the event that directly binding the connection to the target
2509
    // interface is not allowed due to insufficient privileges.
2510
0
    IPAddress curAddr = IPAddress::Any;
2511
0
    InterfaceId curIntfId = INET_NULL_INTERFACEID;
2512
0
    bool ipAddrFound = false;
2513
2514
0
    VerifyOrExit(State != kState_Bound, err = INET_ERROR_NOT_SUPPORTED);
2515
2516
0
    for (InterfaceAddressIterator addrIter; addrIter.HasCurrent(); addrIter.Next())
2517
0
    {
2518
0
        curAddr = addrIter.GetAddress();
2519
0
        curIntfId = addrIter.GetInterface();
2520
2521
0
        if (curIntfId == intf)
2522
0
        {
2523
        // Search for an IPv4 address on the TargetInterface
2524
2525
0
#if INET_CONFIG_ENABLE_IPV4
2526
0
            if (addrType == kIPAddressType_IPv4)
2527
0
            {
2528
0
                if (curAddr.IsIPv4())
2529
0
                {
2530
                    // Bind to the IPv4 address of the TargetInterface
2531
0
                    ipAddrFound = true;
2532
0
                    err = Bind(kIPAddressType_IPv4, curAddr, 0, true);
2533
0
                    SuccessOrExit(err);
2534
2535
0
                    break;
2536
0
                }
2537
0
            }
2538
0
#endif // INET_CONFIG_ENABLE_IPV4
2539
0
            if (addrType == kIPAddressType_IPv6)
2540
0
            {
2541
                // Select an IPv6 address on the interface that is not
2542
                // a link local or a multicast address.
2543
                //TODO: Define a proper IPv6GlobalUnicast address checker.
2544
0
                if (!curAddr.IsIPv4() && !curAddr.IsIPv6LinkLocal() &&
2545
0
                    !curAddr.IsMulticast())
2546
0
                {
2547
                    // Bind to the IPv6 address of the TargetInterface
2548
0
                    ipAddrFound = true;
2549
0
                    err = Bind(kIPAddressType_IPv6, curAddr, 0, true);
2550
0
                    SuccessOrExit(err);
2551
2552
0
                    break;
2553
0
                }
2554
0
            }
2555
0
        }
2556
0
    }
2557
2558
0
    VerifyOrExit(ipAddrFound, err = INET_ERROR_NOT_SUPPORTED);
2559
2560
0
exit:
2561
0
    return err;
2562
0
}
2563
2564
INET_ERROR TCPEndPoint::GetSocket(IPAddressType addrType)
2565
0
{
2566
0
    if (mSocket == INET_INVALID_SOCKET_FD)
2567
0
    {
2568
0
        int family;
2569
0
        if (addrType == kIPAddressType_IPv6)
2570
0
            family = PF_INET6;
2571
0
#if INET_CONFIG_ENABLE_IPV4
2572
0
        else if (addrType == kIPAddressType_IPv4)
2573
0
            family = PF_INET;
2574
0
#endif // INET_CONFIG_ENABLE_IPV4
2575
0
        else
2576
0
            return INET_ERROR_WRONG_ADDRESS_TYPE;
2577
0
        mSocket = ::socket(family, SOCK_STREAM | SOCK_FLAGS, 0);
2578
0
        if (mSocket == -1)
2579
0
            return Weave::System::MapErrorPOSIX(errno);
2580
0
        mAddrType = addrType;
2581
2582
        // If creating an IPv6 socket, tell the kernel that it will be IPv6 only.  This makes it
2583
        // posible to bind two sockets to the same port, one for IPv4 and one for IPv6.
2584
0
#ifdef IPV6_V6ONLY
2585
0
        if (family == PF_INET6)
2586
0
        {
2587
0
            int one = 1;
2588
0
            setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &one, sizeof(one));
2589
0
        }
2590
0
#endif // defined(IPV6_V6ONLY)
2591
2592
        // On systems that support it, disable the delivery of SIGPIPE signals when writing to a closed
2593
        // socket.
2594
#ifdef SO_NOSIGPIPE
2595
        {
2596
            int one = 1;
2597
            int res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
2598
            if (res != 0)
2599
            {
2600
                WeaveLogError(Inet, "SO_NOSIGPIPE: %d", errno);
2601
            }
2602
        }
2603
#endif // defined(SO_NOSIGPIPE)
2604
0
    }
2605
0
    else if (mAddrType != addrType)
2606
0
        return INET_ERROR_INCORRECT_STATE;
2607
2608
0
    return INET_NO_ERROR;
2609
0
}
2610
2611
SocketEvents TCPEndPoint::PrepareIO()
2612
0
{
2613
0
    SocketEvents ioType;
2614
2615
    // If initiating a new connection...
2616
    // OR if connected and there is data to be sent...
2617
    // THEN arrange for the kernel to alert us when the socket is ready to be written.
2618
0
    if (State == kState_Connecting || (IsConnected() && mSendQueue != NULL))
2619
0
        ioType.SetWrite();
2620
2621
    // If listening for incoming connections and the app is ready to receive a connection...
2622
    // OR if in a state where receiving is allowed, and the app is ready to receive data...
2623
    // THEN arrange for the kernel to alert us when the socket is ready to be read.
2624
0
    if ((State == kState_Listening && OnConnectionReceived != NULL) ||
2625
0
        ((State == kState_Connected || State == kState_SendShutdown) && ReceiveEnabled && OnDataReceived != NULL))
2626
0
        ioType.SetRead();
2627
2628
0
    return ioType;
2629
0
}
2630
2631
void TCPEndPoint::HandlePendingIO()
2632
0
{
2633
    // Prevent the end point from being freed while in the middle of a callback.
2634
0
    Retain();
2635
2636
    // If in the Listening state, and the app is ready to receive a connection, and there is a connection
2637
    // ready to be received on the socket, process the incoming connection.
2638
0
    if (State == kState_Listening)
2639
0
    {
2640
0
        if (OnConnectionReceived != NULL && mPendingIO.IsReadable())
2641
0
            HandleIncomingConnection();
2642
0
    }
2643
2644
    // If in the processes of initiating a connection...
2645
0
    else if (State == kState_Connecting)
2646
0
    {
2647
        // The socket being writable indicates the connection has completed (successfully or otherwise).
2648
0
        if (mPendingIO.IsWriteable())
2649
0
        {
2650
            // Get the connection result from the socket.
2651
0
            int osConRes;
2652
0
            socklen_t optLen = sizeof(osConRes);
2653
0
            if (getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &osConRes, &optLen) != 0)
2654
0
                osConRes = errno;
2655
0
            INET_ERROR conRes = Weave::System::MapErrorPOSIX(osConRes);
2656
2657
            // Process the connection result.
2658
0
            HandleConnectComplete(conRes);
2659
0
        }
2660
0
    }
2661
2662
0
    else
2663
0
    {
2664
        // If in a state where sending is allowed, and there is data to be sent, and the socket is ready for
2665
        // writing, drive outbound data into the connection.
2666
0
        if (IsConnected() && mSendQueue != NULL && mPendingIO.IsWriteable())
2667
0
            DriveSending();
2668
2669
        // If in a state were receiving is allowed, and the app is ready to receive data, and data is ready
2670
        // on the socket, receive inbound data from the connection.
2671
0
        if ((State == kState_Connected || State == kState_SendShutdown) && ReceiveEnabled && OnDataReceived != NULL && mPendingIO.IsReadable())
2672
0
            ReceiveData();
2673
0
    }
2674
2675
0
    mPendingIO.Clear();
2676
2677
0
    Release();
2678
0
}
2679
2680
void TCPEndPoint::ReceiveData()
2681
0
{
2682
0
    PacketBuffer *rcvBuf;
2683
0
    bool isNewBuf = true;
2684
2685
0
    if (mRcvQueue == NULL)
2686
0
        rcvBuf = PacketBuffer::New(0);
2687
0
    else
2688
0
    {
2689
0
        rcvBuf = mRcvQueue;
2690
0
        for (PacketBuffer *nextBuf = rcvBuf->Next(); nextBuf != NULL; rcvBuf = nextBuf, nextBuf = nextBuf->Next())
2691
0
            ;
2692
2693
0
        if (rcvBuf->AvailableDataLength() == 0)
2694
0
            rcvBuf = PacketBuffer::New(0);
2695
0
        else
2696
0
        {
2697
0
            isNewBuf = false;
2698
0
            rcvBuf->CompactHead();
2699
0
        }
2700
0
    }
2701
2702
0
    if (rcvBuf == NULL)
2703
0
    {
2704
0
        DoClose(INET_ERROR_NO_MEMORY, false);
2705
0
        return;
2706
0
    }
2707
2708
    // Attempt to receive data from the socket.
2709
0
    ssize_t rcvLen = recv(mSocket, rcvBuf->Start() + rcvBuf->DataLength(), rcvBuf->AvailableDataLength(), 0);
2710
2711
0
#if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
2712
0
    INET_ERROR err;
2713
0
    bool isProgressing = false;
2714
2715
0
    err = CheckConnectionProgress(isProgressing);
2716
0
    if (err != INET_NO_ERROR)
2717
0
    {
2718
0
        DoClose(err, false);
2719
2720
0
        return;
2721
0
    }
2722
2723
0
    if (mLastTCPKernelSendQueueLen == 0)
2724
0
    {
2725
        // If the output queue has been flushed then stop the timer.
2726
2727
0
        StopTCPUserTimeoutTimer();
2728
2729
#if INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
2730
        // Notify up if all outstanding data has been acknowledged
2731
2732
        if (mSendQueue == NULL)
2733
        {
2734
            SetTCPSendIdleAndNotifyChange(true);
2735
        }
2736
#endif // INET_CONFIG_ENABLE_TCP_SEND_IDLE_CALLBACKS
2737
0
    }
2738
0
    else if (isProgressing && mUserTimeoutTimerRunning)
2739
0
    {
2740
        // Progress is being made. So, shift the timer
2741
        // forward if it was started.
2742
0
        RestartTCPUserTimeoutTimer();
2743
0
    }
2744
0
#endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
2745
    // If an error occurred, abort the connection.
2746
0
    if (rcvLen < 0)
2747
0
    {
2748
0
        int systemErrno = errno;
2749
2750
0
        if (isNewBuf)
2751
0
        {
2752
0
            PacketBuffer::Free(rcvBuf);
2753
0
        }
2754
2755
0
        if (systemErrno == EAGAIN)
2756
0
        {
2757
            // Note: in this case, we opt to not retry the recv call,
2758
            // and instead we expect that the read flags will get
2759
            // reset correctly upon a subsequent return from the
2760
            // select call.
2761
0
            WeaveLogError(Inet, "recv: EAGAIN, will retry");
2762
2763
0
            return;
2764
0
        }
2765
2766
0
        DoClose(Weave::System::MapErrorPOSIX(systemErrno), false);
2767
0
    }
2768
2769
0
    else
2770
0
    {
2771
        // Mark the connection as being active.
2772
0
        MarkActive();
2773
2774
        // If the peer closed their end of the connection...
2775
0
        if (rcvLen == 0)
2776
0
        {
2777
0
            if (isNewBuf)
2778
0
                PacketBuffer::Free(rcvBuf);
2779
2780
            // If in the Connected state and the app has provided an OnPeerClose callback,
2781
            // enter the ReceiveShutdown state.  Providing an OnPeerClose callback allows
2782
            // the app to decide whether to keep the send side of the connection open after
2783
            // the peer has closed. If no OnPeerClose is provided, we assume that the app
2784
            // wants to close both directions and automatically enter the Closing state.
2785
0
            if (State == kState_Connected && OnPeerClose != NULL)
2786
0
                State = kState_ReceiveShutdown;
2787
0
            else
2788
0
                State = kState_Closing;
2789
2790
            // Call the app's OnPeerClose.
2791
0
            if (OnPeerClose != NULL)
2792
0
                OnPeerClose(this);
2793
0
        }
2794
2795
        // Otherwise, add the new data onto the receive queue.
2796
0
        else if (isNewBuf)
2797
0
        {
2798
0
            rcvBuf->SetDataLength(rcvBuf->DataLength() + (uint16_t) rcvLen);
2799
0
            if (mRcvQueue == NULL)
2800
0
                mRcvQueue = rcvBuf;
2801
0
            else
2802
0
                mRcvQueue->AddToEnd(rcvBuf);
2803
0
        }
2804
2805
0
        else
2806
0
            rcvBuf->SetDataLength(rcvBuf->DataLength() + (uint16_t) rcvLen, mRcvQueue);
2807
0
    }
2808
2809
    // Drive any received data into the app.
2810
0
    DriveReceiving();
2811
0
}
2812
2813
void TCPEndPoint::HandleIncomingConnection()
2814
0
{
2815
0
    INET_ERROR err = INET_NO_ERROR;
2816
0
    TCPEndPoint *conEP = NULL;
2817
0
    IPAddress peerAddr;
2818
0
    uint16_t peerPort;
2819
2820
0
    union
2821
0
    {
2822
0
        sockaddr any;
2823
0
        sockaddr_in in;
2824
0
        sockaddr_in6 in6;
2825
0
    } sa;
2826
0
    memset(&sa, 0, sizeof(sa));
2827
0
    socklen_t saLen = sizeof(sa);
2828
2829
    // Accept the new connection.
2830
0
    int conSocket = accept(mSocket, &sa.any, &saLen);
2831
0
    if (conSocket == -1)
2832
0
        err = Weave::System::MapErrorPOSIX(errno);
2833
2834
    // If there's no callback available, fail with an error.
2835
0
    if (err == INET_NO_ERROR && OnConnectionReceived == NULL)
2836
0
        err = INET_ERROR_NO_CONNECTION_HANDLER;
2837
2838
    // Extract the peer's address information.
2839
0
    if (err == INET_NO_ERROR)
2840
0
    {
2841
0
        if (sa.any.sa_family == AF_INET6)
2842
0
        {
2843
0
            peerAddr = IPAddress::FromIPv6(sa.in6.sin6_addr);
2844
0
            peerPort = ntohs(sa.in6.sin6_port);
2845
0
        }
2846
0
#if INET_CONFIG_ENABLE_IPV4
2847
0
        else if (sa.any.sa_family == AF_INET)
2848
0
        {
2849
0
            peerAddr = IPAddress::FromIPv4(sa.in.sin_addr);
2850
0
            peerPort = ntohs(sa.in.sin_port);
2851
0
        }
2852
0
#endif // INET_CONFIG_ENABLE_IPV4
2853
0
        else
2854
0
            err = INET_ERROR_INCORRECT_STATE;
2855
0
    }
2856
2857
    // Attempt to allocate an end point object.
2858
0
    if (err == INET_NO_ERROR)
2859
0
    {
2860
0
        InetLayer& lInetLayer = Layer();
2861
2862
0
        err = lInetLayer.NewTCPEndPoint(&conEP);
2863
0
    }
2864
2865
    // If all went well...
2866
0
    if (err == INET_NO_ERROR)
2867
0
    {
2868
        // Put the new end point into the Connected state.
2869
0
        conEP->State = kState_Connected;
2870
0
        conEP->mSocket = conSocket;
2871
0
#if INET_CONFIG_ENABLE_IPV4
2872
0
        conEP->mAddrType = (sa.any.sa_family == AF_INET6) ? kIPAddressType_IPv6 : kIPAddressType_IPv4;
2873
#else // !INET_CONFIG_ENABLE_IPV4
2874
        conEP->mAddrType = kIPAddressType_IPv6;
2875
#endif // !INET_CONFIG_ENABLE_IPV4
2876
0
        conEP->Retain();
2877
2878
        // Call the app's callback function.
2879
0
        OnConnectionReceived(this, conEP, peerAddr, peerPort);
2880
0
    }
2881
2882
    // Otherwise immediately close the connection, clean up and call the app's error callback.
2883
0
    else
2884
0
    {
2885
0
        if (conSocket != -1)
2886
0
            close(conSocket);
2887
0
        if (conEP != NULL)
2888
0
        {
2889
0
            if (conEP->State == kState_Connected)
2890
0
                conEP->Release();
2891
0
            conEP->Release();
2892
0
        }
2893
0
        if (OnAcceptError != NULL)
2894
0
            OnAcceptError(this, err);
2895
0
    }
2896
0
}
2897
2898
#if INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
2899
/**
2900
 *  This function probes the TCP output queue and checks if data is successfully
2901
 *  being transferred to the other end.
2902
 */
2903
INET_ERROR TCPEndPoint::CheckConnectionProgress(bool &isProgressing)
2904
0
{
2905
0
   INET_ERROR err = INET_NO_ERROR;
2906
0
   int currPendingBytes = 0;
2907
2908
   // Fetch the bytes pending successful transmission in the TCP out queue.
2909
2910
0
   if (ioctl(mSocket, TIOCOUTQ, &currPendingBytes) < 0)
2911
0
   {
2912
0
       ExitNow(err = Weave::System::MapErrorPOSIX(errno));
2913
0
   }
2914
2915
0
   if ((currPendingBytes != 0) &&
2916
0
       (mBytesWrittenSinceLastProbe + mLastTCPKernelSendQueueLen == static_cast<uint32_t>(currPendingBytes)))
2917
0
   {
2918
       // No progress has been made
2919
2920
0
       isProgressing = false;
2921
0
   }
2922
0
   else
2923
0
   {
2924
       // Data is flowing successfully
2925
2926
0
       isProgressing = true;
2927
0
   }
2928
2929
   // Reset the value of the bytes written since the last probe into the tcp
2930
   // outqueue was made and update the last tcp outqueue sample.
2931
2932
0
   mBytesWrittenSinceLastProbe = 0;
2933
2934
0
   mLastTCPKernelSendQueueLen = currPendingBytes;
2935
2936
0
exit:
2937
0
   return err;
2938
0
}
2939
#endif // INET_CONFIG_OVERRIDE_SYSTEM_TCP_USER_TIMEOUT
2940
2941
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
2942
2943
} // namespace Inet
2944
} // namespace nl