5 // Copyright (c) 2003-2014 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 // A wrapper for the TransmitFile overlapped I/O operation.
26 template <typename Handler>
27 void transmit_file(tcp::socket& socket,
28 random_access_handle& file, Handler handler)
30 // Construct an OVERLAPPED-derived object to contain the handler.
31 overlapped_ptr overlapped(socket.get_io_service(), handler);
33 // Initiate the TransmitFile operation.
34 BOOL ok = ::TransmitFile(socket.native_handle(),
35 file.native_handle(), 0, 0, overlapped.get(), 0, 0);
36 DWORD last_error = ::GetLastError();
38 // Check if the operation completed immediately.
39 if (!ok && last_error != ERROR_IO_PENDING)
41 // The operation completed immediately, so a completion notification needs
42 // to be posted. When complete() is called, ownership of the OVERLAPPED-
43 // derived object passes to the io_service.
44 boost::system::error_code ec(last_error,
45 boost::asio::error::get_system_category());
46 overlapped.complete(ec, 0);
50 // The operation was successfully initiated, so ownership of the
51 // OVERLAPPED-derived object has passed to the io_service.
57 : public boost::enable_shared_from_this<connection>
60 typedef boost::shared_ptr<connection> pointer;
62 static pointer create(boost::asio::io_service& io_service,
63 const std::string& filename)
65 return pointer(new connection(io_service, filename));
75 boost::system::error_code ec;
76 file_.assign(::CreateFile(filename_.c_str(), GENERIC_READ, 0, 0,
77 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0), ec);
80 transmit_file(socket_, file_,
81 boost::bind(&connection::handle_write, shared_from_this(),
82 boost::asio::placeholders::error,
83 boost::asio::placeholders::bytes_transferred));
88 connection(boost::asio::io_service& io_service, const std::string& filename)
89 : socket_(io_service),
95 void handle_write(const boost::system::error_code& /*error*/,
96 size_t /*bytes_transferred*/)
98 boost::system::error_code ignored_ec;
99 socket_.shutdown(tcp::socket::shutdown_both, ignored_ec);
103 std::string filename_;
104 random_access_handle file_;
110 server(boost::asio::io_service& io_service,
111 unsigned short port, const std::string& filename)
112 : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
121 connection::pointer new_connection =
122 connection::create(acceptor_.get_io_service(), filename_);
124 acceptor_.async_accept(new_connection->socket(),
125 boost::bind(&server::handle_accept, this, new_connection,
126 boost::asio::placeholders::error));
129 void handle_accept(connection::pointer new_connection,
130 const boost::system::error_code& error)
134 new_connection->start();
140 tcp::acceptor acceptor_;
141 std::string filename_;
144 int main(int argc, char* argv[])
150 std::cerr << "Usage: transmit_file <port> <filename>\n";
154 boost::asio::io_service io_service;
156 using namespace std; // For atoi.
157 server s(io_service, atoi(argv[1]), argv[2]);
161 catch (std::exception& e)
163 std::cerr << e.what() << std::endl;
169 #else // defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR)
170 # error Overlapped I/O not available on this platform
171 #endif // defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR)