From: Vadim Zeitlin Date: Sat, 27 Dec 2008 17:15:22 +0000 (+0000) Subject: our sockets are always non-blocking anyhow so throw away all the code dealing with... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/2b036c4b2365723b4c52890bd4c2f6bde20bbc00 our sockets are always non-blocking anyhow so throw away all the code dealing with checking if they're blocking; also merge Unix/Win32 versions of connect() and accept() handling as they were almost identical except for the different checking of the return value which was factored out into a platform-specific GetLastError() function git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57600 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/msw/private/sockmsw.h b/include/wx/msw/private/sockmsw.h index 2490b15482..13319931cd 100644 --- a/include/wx/msw/private/sockmsw.h +++ b/include/wx/msw/private/sockmsw.h @@ -37,14 +37,12 @@ public: virtual ~wxSocketImplMSW(); - virtual wxSocketImpl *WaitConnection(wxSocketBase& wxsocket); + virtual wxSocketError GetLastError() const; - - int Read(void *buffer, int size); - int Write(const void *buffer, int size); + virtual int Read(void *buffer, int size); + virtual int Write(const void *buffer, int size); private: - virtual wxSocketError DoHandleConnect(int ret); virtual void DoClose(); virtual void UnblockAndRegisterWithEventLoop() diff --git a/include/wx/private/socket.h b/include/wx/private/socket.h index 078593477f..97efcbbc6f 100644 --- a/include/wx/private/socket.h +++ b/include/wx/private/socket.h @@ -191,7 +191,6 @@ public: // set various socket properties: all of those can only be called before // creating the socket void SetTimeout(unsigned long millisec); - void SetNonBlocking(bool non_blocking) { m_non_blocking = non_blocking; } void SetReusable() { m_reusable = true; } void SetBroadcast() { m_broadcast = true; } void DontDoBind() { m_dobind = false; } @@ -207,12 +206,17 @@ public: // accessors // --------- + bool IsServer() const { return m_server; } + GAddress *GetLocal(); GAddress *GetPeer(); wxSocketError GetError() const { return m_error; } bool IsOk() const { return m_error == wxSOCKET_NOERROR; } + // get the error code corresponding to the last operation + virtual wxSocketError GetLastError() const = 0; + // creating/closing the socket // -------------------------- @@ -235,8 +239,8 @@ public: // (notice that DontDoBind() is ignored by this function) // // this function may return wxSOCKET_WOULDBLOCK in addition to the return - // values listed above - wxSocketError CreateClient(); + // values listed above if wait is false + wxSocketError CreateClient(bool wait); // create (and bind unless DontDoBind() had been called) an UDP socket // associated with the given local address @@ -256,15 +260,25 @@ public: virtual int Write(const void *buffer, int size) = 0; // basically a wrapper for select(): returns the condition of the socket, - // blocking for not longer than timeout ms for something to become - // available + // blocking for not longer than timeout if it is specified (otherwise just + // poll without blocking at all) // // flags defines what kind of conditions we're interested in, the return // value is composed of a (possibly empty) subset of the bits set in flags wxSocketEventFlags Select(wxSocketEventFlags flags, - unsigned long timeout = 0); + const timeval *timeout = NULL); + + // convenient wrapper calling Select() with our default timeout + wxSocketEventFlags SelectWithTimeout(wxSocketEventFlags flags) + { + return Select(flags, &m_timeout); + } - virtual wxSocketImpl *WaitConnection(wxSocketBase& wxsocket) = 0; + // just a wrapper for accept(): it is called to create a new wxSocketImpl + // corresponding to a new server connection represented by the given + // wxSocketBase, returns NULL on error (including immediately if there are + // no pending connections as our sockets are non-blocking) + wxSocketImpl *Accept(wxSocketBase& wxsocket); // notifications @@ -286,8 +300,6 @@ public: GAddress *m_peer; wxSocketError m_error; - bool m_non_blocking; - bool m_server; bool m_stream; bool m_establishing; bool m_reusable; @@ -301,20 +313,10 @@ public: protected: wxSocketImpl(wxSocketBase& wxsocket); - // wait until input/output becomes available or m_timeout expires - // - // returns true if we do have input/output or false on timeout or error - // (also sets m_error accordingly) - bool BlockForInputWithTimeout() - { return DoBlockWithTimeout(wxSOCKET_INPUT_FLAG); } - bool BlockForOutputWithTimeout() - { return DoBlockWithTimeout(wxSOCKET_OUTPUT_FLAG); } + // true if we're a listening stream socket + bool m_server; private: - // handle the given connect() return value (which may be 0 or EWOULDBLOCK - // or something else) - virtual wxSocketError DoHandleConnect(int ret) = 0; - // called by Close() if we have a valid m_fd virtual void DoClose() = 0; @@ -351,12 +353,6 @@ private: // update local address after binding/connecting wxSocketError UpdateLocalAddress(); - // wait for IO on the socket or until timeout expires - // - // the parameter can be one of wxSOCKET_INPUT/OUTPUT_FLAG (but could be - // their combination in the future, hence we take wxSocketEventFlags) - bool DoBlockWithTimeout(wxSocketEventFlags flags); - // 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 a104888488..ac36bb315b 100644 --- a/include/wx/unix/private/sockunix.h +++ b/include/wx/unix/private/sockunix.h @@ -29,11 +29,12 @@ public: m_enabledCallbacks = 0; } + virtual wxSocketError GetLastError() const; + virtual void Shutdown(); - virtual wxSocketImpl *WaitConnection(wxSocketBase& wxsocket); - int Read(void *buffer, int size); - int Write(const void *buffer, int size); + virtual int Read(void *buffer, int size); + virtual int Write(const void *buffer, int size); // wxFDIOHandler methods virtual void OnReadWaiting(); @@ -49,7 +50,6 @@ public: int GetEnabledCallbacks() const { return m_enabledCallbacks; } private: - virtual wxSocketError DoHandleConnect(int ret); virtual void DoClose() { wxSocketManager * const manager = wxSocketManager::Get(); @@ -151,7 +151,7 @@ protected: case wxSOCKET_CONNECTION: // FIXME: explain this? - return socket->m_server ? FD_INPUT : FD_OUTPUT; + return socket->IsServer() ? FD_INPUT : FD_OUTPUT; } } diff --git a/src/common/socket.cpp b/src/common/socket.cpp index a02d9e9682..222ca488ba 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -102,31 +102,6 @@ public: DECLARE_NO_COPY_CLASS(wxSocketState) }; -// Conditionally make the socket non-blocking for the lifetime of this object. -class wxSocketUnblocker -{ -public: - wxSocketUnblocker(wxSocketImpl *socket, bool unblock = true) - : m_impl(socket), - m_unblock(unblock) - { - if ( m_unblock ) - m_impl->SetNonBlocking(true); - } - - ~wxSocketUnblocker() - { - if ( m_unblock ) - m_impl->SetNonBlocking(false); - } - -private: - wxSocketImpl * const m_impl; - bool m_unblock; - - DECLARE_NO_COPY_CLASS(wxSocketUnblocker) -}; - // ============================================================================ // wxSocketManager // ============================================================================ @@ -185,7 +160,6 @@ wxSocketImpl::wxSocketImpl(wxSocketBase& wxsocket) m_error = wxSOCKET_NOERROR; m_server = false; m_stream = true; - m_non_blocking = false; SetTimeout(wxsocket.GetTimeout() * 1000); @@ -248,8 +222,8 @@ void wxSocketImpl::PostCreation() if ( m_initialSendBufferSize >= 0 ) SetSocketOption(SO_SNDBUF, m_initialSendBufferSize); - // FIXME: shouldn't we check for m_non_blocking here? as it is now, all our - // sockets are non-blocking + // we always put our sockets in unblocked mode and handle blocking + // ourselves in DoRead/Write() if wxSOCKET_WAITALL is specified UnblockAndRegisterWithEventLoop(); } @@ -309,7 +283,7 @@ wxSocketError wxSocketImpl::CreateServer() return UpdateLocalAddress(); } -wxSocketError wxSocketImpl::CreateClient() +wxSocketError wxSocketImpl::CreateClient(bool wait) { if ( !PreCreateCheck(m_peer) ) return m_error; @@ -318,8 +292,8 @@ wxSocketError wxSocketImpl::CreateClient() if ( m_fd == INVALID_SOCKET ) { - m_error = wxSOCKET_IOERR; - return wxSOCKET_IOERR; + m_error = wxSOCKET_IOERR; + return wxSOCKET_IOERR; } PostCreation(); @@ -335,9 +309,34 @@ wxSocketError wxSocketImpl::CreateClient() } } - // Connect to the peer and handle the EWOULDBLOCK return value in - // platform-specific code - return DoHandleConnect(connect(m_fd, m_peer->m_addr, m_peer->m_len)); + // Do connect now + int rc = connect(m_fd, m_peer->m_addr, m_peer->m_len); + if ( rc == SOCKET_ERROR ) + { + wxSocketError err = GetLastError(); + if ( err == wxSOCKET_WOULDBLOCK ) + { + m_establishing = true; + + // block waiting for connection if we should (otherwise just return + // wxSOCKET_WOULDBLOCK to the caller) + if ( wait ) + { + err = SelectWithTimeout(wxSOCKET_CONNECTION_FLAG) + ? wxSOCKET_NOERROR + : wxSOCKET_TIMEDOUT; + m_establishing = false; + } + } + + m_error = err; + } + else // connected + { + m_error = wxSOCKET_NOERROR; + } + + return m_error; } @@ -374,6 +373,26 @@ wxSocketError wxSocketImpl::CreateUDP() return wxSOCKET_NOERROR; } +wxSocketImpl *wxSocketImpl::Accept(wxSocketBase& wxsocket) +{ + wxSockAddr from; + WX_SOCKLEN_T fromlen = sizeof(from); + const int fd = accept(m_fd, &from, &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->UnblockAndRegisterWithEventLoop(); + + return sock; +} + void wxSocketImpl::Close() { @@ -517,38 +536,6 @@ GAddress *wxSocketImpl::GetPeer() return NULL; } -bool wxSocketImpl::DoBlockWithTimeout(wxSocketEventFlags flags) -{ - if ( !m_non_blocking ) - { - fd_set fds; - wxFD_ZERO(&fds); - wxFD_SET(m_fd, &fds); - - fd_set - *readfds = flags & wxSOCKET_INPUT_FLAG ? &fds : NULL, - *writefds = flags & wxSOCKET_OUTPUT_FLAG ? &fds : NULL; - - // make a copy as it can be modified by select() - struct timeval tv = m_timeout; - int ret = select(m_fd + 1, readfds, writefds, NULL, &tv); - - switch ( ret ) - { - case 0: - m_error = wxSOCKET_TIMEDOUT; - return false; - - case -1: - m_error = wxSOCKET_IOERR; - return false; - } - } - //else: we're non-blocking, never block - - return true; -} - // ========================================================================== // wxSocketBase // ========================================================================== @@ -715,9 +702,6 @@ wxSocketError wxSocketBase::LastError() const // The following IO operations update m_error and m_lcount: // {Read, Write, ReadMsg, WriteMsg, Peek, Unread, Discard} -// -// TODO: Should Connect, Accept and AcceptWith update m_error? - bool wxSocketBase::Close() { // Interrupt pending waits @@ -773,7 +757,6 @@ wxUint32 wxSocketBase::DoRead(void* buffer_, wxUint32 nbytes) // polling the socket and don't block at all. if ( m_flags & wxSOCKET_NOWAIT ) { - wxSocketUnblocker unblock(m_impl); int ret = m_impl->Read(buffer, nbytes); if ( ret < 0 ) return 0; @@ -784,10 +767,8 @@ wxUint32 wxSocketBase::DoRead(void* buffer_, wxUint32 nbytes) { for ( ;; ) { - // Wait until socket becomes ready for reading dispatching the GUI - // events in the meanwhile unless wxSOCKET_BLOCK was explicitly - // specified to disable this. - if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForRead() ) + // Wait until socket becomes ready for reading + if ( !WaitForRead() ) break; const int ret = m_impl->Read(buffer, nbytes); @@ -981,7 +962,6 @@ wxUint32 wxSocketBase::DoWrite(const void *buffer_, wxUint32 nbytes) wxUint32 total = 0; if ( m_flags & wxSOCKET_NOWAIT ) { - wxSocketUnblocker unblock(m_impl); const int ret = m_impl->Write(buffer, nbytes); if ( ret > 0 ) total += ret; @@ -990,7 +970,7 @@ wxUint32 wxSocketBase::DoWrite(const void *buffer_, wxUint32 nbytes) { for ( ;; ) { - if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() ) + if ( !WaitForWrite() ) break; const int ret = m_impl->Write(buffer, nbytes); @@ -1124,7 +1104,7 @@ wxSocketBase& wxSocketBase::Discard() and it will return a mask indicating which operations can be performed. */ wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags, - unsigned long timeout) + const timeval *timeout) { wxSocketEventFlags result = 0; @@ -1132,7 +1112,10 @@ wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags, return (wxSOCKET_LOST_FLAG & flags); struct timeval tv; - SetTimeValFromMS(tv, timeout); + if ( timeout ) + tv = *timeout; + else + tv.tv_sec = tv.tv_usec = 0; fd_set readfds; fd_set writefds; @@ -1237,9 +1220,10 @@ wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags) const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout; // Get the active event loop which we'll use for the message dispatching - // when running in the main thread + // when running in the main thread unless this was explicitly disabled by + // setting wxSOCKET_BLOCK flag wxEventLoopBase *eventLoop; - if ( wxIsMainThread() ) + if ( !(m_flags & wxSOCKET_BLOCK) && wxIsMainThread() ) { eventLoop = wxEventLoop::GetActive(); } @@ -1280,7 +1264,9 @@ wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags) else // no event loop or waiting in another thread { // as explained below, we should always check for wxSOCKET_LOST_FLAG - events = m_impl->Select(flags | wxSOCKET_LOST_FLAG, timeLeft); + timeval tv; + SetTimeValFromMS(tv, timeLeft); + events = m_impl->Select(flags | wxSOCKET_LOST_FLAG, &tv); } // always check for wxSOCKET_LOST_FLAG, even if flags doesn't include @@ -1642,17 +1628,34 @@ wxSocketServer::wxSocketServer(const wxSockAddress& addr_man, bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait) { - if (!m_impl) + if ( !m_impl || (m_impl->m_fd == INVALID_SOCKET) || !m_impl->IsServer() ) + { + wxFAIL_MSG( "can only be called for a valid server socket" ); + + m_error = wxSOCKET_INVSOCK; + return false; + } - // If wait == false, then the call should be nonblocking. - // When we are finished, we put the socket to blocking mode - // again. - wxSocketUnblocker unblock(m_impl, !wait); - sock.m_impl = m_impl->WaitConnection(sock); + if ( wait ) + { + // wait until we get a connection + if ( !m_impl->SelectWithTimeout(wxSOCKET_INPUT_FLAG) ) + { + m_error = wxSOCKET_TIMEDOUT; + + return false; + } + } + + sock.m_impl = m_impl->Accept(sock); if ( !sock.m_impl ) + { + m_error = m_impl->GetLastError(); + return false; + } sock.m_type = wxSOCKET_BASE; sock.m_connected = true; @@ -1741,66 +1744,56 @@ wxSocketClient::~wxSocketClient() // Connect // -------------------------------------------------------------------------- -bool wxSocketClient::DoConnect(const wxSockAddress& addr_man, +bool wxSocketClient::DoConnect(const wxSockAddress& remote, const wxSockAddress* local, bool wait) { - if (m_impl) + if ( m_impl ) { - // Shutdown and destroy the socket + // Shutdown and destroy the old socket Close(); delete m_impl; } - m_impl = wxSocketImpl::Create(*this); m_connected = false; m_establishing = false; - if (!m_impl) + // Create and set up the new one + m_impl = wxSocketImpl::Create(*this); + if ( !m_impl ) return false; - // If wait == false, then the call should be nonblocking. When we are - // finished, we put the socket to blocking mode again. - wxSocketUnblocker unblock(m_impl, !wait); - // Reuse makes sense for clients too, if we are trying to rebind to the same port if (GetFlags() & wxSOCKET_REUSEADDR) - { m_impl->SetReusable(); - } if (GetFlags() & wxSOCKET_BROADCAST) - { m_impl->SetBroadcast(); - } if (GetFlags() & wxSOCKET_NOBIND) - { m_impl->DontDoBind(); - } - // If no local address was passed and one has been set, use the one that was Set - if (!local && m_localAddress.GetAddress()) - { + // Bind to the local IP address and port, when provided or if one had been + // set before + if ( !local && m_localAddress.GetAddress() ) local = &m_localAddress; - } - - // Bind to the local IP address and port, when provided - if (local) - { - GAddress* la = local->GetAddress(); - if (la && la->m_addr) - m_impl->SetLocal(la); - } + if ( local ) + m_impl->SetLocal(local->GetAddress()); m_impl->SetInitialSocketBuffers(m_initialRecvBufferSize, m_initialSendBufferSize); - m_impl->SetPeer(addr_man.GetAddress()); - const wxSocketError err = m_impl->CreateClient(); + m_impl->SetPeer(remote.GetAddress()); + + // Finally do create the socket and connect to the peer + const wxSocketError err = m_impl->CreateClient(wait); - if (err != wxSOCKET_NOERROR) + if ( err != wxSOCKET_NOERROR ) { - if (err == wxSOCKET_WOULDBLOCK) + if ( err == wxSOCKET_WOULDBLOCK ) + { + wxASSERT_MSG( !wait, "shouldn't get this for blocking connect" ); + m_establishing = true; + } return false; } @@ -1809,16 +1802,16 @@ bool wxSocketClient::DoConnect(const wxSockAddress& addr_man, return true; } -bool wxSocketClient::Connect(const wxSockAddress& addr_man, bool wait) +bool wxSocketClient::Connect(const wxSockAddress& remote, bool wait) { - return DoConnect(addr_man, NULL, wait); + return DoConnect(remote, NULL, wait); } -bool wxSocketClient::Connect(const wxSockAddress& addr_man, +bool wxSocketClient::Connect(const wxSockAddress& remote, const wxSockAddress& local, bool wait) { - return DoConnect(addr_man, &local, wait); + return DoConnect(remote, &local, wait); } bool wxSocketClient::WaitOnConnect(long seconds, long milliseconds) diff --git a/src/msw/sockmsw.cpp b/src/msw/sockmsw.cpp index 6bae719a94..d7773c0c8a 100644 --- a/src/msw/sockmsw.cpp +++ b/src/msw/sockmsw.cpp @@ -448,139 +448,22 @@ void wxSocketImplMSW::DoClose() closesocket(m_fd); } -/* - * Waits for an incoming client connection. Returns a pointer to - * a wxSocketImpl object, or NULL if there was an error, in which case - * the last error field will be updated for the calling wxSocketImpl. - * - * Error codes (set in the calling wxSocketImpl) - * wxSOCKET_INVSOCK - the socket is not valid or not a server. - * wxSOCKET_TIMEDOUT - timeout, no incoming connections. - * wxSOCKET_WOULDBLOCK - the call would block and the socket is nonblocking. - * wxSOCKET_MEMERR - couldn't allocate memory. - * wxSOCKET_IOERR - low-level error. - */ -wxSocketImpl *wxSocketImplMSW::WaitConnection(wxSocketBase& wxsocket) +wxSocketError wxSocketImplUnix::GetLastError() const { - wxSocketImpl *connection; - wxSockAddr from; - WX_SOCKLEN_T fromlen = sizeof(from); - wxSocketError err; - u_long arg = 1; - - /* Reenable CONNECTION events */ - m_detected &= ~wxSOCKET_CONNECTION_FLAG; - - /* If the socket has already been created, we exit immediately */ - if (m_fd == INVALID_SOCKET || !m_server) - { - m_error = wxSOCKET_INVSOCK; - return NULL; - } - - /* Create a wxSocketImpl object for the new connection */ - connection = wxSocketImplMSW::Create(wxsocket); - - if (!connection) - { - m_error = wxSOCKET_MEMERR; - return NULL; - } - - /* Wait for a connection (with timeout) */ - if ( !BlockForInputWithTimeout() ) - { - delete connection; - return NULL; - } - - connection->m_fd = accept(m_fd, (sockaddr*)&from, &fromlen); - - if (connection->m_fd == INVALID_SOCKET) - { - if (WSAGetLastError() == WSAEWOULDBLOCK) - m_error = wxSOCKET_WOULDBLOCK; - else - m_error = wxSOCKET_IOERR; - - delete connection; - return NULL; - } - - /* Initialize all fields */ - connection->m_server = false; - connection->m_stream = true; - - /* Setup the peer address field */ - connection->m_peer = GAddress_new(); - if (!connection->m_peer) - { - delete connection; - m_error = wxSOCKET_MEMERR; - return NULL; - } - err = _GAddress_translate_from(connection->m_peer, (sockaddr*)&from, fromlen); - if (err != wxSOCKET_NOERROR) - { - GAddress_destroy(connection->m_peer); - delete connection; - m_error = err; - return NULL; - } - - ioctlsocket(connection->m_fd, FIONBIO, (u_long FAR *) &arg); - wxSocketManager::Get()->Install_Callback(connection); - - return connection; -} - -wxSocketError wxSocketImplMSW::DoHandleConnect(int ret) -{ - // TODO: review this - if (ret == SOCKET_ERROR) + switch ( WSAGetLastError() ) { - int err = WSAGetLastError(); + case 0: + return wxSOCKET_NOERROR; - /* If connect failed with EWOULDBLOCK and the wxSocketImpl object - * is in blocking mode, we select() for the specified timeout - * checking for writability to see if the connection request - * completes. - */ - if ((err == WSAEWOULDBLOCK) && (!m_non_blocking)) - { - err = Connect_Timeout(); + case WSAENOTSOCK: + return wxSOCKET_INVSOCK; - if (err != wxSOCKET_NOERROR) - { - Close(); - /* m_error is set in Connect_Timeout */ - } - - return (wxSocketError) err; - } - - /* If connect failed with EWOULDBLOCK and the wxSocketImpl object - * is set to nonblocking, we set m_error to wxSOCKET_WOULDBLOCK - * (and return wxSOCKET_WOULDBLOCK) but we don't close the socket; - * this way if the connection completes, a wxSOCKET_CONNECTION - * event will be generated, if enabled. - */ - if ((err == WSAEWOULDBLOCK) && (m_non_blocking)) - { - m_establishing = true; - m_error = wxSOCKET_WOULDBLOCK; + case WSAEWOULDBLOCK: return wxSOCKET_WOULDBLOCK; - } - /* If connect failed with an error other than EWOULDBLOCK, - * then the call to Connect() has failed. - */ - Close(); - m_error = wxSOCKET_IOERR; - return wxSOCKET_IOERR; + default: + return wxSOCKET_IOERR; } - - return wxSOCKET_NOERROR; } /* Generic IO */ @@ -599,12 +482,6 @@ int wxSocketImplMSW::Read(void *buffer, int size) return -1; } - /* If the socket is blocking, wait for data (with a timeout) */ - if ( !BlockForInputWithTimeout() ) - { - return -1; - } - /* Read the data */ if (m_stream) ret = Recv_Stream(buffer, size); @@ -633,10 +510,6 @@ int wxSocketImplMSW::Write(const void *buffer, int size) return -1; } - /* If the socket is blocking, wait for writability (with a timeout) */ - if ( !BlockForOutputWithTimeout() ) - return -1; - /* Write the data */ if (m_stream) ret = Send_Stream(buffer, size); diff --git a/src/unix/sockunix.cpp b/src/unix/sockunix.cpp index bfe81ba066..60143e73a1 100644 --- a/src/unix/sockunix.cpp +++ b/src/unix/sockunix.cpp @@ -424,13 +424,6 @@ struct servent *wxGetservbyname_r(const char *port, const char *protocol, return se; } -/* debugging helpers */ -#ifdef __GSOCKET_DEBUG__ -# define SOCKET_DEBUG(args) printf args -#else -# define SOCKET_DEBUG(args) -#endif /* __GSOCKET_DEBUG__ */ - /* static */ wxSocketImpl *wxSocketImpl::Create(wxSocketBase& wxsocket) { @@ -450,93 +443,22 @@ void wxSocketImplUnix::Shutdown() wxSocketImpl::Shutdown(); } -/* - * Waits for an incoming client connection. Returns a pointer to - * a wxSocketImplUnix object, or NULL if there was an error, in which case - * the last error field will be updated for the calling wxSocketImplUnix. - * - * Error codes (set in the calling wxSocketImplUnix) - * wxSOCKET_INVSOCK - the socket is not valid or not a server. - * wxSOCKET_TIMEDOUT - timeout, no incoming connections. - * wxSOCKET_WOULDBLOCK - the call would block and the socket is nonblocking. - * wxSOCKET_MEMERR - couldn't allocate memory. - * wxSOCKET_IOERR - low-level error. - */ -wxSocketImpl *wxSocketImplUnix::WaitConnection(wxSocketBase& wxsocket) +wxSocketError wxSocketImplUnix::GetLastError() const { - wxSockAddr from; - WX_SOCKLEN_T fromlen = sizeof(from); - wxSocketImpl *connection; - wxSocketError err; - int arg = 1; - - /* If the socket has already been created, we exit immediately */ - if (m_fd == INVALID_SOCKET || !m_server) - { - m_error = wxSOCKET_INVSOCK; - return NULL; - } - - /* Create a wxSocketImplUnix object for the new connection */ - connection = wxSocketImplUnix::Create(wxsocket); - - if (!connection) - { - m_error = wxSOCKET_MEMERR; - return NULL; - } - - /* Wait for a connection (with timeout) */ - if ( !BlockForInputWithTimeout() ) - { - delete connection; - return NULL; - } - - connection->m_fd = accept(m_fd, (sockaddr*)&from, (WX_SOCKLEN_T *) &fromlen); - - /* Reenable CONNECTION events */ - EnableEvent(wxSOCKET_CONNECTION); - - if (connection->m_fd == INVALID_SOCKET) - { - if (errno == EWOULDBLOCK) - m_error = wxSOCKET_WOULDBLOCK; - else - m_error = wxSOCKET_IOERR; - - delete connection; - return NULL; - } - - /* Initialize all fields */ - connection->m_server = false; - connection->m_stream = true; - - /* Setup the peer address field */ - connection->m_peer = GAddress_new(); - if (!connection->m_peer) - { - delete connection; - m_error = wxSOCKET_MEMERR; - return NULL; - } + switch ( errno ) + { + case 0: + return wxSOCKET_NOERROR; - err = _GAddress_translate_from(connection->m_peer, (sockaddr*)&from, fromlen); - if (err != wxSOCKET_NOERROR) - { - delete connection; - m_error = err; - return NULL; - } + case ENOTSOCK: + return wxSOCKET_INVSOCK; -#if defined(__EMX__) || defined(__VISAGECPP__) - ioctl(connection->m_fd, FIONBIO, (char*)&arg, sizeof(arg)); -#else - ioctl(connection->m_fd, FIONBIO, &arg); -#endif + case EINPROGRESS: + return wxSOCKET_WOULDBLOCK; - return connection; + default: + return wxSOCKET_IOERR; + } } void wxSocketImplUnix::DoEnableEvents(bool flag) @@ -554,70 +476,6 @@ void wxSocketImplUnix::DoEnableEvents(bool flag) } } -wxSocketError wxSocketImplUnix::DoHandleConnect(int ret) -{ - /* We only call EnableEvents() if we know we aren't shutting down the socket. - * NB: EnableEvents() needs to be called whether the socket is blocking or - * non-blocking, it just shouldn't be called prior to knowing there is a - * connection _if_ blocking sockets are being used. - * If connect above returns 0, we are already connected and need to make the - * call to EnableEvents() now. - */ - if ( m_non_blocking || (ret == 0) ) - EnableEvents(); - - if (ret == -1) - { - const int err = errno; - - /* If connect failed with EINPROGRESS and the wxSocketImplUnix object - * is in blocking mode, we select() for the specified timeout - * checking for writability to see if the connection request - * completes. - */ - if ((err == EINPROGRESS) && (!m_non_blocking)) - { - if ( !BlockForOutputWithTimeout() ) - { - Close(); - return wxSOCKET_TIMEDOUT; - } - - int error; - SOCKOPTLEN_T len = sizeof(error); - - getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (char*) &error, &len); - EnableEvents(); - - if (!error) - return wxSOCKET_NOERROR; - } - - /* If connect failed with EINPROGRESS and the wxSocketImplUnix object - * is set to nonblocking, we set m_error to wxSOCKET_WOULDBLOCK - * (and return wxSOCKET_WOULDBLOCK) but we don't close the socket; - * this way if the connection completes, a wxSOCKET_CONNECTION - * event will be generated, if enabled. - */ - if ((err == EINPROGRESS) && (m_non_blocking)) - { - m_establishing = true; - m_error = wxSOCKET_WOULDBLOCK; - return wxSOCKET_WOULDBLOCK; - } - - /* If connect failed with an error other than EINPROGRESS, - * then the call to Connect has failed. - */ - Close(); - m_error = wxSOCKET_IOERR; - - return wxSOCKET_IOERR; - } - - return wxSOCKET_NOERROR; -} - /* Generic IO */ /* Like recv(), send(), ... */ @@ -634,45 +492,34 @@ int wxSocketImplUnix::Read(void *buffer, int size) /* Disable events during query of socket status */ DisableEvent(wxSOCKET_INPUT); - /* If the socket is blocking, wait for data (with a timeout) */ - if ( !BlockForInputWithTimeout() ) - { - m_error = wxSOCKET_TIMEDOUT; - /* Don't return here immediately, otherwise socket events would not be - * re-enabled! */ - ret = -1; - } - else - { - /* Read the data */ - if (m_stream) + /* Read the data */ + if (m_stream) ret = Recv_Stream(buffer, size); - else + 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) - { + /* + * 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) + { /* Make sure wxSOCKET_LOST event gets sent and shut down the socket */ m_detected = wxSOCKET_LOST_FLAG; OnReadWaiting(); return 0; - } - else if (ret == -1) - { + } + else if (ret == -1) + { if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) - m_error = wxSOCKET_WOULDBLOCK; + m_error = wxSOCKET_WOULDBLOCK; else - m_error = wxSOCKET_IOERR; - } + m_error = wxSOCKET_IOERR; } /* Enable events again now that we are done processing */ @@ -685,41 +532,27 @@ int wxSocketImplUnix::Write(const void *buffer, int size) { int ret; - SOCKET_DEBUG(( "Write #1, size %d\n", size )); - if (m_fd == INVALID_SOCKET || m_server) { m_error = wxSOCKET_INVSOCK; return -1; } - SOCKET_DEBUG(( "Write #2, size %d\n", size )); - - /* If the socket is blocking, wait for writability (with a timeout) */ - if ( !BlockForOutputWithTimeout() ) - return -1; - - SOCKET_DEBUG(( "Write #3, size %d\n", size )); - /* Write the data */ if (m_stream) ret = Send_Stream(buffer, size); else ret = Send_Dgram(buffer, size); - SOCKET_DEBUG(( "Write #4, size %d\n", size )); - if (ret == -1) { if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) { m_error = wxSOCKET_WOULDBLOCK; - SOCKET_DEBUG(( "Write error WOULDBLOCK\n" )); } else { m_error = wxSOCKET_IOERR; - SOCKET_DEBUG(( "Write error IOERR\n" )); } /* Only reenable OUTPUT events after an error (just like WSAAsyncSelect @@ -732,8 +565,6 @@ int wxSocketImplUnix::Write(const void *buffer, int size) return -1; } - SOCKET_DEBUG(( "Write #5, size %d ret %d\n", size, ret )); - return ret; }