Skip to content

Commit 142da22

Browse files
committed
Fix win socket, acceptor cancelation
1 parent 49b6230 commit 142da22

12 files changed

Lines changed: 793 additions & 147 deletions

File tree

include/boost/corosio/acceptor.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <concepts>
2828
#include <coroutine>
2929
#include <cstddef>
30+
#include <memory>
3031
#include <stop_token>
3132
#include <type_traits>
3233

@@ -275,7 +276,6 @@ class BOOST_COROSIO_DECL acceptor : public io_object
275276
};
276277

277278
private:
278-
279279
inline acceptor_impl& get() const noexcept
280280
{
281281
return *static_cast<acceptor_impl*>(impl_);

include/boost/corosio/socket.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <concepts>
2828
#include <coroutine>
2929
#include <cstddef>
30+
#include <memory>
3031
#include <stop_token>
3132
#include <type_traits>
3233

src/corosio/src/acceptor.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,18 @@ listen(endpoint ep, int backlog)
5656
close();
5757

5858
auto& svc = ctx_->use_service<acceptor_service>();
59-
auto& impl = svc.create_acceptor_impl();
60-
impl_ = &impl;
59+
auto& wrapper = svc.create_acceptor_impl();
60+
impl_ = &wrapper;
6161

62-
system::error_code ec = svc.open_acceptor(impl, ep, backlog);
62+
#if defined(BOOST_COROSIO_BACKEND_IOCP)
63+
system::error_code ec = svc.open_acceptor(
64+
*wrapper.get_internal(), ep, backlog);
65+
#elif defined(BOOST_COROSIO_BACKEND_EPOLL)
66+
system::error_code ec = svc.open_acceptor(wrapper, ep, backlog);
67+
#endif
6368
if (ec)
6469
{
65-
impl.release();
70+
wrapper.release();
6671
impl_ = nullptr;
6772
detail::throw_system_error(ec, "acceptor::listen");
6873
}
@@ -75,7 +80,8 @@ close()
7580
if (!impl_)
7681
return;
7782

78-
impl_->release();
83+
auto* wrapper = static_cast<acceptor_impl_type*>(impl_);
84+
wrapper->release();
7985
impl_ = nullptr;
8086
}
8187

@@ -84,7 +90,11 @@ acceptor::
8490
cancel()
8591
{
8692
assert(impl_ != nullptr);
93+
#if defined(BOOST_COROSIO_BACKEND_IOCP)
94+
static_cast<acceptor_impl_type*>(impl_)->get_internal()->cancel();
95+
#elif defined(BOOST_COROSIO_BACKEND_EPOLL)
8796
static_cast<acceptor_impl_type*>(impl_)->cancel();
97+
#endif
8898
}
8999

90100
} // namespace corosio

src/corosio/src/detail/epoll/op.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,20 @@ struct epoll_read_op : epoll_op
170170
iovec iovecs[max_buffers];
171171
int iovec_count = 0;
172172

173-
bool is_read_operation() const noexcept override { return true; }
173+
// True when 0 bytes is due to empty buffer, not EOF
174+
bool empty_buffer_read = false;
175+
176+
// EOF only applies when we actually tried to read something
177+
bool is_read_operation() const noexcept override
178+
{
179+
return !empty_buffer_read;
180+
}
174181

175182
void reset() noexcept
176183
{
177184
epoll_op::reset();
178185
iovec_count = 0;
186+
empty_buffer_read = false;
179187
}
180188

181189
void perform_io() noexcept override

src/corosio/src/detail/epoll/sockets.hpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,16 @@ read_some(
292292

293293
capy::mutable_buffer bufs[epoll_read_op::max_buffers];
294294
op.iovec_count = static_cast<int>(param.copy_to(bufs, epoll_read_op::max_buffers));
295+
296+
// Handle empty buffer: complete immediately with 0 bytes
297+
if (op.iovec_count == 0)
298+
{
299+
op.empty_buffer_read = true;
300+
op.complete(0, 0);
301+
svc_.post(&op);
302+
return;
303+
}
304+
295305
for (int i = 0; i < op.iovec_count; ++i)
296306
{
297307
op.iovecs[i].iov_base = bufs[i].data();
@@ -346,6 +356,15 @@ write_some(
346356

347357
capy::mutable_buffer bufs[epoll_write_op::max_buffers];
348358
op.iovec_count = static_cast<int>(param.copy_to(bufs, epoll_write_op::max_buffers));
359+
360+
// Handle empty buffer: complete immediately with 0 bytes
361+
if (op.iovec_count == 0)
362+
{
363+
op.complete(0, 0);
364+
svc_.post(&op);
365+
return;
366+
}
367+
349368
for (int i = 0; i < op.iovec_count; ++i)
350369
{
351370
op.iovecs[i].iov_base = bufs[i].data();

src/corosio/src/detail/iocp/overlapped_op.hpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,25 @@ struct overlapped_op
8989
if (ec_out)
9090
{
9191
if (cancelled.load(std::memory_order_acquire))
92-
*ec_out = make_error_code(system::errc::operation_canceled);
92+
{
93+
// Explicit cancellation via cancel() or stop_token
94+
*ec_out = capy::error::canceled;
95+
}
96+
else if (error == ERROR_OPERATION_ABORTED)
97+
{
98+
// CancelIoEx or socket close caused abort
99+
*ec_out = capy::error::canceled;
100+
}
93101
else if (error != 0)
102+
{
94103
*ec_out = system::error_code(
95104
static_cast<int>(error), system::system_category());
105+
}
96106
else if (is_read_operation() && bytes_transferred == 0 && !empty_buffer)
97107
{
98108
// EOF: 0 bytes transferred with no error indicates end of stream
99109
// (but not if we intentionally read with an empty buffer)
100-
*ec_out = make_error_code(capy::error::eof);
110+
*ec_out = capy::error::eof;
101111
}
102112
}
103113

0 commit comments

Comments
 (0)