]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/sckipc.cpp
adapting to init pattern
[wxWidgets.git] / src / common / sckipc.cpp
index ff7ebbcc2a26fed269ea951baaf7743bf5b2ce7a..31d1273191f156a93b798a7377817b21798f79e4 100644 (file)
 namespace
 {
 
-// Message codes
+// Message codes (don't change them to avoid breaking the existing code using
+// wxIPC protocol!)
 enum IPCCode
 {
-    IPC_EXECUTE = 1,
-    IPC_REQUEST,
-    IPC_POKE,
-    IPC_ADVISE_START,
-    IPC_ADVISE_REQUEST,
-    IPC_ADVISE,
-    IPC_ADVISE_STOP,
-    IPC_REQUEST_REPLY,
-    IPC_FAIL,
-    IPC_CONNECT,
-    IPC_DISCONNECT
+    IPC_EXECUTE         = 1,
+    IPC_REQUEST         = 2,
+    IPC_POKE            = 3,
+    IPC_ADVISE_START    = 4,
+    IPC_ADVISE_REQUEST  = 5,
+    IPC_ADVISE          = 6,
+    IPC_ADVISE_STOP     = 7,
+    IPC_REQUEST_REPLY   = 8,
+    IPC_FAIL            = 9,
+    IPC_CONNECT         = 10,
+    IPC_DISCONNECT      = 11,
+    IPC_MAX
 };
 
 } // anonymous namespace
@@ -90,7 +92,7 @@ GetAddressFromName(const wxString& serverName,
 #if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__)
     // under Unix, if the server name looks like a path, create a AF_UNIX
     // socket instead of AF_INET one
-    if ( serverName.Find(_T('/')) != wxNOT_FOUND )
+    if ( serverName.Find(wxT('/')) != wxNOT_FOUND )
     {
         wxUNIXaddress *addr = new wxUNIXaddress;
         addr->Filename(serverName);
@@ -117,13 +119,16 @@ GetAddressFromName(const wxString& serverName,
 class wxTCPEventHandler : public wxEvtHandler
 {
 public:
-    wxTCPEventHandler() : wxEvtHandler() {}
+    wxTCPEventHandler() : wxEvtHandler() { }
 
     void Client_OnRequest(wxSocketEvent& event);
     void Server_OnRequest(wxSocketEvent& event);
 
+private:
+    void HandleDisconnect(wxTCPConnection *connection);
+
     DECLARE_EVENT_TABLE()
-    DECLARE_NO_COPY_CLASS(wxTCPEventHandler)
+    wxDECLARE_NO_COPY_CLASS(wxTCPEventHandler);
 };
 
 enum
@@ -132,7 +137,38 @@ enum
     _SERVER_ONREQUEST_ID
 };
 
-static wxTCPEventHandler *gs_handler = NULL;
+// --------------------------------------------------------------------------
+// wxTCPEventHandlerModule (private class)
+// --------------------------------------------------------------------------
+
+class wxTCPEventHandlerModule : public wxModule
+{
+public:
+    wxTCPEventHandlerModule() : wxModule() { }
+
+    // get the global wxTCPEventHandler creating it if necessary
+    static wxTCPEventHandler& GetHandler()
+    {
+        if ( !ms_handler )
+            ms_handler = new wxTCPEventHandler;
+
+        return *ms_handler;
+    }
+
+    // as ms_handler is initialized on demand, don't do anything in OnInit()
+    virtual bool OnInit() { return true; }
+    virtual void OnExit() { wxDELETE(ms_handler); }
+
+private:
+    static wxTCPEventHandler *ms_handler;
+
+    DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule)
+    wxDECLARE_NO_COPY_CLASS(wxTCPEventHandlerModule);
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule)
+
+wxTCPEventHandler *wxTCPEventHandlerModule::ms_handler = NULL;
 
 // --------------------------------------------------------------------------
 // wxIPCSocketStreams
@@ -150,11 +186,11 @@ public:
     // ctor initializes all the streams on top of the given socket
     //
     // note that we use a bigger than default buffer size which matches the
-    // typical Ethernet MTU
+    // typical Ethernet MTU (minus TCP header overhead)
     wxIPCSocketStreams(wxSocketBase& sock)
         : m_socketStream(sock),
 #ifdef USE_BUFFER
-          m_bufferedOut(m_socketStream, 1500),
+          m_bufferedOut(m_socketStream, 1448),
 #else
           m_bufferedOut(m_socketStream),
 #endif
@@ -248,7 +284,7 @@ private:
     wxDataInputStream  m_dataIn;
     wxDataOutputStream m_dataOut;
 
-    DECLARE_NO_COPY_CLASS(wxIPCSocketStreams)
+    wxDECLARE_NO_COPY_CLASS(wxIPCSocketStreams);
 };
 
 namespace
