$search
00001 // 00002 // socket_ops.hpp 00003 // ~~~~~~~~~~~~~~ 00004 // 00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) 00006 // 00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 00009 // 00010 00011 #ifndef ASIO_DETAIL_SOCKET_OPS_HPP 00012 #define ASIO_DETAIL_SOCKET_OPS_HPP 00013 00014 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 00015 # pragma once 00016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 00017 00018 #include "asio/detail/push_options.hpp" 00019 00020 #include "asio/detail/push_options.hpp" 00021 #include <boost/config.hpp> 00022 #include <boost/assert.hpp> 00023 #include <cstdio> 00024 #include <cstdlib> 00025 #include <cstring> 00026 #include <cerrno> 00027 #include <boost/detail/workaround.hpp> 00028 #include <new> 00029 #include "asio/detail/pop_options.hpp" 00030 00031 #include "asio/error.hpp" 00032 #include "asio/detail/socket_types.hpp" 00033 00034 namespace asio { 00035 namespace detail { 00036 namespace socket_ops { 00037 00038 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00039 struct msghdr { int msg_namelen; }; 00040 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00041 00042 #if defined(__hpux) 00043 // HP-UX doesn't declare these functions extern "C", so they are declared again 00044 // here to avoid linker errors about undefined symbols. 00045 extern "C" char* if_indextoname(unsigned int, char*); 00046 extern "C" unsigned int if_nametoindex(const char*); 00047 #endif // defined(__hpux) 00048 00049 inline void clear_error(asio::error_code& ec) 00050 { 00051 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00052 WSASetLastError(0); 00053 #else 00054 errno = 0; 00055 #endif 00056 ec = asio::error_code(); 00057 } 00058 00059 template <typename ReturnType> 00060 inline ReturnType error_wrapper(ReturnType return_value, 00061 asio::error_code& ec) 00062 { 00063 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00064 ec = asio::error_code(WSAGetLastError(), 00065 asio::error::get_system_category()); 00066 #else 00067 ec = asio::error_code(errno, 00068 asio::error::get_system_category()); 00069 #endif 00070 return return_value; 00071 } 00072 00073 template <typename SockLenType> 00074 inline socket_type call_accept(SockLenType msghdr::*, 00075 socket_type s, socket_addr_type* addr, std::size_t* addrlen) 00076 { 00077 SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; 00078 socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); 00079 if (addrlen) 00080 *addrlen = (std::size_t)tmp_addrlen; 00081 return result; 00082 } 00083 00084 inline socket_type accept(socket_type s, socket_addr_type* addr, 00085 std::size_t* addrlen, asio::error_code& ec) 00086 { 00087 clear_error(ec); 00088 00089 socket_type new_s = error_wrapper(call_accept( 00090 &msghdr::msg_namelen, s, addr, addrlen), ec); 00091 if (new_s == invalid_socket) 00092 return new_s; 00093 00094 #if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) 00095 int optval = 1; 00096 int result = error_wrapper(::setsockopt(new_s, 00097 SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); 00098 if (result != 0) 00099 { 00100 ::close(new_s); 00101 return invalid_socket; 00102 } 00103 #endif 00104 00105 #if defined(BOOST_WINDOWS) && defined(UNDER_CE) 00106 clear_error(ec); 00107 #endif 00108 00109 return new_s; 00110 } 00111 00112 template <typename SockLenType> 00113 inline int call_bind(SockLenType msghdr::*, 00114 socket_type s, const socket_addr_type* addr, std::size_t addrlen) 00115 { 00116 return ::bind(s, addr, (SockLenType)addrlen); 00117 } 00118 00119 inline int bind(socket_type s, const socket_addr_type* addr, 00120 std::size_t addrlen, asio::error_code& ec) 00121 { 00122 clear_error(ec); 00123 int result = error_wrapper(call_bind( 00124 &msghdr::msg_namelen, s, addr, addrlen), ec); 00125 #if defined(BOOST_WINDOWS) && defined(UNDER_CE) 00126 if (result == 0) 00127 clear_error(ec); 00128 #endif 00129 return result; 00130 } 00131 00132 inline int close(socket_type s, asio::error_code& ec) 00133 { 00134 clear_error(ec); 00135 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00136 int result = error_wrapper(::closesocket(s), ec); 00137 # if defined(UNDER_CE) 00138 if (result == 0) 00139 clear_error(ec); 00140 # endif 00141 return result; 00142 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00143 return error_wrapper(::close(s), ec); 00144 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00145 } 00146 00147 inline int shutdown(socket_type s, int what, asio::error_code& ec) 00148 { 00149 clear_error(ec); 00150 int result = error_wrapper(::shutdown(s, what), ec); 00151 #if defined(BOOST_WINDOWS) && defined(UNDER_CE) 00152 if (result == 0) 00153 clear_error(ec); 00154 #endif 00155 return result; 00156 } 00157 00158 template <typename SockLenType> 00159 inline int call_connect(SockLenType msghdr::*, 00160 socket_type s, const socket_addr_type* addr, std::size_t addrlen) 00161 { 00162 return ::connect(s, addr, (SockLenType)addrlen); 00163 } 00164 00165 inline int connect(socket_type s, const socket_addr_type* addr, 00166 std::size_t addrlen, asio::error_code& ec) 00167 { 00168 clear_error(ec); 00169 int result = error_wrapper(call_connect( 00170 &msghdr::msg_namelen, s, addr, addrlen), ec); 00171 #if defined(BOOST_WINDOWS) && defined(UNDER_CE) 00172 if (result == 0) 00173 clear_error(ec); 00174 #endif 00175 return result; 00176 } 00177 00178 inline int socketpair(int af, int type, int protocol, 00179 socket_type sv[2], asio::error_code& ec) 00180 { 00181 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00182 (void)(af); 00183 (void)(type); 00184 (void)(protocol); 00185 (void)(sv); 00186 ec = asio::error::operation_not_supported; 00187 return -1; 00188 #else 00189 clear_error(ec); 00190 return error_wrapper(::socketpair(af, type, protocol, sv), ec); 00191 #endif 00192 } 00193 00194 inline int listen(socket_type s, int backlog, asio::error_code& ec) 00195 { 00196 clear_error(ec); 00197 int result = error_wrapper(::listen(s, backlog), ec); 00198 #if defined(BOOST_WINDOWS) && defined(UNDER_CE) 00199 if (result == 0) 00200 clear_error(ec); 00201 #endif 00202 return result; 00203 } 00204 00205 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00206 typedef WSABUF buf; 00207 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00208 typedef iovec buf; 00209 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00210 00211 inline void init_buf(buf& b, void* data, size_t size) 00212 { 00213 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00214 b.buf = static_cast<char*>(data); 00215 b.len = static_cast<u_long>(size); 00216 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00217 b.iov_base = data; 00218 b.iov_len = size; 00219 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00220 } 00221 00222 inline void init_buf(buf& b, const void* data, size_t size) 00223 { 00224 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00225 b.buf = static_cast<char*>(const_cast<void*>(data)); 00226 b.len = static_cast<u_long>(size); 00227 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00228 b.iov_base = const_cast<void*>(data); 00229 b.iov_len = size; 00230 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00231 } 00232 00233 inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) 00234 { 00235 name = addr; 00236 } 00237 00238 inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) 00239 { 00240 name = const_cast<socket_addr_type*>(addr); 00241 } 00242 00243 template <typename T> 00244 inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) 00245 { 00246 name = reinterpret_cast<T>(addr); 00247 } 00248 00249 template <typename T> 00250 inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) 00251 { 00252 name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr)); 00253 } 00254 00255 inline int recv(socket_type s, buf* bufs, size_t count, int flags, 00256 asio::error_code& ec) 00257 { 00258 clear_error(ec); 00259 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00260 // Receive some data. 00261 DWORD recv_buf_count = static_cast<DWORD>(count); 00262 DWORD bytes_transferred = 0; 00263 DWORD recv_flags = flags; 00264 int result = error_wrapper(::WSARecv(s, bufs, 00265 recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); 00266 if (result != 0) 00267 return -1; 00268 # if defined(UNDER_CE) 00269 clear_error(ec); 00270 # endif 00271 return bytes_transferred; 00272 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00273 msghdr msg = msghdr(); 00274 msg.msg_iov = bufs; 00275 msg.msg_iovlen = count; 00276 return error_wrapper(::recvmsg(s, &msg, flags), ec); 00277 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00278 } 00279 00280 inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, 00281 socket_addr_type* addr, std::size_t* addrlen, 00282 asio::error_code& ec) 00283 { 00284 clear_error(ec); 00285 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00286 // Receive some data. 00287 DWORD recv_buf_count = static_cast<DWORD>(count); 00288 DWORD bytes_transferred = 0; 00289 DWORD recv_flags = flags; 00290 int tmp_addrlen = (int)*addrlen; 00291 int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, 00292 &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); 00293 *addrlen = (std::size_t)tmp_addrlen; 00294 if (result != 0) 00295 return -1; 00296 # if defined(UNDER_CE) 00297 clear_error(ec); 00298 # endif 00299 return bytes_transferred; 00300 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00301 msghdr msg = msghdr(); 00302 init_msghdr_msg_name(msg.msg_name, addr); 00303 msg.msg_namelen = *addrlen; 00304 msg.msg_iov = bufs; 00305 msg.msg_iovlen = count; 00306 int result = error_wrapper(::recvmsg(s, &msg, flags), ec); 00307 *addrlen = msg.msg_namelen; 00308 return result; 00309 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00310 } 00311 00312 inline int send(socket_type s, const buf* bufs, size_t count, int flags, 00313 asio::error_code& ec) 00314 { 00315 clear_error(ec); 00316 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00317 // Send the data. 00318 DWORD send_buf_count = static_cast<DWORD>(count); 00319 DWORD bytes_transferred = 0; 00320 DWORD send_flags = flags; 00321 int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs), 00322 send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); 00323 if (result != 0) 00324 return -1; 00325 # if defined(UNDER_CE) 00326 clear_error(ec); 00327 # endif 00328 return bytes_transferred; 00329 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00330 msghdr msg = msghdr(); 00331 msg.msg_iov = const_cast<buf*>(bufs); 00332 msg.msg_iovlen = count; 00333 #if defined(__linux__) 00334 flags |= MSG_NOSIGNAL; 00335 #endif // defined(__linux__) 00336 return error_wrapper(::sendmsg(s, &msg, flags), ec); 00337 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00338 } 00339 00340 inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, 00341 const socket_addr_type* addr, std::size_t addrlen, 00342 asio::error_code& ec) 00343 { 00344 clear_error(ec); 00345 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00346 // Send the data. 00347 DWORD send_buf_count = static_cast<DWORD>(count); 00348 DWORD bytes_transferred = 0; 00349 int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs), 00350 send_buf_count, &bytes_transferred, flags, addr, 00351 static_cast<int>(addrlen), 0, 0), ec); 00352 if (result != 0) 00353 return -1; 00354 # if defined(UNDER_CE) 00355 clear_error(ec); 00356 # endif 00357 return bytes_transferred; 00358 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00359 msghdr msg = msghdr(); 00360 init_msghdr_msg_name(msg.msg_name, addr); 00361 msg.msg_namelen = addrlen; 00362 msg.msg_iov = const_cast<buf*>(bufs); 00363 msg.msg_iovlen = count; 00364 #if defined(__linux__) 00365 flags |= MSG_NOSIGNAL; 00366 #endif // defined(__linux__) 00367 return error_wrapper(::sendmsg(s, &msg, flags), ec); 00368 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00369 } 00370 00371 inline socket_type socket(int af, int type, int protocol, 00372 asio::error_code& ec) 00373 { 00374 clear_error(ec); 00375 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00376 socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0, 00377 WSA_FLAG_OVERLAPPED), ec); 00378 if (s == invalid_socket) 00379 return s; 00380 00381 if (af == AF_INET6) 00382 { 00383 // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to 00384 // false. This will only succeed on Windows Vista and later versions of 00385 // Windows, where a dual-stack IPv4/v6 implementation is available. 00386 DWORD optval = 0; 00387 ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 00388 reinterpret_cast<const char*>(&optval), sizeof(optval)); 00389 } 00390 00391 # if defined(UNDER_CE) 00392 clear_error(ec); 00393 # endif 00394 00395 return s; 00396 #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) 00397 socket_type s = error_wrapper(::socket(af, type, protocol), ec); 00398 if (s == invalid_socket) 00399 return s; 00400 00401 int optval = 1; 00402 int result = error_wrapper(::setsockopt(s, 00403 SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); 00404 if (result != 0) 00405 { 00406 ::close(s); 00407 return invalid_socket; 00408 } 00409 00410 return s; 00411 #else 00412 return error_wrapper(::socket(af, type, protocol), ec); 00413 #endif 00414 } 00415 00416 template <typename SockLenType> 00417 inline int call_setsockopt(SockLenType msghdr::*, 00418 socket_type s, int level, int optname, 00419 const void* optval, std::size_t optlen) 00420 { 00421 return ::setsockopt(s, level, optname, 00422 (const char*)optval, (SockLenType)optlen); 00423 } 00424 00425 inline int setsockopt(socket_type s, int level, int optname, 00426 const void* optval, std::size_t optlen, asio::error_code& ec) 00427 { 00428 if (level == custom_socket_option_level && optname == always_fail_option) 00429 { 00430 ec = asio::error::invalid_argument; 00431 return -1; 00432 } 00433 00434 #if defined(__BORLANDC__) 00435 // Mysteriously, using the getsockopt and setsockopt functions directly with 00436 // Borland C++ results in incorrect values being set and read. The bug can be 00437 // worked around by using function addresses resolved with GetProcAddress. 00438 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) 00439 { 00440 typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); 00441 if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) 00442 { 00443 clear_error(ec); 00444 return error_wrapper(sso(s, level, optname, 00445 reinterpret_cast<const char*>(optval), 00446 static_cast<int>(optlen)), ec); 00447 } 00448 } 00449 ec = asio::error::fault; 00450 return -1; 00451 #else // defined(__BORLANDC__) 00452 clear_error(ec); 00453 int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, 00454 s, level, optname, optval, optlen), ec); 00455 # if defined(BOOST_WINDOWS) && defined(UNDER_CE) 00456 if (result == 0) 00457 clear_error(ec); 00458 # endif 00459 return result; 00460 #endif // defined(__BORLANDC__) 00461 } 00462 00463 template <typename SockLenType> 00464 inline int call_getsockopt(SockLenType msghdr::*, 00465 socket_type s, int level, int optname, 00466 void* optval, std::size_t* optlen) 00467 { 00468 SockLenType tmp_optlen = (SockLenType)*optlen; 00469 int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); 00470 *optlen = (std::size_t)tmp_optlen; 00471 return result; 00472 } 00473 00474 inline int getsockopt(socket_type s, int level, int optname, void* optval, 00475 size_t* optlen, asio::error_code& ec) 00476 { 00477 if (level == custom_socket_option_level && optname == always_fail_option) 00478 { 00479 ec = asio::error::invalid_argument; 00480 return -1; 00481 } 00482 00483 #if defined(__BORLANDC__) 00484 // Mysteriously, using the getsockopt and setsockopt functions directly with 00485 // Borland C++ results in incorrect values being set and read. The bug can be 00486 // worked around by using function addresses resolved with GetProcAddress. 00487 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) 00488 { 00489 typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); 00490 if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) 00491 { 00492 clear_error(ec); 00493 int tmp_optlen = static_cast<int>(*optlen); 00494 int result = error_wrapper(gso(s, level, optname, 00495 reinterpret_cast<char*>(optval), &tmp_optlen), ec); 00496 *optlen = static_cast<size_t>(tmp_optlen); 00497 if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY 00498 && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) 00499 { 00500 // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are 00501 // only supported on Windows Vista and later. To simplify program logic 00502 // we will fake success of getting this option and specify that the 00503 // value is non-zero (i.e. true). This corresponds to the behavior of 00504 // IPv6 sockets on Windows platforms pre-Vista. 00505 *static_cast<DWORD*>(optval) = 1; 00506 clear_error(ec); 00507 } 00508 return result; 00509 } 00510 } 00511 ec = asio::error::fault; 00512 return -1; 00513 #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00514 clear_error(ec); 00515 int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, 00516 s, level, optname, optval, optlen), ec); 00517 if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY 00518 && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) 00519 { 00520 // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only 00521 // supported on Windows Vista and later. To simplify program logic we will 00522 // fake success of getting this option and specify that the value is 00523 // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets 00524 // on Windows platforms pre-Vista. 00525 *static_cast<DWORD*>(optval) = 1; 00526 clear_error(ec); 00527 } 00528 # if defined(UNDER_CE) 00529 if (result == 0) 00530 clear_error(ec); 00531 # endif 00532 return result; 00533 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00534 clear_error(ec); 00535 int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, 00536 s, level, optname, optval, optlen), ec); 00537 #if defined(__linux__) 00538 if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) 00539 && (optname == SO_SNDBUF || optname == SO_RCVBUF)) 00540 { 00541 // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel 00542 // to set the buffer size to N*2. Linux puts additional stuff into the 00543 // buffers so that only about half is actually available to the application. 00544 // The retrieved value is divided by 2 here to make it appear as though the 00545 // correct value has been set. 00546 *static_cast<int*>(optval) /= 2; 00547 } 00548 #endif // defined(__linux__) 00549 return result; 00550 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00551 } 00552 00553 template <typename SockLenType> 00554 inline int call_getpeername(SockLenType msghdr::*, 00555 socket_type s, socket_addr_type* addr, std::size_t* addrlen) 00556 { 00557 SockLenType tmp_addrlen = (SockLenType)*addrlen; 00558 int result = ::getpeername(s, addr, &tmp_addrlen); 00559 *addrlen = (std::size_t)tmp_addrlen; 00560 return result; 00561 } 00562 00563 inline int getpeername(socket_type s, socket_addr_type* addr, 00564 std::size_t* addrlen, asio::error_code& ec) 00565 { 00566 clear_error(ec); 00567 int result = error_wrapper(call_getpeername( 00568 &msghdr::msg_namelen, s, addr, addrlen), ec); 00569 #if defined(BOOST_WINDOWS) && defined(UNDER_CE) 00570 if (result == 0) 00571 clear_error(ec); 00572 #endif 00573 return result; 00574 } 00575 00576 template <typename SockLenType> 00577 inline int call_getsockname(SockLenType msghdr::*, 00578 socket_type s, socket_addr_type* addr, std::size_t* addrlen) 00579 { 00580 SockLenType tmp_addrlen = (SockLenType)*addrlen; 00581 int result = ::getsockname(s, addr, &tmp_addrlen); 00582 *addrlen = (std::size_t)tmp_addrlen; 00583 return result; 00584 } 00585 00586 inline int getsockname(socket_type s, socket_addr_type* addr, 00587 std::size_t* addrlen, asio::error_code& ec) 00588 { 00589 clear_error(ec); 00590 int result = error_wrapper(call_getsockname( 00591 &msghdr::msg_namelen, s, addr, addrlen), ec); 00592 #if defined(BOOST_WINDOWS) && defined(UNDER_CE) 00593 if (result == 0) 00594 clear_error(ec); 00595 #endif 00596 return result; 00597 } 00598 00599 inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, 00600 asio::error_code& ec) 00601 { 00602 clear_error(ec); 00603 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00604 int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); 00605 # if defined(UNDER_CE) 00606 if (result == 0) 00607 clear_error(ec); 00608 # endif 00609 return result; 00610 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00611 return error_wrapper(::ioctl(s, cmd, arg), ec); 00612 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00613 } 00614 00615 inline int select(int nfds, fd_set* readfds, fd_set* writefds, 00616 fd_set* exceptfds, timeval* timeout, asio::error_code& ec) 00617 { 00618 clear_error(ec); 00619 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00620 if (!readfds && !writefds && !exceptfds && timeout) 00621 { 00622 DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; 00623 if (milliseconds == 0) 00624 milliseconds = 1; // Force context switch. 00625 ::Sleep(milliseconds); 00626 ec = asio::error_code(); 00627 return 0; 00628 } 00629 00630 // The select() call allows timeout values measured in microseconds, but the 00631 // system clock (as wrapped by boost::posix_time::microsec_clock) typically 00632 // has a resolution of 10 milliseconds. This can lead to a spinning select 00633 // reactor, meaning increased CPU usage, when waiting for the earliest 00634 // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight 00635 // spin we'll use a minimum timeout of 1 millisecond. 00636 if (timeout && timeout->tv_sec == 0 00637 && timeout->tv_usec > 0 && timeout->tv_usec < 1000) 00638 timeout->tv_usec = 1000; 00639 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00640 00641 #if defined(__hpux) && defined(__HP_aCC) 00642 timespec ts; 00643 ts.tv_sec = timeout ? timeout->tv_sec : 0; 00644 ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; 00645 return error_wrapper(::pselect(nfds, readfds, 00646 writefds, exceptfds, timeout ? &ts : 0, 0), ec); 00647 #else 00648 int result = error_wrapper(::select(nfds, readfds, 00649 writefds, exceptfds, timeout), ec); 00650 # if defined(BOOST_WINDOWS) && defined(UNDER_CE) 00651 if (result >= 0) 00652 clear_error(ec); 00653 # endif 00654 return result; 00655 #endif 00656 } 00657 00658 inline int poll_read(socket_type s, asio::error_code& ec) 00659 { 00660 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00661 FD_SET fds; 00662 FD_ZERO(&fds); 00663 FD_SET(s, &fds); 00664 clear_error(ec); 00665 int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); 00666 # if defined(UNDER_CE) 00667 if (result >= 0) 00668 clear_error(ec); 00669 # endif 00670 return result; 00671 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00672 pollfd fds; 00673 fds.fd = s; 00674 fds.events = POLLIN; 00675 fds.revents = 0; 00676 clear_error(ec); 00677 return error_wrapper(::poll(&fds, 1, -1), ec); 00678 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00679 } 00680 00681 inline int poll_write(socket_type s, asio::error_code& ec) 00682 { 00683 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00684 FD_SET fds; 00685 FD_ZERO(&fds); 00686 FD_SET(s, &fds); 00687 clear_error(ec); 00688 int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); 00689 # if defined(UNDER_CE) 00690 if (result >= 0) 00691 clear_error(ec); 00692 # endif 00693 return result; 00694 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00695 pollfd fds; 00696 fds.fd = s; 00697 fds.events = POLLOUT; 00698 fds.revents = 0; 00699 clear_error(ec); 00700 return error_wrapper(::poll(&fds, 1, -1), ec); 00701 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00702 } 00703 00704 inline const char* inet_ntop(int af, const void* src, char* dest, size_t length, 00705 unsigned long scope_id, asio::error_code& ec) 00706 { 00707 clear_error(ec); 00708 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00709 using namespace std; // For memcpy. 00710 00711 if (af != AF_INET && af != AF_INET6) 00712 { 00713 ec = asio::error::address_family_not_supported; 00714 return 0; 00715 } 00716 00717 union 00718 { 00719 socket_addr_type base; 00720 sockaddr_storage_type storage; 00721 sockaddr_in4_type v4; 00722 sockaddr_in6_type v6; 00723 } address; 00724 DWORD address_length; 00725 if (af == AF_INET) 00726 { 00727 address_length = sizeof(sockaddr_in4_type); 00728 address.v4.sin_family = AF_INET; 00729 address.v4.sin_port = 0; 00730 memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); 00731 } 00732 else // AF_INET6 00733 { 00734 address_length = sizeof(sockaddr_in6_type); 00735 address.v6.sin6_family = AF_INET6; 00736 address.v6.sin6_port = 0; 00737 address.v6.sin6_flowinfo = 0; 00738 address.v6.sin6_scope_id = scope_id; 00739 memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); 00740 } 00741 00742 DWORD string_length = static_cast<DWORD>(length); 00743 #if defined(BOOST_NO_ANSI_APIS) 00744 LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); 00745 int result = error_wrapper(::WSAAddressToStringW(&address.base, 00746 address_length, 0, string_buffer, &string_length), ec); 00747 ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); 00748 #else 00749 int result = error_wrapper(::WSAAddressToStringA( 00750 &address.base, address_length, 0, dest, &string_length), ec); 00751 #endif 00752 00753 // Windows may set error code on success. 00754 if (result != socket_error_retval) 00755 clear_error(ec); 00756 00757 // Windows may not set an error code on failure. 00758 else if (result == socket_error_retval && !ec) 00759 ec = asio::error::invalid_argument; 00760 00761 return result == socket_error_retval ? 0 : dest; 00762 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00763 const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec); 00764 if (result == 0 && !ec) 00765 ec = asio::error::invalid_argument; 00766 if (result != 0 && af == AF_INET6 && scope_id != 0) 00767 { 00768 using namespace std; // For strcat and sprintf. 00769 char if_name[IF_NAMESIZE + 1] = "%"; 00770 const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src); 00771 bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); 00772 if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0) 00773 sprintf(if_name + 1, "%lu", scope_id); 00774 strcat(dest, if_name); 00775 } 00776 return result; 00777 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00778 } 00779 00780 inline int inet_pton(int af, const char* src, void* dest, 00781 unsigned long* scope_id, asio::error_code& ec) 00782 { 00783 clear_error(ec); 00784 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00785 using namespace std; // For memcpy and strcmp. 00786 00787 if (af != AF_INET && af != AF_INET6) 00788 { 00789 ec = asio::error::address_family_not_supported; 00790 return -1; 00791 } 00792 00793 union 00794 { 00795 socket_addr_type base; 00796 sockaddr_storage_type storage; 00797 sockaddr_in4_type v4; 00798 sockaddr_in6_type v6; 00799 } address; 00800 int address_length = sizeof(sockaddr_storage_type); 00801 #if defined(BOOST_NO_ANSI_APIS) 00802 int num_wide_chars = strlen(src) + 1; 00803 LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); 00804 ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); 00805 int result = error_wrapper(::WSAStringToAddressW( 00806 wide_buffer, af, 0, &address.base, &address_length), ec); 00807 #else 00808 int result = error_wrapper(::WSAStringToAddressA( 00809 const_cast<char*>(src), af, 0, &address.base, &address_length), ec); 00810 #endif 00811 00812 if (af == AF_INET) 00813 { 00814 if (result != socket_error_retval) 00815 { 00816 memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); 00817 clear_error(ec); 00818 } 00819 else if (strcmp(src, "255.255.255.255") == 0) 00820 { 00821 static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE; 00822 clear_error(ec); 00823 } 00824 } 00825 else // AF_INET6 00826 { 00827 if (result != socket_error_retval) 00828 { 00829 memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); 00830 if (scope_id) 00831 *scope_id = address.v6.sin6_scope_id; 00832 clear_error(ec); 00833 } 00834 } 00835 00836 // Windows may not set an error code on failure. 00837 if (result == socket_error_retval && !ec) 00838 ec = asio::error::invalid_argument; 00839 00840 #if defined(UNDER_CE) 00841 if (result != socket_error_retval) 00842 clear_error(ec); 00843 #endif 00844 00845 return result == socket_error_retval ? -1 : 1; 00846 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00847 int result = error_wrapper(::inet_pton(af, src, dest), ec); 00848 if (result <= 0 && !ec) 00849 ec = asio::error::invalid_argument; 00850 if (result > 0 && af == AF_INET6 && scope_id) 00851 { 00852 using namespace std; // For strchr and atoi. 00853 *scope_id = 0; 00854 if (const char* if_name = strchr(src, '%')) 00855 { 00856 in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest); 00857 bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); 00858 if (is_link_local) 00859 *scope_id = if_nametoindex(if_name + 1); 00860 if (*scope_id == 0) 00861 *scope_id = atoi(if_name + 1); 00862 } 00863 } 00864 return result; 00865 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00866 } 00867 00868 inline int gethostname(char* name, int namelen, asio::error_code& ec) 00869 { 00870 clear_error(ec); 00871 int result = error_wrapper(::gethostname(name, namelen), ec); 00872 #if defined(BOOST_WINDOWS) && defined(UNDER_CE) 00873 if (result == 0) 00874 clear_error(ec); 00875 #endif 00876 return result; 00877 } 00878 00879 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ 00880 || defined(__MACH__) && defined(__APPLE__) 00881 00882 // The following functions are only needed for emulation of getaddrinfo and 00883 // getnameinfo. 00884 00885 inline asio::error_code translate_netdb_error(int error) 00886 { 00887 switch (error) 00888 { 00889 case 0: 00890 return asio::error_code(); 00891 case HOST_NOT_FOUND: 00892 return asio::error::host_not_found; 00893 case TRY_AGAIN: 00894 return asio::error::host_not_found_try_again; 00895 case NO_RECOVERY: 00896 return asio::error::no_recovery; 00897 case NO_DATA: 00898 return asio::error::no_data; 00899 default: 00900 BOOST_ASSERT(false); 00901 return asio::error::invalid_argument; 00902 } 00903 } 00904 00905 inline hostent* gethostbyaddr(const char* addr, int length, int af, 00906 hostent* result, char* buffer, int buflength, asio::error_code& ec) 00907 { 00908 clear_error(ec); 00909 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00910 (void)(buffer); 00911 (void)(buflength); 00912 hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); 00913 if (!retval) 00914 return 0; 00915 # if defined(UNDER_CE) 00916 clear_error(ec); 00917 # endif 00918 *result = *retval; 00919 return retval; 00920 #elif defined(__sun) || defined(__QNX__) 00921 int error = 0; 00922 hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, 00923 buffer, buflength, &error), ec); 00924 if (error) 00925 ec = translate_netdb_error(error); 00926 return retval; 00927 #elif defined(__MACH__) && defined(__APPLE__) 00928 (void)(buffer); 00929 (void)(buflength); 00930 int error = 0; 00931 hostent* retval = error_wrapper(::getipnodebyaddr( 00932 addr, length, af, &error), ec); 00933 if (error) 00934 ec = translate_netdb_error(error); 00935 if (!retval) 00936 return 0; 00937 *result = *retval; 00938 return retval; 00939 #else 00940 hostent* retval = 0; 00941 int error = 0; 00942 error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, 00943 buflength, &retval, &error), ec); 00944 if (error) 00945 ec = translate_netdb_error(error); 00946 return retval; 00947 #endif 00948 } 00949 00950 inline hostent* gethostbyname(const char* name, int af, struct hostent* result, 00951 char* buffer, int buflength, int ai_flags, asio::error_code& ec) 00952 { 00953 clear_error(ec); 00954 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 00955 (void)(buffer); 00956 (void)(buflength); 00957 (void)(ai_flags); 00958 if (af != AF_INET) 00959 { 00960 ec = asio::error::address_family_not_supported; 00961 return 0; 00962 } 00963 hostent* retval = error_wrapper(::gethostbyname(name), ec); 00964 if (!retval) 00965 return 0; 00966 # if defined(UNDER_CE) 00967 clear_error(ec); 00968 # endif 00969 *result = *retval; 00970 return result; 00971 #elif defined(__sun) || defined(__QNX__) 00972 (void)(ai_flags); 00973 if (af != AF_INET) 00974 { 00975 ec = asio::error::address_family_not_supported; 00976 return 0; 00977 } 00978 int error = 0; 00979 hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, 00980 buflength, &error), ec); 00981 if (error) 00982 ec = translate_netdb_error(error); 00983 return retval; 00984 #elif defined(__MACH__) && defined(__APPLE__) 00985 (void)(buffer); 00986 (void)(buflength); 00987 int error = 0; 00988 hostent* retval = error_wrapper(::getipnodebyname( 00989 name, af, ai_flags, &error), ec); 00990 if (error) 00991 ec = translate_netdb_error(error); 00992 if (!retval) 00993 return 0; 00994 *result = *retval; 00995 return retval; 00996 #else 00997 (void)(ai_flags); 00998 if (af != AF_INET) 00999 { 01000 ec = asio::error::address_family_not_supported; 01001 return 0; 01002 } 01003 hostent* retval = 0; 01004 int error = 0; 01005 error_wrapper(::gethostbyname_r(name, result, 01006 buffer, buflength, &retval, &error), ec); 01007 if (error) 01008 ec = translate_netdb_error(error); 01009 return retval; 01010 #endif 01011 } 01012 01013 inline void freehostent(hostent* h) 01014 { 01015 #if defined(__MACH__) && defined(__APPLE__) 01016 if (h) 01017 ::freehostent(h); 01018 #else 01019 (void)(h); 01020 #endif 01021 } 01022 01023 // Emulation of getaddrinfo based on implementation in: 01024 // Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. 01025 01026 struct gai_search 01027 { 01028 const char* host; 01029 int family; 01030 }; 01031 01032 inline int gai_nsearch(const char* host, 01033 const addrinfo_type* hints, gai_search (&search)[2]) 01034 { 01035 int search_count = 0; 01036 if (host == 0 || host[0] == '\0') 01037 { 01038 if (hints->ai_flags & AI_PASSIVE) 01039 { 01040 // No host and AI_PASSIVE implies wildcard bind. 01041 switch (hints->ai_family) 01042 { 01043 case AF_INET: 01044 search[search_count].host = "0.0.0.0"; 01045 search[search_count].family = AF_INET; 01046 ++search_count; 01047 break; 01048 case AF_INET6: 01049 search[search_count].host = "0::0"; 01050 search[search_count].family = AF_INET6; 01051 ++search_count; 01052 break; 01053 case AF_UNSPEC: 01054 search[search_count].host = "0::0"; 01055 search[search_count].family = AF_INET6; 01056 ++search_count; 01057 search[search_count].host = "0.0.0.0"; 01058 search[search_count].family = AF_INET; 01059 ++search_count; 01060 break; 01061 default: 01062 break; 01063 } 01064 } 01065 else 01066 { 01067 // No host and not AI_PASSIVE means connect to local host. 01068 switch (hints->ai_family) 01069 { 01070 case AF_INET: 01071 search[search_count].host = "localhost"; 01072 search[search_count].family = AF_INET; 01073 ++search_count; 01074 break; 01075 case AF_INET6: 01076 search[search_count].host = "localhost"; 01077 search[search_count].family = AF_INET6; 01078 ++search_count; 01079 break; 01080 case AF_UNSPEC: 01081 search[search_count].host = "localhost"; 01082 search[search_count].family = AF_INET6; 01083 ++search_count; 01084 search[search_count].host = "localhost"; 01085 search[search_count].family = AF_INET; 01086 ++search_count; 01087 break; 01088 default: 01089 break; 01090 } 01091 } 01092 } 01093 else 01094 { 01095 // Host is specified. 01096 switch (hints->ai_family) 01097 { 01098 case AF_INET: 01099 search[search_count].host = host; 01100 search[search_count].family = AF_INET; 01101 ++search_count; 01102 break; 01103 case AF_INET6: 01104 search[search_count].host = host; 01105 search[search_count].family = AF_INET6; 01106 ++search_count; 01107 break; 01108 case AF_UNSPEC: 01109 search[search_count].host = host; 01110 search[search_count].family = AF_INET6; 01111 ++search_count; 01112 search[search_count].host = host; 01113 search[search_count].family = AF_INET; 01114 ++search_count; 01115 break; 01116 default: 01117 break; 01118 } 01119 } 01120 return search_count; 01121 } 01122 01123 template <typename T> 01124 inline T* gai_alloc(std::size_t size = sizeof(T)) 01125 { 01126 using namespace std; 01127 T* p = static_cast<T*>(::operator new(size, std::nothrow)); 01128 if (p) 01129 memset(p, 0, size); 01130 return p; 01131 } 01132 01133 inline void gai_free(void* p) 01134 { 01135 ::operator delete(p); 01136 } 01137 01138 inline void gai_strcpy(char* target, const char* source, std::size_t max_size) 01139 { 01140 using namespace std; 01141 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) 01142 strcpy_s(target, max_size, source); 01143 #else 01144 *target = 0; 01145 strncat(target, source, max_size); 01146 #endif 01147 } 01148 01149 enum { gai_clone_flag = 1 << 30 }; 01150 01151 inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, 01152 const void* addr, int family) 01153 { 01154 using namespace std; 01155 01156 addrinfo_type* ai = gai_alloc<addrinfo_type>(); 01157 if (ai == 0) 01158 return EAI_MEMORY; 01159 01160 ai->ai_next = 0; 01161 **next = ai; 01162 *next = &ai->ai_next; 01163 01164 ai->ai_canonname = 0; 01165 ai->ai_socktype = hints->ai_socktype; 01166 if (ai->ai_socktype == 0) 01167 ai->ai_flags |= gai_clone_flag; 01168 ai->ai_protocol = hints->ai_protocol; 01169 ai->ai_family = family; 01170 01171 switch (ai->ai_family) 01172 { 01173 case AF_INET: 01174 { 01175 sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>(); 01176 if (sinptr == 0) 01177 return EAI_MEMORY; 01178 sinptr->sin_family = AF_INET; 01179 memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); 01180 ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr); 01181 ai->ai_addrlen = sizeof(sockaddr_in4_type); 01182 break; 01183 } 01184 case AF_INET6: 01185 { 01186 sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>(); 01187 if (sin6ptr == 0) 01188 return EAI_MEMORY; 01189 sin6ptr->sin6_family = AF_INET6; 01190 memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); 01191 ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr); 01192 ai->ai_addrlen = sizeof(sockaddr_in6_type); 01193 break; 01194 } 01195 default: 01196 break; 01197 } 01198 01199 return 0; 01200 } 01201 01202 inline addrinfo_type* gai_clone(addrinfo_type* ai) 01203 { 01204 using namespace std; 01205 01206 addrinfo_type* new_ai = gai_alloc<addrinfo_type>(); 01207 if (new_ai == 0) 01208 return new_ai; 01209 01210 new_ai->ai_next = ai->ai_next; 01211 ai->ai_next = new_ai; 01212 01213 new_ai->ai_flags = 0; 01214 new_ai->ai_family = ai->ai_family; 01215 new_ai->ai_socktype = ai->ai_socktype; 01216 new_ai->ai_protocol = ai->ai_protocol; 01217 new_ai->ai_canonname = 0; 01218 new_ai->ai_addrlen = ai->ai_addrlen; 01219 new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen); 01220 memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); 01221 01222 return new_ai; 01223 } 01224 01225 inline int gai_port(addrinfo_type* aihead, int port, int socktype) 01226 { 01227 int num_found = 0; 01228 01229 for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) 01230 { 01231 if (ai->ai_flags & gai_clone_flag) 01232 { 01233 if (ai->ai_socktype != 0) 01234 { 01235 ai = gai_clone(ai); 01236 if (ai == 0) 01237 return -1; 01238 // ai now points to newly cloned entry. 01239 } 01240 } 01241 else if (ai->ai_socktype != socktype) 01242 { 01243 // Ignore if mismatch on socket type. 01244 continue; 01245 } 01246 01247 ai->ai_socktype = socktype; 01248 01249 switch (ai->ai_family) 01250 { 01251 case AF_INET: 01252 { 01253 sockaddr_in4_type* sinptr = 01254 reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr); 01255 sinptr->sin_port = port; 01256 ++num_found; 01257 break; 01258 } 01259 case AF_INET6: 01260 { 01261 sockaddr_in6_type* sin6ptr = 01262 reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr); 01263 sin6ptr->sin6_port = port; 01264 ++num_found; 01265 break; 01266 } 01267 default: 01268 break; 01269 } 01270 } 01271 01272 return num_found; 01273 } 01274 01275 inline int gai_serv(addrinfo_type* aihead, 01276 const addrinfo_type* hints, const char* serv) 01277 { 01278 using namespace std; 01279 01280 int num_found = 0; 01281 01282 if ( 01283 #if defined(AI_NUMERICSERV) 01284 (hints->ai_flags & AI_NUMERICSERV) || 01285 #endif 01286 isdigit(serv[0])) 01287 { 01288 int port = htons(atoi(serv)); 01289 if (hints->ai_socktype) 01290 { 01291 // Caller specifies socket type. 01292 int rc = gai_port(aihead, port, hints->ai_socktype); 01293 if (rc < 0) 01294 return EAI_MEMORY; 01295 num_found += rc; 01296 } 01297 else 01298 { 01299 // Caller does not specify socket type. 01300 int rc = gai_port(aihead, port, SOCK_STREAM); 01301 if (rc < 0) 01302 return EAI_MEMORY; 01303 num_found += rc; 01304 rc = gai_port(aihead, port, SOCK_DGRAM); 01305 if (rc < 0) 01306 return EAI_MEMORY; 01307 num_found += rc; 01308 } 01309 } 01310 else 01311 { 01312 // Try service name with TCP first, then UDP. 01313 if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) 01314 { 01315 servent* sptr = getservbyname(serv, "tcp"); 01316 if (sptr != 0) 01317 { 01318 int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); 01319 if (rc < 0) 01320 return EAI_MEMORY; 01321 num_found += rc; 01322 } 01323 } 01324 if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) 01325 { 01326 servent* sptr = getservbyname(serv, "udp"); 01327 if (sptr != 0) 01328 { 01329 int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); 01330 if (rc < 0) 01331 return EAI_MEMORY; 01332 num_found += rc; 01333 } 01334 } 01335 } 01336 01337 if (num_found == 0) 01338 { 01339 if (hints->ai_socktype == 0) 01340 { 01341 // All calls to getservbyname() failed. 01342 return EAI_NONAME; 01343 } 01344 else 01345 { 01346 // Service not supported for socket type. 01347 return EAI_SERVICE; 01348 } 01349 } 01350 01351 return 0; 01352 } 01353 01354 inline int gai_echeck(const char* host, const char* service, 01355 int flags, int family, int socktype, int protocol) 01356 { 01357 (void)(flags); 01358 (void)(protocol); 01359 01360 // Host or service must be specified. 01361 if (host == 0 || host[0] == '\0') 01362 if (service == 0 || service[0] == '\0') 01363 return EAI_NONAME; 01364 01365 // Check combination of family and socket type. 01366 switch (family) 01367 { 01368 case AF_UNSPEC: 01369 break; 01370 case AF_INET: 01371 case AF_INET6: 01372 if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) 01373 return EAI_SOCKTYPE; 01374 break; 01375 default: 01376 return EAI_FAMILY; 01377 } 01378 01379 return 0; 01380 } 01381 01382 inline void freeaddrinfo_emulation(addrinfo_type* aihead) 01383 { 01384 addrinfo_type* ai = aihead; 01385 while (ai) 01386 { 01387 gai_free(ai->ai_addr); 01388 gai_free(ai->ai_canonname); 01389 addrinfo_type* ainext = ai->ai_next; 01390 gai_free(ai); 01391 ai = ainext; 01392 } 01393 } 01394 01395 inline int getaddrinfo_emulation(const char* host, const char* service, 01396 const addrinfo_type* hintsp, addrinfo_type** result) 01397 { 01398 // Set up linked list of addrinfo structures. 01399 addrinfo_type* aihead = 0; 01400 addrinfo_type** ainext = &aihead; 01401 char* canon = 0; 01402 01403 // Supply default hints if not specified by caller. 01404 addrinfo_type hints = addrinfo_type(); 01405 hints.ai_family = AF_UNSPEC; 01406 if (hintsp) 01407 hints = *hintsp; 01408 01409 // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED 01410 // and AI_ALL flags. 01411 #if defined(AI_V4MAPPED) 01412 if (hints.ai_family != AF_INET6) 01413 hints.ai_flags &= ~AI_V4MAPPED; 01414 #endif 01415 #if defined(AI_ALL) 01416 if (hints.ai_family != AF_INET6) 01417 hints.ai_flags &= ~AI_ALL; 01418 #endif 01419 01420 // Basic error checking. 01421 int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, 01422 hints.ai_socktype, hints.ai_protocol); 01423 if (rc != 0) 01424 { 01425 freeaddrinfo_emulation(aihead); 01426 return rc; 01427 } 01428 01429 gai_search search[2]; 01430 int search_count = gai_nsearch(host, &hints, search); 01431 for (gai_search* sptr = search; sptr < search + search_count; ++sptr) 01432 { 01433 // Check for IPv4 dotted decimal string. 01434 in4_addr_type inaddr; 01435 asio::error_code ec; 01436 if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1) 01437 { 01438 if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) 01439 { 01440 freeaddrinfo_emulation(aihead); 01441 gai_free(canon); 01442 return EAI_FAMILY; 01443 } 01444 if (sptr->family == AF_INET) 01445 { 01446 rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET); 01447 if (rc != 0) 01448 { 01449 freeaddrinfo_emulation(aihead); 01450 gai_free(canon); 01451 return rc; 01452 } 01453 } 01454 continue; 01455 } 01456 01457 // Check for IPv6 hex string. 01458 in6_addr_type in6addr; 01459 if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1) 01460 { 01461 if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) 01462 { 01463 freeaddrinfo_emulation(aihead); 01464 gai_free(canon); 01465 return EAI_FAMILY; 01466 } 01467 if (sptr->family == AF_INET6) 01468 { 01469 rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6); 01470 if (rc != 0) 01471 { 01472 freeaddrinfo_emulation(aihead); 01473 gai_free(canon); 01474 return rc; 01475 } 01476 } 01477 continue; 01478 } 01479 01480 // Look up hostname. 01481 hostent hent; 01482 char hbuf[8192] = ""; 01483 hostent* hptr = socket_ops::gethostbyname(sptr->host, 01484 sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); 01485 if (hptr == 0) 01486 { 01487 if (search_count == 2) 01488 { 01489 // Failure is OK if there are multiple searches. 01490 continue; 01491 } 01492 freeaddrinfo_emulation(aihead); 01493 gai_free(canon); 01494 if (ec == asio::error::host_not_found) 01495 return EAI_NONAME; 01496 if (ec == asio::error::host_not_found_try_again) 01497 return EAI_AGAIN; 01498 if (ec == asio::error::no_recovery) 01499 return EAI_FAIL; 01500 if (ec == asio::error::no_data) 01501 return EAI_NONAME; 01502 return EAI_NONAME; 01503 } 01504 01505 // Check for address family mismatch if one was specified. 01506 if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype) 01507 { 01508 freeaddrinfo_emulation(aihead); 01509 gai_free(canon); 01510 socket_ops::freehostent(hptr); 01511 return EAI_FAMILY; 01512 } 01513 01514 // Save canonical name first time. 01515 if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] 01516 && (hints.ai_flags & AI_CANONNAME) && canon == 0) 01517 { 01518 std::size_t canon_len = strlen(hptr->h_name) + 1; 01519 canon = gai_alloc<char>(canon_len); 01520 if (canon == 0) 01521 { 01522 freeaddrinfo_emulation(aihead); 01523 socket_ops::freehostent(hptr); 01524 return EAI_MEMORY; 01525 } 01526 gai_strcpy(canon, hptr->h_name, canon_len); 01527 } 01528 01529 // Create an addrinfo structure for each returned address. 01530 for (char** ap = hptr->h_addr_list; *ap; ++ap) 01531 { 01532 rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); 01533 if (rc != 0) 01534 { 01535 freeaddrinfo_emulation(aihead); 01536 gai_free(canon); 01537 socket_ops::freehostent(hptr); 01538 return EAI_FAMILY; 01539 } 01540 } 01541 01542 socket_ops::freehostent(hptr); 01543 } 01544 01545 // Check if we found anything. 01546 if (aihead == 0) 01547 { 01548 gai_free(canon); 01549 return EAI_NONAME; 01550 } 01551 01552 // Return canonical name in first entry. 01553 if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) 01554 { 01555 if (canon) 01556 { 01557 aihead->ai_canonname = canon; 01558 canon = 0; 01559 } 01560 else 01561 { 01562 std::size_t canonname_len = strlen(search[0].host) + 1; 01563 aihead->ai_canonname = gai_alloc<char>(canonname_len); 01564 if (aihead->ai_canonname == 0) 01565 { 01566 freeaddrinfo_emulation(aihead); 01567 return EAI_MEMORY; 01568 } 01569 gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); 01570 } 01571 } 01572 gai_free(canon); 01573 01574 // Process the service name. 01575 if (service != 0 && service[0] != '\0') 01576 { 01577 rc = gai_serv(aihead, &hints, service); 01578 if (rc != 0) 01579 { 01580 freeaddrinfo_emulation(aihead); 01581 return rc; 01582 } 01583 } 01584 01585 // Return result to caller. 01586 *result = aihead; 01587 return 0; 01588 } 01589 01590 inline asio::error_code getnameinfo_emulation( 01591 const socket_addr_type* sa, std::size_t salen, char* host, 01592 std::size_t hostlen, char* serv, std::size_t servlen, int flags, 01593 asio::error_code& ec) 01594 { 01595 using namespace std; 01596 01597 const char* addr; 01598 size_t addr_len; 01599 unsigned short port; 01600 switch (sa->sa_family) 01601 { 01602 case AF_INET: 01603 if (salen != sizeof(sockaddr_in4_type)) 01604 { 01605 return ec = asio::error::invalid_argument; 01606 } 01607 addr = reinterpret_cast<const char*>( 01608 &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr); 01609 addr_len = sizeof(in4_addr_type); 01610 port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port; 01611 break; 01612 case AF_INET6: 01613 if (salen != sizeof(sockaddr_in6_type)) 01614 { 01615 return ec = asio::error::invalid_argument; 01616 } 01617 addr = reinterpret_cast<const char*>( 01618 &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr); 01619 addr_len = sizeof(in6_addr_type); 01620 port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port; 01621 break; 01622 default: 01623 return ec = asio::error::address_family_not_supported; 01624 } 01625 01626 if (host && hostlen > 0) 01627 { 01628 if (flags & NI_NUMERICHOST) 01629 { 01630 if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) 01631 { 01632 return ec; 01633 } 01634 } 01635 else 01636 { 01637 hostent hent; 01638 char hbuf[8192] = ""; 01639 hostent* hptr = socket_ops::gethostbyaddr(addr, 01640 static_cast<int>(addr_len), sa->sa_family, 01641 &hent, hbuf, sizeof(hbuf), ec); 01642 if (hptr && hptr->h_name && hptr->h_name[0] != '\0') 01643 { 01644 if (flags & NI_NOFQDN) 01645 { 01646 char* dot = strchr(hptr->h_name, '.'); 01647 if (dot) 01648 { 01649 *dot = 0; 01650 } 01651 } 01652 gai_strcpy(host, hptr->h_name, hostlen); 01653 socket_ops::freehostent(hptr); 01654 } 01655 else 01656 { 01657 socket_ops::freehostent(hptr); 01658 if (flags & NI_NAMEREQD) 01659 { 01660 return ec = asio::error::host_not_found; 01661 } 01662 if (socket_ops::inet_ntop(sa->sa_family, 01663 addr, host, hostlen, 0, ec) == 0) 01664 { 01665 return ec; 01666 } 01667 } 01668 } 01669 } 01670 01671 if (serv && servlen > 0) 01672 { 01673 if (flags & NI_NUMERICSERV) 01674 { 01675 if (servlen < 6) 01676 { 01677 return ec = asio::error::no_buffer_space; 01678 } 01679 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) 01680 sprintf_s(serv, servlen, "%u", ntohs(port)); 01681 #else 01682 sprintf(serv, "%u", ntohs(port)); 01683 #endif 01684 } 01685 else 01686 { 01687 #if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) 01688 static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 01689 ::pthread_mutex_lock(&mutex); 01690 #endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) 01691 servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); 01692 if (sptr && sptr->s_name && sptr->s_name[0] != '\0') 01693 { 01694 gai_strcpy(serv, sptr->s_name, servlen); 01695 } 01696 else 01697 { 01698 if (servlen < 6) 01699 { 01700 return ec = asio::error::no_buffer_space; 01701 } 01702 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) 01703 sprintf_s(serv, servlen, "%u", ntohs(port)); 01704 #else 01705 sprintf(serv, "%u", ntohs(port)); 01706 #endif 01707 } 01708 #if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) 01709 ::pthread_mutex_unlock(&mutex); 01710 #endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) 01711 } 01712 } 01713 01714 clear_error(ec); 01715 return ec; 01716 } 01717 01718 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) 01719 // || defined(__MACH__) && defined(__APPLE__) 01720 01721 inline asio::error_code translate_addrinfo_error(int error) 01722 { 01723 switch (error) 01724 { 01725 case 0: 01726 return asio::error_code(); 01727 case EAI_AGAIN: 01728 return asio::error::host_not_found_try_again; 01729 case EAI_BADFLAGS: 01730 return asio::error::invalid_argument; 01731 case EAI_FAIL: 01732 return asio::error::no_recovery; 01733 case EAI_FAMILY: 01734 return asio::error::address_family_not_supported; 01735 case EAI_MEMORY: 01736 return asio::error::no_memory; 01737 case EAI_NONAME: 01738 #if defined(EAI_ADDRFAMILY) 01739 case EAI_ADDRFAMILY: 01740 #endif 01741 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) 01742 case EAI_NODATA: 01743 #endif 01744 return asio::error::host_not_found; 01745 case EAI_SERVICE: 01746 return asio::error::service_not_found; 01747 case EAI_SOCKTYPE: 01748 return asio::error::socket_type_not_supported; 01749 default: // Possibly the non-portable EAI_SYSTEM. 01750 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 01751 return asio::error_code( 01752 WSAGetLastError(), asio::error::get_system_category()); 01753 #else 01754 return asio::error_code( 01755 errno, asio::error::get_system_category()); 01756 #endif 01757 } 01758 } 01759 01760 inline asio::error_code getaddrinfo(const char* host, 01761 const char* service, const addrinfo_type* hints, addrinfo_type** result, 01762 asio::error_code& ec) 01763 { 01764 clear_error(ec); 01765 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 01766 # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) 01767 // Building for Windows XP, Windows Server 2003, or later. 01768 int error = ::getaddrinfo(host, service, hints, result); 01769 return ec = translate_addrinfo_error(error); 01770 # else 01771 // Building for Windows 2000 or earlier. 01772 typedef int (WSAAPI *gai_t)(const char*, 01773 const char*, const addrinfo_type*, addrinfo_type**); 01774 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) 01775 { 01776 if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) 01777 { 01778 int error = gai(host, service, hints, result); 01779 return ec = translate_addrinfo_error(error); 01780 } 01781 } 01782 int error = getaddrinfo_emulation(host, service, hints, result); 01783 return ec = translate_addrinfo_error(error); 01784 # endif 01785 #elif defined(__MACH__) && defined(__APPLE__) 01786 int error = getaddrinfo_emulation(host, service, hints, result); 01787 return ec = translate_addrinfo_error(error); 01788 #else 01789 int error = ::getaddrinfo(host, service, hints, result); 01790 return ec = translate_addrinfo_error(error); 01791 #endif 01792 } 01793 01794 inline void freeaddrinfo(addrinfo_type* ai) 01795 { 01796 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 01797 # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) 01798 // Building for Windows XP, Windows Server 2003, or later. 01799 ::freeaddrinfo(ai); 01800 # else 01801 // Building for Windows 2000 or earlier. 01802 typedef int (WSAAPI *fai_t)(addrinfo_type*); 01803 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) 01804 { 01805 if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) 01806 { 01807 fai(ai); 01808 return; 01809 } 01810 } 01811 freeaddrinfo_emulation(ai); 01812 # endif 01813 #elif defined(__MACH__) && defined(__APPLE__) 01814 freeaddrinfo_emulation(ai); 01815 #else 01816 ::freeaddrinfo(ai); 01817 #endif 01818 } 01819 01820 inline asio::error_code getnameinfo(const socket_addr_type* addr, 01821 std::size_t addrlen, char* host, std::size_t hostlen, 01822 char* serv, std::size_t servlen, int flags, asio::error_code& ec) 01823 { 01824 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 01825 # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) 01826 // Building for Windows XP, Windows Server 2003, or later. 01827 clear_error(ec); 01828 int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen), 01829 host, static_cast<DWORD>(hostlen), 01830 serv, static_cast<DWORD>(servlen), flags); 01831 return ec = translate_addrinfo_error(error); 01832 # else 01833 // Building for Windows 2000 or earlier. 01834 typedef int (WSAAPI *gni_t)(const socket_addr_type*, 01835 int, char*, DWORD, char*, DWORD, int); 01836 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) 01837 { 01838 if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) 01839 { 01840 clear_error(ec); 01841 int error = gni(addr, static_cast<int>(addrlen), 01842 host, static_cast<DWORD>(hostlen), 01843 serv, static_cast<DWORD>(servlen), flags); 01844 return ec = translate_addrinfo_error(error); 01845 } 01846 } 01847 clear_error(ec); 01848 return getnameinfo_emulation(addr, addrlen, 01849 host, hostlen, serv, servlen, flags, ec); 01850 # endif 01851 #elif defined(__MACH__) && defined(__APPLE__) 01852 using namespace std; // For memcpy. 01853 sockaddr_storage_type tmp_addr; 01854 memcpy(&tmp_addr, addr, addrlen); 01855 tmp_addr.ss_len = addrlen; 01856 addr = reinterpret_cast<socket_addr_type*>(&tmp_addr); 01857 clear_error(ec); 01858 return getnameinfo_emulation(addr, addrlen, 01859 host, hostlen, serv, servlen, flags, ec); 01860 #else 01861 clear_error(ec); 01862 int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); 01863 return ec = translate_addrinfo_error(error); 01864 #endif 01865 } 01866 01867 inline u_long_type network_to_host_long(u_long_type value) 01868 { 01869 return ntohl(value); 01870 } 01871 01872 inline u_long_type host_to_network_long(u_long_type value) 01873 { 01874 return htonl(value); 01875 } 01876 01877 inline u_short_type network_to_host_short(u_short_type value) 01878 { 01879 return ntohs(value); 01880 } 01881 01882 inline u_short_type host_to_network_short(u_short_type value) 01883 { 01884 return htons(value); 01885 } 01886 01887 } // namespace socket_ops 01888 } // namespace detail 01889 } // namespace asio 01890 01891 #include "asio/detail/pop_options.hpp" 01892 01893 #endif // ASIO_DETAIL_SOCKET_OPS_HPP