Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / asio / example / cpp03 / windows / transmit_file.cpp
1 //
2 // transmit_file.cpp
3 // ~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
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)
9 //
10
11 #include <ctime>
12 #include <iostream>
13 #include <string>
14 #include <boost/bind.hpp>
15 #include <boost/shared_ptr.hpp>
16 #include <boost/enable_shared_from_this.hpp>
17 #include <boost/asio.hpp>
18
19 #if defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR)
20
21 using boost::asio::ip::tcp;
22 using boost::asio::windows::overlapped_ptr;
23 using boost::asio::windows::random_access_handle;
24
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)
29 {
30   // Construct an OVERLAPPED-derived object to contain the handler.
31   overlapped_ptr overlapped(socket.get_io_service(), handler);
32
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();
37
38   // Check if the operation completed immediately.
39   if (!ok && last_error != ERROR_IO_PENDING)
40   {
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);
47   }
48   else
49   {
50     // The operation was successfully initiated, so ownership of the
51     // OVERLAPPED-derived object has passed to the io_service.
52     overlapped.release();
53   }
54 }
55
56 class connection
57   : public boost::enable_shared_from_this<connection>
58 {
59 public:
60   typedef boost::shared_ptr<connection> pointer;
61
62   static pointer create(boost::asio::io_service& io_service,
63       const std::string& filename)
64   {
65     return pointer(new connection(io_service, filename));
66   }
67
68   tcp::socket& socket()
69   {
70     return socket_;
71   }
72
73   void start()
74   {
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);
78     if (file_.is_open())
79     {
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));
84     }
85   }
86
87 private:
88   connection(boost::asio::io_service& io_service, const std::string& filename)
89     : socket_(io_service),
90       filename_(filename),
91       file_(io_service)
92   {
93   }
94
95   void handle_write(const boost::system::error_code& /*error*/,
96       size_t /*bytes_transferred*/)
97   {
98     boost::system::error_code ignored_ec;
99     socket_.shutdown(tcp::socket::shutdown_both, ignored_ec);
100   }
101
102   tcp::socket socket_;
103   std::string filename_;
104   random_access_handle file_;
105 };
106
107 class server
108 {
109 public:
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)),
113       filename_(filename)
114   {
115     start_accept();
116   }
117
118 private:
119   void start_accept()
120   {
121     connection::pointer new_connection =
122       connection::create(acceptor_.get_io_service(), filename_);
123
124     acceptor_.async_accept(new_connection->socket(),
125         boost::bind(&server::handle_accept, this, new_connection,
126           boost::asio::placeholders::error));
127   }
128
129   void handle_accept(connection::pointer new_connection,
130       const boost::system::error_code& error)
131   {
132     if (!error)
133     {
134       new_connection->start();
135     }
136
137     start_accept();
138   }
139
140   tcp::acceptor acceptor_;
141   std::string filename_;
142 };
143
144 int main(int argc, char* argv[])
145 {
146   try
147   {
148     if (argc != 3)
149     {
150       std::cerr << "Usage: transmit_file <port> <filename>\n";
151       return 1;
152     }
153
154     boost::asio::io_service io_service;
155
156     using namespace std; // For atoi.
157     server s(io_service, atoi(argv[1]), argv[2]);
158
159     io_service.run();
160   }
161   catch (std::exception& e)
162   {
163     std::cerr << e.what() << std::endl;
164   }
165
166   return 0;
167 }
168
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)