@@ -305,7 +341,7 @@ public:
 private:
     wxIPCSocketStreams& m_streams;
 
-    DECLARE_NO_COPY_CLASS(IPCOutput)
+    wxDECLARE_NO_COPY_CLASS(IPCOutput);
 };
 
 } // anonymous namespace
@@ -368,7 +404,8 @@ wxConnectionBase *wxTCPClient::MakeConnection(const wxString& host,
                     connection->m_topic = topic;
                     connection->m_sock  = client;
                     connection->m_streams = streams;
-                    client->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID);
+                    client->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
+                                            _CLIENT_ONREQUEST_ID);
                     client->SetClientData(connection);
                     client->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
                     client->Notify(true);
@@ -461,7 +498,7 @@ bool wxTCPServer::Create(const wxString& serverName)
 
     delete addr;
 
-    if (!m_server->Ok())
+    if (!m_server->IsOk())
     {
         m_server->Destroy();
         m_server = NULL;
@@ -469,7 +506,8 @@ bool wxTCPServer::Create(const wxString& serverName)
         return false;
     }
 
-    m_server->SetEventHandler(*gs_handler, _SERVER_ONREQUEST_ID);
+    m_server->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
+                              _SERVER_ONREQUEST_ID);
     m_server->SetClientData(this);
     m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
     m_server->Notify(true);
@@ -490,7 +528,7 @@ wxTCPServer::~wxTCPServer()
     {
         if ( remove(m_filename.fn_str()) != 0 )
         {
-            wxLogDebug(_T("Stale AF_UNIX file '%s' left."), m_filename.c_str());
+            wxLogDebug(wxT("Stale AF_UNIX file '%s' left."), m_filename.c_str());
         }
     }
 #endif // __UNIX_LIKE__
@@ -576,11 +614,15 @@ const void *wxTCPConnection::Request(const wxString& item,
 
     IPCOutput(m_streams).Write(IPC_REQUEST, item, format);
 
-    int ret = m_streams->Read8();
-    if ( ret == IPC_FAIL )
+    const int ret = m_streams->Read8();
+    if ( ret != IPC_REQUEST_REPLY )
         return NULL;
 
-    return m_streams->ReadData(this, size);
+    // ReadData() needs a non-NULL size pointer but the client code can call us
+    // with NULL pointer (this makes sense if it knows that it always works
+    // with NUL-terminated strings)
+    size_t sizeFallback;
+    return m_streams->ReadData(this, size ? size : &sizeFallback);
 }
 
 bool wxTCPConnection::DoPoke(const wxString& item,
@@ -605,11 +647,9 @@ bool wxTCPConnection::StartAdvise(const wxString& item)
 
     IPCOutput(m_streams).Write(IPC_ADVISE_START, item);
 
-    int ret = m_streams->Read8();
-    if (ret != IPC_FAIL)
-        return true;
-    else
-        return false;
+    const int ret = m_streams->Read8();
+
+    return ret == IPC_ADVISE_START;
 }
 
 bool wxTCPConnection::StopAdvise (const wxString& item)
@@ -619,12 +659,9 @@ bool wxTCPConnection::StopAdvise (const wxString& item)
 
     IPCOutput(m_streams).Write(IPC_ADVISE_STOP, item);
 
-    int ret = m_streams->Read8();
+    const int ret = m_streams->Read8();
 
-    if (ret != IPC_FAIL)
-        return true;
-    else
-        return false;
+    return ret == IPC_ADVISE_STOP;
 }
 
 // Calls that SERVER can make
@@ -652,25 +689,38 @@ BEGIN_EVENT_TABLE(wxTCPEventHandler, wxEvtHandler)
     EVT_SOCKET(_SERVER_ONREQUEST_ID, wxTCPEventHandler::Server_OnRequest)
 END_EVENT_TABLE()
 
