5 // Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
14 #include <boost/bind/bind.hpp>
15 #include <boost/shared_ptr.hpp>
16 #include <boost/enable_shared_from_this.hpp>
17 #include <boost/asio.hpp>
19 #if defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR)
21 using boost::asio::ip::tcp
;
22 using boost::asio::windows::overlapped_ptr
;
23 using boost::asio::windows::random_access_handle
;
25 typedef boost::asio::basic_stream_socket
<tcp
,
26 boost::asio::io_context::executor_type
> tcp_socket
;
28 typedef boost::asio::basic_socket_acceptor
<tcp
,
29 boost::asio::io_context::executor_type
> tcp_acceptor
;
31 // A wrapper for the TransmitFile overlapped I/O operation.
32 template <typename Handler
>
33 void transmit_file(tcp_socket
& socket
,
34 random_access_handle
& file
, Handler handler
)
36 // Construct an OVERLAPPED-derived object to contain the handler.
37 overlapped_ptr
overlapped(socket
.get_executor().context(), handler
);
39 // Initiate the TransmitFile operation.
40 BOOL ok
= ::TransmitFile(socket
.native_handle(),
41 file
.native_handle(), 0, 0, overlapped
.get(), 0, 0);
42 DWORD last_error
= ::GetLastError();
44 // Check if the operation completed immediately.
45 if (!ok
&& last_error
!= ERROR_IO_PENDING
)
47 // The operation completed immediately, so a completion notification needs
48 // to be posted. When complete() is called, ownership of the OVERLAPPED-
49 // derived object passes to the io_context.
50 boost::system::error_code
ec(last_error
,
51 boost::asio::error::get_system_category());
52 overlapped
.complete(ec
, 0);
56 // The operation was successfully initiated, so ownership of the
57 // OVERLAPPED-derived object has passed to the io_context.
63 : public boost::enable_shared_from_this
<connection
>
66 typedef boost::shared_ptr
<connection
> pointer
;
68 static pointer
create(boost::asio::io_context
& io_context
,
69 const std::string
& filename
)
71 return pointer(new connection(io_context
, filename
));
81 boost::system::error_code ec
;
82 file_
.assign(::CreateFile(filename_
.c_str(), GENERIC_READ
, 0, 0,
83 OPEN_ALWAYS
, FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_OVERLAPPED
, 0), ec
);
86 transmit_file(socket_
, file_
,
87 boost::bind(&connection::handle_write
, shared_from_this(),
88 boost::asio::placeholders::error
,
89 boost::asio::placeholders::bytes_transferred
));
94 connection(boost::asio::io_context
& io_context
, const std::string
& filename
)
95 : socket_(io_context
),
101 void handle_write(const boost::system::error_code
& /*error*/,
102 size_t /*bytes_transferred*/)
104 boost::system::error_code ignored_ec
;
105 socket_
.shutdown(tcp_socket::shutdown_both
, ignored_ec
);
109 std::string filename_
;
110 random_access_handle file_
;
116 server(boost::asio::io_context
& io_context
,
117 unsigned short port
, const std::string
& filename
)
118 : acceptor_(io_context
, tcp::endpoint(tcp::v4(), port
)),
127 connection::pointer new_connection
=
128 connection::create(acceptor_
.get_executor().context(), filename_
);
130 acceptor_
.async_accept(new_connection
->socket(),
131 boost::bind(&server::handle_accept
, this, new_connection
,
132 boost::asio::placeholders::error
));
135 void handle_accept(connection::pointer new_connection
,
136 const boost::system::error_code
& error
)
140 new_connection
->start();
146 tcp_acceptor acceptor_
;
147 std::string filename_
;
150 int main(int argc
, char* argv
[])
156 std::cerr
<< "Usage: transmit_file <port> <filename>\n";
160 boost::asio::io_context io_context
;
162 using namespace std
; // For atoi.
163 server
s(io_context
, atoi(argv
[1]), argv
[2]);
167 catch (std::exception
& e
)
169 std::cerr
<< e
.what() << std::endl
;
175 #else // defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR)
176 # error Overlapped I/O not available on this platform
177 #endif // defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR)