#include "wx/private/fd.h"
#include "wx/private/socket.h"
+#ifdef __UNIX__
+ #include <errno.h>
+#endif
+
+// we use MSG_NOSIGNAL to avoid getting SIGPIPE when sending data to a remote
+// host which closed the connection if it is available, otherwise we rely on
+// SO_NOSIGPIPE existency
+//
+// this should cover all the current Unix systems (Windows never sends any
+// signals anyhow) but if we find one that has neither we should explicitly
+// ignore SIGPIPE for it
+#ifdef MSG_NOSIGNAL
+ #define wxSOCKET_MSG_NOSIGNAL MSG_NOSIGNAL
+#else // MSG_NOSIGNAL not available (BSD including OS X)
+ #if defined(__UNIX__) && !defined(SO_NOSIGPIPE)
+ #error "Writing to socket could generate unhandled SIGPIPE."
+ #error "Please post information about your system to wx-dev."
+ #endif
+
+ #define wxSOCKET_MSG_NOSIGNAL 0
+#endif
+
// DLL options compatibility check:
#include "wx/build.h"
WX_CHECK_BUILD_OPTIONS("wxNet")
: m_wxsocket(&wxsocket)
{
m_fd = INVALID_SOCKET;
- m_local = NULL;
- m_peer = NULL;
m_error = wxSOCKET_NOERROR;
m_server = false;
m_stream = true;
wxSocketImpl::~wxSocketImpl()
{
- if (m_fd != INVALID_SOCKET)
+ if ( m_fd != INVALID_SOCKET )
Shutdown();
-
- if (m_local)
- GAddress_destroy(m_local);
-
- if (m_peer)
- GAddress_destroy(m_peer);
}
-bool wxSocketImpl::PreCreateCheck(GAddress *addr)
+bool wxSocketImpl::PreCreateCheck(const wxSockAddressImpl& addr)
{
if ( m_fd != INVALID_SOCKET )
{
return false;
}
- if ( !addr || !addr->m_addr )
+ if ( !addr.IsOk() )
{
m_error = wxSOCKET_INVADDR;
return false;
wxSocketError wxSocketImpl::UpdateLocalAddress()
{
- WX_SOCKLEN_T lenAddr = sizeof(*m_local->m_addr);
- if ( getsockname(m_fd, m_local->m_addr, &lenAddr) != 0 )
+ WX_SOCKLEN_T lenAddr = m_local.GetLen();
+ if ( getsockname(m_fd, m_local.GetWritableAddr(), &lenAddr) != 0 )
{
Close();
m_error = wxSOCKET_IOERR;
return m_error;
}
- m_local->m_len = lenAddr;
-
return wxSOCKET_NOERROR;
}
m_stream = true;
// do create the socket
- m_fd = socket(m_local->m_realfamily, SOCK_STREAM, 0);
+ m_fd = socket(m_local.GetFamily(), SOCK_STREAM, 0);
if ( m_fd == INVALID_SOCKET )
{
// and then bind to and listen on it
//
// FIXME: should we test for m_dobind here?
- if ( bind(m_fd, m_local->m_addr, m_local->m_len) != 0 )
+ if ( bind(m_fd, m_local.GetAddr(), m_local.GetLen()) != 0 )
m_error = wxSOCKET_IOERR;
if ( IsOk() )
if ( !PreCreateCheck(m_peer) )
return m_error;
- m_fd = socket(m_peer->m_realfamily, SOCK_STREAM, 0);
+ m_fd = socket(m_peer.GetFamily(), SOCK_STREAM, 0);
if ( m_fd == INVALID_SOCKET )
{
PostCreation();
// If a local address has been set, then bind to it before calling connect
- if ( m_local && m_local->m_addr )
+ if ( m_local.IsOk() )
{
- if ( bind(m_fd, m_local->m_addr, m_local->m_len) != 0 )
+ if ( bind(m_fd, m_local.GetAddr(), m_local.GetLen()) != 0 )
{
Close();
m_error = wxSOCKET_IOERR;
}
// Do connect now
- int rc = connect(m_fd, m_peer->m_addr, m_peer->m_len);
+ int rc = connect(m_fd, m_peer.GetAddr(), m_peer.GetLen());
if ( rc == SOCKET_ERROR )
{
wxSocketError err = GetLastError();
m_stream = false;
m_server = false;
- m_fd = socket(m_local->m_realfamily, SOCK_DGRAM, 0);
+ m_fd = socket(m_local.GetFamily(), SOCK_DGRAM, 0);
if ( m_fd == INVALID_SOCKET )
{
if ( m_dobind )
{
- if ( bind(m_fd, m_local->m_addr, m_local->m_len) != 0 )
+ if ( bind(m_fd, m_local.GetAddr(), m_local.GetLen()) != 0 )
{
Close();
m_error = wxSOCKET_IOERR;
wxSocketImpl *wxSocketImpl::Accept(wxSocketBase& wxsocket)
{
- wxSockAddr from;
+ wxSockAddressStorage from;
WX_SOCKLEN_T fromlen = sizeof(from);
- const SOCKET fd = accept(m_fd, &from, &fromlen);
+ const SOCKET fd = accept(m_fd, &from.addr, &fromlen);
if ( fd == INVALID_SOCKET )
return NULL;
wxSocketImpl * const sock = Create(wxsocket);
sock->m_fd = fd;
-
- sock->m_peer = GAddress_new();
- _GAddress_translate_from(sock->m_peer, &from, fromlen);
+ sock->m_peer = wxSockAddressImpl(from.addr, fromlen);
sock->UnblockAndRegisterWithEventLoop();
}
/* Address handling */
+wxSocketError wxSocketImpl::SetLocal(const wxSockAddressImpl& local)
+{
+ /* the socket must be initialized, or it must be a server */
+ if (m_fd != INVALID_SOCKET && !m_server)
+ {
+ m_error = wxSOCKET_INVSOCK;
+ return wxSOCKET_INVSOCK;
+ }
-/*
- * Set or get the local or peer address for this socket. The 'set'
- * functions return wxSOCKET_NOERROR on success, an error code otherwise.
- * The 'get' functions return a pointer to a GAddress object on success,
- * or NULL otherwise, in which case they set the error code of the
- * corresponding socket.
- *
- * Error codes:
- * wxSOCKET_INVSOCK - the socket is not valid.
- * wxSOCKET_INVADDR - the address is not valid.
- */
-wxSocketError wxSocketImpl::SetLocal(GAddress *address)
+ if ( !local.IsOk() )
+ {
+ m_error = wxSOCKET_INVADDR;
+ return wxSOCKET_INVADDR;
+ }
+
+ m_local = local;
+
+ return wxSOCKET_NOERROR;
+}
+
+wxSocketError wxSocketImpl::SetPeer(const wxSockAddressImpl& peer)
+{
+ if ( !peer.IsOk() )
+ {
+ m_error = wxSOCKET_INVADDR;
+ return wxSOCKET_INVADDR;
+ }
+
+ m_peer = peer;
+
+ return wxSOCKET_NOERROR;
+}
+
+const wxSockAddressImpl& wxSocketImpl::GetLocal()
+{
+ if ( !m_local.IsOk() )
+ UpdateLocalAddress();
+
+ return m_local;
+}
+
+// ----------------------------------------------------------------------------
+// wxSocketImpl IO
+// ----------------------------------------------------------------------------
+
+// this macro wraps the given expression (normally a syscall) in a loop which
+// ignores any interruptions, i.e. reevaluates it again if it failed and errno
+// is EINTR
+#ifdef __UNIX__
+ #define DO_WHILE_EINTR( rc, syscall ) \
+ do { \
+ rc = (syscall); \
+ } \
+ while ( rc == -1 && errno == EINTR )
+#else
+ #define DO_WHILE_EINTR( rc, syscall ) rc = (syscall)
+#endif
+
+int wxSocketImpl::RecvStream(void *buffer, int size)
{
- /* the socket must be initialized, or it must be a server */
- if (m_fd != INVALID_SOCKET && !m_server)
- {
- m_error = wxSOCKET_INVSOCK;
- return wxSOCKET_INVSOCK;
- }
+ int ret;
+ DO_WHILE_EINTR( ret, recv(m_fd, static_cast<char *>(buffer), size, 0) );
+
+ if ( !ret )
+ {
+ // receiving 0 bytes for a TCP socket indicates that the connection was
+ // closed by peer so shut down our end as well (for UDP sockets empty
+ // datagrams are also possible)
+ m_establishing = false;
+ NotifyOnStateChange(wxSOCKET_LOST);
- /* check address */
- if (address == NULL || address->m_family == wxSOCKET_NOFAMILY)
- {
- m_error = wxSOCKET_INVADDR;
- return wxSOCKET_INVADDR;
- }
+ Shutdown();
- if (m_local)
- GAddress_destroy(m_local);
+ // do not return an error in this case however
+ }
+
+ return ret;
+}
- m_local = GAddress_copy(address);
+int wxSocketImpl::SendStream(const void *buffer, int size)
+{
+ int ret;
+ DO_WHILE_EINTR( ret, send(m_fd, static_cast<const char *>(buffer), size,
+ wxSOCKET_MSG_NOSIGNAL) );
- return wxSOCKET_NOERROR;
+ return ret;
}
-wxSocketError wxSocketImpl::SetPeer(GAddress *address)
+int wxSocketImpl::RecvDgram(void *buffer, int size)
{
- /* check address */
- if (address == NULL || address->m_family == wxSOCKET_NOFAMILY)
- {
- m_error = wxSOCKET_INVADDR;
- return wxSOCKET_INVADDR;
- }
+ wxSockAddressStorage from;
+ WX_SOCKLEN_T fromlen = sizeof(from);
+
+ int ret;
+ DO_WHILE_EINTR( ret, recvfrom(m_fd, static_cast<char *>(buffer), size,
+ 0, &from.addr, &fromlen) );
- if (m_peer)
- GAddress_destroy(m_peer);
+ if ( ret == SOCKET_ERROR )
+ return SOCKET_ERROR;
- m_peer = GAddress_copy(address);
+ m_peer = wxSockAddressImpl(from.addr, fromlen);
+ if ( !m_peer.IsOk() )
+ return -1;
- return wxSOCKET_NOERROR;
+ return ret;
}
-GAddress *wxSocketImpl::GetLocal()
+int wxSocketImpl::SendDgram(const void *buffer, int size)
{
- GAddress *address;
- wxSockAddr addr;
- WX_SOCKLEN_T size = sizeof(addr);
- wxSocketError err;
+ if ( !m_peer.IsOk() )
+ {
+ m_error = wxSOCKET_INVADDR;
+ return -1;
+ }
- /* try to get it from the m_local var first */
- if (m_local)
- return GAddress_copy(m_local);
+ int ret;
+ DO_WHILE_EINTR( ret, sendto(m_fd, static_cast<const char *>(buffer), size,
+ 0, m_peer.GetAddr(), m_peer.GetLen()) );
- /* else, if the socket is initialized, try getsockname */
- if (m_fd == INVALID_SOCKET)
- {
- m_error = wxSOCKET_INVSOCK;
- return NULL;
- }
+ return ret;
+}
- if (getsockname(m_fd, (sockaddr*)&addr, &size) == SOCKET_ERROR)
- {
- m_error = wxSOCKET_IOERR;
- return NULL;
- }
+int wxSocketImpl::Read(void *buffer, int size)
+{
+ // server sockets can't be used for IO, only to accept new connections
+ if ( m_fd == INVALID_SOCKET || m_server )
+ {
+ m_error = wxSOCKET_INVSOCK;
+ return -1;
+ }
- /* got a valid address from getsockname, create a GAddress object */
- if ((address = GAddress_new()) == NULL)
- {
- m_error = wxSOCKET_MEMERR;
- return NULL;
- }
+ int ret = m_stream ? RecvStream(buffer, size)
+ : RecvDgram(buffer, size);
- if ((err = _GAddress_translate_from(address, (sockaddr*)&addr, size)) != wxSOCKET_NOERROR)
- {
- GAddress_destroy(address);
- m_error = err;
- return NULL;
- }
+ m_error = ret == SOCKET_ERROR ? GetLastError() : wxSOCKET_NOERROR;
- return address;
+ return ret;
}
-GAddress *wxSocketImpl::GetPeer()
+int wxSocketImpl::Write(const void *buffer, int size)
{
- /* try to get it from the m_peer var */
- if (m_peer)
- return GAddress_copy(m_peer);
+ if ( m_fd == INVALID_SOCKET || m_server )
+ {
+ m_error = wxSOCKET_INVSOCK;
+ return -1;
+ }
+
+ int ret = m_stream ? SendStream(buffer, size)
+ : SendDgram(buffer, size);
- return NULL;
+ m_error = ret == SOCKET_ERROR ? GetLastError() : wxSOCKET_NOERROR;
+
+ return ret;
}
// ==========================================================================
// Get local or peer address
//
-bool wxSocketBase::GetPeer(wxSockAddress& addr_man) const
+bool wxSocketBase::GetPeer(wxSockAddress& addr) const
{
- GAddress *peer;
+ wxCHECK_MSG( m_impl, false, "invalid socket" );
- if (!m_impl)
+ const wxSockAddressImpl& peer = m_impl->GetPeer();
+ if ( !peer.IsOk() )
return false;
- peer = m_impl->GetPeer();
-
- // copying a null address would just trigger an assert anyway
-
- if (!peer)
- return false;
-
- addr_man.SetAddress(peer);
- GAddress_destroy(peer);
+ addr.SetAddress(peer);
return true;
}
-bool wxSocketBase::GetLocal(wxSockAddress& addr_man) const
+bool wxSocketBase::GetLocal(wxSockAddress& addr) const
{
- GAddress *local;
+ wxCHECK_MSG( m_impl, false, "invalid socket" );
- if (!m_impl)
+ const wxSockAddressImpl& local = m_impl->GetLocal();
+ if ( !local.IsOk() )
return false;
- local = m_impl->GetLocal();
- addr_man.SetAddress(local);
- GAddress_destroy(local);
+ addr.SetAddress(local);
return true;
}
// Ctor
// --------------------------------------------------------------------------
-wxSocketServer::wxSocketServer(const wxSockAddress& addr_man,
+wxSocketServer::wxSocketServer(const wxSockAddress& addr,
wxSocketFlags flags)
: wxSocketBase(flags, wxSOCKET_SERVER)
{
}
// Setup the socket as server
- m_impl->SetLocal(addr_man.GetAddress());
+ m_impl->SetLocal(addr.GetAddress());
if (GetFlags() & wxSOCKET_REUSEADDR) {
m_impl->SetReusable();
bool wxSocketBase::SetLocal(const wxIPV4address& local)
{
- GAddress* la = local.GetAddress();
-
- // If the address is valid, save it for use when we call Connect
- if (la && la->m_addr)
- {
- m_localAddress = local;
+ m_localAddress = local;
- return true;
- }
-
- return false;
+ return true;
}
// ==========================================================================
// Bind to the local IP address and port, when provided or if one had been
// set before
- if ( !local && m_localAddress.GetAddress() )
+ if ( !local && m_localAddress.GetAddress().IsOk() )
local = &m_localAddress;
if ( local )