+void wxTCPEventHandler::HandleDisconnect(wxTCPConnection *connection)
+{
+    // connection was closed (either gracefully or not): destroy everything
+    connection->m_sock->Notify(false);
+    connection->m_sock->Close();
+
+    // don't leave references to this soon-to-be-dangling connection in the
+    // socket as it won't be destroyed immediately as its destruction will be
+    // delayed in case there are more events pending for it
+    connection->m_sock->SetClientData(NULL);
+
+    connection->SetConnected(false);
+    connection->OnDisconnect();
+}
+
 void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
 {
     wxSocketBase *sock = event.GetSocket();
     if (!sock)
-        return ;
+        return;
 
     wxSocketNotify evt = event.GetSocketEvent();
-    wxTCPConnection *connection = (wxTCPConnection *)(sock->GetClientData());
+    wxTCPConnection * const
+        connection = static_cast<wxTCPConnection *>(sock->GetClientData());
 
     // This socket is being deleted; skip this event
     if (!connection)
         return;
 
-    // We lost the connection: destroy everything
-    if (evt == wxSOCKET_LOST)
+    if ( evt == wxSOCKET_LOST )
     {
-        sock->Notify(false);
-        sock->Close();
-        connection->OnDisconnect();
+        HandleDisconnect(connection);
         return;
     }
 
@@ -680,16 +730,21 @@ void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
     const wxString topic = connection->m_topic;
     wxString item;
 
-    switch ( const int msg = streams->Read8() )
+    bool error = false;
+
+    const int msg = streams->Read8();
+    switch ( msg )
     {
         case IPC_EXECUTE:
             {
                 wxIPCFormat format;
-                size_t size;
+                size_t size wxDUMMY_INITIALIZE(0);
                 void * const
                     data = streams->ReadFormatData(connection, &format, &size);
-
-                connection->OnExecute(topic, data, size, format);
+                if ( data )
+                    connection->OnExecute(topic, data, size, format);
+                else
+                    error = true;
             }
             break;
 
@@ -698,11 +753,14 @@ void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
                 item = streams->ReadString();
 
                 wxIPCFormat format;
-                size_t size;
+                size_t size wxDUMMY_INITIALIZE(0);
                 void * const
                     data = streams->ReadFormatData(connection, &format, &size);
 
-                connection->OnAdvise(topic, item, data, size, format);
+                if ( data )
+                    connection->OnAdvise(topic, item, data, size, format);
+                else
+                    error = true;
             }
             break;
 
@@ -731,10 +789,13 @@ void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
                 item = streams->ReadString();
                 wxIPCFormat format = (wxIPCFormat)streams->Read8();
 
-                size_t size;
+                size_t size wxDUMMY_INITIALIZE(0);
                 void * const data = streams->ReadData(connection, &size);
 
-                connection->OnPoke(topic, item, data, size, format);
+                if ( data )
+                    connection->OnPoke(topic, item, data, size, format);
+                else
+                    error = true;
             }
             break;
 
@@ -780,24 +841,29 @@ void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
             break;
 
         case IPC_DISCONNECT:
-            sock->Notify(false);
-            sock->Close();
-            connection->SetConnected(false);
-            connection->OnDisconnect();
+            HandleDisconnect(connection);
+            break;
+
+        case IPC_FAIL:
+            wxLogDebug("Unexpected IPC_FAIL received");
+            error = true;
             break;
 
         default:
             wxLogDebug("Unknown message code %d received.", msg);
-            IPCOutput(streams).Write8(IPC_FAIL);
+            error = true;
             break;
     }
+
+    if ( error )
+        IPCOutput(streams).Write8(IPC_FAIL);
 }
 
 void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
 {
     wxSocketServer *server = (wxSocketServer *) event.GetSocket();
     if (!server)
-        return ;
+        return;
     wxTCPServer *ipcserv = (wxTCPServer *) server->GetClientData();
 
     // This socket is being deleted; skip this event
@@ -810,8 +876,8 @@ void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
     // Accept the connection, getting a new socket
     wxSocketBase *sock = server->Accept();
     if (!sock)
-        return ;
-    if (!sock->Ok())
+        return;
+    if (!sock->IsOk())
     {
         sock->Destroy();
         return;
@@ -840,7 +906,8 @@ void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
                     new_connection->m_sock = sock;
                     new_connection->m_streams = streams;
                     new_connection->m_topic = topic;
-                    sock->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID);
+                    sock->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
+                                          _CLIENT_ONREQUEST_ID);
                     sock->SetClientData(new_connection);
                     sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
                     sock->Notify(true);
@@ -862,19 +929,4 @@ void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
     sock->Destroy();
 }
 
-// --------------------------------------------------------------------------
-// wxTCPEventHandlerModule (private class)
-// --------------------------------------------------------------------------
-
-class wxTCPEventHandlerModule: public wxModule
-{
-public:
-    virtual bool OnInit() { gs_handler = new wxTCPEventHandler; return true; }
-    virtual void OnExit() { wxDELETE(gs_handler); }
-
-    DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule)
-};
-
-IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule)
-
 #endif // wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS