socket_ops.hpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines


Castor
Author(s): Carpe Noctem
autogenerated on Fri Nov 8 2013 11:05:39