From 81b92e17cd24740ce46877d1c87fb4187264831a Mon Sep 17 00:00:00 2001 From: Guillermo Rodriguez Garcia Date: Mon, 10 Jan 2000 03:54:37 +0000 Subject: [PATCH] Important changes to avoid dependence on events inside wxSocket implementation (should also ease a console only version soon) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@5322 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/socket.h | 92 +++++------ src/common/socket.cpp | 345 +++++++++++++----------------------------- 2 files changed, 144 insertions(+), 293 deletions(-) diff --git a/include/wx/socket.h b/include/wx/socket.h index bc9a2c6487..783c767356 100644 --- a/include/wx/socket.h +++ b/include/wx/socket.h @@ -84,6 +84,7 @@ enum wxSockType { SOCK_CLIENT, SOCK_SERVER, + /* SOCK_DGRAM, */ SOCK_INTERNAL, SOCK_UNINIT }; @@ -112,49 +113,34 @@ public: typedef void (*wxSockCbk)(wxSocketBase& sock, wxSocketNotify evt, char *cdata); protected: - GSocket *m_socket; // GSocket - int m_id; // Socket id (for event handler) + GSocket *m_socket; // GSocket + int m_id; // Socket id (for event handler) // Attributes - wxSockFlags m_flags; // wxSocket flags - wxSockType m_type; // wxSocket type + wxSockFlags m_flags; // wxSocket flags + wxSockType m_type; // wxSocket type wxSocketEventFlags m_neededreq; // Event mask - bool m_notify_state; // Notify events to users? - bool m_connected; // Connected ? - bool m_establishing; // Establishing connection ? - bool m_reading; // Busy reading? - bool m_writing; // Busy writing? - bool m_error; // Did last IO call fail ? - wxUint32 m_lcount; // Last IO transaction size - unsigned long m_timeout; // IO timeout value - wxList m_states; // Stack of states - - char *m_unread; // Pushback buffer - wxUint32 m_unrd_size; // Pushback buffer size - wxUint32 m_unrd_cur; // Pushback pointer (index into buffer) - - // Async IO variables - enum - { - NO_DEFER = 0, - DEFER_READ = 1, - DEFER_WRITE = 2 - } m_defering; // Defering state - char *m_defer_buffer; // Defering target buffer - wxUint32 m_defer_nbytes; // Defering buffer size - wxTimer *m_defer_timer; // Timer for defering mode - -/* - char *m_read_buffer; // Target buffer (read) - char *m_write_buffer; // Target buffer (write) - wxUint32 m_read_nbytes; // Buffer size (read) - wxUint32 m_write_nbytes; // Buffer size (write) - wxTimer *m_read_timer; // Timer (read) - wxTimer *m_write_timer; // Timer (write) -*/ - - wxSockCbk m_cbk; // C callback - char *m_cdata; // C callback data + bool m_notify_state; // Notify events to users? + + // State + bool m_connected; // Connected? + bool m_establishing; // Establishing connection? + bool m_reading; // Busy reading? + bool m_writing; // Busy writing? + bool m_error; // Did last IO call fail? + wxUint32 m_lcount; // Last IO transaction size + unsigned long m_timeout; // IO timeout value + wxList m_states; // Stack of states + bool m_interrupt; // Interrupt ongoing wait operations + + // Pushback buffer + char *m_unread; // Pushback buffer + wxUint32 m_unrd_size; // Pushback buffer size + wxUint32 m_unrd_cur; // Pushback pointer (index into buffer) + + // Callback + wxSockCbk m_cbk; // C callback + char *m_cdata; // C callback data public: wxSocketBase(); @@ -181,7 +167,7 @@ public: inline wxSocketError LastError() const { return (wxSocketError)GSocket_GetError(m_socket); } inline wxSockType GetType() const { return m_type; } - // Some info on the socket... + // Addresses virtual bool GetPeer(wxSockAddress& addr_man) const; virtual bool GetLocal(wxSockAddress& addr_man) const; @@ -190,15 +176,23 @@ public: void SetFlags(wxSockFlags flags); inline wxSockFlags GetFlags() const { return m_flags; }; - // Wait functions - // seconds = -1 means default timeout (change with SetTimeout) - // seconds, milliseconds = 0 means no wait - // seconds, milliseconds > 0 means specified wait + /* Wait functions + * seconds = -1 means default timeout (change with SetTimeout) + * seconds, milliseconds = 0 means no wait + * seconds, milliseconds > 0 means specified wait + */ bool Wait(long seconds = -1, long milliseconds = 0); bool WaitForRead(long seconds = -1, long milliseconds = 0); bool WaitForWrite(long seconds = -1, long milliseconds = 0); bool WaitForLost(long seconds = -1, long milliseconds = 0); + /* This function interrupts all ongoing wait operations for this + * socket; use it only as an escape mechanism (for example to close + * an app or to abort an operation). Reception of LOST events and + * calls to Close() automatically call this. + */ + void InterruptAllWaits() { m_interrupt = TRUE; }; + // Save the current state of Socket void SaveState(); void RestoreState(); @@ -242,10 +236,6 @@ protected: wxUint32 _Write(const char *buffer, wxUint32 nbytes); bool _Wait(long seconds, long milliseconds, wxSocketEventFlags flags); - wxUint32 DeferRead(char *buffer, wxUint32 nbytes); - wxUint32 DeferWrite(const char *buffer, wxUint32 nbytes); - void DoDefer(); - // Pushbacks void Pushback(const char *buffer, wxUint32 size); wxUint32 GetPushback(char *buffer, wxUint32 size, bool peek); @@ -259,7 +249,7 @@ class WXDLLEXPORT wxSocketServer : public wxSocketBase public: // 'service' can be a name or a port-number - wxSocketServer(wxSockAddress& addr_man, wxSockFlags flags = wxSocketBase::NONE); + wxSocketServer(wxSockAddress& addr_man, wxSockFlags flags = wxSOCKET_NONE); wxSocketBase* Accept(bool wait = TRUE); bool AcceptWith(wxSocketBase& sock, bool wait = TRUE); @@ -274,7 +264,7 @@ class WXDLLEXPORT wxSocketClient : public wxSocketBase DECLARE_CLASS(wxSocketClient) public: - wxSocketClient(wxSockFlags flags = wxSocketBase::NONE); + wxSocketClient(wxSockFlags flags = wxSOCKET_NONE); virtual ~wxSocketClient(); virtual bool Connect(wxSockAddress& addr_man, bool wait = TRUE); diff --git a/src/common/socket.cpp b/src/common/socket.cpp index a00beb5e2f..3e2ceee503 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -26,6 +26,7 @@ ///////////////////////////////////////////////////////////////////////////// // wxWindows headers ///////////////////////////////////////////////////////////////////////////// + #include "wx/defs.h" #include "wx/object.h" #include "wx/string.h" @@ -42,21 +43,18 @@ ///////////////////////////////////////////////////////////////////////////// // wxSocket headers ///////////////////////////////////////////////////////////////////////////// + #include "wx/sckaddr.h" #include "wx/socket.h" -#if defined(__WXMSW__) || defined(__WXPM__) || defined(__WXMOTIF__) || defined(__WXMAC__) - #define PROCESS_EVENTS() wxYield() -#elif defined(__WXGTK__) - #include - #define PROCESS_EVENTS() gtk_main_iteration() -#endif +#define PROCESS_EVENTS() wxYield() // -------------------------------------------------------------- // ClassInfos // -------------------------------------------------------------- + IMPLEMENT_CLASS(wxSocketBase, wxObject) IMPLEMENT_CLASS(wxSocketServer, wxSocketBase) IMPLEMENT_CLASS(wxSocketClient, wxSocketBase) @@ -65,11 +63,11 @@ IMPLEMENT_DYNAMIC_CLASS(wxSocketEvent, wxEvent) class wxSocketState : public wxObject { public: - bool notify_state; - GSocketEventFlags evt_notify_state; - wxSockFlags socket_flags; - wxSocketBase::wxSockCbk c_callback; - char *c_callback_data; + bool m_notify_state; + GSocketEventFlags m_neededreq; + wxSockFlags m_flags; + wxSocketBase::wxSockCbk m_cbk; + char *m_cdata; public: wxSocketState() : wxObject() {} @@ -88,7 +86,6 @@ wxSocketBase::wxSocketBase(wxSockFlags _flags, wxSockType _type) : m_reading(FALSE), m_writing(FALSE), m_error(FALSE), m_lcount(0), m_timeout(600), m_states(), m_unread(NULL), m_unrd_size(0), m_unrd_cur(0), - m_defering(NO_DEFER), m_defer_buffer(NULL), m_defer_timer(NULL), m_cbk(NULL), m_cdata(NULL) { } @@ -102,7 +99,6 @@ wxSocketBase::wxSocketBase() : m_reading(FALSE), m_writing(FALSE), m_error(FALSE), m_lcount(0), m_timeout(600), m_states(), m_unread(NULL), m_unrd_size(0), m_unrd_cur(0), - m_defering(NO_DEFER), m_defer_buffer(NULL), m_defer_timer(NULL), m_cbk(NULL), m_cdata(NULL) { } @@ -122,6 +118,9 @@ wxSocketBase::~wxSocketBase() bool wxSocketBase::Close() { + // Interrupt pending waits + InterruptAllWaits(); + if (m_socket) { // Disable callbacks @@ -158,49 +157,6 @@ public: } }; -wxUint32 wxSocketBase::DeferRead(char *buffer, wxUint32 nbytes) -{ - // Timer for timeout - _wxSocketInternalTimer timer; - - //wxLogMessage("Entrando a DeferRead, nbytes = %d", nbytes); - wxASSERT(m_defering == NO_DEFER); - - // Set the defering mode to READ. - m_defering = DEFER_READ; - - // Set the current buffer. - m_defer_buffer = buffer; - m_defer_nbytes = nbytes; - m_defer_timer = &timer; - - timer.m_state = (int *)&m_defer_buffer; - timer.m_new_val = 0; - - timer.Start((int)(m_timeout * 1000), FALSE); - - // If the socket is readable, call DoDefer for the first time - if (GSocket_Select(m_socket, GSOCK_INPUT_FLAG)) - { - //wxLogMessage("Llamando al primer DoDefer"); - DoDefer(); - } - - // Wait for buffer completion. - while (m_defer_buffer != NULL) - PROCESS_EVENTS(); - - timer.Stop(); - - // Disable defering mode. - m_defering = NO_DEFER; - m_defer_timer = NULL; - - // Return the number of bytes read from the socket. - //wxLogMessage("Saliendo de DeferRead: total: %d bytes", nbytes - m_defer_nbytes); - return nbytes-m_defer_nbytes; -} - wxSocketBase& wxSocketBase::Read(char* buffer, wxUint32 nbytes) { // Mask read events @@ -237,13 +193,13 @@ wxUint32 wxSocketBase::_Read(char* buffer, wxUint32 nbytes) return total; // Possible combinations (they are checked in this order) - // NOWAIT - // SPEED | WAITALL - // SPEED - // WAITALL - // NONE + // wxSOCKET_NOWAIT + // wxSOCKET_WAITALL | wxSOCKET_BLOCK + // wxSOCKET_WAITALL + // wxSOCKET_BLOCK + // wxSOCKET_NONE // - if (m_flags & NOWAIT) // NOWAIT + if (m_flags & wxSOCKET_NOWAIT) { GSocket_SetNonBlocking(m_socket, TRUE); ret = GSocket_Read(m_socket, buffer, nbytes); @@ -252,32 +208,32 @@ wxUint32 wxSocketBase::_Read(char* buffer, wxUint32 nbytes) if (ret > 0) total += ret; } - else if ((m_flags & SPEED) && (m_flags & WAITALL)) // SPEED, WAITALL + else if (m_flags & wxSOCKET_WAITALL) // wxSOCKET_WAITALL { while (ret > 0 && nbytes > 0) { + if (!(m_flags & wxSOCKET_BLOCK) && !(WaitForRead())) + break; + ret = GSocket_Read(m_socket, buffer, nbytes); - total += ret; - buffer += ret; - nbytes -= ret; - } - // In case the last call was an error ... - if (ret < 0) - total++; - } - else if (m_flags & SPEED) // SPEED, !WAITALL - { - ret = GSocket_Read(m_socket, buffer, nbytes); - if (ret > 0) - total += ret; + if (ret > 0) + { + total += ret; + buffer += ret; + nbytes -= ret; + } + } } - else // NONE or WAITALL + else { - ret = DeferRead(buffer, nbytes); + if ((m_flags & wxSOCKET_BLOCK) || WaitForRead()) + { + ret = GSocket_Read(m_socket, buffer, nbytes); - if (ret > 0) - total += ret; + if (ret > 0) + total += ret; + } } return total; @@ -302,7 +258,7 @@ wxSocketBase& wxSocketBase::ReadMsg(char* buffer, wxUint32 nbytes) total = 0; error = TRUE; old_flags = m_flags; - SetFlags((m_flags & SPEED) | WAITALL); + SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL); if (_Read((char *)&msg, sizeof(msg)) != sizeof(msg)) goto exit; @@ -399,8 +355,8 @@ wxSocketBase& wxSocketBase::Peek(char* buffer, wxUint32 nbytes) m_lcount = _Read(buffer, nbytes); Pushback(buffer, nbytes); - // If in WAITALL mode, all bytes should have been read. - if (m_flags & WAITALL) + // If in wxSOCKET_WAITALL mode, all bytes should have been read. + if (m_flags & wxSOCKET_WAITALL) m_error = (m_lcount != nbytes); else m_error = (m_lcount == 0); @@ -412,51 +368,6 @@ wxSocketBase& wxSocketBase::Peek(char* buffer, wxUint32 nbytes) return *this; } -wxUint32 wxSocketBase::DeferWrite(const char *buffer, wxUint32 nbytes) -{ - // Timer for timeout - _wxSocketInternalTimer timer; - - wxASSERT(m_defering == NO_DEFER); - //wxLogMessage("Entrando a DeferWrite"); - - m_defering = DEFER_WRITE; - - // Set the current buffer - m_defer_buffer = (char *)buffer; - m_defer_nbytes = nbytes; - m_defer_timer = &timer; - - // Start timer - timer.m_state = (int *)&m_defer_buffer; - timer.m_new_val = 0; - - timer.Start((int)(m_timeout * 1000), FALSE); - - // If the socket is writable, call DoDefer for the first time - if (GSocket_Select(m_socket, GSOCK_OUTPUT_FLAG)) - { - //wxLogMessage("Llamando al primer DoDefer"); - DoDefer(); - } - - // Wait for buffer completion. - while (m_defer_buffer != NULL) - PROCESS_EVENTS(); - - timer.Stop(); - - // Disable defering mode - m_defer_timer = NULL; - m_defering = NO_DEFER; - - //wxString s; - //s.Printf(wxT("Saliendo de DeferWrite: total %d bytes"), nbytes-m_defer_nbytes); - //wxLogMessage(s); - - return nbytes-m_defer_nbytes; -} - wxSocketBase& wxSocketBase::Write(const char *buffer, wxUint32 nbytes) { // Mask write events @@ -464,8 +375,8 @@ wxSocketBase& wxSocketBase::Write(const char *buffer, wxUint32 nbytes) m_lcount = _Write(buffer, nbytes); - // If in WAITALL mode, all bytes should have been written. - if (m_flags & WAITALL) + // If in wxSOCKET_WAITALL mode, all bytes should have been written. + if (m_flags & wxSOCKET_WAITALL) m_error = (m_lcount != nbytes); else m_error = (m_lcount == 0); @@ -486,13 +397,13 @@ wxUint32 wxSocketBase::_Write(const char *buffer, wxUint32 nbytes) return 0; // Possible combinations (they are checked in this order) - // NOWAIT - // SPEED | WAITALL - // SPEED - // WAITALL - // NONE + // wxSOCKET_NOWAIT + // wxSOCKET_WAITALL | wxSOCKET_BLOCK + // wxSOCKET_WAITALL + // wxSOCKET_BLOCK + // wxSOCKET_NONE // - if (m_flags & NOWAIT) // NOWAIT + if (m_flags & wxSOCKET_NOWAIT) { GSocket_SetNonBlocking(m_socket, TRUE); ret = GSocket_Write(m_socket, buffer, nbytes); @@ -501,32 +412,32 @@ wxUint32 wxSocketBase::_Write(const char *buffer, wxUint32 nbytes) if (ret > 0) total = ret; } - else if ((m_flags & SPEED) && (m_flags & WAITALL)) // SPEED, WAITALL + else if (m_flags & wxSOCKET_WAITALL) { while (ret > 0 && nbytes > 0) { + if (!(m_flags & wxSOCKET_BLOCK) && !(WaitForWrite())) + break; + ret = GSocket_Write(m_socket, buffer, nbytes); - total += ret; - buffer += ret; - nbytes -= ret; - } - // In case the last call was an error ... - if (ret < 0) - total ++; - } - else if (m_flags & SPEED) // SPEED, !WAITALL - { - ret = GSocket_Write(m_socket, buffer, nbytes); - if (ret > 0) - total = ret; + if (ret > 0) + { + total += ret; + buffer += ret; + nbytes -= ret; + } + } } - else // NONE or WAITALL + else { - ret = DeferWrite(buffer, nbytes); + if ((m_flags & wxSOCKET_BLOCK) || WaitForWrite()) + { + ret = GSocket_Write(m_socket, buffer, nbytes); - if (ret > 0) - total = ret; + if (ret > 0) + total = ret; + } } return total; @@ -548,7 +459,7 @@ wxSocketBase& wxSocketBase::WriteMsg(const char *buffer, wxUint32 nbytes) error = TRUE; total = 0; old_flags = m_flags; - SetFlags((m_flags & SPEED) | WAITALL); + SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL); // warning about 'cast truncates constant value' #ifdef __VISUALC__ @@ -617,43 +528,6 @@ wxSocketBase& wxSocketBase::Unread(const char *buffer, wxUint32 nbytes) return *this; } -void wxSocketBase::DoDefer() -{ - int ret; - - if (!m_defer_buffer) - return; - - switch(m_defering) - { - case DEFER_READ: - ret = GSocket_Read(m_socket, m_defer_buffer, m_defer_nbytes); - break; - case DEFER_WRITE: - ret = GSocket_Write(m_socket, m_defer_buffer, m_defer_nbytes); - break; - default: - ret = -1; - } - - if (ret >= 0) - m_defer_nbytes -= ret; - - // If we are waiting for all bytes to be acquired, keep the defering - // mode enabled. - if (!(m_flags & WAITALL) || !m_defer_nbytes || ret < 0) - { - m_defer_buffer = NULL; - } - else - { - m_defer_buffer += ret; - m_defer_timer->Start((int)(m_timeout * 1000), FALSE); - } - - //wxLogMessage("DoDefer ha transferido %d bytes", ret); -} - wxSocketBase& wxSocketBase::Discard() { #define MAX_BUFSIZE (10*1024) @@ -667,7 +541,7 @@ wxSocketBase& wxSocketBase::Discard() m_reading = TRUE; old_flags = m_flags; - SetFlags(NOWAIT); + SetFlags(wxSOCKET_NOWAIT); while (recv_size == MAX_BUFSIZE) { @@ -730,11 +604,11 @@ void wxSocketBase::SaveState() state = new wxSocketState(); - state->notify_state = m_notify_state; - state->evt_notify_state = m_neededreq; - state->socket_flags = m_flags; - state->c_callback = m_cbk; - state->c_callback_data = m_cdata; + state->m_notify_state = m_notify_state; + state->m_neededreq = m_neededreq; + state->m_flags = m_flags; + state->m_cbk = m_cbk; + state->m_cdata = m_cdata; m_states.Append(state); } @@ -750,11 +624,11 @@ void wxSocketBase::RestoreState() state = (wxSocketState *)node->Data(); - SetFlags(state->socket_flags); - m_neededreq = state->evt_notify_state; - m_cbk = state->c_callback; - m_cdata = state->c_callback_data; - Notify(state->notify_state); + SetFlags(state->m_flags); + m_cbk = state->m_cbk; + m_cdata = state->m_cdata; + m_neededreq = state->m_neededreq; + Notify(state->m_notify_state); delete node; delete state; @@ -779,6 +653,9 @@ bool wxSocketBase::_Wait(long seconds, long milliseconds, wxSocketEventFlags fla long timeout; int state = -1; + // Set this to TRUE to interrupt ongoing waits + m_interrupt = FALSE; + // Check for valid socket if (!m_socket) return FALSE; @@ -811,7 +688,8 @@ bool wxSocketBase::_Wait(long seconds, long milliseconds, wxSocketEventFlags fla // // Do this at least once (important if timeout == 0, when // we are just polling) - do + // + while (state == -1) { result = GSocket_Select(m_socket, flags | GSOCK_LOST_FLAG); @@ -819,7 +697,6 @@ bool wxSocketBase::_Wait(long seconds, long milliseconds, wxSocketEventFlags fla if (result & GSOCK_LOST_FLAG) { timer.Stop(); - m_defer_buffer = NULL; Close(); return TRUE; } @@ -833,24 +710,18 @@ bool wxSocketBase::_Wait(long seconds, long milliseconds, wxSocketEventFlags fla return TRUE; } - // If we are in the middle of a R/W operation, do not propagate - // to users. - if ( ((result & GSOCK_INPUT_FLAG) || (result & GSOCK_OUTPUT_FLAG)) - && (!m_writing) && (!m_reading) ) + if ((result & GSOCK_INPUT_FLAG) || (result & GSOCK_OUTPUT_FLAG)) { -/* TODO: remove this - if (m_defer_buffer == NULL) -*/ - { - timer.Stop(); - return TRUE; - } + timer.Stop(); + return TRUE; } - if (timeout != 0) - PROCESS_EVENTS(); + // Wait more? + if ((timeout == 0) || (m_interrupt)) + break; + + PROCESS_EVENTS(); } - while ((state == -1) && timeout); timer.Stop(); return FALSE; @@ -965,41 +836,30 @@ void wxSocketBase::OnRequest(wxSocketNotify req_evt) // fprintf(stderr, "%s: Entering OnRequest (evt %d)\n", (m_type == SOCK_CLIENT)? "client" : "server", req_evt); - // NOTE: this duplicates some of the code in _Wait (lost - // connection and connection establishment handling) but + // NOTE: this duplicates some of the code in _Wait, (lost + // connections and delayed connection establishment) but // this doesn't hurt. It has to be here because maybe the // WaitXXX are not being used, and it has to be in _Wait // as well because the event might be a bit delayed. // - switch(req_evt) + switch (req_evt) { - case wxSOCKET_CONNECTION: + case wxSOCKET_CONNECTION : m_establishing = FALSE; m_connected = TRUE; break; case wxSOCKET_LOST: - m_defer_buffer = NULL; Close(); break; - case wxSOCKET_INPUT: - case wxSOCKET_OUTPUT: - if (m_defer_buffer) - { - // fprintf(stderr, "%s: Habia buffer, evt %d skipped\n", (m_type == SOCK_CLIENT)? "client" : "server", req_evt); - DoDefer(); - // Do not notify to user - return; - } - break; - } // If we are in the middle of a R/W operation, do not // propagate events to users. - if (((req_evt == wxSOCKET_INPUT) && m_reading) || - ((req_evt == wxSOCKET_OUTPUT) && m_writing)) - { - // fprintf(stderr, "%s: Swallowed evt %d\n", (m_type == SOCK_CLIENT)? "client" : "server", req_evt); - return; + // + case wxSOCKET_INPUT: + if (m_reading) return; + + case wxSOCKET_OUTPUT: + if (m_writing) return; } if (((m_neededreq & flag) == flag) && m_notify_state) @@ -1007,11 +867,12 @@ void wxSocketBase::OnRequest(wxSocketNotify req_evt) // fprintf(stderr, "%s: Evt %d delivered\n", (m_type == SOCK_CLIENT)? "client" : "server", req_evt); event.m_socket = this; event.m_skevt = req_evt; - ProcessEvent(event); - OldOnNotify(req_evt); + ProcessEvent(event); // XXX - should be PostEvent + OldOnNotify(req_evt); if (m_cbk) m_cbk(*this, req_evt, m_cdata); + } // fprintf(stderr, "%s: Exiting OnRequest (evt %d)\n", (m_type == SOCK_CLIENT)? "client" : "server", req_evt); -- 2.45.2