From 39b91ecabeb35ad879412df1bcd1cec9ea97a20a Mon Sep 17 00:00:00 2001 From: Guilhem Lavaux Date: Fri, 30 Jul 1999 17:54:18 +0000 Subject: [PATCH] Renamed GSocket_SetBlocking to GSocket_SetNonBlocking and *Fallback to *Callback Added GSocket_SetTimeout Added timeout support in wxSocket (as it was in previous releases) Updated documentation git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3215 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/latex/wx/classes.tex | 1 + docs/latex/wx/http.tex | 18 +++++++-- docs/latex/wx/inputstr.tex | 2 +- docs/latex/wx/strmbase.tex | 2 +- docs/latex/wx/zipstrm.tex | 2 +- include/wx/gsocket.h | 22 +++++++---- include/wx/socket.h | 13 ++++--- src/common/socket.cpp | 80 ++++++++++++++++++++++++++++++-------- src/gtk/gsockgtk.c | 4 +- src/gtk1/gsockgtk.c | 4 +- src/motif/gsockmot.cpp | 4 +- src/stubs/gsockno.c | 4 +- src/unix/gsocket.c | 53 +++++++++++++++++++------ src/unix/gsockunx.h | 9 +++-- 14 files changed, 158 insertions(+), 60 deletions(-) diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex index 007a40c7bc..678258a1e7 100644 --- a/docs/latex/wx/classes.tex +++ b/docs/latex/wx/classes.tex @@ -183,6 +183,7 @@ \input slider.tex \input sckaddr.tex \input socket.tex +%\input gsocket.tex \input splitevt.tex \input strmsock.tex \input spinbutt.tex diff --git a/docs/latex/wx/http.tex b/docs/latex/wx/http.tex index b6596637c3..1bce1b9522 100644 --- a/docs/latex/wx/http.tex +++ b/docs/latex/wx/http.tex @@ -23,10 +23,18 @@ Creates a new input stream on the the specified path. You can use all except the seek functionality of wxStream. Seek isn't available on all streams. For example, -http or ftp streams doesn't deal with it. Other functions like StreamSize and -Tell aren't available for the moment for this sort of stream. +http or ftp streams doesn't deal with it. Other functions like Tell and SeekI +for this sort of stream. You will be notified when the EOF is reached by an error. +\wxheading{Note} + +You can know the size of the file you are getting using \helpref{wxStreamBase::GetSize()}{wxstreambasegetsize}. +But there is a limitation: as HTTP servers aren't obliged to pass the size ofi +the file, in some case, you will be returned 0xfffffff by GetSize(). In these +cases, you should use the value returned by \helpref{wxInputStream::LastRead()}{wxinputstreamlastread}: +this value will be 0 when the stream is finished. + \wxheading{Return value} Returns the initialized stream. You will have to delete it yourself once you @@ -48,10 +56,14 @@ It sets data of a field to be sent during the next request to the HTTP server. T name is specified by \it{header} and the content by \it{h\_data}. This is a low level function and it assumes that you know what you are doing. -\membersection{wxHTTP::SetHeader} +\membersection{wxHTTP::GetHeader} \func{wxString}{GetHeader}{\param{const wxString\&}{ header}} Returns the data attached with a field whose name is specified by \it{header}. If the field doesn't exist, it will return an empty string and not a NULL string. +\wxheading{Note} + +The header is not case-sensitive: I mean that "CONTENT-TYPE" and "content-type" +represent the same header. diff --git a/docs/latex/wx/inputstr.tex b/docs/latex/wx/inputstr.tex index d0888a8c45..9edd5d824a 100644 --- a/docs/latex/wx/inputstr.tex +++ b/docs/latex/wx/inputstr.tex @@ -32,7 +32,7 @@ Destructor. Returns the first character in the input queue and removes it. -\membersection{wxInputStream::LastRead} +\membersection{wxInputStream::LastRead}\label{wxinputstreamlastread} \constfunc{size\_t}{LastRead}{\void} diff --git a/docs/latex/wx/strmbase.tex b/docs/latex/wx/strmbase.tex index ff108b3b93..5cc9320525 100644 --- a/docs/latex/wx/strmbase.tex +++ b/docs/latex/wx/strmbase.tex @@ -76,7 +76,7 @@ real position in the stream. See \helpref{OnSysRead}{wxstreambaseonsysread}. -\membersection{wxStreamBase::GetSize} +\membersection{wxStreamBase::GetSize}\label{wxstreambasegetsize} \constfunc{size\_t}{GetSize}{\void} diff --git a/docs/latex/wx/zipstrm.tex b/docs/latex/wx/zipstrm.tex index 569c28a618..2120a71735 100644 --- a/docs/latex/wx/zipstrm.tex +++ b/docs/latex/wx/zipstrm.tex @@ -8,7 +8,7 @@ This class is input stream from ZIP archive. The archive must be local file (accessible via FILE*). -It has all features including StreamSize and seeking. +It has all features including GetSize and seeking. \wxheading{Derived from} diff --git a/include/wx/gsocket.h b/include/wx/gsocket.h index 6b786f9a19..59739c14c5 100644 --- a/include/wx/gsocket.h +++ b/include/wx/gsocket.h @@ -66,7 +66,7 @@ enum { typedef int GSocketEventFlags; -typedef void (*GSocketFallback)(GSocket *socket, GSocketEvent event, +typedef void (*GSocketCallback)(GSocket *socket, GSocketEvent event, char *cdata); #ifdef __cplusplus @@ -134,13 +134,19 @@ int GSocket_Write(GSocket *socket, const char *buffer, int size); bool GSocket_DataAvailable(GSocket *socket); -/* Flags */ +/* Flags/Parameters */ + +/* + GSocket_SetTimeout() sets the timeout for reading and writing IO call. Time + is expressed in milliseconds. + */ +void GSocket_SetTimeout(GSocket *socket, unsigned long millisec); /* GSocket_SetBlocking() puts the socket in non-blocking mode. This is useful if we don't want to wait. */ -void GSocket_SetBlocking(GSocket *socket, bool block); +void GSocket_SetNonBlocking(GSocket *socket, bool non_block); /* GSocket_GetError() returns the last error occured on the socket stream. @@ -161,7 +167,7 @@ GSocketError GSocket_GetError(GSocket *socket); Server socket -> a client request a connection LOST: the connection is lost - SetFallback accepts a combination of these flags so a same callback can + SetCallback accepts a combination of these flags so a same callback can receive different events. An event is generated only once and its state is reseted when the relative @@ -169,14 +175,14 @@ GSocketError GSocket_GetError(GSocket *socket); For example: INPUT -> GSocket_Read() CONNECTION -> GSocket_Accept() */ -void GSocket_SetFallback(GSocket *socket, GSocketEventFlags event, - GSocketFallback fallback, char *cdata); +void GSocket_SetCallback(GSocket *socket, GSocketEventFlags event, + GSocketCallback fallback, char *cdata); /* - UnsetFallback will disables all fallbacks specified by "event". + UnsetCallback will disables all fallbacks specified by "event". NOTE: event may be a combination of flags */ -void GSocket_UnsetFallback(GSocket *socket, GSocketEventFlags event); +void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags event); /* GAddress */ diff --git a/include/wx/socket.h b/include/wx/socket.h index a8797de054..762e01c863 100644 --- a/include/wx/socket.h +++ b/include/wx/socket.h @@ -24,15 +24,16 @@ // wxSocket headers (generic) // --------------------------------------------------------------------------- #ifdef WXPREC - #include "wx/wxprec.h" +# include #else - #include "wx/event.h" - #include "wx/string.h" +# include +# include #endif -#include "wx/sckaddr.h" +#include #include "wx/gsocket.h" +class WXDLLEXPORT wxTimer; class WXDLLEXPORT wxSocketEvent; class WXDLLEXPORT wxSocketBase : public wxEvtHandler { @@ -65,11 +66,13 @@ protected: bool m_notify_state; // Notify state int m_id; // Socket id (for event handler) + // Defering variables enum { DEFER_READ, DEFER_WRITE, NO_DEFER - } m_defering; // Defering state + } m_defering; // Defering state char *m_defer_buffer; // Defering target buffer size_t m_defer_nbytes; // Defering buffer size + wxTimer *m_defer_timer; // Timer for defering mode wxList m_states; // Stack of states diff --git a/src/common/socket.cpp b/src/common/socket.cpp index a29b30f8b2..3a0d0b6913 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -128,32 +128,62 @@ bool wxSocketBase::Close() // -------------------------------------------------------------- // wxSocketBase base IO function // -------------------------------------------------------------- +class _wxSocketInternalTimer: public wxTimer { + public: + int *m_state; + int m_new_val; + + void Notify() + { + *m_state = m_new_val; // Change the value + } +}; int wxSocketBase::DeferRead(char *buffer, size_t nbytes) { GSocketEventFlags old_event_flags; bool old_notify_state; + // Timer for timeout + _wxSocketInternalTimer timer; wxASSERT(m_defering == NO_DEFER); + // Set the defering mode to READ. m_defering = DEFER_READ; + // Save the old state. old_event_flags = NeededReq(); old_notify_state = m_notify_state; + // Set the new async flag. SetNotify(GSOCK_INPUT_FLAG | GSOCK_LOST_FLAG); Notify(TRUE); + // 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 = (int)NULL; + + timer.Start(m_timeout * 1000, FALSE); + + // Wait for buffer completion. while (m_defer_buffer != NULL) wxYield(); + timer.Stop(); + + // Restore the old state. Notify(old_notify_state); SetNotify(old_event_flags); + // Disable defering mode. m_defering = NO_DEFER; + m_defer_timer = NULL; + // Return the number of bytes read from the socket. return nbytes-m_defer_nbytes; } @@ -272,22 +302,39 @@ int wxSocketBase::DeferWrite(const char *buffer, size_t nbytes) { GSocketEventFlags old_event_flags; bool old_notify_state; + // Timer for timeout + _wxSocketInternalTimer timer; wxASSERT(m_defering == NO_DEFER); m_defering = DEFER_WRITE; + // Save the old state old_event_flags = NeededReq(); old_notify_state = m_notify_state; SetNotify(GSOCK_OUTPUT_FLAG | GSOCK_LOST_FLAG); Notify(TRUE); + // Set the current buffer m_defer_buffer = (char *)buffer; m_defer_nbytes = nbytes; + + // Start timer + timer.m_state = (int *)&m_defer_buffer; + timer.m_new_val = (int)NULL; + + m_defer_timer = &timer; + timer.Start(m_timeout * 1000, FALSE); + while (m_defer_buffer != NULL) wxYield(); + // Stop timer + m_defer_timer = NULL; + timer.Stop(); + + // Restore the old state Notify(old_notify_state); SetNotify(old_event_flags); @@ -396,11 +443,15 @@ void wxSocketBase::DoDefer(GSocketEvent req_evt) if (ret < 0) m_defer_nbytes++; + // If we are waiting for all bytes to be acquired, keep the defering modei + // enabled. if ((m_flags & WAITALL) == 0 || m_defer_nbytes == 0 || ret < 0) { m_defer_buffer = NULL; Notify(FALSE); - } else + } else { m_defer_buffer += ret; + m_defer_timer->Start(m_timeout * 1000, FALSE); + } } // --------------------------------------------------------------------- @@ -522,16 +573,6 @@ char *wxSocketBase::CallbackData(char *data) // --------- wxSocketBase wait functions ------------------------ // -------------------------------------------------------------- -class _wxSocketInternalTimer: public wxTimer { - public: - int *m_state; - - void Notify() - { - *m_state = GSOCK_MAX_EVENT; // Just to say it's a timeout. - } -}; - static void wx_socket_wait(GSocket *socket, GSocketEvent event, char *cdata) { int *state = (int *)cdata; @@ -542,25 +583,30 @@ static void wx_socket_wait(GSocket *socket, GSocketEvent event, char *cdata) bool wxSocketBase::_Wait(long seconds, long milliseconds, int type) { bool old_notify_state = m_notify_state; - int state = 0; + int state = -1; _wxSocketInternalTimer timer; if (!m_connected || !m_socket) return FALSE; + // Set the variable to change timer.m_state = &state; + timer.m_new_val = GSOCK_MAX_EVENT; + // Disable the previous handler Notify(FALSE); + // Set the timeout timer.Start(seconds * 1000 + milliseconds, TRUE); - GSocket_SetFallback(m_socket, type, wx_socket_wait, (char *)&state); + GSocket_SetCallback(m_socket, type, wx_socket_wait, (char *)&state); - while (state == 0) + while (state == -1) wxYield(); - GSocket_UnsetFallback(m_socket, type); + GSocket_UnsetCallback(m_socket, type); timer.Stop(); + // Notify will restore automatically the old GSocket flags Notify(old_notify_state); return (state != GSOCK_MAX_EVENT); @@ -649,12 +695,12 @@ void wxSocketBase::Notify(bool notify) if (!m_socket) return; - GSocket_UnsetFallback(m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | + GSocket_UnsetCallback(m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG | GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG); if (!notify) return; - GSocket_SetFallback(m_socket, m_neededreq, wx_socket_fallback, (char *)this); + GSocket_SetCallback(m_socket, m_neededreq, wx_socket_fallback, (char *)this); } void wxSocketBase::OnRequest(GSocketEvent req_evt) diff --git a/src/gtk/gsockgtk.c b/src/gtk/gsockgtk.c index 2750b73318..f31333439f 100644 --- a/src/gtk/gsockgtk.c +++ b/src/gtk/gsockgtk.c @@ -53,7 +53,7 @@ void _GSocket_GUI_Destroy(GSocket *socket) free(socket->m_gui_dependent); } -void _GSocket_Install_Fallback(GSocket *socket, GSocketEvent event) +void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event) { GdkInputCondition flag; int c; @@ -76,7 +76,7 @@ void _GSocket_Install_Fallback(GSocket *socket, GSocketEvent event) _GSocket_GDK_Input, (gpointer)socket); } -void _GSocket_Uninstall_Fallback(GSocket *socket, GSocketEvent event) +void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event) { int c; gint *m_id; diff --git a/src/gtk1/gsockgtk.c b/src/gtk1/gsockgtk.c index 2750b73318..f31333439f 100644 --- a/src/gtk1/gsockgtk.c +++ b/src/gtk1/gsockgtk.c @@ -53,7 +53,7 @@ void _GSocket_GUI_Destroy(GSocket *socket) free(socket->m_gui_dependent); } -void _GSocket_Install_Fallback(GSocket *socket, GSocketEvent event) +void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event) { GdkInputCondition flag; int c; @@ -76,7 +76,7 @@ void _GSocket_Install_Fallback(GSocket *socket, GSocketEvent event) _GSocket_GDK_Input, (gpointer)socket); } -void _GSocket_Uninstall_Fallback(GSocket *socket, GSocketEvent event) +void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event) { int c; gint *m_id; diff --git a/src/motif/gsockmot.cpp b/src/motif/gsockmot.cpp index f9870d43c8..535a7b4d42 100644 --- a/src/motif/gsockmot.cpp +++ b/src/motif/gsockmot.cpp @@ -59,7 +59,7 @@ void _GSocket_GUI_Destroy(GSocket *socket) free(socket->m_gui_dependent); } -void _GSocket_Install_Fallback(GSocket *socket, GSocketEvent event) +void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event) { int *m_id; @@ -88,7 +88,7 @@ void _GSocket_Install_Fallback(GSocket *socket, GSocketEvent event) } } -void _GSocket_Uninstall_Fallback(GSocket *socket, GSocketEvent event) +void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event) { int c; int *m_id; diff --git a/src/stubs/gsockno.c b/src/stubs/gsockno.c index 94b8671139..0f40f3efdc 100644 --- a/src/stubs/gsockno.c +++ b/src/stubs/gsockno.c @@ -16,11 +16,11 @@ void _GSocket_GUI_Destroy(GSocket *socket) { } -void _GSocket_Install_Fallback(GSocket *socket, GSocketEvent event) +void _GSocket_Install_Callback(GSocket *socket, GSocketEvent event) { } -void _GSocket_Uninstall_Fallback(GSocket *socket, GSocketEvent event) +void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent event) { } diff --git a/src/unix/gsocket.c b/src/unix/gsocket.c index 4157d89baa..a49a146bb9 100644 --- a/src/unix/gsocket.c +++ b/src/unix/gsocket.c @@ -88,6 +88,8 @@ GSocket *GSocket_new() socket->m_stream = TRUE; socket->m_gui_dependent = NULL; socket->m_blocking = FALSE; + socket->m_timeout = 10*60*1000; + // 10 minutes * 60 sec * 1000 millisec /* We initialize the GUI specific entries here */ _GSocket_GUI_Init(socket); @@ -132,7 +134,7 @@ void GSocket_Shutdown(GSocket *socket) /* We also disable GUI callbacks */ for (evt=0;evtm_blocking); + GSocket_SetTimeout(sck, sck->m_timeout); + return GSOCK_NOERROR; } @@ -338,6 +343,9 @@ GSocketError GSocket_SetNonOriented(GSocket *sck) return GSOCK_IOERR; } + GSocket_SetBlocking(sck, sck->m_blocking); + GSocket_SetTimeout(sck, sck->m_timeout); + return GSOCK_NOERROR; } @@ -393,6 +401,9 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream) /* It is not a server */ sck->m_server = FALSE; + GSocket_SetBlocking(sck, sck->m_blocking); + GSocket_SetTimeout(sck, sck->m_timeout); + return GSOCK_NOERROR; } @@ -461,10 +472,10 @@ bool GSocket_DataAvailable(GSocket *socket) /* Flags */ /* - GSocket_SetBlocking() puts the socket in non-blocking mode. This is useful + GSocket_SetNonBlocking() puts the socket in non-blocking mode. This is useful if we don't want to wait. */ -void GSocket_SetBlocking(GSocket *socket, bool block) +void GSocket_SetNonBlocking(GSocket *socket, bool block) { assert(socket != NULL); @@ -474,6 +485,24 @@ void GSocket_SetBlocking(GSocket *socket, bool block) ioctl(socket->m_fd, FIONBIO, &block); } +/* + * GSocket_SetTimeout() + */ +void GSocket_SetTimeout(GSocket *socket, unsigned long millisec) +{ + assert(socket != NULL); + + socket->m_timeout = millisec; + if (socket->m_fd != -1) { + struct timeval tval; + + tval.tv_sec = millisec / 1000; + tval.tv_usec = (millisec % 1000) * 1000; + setsockopt(socket->m_fd, SOL_SOCKET, SO_SNDTIMEO, &tval, sizeof(tval)); + setsockopt(socket->m_fd, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof(tval)); + } +} + /* GSocket_GetError() returns the last error occured on the socket stream. */ @@ -498,7 +527,7 @@ GSocketError GSocket_GetError(GSocket *socket) Server socket -> a client request a connection LOST: the connection is lost - SetFallback accepts a combination of these flags so a same callback can + SetCallback accepts a combination of these flags so a same callback can receive different events. An event is generated only once and its state is reseted when the relative @@ -506,8 +535,8 @@ GSocketError GSocket_GetError(GSocket *socket) For example: INPUT -> GSocket_Read() CONNECTION -> GSocket_Accept() */ -void GSocket_SetFallback(GSocket *socket, GSocketEventFlags event, - GSocketFallback fallback, char *cdata) +void GSocket_SetCallback(GSocket *socket, GSocketEventFlags event, + GSocketCallback fallback, char *cdata) { int count; @@ -520,17 +549,17 @@ void GSocket_SetFallback(GSocket *socket, GSocketEventFlags event, socket->m_fbacks[count] = fallback; socket->m_data[count] = cdata; - _GSocket_Install_Fallback(socket, count); + _GSocket_Install_Callback(socket, count); _GSocket_Enable(socket, count); } } } /* - UnsetFallback will disables all fallbacks specified by "event". + UnsetCallback will disables all fallbacks specified by "event". NOTE: event may be a combination of flags */ -void GSocket_UnsetFallback(GSocket *socket, GSocketEventFlags event) +void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags event) { int count = 0; @@ -540,7 +569,7 @@ void GSocket_UnsetFallback(GSocket *socket, GSocketEventFlags event) if ((event & (1 << count)) != 0) { _GSocket_Disable(socket, count); socket->m_fbacks[count] = NULL; - _GSocket_Uninstall_Fallback(socket, count); + _GSocket_Uninstall_Callback(socket, count); } } } @@ -567,14 +596,14 @@ void _GSocket_Enable(GSocket *socket, GSocketEvent event) { socket->m_iocalls[event] = TRUE; if (socket->m_fbacks[event]) - _GSocket_Install_Fallback(socket, event); + _GSocket_Install_Callback(socket, event); } void _GSocket_Disable(GSocket *socket, GSocketEvent event) { socket->m_iocalls[event] = FALSE; if (socket->m_fbacks[event]) - _GSocket_Uninstall_Fallback(socket, event); + _GSocket_Uninstall_Callback(socket, event); } int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size) diff --git a/src/unix/gsockunx.h b/src/unix/gsockunx.h index 380a93b10f..29cfe50e2a 100644 --- a/src/unix/gsockunx.h +++ b/src/unix/gsockunx.h @@ -17,9 +17,10 @@ struct _GSocket { GSocketError m_error; bool m_blocking, m_server, m_stream, m_oriented; + unsigned long m_timeout; - /* Fallbacks */ - GSocketFallback m_fbacks[GSOCK_MAX_EVENT]; + /* Callbacks */ + GSocketCallback m_fbacks[GSOCK_MAX_EVENT]; char *m_data[GSOCK_MAX_EVENT]; /* IO calls associated */ @@ -45,8 +46,8 @@ int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size); int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size); int _GSocket_Send_Stream(GSocket *socket, const char *buffer, int size); int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size); -void _GSocket_Install_Fallback(GSocket *socket, GSocketEvent count); -void _GSocket_Uninstall_Fallback(GSocket *socket, GSocketEvent count); +void _GSocket_Install_Callback(GSocket *socket, GSocketEvent count); +void _GSocket_Uninstall_Callback(GSocket *socket, GSocketEvent count); void _GSocket_Detected_Read(GSocket *socket); void _GSocket_Detected_Write(GSocket *socket); void _GSocket_GUI_Init(GSocket *socket);