* Fixed warnings
[libnetpp.git] / net / client / proxy / socks4.hpp
blob32b91d697b895fbb31b3c4285c4c9f35a8363e2d
1 /*
2 * Copyright (c) 2008,2009 by Vinzenz Feenstra
3 * All rights reserved.
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the Vinzenz Feenstra nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
26 #ifndef GUARD_NET_CLIENT_PROXY_SOCKS4_HPP_INCLUDED
27 #define GUARD_NET_CLIENT_PROXY_SOCKS4_HPP_INCLUDED
29 #if defined(WIN32) || defined(WIN64)
30 # ifndef NOMINMAX
31 # define NOMINMAX
32 # endif // NOMINMAX
33 #endif
35 #include <net/client/proxy_socket.hpp>
36 #include <algorithm>
38 namespace net
40 template<typename Tag>
41 struct socks4_proxy
42 : implements_proxy<Tag>
44 typedef implements_proxy<Tag> base_type;
45 typedef typename base_type::service_type service_type;
46 typedef typename base_type::endpoint_type endpoint_type;
47 typedef typename base_type::connected_handler connected_handler;
48 typedef typename base_type::error_code error_code;
50 union request_t
52 struct
54 boost::uint8_t version;
55 boost::uint8_t command;
56 boost::uint16_t destination_port;
57 boost::array<boost::uint8_t, 4> destination_address;
58 boost::uint8_t end_marker;
60 detail;
61 boost::array<boost::uint8_t, 9> bytes;
64 struct session
66 session(proxy_socket<Tag> & socket)
67 : data_buffer()
68 , request(reinterpret_cast<request_t*>(&data_buffer[0]))
69 , handler()
70 , endpoint()
71 , socket(boost::ref(socket))
75 boost::array<boost::uint8_t, 0x1000> data_buffer;
76 request_t * request;
77 connected_handler handler;
78 endpoint_type endpoint;
79 boost::reference_wrapper<proxy_socket<Tag> > socket;
81 void dump_buffer(size_t size)
83 static char const hex_chars[17] = "0123456789ABCDEF";
84 for(size_t i = 0; i < std::min(size, data_buffer.size()); ++i)
86 boost::uint8_t b = data_buffer[i];
87 std::cout << " " << hex_chars[(b&0xF0)>>4] << hex_chars[b&0x0F];
92 typedef boost::shared_ptr<session> session_ptr;
95 socks4_proxy(service_type & service)
96 : base_type(service)
101 virtual void on_async_connected(
102 proxy_socket<Tag> & socket,
103 endpoint_type const & endpoint,
104 connected_handler connected
107 std::cout << "Connected to proxy..." << std::endl;
108 boost::system::error_code ec;
109 session_ptr sess(new session(socket));
111 *(sess->request) = build_request(endpoint, ec);
112 if(ec) // Something went wrong with build_request
114 std::cout << "Something went wrong with build_request: " << ec << " Message: " << ec.message() << std::endl;
115 connected(ec);
118 sess->handler = connected;
119 sess->endpoint = endpoint;
121 std::cout << "Attempt to write: " << sess->request->bytes.size() << " bytes: ";
122 sess->dump_buffer(sess->request->bytes.size());
123 std::cout << std::endl;
125 boost::asio::async_write(
126 sess->socket.get(),
127 boost::asio::buffer(sess->request->bytes),
128 boost::bind(
129 &socks4_proxy::on_async_request_sent,
130 this,
131 boost::asio::placeholders::error,
132 sess
137 virtual void on_async_request_sent(
138 error_code const & ec,
139 session_ptr sess
142 if(!ec)
144 boost::asio::async_read(
145 sess->socket.get(),
146 boost::asio::buffer(sess->data_buffer),
147 boost::asio::transfer_at_least(8),
148 boost::bind(
149 &socks4_proxy::on_async_response_received,
150 this,
151 boost::asio::placeholders::error,
152 boost::asio::placeholders::bytes_transferred,
153 sess
157 else
159 sess->handler(ec);
164 virtual void on_async_response_received(
165 error_code const & ec,
166 size_t bytes_transferred,
167 session_ptr sess
170 static char const hex_chars[17] = "0123456789ABCDEF";
171 std::cout << ec << " Response received: (" << bytes_transferred << ") ";
172 sess->dump_buffer(bytes_transferred);
173 std::cout << std::endl;
175 if(!ec)
177 if(sess->data_buffer[1] == 0x5a)
179 sess->handler(error_code());
181 else
183 sess->handler(error_code(boost::asio::error::connection_refused));
186 else
188 sess->handler(ec);
192 virtual error_code on_connected(
193 proxy_socket<Tag> & socket,
194 endpoint_type const & endpoint,
195 error_code & ec
198 std::cout << "Connected to proxy..." << std::endl;
200 request_t request = build_request(endpoint, ec);
201 if(!ec)
203 std::cout << "Sending connection request to proxy..." << std::endl;
204 size_t bytes_sent = socket.send( boost::asio::buffer(request.bytes), 0, ec);
205 if(!ec)
207 std::cout << "Reading response from proxy..." << std::endl;
208 boost::array<boost::uint8_t, 8> buffer;
209 size_t bytes_read = socket.read_some(boost::asio::buffer(buffer), ec);
210 if(!ec)
212 if(bytes_read == 8)
214 if(buffer[1] == 0x5a)
216 std::cout << "Connection to remote endpoint granted and established" << std::endl;
217 return (ec = error_code());
220 std::cout << "Connection to remote endpoint denied or invalid response" << std::endl;
221 return (ec = error_code(boost::asio::error::connection_refused));
225 return ec;
228 virtual request_t build_request(endpoint_type ep, error_code & ec)
230 request_t rc = request_t();
231 if(!ep.address().is_v4())
233 ec = error_code(boost::asio::error::address_family_not_supported);
234 return rc;
236 rc.detail.version = 4;
237 rc.detail.command = 1;
238 rc.detail.destination_port = ::htons(ep.port());
239 rc.detail.destination_address = ep.address().to_v4().to_bytes();
240 rc.detail.end_marker = 0;
241 return rc;
247 #endif //GUARD_NET_CLIENT_PROXY_SOCKS4_HPP_INCLUDED