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 #if defined(__MACH__) && defined(__APPLE__)
00030 # include <AvailabilityMacros.h>
00031 #endif // defined(__MACH__) && defined(__APPLE__)
00032 #include "asio/detail/pop_options.hpp"
00033
00034 #include "asio/error.hpp"
00035 #include "asio/detail/socket_types.hpp"
00036
00037 namespace asio {
00038 namespace detail {
00039 namespace socket_ops {
00040
00041 inline void clear_error(asio::error_code& ec)
00042 {
00043 errno = 0;
00044 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00045 WSASetLastError(0);
00046 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00047 ec = asio::error_code();
00048 }
00049
00050 template <typename ReturnType>
00051 inline ReturnType error_wrapper(ReturnType return_value,
00052 asio::error_code& ec)
00053 {
00054 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00055 ec = asio::error_code(WSAGetLastError(), asio::native_ecat);
00056 #else
00057 ec = asio::error_code(errno, asio::native_ecat);
00058 #endif
00059 return return_value;
00060 }
00061
00062 inline socket_type accept(socket_type s, socket_addr_type* addr,
00063 socket_addr_len_type* addrlen, asio::error_code& ec)
00064 {
00065 clear_error(ec);
00066 #if defined(__MACH__) && defined(__APPLE__)
00067 socket_type new_s = error_wrapper(::accept(s, addr, addrlen), ec);
00068 if (new_s == invalid_socket)
00069 return new_s;
00070
00071 int optval = 1;
00072 int result = error_wrapper(::setsockopt(new_s,
00073 SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
00074 if (result != 0)
00075 {
00076 ::close(new_s);
00077 return invalid_socket;
00078 }
00079
00080 return new_s;
00081 #else
00082 return error_wrapper(::accept(s, addr, addrlen), ec);
00083 #endif
00084 }
00085
00086 inline int bind(socket_type s, const socket_addr_type* addr,
00087 socket_addr_len_type addrlen, asio::error_code& ec)
00088 {
00089 clear_error(ec);
00090 return error_wrapper(::bind(s, addr, addrlen), ec);
00091 }
00092
00093 inline int close(socket_type s, asio::error_code& ec)
00094 {
00095 clear_error(ec);
00096 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00097 return error_wrapper(::closesocket(s), ec);
00098 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00099 return error_wrapper(::close(s), ec);
00100 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00101 }
00102
00103 inline int shutdown(socket_type s, int what, asio::error_code& ec)
00104 {
00105 clear_error(ec);
00106 return error_wrapper(::shutdown(s, what), ec);
00107 }
00108
00109 inline int connect(socket_type s, const socket_addr_type* addr,
00110 socket_addr_len_type addrlen, asio::error_code& ec)
00111 {
00112 clear_error(ec);
00113 return error_wrapper(::connect(s, addr, addrlen), ec);
00114 }
00115
00116 inline int listen(socket_type s, int backlog, asio::error_code& ec)
00117 {
00118 clear_error(ec);
00119 return error_wrapper(::listen(s, backlog), ec);
00120 }
00121
00122 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00123 typedef WSABUF buf;
00124 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00125 typedef iovec buf;
00126 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00127
00128 inline void init_buf(buf& b, void* data, size_t size)
00129 {
00130 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00131 b.buf = static_cast<char*>(data);
00132 b.len = static_cast<u_long>(size);
00133 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00134 b.iov_base = data;
00135 b.iov_len = size;
00136 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00137 }
00138
00139 inline void init_buf(buf& b, const void* data, size_t size)
00140 {
00141 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00142 b.buf = static_cast<char*>(const_cast<void*>(data));
00143 b.len = static_cast<u_long>(size);
00144 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00145 b.iov_base = const_cast<void*>(data);
00146 b.iov_len = size;
00147 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00148 }
00149
00150 inline int recv(socket_type s, buf* bufs, size_t count, int flags,
00151 asio::error_code& ec)
00152 {
00153 clear_error(ec);
00154 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00155
00156 DWORD recv_buf_count = static_cast<DWORD>(count);
00157 DWORD bytes_transferred = 0;
00158 DWORD recv_flags = flags;
00159 int result = error_wrapper(::WSARecv(s, bufs,
00160 recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec);
00161 if (result != 0)
00162 return -1;
00163 return bytes_transferred;
00164 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00165 msghdr msg;
00166 msg.msg_name = 0;
00167 msg.msg_namelen = 0;
00168 msg.msg_iov = bufs;
00169 msg.msg_iovlen = count;
00170 msg.msg_control = 0;
00171 msg.msg_controllen = 0;
00172 msg.msg_flags = 0;
00173 return error_wrapper(::recvmsg(s, &msg, flags), ec);
00174 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00175 }
00176
00177 inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
00178 socket_addr_type* addr, socket_addr_len_type* addrlen,
00179 asio::error_code& ec)
00180 {
00181 clear_error(ec);
00182 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00183
00184 DWORD recv_buf_count = static_cast<DWORD>(count);
00185 DWORD bytes_transferred = 0;
00186 DWORD recv_flags = flags;
00187 int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count,
00188 &bytes_transferred, &recv_flags, addr, addrlen, 0, 0), ec);
00189 if (result != 0)
00190 return -1;
00191 return bytes_transferred;
00192 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00193 msghdr msg;
00194 #if defined(__MACH__) && defined(__APPLE__) \
00195 && (MAC_OS_X_VERSION_MAX_ALLOWED < 1040)
00196 msg.msg_name = reinterpret_cast<char*>(addr);
00197 #else
00198 msg.msg_name = addr;
00199 #endif
00200 msg.msg_namelen = *addrlen;
00201 msg.msg_iov = bufs;
00202 msg.msg_iovlen = count;
00203 msg.msg_control = 0;
00204 msg.msg_controllen = 0;
00205 msg.msg_flags = 0;
00206 int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
00207 *addrlen = msg.msg_namelen;
00208 return result;
00209 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00210 }
00211
00212 inline int send(socket_type s, const buf* bufs, size_t count, int flags,
00213 asio::error_code& ec)
00214 {
00215 clear_error(ec);
00216 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00217
00218 DWORD send_buf_count = static_cast<DWORD>(count);
00219 DWORD bytes_transferred = 0;
00220 DWORD send_flags = flags;
00221 int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs),
00222 send_buf_count, &bytes_transferred, send_flags, 0, 0), ec);
00223 if (result != 0)
00224 return -1;
00225 return bytes_transferred;
00226 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00227 msghdr msg;
00228 msg.msg_name = 0;
00229 msg.msg_namelen = 0;
00230 msg.msg_iov = const_cast<buf*>(bufs);
00231 msg.msg_iovlen = count;
00232 msg.msg_control = 0;
00233 msg.msg_controllen = 0;
00234 msg.msg_flags = 0;
00235 #if defined(__linux__)
00236 flags |= MSG_NOSIGNAL;
00237 #endif // defined(__linux__)
00238 return error_wrapper(::sendmsg(s, &msg, flags), ec);
00239 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00240 }
00241
00242 inline int sendto(socket_type s, const buf* bufs, size_t count, int flags,
00243 const socket_addr_type* addr, socket_addr_len_type addrlen,
00244 asio::error_code& ec)
00245 {
00246 clear_error(ec);
00247 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00248
00249 DWORD send_buf_count = static_cast<DWORD>(count);
00250 DWORD bytes_transferred = 0;
00251 int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs),
00252 send_buf_count, &bytes_transferred, flags, addr, addrlen, 0, 0), ec);
00253 if (result != 0)
00254 return -1;
00255 return bytes_transferred;
00256 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00257 msghdr msg;
00258 #if defined(__MACH__) && defined(__APPLE__) \
00259 && (MAC_OS_X_VERSION_MAX_ALLOWED < 1040)
00260 msg.msg_name = reinterpret_cast<char*>(const_cast<socket_addr_type*>(addr));
00261 #else
00262 msg.msg_name = const_cast<socket_addr_type*>(addr);
00263 #endif
00264 msg.msg_namelen = addrlen;
00265 msg.msg_iov = const_cast<buf*>(bufs);
00266 msg.msg_iovlen = count;
00267 msg.msg_control = 0;
00268 msg.msg_controllen = 0;
00269 msg.msg_flags = 0;
00270 #if defined(__linux__)
00271 flags |= MSG_NOSIGNAL;
00272 #endif // defined(__linux__)
00273 return error_wrapper(::sendmsg(s, &msg, flags), ec);
00274 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00275 }
00276
00277 inline socket_type socket(int af, int type, int protocol,
00278 asio::error_code& ec)
00279 {
00280 clear_error(ec);
00281 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00282 socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0,
00283 WSA_FLAG_OVERLAPPED), ec);
00284 if (s == invalid_socket)
00285 return s;
00286
00287 if (af == AF_INET6)
00288 {
00289
00290
00291
00292 DWORD optval = 0;
00293 ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
00294 reinterpret_cast<const char*>(&optval), sizeof(optval));
00295 }
00296
00297 return s;
00298 #elif defined(__MACH__) && defined(__APPLE__)
00299 socket_type s = error_wrapper(::socket(af, type, protocol), ec);
00300 if (s == invalid_socket)
00301 return s;
00302
00303 int optval = 1;
00304 int result = error_wrapper(::setsockopt(s,
00305 SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
00306 if (result != 0)
00307 {
00308 ::close(s);
00309 return invalid_socket;
00310 }
00311
00312 return s;
00313 #else
00314 return error_wrapper(::socket(af, type, protocol), ec);
00315 #endif
00316 }
00317
00318 inline int setsockopt(socket_type s, int level, int optname,
00319 const void* optval, size_t optlen, asio::error_code& ec)
00320 {
00321 clear_error(ec);
00322 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00323 return error_wrapper(::setsockopt(s, level, optname,
00324 reinterpret_cast<const char*>(optval), static_cast<int>(optlen)), ec);
00325 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00326 return error_wrapper(::setsockopt(s, level, optname, optval,
00327 static_cast<socklen_t>(optlen)), ec);
00328 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00329 }
00330
00331 inline int getsockopt(socket_type s, int level, int optname, void* optval,
00332 size_t* optlen, asio::error_code& ec)
00333 {
00334 clear_error(ec);
00335 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00336 int tmp_optlen = static_cast<int>(*optlen);
00337 int result = error_wrapper(::getsockopt(s, level, optname,
00338 reinterpret_cast<char*>(optval), &tmp_optlen), ec);
00339 *optlen = static_cast<size_t>(tmp_optlen);
00340 if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
00341 && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
00342 {
00343
00344
00345
00346
00347
00348 *static_cast<DWORD*>(optval) = 1;
00349 clear_error(ec);
00350 }
00351 return result;
00352 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00353 socklen_t tmp_optlen = static_cast<socklen_t>(*optlen);
00354 int result = error_wrapper(::getsockopt(s, level, optname,
00355 optval, &tmp_optlen), ec);
00356 *optlen = static_cast<size_t>(tmp_optlen);
00357 #if defined(__linux__)
00358 if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
00359 && (optname == SO_SNDBUF || optname == SO_RCVBUF))
00360 {
00361
00362
00363
00364
00365
00366 *static_cast<int*>(optval) /= 2;
00367 }
00368 #endif // defined(__linux__)
00369 return result;
00370 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00371 }
00372
00373 inline int getpeername(socket_type s, socket_addr_type* addr,
00374 socket_addr_len_type* addrlen, asio::error_code& ec)
00375 {
00376 clear_error(ec);
00377 return error_wrapper(::getpeername(s, addr, addrlen), ec);
00378 }
00379
00380 inline int getsockname(socket_type s, socket_addr_type* addr,
00381 socket_addr_len_type* addrlen, asio::error_code& ec)
00382 {
00383 clear_error(ec);
00384 return error_wrapper(::getsockname(s, addr, addrlen), ec);
00385 }
00386
00387 inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg,
00388 asio::error_code& ec)
00389 {
00390 clear_error(ec);
00391 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00392 return error_wrapper(::ioctlsocket(s, cmd, arg), ec);
00393 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00394 return error_wrapper(::ioctl(s, cmd, arg), ec);
00395 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00396 }
00397
00398 inline int select(int nfds, fd_set* readfds, fd_set* writefds,
00399 fd_set* exceptfds, timeval* timeout, asio::error_code& ec)
00400 {
00401 clear_error(ec);
00402 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00403 if (!readfds && !writefds && !exceptfds && timeout)
00404 {
00405 DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
00406 if (milliseconds == 0)
00407 milliseconds = 1;
00408 ::Sleep(milliseconds);
00409 ec = asio::error_code();
00410 return 0;
00411 }
00412
00413
00414
00415
00416
00417
00418
00419 if (timeout && timeout->tv_sec == 0
00420 && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
00421 timeout->tv_usec = 1000;
00422 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00423 return error_wrapper(::select(nfds, readfds,
00424 writefds, exceptfds, timeout), ec);
00425 }
00426
00427 inline int poll_read(socket_type s, asio::error_code& ec)
00428 {
00429 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00430 FD_SET fds;
00431 FD_ZERO(&fds);
00432 FD_SET(s, &fds);
00433 clear_error(ec);
00434 return error_wrapper(::select(s, &fds, 0, 0, 0), ec);
00435 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00436 pollfd fds;
00437 fds.fd = s;
00438 fds.events = POLLIN;
00439 fds.revents = 0;
00440 clear_error(ec);
00441 return error_wrapper(::poll(&fds, 1, -1), ec);
00442 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00443 }
00444
00445 inline int poll_write(socket_type s, asio::error_code& ec)
00446 {
00447 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00448 FD_SET fds;
00449 FD_ZERO(&fds);
00450 FD_SET(s, &fds);
00451 clear_error(ec);
00452 return error_wrapper(::select(s, 0, &fds, 0, 0), ec);
00453 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00454 pollfd fds;
00455 fds.fd = s;
00456 fds.events = POLLOUT;
00457 fds.revents = 0;
00458 clear_error(ec);
00459 return error_wrapper(::poll(&fds, 1, -1), ec);
00460 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00461 }
00462
00463 inline const char* inet_ntop(int af, const void* src, char* dest, size_t length,
00464 unsigned long scope_id, asio::error_code& ec)
00465 {
00466 clear_error(ec);
00467 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00468 using namespace std;
00469
00470 if (af != AF_INET && af != AF_INET6)
00471 {
00472 ec = asio::error::address_family_not_supported;
00473 return 0;
00474 }
00475
00476 sockaddr_storage_type address;
00477 DWORD address_length;
00478 if (af == AF_INET)
00479 {
00480 address_length = sizeof(sockaddr_in4_type);
00481 sockaddr_in4_type* ipv4_address =
00482 reinterpret_cast<sockaddr_in4_type*>(&address);
00483 ipv4_address->sin_family = AF_INET;
00484 ipv4_address->sin_port = 0;
00485 memcpy(&ipv4_address->sin_addr, src, sizeof(in4_addr_type));
00486 }
00487 else
00488 {
00489 address_length = sizeof(sockaddr_in6_type);
00490 sockaddr_in6_type* ipv6_address =
00491 reinterpret_cast<sockaddr_in6_type*>(&address);
00492 ipv6_address->sin6_family = AF_INET6;
00493 ipv6_address->sin6_port = 0;
00494 ipv6_address->sin6_flowinfo = 0;
00495 ipv6_address->sin6_scope_id = scope_id;
00496 memcpy(&ipv6_address->sin6_addr, src, sizeof(in6_addr_type));
00497 }
00498
00499 DWORD string_length = static_cast<DWORD>(length);
00500 int result = error_wrapper(::WSAAddressToStringA(
00501 reinterpret_cast<sockaddr*>(&address),
00502 address_length, 0, dest, &string_length), ec);
00503
00504
00505 if (result != socket_error_retval)
00506 clear_error(ec);
00507
00508
00509 else if (result == socket_error_retval && !ec)
00510 ec = asio::error::invalid_argument;
00511
00512 return result == socket_error_retval ? 0 : dest;
00513 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00514 const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec);
00515 if (result == 0 && !ec)
00516 ec = asio::error::invalid_argument;
00517 if (result != 0 && af == AF_INET6 && scope_id != 0)
00518 {
00519 using namespace std;
00520 char if_name[IF_NAMESIZE + 1] = "%";
00521 const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);
00522 bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
00523 if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0)
00524 sprintf(if_name + 1, "%lu", scope_id);
00525 strcat(dest, if_name);
00526 }
00527 return result;
00528 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00529 }
00530
00531 inline int inet_pton(int af, const char* src, void* dest,
00532 unsigned long* scope_id, asio::error_code& ec)
00533 {
00534 clear_error(ec);
00535 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00536 using namespace std;
00537
00538 if (af != AF_INET && af != AF_INET6)
00539 {
00540 ec = asio::error::address_family_not_supported;
00541 return -1;
00542 }
00543
00544 sockaddr_storage_type address;
00545 int address_length = sizeof(sockaddr_storage_type);
00546 int result = error_wrapper(::WSAStringToAddressA(
00547 const_cast<char*>(src), af, 0,
00548 reinterpret_cast<sockaddr*>(&address),
00549 &address_length), ec);
00550
00551 if (af == AF_INET)
00552 {
00553 if (result != socket_error_retval)
00554 {
00555 sockaddr_in4_type* ipv4_address =
00556 reinterpret_cast<sockaddr_in4_type*>(&address);
00557 memcpy(dest, &ipv4_address->sin_addr, sizeof(in4_addr_type));
00558 clear_error(ec);
00559 }
00560 else if (strcmp(src, "255.255.255.255") == 0)
00561 {
00562 static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
00563 clear_error(ec);
00564 }
00565 }
00566 else
00567 {
00568 if (result != socket_error_retval)
00569 {
00570 sockaddr_in6_type* ipv6_address =
00571 reinterpret_cast<sockaddr_in6_type*>(&address);
00572 memcpy(dest, &ipv6_address->sin6_addr, sizeof(in6_addr_type));
00573 if (scope_id)
00574 *scope_id = ipv6_address->sin6_scope_id;
00575 clear_error(ec);
00576 }
00577 }
00578
00579
00580 if (result == socket_error_retval && !ec)
00581 ec = asio::error::invalid_argument;
00582
00583 return result == socket_error_retval ? -1 : 1;
00584 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00585 int result = error_wrapper(::inet_pton(af, src, dest), ec);
00586 if (result <= 0 && !ec)
00587 ec = asio::error::invalid_argument;
00588 if (result > 0 && af == AF_INET6 && scope_id)
00589 {
00590 using namespace std;
00591 *scope_id = 0;
00592 if (const char* if_name = strchr(src, '%'))
00593 {
00594 in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
00595 bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
00596 if (is_link_local)
00597 *scope_id = if_nametoindex(if_name + 1);
00598 if (*scope_id == 0)
00599 *scope_id = atoi(if_name + 1);
00600 }
00601 }
00602 return result;
00603 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00604 }
00605
00606 inline int gethostname(char* name, int namelen, asio::error_code& ec)
00607 {
00608 clear_error(ec);
00609 return error_wrapper(::gethostname(name, namelen), ec);
00610 }
00611
00612 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \
00613 || defined(__MACH__) && defined(__APPLE__)
00614
00615
00616
00617
00618 inline asio::error_code translate_netdb_error(int error)
00619 {
00620 switch (error)
00621 {
00622 case 0:
00623 return asio::error_code();
00624 case HOST_NOT_FOUND:
00625 return asio::error::host_not_found;
00626 case TRY_AGAIN:
00627 return asio::error::host_not_found_try_again;
00628 case NO_RECOVERY:
00629 return asio::error::no_recovery;
00630 case NO_DATA:
00631 return asio::error::no_data;
00632 default:
00633 BOOST_ASSERT(false);
00634 return asio::error::invalid_argument;
00635 }
00636 }
00637
00638 inline hostent* gethostbyaddr(const char* addr, int length, int af,
00639 hostent* result, char* buffer, int buflength, asio::error_code& ec)
00640 {
00641 clear_error(ec);
00642 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00643 (void)(buffer);
00644 (void)(buflength);
00645 hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
00646 if (!retval)
00647 return 0;
00648 *result = *retval;
00649 return retval;
00650 #elif defined(__sun) || defined(__QNX__)
00651 int error = 0;
00652 hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result,
00653 buffer, buflength, &error), ec);
00654 if (error)
00655 ec = translate_netdb_error(error);
00656 return retval;
00657 #elif defined(__MACH__) && defined(__APPLE__)
00658 (void)(buffer);
00659 (void)(buflength);
00660 int error = 0;
00661 hostent* retval = error_wrapper(::getipnodebyaddr(
00662 addr, length, af, &error), ec);
00663 if (error)
00664 ec = translate_netdb_error(error);
00665 if (!retval)
00666 return 0;
00667 *result = *retval;
00668 return retval;
00669 #else
00670 hostent* retval = 0;
00671 int error = 0;
00672 error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer,
00673 buflength, &retval, &error), ec);
00674 if (error)
00675 ec = translate_netdb_error(error);
00676 return retval;
00677 #endif
00678 }
00679
00680 inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
00681 char* buffer, int buflength, int ai_flags, asio::error_code& ec)
00682 {
00683 clear_error(ec);
00684 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
00685 (void)(buffer);
00686 (void)(buflength);
00687 (void)(ai_flags);
00688 if (af != AF_INET)
00689 {
00690 ec = asio::error::address_family_not_supported;
00691 return 0;
00692 }
00693 hostent* retval = error_wrapper(::gethostbyname(name), ec);
00694 if (!retval)
00695 return 0;
00696 *result = *retval;
00697 return result;
00698 #elif defined(__sun) || defined(__QNX__)
00699 (void)(ai_flags);
00700 if (af != AF_INET)
00701 {
00702 ec = asio::error::address_family_not_supported;
00703 return 0;
00704 }
00705 int error = 0;
00706 hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer,
00707 buflength, &error), ec);
00708 if (error)
00709 ec = translate_netdb_error(error);
00710 return retval;
00711 #elif defined(__MACH__) && defined(__APPLE__)
00712 (void)(buffer);
00713 (void)(buflength);
00714 int error = 0;
00715 hostent* retval = error_wrapper(::getipnodebyname(
00716 name, af, ai_flags, &error), ec);
00717 if (error)
00718 ec = translate_netdb_error(error);
00719 if (!retval)
00720 return 0;
00721 *result = *retval;
00722 return retval;
00723 #else
00724 (void)(ai_flags);
00725 if (af != AF_INET)
00726 {
00727 ec = asio::error::address_family_not_supported;
00728 return 0;
00729 }
00730 hostent* retval = 0;
00731 int error = 0;
00732 error_wrapper(::gethostbyname_r(name, result,
00733 buffer, buflength, &retval, &error), ec);
00734 if (error)
00735 ec = translate_netdb_error(error);
00736 return retval;
00737 #endif
00738 }
00739
00740 inline void freehostent(hostent* h)
00741 {
00742 #if defined(__MACH__) && defined(__APPLE__)
00743 if (h)
00744 ::freehostent(h);
00745 #else
00746 (void)(h);
00747 #endif
00748 }
00749
00750
00751
00752
00753 struct gai_search
00754 {
00755 const char* host;
00756 int family;
00757 };
00758
00759 inline int gai_nsearch(const char* host,
00760 const addrinfo_type* hints, gai_search (&search)[2])
00761 {
00762 int search_count = 0;
00763 if (host == 0 || host[0] == '\0')
00764 {
00765 if (hints->ai_flags & AI_PASSIVE)
00766 {
00767
00768 switch (hints->ai_family)
00769 {
00770 case AF_INET:
00771 search[search_count].host = "0.0.0.0";
00772 search[search_count].family = AF_INET;
00773 ++search_count;
00774 break;
00775 case AF_INET6:
00776 search[search_count].host = "0::0";
00777 search[search_count].family = AF_INET6;
00778 ++search_count;
00779 break;
00780 case AF_UNSPEC:
00781 search[search_count].host = "0::0";
00782 search[search_count].family = AF_INET6;
00783 ++search_count;
00784 search[search_count].host = "0.0.0.0";
00785 search[search_count].family = AF_INET;
00786 ++search_count;
00787 break;
00788 default:
00789 break;
00790 }
00791 }
00792 else
00793 {
00794
00795 switch (hints->ai_family)
00796 {
00797 case AF_INET:
00798 search[search_count].host = "localhost";
00799 search[search_count].family = AF_INET;
00800 ++search_count;
00801 break;
00802 case AF_INET6:
00803 search[search_count].host = "localhost";
00804 search[search_count].family = AF_INET6;
00805 ++search_count;
00806 break;
00807 case AF_UNSPEC:
00808 search[search_count].host = "localhost";
00809 search[search_count].family = AF_INET6;
00810 ++search_count;
00811 search[search_count].host = "localhost";
00812 search[search_count].family = AF_INET;
00813 ++search_count;
00814 break;
00815 default:
00816 break;
00817 }
00818 }
00819 }
00820 else
00821 {
00822
00823 switch (hints->ai_family)
00824 {
00825 case AF_INET:
00826 search[search_count].host = host;
00827 search[search_count].family = AF_INET;
00828 ++search_count;
00829 break;
00830 case AF_INET6:
00831 search[search_count].host = host;
00832 search[search_count].family = AF_INET6;
00833 ++search_count;
00834 break;
00835 case AF_UNSPEC:
00836 search[search_count].host = host;
00837 search[search_count].family = AF_INET6;
00838 ++search_count;
00839 search[search_count].host = host;
00840 search[search_count].family = AF_INET;
00841 ++search_count;
00842 break;
00843 default:
00844 break;
00845 }
00846 }
00847 return search_count;
00848 }
00849
00850 template <typename T>
00851 inline T* gai_alloc(std::size_t size = sizeof(T))
00852 {
00853 using namespace std;
00854 T* p = static_cast<T*>(::operator new(size, std::nothrow));
00855 if (p)
00856 memset(p, 0, size);
00857 return p;
00858 }
00859
00860 inline void gai_free(void* p)
00861 {
00862 ::operator delete(p);
00863 }
00864
00865 enum { gai_clone_flag = 1 << 30 };
00866
00867 inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,
00868 const void* addr, int family)
00869 {
00870 using namespace std;
00871
00872 addrinfo_type* ai = gai_alloc<addrinfo_type>();
00873 if (ai == 0)
00874 return EAI_MEMORY;
00875
00876 ai->ai_next = 0;
00877 **next = ai;
00878 *next = &ai->ai_next;
00879
00880 ai->ai_canonname = 0;
00881 ai->ai_socktype = hints->ai_socktype;
00882 if (ai->ai_socktype == 0)
00883 ai->ai_flags |= gai_clone_flag;
00884 ai->ai_protocol = hints->ai_protocol;
00885 ai->ai_family = family;
00886
00887 switch (ai->ai_family)
00888 {
00889 case AF_INET:
00890 {
00891 sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
00892 if (sinptr == 0)
00893 return EAI_MEMORY;
00894 sinptr->sin_family = AF_INET;
00895 memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));
00896 ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);
00897 ai->ai_addrlen = sizeof(sockaddr_in4_type);
00898 break;
00899 }
00900 case AF_INET6:
00901 {
00902 sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
00903 if (sin6ptr == 0)
00904 return EAI_MEMORY;
00905 sin6ptr->sin6_family = AF_INET6;
00906 memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));
00907 ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);
00908 ai->ai_addrlen = sizeof(sockaddr_in6_type);
00909 break;
00910 }
00911 default:
00912 break;
00913 }
00914
00915 return 0;
00916 }
00917
00918 inline addrinfo_type* gai_clone(addrinfo_type* ai)
00919 {
00920 using namespace std;
00921
00922 addrinfo_type* new_ai = gai_alloc<addrinfo_type>();
00923 if (new_ai == 0)
00924 return new_ai;
00925
00926 new_ai->ai_next = ai->ai_next;
00927 ai->ai_next = new_ai;
00928
00929 new_ai->ai_flags = 0;
00930 new_ai->ai_family = ai->ai_family;
00931 new_ai->ai_socktype = ai->ai_socktype;
00932 new_ai->ai_protocol = ai->ai_protocol;
00933 new_ai->ai_canonname = 0;
00934 new_ai->ai_addrlen = ai->ai_addrlen;
00935 new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);
00936 memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);
00937
00938 return new_ai;
00939 }
00940
00941 inline int gai_port(addrinfo_type* aihead, int port, int socktype)
00942 {
00943 int num_found = 0;
00944
00945 for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)
00946 {
00947 if (ai->ai_flags & gai_clone_flag)
00948 {
00949 if (ai->ai_socktype != 0)
00950 {
00951 ai = gai_clone(ai);
00952 if (ai == 0)
00953 return -1;
00954
00955 }
00956 }
00957 else if (ai->ai_socktype != socktype)
00958 {
00959
00960 continue;
00961 }
00962
00963 ai->ai_socktype = socktype;
00964
00965 switch (ai->ai_family)
00966 {
00967 case AF_INET:
00968 {
00969 sockaddr_in4_type* sinptr =
00970 reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
00971 sinptr->sin_port = port;
00972 ++num_found;
00973 break;
00974 }
00975 case AF_INET6:
00976 {
00977 sockaddr_in6_type* sin6ptr =
00978 reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
00979 sin6ptr->sin6_port = port;
00980 ++num_found;
00981 break;
00982 }
00983 default:
00984 break;
00985 }
00986 }
00987
00988 return num_found;
00989 }
00990
00991 inline int gai_serv(addrinfo_type* aihead,
00992 const addrinfo_type* hints, const char* serv)
00993 {
00994 using namespace std;
00995
00996 int num_found = 0;
00997
00998 if (
00999 #if defined(AI_NUMERICSERV)
01000 (hints->ai_flags & AI_NUMERICSERV) ||
01001 #endif
01002 isdigit(serv[0]))
01003 {
01004 int port = htons(atoi(serv));
01005 if (hints->ai_socktype)
01006 {
01007
01008 int rc = gai_port(aihead, port, hints->ai_socktype);
01009 if (rc < 0)
01010 return EAI_MEMORY;
01011 num_found += rc;
01012 }
01013 else
01014 {
01015
01016 int rc = gai_port(aihead, port, SOCK_STREAM);
01017 if (rc < 0)
01018 return EAI_MEMORY;
01019 num_found += rc;
01020 rc = gai_port(aihead, port, SOCK_DGRAM);
01021 if (rc < 0)
01022 return EAI_MEMORY;
01023 num_found += rc;
01024 }
01025 }
01026 else
01027 {
01028
01029 if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM)
01030 {
01031 servent* sptr = getservbyname(serv, "tcp");
01032 if (sptr != 0)
01033 {
01034 int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM);
01035 if (rc < 0)
01036 return EAI_MEMORY;
01037 num_found += rc;
01038 }
01039 }
01040 if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM)
01041 {
01042 servent* sptr = getservbyname(serv, "udp");
01043 if (sptr != 0)
01044 {
01045 int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM);
01046 if (rc < 0)
01047 return EAI_MEMORY;
01048 num_found += rc;
01049 }
01050 }
01051 }
01052
01053 if (num_found == 0)
01054 {
01055 if (hints->ai_socktype == 0)
01056 {
01057
01058 return EAI_NONAME;
01059 }
01060 else
01061 {
01062
01063 return EAI_SERVICE;
01064 }
01065 }
01066
01067 return 0;
01068 }
01069
01070 inline int gai_echeck(const char* host, const char* service,
01071 int flags, int family, int socktype, int protocol)
01072 {
01073 (void)(flags);
01074 (void)(protocol);
01075
01076
01077 if (host == 0 || host[0] == '\0')
01078 if (service == 0 || service[0] == '\0')
01079 return EAI_NONAME;
01080
01081
01082 switch (family)
01083 {
01084 case AF_UNSPEC:
01085 break;
01086 case AF_INET:
01087 case AF_INET6:
01088 if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
01089 return EAI_SOCKTYPE;
01090 break;
01091 default:
01092 return EAI_FAMILY;
01093 }
01094
01095 return 0;
01096 }
01097
01098 inline void freeaddrinfo_emulation(addrinfo_type* aihead)
01099 {
01100 addrinfo_type* ai = aihead;
01101 while (ai)
01102 {
01103 gai_free(ai->ai_addr);
01104 gai_free(ai->ai_canonname);
01105 addrinfo_type* ainext = ai->ai_next;
01106 gai_free(ai);
01107 ai = ainext;
01108 }
01109 }
01110
01111 inline int getaddrinfo_emulation(const char* host, const char* service,
01112 const addrinfo_type* hintsp, addrinfo_type** result)
01113 {
01114
01115 addrinfo_type* aihead = 0;
01116 addrinfo_type** ainext = &aihead;
01117 char* canon = 0;
01118
01119
01120 addrinfo_type hints = addrinfo_type();
01121 hints.ai_family = AF_UNSPEC;
01122 if (hintsp)
01123 hints = *hintsp;
01124
01125
01126
01127 #if defined(AI_V4MAPPED)
01128 if (hints.ai_family != AF_INET6)
01129 hints.ai_flags &= ~AI_V4MAPPED;
01130 #endif
01131 #if defined(AI_ALL)
01132 if (hints.ai_family != AF_INET6)
01133 hints.ai_flags &= ~AI_ALL;
01134 #endif
01135
01136
01137 int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
01138 hints.ai_socktype, hints.ai_protocol);
01139 if (rc != 0)
01140 {
01141 freeaddrinfo_emulation(aihead);
01142 return rc;
01143 }
01144
01145 gai_search search[2];
01146 int search_count = gai_nsearch(host, &hints, search);
01147 for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
01148 {
01149
01150 in4_addr_type inaddr;
01151 asio::error_code ec;
01152 if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1)
01153 {
01154 if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
01155 {
01156 freeaddrinfo_emulation(aihead);
01157 gai_free(canon);
01158 return EAI_FAMILY;
01159 }
01160 if (sptr->family == AF_INET)
01161 {
01162 rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET);
01163 if (rc != 0)
01164 {
01165 freeaddrinfo_emulation(aihead);
01166 gai_free(canon);
01167 return rc;
01168 }
01169 }
01170 continue;
01171 }
01172
01173
01174 in6_addr_type in6addr;
01175 if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1)
01176 {
01177 if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6)
01178 {
01179 freeaddrinfo_emulation(aihead);
01180 gai_free(canon);
01181 return EAI_FAMILY;
01182 }
01183 if (sptr->family == AF_INET6)
01184 {
01185 rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6);
01186 if (rc != 0)
01187 {
01188 freeaddrinfo_emulation(aihead);
01189 gai_free(canon);
01190 return rc;
01191 }
01192 }
01193 continue;
01194 }
01195
01196
01197 hostent hent;
01198 char hbuf[8192] = "";
01199 hostent* hptr = socket_ops::gethostbyname(sptr->host,
01200 sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
01201 if (hptr == 0)
01202 {
01203 if (search_count == 2)
01204 {
01205
01206 continue;
01207 }
01208 freeaddrinfo_emulation(aihead);
01209 gai_free(canon);
01210 if (ec == asio::error::host_not_found)
01211 return EAI_NONAME;
01212 if (ec == asio::error::host_not_found_try_again)
01213 return EAI_AGAIN;
01214 if (ec == asio::error::no_recovery)
01215 return EAI_FAIL;
01216 if (ec == asio::error::no_data)
01217 return EAI_NONAME;
01218 return EAI_NONAME;
01219 }
01220
01221
01222 if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype)
01223 {
01224 freeaddrinfo_emulation(aihead);
01225 gai_free(canon);
01226 socket_ops::freehostent(hptr);
01227 return EAI_FAMILY;
01228 }
01229
01230
01231 if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
01232 && (hints.ai_flags & AI_CANONNAME) && canon == 0)
01233 {
01234 canon = gai_alloc<char>(strlen(hptr->h_name) + 1);
01235 if (canon == 0)
01236 {
01237 freeaddrinfo_emulation(aihead);
01238 socket_ops::freehostent(hptr);
01239 return EAI_MEMORY;
01240 }
01241 strcpy(canon, hptr->h_name);
01242 }
01243
01244
01245 for (char** ap = hptr->h_addr_list; *ap; ++ap)
01246 {
01247 rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
01248 if (rc != 0)
01249 {
01250 freeaddrinfo_emulation(aihead);
01251 gai_free(canon);
01252 socket_ops::freehostent(hptr);
01253 return EAI_FAMILY;
01254 }
01255 }
01256
01257 socket_ops::freehostent(hptr);
01258 }
01259
01260
01261 if (aihead == 0)
01262 {
01263 gai_free(canon);
01264 return EAI_NONAME;
01265 }
01266
01267
01268 if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))
01269 {
01270 if (canon)
01271 {
01272 aihead->ai_canonname = canon;
01273 canon = 0;
01274 }
01275 else
01276 {
01277 aihead->ai_canonname = gai_alloc<char>(strlen(search[0].host) + 1);
01278 if (aihead->ai_canonname == 0)
01279 {
01280 freeaddrinfo_emulation(aihead);
01281 return EAI_MEMORY;
01282 }
01283 strcpy(aihead->ai_canonname, search[0].host);
01284 }
01285 }
01286 gai_free(canon);
01287
01288
01289 if (service != 0 && service[0] != '\0')
01290 {
01291 rc = gai_serv(aihead, &hints, service);
01292 if (rc != 0)
01293 {
01294 freeaddrinfo_emulation(aihead);
01295 return rc;
01296 }
01297 }
01298
01299
01300 *result = aihead;
01301 return 0;
01302 }
01303
01304 inline asio::error_code getnameinfo_emulation(
01305 const socket_addr_type* sa, socket_addr_len_type salen, char* host,
01306 std::size_t hostlen, char* serv, std::size_t servlen, int flags,
01307 asio::error_code& ec)
01308 {
01309 using namespace std;
01310
01311 const char* addr;
01312 size_t addr_len;
01313 unsigned short port;
01314 switch (sa->sa_family)
01315 {
01316 case AF_INET:
01317 if (salen != sizeof(sockaddr_in4_type))
01318 {
01319 return ec = asio::error::invalid_argument;
01320 }
01321 addr = reinterpret_cast<const char*>(
01322 &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);
01323 addr_len = sizeof(in4_addr_type);
01324 port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;
01325 break;
01326 case AF_INET6:
01327 if (salen != sizeof(sockaddr_in6_type))
01328 {
01329 return ec = asio::error::invalid_argument;
01330 }
01331 addr = reinterpret_cast<const char*>(
01332 &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);
01333 addr_len = sizeof(in6_addr_type);
01334 port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;
01335 break;
01336 default:
01337 return ec = asio::error::address_family_not_supported;
01338 }
01339
01340 if (host && hostlen > 0)
01341 {
01342 if (flags & NI_NUMERICHOST)
01343 {
01344 if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)
01345 {
01346 return ec;
01347 }
01348 }
01349 else
01350 {
01351 hostent hent;
01352 char hbuf[8192] = "";
01353 hostent* hptr = socket_ops::gethostbyaddr(addr,
01354 static_cast<int>(addr_len), sa->sa_family,
01355 &hent, hbuf, sizeof(hbuf), ec);
01356 if (hptr && hptr->h_name && hptr->h_name[0] != '\0')
01357 {
01358 if (flags & NI_NOFQDN)
01359 {
01360 char* dot = strchr(hptr->h_name, '.');
01361 if (dot)
01362 {
01363 *dot = 0;
01364 }
01365 }
01366 *host = '\0';
01367 strncat(host, hptr->h_name, hostlen);
01368 socket_ops::freehostent(hptr);
01369 }
01370 else
01371 {
01372 socket_ops::freehostent(hptr);
01373 if (flags & NI_NAMEREQD)
01374 {
01375 return ec = asio::error::host_not_found;
01376 }
01377 if (socket_ops::inet_ntop(sa->sa_family,
01378 addr, host, hostlen, 0, ec) == 0)
01379 {
01380 return ec;
01381 }
01382 }
01383 }
01384 }
01385
01386 if (serv && servlen > 0)
01387 {
01388 if (flags & NI_NUMERICSERV)
01389 {
01390 if (servlen < 6)
01391 {
01392 return ec = asio::error::no_buffer_space;
01393 }
01394 sprintf(serv, "%u", ntohs(port));
01395 }
01396 else
01397 {
01398 #if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
01399 static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
01400 ::pthread_mutex_lock(&mutex);
01401 #endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
01402 servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0);
01403 if (sptr && sptr->s_name && sptr->s_name[0] != '\0')
01404 {
01405 *serv = '\0';
01406 strncat(serv, sptr->s_name, servlen);
01407 }
01408 else
01409 {
01410 if (servlen < 6)
01411 {
01412 return ec = asio::error::no_buffer_space;
01413 }
01414 sprintf(serv, "%u", ntohs(port));
01415 }
01416 #if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
01417 ::pthread_mutex_unlock(&mutex);
01418 #endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
01419 }
01420 }
01421
01422 clear_error(ec);
01423 return ec;
01424 }
01425
01426 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
01427
01428
01429 inline asio::error_code translate_addrinfo_error(int error)
01430 {
01431 switch (error)
01432 {
01433 case 0:
01434 return asio::error_code();
01435 case EAI_AGAIN:
01436 return asio::error::host_not_found_try_again;
01437 case EAI_BADFLAGS:
01438 return asio::error::invalid_argument;
01439 case EAI_FAIL:
01440 return asio::error::no_recovery;
01441 case EAI_FAMILY:
01442 return asio::error::address_family_not_supported;
01443 case EAI_MEMORY:
01444 return asio::error::no_memory;
01445 case EAI_NONAME:
01446 return asio::error::host_not_found;
01447 case EAI_SERVICE:
01448 return asio::error::service_not_found;
01449 case EAI_SOCKTYPE:
01450 return asio::error::socket_type_not_supported;
01451 default:
01452 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
01453 return asio::error_code(
01454 WSAGetLastError(), asio::native_ecat);
01455 #else
01456 return asio::error_code(
01457 errno, asio::native_ecat);
01458 #endif
01459 }
01460 }
01461
01462 inline asio::error_code getaddrinfo(const char* host,
01463 const char* service, const addrinfo_type* hints, addrinfo_type** result,
01464 asio::error_code& ec)
01465 {
01466 clear_error(ec);
01467 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
01468 # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
01469
01470 int error = ::getaddrinfo(host, service, hints, result);
01471 return ec = translate_addrinfo_error(error);
01472 # else
01473
01474 typedef int (WSAAPI *gai_t)(const char*,
01475 const char*, const addrinfo_type*, addrinfo_type**);
01476 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
01477 {
01478 if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
01479 {
01480 int error = gai(host, service, hints, result);
01481 return ec = translate_addrinfo_error(error);
01482 }
01483 }
01484 int error = getaddrinfo_emulation(host, service, hints, result);
01485 return ec = translate_addrinfo_error(error);
01486 # endif
01487 #elif defined(__MACH__) && defined(__APPLE__)
01488 int error = getaddrinfo_emulation(host, service, hints, result);
01489 return ec = translate_addrinfo_error(error);
01490 #else
01491 int error = ::getaddrinfo(host, service, hints, result);
01492 return ec = translate_addrinfo_error(error);
01493 #endif
01494 }
01495
01496 inline void freeaddrinfo(addrinfo_type* ai)
01497 {
01498 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
01499 # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
01500
01501 ::freeaddrinfo(ai);
01502 # else
01503
01504 typedef int (WSAAPI *fai_t)(addrinfo_type*);
01505 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
01506 {
01507 if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
01508 {
01509 fai(ai);
01510 return;
01511 }
01512 }
01513 freeaddrinfo_emulation(ai);
01514 # endif
01515 #elif defined(__MACH__) && defined(__APPLE__)
01516 freeaddrinfo_emulation(ai);
01517 #else
01518 ::freeaddrinfo(ai);
01519 #endif
01520 }
01521
01522 inline asio::error_code getnameinfo(const socket_addr_type* addr,
01523 socket_addr_len_type addrlen, char* host, std::size_t hostlen,
01524 char* serv, std::size_t servlen, int flags, asio::error_code& ec)
01525 {
01526 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
01527 # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
01528
01529 clear_error(ec);
01530 int error = ::getnameinfo(addr, addrlen, host, static_cast<DWORD>(hostlen),
01531 serv, static_cast<DWORD>(servlen), flags);
01532 return ec = translate_addrinfo_error(error);
01533 # else
01534
01535 typedef int (WSAAPI *gni_t)(const socket_addr_type*,
01536 socket_addr_len_type, char*, std::size_t, char*, std::size_t, int);
01537 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
01538 {
01539 if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))
01540 {
01541 clear_error(ec);
01542 int error = gni(addr, addrlen, host, hostlen, serv, servlen, flags);
01543 return ec = translate_addrinfo_error(error);
01544 }
01545 }
01546 clear_error(ec);
01547 return getnameinfo_emulation(addr, addrlen,
01548 host, hostlen, serv, servlen, flags, ec);
01549 # endif
01550 #elif defined(__MACH__) && defined(__APPLE__)
01551 using namespace std;
01552 sockaddr_storage_type tmp_addr;
01553 memcpy(&tmp_addr, addr, addrlen);
01554 tmp_addr.ss_len = addrlen;
01555 addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);
01556 clear_error(ec);
01557 return getnameinfo_emulation(addr, addrlen,
01558 host, hostlen, serv, servlen, flags, ec);
01559 #else
01560 clear_error(ec);
01561 int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
01562 return ec = translate_addrinfo_error(error);
01563 #endif
01564 }
01565
01566 inline u_long_type network_to_host_long(u_long_type value)
01567 {
01568 return ntohl(value);
01569 }
01570
01571 inline u_long_type host_to_network_long(u_long_type value)
01572 {
01573 return htonl(value);
01574 }
01575
01576 inline u_short_type network_to_host_short(u_short_type value)
01577 {
01578 return ntohs(value);
01579 }
01580
01581 inline u_short_type host_to_network_short(u_short_type value)
01582 {
01583 return htons(value);
01584 }
01585
01586 }
01587 }
01588 }
01589
01590 #include "asio/detail/pop_options.hpp"
01591
01592 #endif // ASIO_DETAIL_SOCKET_OPS_HPP