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
This commit is contained in:
Vadim Zeitlin
2008-12-27 17:15:22 +00:00
parent 030e991d1c
commit 2b036c4b23
6 changed files with 188 additions and 497 deletions

View File

@@ -37,14 +37,12 @@ public:
virtual ~wxSocketImplMSW(); virtual ~wxSocketImplMSW();
virtual wxSocketImpl *WaitConnection(wxSocketBase& wxsocket); virtual wxSocketError GetLastError() const;
virtual int Read(void *buffer, int size);
int Read(void *buffer, int size); virtual int Write(const void *buffer, int size);
int Write(const void *buffer, int size);
private: private:
virtual wxSocketError DoHandleConnect(int ret);
virtual void DoClose(); virtual void DoClose();
virtual void UnblockAndRegisterWithEventLoop() virtual void UnblockAndRegisterWithEventLoop()

View File

@@ -191,7 +191,6 @@ public:
// set various socket properties: all of those can only be called before // set various socket properties: all of those can only be called before
// creating the socket // creating the socket
void SetTimeout(unsigned long millisec); void SetTimeout(unsigned long millisec);
void SetNonBlocking(bool non_blocking) { m_non_blocking = non_blocking; }
void SetReusable() { m_reusable = true; } void SetReusable() { m_reusable = true; }
void SetBroadcast() { m_broadcast = true; } void SetBroadcast() { m_broadcast = true; }
void DontDoBind() { m_dobind = false; } void DontDoBind() { m_dobind = false; }
@@ -207,12 +206,17 @@ public:
// accessors // accessors
// --------- // ---------
bool IsServer() const { return m_server; }
GAddress *GetLocal(); GAddress *GetLocal();
GAddress *GetPeer(); GAddress *GetPeer();
wxSocketError GetError() const { return m_error; } wxSocketError GetError() const { return m_error; }
bool IsOk() const { return m_error == wxSOCKET_NOERROR; } 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 // creating/closing the socket
// -------------------------- // --------------------------
@@ -235,8 +239,8 @@ public:
// (notice that DontDoBind() is ignored by this function) // (notice that DontDoBind() is ignored by this function)
// //
// this function may return wxSOCKET_WOULDBLOCK in addition to the return // this function may return wxSOCKET_WOULDBLOCK in addition to the return
// values listed above // values listed above if wait is false
wxSocketError CreateClient(); wxSocketError CreateClient(bool wait);
// create (and bind unless DontDoBind() had been called) an UDP socket // create (and bind unless DontDoBind() had been called) an UDP socket
// associated with the given local address // associated with the given local address
@@ -256,15 +260,25 @@ public:
virtual int Write(const void *buffer, int size) = 0; virtual int Write(const void *buffer, int size) = 0;
// basically a wrapper for select(): returns the condition of the socket, // basically a wrapper for select(): returns the condition of the socket,
// blocking for not longer than timeout ms for something to become // blocking for not longer than timeout if it is specified (otherwise just
// available // poll without blocking at all)
// //
// flags defines what kind of conditions we're interested in, the return // 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 // value is composed of a (possibly empty) subset of the bits set in flags
wxSocketEventFlags Select(wxSocketEventFlags flags, wxSocketEventFlags Select(wxSocketEventFlags flags,
unsigned long timeout = 0); const timeval *timeout = NULL);
virtual wxSocketImpl *WaitConnection(wxSocketBase& wxsocket) = 0; // convenient wrapper calling Select() with our default timeout
wxSocketEventFlags SelectWithTimeout(wxSocketEventFlags flags)
{
return Select(flags, &m_timeout);
}
// 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 // notifications
@@ -286,8 +300,6 @@ public:
GAddress *m_peer; GAddress *m_peer;
wxSocketError m_error; wxSocketError m_error;
bool m_non_blocking;
bool m_server;
bool m_stream; bool m_stream;
bool m_establishing; bool m_establishing;
bool m_reusable; bool m_reusable;
@@ -301,20 +313,10 @@ public:
protected: protected:
wxSocketImpl(wxSocketBase& wxsocket); wxSocketImpl(wxSocketBase& wxsocket);
// wait until input/output becomes available or m_timeout expires // true if we're a listening stream socket
// bool m_server;
// 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); }
private: 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 // called by Close() if we have a valid m_fd
virtual void DoClose() = 0; virtual void DoClose() = 0;
@@ -351,12 +353,6 @@ private:
// update local address after binding/connecting // update local address after binding/connecting
wxSocketError UpdateLocalAddress(); 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 // set in ctor and never changed except that it's reset to NULL when the
// socket is shut down // socket is shut down

