]>
git.saurik.com Git - wxWidgets.git/blob - src/common/sckipc.cpp
   1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Interprocess communication implementation (wxSocket version) 
   4 // Author:      Julian Smart 
   5 // Modified by: Guilhem Lavaux (big rewrite) May 1997, 1998 
   6 //              Guillermo Rodriguez (updated for wxSocket v2) Jan 2000 
   7 //                                  (callbacks deprecated)    Mar 2000 
   8 //              Vadim Zeitlin (added support for Unix sockets) Apr 2002 
  11 // Copyright:   (c) Julian Smart 1993 
  12 //              (c) Guilhem Lavaux 1997, 1998 
  13 //              (c) 2000 Guillermo Rodriguez <guille@iies.es> 
  14 // Licence:     wxWindows licence 
  15 ///////////////////////////////////////////////////////////////////////////// 
  17 // ========================================================================== 
  19 // ========================================================================== 
  21 // -------------------------------------------------------------------------- 
  23 // -------------------------------------------------------------------------- 
  25 // For compilers that support precompilation, includes "wx.h". 
  26 #include "wx/wxprec.h" 
  36 #if wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS 
  42 #include "wx/socket.h" 
  43 #include "wx/sckipc.h" 
  44 #include "wx/module.h" 
  47 // -------------------------------------------------------------------------- 
  48 // macros and constants 
  49 // -------------------------------------------------------------------------- 
  51 // It seems to be already defined somewhere in the Xt includes. 
  70 // All sockets will be created with the following flags 
  71 #define SCKIPC_FLAGS (wxSOCKET_WAITALL) 
  73 // headers needed for umask() 
  75     #include <sys/types.h> 
  77 #endif // __UNIX_LIKE__ 
  79 // ---------------------------------------------------------------------------- 
  81 // ---------------------------------------------------------------------------- 
  83 // get the address object for the given server name, the caller must delete it 
  84 static wxSockAddress 
* 
  85 GetAddressFromName(const wxString
& serverName
, const wxString
& host 
= wxEmptyString
) 
  87     // we always use INET sockets under non-Unix systems 
  88 #if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__) && (!defined(__WXMAC__) || defined(__DARWIN__)) 
  89     // under Unix, if the server name looks like a path, create a AF_UNIX 
  90     // socket instead of AF_INET one 
  91     if ( serverName
.Find(_T('/')) != wxNOT_FOUND 
) 
  93         wxUNIXaddress 
*addr 
= new wxUNIXaddress
; 
  94         addr
->Filename(serverName
); 
 100         wxIPV4address 
*addr 
= new wxIPV4address
; 
 101         addr
->Service(serverName
); 
 104             addr
->Hostname(host
); 
 111 // -------------------------------------------------------------------------- 
 112 // wxTCPEventHandler stuff (private class) 
 113 // -------------------------------------------------------------------------- 
 115 class wxTCPEventHandler 
: public wxEvtHandler
 
 118   wxTCPEventHandler() : wxEvtHandler() {} 
 120   void Client_OnRequest(wxSocketEvent
& event
); 
 121   void Server_OnRequest(wxSocketEvent
& event
); 
 123   DECLARE_EVENT_TABLE() 
 124   DECLARE_NO_COPY_CLASS(wxTCPEventHandler
) 
 129   _CLIENT_ONREQUEST_ID 
= 1000, 
 133 static wxTCPEventHandler 
*gs_handler 
= NULL
; 
 135 // ========================================================================== 
 137 // ========================================================================== 
 139 IMPLEMENT_DYNAMIC_CLASS(wxTCPServer
, wxServerBase
) 
 140 IMPLEMENT_DYNAMIC_CLASS(wxTCPClient
, wxClientBase
) 
 141 IMPLEMENT_CLASS(wxTCPConnection
, wxConnectionBase
) 
 143 // -------------------------------------------------------------------------- 
 145 // -------------------------------------------------------------------------- 
 147 wxTCPClient::wxTCPClient () : wxClientBase() 
 151 wxTCPClient::~wxTCPClient () 
 155 bool wxTCPClient::ValidHost(const wxString
& host
) 
 159   return addr
