// Vadim Zeitlin (added support for Unix sockets) Apr 2002
// (use buffering, many fixes/cleanup) Oct 2008
// Created: 1993
-// RCS-ID: $Id$
// Copyright: (c) Julian Smart 1993
// (c) Guilhem Lavaux 1997, 1998
// (c) 2000 Guillermo Rodriguez <guille@iies.es>
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
#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);
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
_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
// 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
wxDataInputStream m_dataIn;
wxDataOutputStream m_dataOut;
- DECLARE_NO_COPY_CLASS(wxIPCSocketStreams)
+ wxDECLARE_NO_COPY_CLASS(wxIPCSocketStreams);
};
namespace
private:
wxIPCSocketStreams& m_streams;
- DECLARE_NO_COPY_CLASS(IPCOutput)
+ wxDECLARE_NO_COPY_CLASS(IPCOutput);
};
} // anonymous namespace
if (connection)
{
- if (connection->IsKindOf(CLASSINFO(wxTCPConnection)))
+ if (wxDynamicCast(connection, wxTCPConnection))
{
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);
delete addr;
- if (!m_server->Ok())
+ if (!m_server->IsOk())
{
m_server->Destroy();
m_server = NULL;
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);
{
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__
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,
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)
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
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;
}
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;
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;
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;
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
// Accept the connection, getting a new socket
wxSocketBase *sock = server->Accept();
if (!sock)
- return ;
- if (!sock->Ok())
+ return;
+ if (!sock->IsOk())
{
sock->Destroy();
return;
if (new_connection)
{
- if (new_connection->IsKindOf(CLASSINFO(wxTCPConnection)))
+ if (wxDynamicCast(new_connection, wxTCPConnection))
{
// Acknowledge success
out.Write8(IPC_CONNECT);
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);
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