View File

@@ -29,11 +29,12 @@ public:
m_enabledCallbacks = 0; m_enabledCallbacks = 0;
} }
virtual void Shutdown(); virtual wxSocketError GetLastError() const;
virtual wxSocketImpl *WaitConnection(wxSocketBase& wxsocket);
int Read(void *buffer, int size); virtual void Shutdown();
int Write(const void *buffer, int size);
virtual int Read(void *buffer, int size);
virtual int Write(const void *buffer, int size);
// wxFDIOHandler methods // wxFDIOHandler methods
virtual void OnReadWaiting(); virtual void OnReadWaiting();
@@ -49,7 +50,6 @@ public:
int GetEnabledCallbacks() const { return m_enabledCallbacks; } int GetEnabledCallbacks() const { return m_enabledCallbacks; }
private: private:
virtual wxSocketError DoHandleConnect(int ret);
virtual void DoClose() virtual void DoClose()
{ {
wxSocketManager * const manager = wxSocketManager::Get(); wxSocketManager * const manager = wxSocketManager::Get();
@@ -151,7 +151,7 @@ protected:
case wxSOCKET_CONNECTION: case wxSOCKET_CONNECTION:
// FIXME: explain this? // FIXME: explain this?
return socket->m_server ? FD_INPUT : FD_OUTPUT; return socket->IsServer() ? FD_INPUT : FD_OUTPUT;
} }
} }

View File