.Hostname(host
); 
 162 wxConnectionBase 
*wxTCPClient::MakeConnection (const wxString
& host
, 
 163                                                const wxString
& serverName
, 
 164                                                const wxString
& topic
) 
 166   wxSockAddress 
*addr 
= GetAddressFromName(serverName
, host
); 
 170   wxSocketClient 
*client 
= new wxSocketClient(SCKIPC_FLAGS
); 
 171   wxSocketStream 
*stream 
= new wxSocketStream(*client
); 
 172   wxDataInputStream 
*data_is 
= new wxDataInputStream(*stream
); 
 173   wxDataOutputStream 
*data_os 
= new wxDataOutputStream(*stream
); 
 175   bool ok 
= client
->Connect(*addr
); 
 182     // Send topic name, and enquire whether this has succeeded 
 183     data_os
->Write8(IPC_CONNECT
); 
 184     data_os
->WriteString(topic
); 
 186     msg 
= data_is
->Read8(); 
 189     if (msg 
== IPC_CONNECT
) 
 191       wxTCPConnection 
*connection 
= (wxTCPConnection 
*)OnMakeConnection (); 
 195         if (connection
->IsKindOf(CLASSINFO(wxTCPConnection
))) 
 197           connection
->m_topic 
= topic
; 
 198           connection
->m_sock  
= client
; 
 199           connection
->m_sockstrm 
= stream
; 
 200           connection
->m_codeci 
= data_is
; 
 201           connection
->m_codeco 
= data_os
; 
 202           client
->SetEventHandler(*gs_handler
, _CLIENT_ONREQUEST_ID
); 
 203           client
->SetClientData(connection
); 
 204           client
->SetNotify(wxSOCKET_INPUT_FLAG 
| wxSOCKET_LOST_FLAG
); 
 205           client
->Notify(true); 
 211           // and fall through to delete everything else 
 217   // Something went wrong, delete everything 
 226 wxConnectionBase 
*wxTCPClient::OnMakeConnection() 
 228   return new wxTCPConnection(); 
 231 // -------------------------------------------------------------------------- 
 233 // -------------------------------------------------------------------------- 
 235 wxTCPServer::wxTCPServer () : wxServerBase() 
 240 bool wxTCPServer::Create(const wxString
& serverName
) 
 242   // Destroy previous server, if any 
 245     m_server
->SetClientData(NULL
); 
 250   wxSockAddress 
*addr 
= GetAddressFromName(serverName
); 
 256   if ( addr
->Type() == wxSockAddress::UNIX 
) 
 258       // ensure that the file doesn't exist as otherwise calling socket() would 
 260       int rc 
= remove(serverName
.fn_str()); 
 261       if ( rc 
< 0 && errno 
!= ENOENT 
) 
 268       // also set the umask to prevent the others from reading our file 
 269       umaskOld 
= umask(077); 
 273       // unused anyhow but shut down the compiler warnings 
 276 #endif // __UNIX_LIKE__ 
 278   // Create a socket listening on the specified port 
 279   m_server 
= new wxSocketServer(*addr
, SCKIPC_FLAGS
); 
 282   if ( addr
->Type() == wxSockAddress::UNIX 
) 
 287       // save the file name to remove it later 
 288       m_filename 
= serverName
; 
 290 #endif // __UNIX_LIKE__ 
 302   m_server
->SetEventHandler(*gs_handler
, _SERVER_ONREQUEST_ID
); 
 303   m_server
->SetClientData(this); 
 304   m_server
->SetNotify(wxSOCKET_CONNECTION_FLAG
); 
 305   m_server
->Notify(true); 
 310 wxTCPServer::~wxTCPServer() 
 314         m_server
