]>
git.saurik.com Git - wxWidgets.git/blob - src/common/sckipc.cpp
1d43462ec2427ecda5e5b458ac8232fd5c96b71d
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/sckipc.cpp
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"
32 #if wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS
34 #include "wx/sckipc.h"
39 #include "wx/module.h"
46 #include "wx/socket.h"
48 // --------------------------------------------------------------------------
49 // macros and constants
50 // --------------------------------------------------------------------------
68 // All sockets will be created with the following flags
69 #define SCKIPC_FLAGS (wxSOCKET_WAITALL|wxSOCKET_REUSEADDR)
71 // headers needed for umask()
73 #include <sys/types.h>
75 #endif // __UNIX_LIKE__
77 // ----------------------------------------------------------------------------
79 // ----------------------------------------------------------------------------
81 // get the address object for the given server name, the caller must delete it
82 static wxSockAddress
*
83 GetAddressFromName(const wxString
& serverName
,
84 const wxString
& host
= wxEmptyString
)
86 // we always use INET sockets under non-Unix systems
87 #if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__)
88 // under Unix, if the server name looks like a path, create a AF_UNIX
89 // socket instead of AF_INET one
90 if ( serverName
.Find(_T('/')) != wxNOT_FOUND
)
92 wxUNIXaddress
*addr
= new wxUNIXaddress
;
93 addr
->Filename(serverName
);
99 wxIPV4address
*addr
= new wxIPV4address
;
100 addr
->Service(serverName
);
103 addr
->Hostname(host
);
110 // --------------------------------------------------------------------------
111 // wxTCPEventHandler stuff (private class)
112 // --------------------------------------------------------------------------
114 class wxTCPEventHandler
: public wxEvtHandler
117 wxTCPEventHandler() : wxEvtHandler() {}
119 void Client_OnRequest(wxSocketEvent
& event
);
120 void Server_OnRequest(wxSocketEvent
& event
);
122 DECLARE_EVENT_TABLE()
123 DECLARE_NO_COPY_CLASS(wxTCPEventHandler
)
128 _CLIENT_ONREQUEST_ID
= 1000,
132 static wxTCPEventHandler
*gs_handler
= NULL
;
134 // ==========================================================================
136 // ==========================================================================
138 IMPLEMENT_DYNAMIC_CLASS(wxTCPServer
, wxServerBase
)
139 IMPLEMENT_DYNAMIC_CLASS(wxTCPClient
, wxClientBase
)
140 IMPLEMENT_CLASS(wxTCPConnection
, wxConnectionBase
)
142 // --------------------------------------------------------------------------
144 // --------------------------------------------------------------------------
146 wxTCPClient::wxTCPClient()
151 bool wxTCPClient::ValidHost(const wxString
& host
)
155 return addr
.Hostname(host
);
158 wxConnectionBase
*wxTCPClient::MakeConnection (const wxString
& host
,
159 const wxString
& serverName
,
160 const wxString
& topic
)
162 wxSockAddress
*addr
= GetAddressFromName(serverName
, host
);
166 wxSocketClient
*client
= new wxSocketClient(SCKIPC_FLAGS
);
167 wxSocketStream
*stream
= new wxSocketStream(*client
);
168 wxDataInputStream
*data_is
= new wxDataInputStream(*stream
);
169 wxDataOutputStream
*data_os
= new wxDataOutputStream(*stream
);
171 bool ok
= client
->Connect(*addr
);
178 // Send topic name, and enquire whether this has succeeded
179 data_os
->Write8(IPC_CONNECT
);
180 data_os
->WriteString(topic
);
182 msg
= data_is
->Read8();
185 if (msg
== IPC_CONNECT
)
188 connection
= (wxTCPConnection
*)OnMakeConnection ();
192 if (connection
->IsKindOf(CLASSINFO(wxTCPConnection
)))
194 connection
->m_topic
= topic
;
195 connection
->m_sock
= client
;
196 connection
->m_sockstrm
= stream
;
197 connection
->m_codeci
= data_is
;
198 connection
->m_codeco
= data_os
;
199 client
->SetEventHandler(*gs_handler
, _CLIENT_ONREQUEST_ID
);
200 client
->SetClientData(connection
);
201 client
->SetNotify(wxSOCKET_INPUT_FLAG
| wxSOCKET_LOST_FLAG
);
202 client
->Notify(true);
208 // and fall through to delete everything else
214 // Something went wrong, delete everything
223 wxConnectionBase
*wxTCPClient::OnMakeConnection()
225 return new wxTCPConnection();
228 // --------------------------------------------------------------------------
230 // --------------------------------------------------------------------------
232 wxTCPServer::wxTCPServer()
238 bool wxTCPServer::Create(const wxString
& serverName
)
240 // Destroy previous server, if any
243 m_server
->SetClientData(NULL
);
248 wxSockAddress
*addr
= GetAddressFromName(serverName
);
254 if ( addr
->Type() == wxSockAddress::UNIX
)
256 // ensure that the file doesn't exist as otherwise calling socket()
258 int rc
= remove(serverName
.fn_str());
259 if ( rc
< 0 && errno
!= ENOENT
)
266 // also set the umask to prevent the others from reading our file
267 umaskOld
= umask(077);
271 // unused anyhow but shut down the compiler warnings
274 #endif // __UNIX_LIKE__
276 // Create a socket listening on the specified port
277 m_server
= new wxSocketServer(*addr
, SCKIPC_FLAGS
);
280 if ( addr
->Type() == wxSockAddress::UNIX
)
285 // save the file name to remove it later
286 m_filename
= serverName
;
288 #endif // __UNIX_LIKE__
300 m_server
->SetEventHandler(*gs_handler
, _SERVER_ONREQUEST_ID
);
301 m_server
->SetClientData(this);
302 m_server
->SetNotify(wxSOCKET_CONNECTION_FLAG
);
303 m_server
->Notify(true);
308 wxTCPServer::~wxTCPServer()
312 m_server
->SetClientData(NULL
);
317 if ( !m_filename
.empty() )
319 if ( remove(m_filename
.fn_str()) != 0 )
321 wxLogDebug(_T("Stale AF_UNIX file '%s' left."), m_filename
.c_str());
324 #endif // __UNIX_LIKE__
328 wxTCPServer::OnAcceptConnection(const wxString
& WXUNUSED(topic
))
330 return new wxTCPConnection();
333 // --------------------------------------------------------------------------
335 // --------------------------------------------------------------------------
337 void wxTCPConnection::Init()
345 wxTCPConnection::~wxTCPConnection()
351 m_sock
->SetClientData(NULL
);
355 /* Delete after destroy */
358 wxDELETE(m_sockstrm
);
361 void wxTCPConnection::Compress(bool WXUNUSED(on
))
366 // Calls that CLIENT can make.
367 bool wxTCPConnection::Disconnect()
369 if ( !GetConnected() )
372 // Send the disconnect message to the peer.
373 m_codeco
->Write8(IPC_DISCONNECT
);
377 m_sock
->Notify(false);
386 bool wxTCPConnection::DoExecute(const void *data
,
390 if ( !m_sock
->IsConnected() )
393 // Prepare EXECUTE message
394 m_codeco
->Write8(IPC_EXECUTE
);
395 m_codeco
->Write8(format
);
397 m_codeco
->Write32(size
);
398 m_sockstrm
->Write(data
, size
);
403 const void *wxTCPConnection::Request(const wxString
& item
,
407 if ( !m_sock
->IsConnected() )
410 m_codeco
->Write8(IPC_REQUEST
);
411 m_codeco
->WriteString(item
);
412 m_codeco
->Write8(format
);
414 int ret
= m_codeci
->Read8();
415 if ( ret
== IPC_FAIL
)
418 size_t s
= m_codeci
->Read32();
420 void *data
= GetBufferAtLeast( s
);
421 wxASSERT_MSG(data
!= NULL
,
422 _T("Buffer too small in wxTCPConnection::Request") );
423 m_sockstrm
->Read(data
, s
);
430 bool wxTCPConnection::DoPoke(const wxString
& item
,
435 if ( !m_sock
->IsConnected() )
438 m_codeco
->Write8(IPC_POKE
);
439 m_codeco
->WriteString(item
);
440 m_codeco
->Write8(format
);
442 m_codeco
->Write32(size
);
443 m_sockstrm
->Write(data
, size
);
448 bool wxTCPConnection::StartAdvise (const wxString
& item
)
450 if ( !m_sock
->IsConnected() )
453 m_codeco
->Write8(IPC_ADVISE_START
);
454 m_codeco
->WriteString(item
);
456 int ret
= m_codeci
->Read8();
463 bool wxTCPConnection::StopAdvise (const wxString
& item
)
465 if ( !m_sock
->IsConnected() )
468 m_codeco
->Write8(IPC_ADVISE_STOP
);
469 m_codeco
->WriteString(item
);
471 int ret
= m_codeci
->Read8();
479 // Calls that SERVER can make
480 bool wxTCPConnection::DoAdvise(const wxString
& item
,
485 if ( !m_sock
->IsConnected() )
488 m_codeco
->Write8(IPC_ADVISE
);
489 m_codeco
->WriteString(item
);
490 m_codeco
->Write8(format
);
492 m_codeco
->Write32(size
);
493 m_sockstrm
->Write(data
, size
);
498 // --------------------------------------------------------------------------
499 // wxTCPEventHandler (private class)
500 // --------------------------------------------------------------------------
502 BEGIN_EVENT_TABLE(wxTCPEventHandler
, wxEvtHandler
)
503 EVT_SOCKET(_CLIENT_ONREQUEST_ID
, wxTCPEventHandler::Client_OnRequest
)
504 EVT_SOCKET(_SERVER_ONREQUEST_ID
, wxTCPEventHandler::Server_OnRequest
)
507 void wxTCPEventHandler::Client_OnRequest(wxSocketEvent
&event
)
509 wxSocketBase
*sock
= event
.GetSocket();
513 wxSocketNotify evt
= event
.GetSocketEvent();
514 wxTCPConnection
*connection
= (wxTCPConnection
*)(sock
->GetClientData());
516 // This socket is being deleted; skip this event
520 wxDataInputStream
*codeci
;
521 wxDataOutputStream
*codeco
;
522 wxSocketStream
*sockstrm
;
523 wxString topic_name
= connection
->m_topic
;
526 // We lost the connection: destroy everything
527 if (evt
== wxSOCKET_LOST
)
531 connection
->OnDisconnect();
535 // Receive message number.
536 codeci
= connection
->m_codeci
;
537 codeco
= connection
->m_codeco
;
538 sockstrm
= connection
->m_sockstrm
;
539 int msg
= codeci
->Read8();
549 format
= (wxIPCFormat
)codeci
->Read8();
550 size
= codeci
->Read32();
552 data
= connection
->GetBufferAtLeast( size
);
553 wxASSERT_MSG(data
!= NULL
,
554 "Buffer too small in wxTCPEventHandler::Client_OnRequest" );
555 sockstrm
->Read(data
, size
);
557 connection
->OnExecute (topic_name
, data
, size
, format
);
563 item
= codeci
->ReadString();
564 wxIPCFormat format
= (wxIPCFormat
)codeci
->Read8();
565 size_t size
= codeci
->Read32();
566 void *data
= connection
->GetBufferAtLeast( size
);
567 wxASSERT_MSG(data
!= NULL
,
568 "Buffer too small in wxTCPEventHandler::Client_OnRequest" );
569 sockstrm
->Read(data
, size
);
571 connection
->OnAdvise (topic_name
, item
, data
, size
, format
);
575 case IPC_ADVISE_START
:
577 item
= codeci
->ReadString();
579 bool ok
= connection
->OnStartAdvise (topic_name
, item
);
581 codeco
->Write8(IPC_ADVISE_START
);
583 codeco
->Write8(IPC_FAIL
);
587 case IPC_ADVISE_STOP
:
589 item
= codeci
->ReadString();
591 bool ok
= connection
->OnStopAdvise (topic_name
, item
);
593 codeco
->Write8(IPC_ADVISE_STOP
);
595 codeco
->Write8(IPC_FAIL
);
601 item
= codeci
->ReadString();
602 wxIPCFormat format
= (wxIPCFormat
)codeci
->Read8();
603 size_t size
= codeci
->Read32();
604 void *data
= connection
->GetBufferAtLeast( size
);
605 wxASSERT_MSG(data
!= NULL
,
606 "Buffer too small in wxTCPEventHandler::Client_OnRequest" );
607 sockstrm
->Read(data
, size
);
609 connection
->OnPoke (topic_name
, item
, data
, size
, format
);
617 item
= codeci
->ReadString();
618 format
= (wxIPCFormat
)codeci
->Read8();
620 size_t user_size
= wxNO_LEN
;
621 const void *user_data
= connection
->OnRequest(topic_name
,
628 codeco
->Write8(IPC_REQUEST_REPLY
);
630 if (user_size
== wxNO_LEN
)
636 user_size
= strlen((const char *)user_data
) + 1; // includes final NUL
638 case wxIPC_UNICODETEXT
:
639 user_size
= (wcslen((const wchar_t *)user_data
) + 1) * sizeof(wchar_t); // includes final NUL
646 codeco
->Write32(user_size
);
647 sockstrm
->Write(user_data
, user_size
);
650 codeco
->Write8(IPC_FAIL
);
658 connection
->SetConnected(false);
659 connection
->OnDisconnect();
663 codeco
->Write8(IPC_FAIL
);
668 void wxTCPEventHandler::Server_OnRequest(wxSocketEvent
&event
)
670 wxSocketServer
*server
= (wxSocketServer
*) event
.GetSocket();
673 wxTCPServer
*ipcserv
= (wxTCPServer
*) server
->GetClientData();
675 // This socket is being deleted; skip this event
679 if (event
.GetSocketEvent() != wxSOCKET_CONNECTION
)
682 // Accept the connection, getting a new socket
683 wxSocketBase
*sock
= server
->Accept();
692 wxSocketStream
*stream
= new wxSocketStream(*sock
);
693 wxDataInputStream
*codeci
= new wxDataInputStream(*stream
);
694 wxDataOutputStream
*codeco
= new wxDataOutputStream(*stream
);
697 msg
= codeci
->Read8();
699 if (msg
== IPC_CONNECT
)
702 topic_name
= codeci
->ReadString();
704 wxTCPConnection
*new_connection
=
705 (wxTCPConnection
*)ipcserv
->OnAcceptConnection (topic_name
);
709 if (new_connection
->IsKindOf(CLASSINFO(wxTCPConnection
)))
711 // Acknowledge success
712 codeco
->Write8(IPC_CONNECT
);
713 new_connection
->m_topic
= topic_name
;
714 new_connection
->m_sock
= sock
;
715 new_connection
->m_sockstrm
= stream
;
716 new_connection
->m_codeci
= codeci
;
717 new_connection
->m_codeco
= codeco
;
718 sock
->SetEventHandler(*gs_handler
, _CLIENT_ONREQUEST_ID
);
719 sock
->SetClientData(new_connection
);
720 sock
->SetNotify(wxSOCKET_INPUT_FLAG
| wxSOCKET_LOST_FLAG
);
726 delete new_connection
;
727 // and fall through to delete everything else
732 // Something went wrong, send failure message and delete everything
733 codeco
->Write8(IPC_FAIL
);
741 // --------------------------------------------------------------------------
742 // wxTCPEventHandlerModule (private class)
743 // --------------------------------------------------------------------------
745 class wxTCPEventHandlerModule
: public wxModule
748 virtual bool OnInit() { gs_handler
= new wxTCPEventHandler
; return true; }
749 virtual void OnExit() { wxDELETE(gs_handler
); }
751 DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule
)
754 IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule
, wxModule
)
756 #endif // wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS