annotate DEPENDENCIES/generic/include/boost/asio/detail/impl/socket_ops.ipp @ 16:2665513ce2d3

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