@@ -102,31 +102,6 @@ public:
DECLARE_NO_COPY_CLASS(wxSocketState) 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 // wxSocketManager
// ============================================================================ // ============================================================================
@@ -185,7 +160,6 @@ wxSocketImpl::wxSocketImpl(wxSocketBase& wxsocket)
m_error = wxSOCKET_NOERROR; m_error = wxSOCKET_NOERROR;
m_server = false; m_server = false;
m_stream = true; m_stream = true;
m_non_blocking = false;
SetTimeout(wxsocket.GetTimeout() * 1000); SetTimeout(wxsocket.GetTimeout() * 1000);
@@ -248,8 +222,8 @@ void wxSocketImpl::PostCreation()
if ( m_initialSendBufferSize >= 0 ) if ( m_initialSendBufferSize >= 0 )
SetSocketOption(SO_SNDBUF, m_initialSendBufferSize); SetSocketOption(SO_SNDBUF, m_initialSendBufferSize);
// FIXME: shouldn't we check for m_non_blocking here? as it is now, all our // we always put our sockets in unblocked mode and handle blocking
// sockets are non-blocking // ourselves in DoRead/Write() if wxSOCKET_WAITALL is specified
UnblockAndRegisterWithEventLoop(); UnblockAndRegisterWithEventLoop();
} }
@@ -309,7 +283,7 @@ wxSocketError wxSocketImpl::CreateServer()
return UpdateLocalAddress(); return UpdateLocalAddress();
} }
wxSocketError wxSocketImpl::CreateClient() wxSocketError wxSocketImpl::CreateClient(bool wait)
{ {
if ( !PreCreateCheck(m_peer) ) if ( !PreCreateCheck(m_peer) )
return m_error; return m_error;
@@ -318,8 +292,8 @@ wxSocketError wxSocketImpl::CreateClient()
if ( m_fd == INVALID_SOCKET ) if ( m_fd == INVALID_SOCKET )
{ {
m_error = wxSOCKET_IOERR; m_error = wxSOCKET_IOERR;
return wxSOCKET_IOERR; return wxSOCKET_IOERR;
} }
PostCreation(); PostCreation();
@@ -335,9 +309,34 @@ wxSocketError wxSocketImpl::CreateClient()
} }
} }
// Connect to the peer and handle the EWOULDBLOCK return value in // Do connect now
// platform-specific code int rc = connect(m_fd, m_peer->m_addr, m_peer->m_len);
return DoHandleConnect(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; 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() void wxSocketImpl::Close()
{ {
@@ -517,38 +536,6 @@ GAddress *wxSocketImpl::GetPeer()
return NULL; 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 // wxSocketBase
// ========================================================================== // ==========================================================================
@@ -715,9 +702,6 @@ wxSocketError wxSocketBase::LastError() const
// The following IO operations update m_error and m_lcount: // The following IO operations update m_error and m_lcount:
// {Read, Write, ReadMsg, WriteMsg, Peek, Unread, Discard} // {Read, Write, ReadMsg, WriteMsg, Peek, Unread, Discard}
//
// TODO: Should Connect, Accept and AcceptWith update m_error?
bool wxSocketBase::Close() bool wxSocketBase::Close()
{ {
// Interrupt pending waits // Interrupt pending waits
@@ -773,7 +757,6 @@ wxUint32 wxSocketBase::DoRead(void* buffer_, wxUint32 nbytes)
// polling the socket and don't block at all. // polling the socket and don't block at all.
if ( m_flags & wxSOCKET_NOWAIT ) if ( m_flags & wxSOCKET_NOWAIT )
{ {
wxSocketUnblocker unblock(m_impl);
int ret = m_impl->Read(buffer, nbytes); int ret = m_impl->Read(buffer, nbytes);
if ( ret < 0 ) if ( ret < 0 )
return 0; return 0;
@@ -784,10 +767,8 @@ wxUint32 wxSocketBase::DoRead(void* buffer_, wxUint32 nbytes)
{ {
for ( ;; ) for ( ;; )
{ {
// Wait until socket becomes ready for reading dispatching the GUI // Wait until socket becomes ready for reading
// events in the meanwhile unless wxSOCKET_BLOCK was explicitly if ( !WaitForRead() )
// specified to disable this.
if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForRead() )
break; break;
const int ret = m_impl->Read(buffer, nbytes); const int ret = m_impl->Read(buffer, nbytes);
@@ -981,7 +962,6 @@ wxUint32 wxSocketBase::DoWrite(const void *buffer_, wxUint32 nbytes)
wxUint32 total = 0; wxUint32 total = 0;
if ( m_flags & wxSOCKET_NOWAIT ) if ( m_flags & wxSOCKET_NOWAIT )
{ {
wxSocketUnblocker unblock(m_impl);
const int ret = m_impl->Write(buffer, nbytes); const int ret = m_impl->Write(buffer, nbytes);
if ( ret > 0 ) if ( ret > 0 )
total += ret; total += ret;
@@ -990,7 +970,7 @@ wxUint32 wxSocketBase::DoWrite(const void *buffer_, wxUint32 nbytes)
{ {
for ( ;; ) for ( ;; )
{ {
if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() ) if ( !WaitForWrite() )
break; break;
const int ret = m_impl->Write(buffer, nbytes); 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. and it will return a mask indicating which operations can be performed.
*/ */
wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags, wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags,
unsigned long timeout) const timeval *timeout)
{ {
wxSocketEventFlags result = 0; wxSocketEventFlags result = 0;
@@ -1132,7 +1112,10 @@ wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags,
return (wxSOCKET_LOST_FLAG & flags); return (wxSOCKET_LOST_FLAG & flags);
struct timeval tv; struct timeval tv;
SetTimeValFromMS(tv, timeout); if ( timeout )
tv = *timeout;
else
tv.tv_sec = tv.tv_usec = 0;
fd_set readfds; fd_set readfds;
fd_set writefds; fd_set writefds;
@@ -1237,9 +1220,10 @@ wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags)
const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout; const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout;
// Get the active event loop which we'll use for the message dispatching // 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; wxEventLoopBase *eventLoop;
if ( wxIsMainThread() ) if ( !(m_flags & wxSOCKET_BLOCK) && wxIsMainThread() )
{ {
eventLoop = wxEventLoop::GetActive(); eventLoop = wxEventLoop::GetActive();
} }
@@ -1280,7 +1264,9 @@ wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags)
else // no event loop or waiting in another thread else // no event loop or waiting in another thread
{ {
// as explained below, we should always check for wxSOCKET_LOST_FLAG // 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 // 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) bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait)
{ {
if (!m_impl) if ( !m_impl || (m_impl->m_fd == INVALID_SOCKET) || !m_impl->IsServer() )
return false; {
wxFAIL_MSG( "can only be called for a valid server socket" );
// If wait == false, then the call should be nonblocking. m_error = wxSOCKET_INVSOCK;
// When we are finished, we put the socket to blocking mode
// again. return false;
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 ) if ( !sock.m_impl )
{
m_error = m_impl->GetLastError();
return false; return false;
}
sock.m_type = wxSOCKET_BASE; sock.m_type = wxSOCKET_BASE;
sock.m_connected = true; sock.m_connected = true;
@@ -1741,66 +1744,56 @@ wxSocketClient::~wxSocketClient()
// Connect // Connect
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
bool wxSocketClient::DoConnect(const wxSockAddress& addr_man, bool wxSocketClient::DoConnect(const wxSockAddress& remote,
const wxSockAddress* local, const wxSockAddress* local,
bool wait) bool wait)
{ {
if (m_impl) if ( m_impl )
{ {
// Shutdown and destroy the socket // Shutdown and destroy the old socket
Close(); Close();
delete m_impl; delete m_impl;
} }
m_impl = wxSocketImpl::Create(*this);
m_connected = false; m_connected = false;
m_establishing = false; m_establishing = false;
if (!m_impl) // Create and set up the new one
m_impl = wxSocketImpl::Create(*this);
if ( !m_impl )
return false; 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 // Reuse makes sense for clients too, if we are trying to rebind to the same port
if (GetFlags() & wxSOCKET_REUSEADDR) if (GetFlags() & wxSOCKET_REUSEADDR)
{
m_impl->SetReusable(); m_impl->SetReusable();
}
if (GetFlags() & wxSOCKET_BROADCAST) if (GetFlags() & wxSOCKET_BROADCAST)
{
m_impl->SetBroadcast(); m_impl->SetBroadcast();
}
if (GetFlags() & wxSOCKET_NOBIND) if (GetFlags() & wxSOCKET_NOBIND)
{
m_impl->DontDoBind(); m_impl->DontDoBind();
}
// If no local address was passed and one has been set, use the one that was Set // Bind to the local IP address and port, when provided or if one had been
if (!local && m_localAddress.GetAddress()) // set before
{ if ( !local && m_localAddress.GetAddress() )
local = &m_localAddress; local = &m_localAddress;
}
// Bind to the local IP address and port, when provided if ( local )
if (local) m_impl->SetLocal(local->GetAddress());
{
GAddress* la = local->GetAddress();
if (la && la->m_addr)
m_impl->SetLocal(la);
}
m_impl->SetInitialSocketBuffers(m_initialRecvBufferSize, m_initialSendBufferSize); m_impl->SetInitialSocketBuffers(m_initialRecvBufferSize, m_initialSendBufferSize);
m_impl->SetPeer(addr_man.GetAddress()); m_impl->SetPeer(remote.GetAddress());
const wxSocketError err = m_impl->CreateClient();
if (err != wxSOCKET_NOERROR) // Finally do create the socket and connect to the peer
const wxSocketError err = m_impl->CreateClient(wait);
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; m_establishing = true;
}
return false; return false;
} }
@@ -1809,16 +1802,16 @@ bool wxSocketClient::DoConnect(const wxSockAddress& addr_man,
return true; 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, const wxSockAddress& local,
bool wait) bool wait)
{ {
return DoConnect(addr_man, &local, wait); return DoConnect(remote, &local, wait);
} }
bool wxSocketClient::WaitOnConnect(long seconds, long milliseconds) bool wxSocketClient::WaitOnConnect(long seconds, long milliseconds)

View File

@@ -448,139 +448,22 @@ void wxSocketImplMSW::DoClose()
closesocket(m_fd); closesocket(m_fd);
} }
/* wxSocketError wxSocketImplUnix::GetLastError() const
* 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)
{ {
wxSocketImpl *connection; switch ( WSAGetLastError() )
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)
{ {
int err = WSAGetLastError(); case 0:
return wxSOCKET_NOERROR;
/* If connect failed with EWOULDBLOCK and the wxSocketImpl object case WSAENOTSOCK:
* is in blocking mode, we select() for the specified timeout return wxSOCKET_INVSOCK;
* checking for writability to see if the connection request
* completes.
*/
if ((err == WSAEWOULDBLOCK) && (!m_non_blocking))
{
err = Connect_Timeout();
if (err != wxSOCKET_NOERROR) case WSAEWOULDBLOCK:
{
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;
return wxSOCKET_WOULDBLOCK; return wxSOCKET_WOULDBLOCK;
}
/* If connect failed with an error other than EWOULDBLOCK, default:
* then the call to Connect() has failed. return wxSOCKET_IOERR;
*/
Close();
m_error = wxSOCKET_IOERR;
return wxSOCKET_IOERR;
} }
return wxSOCKET_NOERROR;
} }
/* Generic IO */ /* Generic IO */
@@ -599,12 +482,6 @@ int wxSocketImplMSW::Read(void *buffer, int size)
return -1; return -1;
} }
/* If the socket is blocking, wait for data (with a timeout) */
if ( !BlockForInputWithTimeout() )
{
return -1;
}
/* Read the data */ /* Read the data */
if (m_stream) if (m_stream)
ret = Recv_Stream(buffer, size); ret = Recv_Stream(buffer, size);
@@ -633,10 +510,6 @@ int wxSocketImplMSW::Write(const void *buffer, int size)
return -1; return -1;
} }
/* If the socket is blocking, wait for writability (with a timeout) */
if ( !BlockForOutputWithTimeout() )
return -1;
/* Write the data */ /* Write the data */
if (m_stream) if (m_stream)
ret = Send_Stream(buffer, size); ret = Send_Stream(buffer, size);

View File

@@ -424,13 +424,6 @@ struct servent *wxGetservbyname_r(const char *port, const char *protocol,
return se; return se;
} }
/* debugging helpers */
#ifdef __GSOCKET_DEBUG__
# define SOCKET_DEBUG(args) printf args
#else
# define SOCKET_DEBUG(args)
#endif /* __GSOCKET_DEBUG__ */
/* static */ /* static */
wxSocketImpl *wxSocketImpl::Create(wxSocketBase& wxsocket) wxSocketImpl *wxSocketImpl::Create(wxSocketBase& wxsocket)
{ {
@@ -450,93 +443,22 @@ void wxSocketImplUnix::Shutdown()
wxSocketImpl::Shutdown(); wxSocketImpl::Shutdown();
} }
/* wxSocketError wxSocketImplUnix::GetLastError() const
* 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)
{ {
wxSockAddr from; switch ( errno )
WX_SOCKLEN_T fromlen = sizeof(from); {
wxSocketImpl *connection; case 0:
wxSocketError err; return wxSOCKET_NOERROR;
int arg = 1;
/* If the socket has already been created, we exit immediately */ case ENOTSOCK:
if (m_fd == INVALID_SOCKET || !m_server) return wxSOCKET_INVSOCK;
{
m_error = wxSOCKET_INVSOCK;
return NULL;
}
/* Create a wxSocketImplUnix object for the new connection */ case EINPROGRESS:
connection = wxSocketImplUnix::Create(wxsocket); return wxSOCKET_WOULDBLOCK;
if (!connection) default:
{ return wxSOCKET_IOERR;
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;
}
err = _GAddress_translate_from(connection->m_peer, (sockaddr*)&from, fromlen);
if (err != wxSOCKET_NOERROR)
{
delete connection;
m_error = err;
return NULL;
}
#if defined(__EMX__) || defined(__VISAGECPP__)
ioctl(connection->m_fd, FIONBIO, (char*)&arg, sizeof(arg));
#else
ioctl(connection->m_fd, FIONBIO, &arg);
#endif
return connection;
} }
void wxSocketImplUnix::DoEnableEvents(bool flag) 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 */ /* Generic IO */
/* Like recv(), send(), ... */ /* Like recv(), send(), ... */
@@ -634,45 +492,34 @@ int wxSocketImplUnix::Read(void *buffer, int size)
/* Disable events during query of socket status */ /* Disable events during query of socket status */
DisableEvent(wxSOCKET_INPUT); DisableEvent(wxSOCKET_INPUT);
/* If the socket is blocking, wait for data (with a timeout) */ /* Read the data */
if ( !BlockForInputWithTimeout() ) if (m_stream)
{
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)
ret = Recv_Stream(buffer, size); ret = Recv_Stream(buffer, size);
else else
ret = Recv_Dgram(buffer, size); ret = Recv_Dgram(buffer, size);
/* /*
* If recv returned zero for a TCP socket (if m_stream == NULL, it's an UDP * 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 * socket and empty datagrams are possible), then the connection has been
* gracefully closed. * gracefully closed.
* *
* Otherwise, recv has returned an error (-1), in which case we have lost * 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 * the socket only if errno does _not_ indicate that there may be more data
* to read. * to read.
*/ */
if ((ret == 0) && m_stream) if ((ret == 0) && m_stream)
{ {
/* Make sure wxSOCKET_LOST event gets sent and shut down the socket */ /* Make sure wxSOCKET_LOST event gets sent and shut down the socket */
m_detected = wxSOCKET_LOST_FLAG; m_detected = wxSOCKET_LOST_FLAG;
OnReadWaiting(); OnReadWaiting();
return 0; return 0;
} }
else if (ret == -1) else if (ret == -1)
{ {
if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
m_error = wxSOCKET_WOULDBLOCK; m_error = wxSOCKET_WOULDBLOCK;
else else
m_error = wxSOCKET_IOERR; m_error = wxSOCKET_IOERR;
}
} }
/* Enable events again now that we are done processing */ /* Enable events again now that we are done processing */
@@ -685,41 +532,27 @@ int wxSocketImplUnix::Write(const void *buffer, int size)
{ {
int ret; int ret;
SOCKET_DEBUG(( "Write #1, size %d\n", size ));
if (m_fd == INVALID_SOCKET || m_server) if (m_fd == INVALID_SOCKET || m_server)
{ {
m_error = wxSOCKET_INVSOCK; m_error = wxSOCKET_INVSOCK;
return -1; 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 */ /* Write the data */
if (m_stream) if (m_stream)
ret = Send_Stream(buffer, size); ret = Send_Stream(buffer, size);
else else
ret = Send_Dgram(buffer, size); ret = Send_Dgram(buffer, size);
SOCKET_DEBUG(( "Write #4, size %d\n", size ));
if (ret == -1) if (ret == -1)
{ {
if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
{ {
m_error = wxSOCKET_WOULDBLOCK; m_error = wxSOCKET_WOULDBLOCK;
SOCKET_DEBUG(( "Write error WOULDBLOCK\n" ));
} }
else else
{ {
m_error = wxSOCKET_IOERR; m_error = wxSOCKET_IOERR;
SOCKET_DEBUG(( "Write error IOERR\n" ));
} }
/* Only reenable OUTPUT events after an error (just like WSAAsyncSelect /* Only reenable OUTPUT events after an error (just like WSAAsyncSelect
@@ -732,8 +565,6 @@ int wxSocketImplUnix::Write(const void *buffer, int size)
return -1; return -1;
} }
SOCKET_DEBUG(( "Write #5, size %d ret %d\n", size, ret ));
return ret; return ret;
} }