5 // Copyright (c) 2003-2019 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.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)