->SetClientData(NULL
); 
 319     if ( !m_filename
.empty() ) 
 321         if ( remove(m_filename
.fn_str()) != 0 ) 
 323             wxLogDebug(_T("Stale AF_UNIX file '%s' left."), m_filename
.c_str()); 
 326 #endif // __UNIX_LIKE__ 
 329 wxConnectionBase 
*wxTCPServer::OnAcceptConnection( const wxString
& WXUNUSED(topic
) ) 
 331   return new wxTCPConnection(); 
 334 // -------------------------------------------------------------------------- 
 336 // -------------------------------------------------------------------------- 
 338 wxTCPConnection::wxTCPConnection () : wxConnectionBase() 
 346 wxTCPConnection::wxTCPConnection(wxChar 
*buffer
, int size
) 
 347        : wxConnectionBase(buffer
, size
) 
 355 wxTCPConnection::~wxTCPConnection () 
 360   wxDELETE(m_sockstrm
); 
 364     m_sock
->SetClientData(NULL
); 
 369 void wxTCPConnection::Compress(bool WXUNUSED(on
)) 
 374 // Calls that CLIENT can make. 
 375 bool wxTCPConnection::Disconnect () 
 377   if ( !GetConnected() ) 
 379   // Send the the disconnect message to the peer. 
 380   m_codeco
->Write8(IPC_DISCONNECT
); 
 381   m_sock
->Notify(false); 
 388 bool wxTCPConnection::Execute(const wxChar 
*data
, int size
, wxIPCFormat format
) 
 390   if (!m_sock
->IsConnected()) 
 393   // Prepare EXECUTE message 
 394   m_codeco
->Write8(IPC_EXECUTE
); 
 395   m_codeco
->Write8(format
); 
 398     size 
= (wxStrlen(data
) + 1) * sizeof(wxChar
);    // includes final NUL 
 400   m_codeco
->Write32(size
); 
 401   m_sockstrm
->Write(data
, size
); 
 406 wxChar 
*wxTCPConnection::Request (const wxString
& item
, int *size
, wxIPCFormat format
) 
 408   if (!m_sock
->IsConnected()) 
 411   m_codeco
->Write8(IPC_REQUEST
); 
 412   m_codeco
->WriteString(item
); 
 413   m_codeco
->Write8(format
); 
 415   // If Unpack doesn't initialize it. 
 418   ret 
= m_codeci
->Read8(); 
 425     s 
= m_codeci
->Read32(); 
 426     wxChar 
*data 
= GetBufferAtLeast( s 
); 
 427     wxASSERT_MSG(data 
!= NULL
, 
 428                  _T("Buffer too small in wxTCPConnection::Request") ); 
 429     m_sockstrm
->Read(data
, s
); 
 437 bool wxTCPConnection::Poke (const wxString
& item
, wxChar 
*data
, int size
, wxIPCFormat format
) 
 439   if (!m_sock
->IsConnected()) 
 442   m_codeco
->Write8(IPC_POKE
); 
 443   m_codeco
->WriteString(item
); 
 444   m_codeco
->Write8(format
); 
 447     size 
= (wxStrlen(data
) + 1) * sizeof(wxChar
);    // includes final NUL 
 449   m_codeco
->Write32(size
); 
 450   m_sockstrm
->Write(data
, size
); 
 455 bool wxTCPConnection::StartAdvise (const wxString
& item
) 
 459   if (!m_sock
->IsConnected()) 
 462   m_codeco
->Write8(IPC_ADVISE_START
); 
 463   m_codeco
->WriteString(item
); 
 465   ret 
= m_codeci
->Read8(); 
 473 bool wxTCPConnection::StopAdvise (const wxString
& item
) 
 477   if (!m_sock
->IsConnected()) 
 480   m_codeco
->Write8(IPC_ADVISE_STOP
); 
 481   m_codeco
