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()
// 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; }
// 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
// --------------------------
// (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
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
GAddress *m_peer;
wxSocketError m_error;
- bool m_non_blocking;
- bool m_server;
bool m_stream;
bool m_establishing;
bool m_reusable;
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;
// 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
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();
int GetEnabledCallbacks() const { return m_enabledCallbacks; }
private:
- virtual wxSocketError DoHandleConnect(int ret);
virtual void DoClose()
{
wxSocketManager * const manager = wxSocketManager::Get();
case wxSOCKET_CONNECTION:
// FIXME: explain this?
- return socket->m_server ? FD_INPUT : FD_OUTPUT;
+ return socket->IsServer() ? FD_INPUT : FD_OUTPUT;
}
}
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
// ============================================================================
m_error = wxSOCKET_NOERROR;
m_server = false;
m_stream = true;
- m_non_blocking = false;
SetTimeout(wxsocket.GetTimeout() * 1000);
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();
}
return UpdateLocalAddress();
}
-wxSocketError wxSocketImpl::CreateClient()
+wxSocketError wxSocketImpl::CreateClient(bool wait)
{
if ( !PreCreateCheck(m_peer) )
return m_error;
if ( m_fd == INVALID_SOCKET )
{
- m_error = wxSOCKET_IOERR;
- return wxSOCKET_IOERR;
+ m_error = wxSOCKET_IOERR;
+ return wxSOCKET_IOERR;
}
PostCreation();
}
}
- // 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;
}
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()
{
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
// ==========================================================================
// 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
// 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;
{
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);
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;
{
for ( ;; )
{
- if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() )
+ if ( !WaitForWrite() )
break;
const int ret = m_impl->Write(buffer, nbytes);
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;
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;
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();
}
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
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;
// 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;
}
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)
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 */
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);
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);
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)
{
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)
}
}
-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(), ... */
/* 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 */
{
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
return -1;
}
- SOCKET_DEBUG(( "Write #5, size %d ret %d\n", size, ret ));
-
return ret;
}