I'm trying to implement a Windows named pipes server, based on boost asio.
I'm creating a named pipe object, set it for async operation (overlapped), and then assign a pipe (windows::stream_handle
) with the result.
I then create an overlapped (windows::overlapped_ptr
) object, with an appropriate handler. Finally, I call the Windows API ::ConnectNamedPipe
to wait asynchronously
The code looks like this:
class NamedPipeServer {
public:
NamedPipeServer(boost::asio::io_context& io_context)
: io_context_(io_context)
, pipe_(io_context)
{
start_accept();
}
private:
void start_accept() {
HANDLE pipe_handle = ::CreateNamedPipe(
"\\\\.\\pipe\\mypipe",
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
512, 512, 0, nullptr);
pipe_.assign(pipe_handle);
// Copying overlapped to the closure will make sure it isn't released
// after I exit the function, but when I exit the closure
auto overlapped = std::make_shared<boost::asio::windows::overlapped_ptr>();
overlapped->reset(io_context_, [this, overlapped](const boost::system::error_code& ec, std::size_t bytes_transferred) {
handle_accept(ec);
});
::ConnectNamedPipe(pipe_handle, overlapped->get());
}
void handle_accept(const boost::system::error_code& error) {
// Here I should start read/write/etc.
// the problem is: THIS FUNCTION IS NEVER CALLED
}
boost::asio::io_context& io_context_;
std::string pipe_name_;
boost::asio::windows::stream_handle pipe_;
};
int main() {
boost::asio::io_context io_context;
NamedPipeServer server(io_context);
io_context.run();
return 0;
}
My problem is that the handler is never called. Debugging the boost::asio code, I can see that within the function win_iocp_io_context::do_one
, the call to ::GetQueuedCompletionStatus
returns as soon as a client connect to the named pipe. However, the handler isn't being called, because the ready_
property (of win_iocp_operation
structure) property remains 0.
So my question is: What will change ready_
to be true?