->WriteString(item
); 
 483   msg 
= m_codeci
->Read8(); 
 491 // Calls that SERVER can make 
 492 bool wxTCPConnection::Advise (const wxString
& item
, 
 493                               wxChar 
*data
, int size
, wxIPCFormat format
) 
 495   if (!m_sock
->IsConnected()) 
 498   m_codeco
->Write8(IPC_ADVISE
); 
 499   m_codeco
->WriteString(item
); 
 500   m_codeco
->Write8(format
); 
 503     size 
= (wxStrlen(data
) + 1) * sizeof(wxChar
);    // includes final NUL 
 505   m_codeco
->Write32(size
); 
 506   m_sockstrm
->Write(data
, size
); 
 511 // -------------------------------------------------------------------------- 
 512 // wxTCPEventHandler (private class) 
 513 // -------------------------------------------------------------------------- 
 515 BEGIN_EVENT_TABLE(wxTCPEventHandler
, wxEvtHandler
) 
 516   EVT_SOCKET(_CLIENT_ONREQUEST_ID
, wxTCPEventHandler::Client_OnRequest
) 
 517   EVT_SOCKET(_SERVER_ONREQUEST_ID
, wxTCPEventHandler::Server_OnRequest
) 
 520 void wxTCPEventHandler::Client_OnRequest(wxSocketEvent 
&event
) 
 522   wxSocketBase 
*sock 
= event
.GetSocket(); 
 523   wxSocketNotify evt 
= event
.GetSocketEvent(); 
 524   wxTCPConnection 
*connection 
= (wxTCPConnection 
*)(sock
->GetClientData()); 
 526   // This socket is being deleted; skip this event 
 530   wxDataInputStream 
*codeci
; 
 531   wxDataOutputStream 
*codeco
; 
 532   wxSocketStream 
*sockstrm
; 
 533   wxString topic_name 
= connection
->m_topic
; 
 536   // We lost the connection: destroy everything 
 537   if (evt 
== wxSOCKET_LOST
) 
 541     connection
->OnDisconnect(); 
 545   // Receive message number. 
 546   codeci 
= connection
->m_codeci
; 
 547   codeco 
= connection
->m_codeco
; 
 548   sockstrm 
= connection
->m_sockstrm
; 
 549   int msg 
= codeci
->Read8(); 
 559     format 
= (wxIPCFormat
)codeci
->Read8(); 
 560     size 
= codeci
->Read32(); 
 561     data 
= connection
->GetBufferAtLeast( size 
); 
 562     wxASSERT_MSG(data 
!= NULL
, 
 563                  _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); 
 564     sockstrm
->Read(data
, size
); 
 566     connection
->OnExecute (topic_name
, data
, size
, format
); 
 576     item 
= codeci
->ReadString(); 
 577     format 
= (wxIPCFormat
)codeci
->Read8(); 
 578     size 
= codeci
->Read32(); 
 579     data 
= connection
->GetBufferAtLeast( size 
); 
 580     wxASSERT_MSG(data 
!= NULL
, 
 581                  _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); 
 582     sockstrm
->Read(data
, size
); 
 584     connection
->OnAdvise (topic_name
, item
, data
, size
, format
); 
 588   case IPC_ADVISE_START
: 
 590     item 
= codeci
->ReadString(); 
 592     bool ok 
= connection
->OnStartAdvise (topic_name
, item
); 
 594       codeco
->Write8(IPC_ADVISE_START
); 
 596       codeco
->Write8(IPC_FAIL
); 
 600   case IPC_ADVISE_STOP
: 
 602     item 
= codeci
->ReadString(); 
 604     bool ok 
= connection
->OnStopAdvise (topic_name
, item
); 
 606       codeco
->Write8(IPC_ADVISE_STOP
); 
 608       codeco
->Write8(IPC_FAIL
); 
 618     item 
= codeci
->ReadString(); 
 619     format 
