00001
00002
00003
00004
00005
00006
00007
00008
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
00044
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
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
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
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
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
00384
00385
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
00436
00437
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
00485
00486
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
00501
00502
00503
00504
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
00521
00522
00523
00524
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
00542
00543
00544
00545
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;
00625 ::Sleep(milliseconds);
00626 ec = asio::error_code();
00627 return 0;
00628 }
00629
00630
00631
00632
00633
00634
00635
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;
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
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
00754 if (result != socket_error_retval)
00755 clear_error(ec);
00756
00757
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;
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;
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
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
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;
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
00883
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
01024
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
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
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
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
01239 }
01240 }
01241 else if (ai->ai_socktype != socktype)
01242 {
01243
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
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
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
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
01342 return EAI_NONAME;
01343 }
01344 else
01345 {
01346
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
01361 if (host == 0 || host[0] == '\0')
01362 if (service == 0 || service[0] == '\0')
01363 return EAI_NONAME;
01364
01365
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
01399 addrinfo_type* aihead = 0;
01400 addrinfo_type** ainext = &aihead;
01401 char* canon = 0;
01402
01403
01404 addrinfo_type hints = addrinfo_type();
01405 hints.ai_family = AF_UNSPEC;
01406 if (hintsp)
01407 hints = *hintsp;
01408
01409
01410
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
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
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
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
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
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
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
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
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
01546 if (aihead == 0)
01547 {
01548 gai_free(canon);
01549 return EAI_NONAME;
01550 }
01551
01552
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
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
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
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:
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
01768 int error = ::getaddrinfo(host, service, hints, result);
01769 return ec = translate_addrinfo_error(error);
01770 # else
01771
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
01799 ::freeaddrinfo(ai);
01800 # else
01801
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
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
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;
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 }
01888 }
01889 }
01890
01891 #include "asio/detail/pop_options.hpp"
01892
01893 #endif // ASIO_DETAIL_SOCKET_OPS_HPP