/////////////////////////////////////////////////////////////////////////////
-// Name: sckipc.cpp
+// Name: src/common/sckipc.cpp
// Purpose: Interprocess communication implementation (wxSocket version)
// 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 <guille@iies.es>
-// Licence: wxWindows license
+// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ==========================================================================
// headers
// --------------------------------------------------------------------------
-#ifdef __GNUG__
-#pragma implementation "sckipc.h"
-#endif
-
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
-#pragma hdrstop
+ #pragma hdrstop
#endif
+#if wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS
+
+#include "wx/sckipc.h"
+
#ifndef WX_PRECOMP
-#include "wx/defs.h"
+ #include "wx/log.h"
+ #include "wx/event.h"
+ #include "wx/module.h"
#endif
-#if wxUSE_SOCKETS && wxUSE_IPC
-
#include <stdlib.h>
#include <stdio.h>
+#include <errno.h>
#include "wx/socket.h"
-#include "wx/sckipc.h"
-#include "wx/module.h"
-#include "wx/event.h"
-#include "wx/log.h"
-
-#ifdef __BORLANDC__
-#pragma hdrstop
-#endif
// --------------------------------------------------------------------------
// macros and constants
};
#endif
-
// All sockets will be created with the following flags
#define SCKIPC_FLAGS (wxSOCKET_WAITALL)
+// headers needed for umask()
+#ifdef __UNIX_LIKE__
+ #include <sys/types.h>
+ #include <sys/stat.h>
+#endif // __UNIX_LIKE__
+
+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
+
+// get the address object for the given server name, the caller must delete it
+static wxSockAddress *
+GetAddressFromName(const wxString& serverName, const wxString& host = wxEmptyString)
+{
+ // we always use INET sockets under non-Unix systems
+#if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__) && (!defined(__WXMAC__) || defined(__DARWIN__))
+ // 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);
+
+ 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() {};
+ wxTCPEventHandler() : wxEvtHandler() {}
void Client_OnRequest(wxSocketEvent& event);
void Server_OnRequest(wxSocketEvent& event);
DECLARE_EVENT_TABLE()
+ DECLARE_NO_COPY_CLASS(wxTCPEventHandler)
};
enum
}
wxConnectionBase *wxTCPClient::MakeConnection (const wxString& host,
- const wxString& server_name,
+ const wxString& serverName,
const wxString& topic)
{
+ wxSockAddress *addr = GetAddressFromName(serverName, host);
+ if ( !addr )
+ return NULL;
+
wxSocketClient *client = new wxSocketClient(SCKIPC_FLAGS);
wxSocketStream *stream = new wxSocketStream(*client);
wxDataInputStream *data_is = new wxDataInputStream(*stream);
wxDataOutputStream *data_os = new wxDataOutputStream(*stream);
- wxIPV4address addr;
- addr.Service(server_name);
- addr.Hostname(host);
+ 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.
client->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID);
client->SetClientData(connection);
client->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
- client->Notify(TRUE);
+ client->Notify(true);
return connection;
}
else
wxConnectionBase *wxTCPClient::OnMakeConnection()
{
- return new wxTCPConnection;
+ return new wxTCPConnection();
}
// --------------------------------------------------------------------------
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;
+
+ 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;
+ }
- // Create a socket listening on specified port
- server = new wxSocketServer(addr, SCKIPC_FLAGS);
- server->SetEventHandler(*gs_handler, _SERVER_ONREQUEST_ID);
- server->SetClientData(this);
- server->SetNotify(wxSOCKET_CONNECTION_FLAG);
- server->Notify(TRUE);
+ m_server->SetEventHandler(*gs_handler, _SERVER_ONREQUEST_ID);
+ m_server->SetClientData(this);
+ m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
+ m_server->Notify(true);
- return 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) )
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();
+
+ if (m_sock)
+ {
+ m_sock->SetClientData(NULL);
+ m_sock->Destroy();
+ }
+
+ /* Delete after destroy */
wxDELETE(m_codeci);
wxDELETE(m_codeco);
wxDELETE(m_sockstrm);
-
- if (m_sock) m_sock->Destroy();
}
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->Notify(FALSE);
- m_sock->Close();
- return TRUE;
+ if ( m_sock )
+ {
+ m_sock->Notify(false);
+ m_sock->Close();
+ }
+
+ SetConnected(false);
+
+ return true;
}
bool wxTCPConnection::Execute(const wxChar *data, int size, wxIPCFormat format)
{
if (!m_sock->IsConnected())
- return FALSE;
+ return false;
// Prepare EXECUTE message
m_codeco->Write8(IPC_EXECUTE);
m_codeco->Write8(format);
if (size < 0)
- size = strlen(data) + 1; // includes final NUL
+ size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL
m_codeco->Write32(size);
m_sockstrm->Write(data, size);
- return TRUE;
+ 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;
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)
bool wxTCPConnection::Poke (const wxString& item, wxChar *data, int size, wxIPCFormat format)
{
if (!m_sock->IsConnected())
- return FALSE;
+ return false;
m_codeco->Write8(IPC_POKE);
m_codeco->WriteString(item);
m_codeco->Write8(format);
if (size < 0)
- size = strlen(data) + 1; // includes final NUL
+ size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL
m_codeco->Write32(size);
m_sockstrm->Write(data, size);
- return TRUE;
+ return true;
}
bool wxTCPConnection::StartAdvise (const wxString& item)
int ret;
if (!m_sock->IsConnected())
- return FALSE;
+ return false;
m_codeco->Write8(IPC_ADVISE_START);
m_codeco->WriteString(item);
ret = m_codeci->Read8();
if (ret != IPC_FAIL)
- return TRUE;
+ return true;
else
- return FALSE;
+ return false;
}
bool wxTCPConnection::StopAdvise (const wxString& item)
int msg;
if (!m_sock->IsConnected())
- return FALSE;
+ return false;
m_codeco->Write8(IPC_ADVISE_STOP);
m_codeco->WriteString(item);
msg = m_codeci->Read8();
if (msg != IPC_FAIL)
- return TRUE;
+ return true;
else
- return FALSE;
+ return false;
}
// Calls that SERVER can make
wxChar *data, int size, wxIPCFormat format)
{
if (!m_sock->IsConnected())
- return FALSE;
+ return false;
m_codeco->Write8(IPC_ADVISE);
m_codeco->WriteString(item);
m_codeco->Write8(format);
if (size < 0)
- size = strlen(data) + 1; // includes final NUL
+ size = (wxStrlen(data) + 1) * sizeof(wxChar); // includes final NUL
m_codeco->Write32(size);
m_sockstrm->Write(data, size);
- return TRUE;
+ return true;
}
// --------------------------------------------------------------------------
void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
{
wxSocketBase *sock = event.GetSocket();
+ if (!sock) { /* No socket, no glory */
+ return ;
+ }
wxSocketNotify evt = event.GetSocketEvent();
- wxTCPConnection *connection = (wxTCPConnection *)(event.GetClientData());
+ wxTCPConnection *connection = (wxTCPConnection *)(sock->GetClientData());
+
+ // This socket is being deleted; skip this event
+ if (!connection)
+ return;
- int msg = 0;
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->Notify(FALSE);
+ sock->Notify(false);
sock->Close();
connection->OnDisconnect();
return;
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:
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;
}
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) * sizeof(wxChar); // includes final NUL
codeco->Write32(user_size);
sockstrm->Write(user_data, user_size);
}
case IPC_DISCONNECT:
{
- sock->Notify(FALSE);
+ sock->Notify(false);
sock->Close();
+ connection->SetConnected(false);
connection->OnDisconnect();
break;
}
void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
{
wxSocketServer *server = (wxSocketServer *) event.GetSocket();
- wxTCPServer *ipcserv = (wxTCPServer *) event.GetClientData();
+ if (!server) { /* No server, Then exit */
+ return ;
+ }
+ wxTCPServer *ipcserv = (wxTCPServer *) server->GetClientData();
+
+ // 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();
+ if (!sock) { /* No socket, no glory */
+ return ;
+ }
if (!sock->Ok())
{
sock->Destroy();
// 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->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID);
sock->SetClientData(new_connection);
sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
- sock->Notify(TRUE);
+ sock->Notify(true);
return;
}
else
// wxTCPEventHandlerModule (private class)
// --------------------------------------------------------------------------
-class WXDLLEXPORT wxTCPEventHandlerModule: public wxModule
+class wxTCPEventHandlerModule: public wxModule
{
DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule)
public:
- bool OnInit() { gs_handler = new wxTCPEventHandler(); return TRUE; }
+ bool OnInit() { gs_handler = new wxTCPEventHandler(); return true; }
void OnExit() { wxDELETE(gs_handler); }
};
#endif
- // wxUSE_SOCKETS && wxUSE_IPC
+ // wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS