mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 01:37:00 +00:00
1003 lines
31 KiB
C++
1003 lines
31 KiB
C++
// -*- C++ -*-
|
|
// $Id: OS_NS_sys_socket.inl 97938 2014-10-27 07:56:26Z johnnyw $
|
|
|
|
#include "ace/OS_NS_errno.h"
|
|
#include "ace/OS_NS_macros.h"
|
|
#include "ace/OS_NS_sys_uio.h"
|
|
#include "ace/OS_NS_stdio.h"
|
|
#include "ace/OS_QoS.h"
|
|
#include "ace/Global_Macros.h"
|
|
#include "ace/os_include/netinet/os_in.h"
|
|
|
|
#if defined (ACE_GETNAME_RETURNS_RANDOM_SIN_ZERO) \
|
|
&& (ACE_GETNAME_RETURNS_RANDOM_SIN_ZERO == 1)
|
|
#include "ace/OS_NS_string.h"
|
|
#endif
|
|
|
|
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
|
|
|
|
#if defined (ACE_HAS_VOIDPTR_SOCKOPT)
|
|
typedef void *ACE_SOCKOPT_TYPE1;
|
|
#elif defined (ACE_HAS_CHARPTR_SOCKOPT)
|
|
typedef char *ACE_SOCKOPT_TYPE1;
|
|
#else
|
|
typedef const char *ACE_SOCKOPT_TYPE1;
|
|
#endif /* ACE_HAS_VOIDPTR_SOCKOPT */
|
|
|
|
ACE_INLINE ACE_HANDLE
|
|
ACE_OS::accept (ACE_HANDLE handle,
|
|
struct sockaddr *addr,
|
|
int *addrlen)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::accept");
|
|
// On a non-blocking socket with no connections to accept, this
|
|
// system call will return EWOULDBLOCK or EAGAIN, depending on the
|
|
// platform. UNIX 98 allows either errno, and they may be the same
|
|
// numeric value. So to make life easier for upper ACE layers as
|
|
// well as application programmers, always change EAGAIN to
|
|
// EWOULDBLOCK. Rather than hack the ACE_OSCALL_RETURN macro, it's
|
|
// handled explicitly here. If the ACE_OSCALL macro ever changes,
|
|
// this function needs to be reviewed. On Win32, the regular macros
|
|
// can be used, as this is not an issue.
|
|
|
|
#if defined (ACE_LACKS_ACCEPT)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (addr);
|
|
ACE_UNUSED_ARG (addrlen);
|
|
ACE_NOTSUP_RETURN (ACE_INVALID_HANDLE);
|
|
#elif defined (ACE_WIN32)
|
|
ACE_SOCKCALL_RETURN (::accept ((ACE_SOCKET) handle,
|
|
addr,
|
|
(ACE_SOCKET_LEN *) addrlen),
|
|
ACE_HANDLE,
|
|
ACE_INVALID_HANDLE);
|
|
#else
|
|
# if defined (ACE_HAS_BROKEN_ACCEPT_ADDR)
|
|
// Apparently some platforms like VxWorks can't correctly deal with
|
|
// a NULL addr.
|
|
|
|
# if defined (ACE_HAS_IPV6)
|
|
sockaddr_in6 fake_addr;
|
|
# else
|
|
sockaddr_in fake_addr;
|
|
# endif /* ACE_HAS_IPV6 */
|
|
int fake_addrlen;
|
|
|
|
if (addrlen == 0)
|
|
addrlen = &fake_addrlen;
|
|
|
|
if (addr == 0)
|
|
{
|
|
addr = (sockaddr *) &fake_addr;
|
|
*addrlen = sizeof fake_addr;
|
|
}
|
|
# endif /* ACE_HAS_BROKEN_ACCEPT_ADDR */
|
|
ACE_HANDLE ace_result = ::accept ((ACE_SOCKET) handle,
|
|
addr,
|
|
(ACE_SOCKET_LEN *) addrlen);
|
|
|
|
# if !(defined (EAGAIN) && defined (EWOULDBLOCK) && EAGAIN == EWOULDBLOCK)
|
|
// Optimize this code out if we can detect that EAGAIN ==
|
|
// EWOULDBLOCK at compile time. If we cannot detect equality at
|
|
// compile-time (e.g. if EAGAIN or EWOULDBLOCK are not preprocessor
|
|
// macros) perform the check at run-time. The goal is to avoid two
|
|
// TSS accesses in the _REENTRANT case when EAGAIN == EWOULDBLOCK.
|
|
if (ace_result == ACE_INVALID_HANDLE
|
|
# if !defined (EAGAIN) || !defined (EWOULDBLOCK)
|
|
&& EAGAIN != EWOULDBLOCK
|
|
# endif /* !EAGAIN || !EWOULDBLOCK */
|
|
&& errno == EAGAIN)
|
|
{
|
|
errno = EWOULDBLOCK;
|
|
}
|
|
# endif /* EAGAIN != EWOULDBLOCK*/
|
|
|
|
return ace_result;
|
|
|
|
#endif /* defined (ACE_WIN32) */
|
|
}
|
|
|
|
ACE_INLINE int
|
|
ACE_OS::bind (ACE_HANDLE handle, struct sockaddr *addr, int addrlen)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::bind");
|
|
#if defined (ACE_LACKS_BIND)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (addr);
|
|
ACE_UNUSED_ARG (addrlen);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#elif defined (ACE_VXWORKS) && (ACE_VXWORKS <= 0x640)
|
|
// VxWorks clears the sin_port member after a successful bind when
|
|
// sin_addr != INADDR_ANY, so after the bind we do retrieve the
|
|
// original address so that user code can safely check the addr
|
|
// after the bind. See bugzilla 3107 for more details
|
|
int result;
|
|
ACE_SOCKCALL (::bind ((ACE_SOCKET) handle,
|
|
addr,
|
|
(ACE_SOCKET_LEN) addrlen), int, -1, result);
|
|
if (result == -1)
|
|
return -1;
|
|
else
|
|
return ACE_OS::getsockname (handle, addr, &addrlen);
|
|
#else
|
|
ACE_SOCKCALL_RETURN (::bind ((ACE_SOCKET) handle,
|
|
addr,
|
|
(ACE_SOCKET_LEN) addrlen), int, -1);
|
|
#endif
|
|
}
|
|
|
|
ACE_INLINE int
|
|
ACE_OS::closesocket (ACE_HANDLE handle)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::closesocket");
|
|
#if defined (ACE_WIN32)
|
|
// @note Do not shutdown the write end here. Doing so will break
|
|
// applications that duplicate a handle on fork(), for
|
|
// example, and expect to continue writing in the fork()ed
|
|
// process.
|
|
|
|
ACE_SOCKCALL_RETURN (::closesocket ((SOCKET) handle), int, -1);
|
|
#else
|
|
//FUZZ: disable check_for_lack_ACE_OS
|
|
ACE_OSCALL_RETURN (::close (handle), int, -1);
|
|
//FUZZ: enable check_for_lack_ACE_OS
|
|
#endif /* ACE_WIN32 */
|
|
}
|
|
|
|
ACE_INLINE int
|
|
ACE_OS::connect (ACE_HANDLE handle,
|
|
struct sockaddr *addr,
|
|
int addrlen)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::connect");
|
|
#if defined (ACE_LACKS_CONNECT)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (addr);
|
|
ACE_UNUSED_ARG (addrlen);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#else
|
|
ACE_SOCKCALL_RETURN (::connect ((ACE_SOCKET) handle,
|
|
addr,
|
|
(ACE_SOCKET_LEN) addrlen), int, -1);
|
|
#endif /* ACE_LACKS_CONNECT */
|
|
}
|
|
|
|
ACE_INLINE int
|
|
ACE_OS::enum_protocols (int *protocols,
|
|
ACE_Protocol_Info *protocol_buffer,
|
|
u_long *buffer_length)
|
|
{
|
|
#if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0)
|
|
|
|
ACE_SOCKCALL_RETURN (::WSAEnumProtocols (protocols,
|
|
protocol_buffer,
|
|
buffer_length),
|
|
int,
|
|
SOCKET_ERROR);
|
|
|
|
#else
|
|
ACE_UNUSED_ARG (protocols);
|
|
ACE_UNUSED_ARG (protocol_buffer);
|
|
ACE_UNUSED_ARG (buffer_length);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#endif /* ACE_HAS_WINSOCK2 */
|
|
}
|
|
|
|
ACE_INLINE int
|
|
ACE_OS::getpeername (ACE_HANDLE handle, struct sockaddr *addr,
|
|
int *addrlen)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::getpeername");
|
|
|
|
#if defined (ACE_LACKS_GETPEERNAME)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (addr);
|
|
ACE_UNUSED_ARG (addrlen);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#elif defined (ACE_GETNAME_RETURNS_RANDOM_SIN_ZERO) \
|
|
&& (ACE_GETNAME_RETURNS_RANDOM_SIN_ZERO == 1)
|
|
int result;
|
|
ACE_SOCKCALL (::getpeername ((ACE_SOCKET) handle,
|
|
addr,
|
|
(ACE_SOCKET_LEN *) addrlen),
|
|
int,
|
|
-1,
|
|
result);
|
|
|
|
// Some platforms, like older versions of the Linux kernel, do not
|
|
// initialize the sin_zero field since that field is generally only
|
|
// used for padding/alignment purposes. On those platforms
|
|
// memcmp()-based comparisons of the sockaddr_in structure, such as
|
|
// the one in the ACE_INET_Addr equality operator, may fail due to
|
|
// random bytes in the sin_zero field even though that field is
|
|
// unused. Prevent equality comparison of two different sockaddr_in
|
|
// instances that refer to the same socket from failing by
|
|
// explicitly initializing the sockaddr_in::sin_zero field to a
|
|
// consistent value, e.g. zero.
|
|
if (result != -1 && addr->sa_family == AF_INET)
|
|
{
|
|
ACE_OS::memset (reinterpret_cast<struct sockaddr_in *> (addr)->sin_zero,
|
|
0,
|
|
sizeof (reinterpret_cast<struct sockaddr_in *> (addr)->sin_zero));
|
|
}
|
|
|
|
return result;
|
|
#else
|
|
ACE_SOCKCALL_RETURN (::getpeername ((ACE_SOCKET) handle,
|
|
addr,
|
|
(ACE_SOCKET_LEN *) addrlen),
|
|
int,
|
|
-1);
|
|
#endif /* ACE_GETNAME_RETURNS_RANDOM_SIN_ZERO */
|
|
}
|
|
|
|
ACE_INLINE int
|
|
ACE_OS::getsockname (ACE_HANDLE handle,
|
|
struct sockaddr *addr,
|
|
int *addrlen)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::getsockname");
|
|
#if defined (ACE_LACKS_GETSOCKNAME)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (addr);
|
|
ACE_UNUSED_ARG (addrlen);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#elif defined (ACE_GETNAME_RETURNS_RANDOM_SIN_ZERO) \
|
|
&& (ACE_GETNAME_RETURNS_RANDOM_SIN_ZERO == 1)
|
|
int result;
|
|
ACE_SOCKCALL (::getsockname ((ACE_SOCKET) handle,
|
|
addr,
|
|
(ACE_SOCKET_LEN *) addrlen),
|
|
int, -1, result);
|
|
|
|
// Some platforms, like older versions of the Linux kernel, do not
|
|
// initialize the sin_zero field since that field is generally only
|
|
// used for padding/alignment purposes. On those platforms
|
|
// memcmp()-based comparisons of the sockaddr_in structure, such as
|
|
// the one in the ACE_INET_Addr equality operator, may fail due to
|
|
// random bytes in the sin_zero field even though that field is
|
|
// unused. Prevent equality comparison of two different sockaddr_in
|
|
// instances that refer to the same socket from failing by
|
|
// explicitly initializing the sockaddr_in::sin_zero field to a
|
|
// consistent value, e.g. zero.
|
|
if (result != -1 && addr->sa_family == AF_INET)
|
|
{
|
|
ACE_OS::memset (reinterpret_cast<struct sockaddr_in *> (addr)->sin_zero,
|
|
0,
|
|
sizeof (reinterpret_cast<struct sockaddr_in *> (addr)->sin_zero));
|
|
}
|
|
|
|
return result;
|
|
#else
|
|
ACE_SOCKCALL_RETURN (::getsockname ((ACE_SOCKET) handle,
|
|
addr,
|
|
(ACE_SOCKET_LEN *) addrlen),
|
|
int, -1);
|
|
#endif /* ACE_GETNAME_RETURNS_RANDOM_SIN_ZERO */
|
|
}
|
|
|
|
ACE_INLINE int
|
|
ACE_OS::getsockopt (ACE_HANDLE handle,
|
|
int level,
|
|
int optname,
|
|
char *optval,
|
|
int *optlen)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::getsockopt");
|
|
#if defined (ACE_LACKS_GETSOCKOPT)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (level);
|
|
ACE_UNUSED_ARG (optname);
|
|
ACE_UNUSED_ARG (optval);
|
|
ACE_UNUSED_ARG (optlen);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#else
|
|
ACE_SOCKCALL_RETURN (::getsockopt ((ACE_SOCKET) handle,
|
|
level,
|
|
optname,
|
|
optval,
|
|
(ACE_SOCKET_LEN *) optlen),
|
|
int,
|
|
-1);
|
|
#endif /* ACE_LACKS_GETSOCKOPT */
|
|
}
|
|
|
|
ACE_INLINE int
|
|
ACE_OS::listen (ACE_HANDLE handle, int backlog)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::listen");
|
|
#if defined (ACE_LACKS_LISTEN)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (backlog);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#else
|
|
ACE_SOCKCALL_RETURN (::listen ((ACE_SOCKET) handle, backlog), int, -1);
|
|
#endif /* ACE_LACKS_LISTEN */
|
|
}
|
|
|
|
ACE_INLINE ssize_t
|
|
ACE_OS::recv (ACE_HANDLE handle, char *buf, size_t len, int flags)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::recv");
|
|
|
|
// On UNIX, a non-blocking socket with no data to receive, this
|
|
// system call will return EWOULDBLOCK or EAGAIN, depending on the
|
|
// platform. UNIX 98 allows either errno, and they may be the same
|
|
// numeric value. So to make life easier for upper ACE layers as
|
|
// well as application programmers, always change EAGAIN to
|
|
// EWOULDBLOCK. Rather than hack the ACE_OSCALL_RETURN macro, it's
|
|
// handled explicitly here. If the ACE_OSCALL macro ever changes,
|
|
// this function needs to be reviewed. On Win32, the regular macros
|
|
// can be used, as this is not an issue.
|
|
#if defined (ACE_LACKS_RECV)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (buf);
|
|
ACE_UNUSED_ARG (len);
|
|
ACE_UNUSED_ARG (flags);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#elif defined (ACE_WIN32)
|
|
ACE_SOCKCALL_RETURN (::recv ((ACE_SOCKET) handle, buf,
|
|
static_cast<int> (len), flags), ssize_t, -1);
|
|
#else
|
|
ssize_t ace_result_;
|
|
ace_result_ = ::recv ((ACE_SOCKET) handle, buf, len, flags);
|
|
|
|
# if !(defined (EAGAIN) && defined (EWOULDBLOCK) && EAGAIN == EWOULDBLOCK)
|
|
// Optimize this code out if we can detect that EAGAIN ==
|
|
// EWOULDBLOCK at compile time. If we cannot detect equality at
|
|
// compile-time (e.g. if EAGAIN or EWOULDBLOCK are not preprocessor
|
|
// macros) perform the check at run-time. The goal is to avoid two
|
|
// TSS accesses in the _REENTRANT case when EAGAIN == EWOULDBLOCK.
|
|
if (ace_result_ == -1
|
|
# if !defined (EAGAIN) || !defined (EWOULDBLOCK)
|
|
&& EAGAIN != EWOULDBLOCK
|
|
# endif /* !EAGAIN || !EWOULDBLOCK */
|
|
&& errno == EAGAIN)
|
|
{
|
|
errno = EWOULDBLOCK;
|
|
}
|
|
# endif /* EAGAIN != EWOULDBLOCK*/
|
|
|
|
return ace_result_;
|
|
#endif /* ACE_LACKS_RECV */
|
|
}
|
|
|
|
ACE_INLINE ssize_t
|
|
ACE_OS::recvfrom (ACE_HANDLE handle,
|
|
char *buf,
|
|
size_t len,
|
|
int flags,
|
|
struct sockaddr *addr,
|
|
int *addrlen)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::recvfrom");
|
|
#if defined (ACE_LACKS_RECVFROM)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (buf);
|
|
ACE_UNUSED_ARG (len);
|
|
ACE_UNUSED_ARG (flags);
|
|
ACE_UNUSED_ARG (addr);
|
|
ACE_UNUSED_ARG (addrlen);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#elif defined (ACE_WIN32)
|
|
int const shortened_len = static_cast<int> (len);
|
|
int const result = ::recvfrom ((ACE_SOCKET) handle,
|
|
buf,
|
|
shortened_len,
|
|
flags,
|
|
addr,
|
|
(ACE_SOCKET_LEN *) addrlen);
|
|
if (result == SOCKET_ERROR)
|
|
{
|
|
ACE_OS::set_errno_to_wsa_last_error ();
|
|
if (errno == WSAEMSGSIZE &&
|
|
ACE_BIT_ENABLED (flags, MSG_PEEK))
|
|
return shortened_len;
|
|
else
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
# if defined (ACE_HAS_PHARLAP)
|
|
// Pharlap ETS (at least to v13) returns a legit address but doesn't
|
|
// include the sin_zero[8] bytes in the count. Correct for this here.
|
|
if (addrlen != 0 && addr != 0 &&
|
|
*addrlen == 8 && addr->sa_family == AF_INET)
|
|
*addrlen = sizeof(sockaddr_in);
|
|
# endif /* ACE_HAS_PHARLAP */
|
|
return result;
|
|
}
|
|
#else /* non Win32 */
|
|
ACE_SOCKCALL_RETURN (::recvfrom ((ACE_SOCKET) handle,
|
|
buf,
|
|
len,
|
|
flags,
|
|
addr,
|
|
(ACE_SOCKET_LEN *) addrlen),
|
|
ssize_t, -1);
|
|
#endif /* ACE_LACKS_RECVFROM */
|
|
}
|
|
|
|
ACE_INLINE ssize_t
|
|
ACE_OS::recvfrom (ACE_HANDLE handle,
|
|
iovec *buffers,
|
|
int buffer_count,
|
|
size_t &number_of_bytes_recvd,
|
|
int &flags,
|
|
struct sockaddr *addr,
|
|
int *addrlen,
|
|
ACE_OVERLAPPED *overlapped,
|
|
ACE_OVERLAPPED_COMPLETION_FUNC func)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::recvfrom");
|
|
|
|
#if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0)
|
|
DWORD bytes_recvd;
|
|
DWORD the_flags = flags;
|
|
int result = ::WSARecvFrom ((SOCKET) handle,
|
|
(WSABUF*)buffers,
|
|
buffer_count,
|
|
&bytes_recvd,
|
|
&the_flags,
|
|
addr,
|
|
addrlen,
|
|
overlapped,
|
|
func);
|
|
if (result != 0) {
|
|
ACE_OS::set_errno_to_wsa_last_error ();
|
|
}
|
|
flags = the_flags;
|
|
number_of_bytes_recvd = static_cast<size_t> (bytes_recvd);
|
|
return result;
|
|
#else
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (buffers);
|
|
ACE_UNUSED_ARG (buffer_count);
|
|
ACE_UNUSED_ARG (number_of_bytes_recvd);
|
|
ACE_UNUSED_ARG (flags);
|
|
ACE_UNUSED_ARG (addr);
|
|
ACE_UNUSED_ARG (addrlen);
|
|
ACE_UNUSED_ARG (overlapped);
|
|
ACE_UNUSED_ARG (func);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#endif /* defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) */
|
|
}
|
|
|
|
ACE_INLINE ssize_t
|
|
ACE_OS::recvmsg (ACE_HANDLE handle, struct msghdr *msg, int flags)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::recvmsg");
|
|
#if !defined (ACE_LACKS_RECVMSG)
|
|
# if (defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0))
|
|
DWORD bytes_received = 0;
|
|
|
|
int result = ::WSARecvFrom ((SOCKET) handle,
|
|
(WSABUF *) msg->msg_iov,
|
|
msg->msg_iovlen,
|
|
&bytes_received,
|
|
(DWORD *) &flags,
|
|
msg->msg_name,
|
|
&msg->msg_namelen,
|
|
0,
|
|
0);
|
|
|
|
if (result != 0)
|
|
{
|
|
ACE_OS::set_errno_to_wsa_last_error ();
|
|
return -1;
|
|
}
|
|
else
|
|
return bytes_received;
|
|
# else /* ACE_HAS_WINSOCK2 */
|
|
ACE_SOCKCALL_RETURN (::recvmsg (handle, msg, flags), ssize_t, -1);
|
|
# endif /* ACE_HAS_WINSOCK2 */
|
|
#else
|
|
ACE_UNUSED_ARG (flags);
|
|
ACE_UNUSED_ARG (msg);
|
|
ACE_UNUSED_ARG (handle);
|
|
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#endif /* ACE_LACKS_RECVMSG */
|
|
}
|
|
|
|
ACE_INLINE ssize_t
|
|
ACE_OS::recvv (ACE_HANDLE handle,
|
|
iovec *buffers,
|
|
int n)
|
|
{
|
|
#if defined (ACE_HAS_WINSOCK2)
|
|
|
|
DWORD bytes_received = 0;
|
|
int result = 1;
|
|
|
|
// Winsock 2 has WSARecv and can do this directly, but Winsock 1 needs
|
|
// to do the recvs piece-by-piece.
|
|
|
|
# if (ACE_HAS_WINSOCK2 != 0)
|
|
DWORD flags = 0;
|
|
result = ::WSARecv ((SOCKET) handle,
|
|
(WSABUF *) buffers,
|
|
n,
|
|
&bytes_received,
|
|
&flags,
|
|
0,
|
|
0);
|
|
# else
|
|
// Step through the buffers requested by caller; for each one, cycle
|
|
// through reads until it's filled or an error occurs.
|
|
for (int i = 0; i < n && result > 0; ++i)
|
|
{
|
|
char *chunkp = buffers[i].iov_base; // Point to part of chunk being read
|
|
int chunklen = buffers[i].iov_len; // Track how much to read to chunk
|
|
while (chunklen > 0 && result > 0)
|
|
{
|
|
result = ::recv ((SOCKET) handle, chunkp, chunklen, 0);
|
|
if (result > 0)
|
|
{
|
|
chunkp += result;
|
|
chunklen -= result;
|
|
bytes_received += result;
|
|
}
|
|
}
|
|
}
|
|
# endif /* ACE_HAS_WINSOCK2 != 0 */
|
|
|
|
if (result == SOCKET_ERROR)
|
|
{
|
|
ACE_OS::set_errno_to_wsa_last_error ();
|
|
return -1;
|
|
}
|
|
else
|
|
return (ssize_t) bytes_received;
|
|
#else
|
|
return ACE_OS::readv (handle, buffers, n);
|
|
#endif /* ACE_HAS_WINSOCK2 */
|
|
}
|
|
|
|
ACE_INLINE ssize_t
|
|
ACE_OS::send (ACE_HANDLE handle, const char *buf, size_t len, int flags)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::send");
|
|
|
|
// On UNIX, a non-blocking socket with no data to receive, this
|
|
// system call will return EWOULDBLOCK or EAGAIN, depending on the
|
|
// platform. UNIX 98 allows either errno, and they may be the same
|
|
// numeric value. So to make life easier for upper ACE layers as
|
|
// well as application programmers, always change EAGAIN to
|
|
// EWOULDBLOCK. Rather than hack the ACE_OSCALL_RETURN macro, it's
|
|
// handled explicitly here. If the ACE_OSCALL macro ever changes,
|
|
// this function needs to be reviewed. On Win32, the regular macros
|
|
// can be used, as this is not an issue.
|
|
#if defined (ACE_LACKS_SEND)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (buf);
|
|
ACE_UNUSED_ARG (len);
|
|
ACE_UNUSED_ARG (flags);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#elif defined (ACE_WIN32)
|
|
ssize_t result = ::send ((ACE_SOCKET) handle,
|
|
buf,
|
|
static_cast<int> (len),
|
|
flags);
|
|
if (result == -1)
|
|
{
|
|
ACE_OS::set_errno_to_wsa_last_error();
|
|
if (errno != ENOBUFS)
|
|
return -1;
|
|
|
|
ACE_SOCKCALL_RETURN(send_partial_i(handle, buf, len, flags), ssize_t, -1);
|
|
}
|
|
else
|
|
return result;
|
|
|
|
#else
|
|
ssize_t const ace_result_ = ::send ((ACE_SOCKET) handle, buf, len, flags);
|
|
|
|
# if !(defined (EAGAIN) && defined (EWOULDBLOCK) && EAGAIN == EWOULDBLOCK)
|
|
// Optimize this code out if we can detect that EAGAIN ==
|
|
// EWOULDBLOCK at compile time. If we cannot detect equality at
|
|
// compile-time (e.g. if EAGAIN or EWOULDBLOCK are not preprocessor
|
|
// macros) perform the check at run-time. The goal is to avoid two
|
|
// TSS accesses in the _REENTRANT case when EAGAIN == EWOULDBLOCK.
|
|
if (ace_result_ == -1
|
|
# if !defined (EAGAIN) || !defined (EWOULDBLOCK)
|
|
&& EAGAIN != EWOULDBLOCK
|
|
# endif /* !EAGAIN || !EWOULDBLOCK */
|
|
&& errno == EAGAIN)
|
|
{
|
|
errno = EWOULDBLOCK;
|
|
}
|
|
# endif /* EAGAIN != EWOULDBLOCK*/
|
|
|
|
return ace_result_;
|
|
#endif /* defined (ACE_WIN32) */
|
|
}
|
|
|
|
ACE_INLINE ssize_t
|
|
ACE_OS::sendmsg (ACE_HANDLE handle,
|
|
const struct msghdr *msg,
|
|
int flags)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::sendmsg");
|
|
#if !defined (ACE_LACKS_SENDMSG)
|
|
# if (defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0))
|
|
DWORD bytes_sent = 0;
|
|
int result = ::WSASendTo ((SOCKET) handle,
|
|
(WSABUF *) msg->msg_iov,
|
|
msg->msg_iovlen,
|
|
&bytes_sent,
|
|
flags,
|
|
msg->msg_name,
|
|
msg->msg_namelen,
|
|
0,
|
|
0);
|
|
|
|
if (result != 0)
|
|
{
|
|
ACE_OS::set_errno_to_wsa_last_error ();
|
|
return -1;
|
|
}
|
|
else
|
|
return (ssize_t) bytes_sent;
|
|
# elif defined (ACE_HAS_NONCONST_SENDMSG)
|
|
ACE_SOCKCALL_RETURN (::sendmsg (handle,
|
|
const_cast<struct msghdr *>(msg),
|
|
flags), ssize_t, -1);
|
|
# else
|
|
ACE_SOCKCALL_RETURN (::sendmsg (handle, msg, flags), ssize_t, -1);
|
|
# endif
|
|
#else
|
|
ACE_UNUSED_ARG (flags);
|
|
ACE_UNUSED_ARG (msg);
|
|
ACE_UNUSED_ARG (handle);
|
|
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#endif /* ACE_LACKS_SENDMSG */
|
|
}
|
|
|
|
ACE_INLINE ssize_t
|
|
ACE_OS::sendto (ACE_HANDLE handle,
|
|
const char *buf,
|
|
size_t len,
|
|
int flags,
|
|
const struct sockaddr *addr,
|
|
int addrlen)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::sendto");
|
|
#if defined (ACE_LACKS_SENDTO)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (buf);
|
|
ACE_UNUSED_ARG (len);
|
|
ACE_UNUSED_ARG (flags);
|
|
ACE_UNUSED_ARG (addr);
|
|
ACE_UNUSED_ARG (addrlen);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#elif defined (ACE_VXWORKS)
|
|
ACE_SOCKCALL_RETURN (::sendto ((ACE_SOCKET) handle,
|
|
const_cast <char *> (buf),
|
|
len,
|
|
flags,
|
|
const_cast<struct sockaddr *> (addr),
|
|
addrlen),
|
|
ssize_t, -1);
|
|
#elif defined (ACE_WIN32)
|
|
ACE_SOCKCALL_RETURN (::sendto ((ACE_SOCKET) handle,
|
|
buf,
|
|
static_cast<int> (len),
|
|
flags,
|
|
const_cast<struct sockaddr *> (addr),
|
|
addrlen),
|
|
ssize_t, -1);
|
|
#else
|
|
ACE_SOCKCALL_RETURN (::sendto ((ACE_SOCKET) handle,
|
|
buf,
|
|
len,
|
|
flags,
|
|
const_cast<struct sockaddr *> (addr),
|
|
addrlen),
|
|
ssize_t, -1);
|
|
#endif /* ACE_LACKS_SENDTO */
|
|
}
|
|
|
|
ACE_INLINE ssize_t
|
|
ACE_OS::sendto (ACE_HANDLE handle,
|
|
const iovec *buffers,
|
|
int buffer_count,
|
|
size_t &number_of_bytes_sent,
|
|
int flags,
|
|
const struct sockaddr *addr,
|
|
int addrlen,
|
|
ACE_OVERLAPPED *overlapped,
|
|
ACE_OVERLAPPED_COMPLETION_FUNC func)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::sendto");
|
|
#if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0)
|
|
DWORD bytes_sent = 0;
|
|
int result = ::WSASendTo ((SOCKET) handle,
|
|
(WSABUF*) buffers,
|
|
buffer_count,
|
|
&bytes_sent,
|
|
flags,
|
|
addr,
|
|
addrlen,
|
|
overlapped,
|
|
func);
|
|
if (result != 0) {
|
|
ACE_OS::set_errno_to_wsa_last_error ();
|
|
}
|
|
number_of_bytes_sent = static_cast<size_t> (bytes_sent);
|
|
return (ssize_t) result;
|
|
#else
|
|
ACE_UNUSED_ARG (overlapped);
|
|
ACE_UNUSED_ARG (func);
|
|
|
|
number_of_bytes_sent = 0;
|
|
|
|
ssize_t result = 0;
|
|
|
|
for (int i = 0; i < buffer_count; ++i)
|
|
{
|
|
result = ACE_OS::sendto (handle,
|
|
reinterpret_cast<char *> (
|
|
buffers[i].iov_base),
|
|
buffers[i].iov_len,
|
|
flags,
|
|
addr,
|
|
addrlen);
|
|
if (result == -1)
|
|
break;
|
|
number_of_bytes_sent += static_cast<size_t> (result);
|
|
}
|
|
|
|
return result;
|
|
#endif /* defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) */
|
|
}
|
|
|
|
ACE_INLINE ssize_t
|
|
ACE_OS::sendv (ACE_HANDLE handle,
|
|
const iovec *buffers,
|
|
int n)
|
|
{
|
|
#if defined (ACE_HAS_WINSOCK2)
|
|
DWORD bytes_sent = 0;
|
|
ssize_t result = 0;
|
|
|
|
// Winsock 2 has WSASend and can do this directly, but Winsock 1
|
|
// needs to do the sends one-by-one.
|
|
# if (ACE_HAS_WINSOCK2 != 0) && !defined (ACE_DONT_USE_WSASEND)
|
|
result = ::WSASend ((SOCKET) handle,
|
|
(WSABUF *) buffers,
|
|
n,
|
|
&bytes_sent,
|
|
0,
|
|
0,
|
|
0);
|
|
if (result == SOCKET_ERROR)
|
|
{
|
|
ACE_OS::set_errno_to_wsa_last_error ();
|
|
if ((errno != ENOBUFS) ||
|
|
(bytes_sent != 0))
|
|
{
|
|
return -1;
|
|
}
|
|
result = sendv_partial_i(handle, buffers, n);
|
|
if (result == SOCKET_ERROR)
|
|
{
|
|
ACE_OS::set_errno_to_wsa_last_error ();
|
|
return -1;
|
|
}
|
|
bytes_sent = static_cast<DWORD>(result);
|
|
}
|
|
# else
|
|
for (int i = 0; i < n; ++i)
|
|
{
|
|
result = ::send ((SOCKET) handle,
|
|
buffers[i].iov_base,
|
|
buffers[i].iov_len,
|
|
0);
|
|
|
|
if (result == SOCKET_ERROR)
|
|
{
|
|
// There is a subtle difference in behaviour depending on
|
|
// whether or not any data was sent. If no data was sent,
|
|
// then always return -1. Otherwise return bytes_sent.
|
|
// This gives the caller an opportunity to keep track of
|
|
// bytes that have already been sent.
|
|
if (bytes_sent > 0)
|
|
break;
|
|
else
|
|
{
|
|
ACE_OS::set_errno_to_wsa_last_error ();
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Gets ignored on error anyway
|
|
bytes_sent += result;
|
|
|
|
// If the transfer isn't complete just drop out of the loop.
|
|
if (result < (int)buffers[i].iov_len)
|
|
break;
|
|
}
|
|
}
|
|
# endif /* ACE_HAS_WINSOCK2 != 0 */
|
|
|
|
return (ssize_t) bytes_sent;
|
|
|
|
#elif defined (ACE_HAS_SOCK_BUF_SIZE_MAX)
|
|
|
|
// Platform limits the maximum socket message size. Pare down the
|
|
// iovec, if necessary, to obey the limit.
|
|
iovec local_iov[ACE_IOV_MAX];
|
|
long total = 0;
|
|
long new_total = 0;
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
local_iov[i].iov_base = buffers[i].iov_base;
|
|
local_iov[i].iov_len = buffers[i].iov_len;
|
|
|
|
new_total = total + buffers[i].iov_len;
|
|
if (new_total >= ACE_HAS_SOCK_BUF_SIZE_MAX_VALUE)
|
|
{
|
|
local_iov[i].iov_len = ACE_HAS_SOCK_BUF_SIZE_MAX_VALUE - total;
|
|
n = i+1;
|
|
break;
|
|
}
|
|
total = new_total;
|
|
}
|
|
return ACE_OS::writev (handle, local_iov, n);
|
|
|
|
#else
|
|
return ACE_OS::writev (handle, buffers, n);
|
|
#endif /* ACE_HAS_WINSOCK2 */
|
|
}
|
|
|
|
ACE_INLINE int
|
|
ACE_OS::setsockopt (ACE_HANDLE handle,
|
|
int level,
|
|
int optname,
|
|
const char *optval,
|
|
int optlen)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::setsockopt");
|
|
#if defined (ACE_LACKS_SETSOCKOPT)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (level);
|
|
ACE_UNUSED_ARG (optname);
|
|
ACE_UNUSED_ARG (optval);
|
|
ACE_UNUSED_ARG (optlen);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#else
|
|
int result;
|
|
ACE_SOCKCALL (::setsockopt ((ACE_SOCKET) handle,
|
|
level,
|
|
optname,
|
|
(ACE_SOCKOPT_TYPE1) optval,
|
|
optlen),
|
|
int,
|
|
-1,
|
|
result);
|
|
#if defined (WSAEOPNOTSUPP)
|
|
if (result == -1 && (errno == WSAEOPNOTSUPP || errno == WSAENOPROTOOPT))
|
|
#else
|
|
if (result == -1)
|
|
#endif /* WSAEOPNOTSUPP */
|
|
errno = ENOTSUP;
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
ACE_INLINE int
|
|
ACE_OS::shutdown (ACE_HANDLE handle, int how)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::shutdown");
|
|
#if defined (ACE_LACKS_SHUTDOWN)
|
|
ACE_UNUSED_ARG (handle);
|
|
ACE_UNUSED_ARG (how);
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#else
|
|
ACE_SOCKCALL_RETURN (::shutdown ((ACE_SOCKET) handle, how), int, -1);
|
|
#endif /* ACE_LACKS_SHUTDOWN */
|
|
}
|
|
|
|
ACE_INLINE ACE_HANDLE
|
|
ACE_OS::socket (int domain,
|
|
int type,
|
|
int proto)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::socket");
|
|
#if defined (ACE_LACKS_SOCKET)
|
|
ACE_UNUSED_ARG (domain);
|
|
ACE_UNUSED_ARG (type);
|
|
ACE_UNUSED_ARG (proto);
|
|
ACE_NOTSUP_RETURN (ACE_INVALID_HANDLE);
|
|
#else
|
|
ACE_SOCKCALL_RETURN (::socket (domain,
|
|
type,
|
|
proto),
|
|
ACE_HANDLE,
|
|
ACE_INVALID_HANDLE);
|
|
#endif /* ACE_LACKS_SOCKET */
|
|
}
|
|
|
|
ACE_INLINE ACE_HANDLE
|
|
ACE_OS::socket (int domain,
|
|
int type,
|
|
int proto,
|
|
ACE_Protocol_Info *protocolinfo,
|
|
ACE_SOCK_GROUP g,
|
|
u_long flags)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::socket");
|
|
|
|
#if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0)
|
|
ACE_SOCKCALL_RETURN (::WSASocket (domain,
|
|
type,
|
|
proto,
|
|
protocolinfo,
|
|
g,
|
|
flags),
|
|
ACE_HANDLE,
|
|
ACE_INVALID_HANDLE);
|
|
#else
|
|
ACE_UNUSED_ARG (protocolinfo);
|
|
ACE_UNUSED_ARG (g);
|
|
ACE_UNUSED_ARG (flags);
|
|
|
|
return ACE_OS::socket (domain,
|
|
type,
|
|
proto);
|
|
#endif /* ACE_HAS_WINSOCK2 */
|
|
}
|
|
|
|
ACE_INLINE int
|
|
ACE_OS::socketpair (int domain, int type,
|
|
int protocol, ACE_HANDLE sv[2])
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::socketpair");
|
|
#if defined (ACE_LACKS_SOCKETPAIR)
|
|
ACE_UNUSED_ARG (domain);
|
|
ACE_UNUSED_ARG (type);
|
|
ACE_UNUSED_ARG (protocol);
|
|
ACE_UNUSED_ARG (sv);
|
|
|
|
ACE_NOTSUP_RETURN (-1);
|
|
#else
|
|
ACE_OSCALL_RETURN (::socketpair (domain, type, protocol, sv),
|
|
int, -1);
|
|
#endif /* ACE_LACKS_SOCKETPAIR */
|
|
}
|
|
|
|
#if defined (ACE_LINUX) && defined (ACE_HAS_IPV6)
|
|
ACE_INLINE unsigned int
|
|
ACE_OS::if_nametoindex (const char *ifname)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::if_nametoindex");
|
|
ACE_OSCALL_RETURN (::if_nametoindex (ifname), int, 0);
|
|
}
|
|
|
|
ACE_INLINE char *
|
|
ACE_OS::if_indextoname (unsigned int ifindex, char *ifname)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::if_indextoname");
|
|
ACE_OSCALL_RETURN (::if_indextoname (ifindex, ifname), char *, 0);
|
|
}
|
|
|
|
ACE_INLINE struct if_nameindex *
|
|
ACE_OS::if_nameindex (void)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::if_nameindex");
|
|
ACE_OSCALL_RETURN (::if_nameindex (), struct if_nameindex *, 0);
|
|
}
|
|
|
|
ACE_INLINE void
|
|
ACE_OS::if_freenameindex (struct if_nameindex *ptr)
|
|
{
|
|
ACE_OS_TRACE ("ACE_OS::if_freenameindex");
|
|
if (ptr != 0)
|
|
::if_freenameindex (ptr);
|
|
}
|
|
#endif /* ACE_LINUX && ACE_HAS_IPV6 */
|
|
|
|
ACE_END_VERSIONED_NAMESPACE_DECL
|