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

jbaldwin / libcoro / 21315795177

24 Jan 2026 01:23PM UTC coverage: 86.888%. First build
21315795177

Pull #435

github

web-flow
Merge b39d95fbe into 44d12235a
Pull Request #435: Rename io_scheduler to scheduler

51 of 71 new or added lines in 11 files covered. (71.83%)

1756 of 2021 relevant lines covered (86.89%)

4941352.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, options opts)
199✔
10
    : m_scheduler(scheduler.get()),
199✔
11
      m_options(std::move(opts)),
198✔
12
      m_socket(
199✔
13
          net::make_socket(
14
              net::socket::options{m_options.address.domain(), net::socket::type_t::tcp, net::socket::blocking_t::no}))
199✔
15
{
16
    if (m_scheduler == nullptr)
194✔
17
    {
NEW
18
        throw std::runtime_error{"tcp::client cannot have nullptr scheduler"};
×
19
    }
20
}
194✔
21

22
client::client(coro::scheduler* scheduler, net::socket socket, options opts)
203✔
23
    : m_scheduler(scheduler),
203✔
24
      m_options(std::move(opts)),
203✔
25
      m_socket(std::move(socket)),
203✔
26
      m_connect_status(connect_status::connected)
203✔
27
{
28
    // scheduler is assumed good since it comes from a tcp::server.
29

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

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

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

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

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

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

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

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

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

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

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

132
    co_return return_value(connect_status::error);
133
}
377✔
134

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