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

libbitcoin / libbitcoin-network / 42421988994

07 Nov 2026 10:44PM UTC coverage: 93.582% (-0.3%) from 93.863%
42421988994

Pull #1011

github

web-flow
Merge 62b70bb20 into ddc7eabb3
Pull Request #1011: Read rpc channel post bodies as json-rpc regardless of content type.

70 of 70 new or added lines in 5 files covered. (100.0%)

58 existing lines in 7 files now uncovered.

14567 of 15566 relevant lines covered (93.58%)

2260.09 hits per line

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

83.95
/src/net/socket_stop.cpp
1
/**
2
 * Copyright (c) 2011-2026 libbitcoin developers
3
 *
4
 * This file is part of libbitcoin.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
#include <bitcoin/network/net/socket.hpp>
20

21
#include <bitcoin/network/config/config.hpp>
22
#include <bitcoin/network/define.hpp>
23

24
namespace libbitcoin {
25
namespace network {
26

27
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
28

29
using namespace system;
30
using namespace std::placeholders;
31

32
constexpr size_t drain_size = 1024;
33

34
// The socket does not (must not) stop itself.
35

36
// Stop (async).
37
// ----------------------------------------------------------------------------
38
// Hard stop (no graceful websocket/tls closure).
39

40
void socket::stop() NOEXCEPT
650 ✔
41
{
42
    // Stop flag accelerates work stoppage, as it does not wait on strand.
43
    if (stopped_.exchange(true) && !lazy_.exchange(false))
650 ✔
44
        return;
45

46
    // Stop is posted to strand to protect the socket.
47
    io::post(strand_,
472 ✔
48
        std::bind(&socket::do_stop, shared_from_this()));
944 ✔
49
}
50

51
// private
52
void socket::do_stop() NOEXCEPT
517 ✔
53
{
54
    BC_ASSERT(stranded());
517 ✔
55

56
    watch_->stop();
517 ✔
57
    timer_->stop();
517 ✔
58

59
    code ignore{};
517 ✔
60
    auto& layer = get_base();
517 ✔
61
    layer.shutdown(io::socket::shutdown_type::both, ignore);
517 ✔
62
    layer.close(ignore);
517 ✔
63
}
517 ✔
64

65
// Stop (lazy).
66
// ----------------------------------------------------------------------------
67
// Lazy stop (graceful websocket/tls closure).
68

69
void socket::lazy_stop() NOEXCEPT
46 ✔
70
{
71
    // Stop flag accelerates work stoppage, as it does not wait on strand.
72
    if (stopped_.exchange(true))
46 ✔
73
        return;
74

75
    lazy_.store(true);
45 ✔
76

77
    // Async stop is dispatched to strand to protect the socket.
78
    io::dispatch(strand_,
45 ✔
79
        std::bind(&socket::do_lazy_stop, shared_from_this()));
90 ✔
80
}
81

82
// private
83
void socket::do_lazy_stop() NOEXCEPT
45 ✔
84
{
85
    BC_ASSERT(stranded());
45 ✔
86

87
    // The peer is not required to answer a close, so the wait is bounded.
88
    if (is_zero(timer_->timeout().count()))
45 ✔
89
    {
90
        do_stop();
42 ✔
91
        return;
42 ✔
92
    }
93

94
    timer_->start(std::bind(&socket::handle_lazy_timer,
3 ✔
95
        shared_from_this(), _1));
6 ✔
96

97
    do_ws_stop();
3 ✔
98
}
99

100
// private
101
// Socket stop cancels the pending close, which completes its handler.
102
void socket::handle_lazy_timer(const code& ec) NOEXCEPT
3 ✔
103
{
104
    if (!ec)
3 ✔
UNCOV
105
        stop();
×
106
}
3 ✔
107

108
// private
109
void socket::do_ws_stop() NOEXCEPT
3 ✔
110
{
111
    BC_ASSERT(stranded());
3 ✔
112
    if (!websocket())
3 ✔
113
    {
114
        do_tls_stop();
1 ✔
115
        return;
1 ✔
116
    }
117

118
    // A close already sent (answering the peer) is not repeated.
119
    if (ws_closing_)
2 ✔
120
    {
121
        do_tls_stop();
×
122
        return;
×
123
    }
124

125
    ws_closing_ = true;
2 ✔
126
    ws_send(ws::opcode::close, ws::close_payload(ws::close_code::normal),
2 ✔
127
        std::bind(&socket::handle_ws_close, shared_from_this(), _1));
4 ✔
128
}
129

130
// private
131
void socket::handle_ws_close(const code& ec) NOEXCEPT
2 ✔
132
{
133
    BC_ASSERT(stranded());
2 ✔
134
    if (ec && ec != error::peer_disconnect && ec != error::channel_stopped)
2 ✔
135
        LOGX("WS close [" << endpoint() << "] " << ec.message());
×
136

137
    do_tls_stop();
2 ✔
138
}
2 ✔
139

140
// private
141
void socket::do_tls_stop() NOEXCEPT
3 ✔
142
{
143
    BC_ASSERT(stranded());
3 ✔
144
    if (!secure())
3 ✔
145
    {
146
        do_linger();
3 ✔
147
        return;
3 ✔
148
    }
149

UNCOV
150
    get_tls().async_shutdown(
×
UNCOV
151
        std::bind(&socket::handle_tls_close,
×
UNCOV
152
            shared_from_this(), _1));
×
153
}
154

155
// private
UNCOV
156
void socket::handle_tls_close(const code& ec) NOEXCEPT
×
157
{
UNCOV
158
    BC_ASSERT(stranded());
×
UNCOV
159
    if (ec && ec != error::peer_disconnect && ec != error::operation_canceled)
×
160
        logx("tls_stop", ec);
×
161

UNCOV
162
    do_linger();
×
UNCOV
163
}
×
164

165
// private
166
// Lingering close (rfc9112 9.6): send is closed and receive is drained to the
167
// peer's close, so unread bytes do not reset the connection under a response.
168
void socket::do_linger() NOEXCEPT
3 ✔
169
{
170
    BC_ASSERT(stranded());
3 ✔
171

172
    code ignore{};
3 ✔
173
    auto& layer = get_base();
3 ✔
174
    layer.cancel(ignore);
3 ✔
175
    layer.shutdown(io::socket::shutdown_type::send, ignore);
3 ✔
176
    do_drain(emplace_shared<data_chunk>(drain_size));
3 ✔
177
}
3 ✔
178

179
// private
180
void socket::do_drain(const chunk_ptr& sink) NOEXCEPT
5 ✔
181
{
182
    BC_ASSERT(stranded());
5 ✔
183

184
    get_base().async_read_some(io::buffer(*sink),
10 ✔
185
        std::bind(&socket::handle_drain,
10 ✔
186
            shared_from_this(), _1, sink));
10 ✔
187
}
5 ✔
188

189
// private
190
void socket::handle_drain(const code& ec,
5 ✔
191
    const chunk_ptr& sink) NOEXCEPT
192
{
193
    BC_ASSERT(stranded());
5 ✔
194

195
    if (ec)
5 ✔
196
    {
197
        do_stop();
3 ✔
198
        return;
3 ✔
199
    }
200

201
    do_drain(sink);
2 ✔
202
}
203

204
BC_POP_WARNING()
205

206
} // namespace network
207
} // namespace libbitcoin
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc