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

jbaldwin / libcoro / 18355807267

08 Oct 2025 07:27PM UTC coverage: 88.651%. First build
18355807267

Pull #400

github

web-flow
Merge 82d22144f into 749e5b474
Pull Request #400: Executor types remove circular refs

48 of 56 new or added lines in 15 files covered. (85.71%)

1656 of 1868 relevant lines covered (88.65%)

5382608.64 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
namespace coro::net::tcp
4
{
5
using namespace std::chrono_literals;
6

7
client::client(std::unique_ptr<coro::io_scheduler>& scheduler, options opts)
201✔
8
    : m_io_scheduler(scheduler.get()),
201✔
9
      m_options(std::move(opts)),
198✔
10
      m_socket(net::make_socket(
200✔
11
          net::socket::options{m_options.address.domain(), net::socket::type_t::tcp, net::socket::blocking_t::no}))
201✔
12
{
13
    if (m_io_scheduler == nullptr)
197✔
14
    {
15
        throw std::runtime_error{"tcp::client cannot have nullptr io_scheduler"};
×
16
    }
17
}
197✔
18

19
client::client(coro::io_scheduler* scheduler, net::socket socket, options opts)
202✔
20
    : m_io_scheduler(scheduler),
202✔
21
      m_options(std::move(opts)),
202✔
22
      m_socket(std::move(socket)),
203✔
23
      m_connect_status(connect_status::connected)
203✔
24
{
25
    // io_scheduler is assumed good since it comes from a tcp::server.
26

27
    // Force the socket to be non-blocking.
28
    m_socket.blocking(coro::net::socket::blocking_t::no);
203✔
29
}
202✔
30

31
client::client(const client& other)
1✔
32
    : m_io_scheduler(other.m_io_scheduler),
1✔
33
      m_options(other.m_options),
1✔
34
      m_socket(other.m_socket),
1✔
35
      m_connect_status(other.m_connect_status)
1✔
36
{
37
}
1✔
38

39
client::client(client&& other) noexcept
402✔
40
    : m_io_scheduler(other.m_io_scheduler),
402✔
41
      m_options(std::move(other.m_options)),
402✔
42
      m_socket(std::move(other.m_socket)),
402✔
43
      m_connect_status(std::exchange(other.m_connect_status, std::nullopt))
402✔
44
{
45
}
402✔
46

47
client::~client()
808✔
48
{
49
}
808✔
50

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

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

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

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

91
    sockaddr_in server{};
92
    server.sin_family = static_cast<int>(m_options.address.domain());
93
    server.sin_port   = htons(m_options.port);
94
    server.sin_addr   = *reinterpret_cast<const in_addr*>(m_options.address.data().data());
95

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

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

129
    co_return return_value(connect_status::error);
130
}
387✔
131

132
} // 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