Chris@16
|
1 //
|
Chris@16
|
2 // detail/impl/socket_ops.ipp
|
Chris@16
|
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
Chris@16
|
4 //
|
Chris@16
|
5 // Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
Chris@16
|
6 //
|
Chris@16
|
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 //
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_IPP
|
Chris@16
|
12 #define BOOST_ASIO_DETAIL_SOCKET_OPS_IPP
|
Chris@16
|
13
|
Chris@16
|
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
15 # pragma once
|
Chris@16
|
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/asio/detail/config.hpp>
|
Chris@16
|
19
|
Chris@16
|
20 #include <cctype>
|
Chris@16
|
21 #include <cstdio>
|
Chris@16
|
22 #include <cstdlib>
|
Chris@16
|
23 #include <cstring>
|
Chris@16
|
24 #include <cerrno>
|
Chris@16
|
25 #include <new>
|
Chris@16
|
26 #include <boost/asio/detail/assert.hpp>
|
Chris@16
|
27 #include <boost/asio/detail/socket_ops.hpp>
|
Chris@16
|
28 #include <boost/asio/error.hpp>
|
Chris@16
|
29
|
Chris@16
|
30 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
31 # include <codecvt>
|
Chris@16
|
32 # include <locale>
|
Chris@16
|
33 # include <string>
|
Chris@16
|
34 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
35
|
Chris@16
|
36 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) \
|
Chris@16
|
37 || defined(__MACH__) && defined(__APPLE__)
|
Chris@16
|
38 # if defined(BOOST_ASIO_HAS_PTHREADS)
|
Chris@16
|
39 # include <pthread.h>
|
Chris@16
|
40 # endif // defined(BOOST_ASIO_HAS_PTHREADS)
|
Chris@16
|
41 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
42 // || defined(__MACH__) && defined(__APPLE__)
|
Chris@16
|
43
|
Chris@16
|
44 #include <boost/asio/detail/push_options.hpp>
|
Chris@16
|
45
|
Chris@16
|
46 namespace boost {
|
Chris@16
|
47 namespace asio {
|
Chris@16
|
48 namespace detail {
|
Chris@16
|
49 namespace socket_ops {
|
Chris@16
|
50
|
Chris@16
|
51 #if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
52
|
Chris@16
|
53 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
54 struct msghdr { int msg_namelen; };
|
Chris@16
|
55 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
56
|
Chris@16
|
57 #if defined(__hpux)
|
Chris@16
|
58 // HP-UX doesn't declare these functions extern "C", so they are declared again
|
Chris@16
|
59 // here to avoid linker errors about undefined symbols.
|
Chris@16
|
60 extern "C" char* if_indextoname(unsigned int, char*);
|
Chris@16
|
61 extern "C" unsigned int if_nametoindex(const char*);
|
Chris@16
|
62 #endif // defined(__hpux)
|
Chris@16
|
63
|
Chris@16
|
64 #endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
65
|
Chris@16
|
66 inline void clear_last_error()
|
Chris@16
|
67 {
|
Chris@16
|
68 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
69 WSASetLastError(0);
|
Chris@16
|
70 #else
|
Chris@16
|
71 errno = 0;
|
Chris@16
|
72 #endif
|
Chris@16
|
73 }
|
Chris@16
|
74
|
Chris@16
|
75 #if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
76
|
Chris@16
|
77 template <typename ReturnType>
|
Chris@16
|
78 inline ReturnType error_wrapper(ReturnType return_value,
|
Chris@16
|
79 boost::system::error_code& ec)
|
Chris@16
|
80 {
|
Chris@16
|
81 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
82 ec = boost::system::error_code(WSAGetLastError(),
|
Chris@16
|
83 boost::asio::error::get_system_category());
|
Chris@16
|
84 #else
|
Chris@16
|
85 ec = boost::system::error_code(errno,
|
Chris@16
|
86 boost::asio::error::get_system_category());
|
Chris@16
|
87 #endif
|
Chris@16
|
88 return return_value;
|
Chris@16
|
89 }
|
Chris@16
|
90
|
Chris@16
|
91 template <typename SockLenType>
|
Chris@16
|
92 inline socket_type call_accept(SockLenType msghdr::*,
|
Chris@16
|
93 socket_type s, socket_addr_type* addr, std::size_t* addrlen)
|
Chris@16
|
94 {
|
Chris@16
|
95 SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
|
Chris@16
|
96 socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);
|
Chris@16
|
97 if (addrlen)
|
Chris@16
|
98 *addrlen = (std::size_t)tmp_addrlen;
|
Chris@16
|
99 return result;
|
Chris@16
|
100 }
|
Chris@16
|
101
|
Chris@16
|
102 socket_type accept(socket_type s, socket_addr_type* addr,
|
Chris@16
|
103 std::size_t* addrlen, boost::system::error_code& ec)
|
Chris@16
|
104 {
|
Chris@16
|
105 if (s == invalid_socket)
|
Chris@16
|
106 {
|
Chris@16
|
107 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
108 return invalid_socket;
|
Chris@16
|
109 }
|
Chris@16
|
110
|
Chris@16
|
111 clear_last_error();
|
Chris@16
|
112
|
Chris@16
|
113 socket_type new_s = error_wrapper(call_accept(
|
Chris@16
|
114 &msghdr::msg_namelen, s, addr, addrlen), ec);
|
Chris@16
|
115 if (new_s == invalid_socket)
|
Chris@16
|
116 return new_s;
|
Chris@16
|
117
|
Chris@16
|
118 #if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
|
Chris@16
|
119 int optval = 1;
|
Chris@16
|
120 int result = error_wrapper(::setsockopt(new_s,
|
Chris@16
|
121 SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
|
Chris@16
|
122 if (result != 0)
|
Chris@16
|
123 {
|
Chris@16
|
124 ::close(new_s);
|
Chris@16
|
125 return invalid_socket;
|
Chris@16
|
126 }
|
Chris@16
|
127 #endif
|
Chris@16
|
128
|
Chris@16
|
129 ec = boost::system::error_code();
|
Chris@16
|
130 return new_s;
|
Chris@16
|
131 }
|
Chris@16
|
132
|
Chris@16
|
133 socket_type sync_accept(socket_type s, state_type state,
|
Chris@16
|
134 socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec)
|
Chris@16
|
135 {
|
Chris@16
|
136 // Accept a socket.
|
Chris@16
|
137 for (;;)
|
Chris@16
|
138 {
|
Chris@16
|
139 // Try to complete the operation without blocking.
|
Chris@16
|
140 socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec);
|
Chris@16
|
141
|
Chris@16
|
142 // Check if operation succeeded.
|
Chris@16
|
143 if (new_socket != invalid_socket)
|
Chris@16
|
144 return new_socket;
|
Chris@16
|
145
|
Chris@16
|
146 // Operation failed.
|
Chris@16
|
147 if (ec == boost::asio::error::would_block
|
Chris@16
|
148 || ec == boost::asio::error::try_again)
|
Chris@16
|
149 {
|
Chris@16
|
150 if (state & user_set_non_blocking)
|
Chris@16
|
151 return invalid_socket;
|
Chris@16
|
152 // Fall through to retry operation.
|
Chris@16
|
153 }
|
Chris@16
|
154 else if (ec == boost::asio::error::connection_aborted)
|
Chris@16
|
155 {
|
Chris@16
|
156 if (state & enable_connection_aborted)
|
Chris@16
|
157 return invalid_socket;
|
Chris@16
|
158 // Fall through to retry operation.
|
Chris@16
|
159 }
|
Chris@16
|
160 #if defined(EPROTO)
|
Chris@16
|
161 else if (ec.value() == EPROTO)
|
Chris@16
|
162 {
|
Chris@16
|
163 if (state & enable_connection_aborted)
|
Chris@16
|
164 return invalid_socket;
|
Chris@16
|
165 // Fall through to retry operation.
|
Chris@16
|
166 }
|
Chris@16
|
167 #endif // defined(EPROTO)
|
Chris@16
|
168 else
|
Chris@16
|
169 return invalid_socket;
|
Chris@16
|
170
|
Chris@16
|
171 // Wait for socket to become ready.
|
Chris@16
|
172 if (socket_ops::poll_read(s, 0, ec) < 0)
|
Chris@16
|
173 return invalid_socket;
|
Chris@16
|
174 }
|
Chris@16
|
175 }
|
Chris@16
|
176
|
Chris@16
|
177 #if defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
178
|
Chris@16
|
179 void complete_iocp_accept(socket_type s,
|
Chris@16
|
180 void* output_buffer, DWORD address_length,
|
Chris@16
|
181 socket_addr_type* addr, std::size_t* addrlen,
|
Chris@16
|
182 socket_type new_socket, boost::system::error_code& ec)
|
Chris@16
|
183 {
|
Chris@16
|
184 // Map non-portable errors to their portable counterparts.
|
Chris@16
|
185 if (ec.value() == ERROR_NETNAME_DELETED)
|
Chris@16
|
186 ec = boost::asio::error::connection_aborted;
|
Chris@16
|
187
|
Chris@16
|
188 if (!ec)
|
Chris@16
|
189 {
|
Chris@16
|
190 // Get the address of the peer.
|
Chris@16
|
191 if (addr && addrlen)
|
Chris@16
|
192 {
|
Chris@16
|
193 LPSOCKADDR local_addr = 0;
|
Chris@16
|
194 int local_addr_length = 0;
|
Chris@16
|
195 LPSOCKADDR remote_addr = 0;
|
Chris@16
|
196 int remote_addr_length = 0;
|
Chris@16
|
197 GetAcceptExSockaddrs(output_buffer, 0, address_length,
|
Chris@16
|
198 address_length, &local_addr, &local_addr_length,
|
Chris@16
|
199 &remote_addr, &remote_addr_length);
|
Chris@16
|
200 if (static_cast<std::size_t>(remote_addr_length) > *addrlen)
|
Chris@16
|
201 {
|
Chris@16
|
202 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
203 }
|
Chris@16
|
204 else
|
Chris@16
|
205 {
|
Chris@16
|
206 using namespace std; // For memcpy.
|
Chris@16
|
207 memcpy(addr, remote_addr, remote_addr_length);
|
Chris@16
|
208 *addrlen = static_cast<std::size_t>(remote_addr_length);
|
Chris@16
|
209 }
|
Chris@16
|
210 }
|
Chris@16
|
211
|
Chris@16
|
212 // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
|
Chris@16
|
213 // and getpeername will work on the accepted socket.
|
Chris@16
|
214 SOCKET update_ctx_param = s;
|
Chris@16
|
215 socket_ops::state_type state = 0;
|
Chris@16
|
216 socket_ops::setsockopt(new_socket, state,
|
Chris@16
|
217 SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
|
Chris@16
|
218 &update_ctx_param, sizeof(SOCKET), ec);
|
Chris@16
|
219 }
|
Chris@16
|
220 }
|
Chris@16
|
221
|
Chris@16
|
222 #else // defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
223
|
Chris@16
|
224 bool non_blocking_accept(socket_type s,
|
Chris@16
|
225 state_type state, socket_addr_type* addr, std::size_t* addrlen,
|
Chris@16
|
226 boost::system::error_code& ec, socket_type& new_socket)
|
Chris@16
|
227 {
|
Chris@16
|
228 for (;;)
|
Chris@16
|
229 {
|
Chris@16
|
230 // Accept the waiting connection.
|
Chris@16
|
231 new_socket = socket_ops::accept(s, addr, addrlen, ec);
|
Chris@16
|
232
|
Chris@16
|
233 // Check if operation succeeded.
|
Chris@16
|
234 if (new_socket != invalid_socket)
|
Chris@16
|
235 return true;
|
Chris@16
|
236
|
Chris@16
|
237 // Retry operation if interrupted by signal.
|
Chris@16
|
238 if (ec == boost::asio::error::interrupted)
|
Chris@16
|
239 continue;
|
Chris@16
|
240
|
Chris@16
|
241 // Operation failed.
|
Chris@16
|
242 if (ec == boost::asio::error::would_block
|
Chris@16
|
243 || ec == boost::asio::error::try_again)
|
Chris@16
|
244 {
|
Chris@16
|
245 if (state & user_set_non_blocking)
|
Chris@16
|
246 return true;
|
Chris@16
|
247 // Fall through to retry operation.
|
Chris@16
|
248 }
|
Chris@16
|
249 else if (ec == boost::asio::error::connection_aborted)
|
Chris@16
|
250 {
|
Chris@16
|
251 if (state & enable_connection_aborted)
|
Chris@16
|
252 return true;
|
Chris@16
|
253 // Fall through to retry operation.
|
Chris@16
|
254 }
|
Chris@16
|
255 #if defined(EPROTO)
|
Chris@16
|
256 else if (ec.value() == EPROTO)
|
Chris@16
|
257 {
|
Chris@16
|
258 if (state & enable_connection_aborted)
|
Chris@16
|
259 return true;
|
Chris@16
|
260 // Fall through to retry operation.
|
Chris@16
|
261 }
|
Chris@16
|
262 #endif // defined(EPROTO)
|
Chris@16
|
263 else
|
Chris@16
|
264 return true;
|
Chris@16
|
265
|
Chris@16
|
266 return false;
|
Chris@16
|
267 }
|
Chris@16
|
268 }
|
Chris@16
|
269
|
Chris@16
|
270 #endif // defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
271
|
Chris@16
|
272 template <typename SockLenType>
|
Chris@16
|
273 inline int call_bind(SockLenType msghdr::*,
|
Chris@16
|
274 socket_type s, const socket_addr_type* addr, std::size_t addrlen)
|
Chris@16
|
275 {
|
Chris@16
|
276 return ::bind(s, addr, (SockLenType)addrlen);
|
Chris@16
|
277 }
|
Chris@16
|
278
|
Chris@16
|
279 int bind(socket_type s, const socket_addr_type* addr,
|
Chris@16
|
280 std::size_t addrlen, boost::system::error_code& ec)
|
Chris@16
|
281 {
|
Chris@16
|
282 if (s == invalid_socket)
|
Chris@16
|
283 {
|
Chris@16
|
284 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
285 return socket_error_retval;
|
Chris@16
|
286 }
|
Chris@16
|
287
|
Chris@16
|
288 clear_last_error();
|
Chris@16
|
289 int result = error_wrapper(call_bind(
|
Chris@16
|
290 &msghdr::msg_namelen, s, addr, addrlen), ec);
|
Chris@16
|
291 if (result == 0)
|
Chris@16
|
292 ec = boost::system::error_code();
|
Chris@16
|
293 return result;
|
Chris@16
|
294 }
|
Chris@16
|
295
|
Chris@16
|
296 int close(socket_type s, state_type& state,
|
Chris@16
|
297 bool destruction, boost::system::error_code& ec)
|
Chris@16
|
298 {
|
Chris@16
|
299 int result = 0;
|
Chris@16
|
300 if (s != invalid_socket)
|
Chris@16
|
301 {
|
Chris@16
|
302 // We don't want the destructor to block, so set the socket to linger in
|
Chris@16
|
303 // the background. If the user doesn't like this behaviour then they need
|
Chris@16
|
304 // to explicitly close the socket.
|
Chris@16
|
305 if (destruction && (state & user_set_linger))
|
Chris@16
|
306 {
|
Chris@16
|
307 ::linger opt;
|
Chris@16
|
308 opt.l_onoff = 0;
|
Chris@16
|
309 opt.l_linger = 0;
|
Chris@16
|
310 boost::system::error_code ignored_ec;
|
Chris@16
|
311 socket_ops::setsockopt(s, state, SOL_SOCKET,
|
Chris@16
|
312 SO_LINGER, &opt, sizeof(opt), ignored_ec);
|
Chris@16
|
313 }
|
Chris@16
|
314
|
Chris@16
|
315 clear_last_error();
|
Chris@16
|
316 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
317 result = error_wrapper(::closesocket(s), ec);
|
Chris@16
|
318 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
319 result = error_wrapper(::close(s), ec);
|
Chris@16
|
320 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
321
|
Chris@16
|
322 if (result != 0
|
Chris@16
|
323 && (ec == boost::asio::error::would_block
|
Chris@16
|
324 || ec == boost::asio::error::try_again))
|
Chris@16
|
325 {
|
Chris@16
|
326 // According to UNIX Network Programming Vol. 1, it is possible for
|
Chris@16
|
327 // close() to fail with EWOULDBLOCK under certain circumstances. What
|
Chris@16
|
328 // isn't clear is the state of the descriptor after this error. The one
|
Chris@16
|
329 // current OS where this behaviour is seen, Windows, says that the socket
|
Chris@16
|
330 // remains open. Therefore we'll put the descriptor back into blocking
|
Chris@16
|
331 // mode and have another attempt at closing it.
|
Chris@16
|
332 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
333 ioctl_arg_type arg = 0;
|
Chris@16
|
334 ::ioctlsocket(s, FIONBIO, &arg);
|
Chris@16
|
335 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
336 # if defined(__SYMBIAN32__)
|
Chris@16
|
337 int flags = ::fcntl(s, F_GETFL, 0);
|
Chris@16
|
338 if (flags >= 0)
|
Chris@16
|
339 ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK);
|
Chris@16
|
340 # else // defined(__SYMBIAN32__)
|
Chris@16
|
341 ioctl_arg_type arg = 0;
|
Chris@16
|
342 ::ioctl(s, FIONBIO, &arg);
|
Chris@16
|
343 # endif // defined(__SYMBIAN32__)
|
Chris@16
|
344 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
345 state &= ~non_blocking;
|
Chris@16
|
346
|
Chris@16
|
347 clear_last_error();
|
Chris@16
|
348 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
349 result = error_wrapper(::closesocket(s), ec);
|
Chris@16
|
350 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
351 result = error_wrapper(::close(s), ec);
|
Chris@16
|
352 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
353 }
|
Chris@16
|
354 }
|
Chris@16
|
355
|
Chris@16
|
356 if (result == 0)
|
Chris@16
|
357 ec = boost::system::error_code();
|
Chris@16
|
358 return result;
|
Chris@16
|
359 }
|
Chris@16
|
360
|
Chris@16
|
361 bool set_user_non_blocking(socket_type s,
|
Chris@16
|
362 state_type& state, bool value, boost::system::error_code& ec)
|
Chris@16
|
363 {
|
Chris@16
|
364 if (s == invalid_socket)
|
Chris@16
|
365 {
|
Chris@16
|
366 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
367 return false;
|
Chris@16
|
368 }
|
Chris@16
|
369
|
Chris@16
|
370 clear_last_error();
|
Chris@16
|
371 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
372 ioctl_arg_type arg = (value ? 1 : 0);
|
Chris@16
|
373 int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec);
|
Chris@16
|
374 #elif defined(__SYMBIAN32__)
|
Chris@16
|
375 int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec);
|
Chris@16
|
376 if (result >= 0)
|
Chris@16
|
377 {
|
Chris@16
|
378 clear_last_error();
|
Chris@16
|
379 int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
|
Chris@16
|
380 result = error_wrapper(::fcntl(s, F_SETFL, flag), ec);
|
Chris@16
|
381 }
|
Chris@16
|
382 #else
|
Chris@16
|
383 ioctl_arg_type arg = (value ? 1 : 0);
|
Chris@16
|
384 int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec);
|
Chris@16
|
385 #endif
|
Chris@16
|
386
|
Chris@16
|
387 if (result >= 0)
|
Chris@16
|
388 {
|
Chris@16
|
389 ec = boost::system::error_code();
|
Chris@16
|
390 if (value)
|
Chris@16
|
391 state |= user_set_non_blocking;
|
Chris@16
|
392 else
|
Chris@16
|
393 {
|
Chris@16
|
394 // Clearing the user-set non-blocking mode always overrides any
|
Chris@16
|
395 // internally-set non-blocking flag. Any subsequent asynchronous
|
Chris@16
|
396 // operations will need to re-enable non-blocking I/O.
|
Chris@16
|
397 state &= ~(user_set_non_blocking | internal_non_blocking);
|
Chris@16
|
398 }
|
Chris@16
|
399 return true;
|
Chris@16
|
400 }
|
Chris@16
|
401
|
Chris@16
|
402 return false;
|
Chris@16
|
403 }
|
Chris@16
|
404
|
Chris@16
|
405 bool set_internal_non_blocking(socket_type s,
|
Chris@16
|
406 state_type& state, bool value, boost::system::error_code& ec)
|
Chris@16
|
407 {
|
Chris@16
|
408 if (s == invalid_socket)
|
Chris@16
|
409 {
|
Chris@16
|
410 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
411 return false;
|
Chris@16
|
412 }
|
Chris@16
|
413
|
Chris@16
|
414 if (!value && (state & user_set_non_blocking))
|
Chris@16
|
415 {
|
Chris@16
|
416 // It does not make sense to clear the internal non-blocking flag if the
|
Chris@16
|
417 // user still wants non-blocking behaviour. Return an error and let the
|
Chris@16
|
418 // caller figure out whether to update the user-set non-blocking flag.
|
Chris@16
|
419 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
420 return false;
|
Chris@16
|
421 }
|
Chris@16
|
422
|
Chris@16
|
423 clear_last_error();
|
Chris@16
|
424 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
425 ioctl_arg_type arg = (value ? 1 : 0);
|
Chris@16
|
426 int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec);
|
Chris@16
|
427 #elif defined(__SYMBIAN32__)
|
Chris@16
|
428 int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec);
|
Chris@16
|
429 if (result >= 0)
|
Chris@16
|
430 {
|
Chris@16
|
431 clear_last_error();
|
Chris@16
|
432 int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
|
Chris@16
|
433 result = error_wrapper(::fcntl(s, F_SETFL, flag), ec);
|
Chris@16
|
434 }
|
Chris@16
|
435 #else
|
Chris@16
|
436 ioctl_arg_type arg = (value ? 1 : 0);
|
Chris@16
|
437 int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec);
|
Chris@16
|
438 #endif
|
Chris@16
|
439
|
Chris@16
|
440 if (result >= 0)
|
Chris@16
|
441 {
|
Chris@16
|
442 ec = boost::system::error_code();
|
Chris@16
|
443 if (value)
|
Chris@16
|
444 state |= internal_non_blocking;
|
Chris@16
|
445 else
|
Chris@16
|
446 state &= ~internal_non_blocking;
|
Chris@16
|
447 return true;
|
Chris@16
|
448 }
|
Chris@16
|
449
|
Chris@16
|
450 return false;
|
Chris@16
|
451 }
|
Chris@16
|
452
|
Chris@16
|
453 int shutdown(socket_type s, int what, boost::system::error_code& ec)
|
Chris@16
|
454 {
|
Chris@16
|
455 if (s == invalid_socket)
|
Chris@16
|
456 {
|
Chris@16
|
457 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
458 return socket_error_retval;
|
Chris@16
|
459 }
|
Chris@16
|
460
|
Chris@16
|
461 clear_last_error();
|
Chris@16
|
462 int result = error_wrapper(::shutdown(s, what), ec);
|
Chris@16
|
463 if (result == 0)
|
Chris@16
|
464 ec = boost::system::error_code();
|
Chris@16
|
465 return result;
|
Chris@16
|
466 }
|
Chris@16
|
467
|
Chris@16
|
468 template <typename SockLenType>
|
Chris@16
|
469 inline int call_connect(SockLenType msghdr::*,
|
Chris@16
|
470 socket_type s, const socket_addr_type* addr, std::size_t addrlen)
|
Chris@16
|
471 {
|
Chris@16
|
472 return ::connect(s, addr, (SockLenType)addrlen);
|
Chris@16
|
473 }
|
Chris@16
|
474
|
Chris@16
|
475 int connect(socket_type s, const socket_addr_type* addr,
|
Chris@16
|
476 std::size_t addrlen, boost::system::error_code& ec)
|
Chris@16
|
477 {
|
Chris@16
|
478 if (s == invalid_socket)
|
Chris@16
|
479 {
|
Chris@16
|
480 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
481 return socket_error_retval;
|
Chris@16
|
482 }
|
Chris@16
|
483
|
Chris@16
|
484 clear_last_error();
|
Chris@16
|
485 int result = error_wrapper(call_connect(
|
Chris@16
|
486 &msghdr::msg_namelen, s, addr, addrlen), ec);
|
Chris@16
|
487 if (result == 0)
|
Chris@16
|
488 ec = boost::system::error_code();
|
Chris@16
|
489 #if defined(__linux__)
|
Chris@16
|
490 else if (ec == boost::asio::error::try_again)
|
Chris@16
|
491 ec = boost::asio::error::no_buffer_space;
|
Chris@16
|
492 #endif // defined(__linux__)
|
Chris@16
|
493 return result;
|
Chris@16
|
494 }
|
Chris@16
|
495
|
Chris@16
|
496 void sync_connect(socket_type s, const socket_addr_type* addr,
|
Chris@16
|
497 std::size_t addrlen, boost::system::error_code& ec)
|
Chris@16
|
498 {
|
Chris@16
|
499 // Perform the connect operation.
|
Chris@16
|
500 socket_ops::connect(s, addr, addrlen, ec);
|
Chris@16
|
501 if (ec != boost::asio::error::in_progress
|
Chris@16
|
502 && ec != boost::asio::error::would_block)
|
Chris@16
|
503 {
|
Chris@16
|
504 // The connect operation finished immediately.
|
Chris@16
|
505 return;
|
Chris@16
|
506 }
|
Chris@16
|
507
|
Chris@16
|
508 // Wait for socket to become ready.
|
Chris@16
|
509 if (socket_ops::poll_connect(s, ec) < 0)
|
Chris@16
|
510 return;
|
Chris@16
|
511
|
Chris@16
|
512 // Get the error code from the connect operation.
|
Chris@16
|
513 int connect_error = 0;
|
Chris@16
|
514 size_t connect_error_len = sizeof(connect_error);
|
Chris@16
|
515 if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
|
Chris@16
|
516 &connect_error, &connect_error_len, ec) == socket_error_retval)
|
Chris@16
|
517 return;
|
Chris@16
|
518
|
Chris@16
|
519 // Return the result of the connect operation.
|
Chris@16
|
520 ec = boost::system::error_code(connect_error,
|
Chris@16
|
521 boost::asio::error::get_system_category());
|
Chris@16
|
522 }
|
Chris@16
|
523
|
Chris@16
|
524 bool non_blocking_connect(socket_type s, boost::system::error_code& ec)
|
Chris@16
|
525 {
|
Chris@16
|
526 // Check if the connect operation has finished. This is required since we may
|
Chris@16
|
527 // get spurious readiness notifications from the reactor.
|
Chris@16
|
528 #if defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
529 || defined(__CYGWIN__) \
|
Chris@16
|
530 || defined(__SYMBIAN32__)
|
Chris@16
|
531 fd_set write_fds;
|
Chris@16
|
532 FD_ZERO(&write_fds);
|
Chris@16
|
533 FD_SET(s, &write_fds);
|
Chris@16
|
534 fd_set except_fds;
|
Chris@16
|
535 FD_ZERO(&except_fds);
|
Chris@16
|
536 FD_SET(s, &except_fds);
|
Chris@16
|
537 timeval zero_timeout;
|
Chris@16
|
538 zero_timeout.tv_sec = 0;
|
Chris@16
|
539 zero_timeout.tv_usec = 0;
|
Chris@16
|
540 int ready = ::select(s + 1, 0, &write_fds, &except_fds, &zero_timeout);
|
Chris@16
|
541 #else // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
542 // || defined(__CYGWIN__)
|
Chris@16
|
543 // || defined(__SYMBIAN32__)
|
Chris@16
|
544 pollfd fds;
|
Chris@16
|
545 fds.fd = s;
|
Chris@16
|
546 fds.events = POLLOUT;
|
Chris@16
|
547 fds.revents = 0;
|
Chris@16
|
548 int ready = ::poll(&fds, 1, 0);
|
Chris@16
|
549 #endif // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
550 // || defined(__CYGWIN__)
|
Chris@16
|
551 // || defined(__SYMBIAN32__)
|
Chris@16
|
552 if (ready == 0)
|
Chris@16
|
553 {
|
Chris@16
|
554 // The asynchronous connect operation is still in progress.
|
Chris@16
|
555 return false;
|
Chris@16
|
556 }
|
Chris@16
|
557
|
Chris@16
|
558 // Get the error code from the connect operation.
|
Chris@16
|
559 int connect_error = 0;
|
Chris@16
|
560 size_t connect_error_len = sizeof(connect_error);
|
Chris@16
|
561 if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
|
Chris@16
|
562 &connect_error, &connect_error_len, ec) == 0)
|
Chris@16
|
563 {
|
Chris@16
|
564 if (connect_error)
|
Chris@16
|
565 {
|
Chris@16
|
566 ec = boost::system::error_code(connect_error,
|
Chris@16
|
567 boost::asio::error::get_system_category());
|
Chris@16
|
568 }
|
Chris@16
|
569 else
|
Chris@16
|
570 ec = boost::system::error_code();
|
Chris@16
|
571 }
|
Chris@16
|
572
|
Chris@16
|
573 return true;
|
Chris@16
|
574 }
|
Chris@16
|
575
|
Chris@16
|
576 int socketpair(int af, int type, int protocol,
|
Chris@16
|
577 socket_type sv[2], boost::system::error_code& ec)
|
Chris@16
|
578 {
|
Chris@16
|
579 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
580 (void)(af);
|
Chris@16
|
581 (void)(type);
|
Chris@16
|
582 (void)(protocol);
|
Chris@16
|
583 (void)(sv);
|
Chris@16
|
584 ec = boost::asio::error::operation_not_supported;
|
Chris@16
|
585 return socket_error_retval;
|
Chris@16
|
586 #else
|
Chris@16
|
587 clear_last_error();
|
Chris@16
|
588 int result = error_wrapper(::socketpair(af, type, protocol, sv), ec);
|
Chris@16
|
589 if (result == 0)
|
Chris@16
|
590 ec = boost::system::error_code();
|
Chris@16
|
591 return result;
|
Chris@16
|
592 #endif
|
Chris@16
|
593 }
|
Chris@16
|
594
|
Chris@16
|
595 bool sockatmark(socket_type s, boost::system::error_code& ec)
|
Chris@16
|
596 {
|
Chris@16
|
597 if (s == invalid_socket)
|
Chris@16
|
598 {
|
Chris@16
|
599 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
600 return false;
|
Chris@16
|
601 }
|
Chris@16
|
602
|
Chris@16
|
603 #if defined(SIOCATMARK)
|
Chris@16
|
604 ioctl_arg_type value = 0;
|
Chris@16
|
605 # if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
606 int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec);
|
Chris@16
|
607 # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
608 int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec);
|
Chris@16
|
609 # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
610 if (result == 0)
|
Chris@16
|
611 ec = boost::system::error_code();
|
Chris@16
|
612 # if defined(ENOTTY)
|
Chris@16
|
613 if (ec.value() == ENOTTY)
|
Chris@16
|
614 ec = boost::asio::error::not_socket;
|
Chris@16
|
615 # endif // defined(ENOTTY)
|
Chris@16
|
616 #else // defined(SIOCATMARK)
|
Chris@16
|
617 int value = error_wrapper(::sockatmark(s), ec);
|
Chris@16
|
618 if (value != -1)
|
Chris@16
|
619 ec = boost::system::error_code();
|
Chris@16
|
620 #endif // defined(SIOCATMARK)
|
Chris@16
|
621
|
Chris@16
|
622 return ec ? false : value != 0;
|
Chris@16
|
623 }
|
Chris@16
|
624
|
Chris@16
|
625 size_t available(socket_type s, boost::system::error_code& ec)
|
Chris@16
|
626 {
|
Chris@16
|
627 if (s == invalid_socket)
|
Chris@16
|
628 {
|
Chris@16
|
629 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
630 return 0;
|
Chris@16
|
631 }
|
Chris@16
|
632
|
Chris@16
|
633 ioctl_arg_type value = 0;
|
Chris@16
|
634 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
635 int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec);
|
Chris@16
|
636 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
637 int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec);
|
Chris@16
|
638 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
639 if (result == 0)
|
Chris@16
|
640 ec = boost::system::error_code();
|
Chris@16
|
641 #if defined(ENOTTY)
|
Chris@16
|
642 if (ec.value() == ENOTTY)
|
Chris@16
|
643 ec = boost::asio::error::not_socket;
|
Chris@16
|
644 #endif // defined(ENOTTY)
|
Chris@16
|
645
|
Chris@16
|
646 return ec ? static_cast<size_t>(0) : static_cast<size_t>(value);
|
Chris@16
|
647 }
|
Chris@16
|
648
|
Chris@16
|
649 int listen(socket_type s, int backlog, boost::system::error_code& ec)
|
Chris@16
|
650 {
|
Chris@16
|
651 if (s == invalid_socket)
|
Chris@16
|
652 {
|
Chris@16
|
653 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
654 return socket_error_retval;
|
Chris@16
|
655 }
|
Chris@16
|
656
|
Chris@16
|
657 clear_last_error();
|
Chris@16
|
658 int result = error_wrapper(::listen(s, backlog), ec);
|
Chris@16
|
659 if (result == 0)
|
Chris@16
|
660 ec = boost::system::error_code();
|
Chris@16
|
661 return result;
|
Chris@16
|
662 }
|
Chris@16
|
663
|
Chris@16
|
664 inline void init_buf_iov_base(void*& base, void* addr)
|
Chris@16
|
665 {
|
Chris@16
|
666 base = addr;
|
Chris@16
|
667 }
|
Chris@16
|
668
|
Chris@16
|
669 template <typename T>
|
Chris@16
|
670 inline void init_buf_iov_base(T& base, void* addr)
|
Chris@16
|
671 {
|
Chris@16
|
672 base = static_cast<T>(addr);
|
Chris@16
|
673 }
|
Chris@16
|
674
|
Chris@16
|
675 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
676 typedef WSABUF buf;
|
Chris@16
|
677 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
678 typedef iovec buf;
|
Chris@16
|
679 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
680
|
Chris@16
|
681 void init_buf(buf& b, void* data, size_t size)
|
Chris@16
|
682 {
|
Chris@16
|
683 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
684 b.buf = static_cast<char*>(data);
|
Chris@16
|
685 b.len = static_cast<u_long>(size);
|
Chris@16
|
686 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
687 init_buf_iov_base(b.iov_base, data);
|
Chris@16
|
688 b.iov_len = size;
|
Chris@16
|
689 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
690 }
|
Chris@16
|
691
|
Chris@16
|
692 void init_buf(buf& b, const void* data, size_t size)
|
Chris@16
|
693 {
|
Chris@16
|
694 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
695 b.buf = static_cast<char*>(const_cast<void*>(data));
|
Chris@16
|
696 b.len = static_cast<u_long>(size);
|
Chris@16
|
697 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
698 init_buf_iov_base(b.iov_base, const_cast<void*>(data));
|
Chris@16
|
699 b.iov_len = size;
|
Chris@16
|
700 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
701 }
|
Chris@16
|
702
|
Chris@16
|
703 inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr)
|
Chris@16
|
704 {
|
Chris@16
|
705 name = addr;
|
Chris@16
|
706 }
|
Chris@16
|
707
|
Chris@16
|
708 inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
|
Chris@16
|
709 {
|
Chris@16
|
710 name = const_cast<socket_addr_type*>(addr);
|
Chris@16
|
711 }
|
Chris@16
|
712
|
Chris@16
|
713 template <typename T>
|
Chris@16
|
714 inline void init_msghdr_msg_name(T& name, socket_addr_type* addr)
|
Chris@16
|
715 {
|
Chris@16
|
716 name = reinterpret_cast<T>(addr);
|
Chris@16
|
717 }
|
Chris@16
|
718
|
Chris@16
|
719 template <typename T>
|
Chris@16
|
720 inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr)
|
Chris@16
|
721 {
|
Chris@16
|
722 name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr));
|
Chris@16
|
723 }
|
Chris@16
|
724
|
Chris@16
|
725 signed_size_type recv(socket_type s, buf* bufs, size_t count,
|
Chris@16
|
726 int flags, boost::system::error_code& ec)
|
Chris@16
|
727 {
|
Chris@16
|
728 clear_last_error();
|
Chris@16
|
729 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
730 // Receive some data.
|
Chris@16
|
731 DWORD recv_buf_count = static_cast<DWORD>(count);
|
Chris@16
|
732 DWORD bytes_transferred = 0;
|
Chris@16
|
733 DWORD recv_flags = flags;
|
Chris@16
|
734 int result = error_wrapper(::WSARecv(s, bufs,
|
Chris@16
|
735 recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec);
|
Chris@16
|
736 if (ec.value() == ERROR_NETNAME_DELETED)
|
Chris@16
|
737 ec = boost::asio::error::connection_reset;
|
Chris@16
|
738 else if (ec.value() == ERROR_PORT_UNREACHABLE)
|
Chris@16
|
739 ec = boost::asio::error::connection_refused;
|
Chris@16
|
740 if (result != 0)
|
Chris@16
|
741 return socket_error_retval;
|
Chris@16
|
742 ec = boost::system::error_code();
|
Chris@16
|
743 return bytes_transferred;
|
Chris@16
|
744 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
745 msghdr msg = msghdr();
|
Chris@16
|
746 msg.msg_iov = bufs;
|
Chris@16
|
747 msg.msg_iovlen = static_cast<int>(count);
|
Chris@16
|
748 signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec);
|
Chris@16
|
749 if (result >= 0)
|
Chris@16
|
750 ec = boost::system::error_code();
|
Chris@16
|
751 return result;
|
Chris@16
|
752 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
753 }
|
Chris@16
|
754
|
Chris@16
|
755 size_t sync_recv(socket_type s, state_type state, buf* bufs,
|
Chris@16
|
756 size_t count, int flags, bool all_empty, boost::system::error_code& ec)
|
Chris@16
|
757 {
|
Chris@16
|
758 if (s == invalid_socket)
|
Chris@16
|
759 {
|
Chris@16
|
760 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
761 return 0;
|
Chris@16
|
762 }
|
Chris@16
|
763
|
Chris@16
|
764 // A request to read 0 bytes on a stream is a no-op.
|
Chris@16
|
765 if (all_empty && (state & stream_oriented))
|
Chris@16
|
766 {
|
Chris@16
|
767 ec = boost::system::error_code();
|
Chris@16
|
768 return 0;
|
Chris@16
|
769 }
|
Chris@16
|
770
|
Chris@16
|
771 // Read some data.
|
Chris@16
|
772 for (;;)
|
Chris@16
|
773 {
|
Chris@16
|
774 // Try to complete the operation without blocking.
|
Chris@16
|
775 signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);
|
Chris@16
|
776
|
Chris@16
|
777 // Check if operation succeeded.
|
Chris@16
|
778 if (bytes > 0)
|
Chris@16
|
779 return bytes;
|
Chris@16
|
780
|
Chris@16
|
781 // Check for EOF.
|
Chris@16
|
782 if ((state & stream_oriented) && bytes == 0)
|
Chris@16
|
783 {
|
Chris@16
|
784 ec = boost::asio::error::eof;
|
Chris@16
|
785 return 0;
|
Chris@16
|
786 }
|
Chris@16
|
787
|
Chris@16
|
788 // Operation failed.
|
Chris@16
|
789 if ((state & user_set_non_blocking)
|
Chris@16
|
790 || (ec != boost::asio::error::would_block
|
Chris@16
|
791 && ec != boost::asio::error::try_again))
|
Chris@16
|
792 return 0;
|
Chris@16
|
793
|
Chris@16
|
794 // Wait for socket to become ready.
|
Chris@16
|
795 if (socket_ops::poll_read(s, 0, ec) < 0)
|
Chris@16
|
796 return 0;
|
Chris@16
|
797 }
|
Chris@16
|
798 }
|
Chris@16
|
799
|
Chris@16
|
800 #if defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
801
|
Chris@16
|
802 void complete_iocp_recv(state_type state,
|
Chris@16
|
803 const weak_cancel_token_type& cancel_token, bool all_empty,
|
Chris@16
|
804 boost::system::error_code& ec, size_t bytes_transferred)
|
Chris@16
|
805 {
|
Chris@16
|
806 // Map non-portable errors to their portable counterparts.
|
Chris@16
|
807 if (ec.value() == ERROR_NETNAME_DELETED)
|
Chris@16
|
808 {
|
Chris@16
|
809 if (cancel_token.expired())
|
Chris@16
|
810 ec = boost::asio::error::operation_aborted;
|
Chris@16
|
811 else
|
Chris@16
|
812 ec = boost::asio::error::connection_reset;
|
Chris@16
|
813 }
|
Chris@16
|
814 else if (ec.value() == ERROR_PORT_UNREACHABLE)
|
Chris@16
|
815 {
|
Chris@16
|
816 ec = boost::asio::error::connection_refused;
|
Chris@16
|
817 }
|
Chris@16
|
818
|
Chris@16
|
819 // Check for connection closed.
|
Chris@16
|
820 else if (!ec && bytes_transferred == 0
|
Chris@16
|
821 && (state & stream_oriented) != 0
|
Chris@16
|
822 && !all_empty)
|
Chris@16
|
823 {
|
Chris@16
|
824 ec = boost::asio::error::eof;
|
Chris@16
|
825 }
|
Chris@16
|
826 }
|
Chris@16
|
827
|
Chris@16
|
828 #else // defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
829
|
Chris@16
|
830 bool non_blocking_recv(socket_type s,
|
Chris@16
|
831 buf* bufs, size_t count, int flags, bool is_stream,
|
Chris@16
|
832 boost::system::error_code& ec, size_t& bytes_transferred)
|
Chris@16
|
833 {
|
Chris@16
|
834 for (;;)
|
Chris@16
|
835 {
|
Chris@16
|
836 // Read some data.
|
Chris@16
|
837 signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);
|
Chris@16
|
838
|
Chris@16
|
839 // Check for end of stream.
|
Chris@16
|
840 if (is_stream && bytes == 0)
|
Chris@16
|
841 {
|
Chris@16
|
842 ec = boost::asio::error::eof;
|
Chris@16
|
843 return true;
|
Chris@16
|
844 }
|
Chris@16
|
845
|
Chris@16
|
846 // Retry operation if interrupted by signal.
|
Chris@16
|
847 if (ec == boost::asio::error::interrupted)
|
Chris@16
|
848 continue;
|
Chris@16
|
849
|
Chris@16
|
850 // Check if we need to run the operation again.
|
Chris@16
|
851 if (ec == boost::asio::error::would_block
|
Chris@16
|
852 || ec == boost::asio::error::try_again)
|
Chris@16
|
853 return false;
|
Chris@16
|
854
|
Chris@16
|
855 // Operation is complete.
|
Chris@16
|
856 if (bytes >= 0)
|
Chris@16
|
857 {
|
Chris@16
|
858 ec = boost::system::error_code();
|
Chris@16
|
859 bytes_transferred = bytes;
|
Chris@16
|
860 }
|
Chris@16
|
861 else
|
Chris@16
|
862 bytes_transferred = 0;
|
Chris@16
|
863
|
Chris@16
|
864 return true;
|
Chris@16
|
865 }
|
Chris@16
|
866 }
|
Chris@16
|
867
|
Chris@16
|
868 #endif // defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
869
|
Chris@16
|
870 signed_size_type recvfrom(socket_type s, buf* bufs, size_t count,
|
Chris@16
|
871 int flags, socket_addr_type* addr, std::size_t* addrlen,
|
Chris@16
|
872 boost::system::error_code& ec)
|
Chris@16
|
873 {
|
Chris@16
|
874 clear_last_error();
|
Chris@16
|
875 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
876 // Receive some data.
|
Chris@16
|
877 DWORD recv_buf_count = static_cast<DWORD>(count);
|
Chris@16
|
878 DWORD bytes_transferred = 0;
|
Chris@16
|
879 DWORD recv_flags = flags;
|
Chris@16
|
880 int tmp_addrlen = (int)*addrlen;
|
Chris@16
|
881 int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count,
|
Chris@16
|
882 &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec);
|
Chris@16
|
883 *addrlen = (std::size_t)tmp_addrlen;
|
Chris@16
|
884 if (ec.value() == ERROR_NETNAME_DELETED)
|
Chris@16
|
885 ec = boost::asio::error::connection_reset;
|
Chris@16
|
886 else if (ec.value() == ERROR_PORT_UNREACHABLE)
|
Chris@16
|
887 ec = boost::asio::error::connection_refused;
|
Chris@16
|
888 if (result != 0)
|
Chris@16
|
889 return socket_error_retval;
|
Chris@16
|
890 ec = boost::system::error_code();
|
Chris@16
|
891 return bytes_transferred;
|
Chris@16
|
892 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
893 msghdr msg = msghdr();
|
Chris@16
|
894 init_msghdr_msg_name(msg.msg_name, addr);
|
Chris@16
|
895 msg.msg_namelen = static_cast<int>(*addrlen);
|
Chris@16
|
896 msg.msg_iov = bufs;
|
Chris@16
|
897 msg.msg_iovlen = static_cast<int>(count);
|
Chris@16
|
898 signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec);
|
Chris@16
|
899 *addrlen = msg.msg_namelen;
|
Chris@16
|
900 if (result >= 0)
|
Chris@16
|
901 ec = boost::system::error_code();
|
Chris@16
|
902 return result;
|
Chris@16
|
903 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
904 }
|
Chris@16
|
905
|
Chris@16
|
906 size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,
|
Chris@16
|
907 size_t count, int flags, socket_addr_type* addr,
|
Chris@16
|
908 std::size_t* addrlen, boost::system::error_code& ec)
|
Chris@16
|
909 {
|
Chris@16
|
910 if (s == invalid_socket)
|
Chris@16
|
911 {
|
Chris@16
|
912 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
913 return 0;
|
Chris@16
|
914 }
|
Chris@16
|
915
|
Chris@16
|
916 // Read some data.
|
Chris@16
|
917 for (;;)
|
Chris@16
|
918 {
|
Chris@16
|
919 // Try to complete the operation without blocking.
|
Chris@16
|
920 signed_size_type bytes = socket_ops::recvfrom(
|
Chris@16
|
921 s, bufs, count, flags, addr, addrlen, ec);
|
Chris@16
|
922
|
Chris@16
|
923 // Check if operation succeeded.
|
Chris@16
|
924 if (bytes >= 0)
|
Chris@16
|
925 return bytes;
|
Chris@16
|
926
|
Chris@16
|
927 // Operation failed.
|
Chris@16
|
928 if ((state & user_set_non_blocking)
|
Chris@16
|
929 || (ec != boost::asio::error::would_block
|
Chris@16
|
930 && ec != boost::asio::error::try_again))
|
Chris@16
|
931 return 0;
|
Chris@16
|
932
|
Chris@16
|
933 // Wait for socket to become ready.
|
Chris@16
|
934 if (socket_ops::poll_read(s, 0, ec) < 0)
|
Chris@16
|
935 return 0;
|
Chris@16
|
936 }
|
Chris@16
|
937 }
|
Chris@16
|
938
|
Chris@16
|
939 #if defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
940
|
Chris@16
|
941 void complete_iocp_recvfrom(
|
Chris@16
|
942 const weak_cancel_token_type& cancel_token,
|
Chris@16
|
943 boost::system::error_code& ec)
|
Chris@16
|
944 {
|
Chris@16
|
945 // Map non-portable errors to their portable counterparts.
|
Chris@16
|
946 if (ec.value() == ERROR_NETNAME_DELETED)
|
Chris@16
|
947 {
|
Chris@16
|
948 if (cancel_token.expired())
|
Chris@16
|
949 ec = boost::asio::error::operation_aborted;
|
Chris@16
|
950 else
|
Chris@16
|
951 ec = boost::asio::error::connection_reset;
|
Chris@16
|
952 }
|
Chris@16
|
953 else if (ec.value() == ERROR_PORT_UNREACHABLE)
|
Chris@16
|
954 {
|
Chris@16
|
955 ec = boost::asio::error::connection_refused;
|
Chris@16
|
956 }
|
Chris@16
|
957 }
|
Chris@16
|
958
|
Chris@16
|
959 #else // defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
960
|
Chris@16
|
961 bool non_blocking_recvfrom(socket_type s,
|
Chris@16
|
962 buf* bufs, size_t count, int flags,
|
Chris@16
|
963 socket_addr_type* addr, std::size_t* addrlen,
|
Chris@16
|
964 boost::system::error_code& ec, size_t& bytes_transferred)
|
Chris@16
|
965 {
|
Chris@16
|
966 for (;;)
|
Chris@16
|
967 {
|
Chris@16
|
968 // Read some data.
|
Chris@16
|
969 signed_size_type bytes = socket_ops::recvfrom(
|
Chris@16
|
970 s, bufs, count, flags, addr, addrlen, ec);
|
Chris@16
|
971
|
Chris@16
|
972 // Retry operation if interrupted by signal.
|
Chris@16
|
973 if (ec == boost::asio::error::interrupted)
|
Chris@16
|
974 continue;
|
Chris@16
|
975
|
Chris@16
|
976 // Check if we need to run the operation again.
|
Chris@16
|
977 if (ec == boost::asio::error::would_block
|
Chris@16
|
978 || ec == boost::asio::error::try_again)
|
Chris@16
|
979 return false;
|
Chris@16
|
980
|
Chris@16
|
981 // Operation is complete.
|
Chris@16
|
982 if (bytes >= 0)
|
Chris@16
|
983 {
|
Chris@16
|
984 ec = boost::system::error_code();
|
Chris@16
|
985 bytes_transferred = bytes;
|
Chris@16
|
986 }
|
Chris@16
|
987 else
|
Chris@16
|
988 bytes_transferred = 0;
|
Chris@16
|
989
|
Chris@16
|
990 return true;
|
Chris@16
|
991 }
|
Chris@16
|
992 }
|
Chris@16
|
993
|
Chris@16
|
994 #endif // defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
995
|
Chris@16
|
996 signed_size_type recvmsg(socket_type s, buf* bufs, size_t count,
|
Chris@16
|
997 int in_flags, int& out_flags, boost::system::error_code& ec)
|
Chris@16
|
998 {
|
Chris@16
|
999 clear_last_error();
|
Chris@16
|
1000 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1001 out_flags = 0;
|
Chris@16
|
1002 return socket_ops::recv(s, bufs, count, in_flags, ec);
|
Chris@16
|
1003 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1004 msghdr msg = msghdr();
|
Chris@16
|
1005 msg.msg_iov = bufs;
|
Chris@16
|
1006 msg.msg_iovlen = static_cast<int>(count);
|
Chris@16
|
1007 signed_size_type result = error_wrapper(::recvmsg(s, &msg, in_flags), ec);
|
Chris@16
|
1008 if (result >= 0)
|
Chris@16
|
1009 {
|
Chris@16
|
1010 ec = boost::system::error_code();
|
Chris@16
|
1011 out_flags = msg.msg_flags;
|
Chris@16
|
1012 }
|
Chris@16
|
1013 else
|
Chris@16
|
1014 out_flags = 0;
|
Chris@16
|
1015 return result;
|
Chris@16
|
1016 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1017 }
|
Chris@16
|
1018
|
Chris@16
|
1019 size_t sync_recvmsg(socket_type s, state_type state,
|
Chris@16
|
1020 buf* bufs, size_t count, int in_flags, int& out_flags,
|
Chris@16
|
1021 boost::system::error_code& ec)
|
Chris@16
|
1022 {
|
Chris@16
|
1023 if (s == invalid_socket)
|
Chris@16
|
1024 {
|
Chris@16
|
1025 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
1026 return 0;
|
Chris@16
|
1027 }
|
Chris@16
|
1028
|
Chris@16
|
1029 // Read some data.
|
Chris@16
|
1030 for (;;)
|
Chris@16
|
1031 {
|
Chris@16
|
1032 // Try to complete the operation without blocking.
|
Chris@16
|
1033 signed_size_type bytes = socket_ops::recvmsg(
|
Chris@16
|
1034 s, bufs, count, in_flags, out_flags, ec);
|
Chris@16
|
1035
|
Chris@16
|
1036 // Check if operation succeeded.
|
Chris@16
|
1037 if (bytes >= 0)
|
Chris@16
|
1038 return bytes;
|
Chris@16
|
1039
|
Chris@16
|
1040 // Operation failed.
|
Chris@16
|
1041 if ((state & user_set_non_blocking)
|
Chris@16
|
1042 || (ec != boost::asio::error::would_block
|
Chris@16
|
1043 && ec != boost::asio::error::try_again))
|
Chris@16
|
1044 return 0;
|
Chris@16
|
1045
|
Chris@16
|
1046 // Wait for socket to become ready.
|
Chris@16
|
1047 if (socket_ops::poll_read(s, 0, ec) < 0)
|
Chris@16
|
1048 return 0;
|
Chris@16
|
1049 }
|
Chris@16
|
1050 }
|
Chris@16
|
1051
|
Chris@16
|
1052 #if defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
1053
|
Chris@16
|
1054 void complete_iocp_recvmsg(
|
Chris@16
|
1055 const weak_cancel_token_type& cancel_token,
|
Chris@16
|
1056 boost::system::error_code& ec)
|
Chris@16
|
1057 {
|
Chris@16
|
1058 // Map non-portable errors to their portable counterparts.
|
Chris@16
|
1059 if (ec.value() == ERROR_NETNAME_DELETED)
|
Chris@16
|
1060 {
|
Chris@16
|
1061 if (cancel_token.expired())
|
Chris@16
|
1062 ec = boost::asio::error::operation_aborted;
|
Chris@16
|
1063 else
|
Chris@16
|
1064 ec = boost::asio::error::connection_reset;
|
Chris@16
|
1065 }
|
Chris@16
|
1066 else if (ec.value() == ERROR_PORT_UNREACHABLE)
|
Chris@16
|
1067 {
|
Chris@16
|
1068 ec = boost::asio::error::connection_refused;
|
Chris@16
|
1069 }
|
Chris@16
|
1070 }
|
Chris@16
|
1071
|
Chris@16
|
1072 #else // defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
1073
|
Chris@16
|
1074 bool non_blocking_recvmsg(socket_type s,
|
Chris@16
|
1075 buf* bufs, size_t count, int in_flags, int& out_flags,
|
Chris@16
|
1076 boost::system::error_code& ec, size_t& bytes_transferred)
|
Chris@16
|
1077 {
|
Chris@16
|
1078 for (;;)
|
Chris@16
|
1079 {
|
Chris@16
|
1080 // Read some data.
|
Chris@16
|
1081 signed_size_type bytes = socket_ops::recvmsg(
|
Chris@16
|
1082 s, bufs, count, in_flags, out_flags, ec);
|
Chris@16
|
1083
|
Chris@16
|
1084 // Retry operation if interrupted by signal.
|
Chris@16
|
1085 if (ec == boost::asio::error::interrupted)
|
Chris@16
|
1086 continue;
|
Chris@16
|
1087
|
Chris@16
|
1088 // Check if we need to run the operation again.
|
Chris@16
|
1089 if (ec == boost::asio::error::would_block
|
Chris@16
|
1090 || ec == boost::asio::error::try_again)
|
Chris@16
|
1091 return false;
|
Chris@16
|
1092
|
Chris@16
|
1093 // Operation is complete.
|
Chris@16
|
1094 if (bytes >= 0)
|
Chris@16
|
1095 {
|
Chris@16
|
1096 ec = boost::system::error_code();
|
Chris@16
|
1097 bytes_transferred = bytes;
|
Chris@16
|
1098 }
|
Chris@16
|
1099 else
|
Chris@16
|
1100 bytes_transferred = 0;
|
Chris@16
|
1101
|
Chris@16
|
1102 return true;
|
Chris@16
|
1103 }
|
Chris@16
|
1104 }
|
Chris@16
|
1105
|
Chris@16
|
1106 #endif // defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
1107
|
Chris@16
|
1108 signed_size_type send(socket_type s, const buf* bufs, size_t count,
|
Chris@16
|
1109 int flags, boost::system::error_code& ec)
|
Chris@16
|
1110 {
|
Chris@16
|
1111 clear_last_error();
|
Chris@16
|
1112 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1113 // Send the data.
|
Chris@16
|
1114 DWORD send_buf_count = static_cast<DWORD>(count);
|
Chris@16
|
1115 DWORD bytes_transferred = 0;
|
Chris@16
|
1116 DWORD send_flags = flags;
|
Chris@16
|
1117 int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs),
|
Chris@16
|
1118 send_buf_count, &bytes_transferred, send_flags, 0, 0), ec);
|
Chris@16
|
1119 if (ec.value() == ERROR_NETNAME_DELETED)
|
Chris@16
|
1120 ec = boost::asio::error::connection_reset;
|
Chris@16
|
1121 else if (ec.value() == ERROR_PORT_UNREACHABLE)
|
Chris@16
|
1122 ec = boost::asio::error::connection_refused;
|
Chris@16
|
1123 if (result != 0)
|
Chris@16
|
1124 return socket_error_retval;
|
Chris@16
|
1125 ec = boost::system::error_code();
|
Chris@16
|
1126 return bytes_transferred;
|
Chris@16
|
1127 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1128 msghdr msg = msghdr();
|
Chris@16
|
1129 msg.msg_iov = const_cast<buf*>(bufs);
|
Chris@16
|
1130 msg.msg_iovlen = static_cast<int>(count);
|
Chris@16
|
1131 #if defined(__linux__)
|
Chris@16
|
1132 flags |= MSG_NOSIGNAL;
|
Chris@16
|
1133 #endif // defined(__linux__)
|
Chris@16
|
1134 signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec);
|
Chris@16
|
1135 if (result >= 0)
|
Chris@16
|
1136 ec = boost::system::error_code();
|
Chris@16
|
1137 return result;
|
Chris@16
|
1138 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1139 }
|
Chris@16
|
1140
|
Chris@16
|
1141 size_t sync_send(socket_type s, state_type state, const buf* bufs,
|
Chris@16
|
1142 size_t count, int flags, bool all_empty, boost::system::error_code& ec)
|
Chris@16
|
1143 {
|
Chris@16
|
1144 if (s == invalid_socket)
|
Chris@16
|
1145 {
|
Chris@16
|
1146 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
1147 return 0;
|
Chris@16
|
1148 }
|
Chris@16
|
1149
|
Chris@16
|
1150 // A request to write 0 bytes to a stream is a no-op.
|
Chris@16
|
1151 if (all_empty && (state & stream_oriented))
|
Chris@16
|
1152 {
|
Chris@16
|
1153 ec = boost::system::error_code();
|
Chris@16
|
1154 return 0;
|
Chris@16
|
1155 }
|
Chris@16
|
1156
|
Chris@16
|
1157 // Read some data.
|
Chris@16
|
1158 for (;;)
|
Chris@16
|
1159 {
|
Chris@16
|
1160 // Try to complete the operation without blocking.
|
Chris@16
|
1161 signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);
|
Chris@16
|
1162
|
Chris@16
|
1163 // Check if operation succeeded.
|
Chris@16
|
1164 if (bytes >= 0)
|
Chris@16
|
1165 return bytes;
|
Chris@16
|
1166
|
Chris@16
|
1167 // Operation failed.
|
Chris@16
|
1168 if ((state & user_set_non_blocking)
|
Chris@16
|
1169 || (ec != boost::asio::error::would_block
|
Chris@16
|
1170 && ec != boost::asio::error::try_again))
|
Chris@16
|
1171 return 0;
|
Chris@16
|
1172
|
Chris@16
|
1173 // Wait for socket to become ready.
|
Chris@16
|
1174 if (socket_ops::poll_write(s, 0, ec) < 0)
|
Chris@16
|
1175 return 0;
|
Chris@16
|
1176 }
|
Chris@16
|
1177 }
|
Chris@16
|
1178
|
Chris@16
|
1179 #if defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
1180
|
Chris@16
|
1181 void complete_iocp_send(
|
Chris@16
|
1182 const weak_cancel_token_type& cancel_token,
|
Chris@16
|
1183 boost::system::error_code& ec)
|
Chris@16
|
1184 {
|
Chris@16
|
1185 // Map non-portable errors to their portable counterparts.
|
Chris@16
|
1186 if (ec.value() == ERROR_NETNAME_DELETED)
|
Chris@16
|
1187 {
|
Chris@16
|
1188 if (cancel_token.expired())
|
Chris@16
|
1189 ec = boost::asio::error::operation_aborted;
|
Chris@16
|
1190 else
|
Chris@16
|
1191 ec = boost::asio::error::connection_reset;
|
Chris@16
|
1192 }
|
Chris@16
|
1193 else if (ec.value() == ERROR_PORT_UNREACHABLE)
|
Chris@16
|
1194 {
|
Chris@16
|
1195 ec = boost::asio::error::connection_refused;
|
Chris@16
|
1196 }
|
Chris@16
|
1197 }
|
Chris@16
|
1198
|
Chris@16
|
1199 #else // defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
1200
|
Chris@16
|
1201 bool non_blocking_send(socket_type s,
|
Chris@16
|
1202 const buf* bufs, size_t count, int flags,
|
Chris@16
|
1203 boost::system::error_code& ec, size_t& bytes_transferred)
|
Chris@16
|
1204 {
|
Chris@16
|
1205 for (;;)
|
Chris@16
|
1206 {
|
Chris@16
|
1207 // Write some data.
|
Chris@16
|
1208 signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);
|
Chris@16
|
1209
|
Chris@16
|
1210 // Retry operation if interrupted by signal.
|
Chris@16
|
1211 if (ec == boost::asio::error::interrupted)
|
Chris@16
|
1212 continue;
|
Chris@16
|
1213
|
Chris@16
|
1214 // Check if we need to run the operation again.
|
Chris@16
|
1215 if (ec == boost::asio::error::would_block
|
Chris@16
|
1216 || ec == boost::asio::error::try_again)
|
Chris@16
|
1217 return false;
|
Chris@16
|
1218
|
Chris@16
|
1219 // Operation is complete.
|
Chris@16
|
1220 if (bytes >= 0)
|
Chris@16
|
1221 {
|
Chris@16
|
1222 ec = boost::system::error_code();
|
Chris@16
|
1223 bytes_transferred = bytes;
|
Chris@16
|
1224 }
|
Chris@16
|
1225 else
|
Chris@16
|
1226 bytes_transferred = 0;
|
Chris@16
|
1227
|
Chris@16
|
1228 return true;
|
Chris@16
|
1229 }
|
Chris@16
|
1230 }
|
Chris@16
|
1231
|
Chris@16
|
1232 #endif // defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
1233
|
Chris@16
|
1234 signed_size_type sendto(socket_type s, const buf* bufs, size_t count,
|
Chris@16
|
1235 int flags, const socket_addr_type* addr, std::size_t addrlen,
|
Chris@16
|
1236 boost::system::error_code& ec)
|
Chris@16
|
1237 {
|
Chris@16
|
1238 clear_last_error();
|
Chris@16
|
1239 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1240 // Send the data.
|
Chris@16
|
1241 DWORD send_buf_count = static_cast<DWORD>(count);
|
Chris@16
|
1242 DWORD bytes_transferred = 0;
|
Chris@16
|
1243 int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs),
|
Chris@16
|
1244 send_buf_count, &bytes_transferred, flags, addr,
|
Chris@16
|
1245 static_cast<int>(addrlen), 0, 0), ec);
|
Chris@16
|
1246 if (ec.value() == ERROR_NETNAME_DELETED)
|
Chris@16
|
1247 ec = boost::asio::error::connection_reset;
|
Chris@16
|
1248 else if (ec.value() == ERROR_PORT_UNREACHABLE)
|
Chris@16
|
1249 ec = boost::asio::error::connection_refused;
|
Chris@16
|
1250 if (result != 0)
|
Chris@16
|
1251 return socket_error_retval;
|
Chris@16
|
1252 ec = boost::system::error_code();
|
Chris@16
|
1253 return bytes_transferred;
|
Chris@16
|
1254 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1255 msghdr msg = msghdr();
|
Chris@16
|
1256 init_msghdr_msg_name(msg.msg_name, addr);
|
Chris@16
|
1257 msg.msg_namelen = static_cast<int>(addrlen);
|
Chris@16
|
1258 msg.msg_iov = const_cast<buf*>(bufs);
|
Chris@16
|
1259 msg.msg_iovlen = static_cast<int>(count);
|
Chris@16
|
1260 #if defined(__linux__)
|
Chris@16
|
1261 flags |= MSG_NOSIGNAL;
|
Chris@16
|
1262 #endif // defined(__linux__)
|
Chris@16
|
1263 signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec);
|
Chris@16
|
1264 if (result >= 0)
|
Chris@16
|
1265 ec = boost::system::error_code();
|
Chris@16
|
1266 return result;
|
Chris@16
|
1267 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1268 }
|
Chris@16
|
1269
|
Chris@16
|
1270 size_t sync_sendto(socket_type s, state_type state, const buf* bufs,
|
Chris@16
|
1271 size_t count, int flags, const socket_addr_type* addr,
|
Chris@16
|
1272 std::size_t addrlen, boost::system::error_code& ec)
|
Chris@16
|
1273 {
|
Chris@16
|
1274 if (s == invalid_socket)
|
Chris@16
|
1275 {
|
Chris@16
|
1276 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
1277 return 0;
|
Chris@16
|
1278 }
|
Chris@16
|
1279
|
Chris@16
|
1280 // Write some data.
|
Chris@16
|
1281 for (;;)
|
Chris@16
|
1282 {
|
Chris@16
|
1283 // Try to complete the operation without blocking.
|
Chris@16
|
1284 signed_size_type bytes = socket_ops::sendto(
|
Chris@16
|
1285 s, bufs, count, flags, addr, addrlen, ec);
|
Chris@16
|
1286
|
Chris@16
|
1287 // Check if operation succeeded.
|
Chris@16
|
1288 if (bytes >= 0)
|
Chris@16
|
1289 return bytes;
|
Chris@16
|
1290
|
Chris@16
|
1291 // Operation failed.
|
Chris@16
|
1292 if ((state & user_set_non_blocking)
|
Chris@16
|
1293 || (ec != boost::asio::error::would_block
|
Chris@16
|
1294 && ec != boost::asio::error::try_again))
|
Chris@16
|
1295 return 0;
|
Chris@16
|
1296
|
Chris@16
|
1297 // Wait for socket to become ready.
|
Chris@16
|
1298 if (socket_ops::poll_write(s, 0, ec) < 0)
|
Chris@16
|
1299 return 0;
|
Chris@16
|
1300 }
|
Chris@16
|
1301 }
|
Chris@16
|
1302
|
Chris@16
|
1303 #if !defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
1304
|
Chris@16
|
1305 bool non_blocking_sendto(socket_type s,
|
Chris@16
|
1306 const buf* bufs, size_t count, int flags,
|
Chris@16
|
1307 const socket_addr_type* addr, std::size_t addrlen,
|
Chris@16
|
1308 boost::system::error_code& ec, size_t& bytes_transferred)
|
Chris@16
|
1309 {
|
Chris@16
|
1310 for (;;)
|
Chris@16
|
1311 {
|
Chris@16
|
1312 // Write some data.
|
Chris@16
|
1313 signed_size_type bytes = socket_ops::sendto(
|
Chris@16
|
1314 s, bufs, count, flags, addr, addrlen, ec);
|
Chris@16
|
1315
|
Chris@16
|
1316 // Retry operation if interrupted by signal.
|
Chris@16
|
1317 if (ec == boost::asio::error::interrupted)
|
Chris@16
|
1318 continue;
|
Chris@16
|
1319
|
Chris@16
|
1320 // Check if we need to run the operation again.
|
Chris@16
|
1321 if (ec == boost::asio::error::would_block
|
Chris@16
|
1322 || ec == boost::asio::error::try_again)
|
Chris@16
|
1323 return false;
|
Chris@16
|
1324
|
Chris@16
|
1325 // Operation is complete.
|
Chris@16
|
1326 if (bytes >= 0)
|
Chris@16
|
1327 {
|
Chris@16
|
1328 ec = boost::system::error_code();
|
Chris@16
|
1329 bytes_transferred = bytes;
|
Chris@16
|
1330 }
|
Chris@16
|
1331 else
|
Chris@16
|
1332 bytes_transferred = 0;
|
Chris@16
|
1333
|
Chris@16
|
1334 return true;
|
Chris@16
|
1335 }
|
Chris@16
|
1336 }
|
Chris@16
|
1337
|
Chris@16
|
1338 #endif // !defined(BOOST_ASIO_HAS_IOCP)
|
Chris@16
|
1339
|
Chris@16
|
1340 socket_type socket(int af, int type, int protocol,
|
Chris@16
|
1341 boost::system::error_code& ec)
|
Chris@16
|
1342 {
|
Chris@16
|
1343 clear_last_error();
|
Chris@16
|
1344 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1345 socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0,
|
Chris@16
|
1346 WSA_FLAG_OVERLAPPED), ec);
|
Chris@16
|
1347 if (s == invalid_socket)
|
Chris@16
|
1348 return s;
|
Chris@16
|
1349
|
Chris@16
|
1350 if (af == BOOST_ASIO_OS_DEF(AF_INET6))
|
Chris@16
|
1351 {
|
Chris@16
|
1352 // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to
|
Chris@16
|
1353 // false. This will only succeed on Windows Vista and later versions of
|
Chris@16
|
1354 // Windows, where a dual-stack IPv4/v6 implementation is available.
|
Chris@16
|
1355 DWORD optval = 0;
|
Chris@16
|
1356 ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
Chris@16
|
1357 reinterpret_cast<const char*>(&optval), sizeof(optval));
|
Chris@16
|
1358 }
|
Chris@16
|
1359
|
Chris@16
|
1360 ec = boost::system::error_code();
|
Chris@16
|
1361
|
Chris@16
|
1362 return s;
|
Chris@16
|
1363 #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
|
Chris@16
|
1364 socket_type s = error_wrapper(::socket(af, type, protocol), ec);
|
Chris@16
|
1365 if (s == invalid_socket)
|
Chris@16
|
1366 return s;
|
Chris@16
|
1367
|
Chris@16
|
1368 int optval = 1;
|
Chris@16
|
1369 int result = error_wrapper(::setsockopt(s,
|
Chris@16
|
1370 SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
|
Chris@16
|
1371 if (result != 0)
|
Chris@16
|
1372 {
|
Chris@16
|
1373 ::close(s);
|
Chris@16
|
1374 return invalid_socket;
|
Chris@16
|
1375 }
|
Chris@16
|
1376
|
Chris@16
|
1377 return s;
|
Chris@16
|
1378 #else
|
Chris@16
|
1379 int s = error_wrapper(::socket(af, type, protocol), ec);
|
Chris@16
|
1380 if (s >= 0)
|
Chris@16
|
1381 ec = boost::system::error_code();
|
Chris@16
|
1382 return s;
|
Chris@16
|
1383 #endif
|
Chris@16
|
1384 }
|
Chris@16
|
1385
|
Chris@16
|
1386 template <typename SockLenType>
|
Chris@16
|
1387 inline int call_setsockopt(SockLenType msghdr::*,
|
Chris@16
|
1388 socket_type s, int level, int optname,
|
Chris@16
|
1389 const void* optval, std::size_t optlen)
|
Chris@16
|
1390 {
|
Chris@16
|
1391 return ::setsockopt(s, level, optname,
|
Chris@16
|
1392 (const char*)optval, (SockLenType)optlen);
|
Chris@16
|
1393 }
|
Chris@16
|
1394
|
Chris@16
|
1395 int setsockopt(socket_type s, state_type& state, int level, int optname,
|
Chris@16
|
1396 const void* optval, std::size_t optlen, boost::system::error_code& ec)
|
Chris@16
|
1397 {
|
Chris@16
|
1398 if (s == invalid_socket)
|
Chris@16
|
1399 {
|
Chris@16
|
1400 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
1401 return socket_error_retval;
|
Chris@16
|
1402 }
|
Chris@16
|
1403
|
Chris@16
|
1404 if (level == custom_socket_option_level && optname == always_fail_option)
|
Chris@16
|
1405 {
|
Chris@16
|
1406 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
1407 return socket_error_retval;
|
Chris@16
|
1408 }
|
Chris@16
|
1409
|
Chris@16
|
1410 if (level == custom_socket_option_level
|
Chris@16
|
1411 && optname == enable_connection_aborted_option)
|
Chris@16
|
1412 {
|
Chris@16
|
1413 if (optlen != sizeof(int))
|
Chris@16
|
1414 {
|
Chris@16
|
1415 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
1416 return socket_error_retval;
|
Chris@16
|
1417 }
|
Chris@16
|
1418
|
Chris@16
|
1419 if (*static_cast<const int*>(optval))
|
Chris@16
|
1420 state |= enable_connection_aborted;
|
Chris@16
|
1421 else
|
Chris@16
|
1422 state &= ~enable_connection_aborted;
|
Chris@16
|
1423 ec = boost::system::error_code();
|
Chris@16
|
1424 return 0;
|
Chris@16
|
1425 }
|
Chris@16
|
1426
|
Chris@16
|
1427 if (level == SOL_SOCKET && optname == SO_LINGER)
|
Chris@16
|
1428 state |= user_set_linger;
|
Chris@16
|
1429
|
Chris@16
|
1430 #if defined(__BORLANDC__)
|
Chris@16
|
1431 // Mysteriously, using the getsockopt and setsockopt functions directly with
|
Chris@16
|
1432 // Borland C++ results in incorrect values being set and read. The bug can be
|
Chris@16
|
1433 // worked around by using function addresses resolved with GetProcAddress.
|
Chris@16
|
1434 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
|
Chris@16
|
1435 {
|
Chris@16
|
1436 typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
|
Chris@16
|
1437 if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
|
Chris@16
|
1438 {
|
Chris@16
|
1439 clear_last_error();
|
Chris@16
|
1440 return error_wrapper(sso(s, level, optname,
|
Chris@16
|
1441 reinterpret_cast<const char*>(optval),
|
Chris@16
|
1442 static_cast<int>(optlen)), ec);
|
Chris@16
|
1443 }
|
Chris@16
|
1444 }
|
Chris@16
|
1445 ec = boost::asio::error::fault;
|
Chris@16
|
1446 return socket_error_retval;
|
Chris@16
|
1447 #else // defined(__BORLANDC__)
|
Chris@16
|
1448 clear_last_error();
|
Chris@16
|
1449 int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen,
|
Chris@16
|
1450 s, level, optname, optval, optlen), ec);
|
Chris@16
|
1451 if (result == 0)
|
Chris@16
|
1452 {
|
Chris@16
|
1453 ec = boost::system::error_code();
|
Chris@16
|
1454
|
Chris@16
|
1455 #if defined(__MACH__) && defined(__APPLE__) \
|
Chris@16
|
1456 || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
Chris@16
|
1457 // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
|
Chris@16
|
1458 // need to also set SO_REUSEPORT on BSD-based platforms.
|
Chris@16
|
1459 if ((state & datagram_oriented)
|
Chris@16
|
1460 && level == SOL_SOCKET && optname == SO_REUSEADDR)
|
Chris@16
|
1461 {
|
Chris@16
|
1462 call_setsockopt(&msghdr::msg_namelen, s,
|
Chris@16
|
1463 SOL_SOCKET, SO_REUSEPORT, optval, optlen);
|
Chris@16
|
1464 }
|
Chris@16
|
1465 #endif
|
Chris@16
|
1466 }
|
Chris@16
|
1467
|
Chris@16
|
1468 return result;
|
Chris@16
|
1469 #endif // defined(__BORLANDC__)
|
Chris@16
|
1470 }
|
Chris@16
|
1471
|
Chris@16
|
1472 template <typename SockLenType>
|
Chris@16
|
1473 inline int call_getsockopt(SockLenType msghdr::*,
|
Chris@16
|
1474 socket_type s, int level, int optname,
|
Chris@16
|
1475 void* optval, std::size_t* optlen)
|
Chris@16
|
1476 {
|
Chris@16
|
1477 SockLenType tmp_optlen = (SockLenType)*optlen;
|
Chris@16
|
1478 int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);
|
Chris@16
|
1479 *optlen = (std::size_t)tmp_optlen;
|
Chris@16
|
1480 return result;
|
Chris@16
|
1481 }
|
Chris@16
|
1482
|
Chris@16
|
1483 int getsockopt(socket_type s, state_type state, int level, int optname,
|
Chris@16
|
1484 void* optval, size_t* optlen, boost::system::error_code& ec)
|
Chris@16
|
1485 {
|
Chris@16
|
1486 if (s == invalid_socket)
|
Chris@16
|
1487 {
|
Chris@16
|
1488 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
1489 return socket_error_retval;
|
Chris@16
|
1490 }
|
Chris@16
|
1491
|
Chris@16
|
1492 if (level == custom_socket_option_level && optname == always_fail_option)
|
Chris@16
|
1493 {
|
Chris@16
|
1494 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
1495 return socket_error_retval;
|
Chris@16
|
1496 }
|
Chris@16
|
1497
|
Chris@16
|
1498 if (level == custom_socket_option_level
|
Chris@16
|
1499 && optname == enable_connection_aborted_option)
|
Chris@16
|
1500 {
|
Chris@16
|
1501 if (*optlen != sizeof(int))
|
Chris@16
|
1502 {
|
Chris@16
|
1503 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
1504 return socket_error_retval;
|
Chris@16
|
1505 }
|
Chris@16
|
1506
|
Chris@16
|
1507 *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0;
|
Chris@16
|
1508 ec = boost::system::error_code();
|
Chris@16
|
1509 return 0;
|
Chris@16
|
1510 }
|
Chris@16
|
1511
|
Chris@16
|
1512 #if defined(__BORLANDC__)
|
Chris@16
|
1513 // Mysteriously, using the getsockopt and setsockopt functions directly with
|
Chris@16
|
1514 // Borland C++ results in incorrect values being set and read. The bug can be
|
Chris@16
|
1515 // worked around by using function addresses resolved with GetProcAddress.
|
Chris@16
|
1516 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
|
Chris@16
|
1517 {
|
Chris@16
|
1518 typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
|
Chris@16
|
1519 if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
|
Chris@16
|
1520 {
|
Chris@16
|
1521 clear_last_error();
|
Chris@16
|
1522 int tmp_optlen = static_cast<int>(*optlen);
|
Chris@16
|
1523 int result = error_wrapper(gso(s, level, optname,
|
Chris@16
|
1524 reinterpret_cast<char*>(optval), &tmp_optlen), ec);
|
Chris@16
|
1525 *optlen = static_cast<size_t>(tmp_optlen);
|
Chris@16
|
1526 if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
|
Chris@16
|
1527 && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
|
Chris@16
|
1528 {
|
Chris@16
|
1529 // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
|
Chris@16
|
1530 // only supported on Windows Vista and later. To simplify program logic
|
Chris@16
|
1531 // we will fake success of getting this option and specify that the
|
Chris@16
|
1532 // value is non-zero (i.e. true). This corresponds to the behavior of
|
Chris@16
|
1533 // IPv6 sockets on Windows platforms pre-Vista.
|
Chris@16
|
1534 *static_cast<DWORD*>(optval) = 1;
|
Chris@16
|
1535 ec = boost::system::error_code();
|
Chris@16
|
1536 }
|
Chris@16
|
1537 return result;
|
Chris@16
|
1538 }
|
Chris@16
|
1539 }
|
Chris@16
|
1540 ec = boost::asio::error::fault;
|
Chris@16
|
1541 return socket_error_retval;
|
Chris@16
|
1542 #elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1543 clear_last_error();
|
Chris@16
|
1544 int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
|
Chris@16
|
1545 s, level, optname, optval, optlen), ec);
|
Chris@16
|
1546 if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
|
Chris@16
|
1547 && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
|
Chris@16
|
1548 {
|
Chris@16
|
1549 // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only
|
Chris@16
|
1550 // supported on Windows Vista and later. To simplify program logic we will
|
Chris@16
|
1551 // fake success of getting this option and specify that the value is
|
Chris@16
|
1552 // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets
|
Chris@16
|
1553 // on Windows platforms pre-Vista.
|
Chris@16
|
1554 *static_cast<DWORD*>(optval) = 1;
|
Chris@16
|
1555 ec = boost::system::error_code();
|
Chris@16
|
1556 }
|
Chris@16
|
1557 if (result == 0)
|
Chris@16
|
1558 ec = boost::system::error_code();
|
Chris@16
|
1559 return result;
|
Chris@16
|
1560 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1561 clear_last_error();
|
Chris@16
|
1562 int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
|
Chris@16
|
1563 s, level, optname, optval, optlen), ec);
|
Chris@16
|
1564 #if defined(__linux__)
|
Chris@16
|
1565 if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
|
Chris@16
|
1566 && (optname == SO_SNDBUF || optname == SO_RCVBUF))
|
Chris@16
|
1567 {
|
Chris@16
|
1568 // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel
|
Chris@16
|
1569 // to set the buffer size to N*2. Linux puts additional stuff into the
|
Chris@16
|
1570 // buffers so that only about half is actually available to the application.
|
Chris@16
|
1571 // The retrieved value is divided by 2 here to make it appear as though the
|
Chris@16
|
1572 // correct value has been set.
|
Chris@16
|
1573 *static_cast<int*>(optval) /= 2;
|
Chris@16
|
1574 }
|
Chris@16
|
1575 #endif // defined(__linux__)
|
Chris@16
|
1576 if (result == 0)
|
Chris@16
|
1577 ec = boost::system::error_code();
|
Chris@16
|
1578 return result;
|
Chris@16
|
1579 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1580 }
|
Chris@16
|
1581
|
Chris@16
|
1582 template <typename SockLenType>
|
Chris@16
|
1583 inline int call_getpeername(SockLenType msghdr::*,
|
Chris@16
|
1584 socket_type s, socket_addr_type* addr, std::size_t* addrlen)
|
Chris@16
|
1585 {
|
Chris@16
|
1586 SockLenType tmp_addrlen = (SockLenType)*addrlen;
|
Chris@16
|
1587 int result = ::getpeername(s, addr, &tmp_addrlen);
|
Chris@16
|
1588 *addrlen = (std::size_t)tmp_addrlen;
|
Chris@16
|
1589 return result;
|
Chris@16
|
1590 }
|
Chris@16
|
1591
|
Chris@16
|
1592 int getpeername(socket_type s, socket_addr_type* addr,
|
Chris@16
|
1593 std::size_t* addrlen, bool cached, boost::system::error_code& ec)
|
Chris@16
|
1594 {
|
Chris@16
|
1595 if (s == invalid_socket)
|
Chris@16
|
1596 {
|
Chris@16
|
1597 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
1598 return socket_error_retval;
|
Chris@16
|
1599 }
|
Chris@16
|
1600
|
Chris@16
|
1601 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1602 if (cached)
|
Chris@16
|
1603 {
|
Chris@16
|
1604 // Check if socket is still connected.
|
Chris@16
|
1605 DWORD connect_time = 0;
|
Chris@16
|
1606 size_t connect_time_len = sizeof(connect_time);
|
Chris@16
|
1607 if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME,
|
Chris@16
|
1608 &connect_time, &connect_time_len, ec) == socket_error_retval)
|
Chris@16
|
1609 {
|
Chris@16
|
1610 return socket_error_retval;
|
Chris@16
|
1611 }
|
Chris@16
|
1612 if (connect_time == 0xFFFFFFFF)
|
Chris@16
|
1613 {
|
Chris@16
|
1614 ec = boost::asio::error::not_connected;
|
Chris@16
|
1615 return socket_error_retval;
|
Chris@16
|
1616 }
|
Chris@16
|
1617
|
Chris@16
|
1618 // The cached value is still valid.
|
Chris@16
|
1619 ec = boost::system::error_code();
|
Chris@16
|
1620 return 0;
|
Chris@16
|
1621 }
|
Chris@16
|
1622 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1623 (void)cached;
|
Chris@16
|
1624 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1625
|
Chris@16
|
1626 clear_last_error();
|
Chris@16
|
1627 int result = error_wrapper(call_getpeername(
|
Chris@16
|
1628 &msghdr::msg_namelen, s, addr, addrlen), ec);
|
Chris@16
|
1629 if (result == 0)
|
Chris@16
|
1630 ec = boost::system::error_code();
|
Chris@16
|
1631 return result;
|
Chris@16
|
1632 }
|
Chris@16
|
1633
|
Chris@16
|
1634 template <typename SockLenType>
|
Chris@16
|
1635 inline int call_getsockname(SockLenType msghdr::*,
|
Chris@16
|
1636 socket_type s, socket_addr_type* addr, std::size_t* addrlen)
|
Chris@16
|
1637 {
|
Chris@16
|
1638 SockLenType tmp_addrlen = (SockLenType)*addrlen;
|
Chris@16
|
1639 int result = ::getsockname(s, addr, &tmp_addrlen);
|
Chris@16
|
1640 *addrlen = (std::size_t)tmp_addrlen;
|
Chris@16
|
1641 return result;
|
Chris@16
|
1642 }
|
Chris@16
|
1643
|
Chris@16
|
1644 int getsockname(socket_type s, socket_addr_type* addr,
|
Chris@16
|
1645 std::size_t* addrlen, boost::system::error_code& ec)
|
Chris@16
|
1646 {
|
Chris@16
|
1647 if (s == invalid_socket)
|
Chris@16
|
1648 {
|
Chris@16
|
1649 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
1650 return socket_error_retval;
|
Chris@16
|
1651 }
|
Chris@16
|
1652
|
Chris@16
|
1653 clear_last_error();
|
Chris@16
|
1654 int result = error_wrapper(call_getsockname(
|
Chris@16
|
1655 &msghdr::msg_namelen, s, addr, addrlen), ec);
|
Chris@16
|
1656 if (result == 0)
|
Chris@16
|
1657 ec = boost::system::error_code();
|
Chris@16
|
1658 return result;
|
Chris@16
|
1659 }
|
Chris@16
|
1660
|
Chris@16
|
1661 int ioctl(socket_type s, state_type& state, int cmd,
|
Chris@16
|
1662 ioctl_arg_type* arg, boost::system::error_code& ec)
|
Chris@16
|
1663 {
|
Chris@16
|
1664 if (s == invalid_socket)
|
Chris@16
|
1665 {
|
Chris@16
|
1666 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
1667 return socket_error_retval;
|
Chris@16
|
1668 }
|
Chris@16
|
1669
|
Chris@16
|
1670 clear_last_error();
|
Chris@16
|
1671 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1672 int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
|
Chris@16
|
1673 #elif defined(__MACH__) && defined(__APPLE__) \
|
Chris@16
|
1674 || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
Chris@16
|
1675 int result = error_wrapper(::ioctl(s,
|
Chris@16
|
1676 static_cast<unsigned int>(cmd), arg), ec);
|
Chris@16
|
1677 #else
|
Chris@16
|
1678 int result = error_wrapper(::ioctl(s, cmd, arg), ec);
|
Chris@16
|
1679 #endif
|
Chris@16
|
1680 if (result >= 0)
|
Chris@16
|
1681 {
|
Chris@16
|
1682 ec = boost::system::error_code();
|
Chris@16
|
1683
|
Chris@16
|
1684 // When updating the non-blocking mode we always perform the ioctl syscall,
|
Chris@16
|
1685 // even if the flags would otherwise indicate that the socket is already in
|
Chris@16
|
1686 // the correct state. This ensures that the underlying socket is put into
|
Chris@16
|
1687 // the state that has been requested by the user. If the ioctl syscall was
|
Chris@16
|
1688 // successful then we need to update the flags to match.
|
Chris@16
|
1689 if (cmd == static_cast<int>(FIONBIO))
|
Chris@16
|
1690 {
|
Chris@16
|
1691 if (*arg)
|
Chris@16
|
1692 {
|
Chris@16
|
1693 state |= user_set_non_blocking;
|
Chris@16
|
1694 }
|
Chris@16
|
1695 else
|
Chris@16
|
1696 {
|
Chris@16
|
1697 // Clearing the non-blocking mode always overrides any internally-set
|
Chris@16
|
1698 // non-blocking flag. Any subsequent asynchronous operations will need
|
Chris@16
|
1699 // to re-enable non-blocking I/O.
|
Chris@16
|
1700 state &= ~(user_set_non_blocking | internal_non_blocking);
|
Chris@16
|
1701 }
|
Chris@16
|
1702 }
|
Chris@16
|
1703 }
|
Chris@16
|
1704
|
Chris@16
|
1705 return result;
|
Chris@16
|
1706 }
|
Chris@16
|
1707
|
Chris@16
|
1708 int select(int nfds, fd_set* readfds, fd_set* writefds,
|
Chris@16
|
1709 fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec)
|
Chris@16
|
1710 {
|
Chris@16
|
1711 clear_last_error();
|
Chris@16
|
1712 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1713 if (!readfds && !writefds && !exceptfds && timeout)
|
Chris@16
|
1714 {
|
Chris@16
|
1715 DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
|
Chris@16
|
1716 if (milliseconds == 0)
|
Chris@16
|
1717 milliseconds = 1; // Force context switch.
|
Chris@16
|
1718 ::Sleep(milliseconds);
|
Chris@16
|
1719 ec = boost::system::error_code();
|
Chris@16
|
1720 return 0;
|
Chris@16
|
1721 }
|
Chris@16
|
1722
|
Chris@16
|
1723 // The select() call allows timeout values measured in microseconds, but the
|
Chris@16
|
1724 // system clock (as wrapped by boost::posix_time::microsec_clock) typically
|
Chris@16
|
1725 // has a resolution of 10 milliseconds. This can lead to a spinning select
|
Chris@16
|
1726 // reactor, meaning increased CPU usage, when waiting for the earliest
|
Chris@16
|
1727 // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight
|
Chris@16
|
1728 // spin we'll use a minimum timeout of 1 millisecond.
|
Chris@16
|
1729 if (timeout && timeout->tv_sec == 0
|
Chris@16
|
1730 && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
|
Chris@16
|
1731 timeout->tv_usec = 1000;
|
Chris@16
|
1732 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1733
|
Chris@16
|
1734 #if defined(__hpux) && defined(__SELECT)
|
Chris@16
|
1735 timespec ts;
|
Chris@16
|
1736 ts.tv_sec = timeout ? timeout->tv_sec : 0;
|
Chris@16
|
1737 ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;
|
Chris@16
|
1738 return error_wrapper(::pselect(nfds, readfds,
|
Chris@16
|
1739 writefds, exceptfds, timeout ? &ts : 0, 0), ec);
|
Chris@16
|
1740 #else
|
Chris@16
|
1741 int result = error_wrapper(::select(nfds, readfds,
|
Chris@16
|
1742 writefds, exceptfds, timeout), ec);
|
Chris@16
|
1743 if (result >= 0)
|
Chris@16
|
1744 ec = boost::system::error_code();
|
Chris@16
|
1745 return result;
|
Chris@16
|
1746 #endif
|
Chris@16
|
1747 }
|
Chris@16
|
1748
|
Chris@16
|
1749 int poll_read(socket_type s, state_type state, boost::system::error_code& ec)
|
Chris@16
|
1750 {
|
Chris@16
|
1751 if (s == invalid_socket)
|
Chris@16
|
1752 {
|
Chris@16
|
1753 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
1754 return socket_error_retval;
|
Chris@16
|
1755 }
|
Chris@16
|
1756
|
Chris@16
|
1757 #if defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
1758 || defined(__CYGWIN__) \
|
Chris@16
|
1759 || defined(__SYMBIAN32__)
|
Chris@16
|
1760 fd_set fds;
|
Chris@16
|
1761 FD_ZERO(&fds);
|
Chris@16
|
1762 FD_SET(s, &fds);
|
Chris@16
|
1763 timeval zero_timeout;
|
Chris@16
|
1764 zero_timeout.tv_sec = 0;
|
Chris@16
|
1765 zero_timeout.tv_usec = 0;
|
Chris@16
|
1766 timeval* timeout = (state & user_set_non_blocking) ? &zero_timeout : 0;
|
Chris@16
|
1767 clear_last_error();
|
Chris@16
|
1768 int result = error_wrapper(::select(s + 1, &fds, 0, 0, timeout), ec);
|
Chris@16
|
1769 #else // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
1770 // || defined(__CYGWIN__)
|
Chris@16
|
1771 // || defined(__SYMBIAN32__)
|
Chris@16
|
1772 pollfd fds;
|
Chris@16
|
1773 fds.fd = s;
|
Chris@16
|
1774 fds.events = POLLIN;
|
Chris@16
|
1775 fds.revents = 0;
|
Chris@16
|
1776 int timeout = (state & user_set_non_blocking) ? 0 : -1;
|
Chris@16
|
1777 clear_last_error();
|
Chris@16
|
1778 int result = error_wrapper(::poll(&fds, 1, timeout), ec);
|
Chris@16
|
1779 #endif // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
1780 // || defined(__CYGWIN__)
|
Chris@16
|
1781 // || defined(__SYMBIAN32__)
|
Chris@16
|
1782 if (result == 0)
|
Chris@16
|
1783 ec = (state & user_set_non_blocking)
|
Chris@16
|
1784 ? boost::asio::error::would_block : boost::system::error_code();
|
Chris@16
|
1785 else if (result > 0)
|
Chris@16
|
1786 ec = boost::system::error_code();
|
Chris@16
|
1787 return result;
|
Chris@16
|
1788 }
|
Chris@16
|
1789
|
Chris@16
|
1790 int poll_write(socket_type s, state_type state, boost::system::error_code& ec)
|
Chris@16
|
1791 {
|
Chris@16
|
1792 if (s == invalid_socket)
|
Chris@16
|
1793 {
|
Chris@16
|
1794 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
1795 return socket_error_retval;
|
Chris@16
|
1796 }
|
Chris@16
|
1797
|
Chris@16
|
1798 #if defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
1799 || defined(__CYGWIN__) \
|
Chris@16
|
1800 || defined(__SYMBIAN32__)
|
Chris@16
|
1801 fd_set fds;
|
Chris@16
|
1802 FD_ZERO(&fds);
|
Chris@16
|
1803 FD_SET(s, &fds);
|
Chris@16
|
1804 timeval zero_timeout;
|
Chris@16
|
1805 zero_timeout.tv_sec = 0;
|
Chris@16
|
1806 zero_timeout.tv_usec = 0;
|
Chris@16
|
1807 timeval* timeout = (state & user_set_non_blocking) ? &zero_timeout : 0;
|
Chris@16
|
1808 clear_last_error();
|
Chris@16
|
1809 int result = error_wrapper(::select(s + 1, 0, &fds, 0, timeout), ec);
|
Chris@16
|
1810 #else // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
1811 // || defined(__CYGWIN__)
|
Chris@16
|
1812 // || defined(__SYMBIAN32__)
|
Chris@16
|
1813 pollfd fds;
|
Chris@16
|
1814 fds.fd = s;
|
Chris@16
|
1815 fds.events = POLLOUT;
|
Chris@16
|
1816 fds.revents = 0;
|
Chris@16
|
1817 int timeout = (state & user_set_non_blocking) ? 0 : -1;
|
Chris@16
|
1818 clear_last_error();
|
Chris@16
|
1819 int result = error_wrapper(::poll(&fds, 1, timeout), ec);
|
Chris@16
|
1820 #endif // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
1821 // || defined(__CYGWIN__)
|
Chris@16
|
1822 // || defined(__SYMBIAN32__)
|
Chris@16
|
1823 if (result == 0)
|
Chris@16
|
1824 ec = (state & user_set_non_blocking)
|
Chris@16
|
1825 ? boost::asio::error::would_block : boost::system::error_code();
|
Chris@16
|
1826 else if (result > 0)
|
Chris@16
|
1827 ec = boost::system::error_code();
|
Chris@16
|
1828 return result;
|
Chris@16
|
1829 }
|
Chris@16
|
1830
|
Chris@16
|
1831 int poll_connect(socket_type s, boost::system::error_code& ec)
|
Chris@16
|
1832 {
|
Chris@16
|
1833 if (s == invalid_socket)
|
Chris@16
|
1834 {
|
Chris@16
|
1835 ec = boost::asio::error::bad_descriptor;
|
Chris@16
|
1836 return socket_error_retval;
|
Chris@16
|
1837 }
|
Chris@16
|
1838
|
Chris@16
|
1839 #if defined(BOOST_ASIO_WINDOWS) \
|
Chris@16
|
1840 || defined(__CYGWIN__) \
|
Chris@16
|
1841 || defined(__SYMBIAN32__)
|
Chris@16
|
1842 fd_set write_fds;
|
Chris@16
|
1843 FD_ZERO(&write_fds);
|
Chris@16
|
1844 FD_SET(s, &write_fds);
|
Chris@16
|
1845 fd_set except_fds;
|
Chris@16
|
1846 FD_ZERO(&except_fds);
|
Chris@16
|
1847 FD_SET(s, &except_fds);
|
Chris@16
|
1848 clear_last_error();
|
Chris@16
|
1849 int result = error_wrapper(::select(
|
Chris@16
|
1850 s + 1, 0, &write_fds, &except_fds, 0), ec);
|
Chris@16
|
1851 if (result >= 0)
|
Chris@16
|
1852 ec = boost::system::error_code();
|
Chris@16
|
1853 return result;
|
Chris@16
|
1854 #else // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
1855 // || defined(__CYGWIN__)
|
Chris@16
|
1856 // || defined(__SYMBIAN32__)
|
Chris@16
|
1857 pollfd fds;
|
Chris@16
|
1858 fds.fd = s;
|
Chris@16
|
1859 fds.events = POLLOUT;
|
Chris@16
|
1860 fds.revents = 0;
|
Chris@16
|
1861 clear_last_error();
|
Chris@16
|
1862 int result = error_wrapper(::poll(&fds, 1, -1), ec);
|
Chris@16
|
1863 if (result >= 0)
|
Chris@16
|
1864 ec = boost::system::error_code();
|
Chris@16
|
1865 return result;
|
Chris@16
|
1866 #endif // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
1867 // || defined(__CYGWIN__)
|
Chris@16
|
1868 // || defined(__SYMBIAN32__)
|
Chris@16
|
1869 }
|
Chris@16
|
1870
|
Chris@16
|
1871 #endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
1872
|
Chris@16
|
1873 const char* inet_ntop(int af, const void* src, char* dest, size_t length,
|
Chris@16
|
1874 unsigned long scope_id, boost::system::error_code& ec)
|
Chris@16
|
1875 {
|
Chris@16
|
1876 clear_last_error();
|
Chris@16
|
1877 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
1878 using namespace std; // For sprintf.
|
Chris@16
|
1879 const unsigned char* bytes = static_cast<const unsigned char*>(src);
|
Chris@16
|
1880 if (af == BOOST_ASIO_OS_DEF(AF_INET))
|
Chris@16
|
1881 {
|
Chris@16
|
1882 sprintf_s(dest, length, "%u.%u.%u.%u",
|
Chris@16
|
1883 bytes[0], bytes[1], bytes[2], bytes[3]);
|
Chris@16
|
1884 return dest;
|
Chris@16
|
1885 }
|
Chris@16
|
1886 else if (af == BOOST_ASIO_OS_DEF(AF_INET6))
|
Chris@16
|
1887 {
|
Chris@16
|
1888 size_t n = 0, b = 0, z = 0;
|
Chris@16
|
1889 while (n < length && b < 16)
|
Chris@16
|
1890 {
|
Chris@16
|
1891 if (bytes[b] == 0 && bytes[b + 1] == 0 && z == 0)
|
Chris@16
|
1892 {
|
Chris@16
|
1893 do b += 2; while (b < 16 && bytes[b] == 0 && bytes[b + 1] == 0);
|
Chris@16
|
1894 n += sprintf_s(dest + n, length - n, ":%s", b < 16 ? "" : ":"), ++z;
|
Chris@16
|
1895 }
|
Chris@16
|
1896 else
|
Chris@16
|
1897 {
|
Chris@16
|
1898 n += sprintf_s(dest + n, length - n, "%s%x", b ? ":" : "",
|
Chris@16
|
1899 (static_cast<u_long_type>(bytes[b]) << 8) | bytes[b + 1]);
|
Chris@16
|
1900 b += 2;
|
Chris@16
|
1901 }
|
Chris@16
|
1902 }
|
Chris@16
|
1903 if (scope_id)
|
Chris@16
|
1904 n += sprintf_s(dest + n, length - n, "%%%lu", scope_id);
|
Chris@16
|
1905 return dest;
|
Chris@16
|
1906 }
|
Chris@16
|
1907 else
|
Chris@16
|
1908 {
|
Chris@16
|
1909 ec = boost::asio::error::address_family_not_supported;
|
Chris@16
|
1910 return 0;
|
Chris@16
|
1911 }
|
Chris@16
|
1912 #elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1913 using namespace std; // For memcpy.
|
Chris@16
|
1914
|
Chris@16
|
1915 if (af != BOOST_ASIO_OS_DEF(AF_INET) && af != BOOST_ASIO_OS_DEF(AF_INET6))
|
Chris@16
|
1916 {
|
Chris@16
|
1917 ec = boost::asio::error::address_family_not_supported;
|
Chris@16
|
1918 return 0;
|
Chris@16
|
1919 }
|
Chris@16
|
1920
|
Chris@16
|
1921 union
|
Chris@16
|
1922 {
|
Chris@16
|
1923 socket_addr_type base;
|
Chris@16
|
1924 sockaddr_storage_type storage;
|
Chris@16
|
1925 sockaddr_in4_type v4;
|
Chris@16
|
1926 sockaddr_in6_type v6;
|
Chris@16
|
1927 } address;
|
Chris@16
|
1928 DWORD address_length;
|
Chris@16
|
1929 if (af == BOOST_ASIO_OS_DEF(AF_INET))
|
Chris@16
|
1930 {
|
Chris@16
|
1931 address_length = sizeof(sockaddr_in4_type);
|
Chris@16
|
1932 address.v4.sin_family = BOOST_ASIO_OS_DEF(AF_INET);
|
Chris@16
|
1933 address.v4.sin_port = 0;
|
Chris@16
|
1934 memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type));
|
Chris@16
|
1935 }
|
Chris@16
|
1936 else // AF_INET6
|
Chris@16
|
1937 {
|
Chris@16
|
1938 address_length = sizeof(sockaddr_in6_type);
|
Chris@16
|
1939 address.v6.sin6_family = BOOST_ASIO_OS_DEF(AF_INET6);
|
Chris@16
|
1940 address.v6.sin6_port = 0;
|
Chris@16
|
1941 address.v6.sin6_flowinfo = 0;
|
Chris@16
|
1942 address.v6.sin6_scope_id = scope_id;
|
Chris@16
|
1943 memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type));
|
Chris@16
|
1944 }
|
Chris@16
|
1945
|
Chris@16
|
1946 DWORD string_length = static_cast<DWORD>(length);
|
Chris@16
|
1947 #if defined(BOOST_NO_ANSI_APIS)
|
Chris@16
|
1948 LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
|
Chris@16
|
1949 int result = error_wrapper(::WSAAddressToStringW(&address.base,
|
Chris@16
|
1950 address_length, 0, string_buffer, &string_length), ec);
|
Chris@16
|
1951 ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0);
|
Chris@16
|
1952 #else
|
Chris@16
|
1953 int result = error_wrapper(::WSAAddressToStringA(
|
Chris@16
|
1954 &address.base, address_length, 0, dest, &string_length), ec);
|
Chris@16
|
1955 #endif
|
Chris@16
|
1956
|
Chris@16
|
1957 // Windows may set error code on success.
|
Chris@16
|
1958 if (result != socket_error_retval)
|
Chris@16
|
1959 ec = boost::system::error_code();
|
Chris@16
|
1960
|
Chris@16
|
1961 // Windows may not set an error code on failure.
|
Chris@16
|
1962 else if (result == socket_error_retval && !ec)
|
Chris@16
|
1963 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
1964
|
Chris@16
|
1965 return result == socket_error_retval ? 0 : dest;
|
Chris@16
|
1966 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1967 const char* result = error_wrapper(::inet_ntop(
|
Chris@16
|
1968 af, src, dest, static_cast<int>(length)), ec);
|
Chris@16
|
1969 if (result == 0 && !ec)
|
Chris@16
|
1970 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
1971 if (result != 0 && af == BOOST_ASIO_OS_DEF(AF_INET6) && scope_id != 0)
|
Chris@16
|
1972 {
|
Chris@16
|
1973 using namespace std; // For strcat and sprintf.
|
Chris@16
|
1974 char if_name[IF_NAMESIZE + 1] = "%";
|
Chris@16
|
1975 const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);
|
Chris@16
|
1976 bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe)
|
Chris@16
|
1977 && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80));
|
Chris@16
|
1978 if (!is_link_local
|
Chris@16
|
1979 || if_indextoname(static_cast<unsigned>(scope_id), if_name + 1) == 0)
|
Chris@16
|
1980 sprintf(if_name + 1, "%lu", scope_id);
|
Chris@16
|
1981 strcat(dest, if_name);
|
Chris@16
|
1982 }
|
Chris@16
|
1983 return result;
|
Chris@16
|
1984 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
1985 }
|
Chris@16
|
1986
|
Chris@16
|
1987 int inet_pton(int af, const char* src, void* dest,
|
Chris@16
|
1988 unsigned long* scope_id, boost::system::error_code& ec)
|
Chris@16
|
1989 {
|
Chris@16
|
1990 clear_last_error();
|
Chris@16
|
1991 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
1992 using namespace std; // For sscanf.
|
Chris@16
|
1993 unsigned char* bytes = static_cast<unsigned char*>(dest);
|
Chris@16
|
1994 if (af == BOOST_ASIO_OS_DEF(AF_INET))
|
Chris@16
|
1995 {
|
Chris@16
|
1996 unsigned int b0, b1, b2, b3;
|
Chris@16
|
1997 if (sscanf_s(src, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) != 4)
|
Chris@16
|
1998 {
|
Chris@16
|
1999 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
2000 return -1;
|
Chris@16
|
2001 }
|
Chris@16
|
2002 if (b0 > 255 || b1 > 255 || b2 > 255 || b3 > 255)
|
Chris@16
|
2003 {
|
Chris@16
|
2004 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
2005 return -1;
|
Chris@16
|
2006 }
|
Chris@16
|
2007 bytes[0] = static_cast<unsigned char>(b0);
|
Chris@16
|
2008 bytes[1] = static_cast<unsigned char>(b1);
|
Chris@16
|
2009 bytes[2] = static_cast<unsigned char>(b2);
|
Chris@16
|
2010 bytes[3] = static_cast<unsigned char>(b3);
|
Chris@16
|
2011 ec = boost::system::error_code();
|
Chris@16
|
2012 return 1;
|
Chris@16
|
2013 }
|
Chris@16
|
2014 else if (af == BOOST_ASIO_OS_DEF(AF_INET6))
|
Chris@16
|
2015 {
|
Chris@16
|
2016 unsigned char* bytes = static_cast<unsigned char*>(dest);
|
Chris@16
|
2017 std::memset(bytes, 0, 16);
|
Chris@16
|
2018 unsigned char back_bytes[16] = { 0 };
|
Chris@16
|
2019 int num_front_bytes = 0, num_back_bytes = 0;
|
Chris@16
|
2020 const char* p = src;
|
Chris@16
|
2021
|
Chris@16
|
2022 enum { fword, fcolon, bword, scope, done } state = fword;
|
Chris@16
|
2023 unsigned long current_word = 0;
|
Chris@16
|
2024 while (state != done)
|
Chris@16
|
2025 {
|
Chris@16
|
2026 if (current_word > 0xFFFF)
|
Chris@16
|
2027 {
|
Chris@16
|
2028 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
2029 return -1;
|
Chris@16
|
2030 }
|
Chris@16
|
2031
|
Chris@16
|
2032 switch (state)
|
Chris@16
|
2033 {
|
Chris@16
|
2034 case fword:
|
Chris@16
|
2035 if (*p >= '0' && *p <= '9')
|
Chris@16
|
2036 current_word = current_word * 16 + *p++ - '0';
|
Chris@16
|
2037 else if (*p >= 'a' && *p <= 'f')
|
Chris@16
|
2038 current_word = current_word * 16 + *p++ - 'a' + 10;
|
Chris@16
|
2039 else if (*p >= 'A' && *p <= 'F')
|
Chris@16
|
2040 current_word = current_word * 16 + *p++ - 'A' + 10;
|
Chris@16
|
2041 else
|
Chris@16
|
2042 {
|
Chris@16
|
2043 if (num_front_bytes == 16)
|
Chris@16
|
2044 {
|
Chris@16
|
2045 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
2046 return -1;
|
Chris@16
|
2047 }
|
Chris@16
|
2048
|
Chris@16
|
2049 bytes[num_front_bytes++] = (current_word >> 8) & 0xFF;
|
Chris@16
|
2050 bytes[num_front_bytes++] = current_word & 0xFF;
|
Chris@16
|
2051 current_word = 0;
|
Chris@16
|
2052
|
Chris@16
|
2053 if (*p == ':')
|
Chris@16
|
2054 state = fcolon, ++p;
|
Chris@16
|
2055 else if (*p == '%')
|
Chris@16
|
2056 state = scope, ++p;
|
Chris@16
|
2057 else if (*p == 0)
|
Chris@16
|
2058 state = done;
|
Chris@16
|
2059 else
|
Chris@16
|
2060 {
|
Chris@16
|
2061 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
2062 return -1;
|
Chris@16
|
2063 }
|
Chris@16
|
2064 }
|
Chris@16
|
2065 break;
|
Chris@16
|
2066
|
Chris@16
|
2067 case fcolon:
|
Chris@16
|
2068 if (*p == ':')
|
Chris@16
|
2069 state = bword, ++p;
|
Chris@16
|
2070 else
|
Chris@16
|
2071 state = fword;
|
Chris@16
|
2072 break;
|
Chris@16
|
2073
|
Chris@16
|
2074 case bword:
|
Chris@16
|
2075 if (*p >= '0' && *p <= '9')
|
Chris@16
|
2076 current_word = current_word * 16 + *p++ - '0';
|
Chris@16
|
2077 else if (*p >= 'a' && *p <= 'f')
|
Chris@16
|
2078 current_word = current_word * 16 + *p++ - 'a' + 10;
|
Chris@16
|
2079 else if (*p >= 'A' && *p <= 'F')
|
Chris@16
|
2080 current_word = current_word * 16 + *p++ - 'A' + 10;
|
Chris@16
|
2081 else
|
Chris@16
|
2082 {
|
Chris@16
|
2083 if (num_front_bytes + num_back_bytes == 16)
|
Chris@16
|
2084 {
|
Chris@16
|
2085 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
2086 return -1;
|
Chris@16
|
2087 }
|
Chris@16
|
2088
|
Chris@16
|
2089 back_bytes[num_back_bytes++] = (current_word >> 8) & 0xFF;
|
Chris@16
|
2090 back_bytes[num_back_bytes++] = current_word & 0xFF;
|
Chris@16
|
2091 current_word = 0;
|
Chris@16
|
2092
|
Chris@16
|
2093 if (*p == ':')
|
Chris@16
|
2094 state = bword, ++p;
|
Chris@16
|
2095 else if (*p == '%')
|
Chris@16
|
2096 state = scope, ++p;
|
Chris@16
|
2097 else if (*p == 0)
|
Chris@16
|
2098 state = done;
|
Chris@16
|
2099 else
|
Chris@16
|
2100 {
|
Chris@16
|
2101 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
2102 return -1;
|
Chris@16
|
2103 }
|
Chris@16
|
2104 }
|
Chris@16
|
2105 break;
|
Chris@16
|
2106
|
Chris@16
|
2107 case scope:
|
Chris@16
|
2108 if (*p >= '0' && *p <= '9')
|
Chris@16
|
2109 current_word = current_word * 10 + *p++ - '0';
|
Chris@16
|
2110 else if (*p == 0)
|
Chris@16
|
2111 *scope_id = current_word, state = done;
|
Chris@16
|
2112 else
|
Chris@16
|
2113 {
|
Chris@16
|
2114 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
2115 return -1;
|
Chris@16
|
2116 }
|
Chris@16
|
2117 break;
|
Chris@16
|
2118
|
Chris@16
|
2119 default:
|
Chris@16
|
2120 break;
|
Chris@16
|
2121 }
|
Chris@16
|
2122 }
|
Chris@16
|
2123
|
Chris@16
|
2124 for (int i = 0; i < num_back_bytes; ++i)
|
Chris@16
|
2125 bytes[16 - num_back_bytes + i] = back_bytes[i];
|
Chris@16
|
2126
|
Chris@16
|
2127 ec = boost::system::error_code();
|
Chris@16
|
2128 return 1;
|
Chris@16
|
2129 }
|
Chris@16
|
2130 else
|
Chris@16
|
2131 {
|
Chris@16
|
2132 ec = boost::asio::error::address_family_not_supported;
|
Chris@16
|
2133 return -1;
|
Chris@16
|
2134 }
|
Chris@16
|
2135 #elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
2136 using namespace std; // For memcpy and strcmp.
|
Chris@16
|
2137
|
Chris@16
|
2138 if (af != BOOST_ASIO_OS_DEF(AF_INET) && af != BOOST_ASIO_OS_DEF(AF_INET6))
|
Chris@16
|
2139 {
|
Chris@16
|
2140 ec = boost::asio::error::address_family_not_supported;
|
Chris@16
|
2141 return -1;
|
Chris@16
|
2142 }
|
Chris@16
|
2143
|
Chris@16
|
2144 union
|
Chris@16
|
2145 {
|
Chris@16
|
2146 socket_addr_type base;
|
Chris@16
|
2147 sockaddr_storage_type storage;
|
Chris@16
|
2148 sockaddr_in4_type v4;
|
Chris@16
|
2149 sockaddr_in6_type v6;
|
Chris@16
|
2150 } address;
|
Chris@16
|
2151 int address_length = sizeof(sockaddr_storage_type);
|
Chris@16
|
2152 #if defined(BOOST_NO_ANSI_APIS)
|
Chris@16
|
2153 int num_wide_chars = strlen(src) + 1;
|
Chris@16
|
2154 LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
|
Chris@16
|
2155 ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
|
Chris@16
|
2156 int result = error_wrapper(::WSAStringToAddressW(
|
Chris@16
|
2157 wide_buffer, af, 0, &address.base, &address_length), ec);
|
Chris@16
|
2158 #else
|
Chris@16
|
2159 int result = error_wrapper(::WSAStringToAddressA(
|
Chris@16
|
2160 const_cast<char*>(src), af, 0, &address.base, &address_length), ec);
|
Chris@16
|
2161 #endif
|
Chris@16
|
2162
|
Chris@16
|
2163 if (af == BOOST_ASIO_OS_DEF(AF_INET))
|
Chris@16
|
2164 {
|
Chris@16
|
2165 if (result != socket_error_retval)
|
Chris@16
|
2166 {
|
Chris@16
|
2167 memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
|
Chris@16
|
2168 ec = boost::system::error_code();
|
Chris@16
|
2169 }
|
Chris@16
|
2170 else if (strcmp(src, "255.255.255.255") == 0)
|
Chris@16
|
2171 {
|
Chris@16
|
2172 static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
|
Chris@16
|
2173 ec = boost::system::error_code();
|
Chris@16
|
2174 }
|
Chris@16
|
2175 }
|
Chris@16
|
2176 else // AF_INET6
|
Chris@16
|
2177 {
|
Chris@16
|
2178 if (result != socket_error_retval)
|
Chris@16
|
2179 {
|
Chris@16
|
2180 memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));
|
Chris@16
|
2181 if (scope_id)
|
Chris@16
|
2182 *scope_id = address.v6.sin6_scope_id;
|
Chris@16
|
2183 ec = boost::system::error_code();
|
Chris@16
|
2184 }
|
Chris@16
|
2185 }
|
Chris@16
|
2186
|
Chris@16
|
2187 // Windows may not set an error code on failure.
|
Chris@16
|
2188 if (result == socket_error_retval && !ec)
|
Chris@16
|
2189 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
2190
|
Chris@16
|
2191 if (result != socket_error_retval)
|
Chris@16
|
2192 ec = boost::system::error_code();
|
Chris@16
|
2193
|
Chris@16
|
2194 return result == socket_error_retval ? -1 : 1;
|
Chris@16
|
2195 #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
2196 int result = error_wrapper(::inet_pton(af, src, dest), ec);
|
Chris@16
|
2197 if (result <= 0 && !ec)
|
Chris@16
|
2198 ec = boost::asio::error::invalid_argument;
|
Chris@16
|
2199 if (result > 0 && af == BOOST_ASIO_OS_DEF(AF_INET6) && scope_id)
|
Chris@16
|
2200 {
|
Chris@16
|
2201 using namespace std; // For strchr and atoi.
|
Chris@16
|
2202 *scope_id = 0;
|
Chris@16
|
2203 if (const char* if_name = strchr(src, '%'))
|
Chris@16
|
2204 {
|
Chris@16
|
2205 in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
|
Chris@16
|
2206 bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe)
|
Chris@16
|
2207 && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80));
|
Chris@16
|
2208 if (is_link_local)
|
Chris@16
|
2209 *scope_id = if_nametoindex(if_name + 1);
|
Chris@16
|
2210 if (*scope_id == 0)
|
Chris@16
|
2211 *scope_id = atoi(if_name + 1);
|
Chris@16
|
2212 }
|
Chris@16
|
2213 }
|
Chris@16
|
2214 return result;
|
Chris@16
|
2215 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
2216 }
|
Chris@16
|
2217
|
Chris@16
|
2218 int gethostname(char* name, int namelen, boost::system::error_code& ec)
|
Chris@16
|
2219 {
|
Chris@16
|
2220 clear_last_error();
|
Chris@16
|
2221 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
2222 try
|
Chris@16
|
2223 {
|
Chris@16
|
2224 using namespace Windows::Foundation::Collections;
|
Chris@16
|
2225 using namespace Windows::Networking;
|
Chris@16
|
2226 using namespace Windows::Networking::Connectivity;
|
Chris@16
|
2227 IVectorView<HostName^>^ hostnames = NetworkInformation::GetHostNames();
|
Chris@16
|
2228 for (unsigned i = 0; i < hostnames->Size; ++i)
|
Chris@16
|
2229 {
|
Chris@16
|
2230 HostName^ hostname = hostnames->GetAt(i);
|
Chris@16
|
2231 if (hostname->Type == HostNameType::DomainName)
|
Chris@16
|
2232 {
|
Chris@16
|
2233 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
Chris@16
|
2234 std::string raw_name = converter.to_bytes(hostname->RawName->Data());
|
Chris@16
|
2235 if (namelen > 0 && raw_name.size() < static_cast<std::size_t>(namelen))
|
Chris@16
|
2236 {
|
Chris@16
|
2237 strcpy_s(name, namelen, raw_name.c_str());
|
Chris@16
|
2238 return 0;
|
Chris@16
|
2239 }
|
Chris@16
|
2240 }
|
Chris@16
|
2241 }
|
Chris@16
|
2242 return -1;
|
Chris@16
|
2243 }
|
Chris@16
|
2244 catch (Platform::Exception^ e)
|
Chris@16
|
2245 {
|
Chris@16
|
2246 ec = boost::system::error_code(e->HResult,
|
Chris@16
|
2247 boost::system::system_category());
|
Chris@16
|
2248 return -1;
|
Chris@16
|
2249 }
|
Chris@16
|
2250 #else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
2251 int result = error_wrapper(::gethostname(name, namelen), ec);
|
Chris@16
|
2252 # if defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
2253 if (result == 0)
|
Chris@16
|
2254 ec = boost::system::error_code();
|
Chris@16
|
2255 # endif // defined(BOOST_ASIO_WINDOWS)
|
Chris@16
|
2256 return result;
|
Chris@16
|
2257 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
2258 }
|
Chris@16
|
2259
|
Chris@16
|
2260 #if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
2261
|
Chris@16
|
2262 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) \
|
Chris@16
|
2263 || defined(__MACH__) && defined(__APPLE__)
|
Chris@16
|
2264
|
Chris@16
|
2265 // The following functions are only needed for emulation of getaddrinfo and
|
Chris@16
|
2266 // getnameinfo.
|
Chris@16
|
2267
|
Chris@16
|
2268 inline boost::system::error_code translate_netdb_error(int error)
|
Chris@16
|
2269 {
|
Chris@16
|
2270 switch (error)
|
Chris@16
|
2271 {
|
Chris@16
|
2272 case 0:
|
Chris@16
|
2273 return boost::system::error_code();
|
Chris@16
|
2274 case HOST_NOT_FOUND:
|
Chris@16
|
2275 return boost::asio::error::host_not_found;
|
Chris@16
|
2276 case TRY_AGAIN:
|
Chris@16
|
2277 return boost::asio::error::host_not_found_try_again;
|
Chris@16
|
2278 case NO_RECOVERY:
|
Chris@16
|
2279 return boost::asio::error::no_recovery;
|
Chris@16
|
2280 case NO_DATA:
|
Chris@16
|
2281 return boost::asio::error::no_data;
|
Chris@16
|
2282 default:
|
Chris@16
|
2283 BOOST_ASIO_ASSERT(false);
|
Chris@16
|
2284 return boost::asio::error::invalid_argument;
|
Chris@16
|
2285 }
|
Chris@16
|
2286 }
|
Chris@16
|
2287
|
Chris@16
|
2288 inline hostent* gethostbyaddr(const char* addr, int length, int af,
|
Chris@16
|
2289 hostent* result, char* buffer, int buflength, boost::system::error_code& ec)
|
Chris@16
|
2290 {
|
Chris@16
|
2291 clear_last_error();
|
Chris@16
|
2292 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
2293 (void)(buffer);
|
Chris@16
|
2294 (void)(buflength);
|
Chris@16
|
2295 hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
|
Chris@16
|
2296 if (!retval)
|
Chris@16
|
2297 return 0;
|
Chris@16
|
2298 ec = boost::system::error_code();
|
Chris@16
|
2299 *result = *retval;
|
Chris@16
|
2300 return retval;
|
Chris@16
|
2301 #elif defined(__sun) || defined(__QNX__)
|
Chris@16
|
2302 int error = 0;
|
Chris@16
|
2303 hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result,
|
Chris@16
|
2304 buffer, buflength, &error), ec);
|
Chris@16
|
2305 if (error)
|
Chris@16
|
2306 ec = translate_netdb_error(error);
|
Chris@16
|
2307 return retval;
|
Chris@16
|
2308 #elif defined(__MACH__) && defined(__APPLE__)
|
Chris@16
|
2309 (void)(buffer);
|
Chris@16
|
2310 (void)(buflength);
|
Chris@16
|
2311 int error = 0;
|
Chris@16
|
2312 hostent* retval = error_wrapper(::getipnodebyaddr(
|
Chris@16
|
2313 addr, length, af, &error), ec);
|
Chris@16
|
2314 if (error)
|
Chris@16
|
2315 ec = translate_netdb_error(error);
|
Chris@16
|
2316 if (!retval)
|
Chris@16
|
2317 return 0;
|
Chris@16
|
2318 *result = *retval;
|
Chris@16
|
2319 return retval;
|
Chris@16
|
2320 #else
|
Chris@16
|
2321 hostent* retval = 0;
|
Chris@16
|
2322 int error = 0;
|
Chris@16
|
2323 error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer,
|
Chris@16
|
2324 buflength, &retval, &error), ec);
|
Chris@16
|
2325 if (error)
|
Chris@16
|
2326 ec = translate_netdb_error(error);
|
Chris@16
|
2327 return retval;
|
Chris@16
|
2328 #endif
|
Chris@16
|
2329 }
|
Chris@16
|
2330
|
Chris@16
|
2331 inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
|
Chris@16
|
2332 char* buffer, int buflength, int ai_flags, boost::system::error_code& ec)
|
Chris@16
|
2333 {
|
Chris@16
|
2334 clear_last_error();
|
Chris@16
|
2335 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
2336 (void)(buffer);
|
Chris@16
|
2337 (void)(buflength);
|
Chris@16
|
2338 (void)(ai_flags);
|
Chris@16
|
2339 if (af != BOOST_ASIO_OS_DEF(AF_INET))
|
Chris@16
|
2340 {
|
Chris@16
|
2341 ec = boost::asio::error::address_family_not_supported;
|
Chris@16
|
2342 return 0;
|
Chris@16
|
2343 }
|
Chris@16
|
2344 hostent* retval = error_wrapper(::gethostbyname(name), ec);
|
Chris@16
|
2345 if (!retval)
|
Chris@16
|
2346 return 0;
|
Chris@16
|
2347 ec = boost::system::error_code();
|
Chris@16
|
2348 *result = *retval;
|
Chris@16
|
2349 return result;
|
Chris@16
|
2350 #elif defined(__sun) || defined(__QNX__)
|
Chris@16
|
2351 (void)(ai_flags);
|
Chris@16
|
2352 if (af != BOOST_ASIO_OS_DEF(AF_INET))
|
Chris@16
|
2353 {
|
Chris@16
|
2354 ec = boost::asio::error::address_family_not_supported;
|
Chris@16
|
2355 return 0;
|
Chris@16
|
2356 }
|
Chris@16
|
2357 int error = 0;
|
Chris@16
|
2358 hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer,
|
Chris@16
|
2359 buflength, &error), ec);
|
Chris@16
|
2360 if (error)
|
Chris@16
|
2361 ec = translate_netdb_error(error);
|
Chris@16
|
2362 return retval;
|
Chris@16
|
2363 #elif defined(__MACH__) && defined(__APPLE__)
|
Chris@16
|
2364 (void)(buffer);
|
Chris@16
|
2365 (void)(buflength);
|
Chris@16
|
2366 int error = 0;
|
Chris@16
|
2367 hostent* retval = error_wrapper(::getipnodebyname(
|
Chris@16
|
2368 name, af, ai_flags, &error), ec);
|
Chris@16
|
2369 if (error)
|
Chris@16
|
2370 ec = translate_netdb_error(error);
|
Chris@16
|
2371 if (!retval)
|
Chris@16
|
2372 return 0;
|
Chris@16
|
2373 *result = *retval;
|
Chris@16
|
2374 return retval;
|
Chris@16
|
2375 #else
|
Chris@16
|
2376 (void)(ai_flags);
|
Chris@16
|
2377 if (af != BOOST_ASIO_OS_DEF(AF_INET))
|
Chris@16
|
2378 {
|
Chris@16
|
2379 ec = boost::asio::error::address_family_not_supported;
|
Chris@16
|
2380 return 0;
|
Chris@16
|
2381 }
|
Chris@16
|
2382 hostent* retval = 0;
|
Chris@16
|
2383 int error = 0;
|
Chris@16
|
2384 error_wrapper(::gethostbyname_r(name, result,
|
Chris@16
|
2385 buffer, buflength, &retval, &error), ec);
|
Chris@16
|
2386 if (error)
|
Chris@16
|
2387 ec = translate_netdb_error(error);
|
Chris@16
|
2388 return retval;
|
Chris@16
|
2389 #endif
|
Chris@16
|
2390 }
|
Chris@16
|
2391
|
Chris@16
|
2392 inline void freehostent(hostent* h)
|
Chris@16
|
2393 {
|
Chris@16
|
2394 #if defined(__MACH__) && defined(__APPLE__)
|
Chris@16
|
2395 if (h)
|
Chris@16
|
2396 ::freehostent(h);
|
Chris@16
|
2397 #else
|
Chris@16
|
2398 (void)(h);
|
Chris@16
|
2399 #endif
|
Chris@16
|
2400 }
|
Chris@16
|
2401
|
Chris@16
|
2402 // Emulation of getaddrinfo based on implementation in:
|
Chris@16
|
2403 // Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998.
|
Chris@16
|
2404
|
Chris@16
|
2405 struct gai_search
|
Chris@16
|
2406 {
|
Chris@16
|
2407 const char* host;
|
Chris@16
|
2408 int family;
|
Chris@16
|
2409 };
|
Chris@16
|
2410
|
Chris@16
|
2411 inline int gai_nsearch(const char* host,
|
Chris@16
|
2412 const addrinfo_type* hints, gai_search (&search)[2])
|
Chris@16
|
2413 {
|
Chris@16
|
2414 int search_count = 0;
|
Chris@16
|
2415 if (host == 0 || host[0] == '\0')
|
Chris@16
|
2416 {
|
Chris@16
|
2417 if (hints->ai_flags & AI_PASSIVE)
|
Chris@16
|
2418 {
|
Chris@16
|
2419 // No host and AI_PASSIVE implies wildcard bind.
|
Chris@16
|
2420 switch (hints->ai_family)
|
Chris@16
|
2421 {
|
Chris@16
|
2422 case BOOST_ASIO_OS_DEF(AF_INET):
|
Chris@16
|
2423 search[search_count].host = "0.0.0.0";
|
Chris@16
|
2424 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
|
Chris@16
|
2425 ++search_count;
|
Chris@16
|
2426 break;
|
Chris@16
|
2427 case BOOST_ASIO_OS_DEF(AF_INET6):
|
Chris@16
|
2428 search[search_count].host = "0::0";
|
Chris@16
|
2429 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
|
Chris@16
|
2430 ++search_count;
|
Chris@16
|
2431 break;
|
Chris@16
|
2432 case BOOST_ASIO_OS_DEF(AF_UNSPEC):
|
Chris@16
|
2433 search[search_count].host = "0::0";
|
Chris@16
|
2434 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
|
Chris@16
|
2435 ++search_count;
|
Chris@16
|
2436 search[search_count].host = "0.0.0.0";
|
Chris@16
|
2437 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
|
Chris@16
|
2438 ++search_count;
|
Chris@16
|
2439 break;
|
Chris@16
|
2440 default:
|
Chris@16
|
2441 break;
|
Chris@16
|
2442 }
|
Chris@16
|
2443 }
|
Chris@16
|
2444 else
|
Chris@16
|
2445 {
|
Chris@16
|
2446 // No host and not AI_PASSIVE means connect to local host.
|
Chris@16
|
2447 switch (hints->ai_family)
|
Chris@16
|
2448 {
|
Chris@16
|
2449 case BOOST_ASIO_OS_DEF(AF_INET):
|
Chris@16
|
2450 search[search_count].host = "localhost";
|
Chris@16
|
2451 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
|
Chris@16
|
2452 ++search_count;
|
Chris@16
|
2453 break;
|
Chris@16
|
2454 case BOOST_ASIO_OS_DEF(AF_INET6):
|
Chris@16
|
2455 search[search_count].host = "localhost";
|
Chris@16
|
2456 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
|
Chris@16
|
2457 ++search_count;
|
Chris@16
|
2458 break;
|
Chris@16
|
2459 case BOOST_ASIO_OS_DEF(AF_UNSPEC):
|
Chris@16
|
2460 search[search_count].host = "localhost";
|
Chris@16
|
2461 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
|
Chris@16
|
2462 ++search_count;
|
Chris@16
|
2463 search[search_count].host = "localhost";
|
Chris@16
|
2464 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
|
Chris@16
|
2465 ++search_count;
|
Chris@16
|
2466 break;
|
Chris@16
|
2467 default:
|
Chris@16
|
2468 break;
|
Chris@16
|
2469 }
|
Chris@16
|
2470 }
|
Chris@16
|
2471 }
|
Chris@16
|
2472 else
|
Chris@16
|
2473 {
|
Chris@16
|
2474 // Host is specified.
|
Chris@16
|
2475 switch (hints->ai_family)
|
Chris@16
|
2476 {
|
Chris@16
|
2477 case BOOST_ASIO_OS_DEF(AF_INET):
|
Chris@16
|
2478 search[search_count].host = host;
|
Chris@16
|
2479 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
|
Chris@16
|
2480 ++search_count;
|
Chris@16
|
2481 break;
|
Chris@16
|
2482 case BOOST_ASIO_OS_DEF(AF_INET6):
|
Chris@16
|
2483 search[search_count].host = host;
|
Chris@16
|
2484 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
|
Chris@16
|
2485 ++search_count;
|
Chris@16
|
2486 break;
|
Chris@16
|
2487 case BOOST_ASIO_OS_DEF(AF_UNSPEC):
|
Chris@16
|
2488 search[search_count].host = host;
|
Chris@16
|
2489 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6);
|
Chris@16
|
2490 ++search_count;
|
Chris@16
|
2491 search[search_count].host = host;
|
Chris@16
|
2492 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET);
|
Chris@16
|
2493 ++search_count;
|
Chris@16
|
2494 break;
|
Chris@16
|
2495 default:
|
Chris@16
|
2496 break;
|
Chris@16
|
2497 }
|
Chris@16
|
2498 }
|
Chris@16
|
2499 return search_count;
|
Chris@16
|
2500 }
|
Chris@16
|
2501
|
Chris@16
|
2502 template <typename T>
|
Chris@16
|
2503 inline T* gai_alloc(std::size_t size = sizeof(T))
|
Chris@16
|
2504 {
|
Chris@16
|
2505 using namespace std;
|
Chris@16
|
2506 T* p = static_cast<T*>(::operator new(size, std::nothrow));
|
Chris@16
|
2507 if (p)
|
Chris@16
|
2508 memset(p, 0, size);
|
Chris@16
|
2509 return p;
|
Chris@16
|
2510 }
|
Chris@16
|
2511
|
Chris@16
|
2512 inline void gai_free(void* p)
|
Chris@16
|
2513 {
|
Chris@16
|
2514 ::operator delete(p);
|
Chris@16
|
2515 }
|
Chris@16
|
2516
|
Chris@16
|
2517 inline void gai_strcpy(char* target, const char* source, std::size_t max_size)
|
Chris@16
|
2518 {
|
Chris@16
|
2519 using namespace std;
|
Chris@16
|
2520 #if defined(BOOST_ASIO_HAS_SECURE_RTL)
|
Chris@16
|
2521 strcpy_s(target, max_size, source);
|
Chris@16
|
2522 #else // defined(BOOST_ASIO_HAS_SECURE_RTL)
|
Chris@16
|
2523 *target = 0;
|
Chris@16
|
2524 strncat(target, source, max_size);
|
Chris@16
|
2525 #endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
|
Chris@16
|
2526 }
|
Chris@16
|
2527
|
Chris@16
|
2528 enum { gai_clone_flag = 1 << 30 };
|
Chris@16
|
2529
|
Chris@16
|
2530 inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,
|
Chris@16
|
2531 const void* addr, int family)
|
Chris@16
|
2532 {
|
Chris@16
|
2533 using namespace std;
|
Chris@16
|
2534
|
Chris@16
|
2535 addrinfo_type* ai = gai_alloc<addrinfo_type>();
|
Chris@16
|
2536 if (ai == 0)
|
Chris@16
|
2537 return EAI_MEMORY;
|
Chris@16
|
2538
|
Chris@16
|
2539 ai->ai_next = 0;
|
Chris@16
|
2540 **next = ai;
|
Chris@16
|
2541 *next = &ai->ai_next;
|
Chris@16
|
2542
|
Chris@16
|
2543 ai->ai_canonname = 0;
|
Chris@16
|
2544 ai->ai_socktype = hints->ai_socktype;
|
Chris@16
|
2545 if (ai->ai_socktype == 0)
|
Chris@16
|
2546 ai->ai_flags |= gai_clone_flag;
|
Chris@16
|
2547 ai->ai_protocol = hints->ai_protocol;
|
Chris@16
|
2548 ai->ai_family = family;
|
Chris@16
|
2549
|
Chris@16
|
2550 switch (ai->ai_family)
|
Chris@16
|
2551 {
|
Chris@16
|
2552 case BOOST_ASIO_OS_DEF(AF_INET):
|
Chris@16
|
2553 {
|
Chris@16
|
2554 sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
|
Chris@16
|
2555 if (sinptr == 0)
|
Chris@16
|
2556 return EAI_MEMORY;
|
Chris@16
|
2557 sinptr->sin_family = BOOST_ASIO_OS_DEF(AF_INET);
|
Chris@16
|
2558 memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));
|
Chris@16
|
2559 ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);
|
Chris@16
|
2560 ai->ai_addrlen = sizeof(sockaddr_in4_type);
|
Chris@16
|
2561 break;
|
Chris@16
|
2562 }
|
Chris@16
|
2563 case BOOST_ASIO_OS_DEF(AF_INET6):
|
Chris@16
|
2564 {
|
Chris@16
|
2565 sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
|
Chris@16
|
2566 if (sin6ptr == 0)
|
Chris@16
|
2567 return EAI_MEMORY;
|
Chris@16
|
2568 sin6ptr->sin6_family = BOOST_ASIO_OS_DEF(AF_INET6);
|
Chris@16
|
2569 memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));
|
Chris@16
|
2570 ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);
|
Chris@16
|
2571 ai->ai_addrlen = sizeof(sockaddr_in6_type);
|
Chris@16
|
2572 break;
|
Chris@16
|
2573 }
|
Chris@16
|
2574 default:
|
Chris@16
|
2575 break;
|
Chris@16
|
2576 }
|
Chris@16
|
2577
|
Chris@16
|
2578 return 0;
|
Chris@16
|
2579 }
|
Chris@16
|
2580
|
Chris@16
|
2581 inline addrinfo_type* gai_clone(addrinfo_type* ai)
|
Chris@16
|
2582 {
|
Chris@16
|
2583 using namespace std;
|
Chris@16
|
2584
|
Chris@16
|
2585 addrinfo_type* new_ai = gai_alloc<addrinfo_type>();
|
Chris@16
|
2586 if (new_ai == 0)
|
Chris@16
|
2587 return new_ai;
|
Chris@16
|
2588
|
Chris@16
|
2589 new_ai->ai_next = ai->ai_next;
|
Chris@16
|
2590 ai->ai_next = new_ai;
|
Chris@16
|
2591
|
Chris@16
|
2592 new_ai->ai_flags = 0;
|
Chris@16
|
2593 new_ai->ai_family = ai->ai_family;
|
Chris@16
|
2594 new_ai->ai_socktype = ai->ai_socktype;
|
Chris@16
|
2595 new_ai->ai_protocol = ai->ai_protocol;
|
Chris@16
|
2596 new_ai->ai_canonname = 0;
|
Chris@16
|
2597 new_ai->ai_addrlen = ai->ai_addrlen;
|
Chris@16
|
2598 new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);
|
Chris@16
|
2599 memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);
|
Chris@16
|
2600
|
Chris@16
|
2601 return new_ai;
|
Chris@16
|
2602 }
|
Chris@16
|
2603
|
Chris@16
|
2604 inline int gai_port(addrinfo_type* aihead, int port, int socktype)
|
Chris@16
|
2605 {
|
Chris@16
|
2606 int num_found = 0;
|
Chris@16
|
2607
|
Chris@16
|
2608 for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)
|
Chris@16
|
2609 {
|
Chris@16
|
2610 if (ai->ai_flags & gai_clone_flag)
|
Chris@16
|
2611 {
|
Chris@16
|
2612 if (ai->ai_socktype != 0)
|
Chris@16
|
2613 {
|
Chris@16
|
2614 ai = gai_clone(ai);
|
Chris@16
|
2615 if (ai == 0)
|
Chris@16
|
2616 return -1;
|
Chris@16
|
2617 // ai now points to newly cloned entry.
|
Chris@16
|
2618 }
|
Chris@16
|
2619 }
|
Chris@16
|
2620 else if (ai->ai_socktype != socktype)
|
Chris@16
|
2621 {
|
Chris@16
|
2622 // Ignore if mismatch on socket type.
|
Chris@16
|
2623 continue;
|
Chris@16
|
2624 }
|
Chris@16
|
2625
|
Chris@16
|
2626 ai->ai_socktype = socktype;
|
Chris@16
|
2627
|
Chris@16
|
2628 switch (ai->ai_family)
|
Chris@16
|
2629 {
|
Chris@16
|
2630 case BOOST_ASIO_OS_DEF(AF_INET):
|
Chris@16
|
2631 {
|
Chris@16
|
2632 sockaddr_in4_type* sinptr =
|
Chris@16
|
2633 reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
|
Chris@16
|
2634 sinptr->sin_port = port;
|
Chris@16
|
2635 ++num_found;
|
Chris@16
|
2636 break;
|
Chris@16
|
2637 }
|
Chris@16
|
2638 case BOOST_ASIO_OS_DEF(AF_INET6):
|
Chris@16
|
2639 {
|
Chris@16
|
2640 sockaddr_in6_type* sin6ptr =
|
Chris@16
|
2641 reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
|
Chris@16
|
2642 sin6ptr->sin6_port = port;
|
Chris@16
|
2643 ++num_found;
|
Chris@16
|
2644 break;
|
Chris@16
|
2645 }
|
Chris@16
|
2646 default:
|
Chris@16
|
2647 break;
|
Chris@16
|
2648 }
|
Chris@16
|
2649 }
|
Chris@16
|
2650
|
Chris@16
|
2651 return num_found;
|
Chris@16
|
2652 }
|
Chris@16
|
2653
|
Chris@16
|
2654 inline int gai_serv(addrinfo_type* aihead,
|
Chris@16
|
2655 const addrinfo_type* hints, const char* serv)
|
Chris@16
|
2656 {
|
Chris@16
|
2657 using namespace std;
|
Chris@16
|
2658
|
Chris@16
|
2659 int num_found = 0;
|
Chris@16
|
2660
|
Chris@16
|
2661 if (
|
Chris@16
|
2662 #if defined(AI_NUMERICSERV)
|
Chris@16
|
2663 (hints->ai_flags & AI_NUMERICSERV) ||
|
Chris@16
|
2664 #endif
|
Chris@16
|
2665 isdigit(static_cast<unsigned char>(serv[0])))
|
Chris@16
|
2666 {
|
Chris@16
|
2667 int port = htons(atoi(serv));
|
Chris@16
|
2668 if (hints->ai_socktype)
|
Chris@16
|
2669 {
|
Chris@16
|
2670 // Caller specifies socket type.
|
Chris@16
|
2671 int rc = gai_port(aihead, port, hints->ai_socktype);
|
Chris@16
|
2672 if (rc < 0)
|
Chris@16
|
2673 return EAI_MEMORY;
|
Chris@16
|
2674 num_found += rc;
|
Chris@16
|
2675 }
|
Chris@16
|
2676 else
|
Chris@16
|
2677 {
|
Chris@16
|
2678 // Caller does not specify socket type.
|
Chris@16
|
2679 int rc = gai_port(aihead, port, SOCK_STREAM);
|
Chris@16
|
2680 if (rc < 0)
|
Chris@16
|
2681 return EAI_MEMORY;
|
Chris@16
|
2682 num_found += rc;
|
Chris@16
|
2683 rc = gai_port(aihead, port, SOCK_DGRAM);
|
Chris@16
|
2684 if (rc < 0)
|
Chris@16
|
2685 return EAI_MEMORY;
|
Chris@16
|
2686 num_found += rc;
|
Chris@16
|
2687 }
|
Chris@16
|
2688 }
|
Chris@16
|
2689 else
|
Chris@16
|
2690 {
|
Chris@16
|
2691 // Try service name with TCP first, then UDP.
|
Chris@16
|
2692 if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM)
|
Chris@16
|
2693 {
|
Chris@16
|
2694 servent* sptr = getservbyname(serv, "tcp");
|
Chris@16
|
2695 if (sptr != 0)
|
Chris@16
|
2696 {
|
Chris@16
|
2697 int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM);
|
Chris@16
|
2698 if (rc < 0)
|
Chris@16
|
2699 return EAI_MEMORY;
|
Chris@16
|
2700 num_found += rc;
|
Chris@16
|
2701 }
|
Chris@16
|
2702 }
|
Chris@16
|
2703 if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM)
|
Chris@16
|
2704 {
|
Chris@16
|
2705 servent* sptr = getservbyname(serv, "udp");
|
Chris@16
|
2706 if (sptr != 0)
|
Chris@16
|
2707 {
|
Chris@16
|
2708 int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM);
|
Chris@16
|
2709 if (rc < 0)
|
Chris@16
|
2710 return EAI_MEMORY;
|
Chris@16
|
2711 num_found += rc;
|
Chris@16
|
2712 }
|
Chris@16
|
2713 }
|
Chris@16
|
2714 }
|
Chris@16
|
2715
|
Chris@16
|
2716 if (num_found == 0)
|
Chris@16
|
2717 {
|
Chris@16
|
2718 if (hints->ai_socktype == 0)
|
Chris@16
|
2719 {
|
Chris@16
|
2720 // All calls to getservbyname() failed.
|
Chris@16
|
2721 return EAI_NONAME;
|
Chris@16
|
2722 }
|
Chris@16
|
2723 else
|
Chris@16
|
2724 {
|
Chris@16
|
2725 // Service not supported for socket type.
|
Chris@16
|
2726 return EAI_SERVICE;
|
Chris@16
|
2727 }
|
Chris@16
|
2728 }
|
Chris@16
|
2729
|
Chris@16
|
2730 return 0;
|
Chris@16
|
2731 }
|
Chris@16
|
2732
|
Chris@16
|
2733 inline int gai_echeck(const char* host, const char* service,
|
Chris@16
|
2734 int flags, int family, int socktype, int protocol)
|
Chris@16
|
2735 {
|
Chris@16
|
2736 (void)(flags);
|
Chris@16
|
2737 (void)(protocol);
|
Chris@16
|
2738
|
Chris@16
|
2739 // Host or service must be specified.
|
Chris@16
|
2740 if (host == 0 || host[0] == '\0')
|
Chris@16
|
2741 if (service == 0 || service[0] == '\0')
|
Chris@16
|
2742 return EAI_NONAME;
|
Chris@16
|
2743
|
Chris@16
|
2744 // Check combination of family and socket type.
|
Chris@16
|
2745 switch (family)
|
Chris@16
|
2746 {
|
Chris@16
|
2747 case BOOST_ASIO_OS_DEF(AF_UNSPEC):
|
Chris@16
|
2748 break;
|
Chris@16
|
2749 case BOOST_ASIO_OS_DEF(AF_INET):
|
Chris@16
|
2750 case BOOST_ASIO_OS_DEF(AF_INET6):
|
Chris@16
|
2751 if (service != 0 && service[0] != '\0')
|
Chris@16
|
2752 if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
|
Chris@16
|
2753 return EAI_SOCKTYPE;
|
Chris@16
|
2754 break;
|
Chris@16
|
2755 default:
|
Chris@16
|
2756 return EAI_FAMILY;
|
Chris@16
|
2757 }
|
Chris@16
|
2758
|
Chris@16
|
2759 return 0;
|
Chris@16
|
2760 }
|
Chris@16
|
2761
|
Chris@16
|
2762 inline void freeaddrinfo_emulation(addrinfo_type* aihead)
|
Chris@16
|
2763 {
|
Chris@16
|
2764 addrinfo_type* ai = aihead;
|
Chris@16
|
2765 while (ai)
|
Chris@16
|
2766 {
|
Chris@16
|
2767 gai_free(ai->ai_addr);
|
Chris@16
|
2768 gai_free(ai->ai_canonname);
|
Chris@16
|
2769 addrinfo_type* ainext = ai->ai_next;
|
Chris@16
|
2770 gai_free(ai);
|
Chris@16
|
2771 ai = ainext;
|
Chris@16
|
2772 }
|
Chris@16
|
2773 }
|
Chris@16
|
2774
|
Chris@16
|
2775 inline int getaddrinfo_emulation(const char* host, const char* service,
|
Chris@16
|
2776 const addrinfo_type* hintsp, addrinfo_type** result)
|
Chris@16
|
2777 {
|
Chris@16
|
2778 // Set up linked list of addrinfo structures.
|
Chris@16
|
2779 addrinfo_type* aihead = 0;
|
Chris@16
|
2780 addrinfo_type** ainext = &aihead;
|
Chris@16
|
2781 char* canon = 0;
|
Chris@16
|
2782
|
Chris@16
|
2783 // Supply default hints if not specified by caller.
|
Chris@16
|
2784 addrinfo_type hints = addrinfo_type();
|
Chris@16
|
2785 hints.ai_family = BOOST_ASIO_OS_DEF(AF_UNSPEC);
|
Chris@16
|
2786 if (hintsp)
|
Chris@16
|
2787 hints = *hintsp;
|
Chris@16
|
2788
|
Chris@16
|
2789 // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED
|
Chris@16
|
2790 // and AI_ALL flags.
|
Chris@16
|
2791 #if defined(AI_V4MAPPED)
|
Chris@16
|
2792 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6))
|
Chris@16
|
2793 hints.ai_flags &= ~AI_V4MAPPED;
|
Chris@16
|
2794 #endif
|
Chris@16
|
2795 #if defined(AI_ALL)
|
Chris@16
|
2796 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6))
|
Chris@16
|
2797 hints.ai_flags &= ~AI_ALL;
|
Chris@16
|
2798 #endif
|
Chris@16
|
2799
|
Chris@16
|
2800 // Basic error checking.
|
Chris@16
|
2801 int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
|
Chris@16
|
2802 hints.ai_socktype, hints.ai_protocol);
|
Chris@16
|
2803 if (rc != 0)
|
Chris@16
|
2804 {
|
Chris@16
|
2805 freeaddrinfo_emulation(aihead);
|
Chris@16
|
2806 return rc;
|
Chris@16
|
2807 }
|
Chris@16
|
2808
|
Chris@16
|
2809 gai_search search[2];
|
Chris@16
|
2810 int search_count = gai_nsearch(host, &hints, search);
|
Chris@16
|
2811 for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
|
Chris@16
|
2812 {
|
Chris@16
|
2813 // Check for IPv4 dotted decimal string.
|
Chris@16
|
2814 in4_addr_type inaddr;
|
Chris@16
|
2815 boost::system::error_code ec;
|
Chris@16
|
2816 if (socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET),
|
Chris@16
|
2817 sptr->host, &inaddr, 0, ec) == 1)
|
Chris@16
|
2818 {
|
Chris@16
|
2819 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC)
|
Chris@16
|
2820 && hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET))
|
Chris@16
|
2821 {
|
Chris@16
|
2822 freeaddrinfo_emulation(aihead);
|
Chris@16
|
2823 gai_free(canon);
|
Chris@16
|
2824 return EAI_FAMILY;
|
Chris@16
|
2825 }
|
Chris@16
|
2826 if (sptr->family == BOOST_ASIO_OS_DEF(AF_INET))
|
Chris@16
|
2827 {
|
Chris@16
|
2828 rc = gai_aistruct(&ainext, &hints, &inaddr, BOOST_ASIO_OS_DEF(AF_INET));
|
Chris@16
|
2829 if (rc != 0)
|
Chris@16
|
2830 {
|
Chris@16
|
2831 freeaddrinfo_emulation(aihead);
|
Chris@16
|
2832 gai_free(canon);
|
Chris@16
|
2833 return rc;
|
Chris@16
|
2834 }
|
Chris@16
|
2835 }
|
Chris@16
|
2836 continue;
|
Chris@16
|
2837 }
|
Chris@16
|
2838
|
Chris@16
|
2839 // Check for IPv6 hex string.
|
Chris@16
|
2840 in6_addr_type in6addr;
|
Chris@16
|
2841 if (socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET6),
|
Chris@16
|
2842 sptr->host, &in6addr, 0, ec) == 1)
|
Chris@16
|
2843 {
|
Chris@16
|
2844 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC)
|
Chris@16
|
2845 && hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6))
|
Chris@16
|
2846 {
|
Chris@16
|
2847 freeaddrinfo_emulation(aihead);
|
Chris@16
|
2848 gai_free(canon);
|
Chris@16
|
2849 return EAI_FAMILY;
|
Chris@16
|
2850 }
|
Chris@16
|
2851 if (sptr->family == BOOST_ASIO_OS_DEF(AF_INET6))
|
Chris@16
|
2852 {
|
Chris@16
|
2853 rc = gai_aistruct(&ainext, &hints, &in6addr,
|
Chris@16
|
2854 BOOST_ASIO_OS_DEF(AF_INET6));
|
Chris@16
|
2855 if (rc != 0)
|
Chris@16
|
2856 {
|
Chris@16
|
2857 freeaddrinfo_emulation(aihead);
|
Chris@16
|
2858 gai_free(canon);
|
Chris@16
|
2859 return rc;
|
Chris@16
|
2860 }
|
Chris@16
|
2861 }
|
Chris@16
|
2862 continue;
|
Chris@16
|
2863 }
|
Chris@16
|
2864
|
Chris@16
|
2865 // Look up hostname.
|
Chris@16
|
2866 hostent hent;
|
Chris@16
|
2867 char hbuf[8192] = "";
|
Chris@16
|
2868 hostent* hptr = socket_ops::gethostbyname(sptr->host,
|
Chris@16
|
2869 sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
|
Chris@16
|
2870 if (hptr == 0)
|
Chris@16
|
2871 {
|
Chris@16
|
2872 if (search_count == 2)
|
Chris@16
|
2873 {
|
Chris@16
|
2874 // Failure is OK if there are multiple searches.
|
Chris@16
|
2875 continue;
|
Chris@16
|
2876 }
|
Chris@16
|
2877 freeaddrinfo_emulation(aihead);
|
Chris@16
|
2878 gai_free(canon);
|
Chris@16
|
2879 if (ec == boost::asio::error::host_not_found)
|
Chris@16
|
2880 return EAI_NONAME;
|
Chris@16
|
2881 if (ec == boost::asio::error::host_not_found_try_again)
|
Chris@16
|
2882 return EAI_AGAIN;
|
Chris@16
|
2883 if (ec == boost::asio::error::no_recovery)
|
Chris@16
|
2884 return EAI_FAIL;
|
Chris@16
|
2885 if (ec == boost::asio::error::no_data)
|
Chris@16
|
2886 return EAI_NONAME;
|
Chris@16
|
2887 return EAI_NONAME;
|
Chris@16
|
2888 }
|
Chris@16
|
2889
|
Chris@16
|
2890 // Check for address family mismatch if one was specified.
|
Chris@16
|
2891 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC)
|
Chris@16
|
2892 && hints.ai_family != hptr->h_addrtype)
|
Chris@16
|
2893 {
|
Chris@16
|
2894 freeaddrinfo_emulation(aihead);
|
Chris@16
|
2895 gai_free(canon);
|
Chris@16
|
2896 socket_ops::freehostent(hptr);
|
Chris@16
|
2897 return EAI_FAMILY;
|
Chris@16
|
2898 }
|
Chris@16
|
2899
|
Chris@16
|
2900 // Save canonical name first time.
|
Chris@16
|
2901 if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
|
Chris@16
|
2902 && (hints.ai_flags & AI_CANONNAME) && canon == 0)
|
Chris@16
|
2903 {
|
Chris@16
|
2904 std::size_t canon_len = strlen(hptr->h_name) + 1;
|
Chris@16
|
2905 canon = gai_alloc<char>(canon_len);
|
Chris@16
|
2906 if (canon == 0)
|
Chris@16
|
2907 {
|
Chris@16
|
2908 freeaddrinfo_emulation(aihead);
|
Chris@16
|
2909 socket_ops::freehostent(hptr);
|
Chris@16
|
2910 return EAI_MEMORY;
|
Chris@16
|
2911 }
|
Chris@16
|
2912 gai_strcpy(canon, hptr->h_name, canon_len);
|
Chris@16
|
2913 }
|
Chris@16
|
2914
|
Chris@16
|
2915 // Create an addrinfo structure for each returned address.
|
Chris@16
|
2916 for (char** ap = hptr->h_addr_list; *ap; ++ap)
|
Chris@16
|
2917 {
|
Chris@16
|
2918 rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
|
Chris@16
|
2919 if (rc != 0)
|
Chris@16
|
2920 {
|
Chris@16
|
2921 freeaddrinfo_emulation(aihead);
|
Chris@16
|
2922 gai_free(canon);
|
Chris@16
|
2923 socket_ops::freehostent(hptr);
|
Chris@16
|
2924 return EAI_FAMILY;
|
Chris@16
|
2925 }
|
Chris@16
|
2926 }
|
Chris@16
|
2927
|
Chris@16
|
2928 socket_ops::freehostent(hptr);
|
Chris@16
|
2929 }
|
Chris@16
|
2930
|
Chris@16
|
2931 // Check if we found anything.
|
Chris@16
|
2932 if (aihead == 0)
|
Chris@16
|
2933 {
|
Chris@16
|
2934 gai_free(canon);
|
Chris@16
|
2935 return EAI_NONAME;
|
Chris@16
|
2936 }
|
Chris@16
|
2937
|
Chris@16
|
2938 // Return canonical name in first entry.
|
Chris@16
|
2939 if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))
|
Chris@16
|
2940 {
|
Chris@16
|
2941 if (canon)
|
Chris@16
|
2942 {
|
Chris@16
|
2943 aihead->ai_canonname = canon;
|
Chris@16
|
2944 canon = 0;
|
Chris@16
|
2945 }
|
Chris@16
|
2946 else
|
Chris@16
|
2947 {
|
Chris@16
|
2948 std::size_t canonname_len = strlen(search[0].host) + 1;
|
Chris@16
|
2949 aihead->ai_canonname = gai_alloc<char>(canonname_len);
|
Chris@16
|
2950 if (aihead->ai_canonname == 0)
|
Chris@16
|
2951 {
|
Chris@16
|
2952 freeaddrinfo_emulation(aihead);
|
Chris@16
|
2953 return EAI_MEMORY;
|
Chris@16
|
2954 }
|
Chris@16
|
2955 gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);
|
Chris@16
|
2956 }
|
Chris@16
|
2957 }
|
Chris@16
|
2958 gai_free(canon);
|
Chris@16
|
2959
|
Chris@16
|
2960 // Process the service name.
|
Chris@16
|
2961 if (service != 0 && service[0] != '\0')
|
Chris@16
|
2962 {
|
Chris@16
|
2963 rc = gai_serv(aihead, &hints, service);
|
Chris@16
|
2964 if (rc != 0)
|
Chris@16
|
2965 {
|
Chris@16
|
2966 freeaddrinfo_emulation(aihead);
|
Chris@16
|
2967 return rc;
|
Chris@16
|
2968 }
|
Chris@16
|
2969 }
|
Chris@16
|
2970
|
Chris@16
|
2971 // Return result to caller.
|
Chris@16
|
2972 *result = aihead;
|
Chris@16
|
2973 return 0;
|
Chris@16
|
2974 }
|
Chris@16
|
2975
|
Chris@16
|
2976 inline boost::system::error_code getnameinfo_emulation(
|
Chris@16
|
2977 const socket_addr_type* sa, std::size_t salen, char* host,
|
Chris@16
|
2978 std::size_t hostlen, char* serv, std::size_t servlen, int flags,
|
Chris@16
|
2979 boost::system::error_code& ec)
|
Chris@16
|
2980 {
|
Chris@16
|
2981 using namespace std;
|
Chris@16
|
2982
|
Chris@16
|
2983 const char* addr;
|
Chris@16
|
2984 size_t addr_len;
|
Chris@16
|
2985 unsigned short port;
|
Chris@16
|
2986 switch (sa->sa_family)
|
Chris@16
|
2987 {
|
Chris@16
|
2988 case BOOST_ASIO_OS_DEF(AF_INET):
|
Chris@16
|
2989 if (salen != sizeof(sockaddr_in4_type))
|
Chris@16
|
2990 {
|
Chris@16
|
2991 return ec = boost::asio::error::invalid_argument;
|
Chris@16
|
2992 }
|
Chris@16
|
2993 addr = reinterpret_cast<const char*>(
|
Chris@16
|
2994 &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);
|
Chris@16
|
2995 addr_len = sizeof(in4_addr_type);
|
Chris@16
|
2996 port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;
|
Chris@16
|
2997 break;
|
Chris@16
|
2998 case BOOST_ASIO_OS_DEF(AF_INET6):
|
Chris@16
|
2999 if (salen != sizeof(sockaddr_in6_type))
|
Chris@16
|
3000 {
|
Chris@16
|
3001 return ec = boost::asio::error::invalid_argument;
|
Chris@16
|
3002 }
|
Chris@16
|
3003 addr = reinterpret_cast<const char*>(
|
Chris@16
|
3004 &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);
|
Chris@16
|
3005 addr_len = sizeof(in6_addr_type);
|
Chris@16
|
3006 port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;
|
Chris@16
|
3007 break;
|
Chris@16
|
3008 default:
|
Chris@16
|
3009 return ec = boost::asio::error::address_family_not_supported;
|
Chris@16
|
3010 }
|
Chris@16
|
3011
|
Chris@16
|
3012 if (host && hostlen > 0)
|
Chris@16
|
3013 {
|
Chris@16
|
3014 if (flags & NI_NUMERICHOST)
|
Chris@16
|
3015 {
|
Chris@16
|
3016 if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)
|
Chris@16
|
3017 {
|
Chris@16
|
3018 return ec;
|
Chris@16
|
3019 }
|
Chris@16
|
3020 }
|
Chris@16
|
3021 else
|
Chris@16
|
3022 {
|
Chris@16
|
3023 hostent hent;
|
Chris@16
|
3024 char hbuf[8192] = "";
|
Chris@16
|
3025 hostent* hptr = socket_ops::gethostbyaddr(addr,
|
Chris@16
|
3026 static_cast<int>(addr_len), sa->sa_family,
|
Chris@16
|
3027 &hent, hbuf, sizeof(hbuf), ec);
|
Chris@16
|
3028 if (hptr && hptr->h_name && hptr->h_name[0] != '\0')
|
Chris@16
|
3029 {
|
Chris@16
|
3030 if (flags & NI_NOFQDN)
|
Chris@16
|
3031 {
|
Chris@16
|
3032 char* dot = strchr(hptr->h_name, '.');
|
Chris@16
|
3033 if (dot)
|
Chris@16
|
3034 {
|
Chris@16
|
3035 *dot = 0;
|
Chris@16
|
3036 }
|
Chris@16
|
3037 }
|
Chris@16
|
3038 gai_strcpy(host, hptr->h_name, hostlen);
|
Chris@16
|
3039 socket_ops::freehostent(hptr);
|
Chris@16
|
3040 }
|
Chris@16
|
3041 else
|
Chris@16
|
3042 {
|
Chris@16
|
3043 socket_ops::freehostent(hptr);
|
Chris@16
|
3044 if (flags & NI_NAMEREQD)
|
Chris@16
|
3045 {
|
Chris@16
|
3046 return ec = boost::asio::error::host_not_found;
|
Chris@16
|
3047 }
|
Chris@16
|
3048 if (socket_ops::inet_ntop(sa->sa_family,
|
Chris@16
|
3049 addr, host, hostlen, 0, ec) == 0)
|
Chris@16
|
3050 {
|
Chris@16
|
3051 return ec;
|
Chris@16
|
3052 }
|
Chris@16
|
3053 }
|
Chris@16
|
3054 }
|
Chris@16
|
3055 }
|
Chris@16
|
3056
|
Chris@16
|
3057 if (serv && servlen > 0)
|
Chris@16
|
3058 {
|
Chris@16
|
3059 if (flags & NI_NUMERICSERV)
|
Chris@16
|
3060 {
|
Chris@16
|
3061 if (servlen < 6)
|
Chris@16
|
3062 {
|
Chris@16
|
3063 return ec = boost::asio::error::no_buffer_space;
|
Chris@16
|
3064 }
|
Chris@16
|
3065 #if defined(BOOST_ASIO_HAS_SECURE_RTL)
|
Chris@16
|
3066 sprintf_s(serv, servlen, "%u", ntohs(port));
|
Chris@16
|
3067 #else // defined(BOOST_ASIO_HAS_SECURE_RTL)
|
Chris@16
|
3068 sprintf(serv, "%u", ntohs(port));
|
Chris@16
|
3069 #endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
|
Chris@16
|
3070 }
|
Chris@16
|
3071 else
|
Chris@16
|
3072 {
|
Chris@16
|
3073 #if defined(BOOST_ASIO_HAS_PTHREADS)
|
Chris@16
|
3074 static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
Chris@16
|
3075 ::pthread_mutex_lock(&mutex);
|
Chris@16
|
3076 #endif // defined(BOOST_ASIO_HAS_PTHREADS)
|
Chris@16
|
3077 servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0);
|
Chris@16
|
3078 if (sptr && sptr->s_name && sptr->s_name[0] != '\0')
|
Chris@16
|
3079 {
|
Chris@16
|
3080 gai_strcpy(serv, sptr->s_name, servlen);
|
Chris@16
|
3081 }
|
Chris@16
|
3082 else
|
Chris@16
|
3083 {
|
Chris@16
|
3084 if (servlen < 6)
|
Chris@16
|
3085 {
|
Chris@16
|
3086 return ec = boost::asio::error::no_buffer_space;
|
Chris@16
|
3087 }
|
Chris@16
|
3088 #if defined(BOOST_ASIO_HAS_SECURE_RTL)
|
Chris@16
|
3089 sprintf_s(serv, servlen, "%u", ntohs(port));
|
Chris@16
|
3090 #else // defined(BOOST_ASIO_HAS_SECURE_RTL)
|
Chris@16
|
3091 sprintf(serv, "%u", ntohs(port));
|
Chris@16
|
3092 #endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
|
Chris@16
|
3093 }
|
Chris@16
|
3094 #if defined(BOOST_ASIO_HAS_PTHREADS)
|
Chris@16
|
3095 ::pthread_mutex_unlock(&mutex);
|
Chris@16
|
3096 #endif // defined(BOOST_ASIO_HAS_PTHREADS)
|
Chris@16
|
3097 }
|
Chris@16
|
3098 }
|
Chris@16
|
3099
|
Chris@16
|
3100 ec = boost::system::error_code();
|
Chris@16
|
3101 return ec;
|
Chris@16
|
3102 }
|
Chris@16
|
3103
|
Chris@16
|
3104 #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
3105 // || defined(__MACH__) && defined(__APPLE__)
|
Chris@16
|
3106
|
Chris@16
|
3107 inline boost::system::error_code translate_addrinfo_error(int error)
|
Chris@16
|
3108 {
|
Chris@16
|
3109 switch (error)
|
Chris@16
|
3110 {
|
Chris@16
|
3111 case 0:
|
Chris@16
|
3112 return boost::system::error_code();
|
Chris@16
|
3113 case EAI_AGAIN:
|
Chris@16
|
3114 return boost::asio::error::host_not_found_try_again;
|
Chris@16
|
3115 case EAI_BADFLAGS:
|
Chris@16
|
3116 return boost::asio::error::invalid_argument;
|
Chris@16
|
3117 case EAI_FAIL:
|
Chris@16
|
3118 return boost::asio::error::no_recovery;
|
Chris@16
|
3119 case EAI_FAMILY:
|
Chris@16
|
3120 return boost::asio::error::address_family_not_supported;
|
Chris@16
|
3121 case EAI_MEMORY:
|
Chris@16
|
3122 return boost::asio::error::no_memory;
|
Chris@16
|
3123 case EAI_NONAME:
|
Chris@16
|
3124 #if defined(EAI_ADDRFAMILY)
|
Chris@16
|
3125 case EAI_ADDRFAMILY:
|
Chris@16
|
3126 #endif
|
Chris@16
|
3127 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
|
Chris@16
|
3128 case EAI_NODATA:
|
Chris@16
|
3129 #endif
|
Chris@16
|
3130 return boost::asio::error::host_not_found;
|
Chris@16
|
3131 case EAI_SERVICE:
|
Chris@16
|
3132 return boost::asio::error::service_not_found;
|
Chris@16
|
3133 case EAI_SOCKTYPE:
|
Chris@16
|
3134 return boost::asio::error::socket_type_not_supported;
|
Chris@16
|
3135 default: // Possibly the non-portable EAI_SYSTEM.
|
Chris@16
|
3136 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
3137 return boost::system::error_code(
|
Chris@16
|
3138 WSAGetLastError(), boost::asio::error::get_system_category());
|
Chris@16
|
3139 #else
|
Chris@16
|
3140 return boost::system::error_code(
|
Chris@16
|
3141 errno, boost::asio::error::get_system_category());
|
Chris@16
|
3142 #endif
|
Chris@16
|
3143 }
|
Chris@16
|
3144 }
|
Chris@16
|
3145
|
Chris@16
|
3146 boost::system::error_code getaddrinfo(const char* host,
|
Chris@16
|
3147 const char* service, const addrinfo_type& hints,
|
Chris@16
|
3148 addrinfo_type** result, boost::system::error_code& ec)
|
Chris@16
|
3149 {
|
Chris@16
|
3150 host = (host && *host) ? host : 0;
|
Chris@16
|
3151 service = (service && *service) ? service : 0;
|
Chris@16
|
3152 clear_last_error();
|
Chris@16
|
3153 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
3154 # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
|
Chris@16
|
3155 // Building for Windows XP, Windows Server 2003, or later.
|
Chris@16
|
3156 int error = ::getaddrinfo(host, service, &hints, result);
|
Chris@16
|
3157 return ec = translate_addrinfo_error(error);
|
Chris@16
|
3158 # else
|
Chris@16
|
3159 // Building for Windows 2000 or earlier.
|
Chris@16
|
3160 typedef int (WSAAPI *gai_t)(const char*,
|
Chris@16
|
3161 const char*, const addrinfo_type*, addrinfo_type**);
|
Chris@16
|
3162 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
|
Chris@16
|
3163 {
|
Chris@16
|
3164 if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
|
Chris@16
|
3165 {
|
Chris@16
|
3166 int error = gai(host, service, &hints, result);
|
Chris@16
|
3167 return ec = translate_addrinfo_error(error);
|
Chris@16
|
3168 }
|
Chris@16
|
3169 }
|
Chris@16
|
3170 int error = getaddrinfo_emulation(host, service, &hints, result);
|
Chris@16
|
3171 return ec = translate_addrinfo_error(error);
|
Chris@16
|
3172 # endif
|
Chris@16
|
3173 #elif defined(__MACH__) && defined(__APPLE__)
|
Chris@16
|
3174 int error = getaddrinfo_emulation(host, service, &hints, result);
|
Chris@16
|
3175 return ec = translate_addrinfo_error(error);
|
Chris@16
|
3176 #else
|
Chris@16
|
3177 int error = ::getaddrinfo(host, service, &hints, result);
|
Chris@16
|
3178 return ec = translate_addrinfo_error(error);
|
Chris@16
|
3179 #endif
|
Chris@16
|
3180 }
|
Chris@16
|
3181
|
Chris@16
|
3182 boost::system::error_code background_getaddrinfo(
|
Chris@16
|
3183 const weak_cancel_token_type& cancel_token, const char* host,
|
Chris@16
|
3184 const char* service, const addrinfo_type& hints,
|
Chris@16
|
3185 addrinfo_type** result, boost::system::error_code& ec)
|
Chris@16
|
3186 {
|
Chris@16
|
3187 if (cancel_token.expired())
|
Chris@16
|
3188 ec = boost::asio::error::operation_aborted;
|
Chris@16
|
3189 else
|
Chris@16
|
3190 socket_ops::getaddrinfo(host, service, hints, result, ec);
|
Chris@16
|
3191 return ec;
|
Chris@16
|
3192 }
|
Chris@16
|
3193
|
Chris@16
|
3194 void freeaddrinfo(addrinfo_type* ai)
|
Chris@16
|
3195 {
|
Chris@16
|
3196 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
3197 # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
|
Chris@16
|
3198 // Building for Windows XP, Windows Server 2003, or later.
|
Chris@16
|
3199 ::freeaddrinfo(ai);
|
Chris@16
|
3200 # else
|
Chris@16
|
3201 // Building for Windows 2000 or earlier.
|
Chris@16
|
3202 typedef int (WSAAPI *fai_t)(addrinfo_type*);
|
Chris@16
|
3203 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
|
Chris@16
|
3204 {
|
Chris@16
|
3205 if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
|
Chris@16
|
3206 {
|
Chris@16
|
3207 fai(ai);
|
Chris@16
|
3208 return;
|
Chris@16
|
3209 }
|
Chris@16
|
3210 }
|
Chris@16
|
3211 freeaddrinfo_emulation(ai);
|
Chris@16
|
3212 # endif
|
Chris@16
|
3213 #elif defined(__MACH__) && defined(__APPLE__)
|
Chris@16
|
3214 freeaddrinfo_emulation(ai);
|
Chris@16
|
3215 #else
|
Chris@16
|
3216 ::freeaddrinfo(ai);
|
Chris@16
|
3217 #endif
|
Chris@16
|
3218 }
|
Chris@16
|
3219
|
Chris@16
|
3220 boost::system::error_code getnameinfo(const socket_addr_type* addr,
|
Chris@16
|
3221 std::size_t addrlen, char* host, std::size_t hostlen,
|
Chris@16
|
3222 char* serv, std::size_t servlen, int flags, boost::system::error_code& ec)
|
Chris@16
|
3223 {
|
Chris@16
|
3224 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
Chris@16
|
3225 # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
|
Chris@16
|
3226 // Building for Windows XP, Windows Server 2003, or later.
|
Chris@16
|
3227 clear_last_error();
|
Chris@16
|
3228 int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen),
|
Chris@16
|
3229 host, static_cast<DWORD>(hostlen),
|
Chris@16
|
3230 serv, static_cast<DWORD>(servlen), flags);
|
Chris@16
|
3231 return ec = translate_addrinfo_error(error);
|
Chris@16
|
3232 # else
|
Chris@16
|
3233 // Building for Windows 2000 or earlier.
|
Chris@16
|
3234 typedef int (WSAAPI *gni_t)(const socket_addr_type*,
|
Chris@16
|
3235 int, char*, DWORD, char*, DWORD, int);
|
Chris@16
|
3236 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
|
Chris@16
|
3237 {
|
Chris@16
|
3238 if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))
|
Chris@16
|
3239 {
|
Chris@16
|
3240 clear_last_error();
|
Chris@16
|
3241 int error = gni(addr, static_cast<int>(addrlen),
|
Chris@16
|
3242 host, static_cast<DWORD>(hostlen),
|
Chris@16
|
3243 serv, static_cast<DWORD>(servlen), flags);
|
Chris@16
|
3244 return ec = translate_addrinfo_error(error);
|
Chris@16
|
3245 }
|
Chris@16
|
3246 }
|
Chris@16
|
3247 clear_last_error();
|
Chris@16
|
3248 return getnameinfo_emulation(addr, addrlen,
|
Chris@16
|
3249 host, hostlen, serv, servlen, flags, ec);
|
Chris@16
|
3250 # endif
|
Chris@16
|
3251 #elif defined(__MACH__) && defined(__APPLE__)
|
Chris@16
|
3252 using namespace std; // For memcpy.
|
Chris@16
|
3253 sockaddr_storage_type tmp_addr;
|
Chris@16
|
3254 memcpy(&tmp_addr, addr, addrlen);
|
Chris@16
|
3255 tmp_addr.ss_len = addrlen;
|
Chris@16
|
3256 addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);
|
Chris@16
|
3257 clear_last_error();
|
Chris@16
|
3258 return getnameinfo_emulation(addr, addrlen,
|
Chris@16
|
3259 host, hostlen, serv, servlen, flags, ec);
|
Chris@16
|
3260 #else
|
Chris@16
|
3261 clear_last_error();
|
Chris@16
|
3262 int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
|
Chris@16
|
3263 return ec = translate_addrinfo_error(error);
|
Chris@16
|
3264 #endif
|
Chris@16
|
3265 }
|
Chris@16
|
3266
|
Chris@16
|
3267 boost::system::error_code sync_getnameinfo(
|
Chris@16
|
3268 const socket_addr_type* addr, std::size_t addrlen,
|
Chris@16
|
3269 char* host, std::size_t hostlen, char* serv,
|
Chris@16
|
3270 std::size_t servlen, int sock_type, boost::system::error_code& ec)
|
Chris@16
|
3271 {
|
Chris@16
|
3272 // First try resolving with the service name. If that fails try resolving
|
Chris@16
|
3273 // but allow the service to be returned as a number.
|
Chris@16
|
3274 int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
|
Chris@16
|
3275 socket_ops::getnameinfo(addr, addrlen, host,
|
Chris@16
|
3276 hostlen, serv, servlen, flags, ec);
|
Chris@16
|
3277 if (ec)
|
Chris@16
|
3278 {
|
Chris@16
|
3279 socket_ops::getnameinfo(addr, addrlen, host, hostlen,
|
Chris@16
|
3280 serv, servlen, flags | NI_NUMERICSERV, ec);
|
Chris@16
|
3281 }
|
Chris@16
|
3282
|
Chris@16
|
3283 return ec;
|
Chris@16
|
3284 }
|
Chris@16
|
3285
|
Chris@16
|
3286 boost::system::error_code background_getnameinfo(
|
Chris@16
|
3287 const weak_cancel_token_type& cancel_token,
|
Chris@16
|
3288 const socket_addr_type* addr, std::size_t addrlen,
|
Chris@16
|
3289 char* host, std::size_t hostlen, char* serv,
|
Chris@16
|
3290 std::size_t servlen, int sock_type, boost::system::error_code& ec)
|
Chris@16
|
3291 {
|
Chris@16
|
3292 if (cancel_token.expired())
|
Chris@16
|
3293 {
|
Chris@16
|
3294 ec = boost::asio::error::operation_aborted;
|
Chris@16
|
3295 }
|
Chris@16
|
3296 else
|
Chris@16
|
3297 {
|
Chris@16
|
3298 // First try resolving with the service name. If that fails try resolving
|
Chris@16
|
3299 // but allow the service to be returned as a number.
|
Chris@16
|
3300 int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
|
Chris@16
|
3301 socket_ops::getnameinfo(addr, addrlen, host,
|
Chris@16
|
3302 hostlen, serv, servlen, flags, ec);
|
Chris@16
|
3303 if (ec)
|
Chris@16
|
3304 {
|
Chris@16
|
3305 socket_ops::getnameinfo(addr, addrlen, host, hostlen,
|
Chris@16
|
3306 serv, servlen, flags | NI_NUMERICSERV, ec);
|
Chris@16
|
3307 }
|
Chris@16
|
3308 }
|
Chris@16
|
3309
|
Chris@16
|
3310 return ec;
|
Chris@16
|
3311 }
|
Chris@16
|
3312
|
Chris@16
|
3313 #endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3314
|
Chris@16
|
3315 u_long_type network_to_host_long(u_long_type value)
|
Chris@16
|
3316 {
|
Chris@16
|
3317 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3318 unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);
|
Chris@16
|
3319 u_long_type result = (static_cast<u_long_type>(value_p[0]) << 24)
|
Chris@16
|
3320 | (static_cast<u_long_type>(value_p[1]) << 16)
|
Chris@16
|
3321 | (static_cast<u_long_type>(value_p[2]) << 8)
|
Chris@16
|
3322 | static_cast<u_long_type>(value_p[3]);
|
Chris@16
|
3323 return result;
|
Chris@16
|
3324 #else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3325 return ntohl(value);
|
Chris@16
|
3326 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3327 }
|
Chris@16
|
3328
|
Chris@16
|
3329 u_long_type host_to_network_long(u_long_type value)
|
Chris@16
|
3330 {
|
Chris@16
|
3331 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3332 u_long_type result;
|
Chris@16
|
3333 unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);
|
Chris@16
|
3334 result_p[0] = static_cast<unsigned char>((value >> 24) & 0xFF);
|
Chris@16
|
3335 result_p[1] = static_cast<unsigned char>((value >> 16) & 0xFF);
|
Chris@16
|
3336 result_p[2] = static_cast<unsigned char>((value >> 8) & 0xFF);
|
Chris@16
|
3337 result_p[3] = static_cast<unsigned char>(value & 0xFF);
|
Chris@16
|
3338 return result;
|
Chris@16
|
3339 #else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3340 return htonl(value);
|
Chris@16
|
3341 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3342 }
|
Chris@16
|
3343
|
Chris@16
|
3344 u_short_type network_to_host_short(u_short_type value)
|
Chris@16
|
3345 {
|
Chris@16
|
3346 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3347 unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);
|
Chris@16
|
3348 u_short_type result = (static_cast<u_long_type>(value_p[0]) << 8)
|
Chris@16
|
3349 | static_cast<u_long_type>(value_p[1]);
|
Chris@16
|
3350 return result;
|
Chris@16
|
3351 #else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3352 return ntohs(value);
|
Chris@16
|
3353 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3354 }
|
Chris@16
|
3355
|
Chris@16
|
3356 u_short_type host_to_network_short(u_short_type value)
|
Chris@16
|
3357 {
|
Chris@16
|
3358 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3359 u_long_type result;
|
Chris@16
|
3360 unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);
|
Chris@16
|
3361 result_p[0] = static_cast<unsigned char>((value >> 8) & 0xFF);
|
Chris@16
|
3362 result_p[1] = static_cast<unsigned char>(value & 0xFF);
|
Chris@16
|
3363 return result;
|
Chris@16
|
3364 #else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3365 return htons(value);
|
Chris@16
|
3366 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
Chris@16
|
3367 }
|
Chris@16
|
3368
|
Chris@16
|
3369 } // namespace socket_ops
|
Chris@16
|
3370 } // namespace detail
|
Chris@16
|
3371 } // namespace asio
|
Chris@16
|
3372 } // namespace boost
|
Chris@16
|
3373
|
Chris@16
|
3374 #include <boost/asio/detail/pop_options.hpp>
|
Chris@16
|
3375
|
Chris@16
|
3376 #endif // BOOST_ASIO_DETAIL_SOCKET_OPS_IPP
|