= (wxIPCFormat
)codeci
->Read8(); 
 620     size 
= codeci
->Read32(); 
 621     data 
= connection
->GetBufferAtLeast( size 
); 
 622     wxASSERT_MSG(data 
!= NULL
, 
 623                  _T("Buffer too small in wxTCPEventHandler::Client_OnRequest") ); 
 624     sockstrm
->Read(data
, size
); 
 626     connection
->OnPoke (topic_name
, item
, data
, size
, format
); 
 634     item 
= codeci
->ReadString(); 
 635     format 
= (wxIPCFormat
)codeci
->Read8(); 
 638     wxChar 
*user_data 
= connection
->OnRequest (topic_name
, item
, &user_size
, format
); 
 642       codeco
->Write8(IPC_REQUEST_REPLY
); 
 645         user_size 
= (wxStrlen(user_data
) + 1) * sizeof(wxChar
);    // includes final NUL 
 647       codeco
->Write32(user_size
); 
 648       sockstrm
->Write(user_data
, user_size
); 
 651       codeco
->Write8(IPC_FAIL
); 
 659     connection
->SetConnected(false); 
 660     connection
->OnDisconnect(); 
 664     codeco
->Write8(IPC_FAIL
); 
 669 void wxTCPEventHandler::Server_OnRequest(wxSocketEvent 
&event
) 
 671   wxSocketServer 
*server 
= (wxSocketServer 
*) event
.GetSocket(); 
 672   wxTCPServer 
*ipcserv 
= (wxTCPServer 
*) server
->GetClientData(); 
 674   // This socket is being deleted; skip this event 
 678   if (event
.GetSocketEvent() != wxSOCKET_CONNECTION
) 
 681   // Accept the connection, getting a new socket 
 682   wxSocketBase 
*sock 
= server
->Accept(); 
 689   wxSocketStream 
*stream     
= new wxSocketStream(*sock
); 
 690   wxDataInputStream 
*codeci  
= new wxDataInputStream(*stream
); 
 691   wxDataOutputStream 
*codeco 
= new wxDataOutputStream(*stream
); 
 694   msg 
= codeci
->Read8(); 
 696   if (msg 
== IPC_CONNECT
) 
 699     topic_name 
= codeci
->ReadString(); 
 701     wxTCPConnection 
*new_connection 
= 
 702          (wxTCPConnection 
*)ipcserv
->OnAcceptConnection (topic_name
); 
 706       if (new_connection
->IsKindOf(CLASSINFO(wxTCPConnection
))) 
 708         // Acknowledge success 
 709         codeco
->Write8(IPC_CONNECT
); 
 710         new_connection
->m_topic 
= topic_name
; 
 711         new_connection
->m_sock 
= sock
; 
 712         new_connection
->m_sockstrm 
= stream
; 
 713         new_connection
->m_codeci 
= codeci
; 
 714         new_connection
->m_codeco 
= codeco
; 
 715         sock
->SetEventHandler(*gs_handler
, _CLIENT_ONREQUEST_ID
); 
 716         sock
->SetClientData(new_connection
); 
 717         sock
->SetNotify(wxSOCKET_INPUT_FLAG 
| wxSOCKET_LOST_FLAG
); 
 723         delete new_connection
; 
 724         // and fall through to delete everything else 
 729   // Something went wrong, send failure message and delete everything 
 730   codeco
->Write8(IPC_FAIL
); 
 738 // -------------------------------------------------------------------------- 
 739 // wxTCPEventHandlerModule (private class) 
 740 // -------------------------------------------------------------------------- 
 742 class wxTCPEventHandlerModule
: public wxModule
 
 744   DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule
) 
 747   bool OnInit() { gs_handler 
= new wxTCPEventHandler(); return true; } 
 748   void OnExit() { wxDELETE(gs_handler
); } 
 751 IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule
, wxModule
) 
 755     // wxUSE_SOCKETS && wxUSE_IPC