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