• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jbaldwin / libcoro / 21527690670

30 Jan 2026 07:16PM UTC coverage: 87.058%. First build
21527690670

Pull #439

github

web-flow
Merge ec620dc22 into 328b510d3
Pull Request #439: "One `endpoint` to rule them all" & UB fix

86 of 97 new or added lines in 9 files covered. (88.66%)

1796 of 2063 relevant lines covered (87.06%)

4839185.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.75
/src/net/tcp/client.cpp
1
#include "coro/net/tcp/client.hpp"
2

3
#include <iostream>
4

5
namespace coro::net::tcp
6
{
7
using namespace std::chrono_literals;
8

9
client::client(std::unique_ptr<coro::scheduler>& scheduler, net::socket_address endpoint)
203✔
10
    : m_scheduler(scheduler.get()),
203✔
11
      m_endpoint(std::move(endpoint)),
201✔
12
      m_socket(
200✔
13
          net::make_socket(net::socket::options{socket::type_t::tcp, net::socket::blocking_t::no}, endpoint.domain()))
200✔
14
{
15
    if (m_scheduler == nullptr)
198✔
16
    {
17
        throw std::runtime_error{"tcp::client cannot have nullptr scheduler"};
×
18
    }
19
}
198✔
20

21
client::client(coro::scheduler* scheduler, net::socket socket, const net::socket_address &endpoint)
203✔
22
    : m_scheduler(scheduler),
203✔
23
      m_endpoint(std::move(endpoint)),
203✔
24
      m_socket(std::move(socket)),
203✔
25
      m_connect_status(connect_status::connected)
203✔
26
{
27
    // scheduler is assumed good since it comes from a tcp::server.
28

29
    // Force the socket to be non-blocking.
30
    m_socket.blocking(coro::net::socket::blocking_t::no);
204✔
31
}
204✔
32

33
client::client(const client& other)
1✔
34
    : m_scheduler(other.m_scheduler),
1✔
35
      m_endpoint(other.m_endpoint),
1✔
36
      m_socket(other.m_socket),
1✔
37
      m_connect_status(other.m_connect_status)
1✔
38
{
39
}
1✔
40

41
client::client(client&& other) noexcept
402✔
42
    : m_scheduler(other.m_scheduler),
402✔
43
      m_endpoint(std::move(other.m_endpoint)),
402✔
44
      m_socket(std::move(other.m_socket)),
402✔
45
      m_connect_status(std::exchange(other.m_connect_status, std::nullopt))
401✔
46
{
47
}
401✔
48

49
client::~client()
808✔
50
{
51
}
808✔
52

53
auto client::operator=(const client& other) noexcept -> client&
×
54
{
55
    if (std::addressof(other) != this)
×
56
    {
57
        m_scheduler   = other.m_scheduler;
×
NEW
58
        m_endpoint       = other.m_endpoint;
×
59
        m_socket         = other.m_socket;
×
60
        m_connect_status = other.m_connect_status;
×
61
    }
62
    return *this;
×
63
}
64

65
auto client::operator=(client&& other) noexcept -> client&
×
66
{
67
    if (std::addressof(other) != this)
×
68
    {
69
        m_scheduler   = std::exchange(other.m_scheduler, nullptr);
×
NEW
70
        m_endpoint       = std::move(other.m_endpoint);
×
71
        m_socket         = std::move(other.m_socket);
×
72
        m_connect_status = std::exchange(other.m_connect_status, std::nullopt);
×
73
    }
74
    return *this;
×
75
}
76

77
auto client::connect(std::chrono::milliseconds timeout) -> coro::task<connect_status>
199✔
78
{
79
    // Only allow the user to connect per tcp client once, if they need to re-connect they should
80
    // make a new tcp::client.
81
    if (m_connect_status.has_value())
82
    {
83
        co_return m_connect_status.value();
84
    }
85

86
    // This enforces the connection status is aways set on the client object upon returning.
87
    auto return_value = [this](connect_status s) -> connect_status
406✔
88
    {
89
        m_connect_status = s;
203✔
90
        return s;
203✔
91
    };
92

93
    auto [sockaddr, len] = m_endpoint.data();
94

95
    auto cret = ::connect(m_socket.native_handle(), sockaddr, len);
96
    if (cret == 0)
97
    {
98
        co_return return_value(connect_status::connected);
99
    }
100
    else if (cret == -1)
101
    {
102
        // If the connect is happening in the background poll for write on the socket to trigger
103
        // when the connection is established.
104
        if (errno == EAGAIN || errno == EINPROGRESS)
105
        {
106
            auto pstatus = co_await m_scheduler->poll(m_socket, poll_op::write, timeout);
107
            if (pstatus == poll_status::write)
108
            {
109
                int       result{0};
110
                socklen_t result_length{sizeof(result)};
111
                if (getsockopt(m_socket.native_handle(), SOL_SOCKET, SO_ERROR, &result, &result_length) < 0)
112
                {
113
                    std::cerr << "connect failed to getsockopt after write poll event\n";
114
                }
115

116
                if (result == 0)
117
                {
118
                    co_return return_value(connect_status::connected);
119
                }
120
            }
121
            else if (pstatus == poll_status::timeout)
122
            {
123
                co_return return_value(connect_status::timeout);
124
            }
125
        }
126
    }
127

128
    co_return return_value(connect_status::error);
129
}
392✔
130

131
} // namespace coro::net::tcp
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc