X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3adb47a937983b19448f68601bd5ec90767646d5..301deecc27a700e5432f8923be63ec71a79b8a52:/src/common/sckipc.cpp diff --git a/src/common/sckipc.cpp b/src/common/sckipc.cpp index 47622c76ca..03e8f0958e 100644 --- a/src/common/sckipc.cpp +++ b/src/common/sckipc.cpp @@ -4,15 +4,25 @@ // Author: Julian Smart // Modified by: Guilhem Lavaux (big rewrite) May 1997, 1998 // Guillermo Rodriguez (updated for wxSocket v2) Jan 2000 +// (callbacks deprecated) Mar 2000 +// Vadim Zeitlin (added support for Unix sockets) Apr 2002 // Created: 1993 // RCS-ID: $Id$ // Copyright: (c) Julian Smart 1993 // (c) Guilhem Lavaux 1997, 1998 // (c) 2000 Guillermo Rodriguez -// Licence: wxWindows license +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ +// ========================================================================== +// declarations +// ========================================================================== + +// -------------------------------------------------------------------------- +// headers +// -------------------------------------------------------------------------- + +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "sckipc.h" #endif @@ -24,30 +34,29 @@ #endif #ifndef WX_PRECOMP -#include "wx/defs.h" +#include "wx/log.h" #endif -#if wxUSE_SOCKETS && wxUSE_IPC +#if wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS #include #include +#include #include "wx/socket.h" #include "wx/sckipc.h" -#include "wx/log.h" +#include "wx/module.h" +#include "wx/event.h" -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase) -IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase) -IMPLEMENT_CLASS(wxTCPConnection, wxConnectionBase) +// -------------------------------------------------------------------------- +// macros and constants +// -------------------------------------------------------------------------- // It seems to be already defined somewhere in the Xt includes. #ifndef __XT__ // Message codes -enum { +enum +{ IPC_EXECUTE = 1, IPC_REQUEST, IPC_POKE, @@ -62,24 +71,84 @@ enum { }; #endif -void Server_OnRequest(wxSocketServer& server, - wxSocketNotify evt, - char *cdata); -void Client_OnRequest(wxSocketBase& sock, - wxSocketNotify evt, - char *cdata); +// All sockets will be created with the following flags +#define SCKIPC_FLAGS (wxSOCKET_WAITALL) + +// headers needed for umask() +#ifdef __UNIX_LIKE__ + #include + #include +#endif // __UNIX_LIKE__ +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- -// All sockets will be created with the following flags +// get the address object for the given server name, the caller must delete it +static wxSockAddress * +GetAddressFromName(const wxString& serverName, const wxString& host = _T("")) +{ + // we always use INET sockets under non-Unix systems +#if defined(__UNIX__) && !defined(__WXMAC__) && !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 ) + { + wxUNIXaddress *addr = new wxUNIXaddress; + addr->Filename(serverName); -#define SCKIPC_FLAGS (wxSOCKET_WAITALL) + return addr; + } +#endif // Unix/!Unix + { + wxIPV4address *addr = new wxIPV4address; + addr->Service(serverName); + if ( !host.empty() ) + { + addr->Hostname(host); + } + + return addr; + } +} -// --------------------------------------------------------------------------- +// -------------------------------------------------------------------------- +// wxTCPEventHandler stuff (private class) +// -------------------------------------------------------------------------- + +class wxTCPEventHandler : public wxEvtHandler +{ +public: + wxTCPEventHandler() : wxEvtHandler() {}; + + void Client_OnRequest(wxSocketEvent& event); + void Server_OnRequest(wxSocketEvent& event); + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxTCPEventHandler) +}; + +enum +{ + _CLIENT_ONREQUEST_ID = 1000, + _SERVER_ONREQUEST_ID +}; + +static wxTCPEventHandler *gs_handler = NULL; + +// ========================================================================== +// implementation +// ========================================================================== + +IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase) +IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase) +IMPLEMENT_CLASS(wxTCPConnection, wxConnectionBase) + +// -------------------------------------------------------------------------- // wxTCPClient -// --------------------------------------------------------------------------- +// -------------------------------------------------------------------------- -wxTCPClient::wxTCPClient () - : wxClientBase() +wxTCPClient::wxTCPClient () : wxClientBase() { } @@ -95,7 +164,7 @@ bool wxTCPClient::ValidHost(const wxString& host) } wxConnectionBase *wxTCPClient::MakeConnection (const wxString& host, - const wxString& server_name, + const wxString& serverName, const wxString& topic) { wxSocketClient *client = new wxSocketClient(SCKIPC_FLAGS); @@ -103,18 +172,21 @@ wxConnectionBase *wxTCPClient::MakeConnection (const wxString& host, wxDataInputStream *data_is = new wxDataInputStream(*stream); wxDataOutputStream *data_os = new wxDataOutputStream(*stream); - wxIPV4address addr; - addr.Service(server_name); - addr.Hostname(host); + wxSockAddress *addr = GetAddressFromName(serverName, host); + if ( !addr ) + return NULL; + + bool ok = client->Connect(*addr); + delete addr; - if (client->Connect(addr)) + if ( ok ) { unsigned char msg; - + // Send topic name, and enquire whether this has succeeded data_os->Write8(IPC_CONNECT); data_os->WriteString(topic); - + msg = data_is->Read8(); // OK! Confirmation. @@ -131,8 +203,8 @@ wxConnectionBase *wxTCPClient::MakeConnection (const wxString& host, connection->m_sockstrm = stream; connection->m_codeci = data_is; connection->m_codeco = data_os; - client->Callback(Client_OnRequest); - client->CallbackData((char *)connection); + client->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID); + client->SetClientData(connection); client->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); client->Notify(TRUE); return connection; @@ -157,38 +229,105 @@ wxConnectionBase *wxTCPClient::MakeConnection (const wxString& host, wxConnectionBase *wxTCPClient::OnMakeConnection() { - return new wxTCPConnection; + return new wxTCPConnection(); } -// --------------------------------------------------------------------------- +// -------------------------------------------------------------------------- // wxTCPServer -// --------------------------------------------------------------------------- +// -------------------------------------------------------------------------- -wxTCPServer::wxTCPServer () - : wxServerBase() +wxTCPServer::wxTCPServer () : wxServerBase() { + m_server = NULL; } -bool wxTCPServer::Create(const wxString& server_name) +bool wxTCPServer::Create(const wxString& serverName) { - wxSocketServer *server; + // Destroy previous server, if any + if (m_server) + { + m_server->SetClientData(NULL); + m_server->Destroy(); + m_server = NULL; + } - // wxIPV4address defaults to INADDR_ANY:0 - wxIPV4address addr; - addr.Service(server_name); + wxSockAddress *addr = GetAddressFromName(serverName); + if ( !addr ) + return FALSE; + +#ifdef __UNIX_LIKE__ + mode_t umaskOld; + if ( addr->Type() == wxSockAddress::UNIX ) + { + // ensure that the file doesn't exist as otherwise calling socket() would + // fail + int rc = remove(serverName.fn_str()); + if ( rc < 0 && errno != ENOENT ) + { + delete addr; - // Create a socket listening on specified port - server = new wxSocketServer(addr, SCKIPC_FLAGS); - server->Callback((wxSocketBase::wxSockCbk)Server_OnRequest); - server->CallbackData((char *)this); - server->SetNotify(wxSOCKET_CONNECTION_FLAG); - server->Notify(TRUE); + return FALSE; + } + + // also set the umask to prevent the others from reading our file + umaskOld = umask(077); + } + else + { + // unused anyhow but shut down the compiler warnings + umaskOld = 0; + } +#endif // __UNIX_LIKE__ + + // Create a socket listening on the specified port + m_server = new wxSocketServer(*addr, SCKIPC_FLAGS); + +#ifdef __UNIX_LIKE__ + if ( addr->Type() == wxSockAddress::UNIX ) + { + // restore the umask + umask(umaskOld); + + // save the file name to remove it later + m_filename = serverName; + } +#endif // __UNIX_LIKE__ + + delete addr; + + if (!m_server->Ok()) + { + m_server->Destroy(); + m_server = NULL; + + return FALSE; + } + + m_server->SetEventHandler(*gs_handler, _SERVER_ONREQUEST_ID); + m_server->SetClientData(this); + m_server->SetNotify(wxSOCKET_CONNECTION_FLAG); + m_server->Notify(TRUE); return TRUE; } wxTCPServer::~wxTCPServer() { + if (m_server) + { + m_server->SetClientData(NULL); + m_server->Destroy(); + } + +#ifdef __UNIX_LIKE__ + if ( !m_filename.empty() ) + { + if ( remove(m_filename.fn_str()) != 0 ) + { + wxLogDebug(_T("Stale AF_UNIX file '%s' left."), m_filename.c_str()); + } + } +#endif // __UNIX_LIKE__ } wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) ) @@ -196,27 +335,39 @@ wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topi return new wxTCPConnection(); } -// --------------------------------------------------------------------------- +// -------------------------------------------------------------------------- // wxTCPConnection -// --------------------------------------------------------------------------- +// -------------------------------------------------------------------------- -wxTCPConnection::wxTCPConnection () - : wxConnectionBase(), - m_sock(NULL), m_sockstrm(NULL), m_codeci(NULL), m_codeco(NULL) +wxTCPConnection::wxTCPConnection () : wxConnectionBase() { + m_sock = NULL; + m_sockstrm = NULL; + m_codeci = NULL; + m_codeco = NULL; } -wxTCPConnection::wxTCPConnection(char * WXUNUSED(buffer), int WXUNUSED(size)) +wxTCPConnection::wxTCPConnection(wxChar *buffer, int size) + : wxConnectionBase(buffer, size) { + m_sock = NULL; + m_sockstrm = NULL; + m_codeci = NULL; + m_codeco = NULL; } wxTCPConnection::~wxTCPConnection () { + Disconnect(); wxDELETE(m_codeci); wxDELETE(m_codeco); wxDELETE(m_sockstrm); - if (m_sock) m_sock->Destroy(); + if (m_sock) + { + m_sock->SetClientData(NULL); + m_sock->Destroy(); + } } void wxTCPConnection::Compress(bool WXUNUSED(on)) @@ -227,10 +378,13 @@ void wxTCPConnection::Compress(bool WXUNUSED(on)) // Calls that CLIENT can make. bool wxTCPConnection::Disconnect () { + if ( !GetConnected() ) + return TRUE; // Send the the disconnect message to the peer. m_codeco->Write8(IPC_DISCONNECT); - m_sock->Callback(NULL); + m_sock->Notify(FALSE); m_sock->Close(); + SetConnected(FALSE); return TRUE; } @@ -245,7 +399,7 @@ bool wxTCPConnection::Execute(const wxChar *data, int size, wxIPCFormat format) m_codeco->Write8(format); if (size < 0) - size = strlen(data) + 1; // includes final NUL + size = wxStrlen(data) + 1; // includes final NUL m_codeco->Write32(size); m_sockstrm->Write(data, size); @@ -253,7 +407,7 @@ bool wxTCPConnection::Execute(const wxChar *data, int size, wxIPCFormat format) return TRUE; } -char *wxTCPConnection::Request (const wxString& item, int *size, wxIPCFormat format) +wxChar *wxTCPConnection::Request (const wxString& item, int *size, wxIPCFormat format) { if (!m_sock->IsConnected()) return NULL; @@ -271,10 +425,11 @@ char *wxTCPConnection::Request (const wxString& item, int *size, wxIPCFormat for else { size_t s; - char *data = NULL; s = m_codeci->Read32(); - data = new char[s]; + wxChar *data = GetBufferAtLeast( s ); + wxASSERT_MSG(data != NULL, + _T("Buffer too small in wxTCPConnection::Request") ); m_sockstrm->Read(data, s); if (size) @@ -293,7 +448,7 @@ bool wxTCPConnection::Poke (const wxString& item, wxChar *data, int size, wxIPCF m_codeco->Write8(format); if (size < 0) - size = strlen(data) + 1; // includes final NUL + size = wxStrlen(data) + 1; // includes final NUL m_codeco->Write32(size); m_sockstrm->Write(data, size); @@ -349,7 +504,7 @@ bool wxTCPConnection::Advise (const wxString& item, m_codeco->Write8(format); if (size < 0) - size = strlen(data) + 1; // includes final NUL + size = wxStrlen(data) + 1; // includes final NUL m_codeco->Write32(size); m_sockstrm->Write(data, size); @@ -357,23 +512,36 @@ bool wxTCPConnection::Advise (const wxString& item, return TRUE; } -void Client_OnRequest(wxSocketBase& sock, - wxSocketNotify evt, - char *cdata) +// -------------------------------------------------------------------------- +// wxTCPEventHandler (private class) +// -------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxTCPEventHandler, wxEvtHandler) + EVT_SOCKET(_CLIENT_ONREQUEST_ID, wxTCPEventHandler::Client_OnRequest) + EVT_SOCKET(_SERVER_ONREQUEST_ID, wxTCPEventHandler::Server_OnRequest) +END_EVENT_TABLE() + +void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event) { - int msg = 0; - wxTCPConnection *connection = (wxTCPConnection *)cdata; + wxSocketBase *sock = event.GetSocket(); + wxSocketNotify evt = event.GetSocketEvent(); + wxTCPConnection *connection = (wxTCPConnection *)(sock->GetClientData()); + + // This socket is being deleted; skip this event + if (!connection) + return; + wxDataInputStream *codeci; - wxDataOutputStream *codeco; + wxDataOutputStream *codeco; wxSocketStream *sockstrm; wxString topic_name = connection->m_topic; wxString item; - // The socket handler signals us that we lost the connection: destroy all. + // We lost the connection: destroy everything if (evt == wxSOCKET_LOST) { - sock.Callback(NULL); - sock.Close(); + sock->Notify(FALSE); + sock->Close(); connection->OnDisconnect(); return; } @@ -382,41 +550,43 @@ void Client_OnRequest(wxSocketBase& sock, codeci = connection->m_codeci; codeco = connection->m_codeco; sockstrm = connection->m_sockstrm; - msg = codeci->Read8(); + int msg = codeci->Read8(); switch (msg) { case IPC_EXECUTE: { - char *data; - size_t size; + wxChar *data; + size_t size; wxIPCFormat format; - + format = (wxIPCFormat)codeci->Read8(); size = codeci->Read32(); - data = new char[size]; + data = connection->GetBufferAtLeast( size ); + wxASSERT_MSG(data != NULL, + _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); sockstrm->Read(data, size); connection->OnExecute (topic_name, data, size, format); - delete [] data; break; } case IPC_ADVISE: { - char *data; + wxChar *data; size_t size; wxIPCFormat format; item = codeci->ReadString(); format = (wxIPCFormat)codeci->Read8(); size = codeci->Read32(); - data = new char[size]; + data = connection->GetBufferAtLeast( size ); + wxASSERT_MSG(data != NULL, + _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); sockstrm->Read(data, size); - + connection->OnAdvise (topic_name, item, data, size, format); - delete [] data; break; } case IPC_ADVISE_START: @@ -452,12 +622,12 @@ void Client_OnRequest(wxSocketBase& sock, item = codeci->ReadString(); format = (wxIPCFormat)codeci->Read8(); size = codeci->Read32(); - data = new wxChar[size]; + data = connection->GetBufferAtLeast( size ); + wxASSERT_MSG(data != NULL, + _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); sockstrm->Read(data, size); - - connection->OnPoke (topic_name, item, data, size, format); - delete [] data; + connection->OnPoke (topic_name, item, data, size, format); break; } @@ -469,14 +639,14 @@ void Client_OnRequest(wxSocketBase& sock, format = (wxIPCFormat)codeci->Read8(); int user_size = -1; - char *user_data = connection->OnRequest (topic_name, item, &user_size, format); + wxChar *user_data = connection->OnRequest (topic_name, item, &user_size, format); if (user_data) { codeco->Write8(IPC_REQUEST_REPLY); if (user_size == -1) - user_size = strlen(user_data) + 1; // includes final NUL + user_size = wxStrlen(user_data) + 1; // includes final NUL codeco->Write32(user_size); sockstrm->Write(user_data, user_size); @@ -488,9 +658,9 @@ void Client_OnRequest(wxSocketBase& sock, } case IPC_DISCONNECT: { - wxLogDebug("IPC_DISCONNECT"); - sock.Callback(NULL); - sock.Close(); + sock->Notify(FALSE); + sock->Close(); + connection->SetConnected(FALSE); connection->OnDisconnect(); break; } @@ -500,29 +670,29 @@ void Client_OnRequest(wxSocketBase& sock, } } -void Server_OnRequest(wxSocketServer& server, - wxSocketNotify evt, - char *cdata) +void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event) { - wxTCPServer *ipcserv = (wxTCPServer *)cdata; - wxSocketStream *stream; - wxDataInputStream *codeci; - wxDataOutputStream *codeco; + wxSocketServer *server = (wxSocketServer *) event.GetSocket(); + wxTCPServer *ipcserv = (wxTCPServer *) server->GetClientData(); - if (evt != wxSOCKET_CONNECTION) + // This socket is being deleted; skip this event + if (!ipcserv) + return; + + if (event.GetSocketEvent() != wxSOCKET_CONNECTION) return; // Accept the connection, getting a new socket - wxSocketBase *sock = server.Accept(); + wxSocketBase *sock = server->Accept(); if (!sock->Ok()) { sock->Destroy(); return; } - stream = new wxSocketStream(*sock); - codeci = new wxDataInputStream(*stream); - codeco = new wxDataOutputStream(*stream); + wxSocketStream *stream = new wxSocketStream(*sock); + wxDataInputStream *codeci = new wxDataInputStream(*stream); + wxDataOutputStream *codeco = new wxDataOutputStream(*stream); int msg; msg = codeci->Read8(); @@ -542,12 +712,12 @@ void Server_OnRequest(wxSocketServer& server, // Acknowledge success codeco->Write8(IPC_CONNECT); new_connection->m_topic = topic_name; - new_connection->m_sock = sock; + new_connection->m_sock = sock; new_connection->m_sockstrm = stream; new_connection->m_codeci = codeci; new_connection->m_codeco = codeco; - sock->Callback(Client_OnRequest); - sock->CallbackData((char *)new_connection); + sock->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID); + sock->SetClientData(new_connection); sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); sock->Notify(TRUE); return; @@ -569,5 +739,21 @@ void Server_OnRequest(wxSocketServer& server, sock->Destroy(); } +// -------------------------------------------------------------------------- +// wxTCPEventHandlerModule (private class) +// -------------------------------------------------------------------------- + +class wxTCPEventHandlerModule: public wxModule +{ + DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule) + +public: + bool OnInit() { gs_handler = new wxTCPEventHandler(); return TRUE; } + void OnExit() { wxDELETE(gs_handler); } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule) + + #endif // wxUSE_SOCKETS && wxUSE_IPC