From 14372de82e2129fab7d416de79fc3d95e57960b9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 27 Dec 2008 22:49:46 +0000 Subject: [PATCH] move Read/Write() to common code, there was almost nothing platform-specific in it git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57613 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/private/sockmsw.h | 8 -- include/wx/private/socket.h | 13 +- include/wx/unix/private/sockunix.h | 10 -- src/common/socket.cpp | 152 ++++++++++++++++++++ src/msw/sockmsw.cpp | 134 ----------------- src/unix/sockunix.cpp | 221 ++--------------------------- 6 files changed, 173 insertions(+), 365 deletions(-) diff --git a/include/wx/msw/private/sockmsw.h b/include/wx/msw/private/sockmsw.h index 5f722c5083..1c0a6fe627 100644 --- a/include/wx/msw/private/sockmsw.h +++ b/include/wx/msw/private/sockmsw.h @@ -39,9 +39,6 @@ public: virtual wxSocketError GetLastError() const; - virtual int Read(void *buffer, int size); - virtual int Write(const void *buffer, int size); - private: virtual void DoClose(); @@ -52,11 +49,6 @@ private: wxSocketManager::Get()->Install_Callback(this); } - int Recv_Stream(void *buffer, int size); - int Recv_Dgram(void *buffer, int size); - int Send_Stream(const void *buffer, int size); - int Send_Dgram(const void *buffer, int size); - int m_msgnumber; friend class wxSocketMSWManager; diff --git a/include/wx/private/socket.h b/include/wx/private/socket.h index d546a91acc..d25f8d0481 100644 --- a/include/wx/private/socket.h +++ b/include/wx/private/socket.h @@ -260,8 +260,11 @@ public: // IO operations // ------------- - virtual int Read(void *buffer, int size) = 0; - virtual int Write(const void *buffer, int size) = 0; + // basic IO, work for both TCP and UDP sockets + // + // return the number of bytes read/written (possibly 0) or -1 on error + int Read(void *buffer, int size); + int Write(const void *buffer, int size); // basically a wrapper for select(): returns the condition of the socket, // blocking for not longer than timeout if it is specified (otherwise just @@ -355,6 +358,12 @@ private: // update local address after binding/connecting wxSocketError UpdateLocalAddress(); + // functions used to implement Read/Write() + int RecvStream(void *buffer, int size); + int RecvDgram(void *buffer, int size); + int SendStream(const void *buffer, int size); + int SendDgram(const void *buffer, int size); + // set in ctor and never changed except that it's reset to NULL when the // socket is shut down diff --git a/include/wx/unix/private/sockunix.h b/include/wx/unix/private/sockunix.h index d51d75f130..4ff2164b44 100644 --- a/include/wx/unix/private/sockunix.h +++ b/include/wx/unix/private/sockunix.h @@ -31,9 +31,6 @@ public: virtual wxSocketError GetLastError() const; - virtual int Read(void *buffer, int size); - virtual int Write(const void *buffer, int size); - // wxFDIOHandler methods virtual void OnReadWaiting(); virtual void OnWriteWaiting(); @@ -70,13 +67,6 @@ private: // really enable or disable socket input/output events void DoEnableEvents(bool enable); - - int Recv_Stream(void *buffer, int size); - int Recv_Dgram(void *buffer, int size); - int Send_Stream(const void *buffer, int size); - int Send_Dgram(const void *buffer, int size); - - protected: // descriptors for input and output event notification channels associated // with the socket diff --git a/src/common/socket.cpp b/src/common/socket.cpp index dd9cd502c0..ccfb23438c 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -46,6 +46,28 @@ #include "wx/private/fd.h" #include "wx/private/socket.h" +#ifdef __UNIX__ + #include +#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") @@ -533,6 +555,136 @@ GAddress *wxSocketImpl::GetPeer() return NULL; } +// ---------------------------------------------------------------------------- +// 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) +{ + int ret; + DO_WHILE_EINTR( ret, recv(m_fd, static_cast(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); + + Shutdown(); + + // do not return an error in this case however + } + + return ret; +} + +int wxSocketImpl::SendStream(const void *buffer, int size) +{ + int ret; + DO_WHILE_EINTR( ret, send(m_fd, static_cast(buffer), size, + wxSOCKET_MSG_NOSIGNAL) ); + + return ret; +} + +int wxSocketImpl::RecvDgram(void *buffer, int size) +{ + wxSockAddr from; + WX_SOCKLEN_T fromlen = sizeof(from); + + int ret; + DO_WHILE_EINTR( ret, recvfrom(m_fd, static_cast(buffer), size, + 0, &from, &fromlen) ); + + if ( ret == SOCKET_ERROR ) + return SOCKET_ERROR; + + /* Translate a system address into a wxSocketImpl address */ + if ( !m_peer ) + m_peer = GAddress_new(); + + m_error = _GAddress_translate_from(m_peer, &from, fromlen); + if ( m_error != wxSOCKET_NOERROR ) + { + GAddress_destroy(m_peer); + m_peer = NULL; + return -1; + } + + return ret; +} + +int wxSocketImpl::SendDgram(const void *buffer, int size) +{ + if ( !m_peer ) + { + m_error = wxSOCKET_INVADDR; + return -1; + } + + struct sockaddr *addr; + int len; + m_error = _GAddress_translate_to(m_peer, &addr, &len); + if ( m_error != wxSOCKET_NOERROR ) + return -1; + + int ret; + DO_WHILE_EINTR( ret, sendto(m_fd, static_cast(buffer), size, + 0, addr, len) ); + + free(addr); + + return ret; +} + +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; + } + + int ret = m_stream ? RecvStream(buffer, size) + : RecvDgram(buffer, size); + + m_error = ret == SOCKET_ERROR ? GetLastError() : wxSOCKET_NOERROR; + + return ret; +} + +int wxSocketImpl::Write(const void *buffer, int size) +{ + if ( m_fd == INVALID_SOCKET || m_server ) + { + m_error = wxSOCKET_INVSOCK; + return -1; + } + + int ret = m_stream ? SendStream(buffer, size) + : SendDgram(buffer, size); + + m_error = ret == SOCKET_ERROR ? GetLastError() : wxSOCKET_NOERROR; + + return ret; +} + // ========================================================================== // wxSocketBase // ========================================================================== diff --git a/src/msw/sockmsw.cpp b/src/msw/sockmsw.cpp index e0336fee60..dc20dcf9ba 100644 --- a/src/msw/sockmsw.cpp +++ b/src/msw/sockmsw.cpp @@ -466,140 +466,6 @@ wxSocketError wxSocketImplMSW::GetLastError() const } } -/* Generic IO */ - -/* Like recv(), send(), ... */ -int wxSocketImplMSW::Read(void *buffer, int size) -{ - int ret; - - if (m_fd == INVALID_SOCKET || m_server) - { - m_error = wxSOCKET_INVSOCK; - return -1; - } - - /* Read the data */ - if (m_stream) - ret = Recv_Stream(buffer, size); - else - ret = Recv_Dgram(buffer, size); - - if (ret == SOCKET_ERROR) - { - if (WSAGetLastError() != WSAEWOULDBLOCK) - m_error = wxSOCKET_IOERR; - else - m_error = wxSOCKET_WOULDBLOCK; - return -1; - } - - return ret; -} - -int wxSocketImplMSW::Write(const void *buffer, int size) -{ - int ret; - - if (m_fd == INVALID_SOCKET || m_server) - { - m_error = wxSOCKET_INVSOCK; - return -1; - } - - /* Write the data */ - if (m_stream) - ret = Send_Stream(buffer, size); - else - ret = Send_Dgram(buffer, size); - - if (ret == SOCKET_ERROR) - { - if (WSAGetLastError() != WSAEWOULDBLOCK) - m_error = wxSOCKET_IOERR; - else - m_error = wxSOCKET_WOULDBLOCK; - - return -1; - } - - return ret; -} - -/* Internals (IO) */ - -int wxSocketImplMSW::Recv_Stream(void *buffer, int size) -{ - return recv(m_fd, static_cast(buffer), size, 0); -} - -int wxSocketImplMSW::Recv_Dgram(void *buffer, int size) -{ - wxSockAddr from; - WX_SOCKLEN_T fromlen = sizeof(from); - int ret; - wxSocketError err; - - ret = recvfrom(m_fd, static_cast(buffer), - size, 0, &from, &fromlen); - - if (ret == SOCKET_ERROR) - return SOCKET_ERROR; - - /* Translate a system address into a wxSocketImpl address */ - if (!m_peer) - { - m_peer = GAddress_new(); - if (!m_peer) - { - m_error = wxSOCKET_MEMERR; - return -1; - } - } - err = _GAddress_translate_from(m_peer, (sockaddr*)&from, fromlen); - if (err != wxSOCKET_NOERROR) - { - GAddress_destroy(m_peer); - m_peer = NULL; - m_error = err; - return -1; - } - - return ret; -} - -int wxSocketImplMSW::Send_Stream(const void *buffer, int size) -{ - return send(m_fd, static_cast(buffer), size, 0); -} - -int wxSocketImplMSW::Send_Dgram(const void *buffer, int size) -{ - struct sockaddr *addr; - int len, ret; - wxSocketError err; - - if (!m_peer) - { - m_error = wxSOCKET_INVADDR; - return -1; - } - - err = _GAddress_translate_to(m_peer, &addr, &len); - if (err != wxSOCKET_NOERROR) - { - m_error = err; - return -1; - } - - ret = sendto(m_fd, static_cast(buffer), size, 0, addr, len); - - /* Frees memory allocated by _GAddress_translate_to */ - free(addr); - - return ret; -} - /* * ------------------------------------------------------------------------- * GAddress diff --git a/src/unix/sockunix.cpp b/src/unix/sockunix.cpp index 30a417ecc3..d0020dfbdb 100644 --- a/src/unix/sockunix.cpp +++ b/src/unix/sockunix.cpp @@ -146,34 +146,6 @@ int _System soclose(int); #define INADDR_NONE INADDR_BROADCAST #endif -#if defined(__VISAGECPP__) || defined(__WATCOMC__) - - #define MASK_SIGNAL() { - #define UNMASK_SIGNAL() } - -#else - extern "C" { typedef void (*wxSigHandler)(int); } - - #define MASK_SIGNAL() \ - { \ - wxSigHandler old_handler = signal(SIGPIPE, SIG_IGN); - - #define UNMASK_SIGNAL() \ - signal(SIGPIPE, old_handler); \ - } - -#endif - -/* If a SIGPIPE is issued by a socket call on a remotely closed socket, - the program will "crash" unless it explicitly handles the SIGPIPE. - By using MSG_NOSIGNAL, the SIGPIPE is suppressed. Later, we will - use SO_NOSIGPIPE (if available), the BSD equivalent. */ -#ifdef MSG_NOSIGNAL -# define GSOCKET_MSG_NOSIGNAL MSG_NOSIGNAL -#else /* MSG_NOSIGNAL not available (FreeBSD including OS X) */ -# define GSOCKET_MSG_NOSIGNAL 0 -#endif /* MSG_NOSIGNAL */ - // ---------------------------------------------------------------------------- // implementation of thread-safe/reentrant functions if they're missing // ---------------------------------------------------------------------------- @@ -452,7 +424,16 @@ wxSocketError wxSocketImplUnix::GetLastError() const // unfortunately EAGAIN only has the "would block" meaning for read(), // not for connect() for which it means something rather different but // we can't distinguish between these two situations currently... + // + // also notice that EWOULDBLOCK can be different from EAGAIN on some + // systems (HP-UX being the only known example) while it's defined as + // EAGAIN on most others (e.g. Linux) case EAGAIN: +#ifdef EWOULDBLOCK + #if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: + #endif +#endif // EWOULDBLOCK case EINPROGRESS: return wxSOCKET_WOULDBLOCK; @@ -476,188 +457,6 @@ void wxSocketImplUnix::DoEnableEvents(bool flag) } } -/* Generic IO */ - -/* Like recv(), send(), ... */ -int wxSocketImplUnix::Read(void *buffer, int size) -{ - int ret; - - if (m_fd == INVALID_SOCKET || m_server) - { - m_error = wxSOCKET_INVSOCK; - return -1; - } - - /* Read the data */ - if (m_stream) - ret = Recv_Stream(buffer, size); - else - ret = Recv_Dgram(buffer, size); - - /* - * If recv returned zero for a TCP socket (if m_stream == NULL, it's an UDP - * socket and empty datagrams are possible), then the connection has been - * gracefully closed. - * - * Otherwise, recv has returned an error (-1), in which case we have lost - * the socket only if errno does _not_ indicate that there may be more data - * to read. - */ - if ((ret == 0) && m_stream) - { - m_establishing = false; - OnStateChange(wxSOCKET_LOST); - return 0; - } - else if (ret == -1) - { - if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) - m_error = wxSOCKET_WOULDBLOCK; - else - m_error = wxSOCKET_IOERR; - } - - return ret; -} - -int wxSocketImplUnix::Write(const void *buffer, int size) -{ - int ret; - - if (m_fd == INVALID_SOCKET || m_server) - { - m_error = wxSOCKET_INVSOCK; - return -1; - } - - /* Write the data */ - if (m_stream) - ret = Send_Stream(buffer, size); - else - ret = Send_Dgram(buffer, size); - - if (ret == -1) - { - if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) - { - m_error = wxSOCKET_WOULDBLOCK; - } - else - { - m_error = wxSOCKET_IOERR; - } - } - - return ret; -} - -/* Flags */ - -int wxSocketImplUnix::Recv_Stream(void *buffer, int size) -{ - int ret; - do - { - ret = recv(m_fd, buffer, size, GSOCKET_MSG_NOSIGNAL); - } - while (ret == -1 && errno == EINTR); /* Loop until not interrupted */ - - return ret; -} - -int wxSocketImplUnix::Recv_Dgram(void *buffer, int size) -{ - wxSockAddr from; - WX_SOCKLEN_T fromlen = sizeof(from); - int ret; - wxSocketError err; - - fromlen = sizeof(from); - - do - { - ret = recvfrom(m_fd, buffer, size, 0, (sockaddr*)&from, (WX_SOCKLEN_T *) &fromlen); - } - while (ret == -1 && errno == EINTR); /* Loop until not interrupted */ - - if (ret == -1) - return -1; - - /* Translate a system address into a wxSocketImplUnix address */ - if (!m_peer) - { - m_peer = GAddress_new(); - if (!m_peer) - { - m_error = wxSOCKET_MEMERR; - return -1; - } - } - - err = _GAddress_translate_from(m_peer, (sockaddr*)&from, fromlen); - if (err != wxSOCKET_NOERROR) - { - GAddress_destroy(m_peer); - m_peer = NULL; - m_error = err; - return -1; - } - - return ret; -} - -int wxSocketImplUnix::Send_Stream(const void *buffer, int size) -{ - int ret; - - MASK_SIGNAL(); - - do - { - ret = send(m_fd, buffer, size, GSOCKET_MSG_NOSIGNAL); - } - while (ret == -1 && errno == EINTR); /* Loop until not interrupted */ - - UNMASK_SIGNAL(); - - return ret; -} - -int wxSocketImplUnix::Send_Dgram(const void *buffer, int size) -{ - struct sockaddr *addr; - int len, ret; - wxSocketError err; - - if (!m_peer) - { - m_error = wxSOCKET_INVADDR; - return -1; - } - - err = _GAddress_translate_to(m_peer, &addr, &len); - if (err != wxSOCKET_NOERROR) - { - m_error = err; - return -1; - } - - MASK_SIGNAL(); - - do - { - ret = sendto(m_fd, buffer, size, 0, addr, len); - } - while (ret == -1 && errno == EINTR); /* Loop until not interrupted */ - - UNMASK_SIGNAL(); - - /* Frees memory allocated from _GAddress_translate_to */ - free(addr); - - return ret; -} void wxSocketImplUnix::OnStateChange(wxSocketNotify event) { @@ -676,7 +475,7 @@ void wxSocketImplUnix::OnReadWaiting() return; } - int num = recv(m_fd, &c, 1, MSG_PEEK | GSOCKET_MSG_NOSIGNAL); + int num = recv(m_fd, &c, 1, MSG_PEEK); if (num > 0) { -- 2.45.2