]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/socket.cpp
correct test for wxDEBUG_LEVEL in last commit
[wxWidgets.git] / src / common / socket.cpp
index c80b314d606202c72b1e47b1a47d94606a50ed65..3c4f417e75596fb46ad83049a83e8ca97b95cd55 100644 (file)
@@ -42,6 +42,7 @@
 #include "wx/stopwatch.h"
 #include "wx/thread.h"
 #include "wx/evtloop.h"
+#include "wx/link.h"
 
 #include "wx/private/fd.h"
 #include "wx/private/socket.h"
 // this should cover all the current Unix systems (Windows never sends any
 // signals anyhow) but if we find one that has neither we should explicitly
 // ignore SIGPIPE for it
+// OpenVMS has neither MSG_NOSIGNAL nor SO_NOSIGPIPE. However the socket sample
+// seems to work. Not sure if problems will show up on OpenVMS using sockets.
 #ifdef MSG_NOSIGNAL
     #define wxSOCKET_MSG_NOSIGNAL MSG_NOSIGNAL
 #else // MSG_NOSIGNAL not available (BSD including OS X)
+    // next best possibility is to use SO_NOSIGPIPE socket option, this covers
+    // BSD systems (including OS X) -- but if we don't have it neither (AIX and
+    // old HP-UX do not), we have to fall back to the old way of simply
+    // disabling SIGPIPE temporarily, so define a class to do it in a safe way
     #if defined(__UNIX__) && !defined(SO_NOSIGPIPE)
-        #error "Writing to socket could generate unhandled SIGPIPE."
-        #error "Please post information about your system to wx-dev."
-    #endif
+    extern "C" { typedef void (*wxSigHandler_t)(int); }
+    namespace
+    {
+        class IgnoreSignal
+        {
+        public:
+            // ctor disables the given signal
+            IgnoreSignal(int sig)
+                : m_handler(signal(sig, SIG_IGN)),
+                  m_sig(sig)
+            {
+            }
+
+            // dtor restores the old handler
+            ~IgnoreSignal()
+            {
+                signal(m_sig, m_handler);
+            }
+
+        private:
+            const wxSigHandler_t m_handler;
+            const int m_sig;
+
+            wxDECLARE_NO_COPY_CLASS(IgnoreSignal);
+        };
+    } // anonymous namespace
+
+    #define wxNEEDS_IGNORE_SIGPIPE
+    #endif // Unix without SO_NOSIGPIPE
 
     #define wxSOCKET_MSG_NOSIGNAL 0
 #endif
@@ -76,6 +109,9 @@ WX_CHECK_BUILD_OPTIONS("wxNet")
 // macros and constants
 // --------------------------------------------------------------------------
 
+// event
+wxDEFINE_EVENT(wxEVT_SOCKET, wxSocketEvent);
+
 // discard buffer
 #define MAX_DISCARD_SIZE (10 * 1024)
 
@@ -121,7 +157,7 @@ public:
 public:
     wxSocketState() : wxObject() {}
 
-    DECLARE_NO_COPY_CLASS(wxSocketState)
+    wxDECLARE_NO_COPY_CLASS(wxSocketState);
 };
 
 // wxSocketWaitModeChanger: temporarily change the socket flags affecting its
@@ -157,7 +193,7 @@ private:
     wxSocketBase * const m_socket;
     const int m_oldflags;
 
-    DECLARE_NO_COPY_CLASS(wxSocketWaitModeChanger)
+    wxDECLARE_NO_COPY_CLASS(wxSocketWaitModeChanger);
 };
 
 // wxSocketRead/WriteGuard are instantiated before starting reading
@@ -183,7 +219,7 @@ public:
 private:
     wxSocketBase * const m_socket;
 
-    DECLARE_NO_COPY_CLASS(wxSocketReadGuard)
+    wxDECLARE_NO_COPY_CLASS(wxSocketReadGuard);
 };
 
 class wxSocketWriteGuard
@@ -207,7 +243,7 @@ public:
 private:
     wxSocketBase * const m_socket;
 
-    DECLARE_NO_COPY_CLASS(wxSocketWriteGuard)
+    wxDECLARE_NO_COPY_CLASS(wxSocketWriteGuard);
 };
 
 // ============================================================================
@@ -607,6 +643,10 @@ int wxSocketImpl::RecvStream(void *buffer, int size)
 
 int wxSocketImpl::SendStream(const void *buffer, int size)
 {
+#ifdef wxNEEDS_IGNORE_SIGPIPE
+    IgnoreSignal ignore(SIGPIPE);
+#endif
+
     int ret;
     DO_WHILE_EINTR( ret, send(m_fd, static_cast<const char *>(buffer), size,
                               wxSOCKET_MSG_NOSIGNAL) );
@@ -764,7 +804,8 @@ void wxSocketBase::Init()
     {
         // this Initialize() will be undone by wxSocketModule::OnExit(), all
         // the other calls to it should be matched by a call to Shutdown()
-        Initialize();
+        if (!Initialize())
+            wxLogError("Cannot initialize wxSocketBase");
     }
 }
 
@@ -1321,6 +1362,20 @@ wxSocketBase::DoWait(long timeout, wxSocketEventFlags flags)
         eventLoop = NULL;
     }
 
+    // Make sure the events we're interested in are enabled before waiting for
+    // them: this is really necessary here as otherwise this could happen:
+    //  1. DoRead(wxSOCKET_WAITALL) is called
+    //  2. There is nothing to read so DoWait(wxSOCKET_INPUT_FLAG) is called
+    //  3. Some, but not all data appears, wxSocketImplUnix::OnReadWaiting()
+    //     is called and wxSOCKET_INPUT_FLAG events are disabled in it
+    //  4. Because of wxSOCKET_WAITALL we call DoWait() again but the events
+    //     are still disabled and we block forever
+    //
+    // More elegant solution would be nice but for now simply re-enabling the
+    // events here will do
+    m_impl->ReenableEvents(flags & (wxSOCKET_INPUT_FLAG | wxSOCKET_OUTPUT_FLAG));
+
+
     // Wait until we receive the event we're waiting for or the timeout expires
     // (but note that we always execute the loop at least once, even if timeout
     // is 0 as this is used for polling)
@@ -1983,4 +2038,11 @@ private:
 
 IMPLEMENT_DYNAMIC_CLASS(wxSocketModule, wxModule)
 
+#if defined(wxUSE_SELECT_DISPATCHER) && wxUSE_SELECT_DISPATCHER
+// NOTE: we need to force linking against socketiohandler.cpp otherwise in
+//       static builds of wxWidgets the ManagerSetter::ManagerSetter ctor
+//       contained there wouldn't be ever called
+wxFORCE_LINK_MODULE( socketiohandler )
+#endif
+
 #endif // wxUSE_SOCKETS