]> git.saurik.com Git - wxWidgets.git/blame - src/common/sckipc.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / common / sckipc.cpp
CommitLineData
f4ada568 1/////////////////////////////////////////////////////////////////////////////
d5da0ce7 2// Name: src/common/sckipc.cpp
f4ada568 3// Purpose: Interprocess communication implementation (wxSocket version)
0834112f 4// Author: Julian Smart
f4ada568 5// Modified by: Guilhem Lavaux (big rewrite) May 1997, 1998
0834112f 6// Guillermo Rodriguez (updated for wxSocket v2) Jan 2000
cdc59bb6 7// (callbacks deprecated) Mar 2000
0dbfd66d 8// Vadim Zeitlin (added support for Unix sockets) Apr 2002
8aea37a9 9// (use buffering, many fixes/cleanup) Oct 2008
f4ada568 10// Created: 1993
0834112f
GRG
11// Copyright: (c) Julian Smart 1993
12// (c) Guilhem Lavaux 1997, 1998
13// (c) 2000 Guillermo Rodriguez <guille@iies.es>
65571936 14// Licence: wxWindows licence
f4ada568
GL
15/////////////////////////////////////////////////////////////////////////////
16
cdc59bb6
GRG
17// ==========================================================================
18// declarations
19// ==========================================================================
20
21// --------------------------------------------------------------------------
22// headers
23// --------------------------------------------------------------------------
24
fcc6dddd
JS
25// For compilers that support precompilation, includes "wx.h".
26#include "wx/wxprec.h"
f4ada568 27
fcc6dddd 28#ifdef __BORLANDC__
d5da0ce7 29 #pragma hdrstop
f4ada568
GL
30#endif
31
d5da0ce7
WS
32#if wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS
33
34#include "wx/sckipc.h"
35
fcc6dddd 36#ifndef WX_PRECOMP
d5da0ce7
WS
37 #include "wx/log.h"
38 #include "wx/event.h"
02761f6c 39 #include "wx/module.h"
fcc6dddd
JS
40#endif
41
42#include <stdlib.h>
43#include <stdio.h>
0dbfd66d 44#include <errno.h>
fcc6dddd 45
f4ada568 46#include "wx/socket.h"
f4ada568 47
cdc59bb6
GRG
48// --------------------------------------------------------------------------
49// macros and constants
50// --------------------------------------------------------------------------
f4ada568 51
8aea37a9
VZ
52namespace
53{
54
d730bd8a
VZ
55// Message codes (don't change them to avoid breaking the existing code using
56// wxIPC protocol!)
8aea37a9 57enum IPCCode
cdc59bb6 58{
d730bd8a
VZ
59 IPC_EXECUTE = 1,
60 IPC_REQUEST = 2,
61 IPC_POKE = 3,
62 IPC_ADVISE_START = 4,
63 IPC_ADVISE_REQUEST = 5,
64 IPC_ADVISE = 6,
65 IPC_ADVISE_STOP = 7,
66 IPC_REQUEST_REPLY = 8,
67 IPC_FAIL = 9,
68 IPC_CONNECT = 10,
69 IPC_DISCONNECT = 11,
70 IPC_MAX
f4ada568 71};
f4ada568 72
8aea37a9 73} // anonymous namespace
d3ea6527 74
0dbfd66d
VZ
75// headers needed for umask()
76#ifdef __UNIX_LIKE__
77 #include <sys/types.h>
78 #include <sys/stat.h>
79#endif // __UNIX_LIKE__
80
81// ----------------------------------------------------------------------------
82// private functions
83// ----------------------------------------------------------------------------
84
85// get the address object for the given server name, the caller must delete it
86static wxSockAddress *
7e73fb9c
VZ
87GetAddressFromName(const wxString& serverName,
88 const wxString& host = wxEmptyString)
0dbfd66d
VZ
89{
90 // we always use INET sockets under non-Unix systems
0ad76eea 91#if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__)
0dbfd66d
VZ
92 // under Unix, if the server name looks like a path, create a AF_UNIX
93 // socket instead of AF_INET one
9a83f860 94 if ( serverName.Find(wxT('/')) != wxNOT_FOUND )
0dbfd66d
VZ
95 {
96 wxUNIXaddress *addr = new wxUNIXaddress;
97 addr->Filename(serverName);
98
99 return addr;
100 }
101#endif // Unix/!Unix
102 {
103 wxIPV4address *addr = new wxIPV4address;
104 addr->Service(serverName);
105 if ( !host.empty() )
106 {
107 addr->Hostname(host);
108 }
109
110 return addr;
111 }
112}
113
cdc59bb6
GRG
114// --------------------------------------------------------------------------
115// wxTCPEventHandler stuff (private class)
116// --------------------------------------------------------------------------
117
118class wxTCPEventHandler : public wxEvtHandler
119{
120public:
01f3d275 121 wxTCPEventHandler() : wxEvtHandler() { }
cdc59bb6 122
7e73fb9c
VZ
123 void Client_OnRequest(wxSocketEvent& event);
124 void Server_OnRequest(wxSocketEvent& event);
cdc59bb6 125
01f3d275 126private:
64be91ed
VZ
127 void HandleDisconnect(wxTCPConnection *connection);
128
7e73fb9c 129 DECLARE_EVENT_TABLE()
c0c133e1 130 wxDECLARE_NO_COPY_CLASS(wxTCPEventHandler);
cdc59bb6
GRG
131};
132
133enum
134{
7e73fb9c
VZ
135 _CLIENT_ONREQUEST_ID = 1000,
136 _SERVER_ONREQUEST_ID
cdc59bb6
GRG
137};
138
01f3d275
VZ
139// --------------------------------------------------------------------------
140// wxTCPEventHandlerModule (private class)
141// --------------------------------------------------------------------------
142
143class wxTCPEventHandlerModule : public wxModule
144{
145public:
146 wxTCPEventHandlerModule() : wxModule() { }
147
148 // get the global wxTCPEventHandler creating it if necessary
149 static wxTCPEventHandler& GetHandler()
150 {
151 if ( !ms_handler )
152 ms_handler = new wxTCPEventHandler;
153
154 return *ms_handler;
155 }
156
157 // as ms_handler is initialized on demand, don't do anything in OnInit()
158 virtual bool OnInit() { return true; }
159 virtual void OnExit() { wxDELETE(ms_handler); }
160
161private:
162 static wxTCPEventHandler *ms_handler;
163
164 DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule)
c0c133e1 165 wxDECLARE_NO_COPY_CLASS(wxTCPEventHandlerModule);
01f3d275
VZ
166};
167
168IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule)
169
170wxTCPEventHandler *wxTCPEventHandlerModule::ms_handler = NULL;
cdc59bb6 171
8aea37a9
VZ
172// --------------------------------------------------------------------------
173// wxIPCSocketStreams
174// --------------------------------------------------------------------------
175
176#define USE_BUFFER
177
178// this class contains the various (related) streams used by wxTCPConnection
179// and also provides a way to read from the socket stream directly
180//
181// for writing to the stream use the IPCOutput class below
182class wxIPCSocketStreams
183{
184public:
185 // ctor initializes all the streams on top of the given socket
186 //
187 // note that we use a bigger than default buffer size which matches the
1f732901 188 // typical Ethernet MTU (minus TCP header overhead)
8aea37a9
VZ
189 wxIPCSocketStreams(wxSocketBase& sock)
190 : m_socketStream(sock),
191#ifdef USE_BUFFER
1f732901 192 m_bufferedOut(m_socketStream, 1448),
8aea37a9
VZ
193#else
194 m_bufferedOut(m_socketStream),
195#endif
196 m_dataIn(m_socketStream),
197 m_dataOut(m_bufferedOut)
198 {
199 }
200
201 // expose the IO methods needed by IPC code (notice that writing is only
202 // done via IPCOutput)
203
204 // flush output
205 void Flush()
206 {
207#ifdef USE_BUFFER
208 m_bufferedOut.Sync();
209#endif
210 }
211
212 // simple wrappers around the functions with the same name in
213 // wxDataInputStream
214 wxUint8 Read8()
215 {
216 Flush();
217 return m_dataIn.Read8();
218 }
219
220 wxUint32 Read32()
221 {
222 Flush();
223 return m_dataIn.Read32();
224 }
225
226 wxString ReadString()
227 {
228 Flush();
229 return m_dataIn.ReadString();
230 }
231
232 // read arbitrary (size-prepended) data
233 //
234 // connection parameter is needed to call its GetBufferAtLeast() method
235 void *ReadData(wxConnectionBase *conn, size_t *size)
236 {
237 Flush();
238
239 wxCHECK_MSG( conn, NULL, "NULL connection parameter" );
240 wxCHECK_MSG( size, NULL, "NULL size parameter" );
241
242 *size = Read32();
243
244 void * const data = conn->GetBufferAtLeast(*size);
245 wxCHECK_MSG( data, NULL, "IPC buffer allocation failed" );
246
247 m_socketStream.Read(data, *size);
248
249 return data;
250 }
251
252 // same as above but for data preceded by the format
253 void *
254 ReadFormatData(wxConnectionBase *conn, wxIPCFormat *format, size_t *size)
255 {
256 wxCHECK_MSG( format, NULL, "NULL format parameter" );
257
258 *format = static_cast<wxIPCFormat>(Read8());
259
260 return ReadData(conn, size);
261 }
262
263
264 // these methods are only used by IPCOutput and not directly
265 wxDataOutputStream& GetDataOut() { return m_dataOut; }
266 wxOutputStream& GetUnformattedOut() { return m_bufferedOut; }
267
268private:
269 // this is the low-level underlying stream using the connection socket
270 wxSocketStream m_socketStream;
271
272 // the buffered stream is used to avoid writing all pieces of an IPC
273 // request to the socket one by one but to instead do it all at once when
274 // we're done with it
275#ifdef USE_BUFFER
276 wxBufferedOutputStream m_bufferedOut;
277#else
278 wxOutputStream& m_bufferedOut;
279#endif
280
281 // finally the data streams are used to be able to write typed data into
282 // the above streams easily
283 wxDataInputStream m_dataIn;
284 wxDataOutputStream m_dataOut;
285
c0c133e1 286 wxDECLARE_NO_COPY_CLASS(wxIPCSocketStreams);
8aea37a9
VZ
287};
288
289namespace
290{
291
292// an object of this class should be instantiated on the stack to write to the
293// underlying socket stream
294//
295// this class is intentionally separated from wxIPCSocketStreams to ensure that
296// Flush() is always called
297class IPCOutput
298{
299public:
300 // construct an object associated with the given streams (which must have
301 // life time greater than ours as we keep a reference to it)
302 IPCOutput(wxIPCSocketStreams *streams)
303 : m_streams(*streams)
304 {
305 wxASSERT_MSG( streams, "NULL streams pointer" );
306 }
307
308 // dtor calls Flush() really sending the IPC data to the network
309 ~IPCOutput() { m_streams.Flush(); }
310
311
312 // write a byte
313 void Write8(wxUint8 i)
314 {
315 m_streams.GetDataOut().Write8(i);
316 }
317
318 // write the reply code and a string
319 void Write(IPCCode code, const wxString& str)
320 {
321 Write8(code);
322 m_streams.GetDataOut().WriteString(str);
323 }
324
325 // write the reply code, a string and a format in this order
326 void Write(IPCCode code, const wxString& str, wxIPCFormat format)
327 {
328 Write(code, str);
329 Write8(format);
330 }
331
332 // write arbitrary data
333 void WriteData(const void *data, size_t size)
334 {
335 m_streams.GetDataOut().Write32(size);
336 m_streams.GetUnformattedOut().Write(data, size);
337 }
338
339
340private:
341 wxIPCSocketStreams& m_streams;
342
c0c133e1 343 wxDECLARE_NO_COPY_CLASS(IPCOutput);
8aea37a9
VZ
344};
345
346} // anonymous namespace
347
cdc59bb6
GRG
348// ==========================================================================
349// implementation
350// ==========================================================================
351
352IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase)
353IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase)
354IMPLEMENT_CLASS(wxTCPConnection, wxConnectionBase)
355
356// --------------------------------------------------------------------------
f4ada568 357// wxTCPClient
cdc59bb6 358// --------------------------------------------------------------------------
f4ada568 359
7e73fb9c
VZ
360wxTCPClient::wxTCPClient()
361 : wxClientBase()
f4ada568
GL
362{
363}
364
365bool wxTCPClient::ValidHost(const wxString& host)
366{
7e73fb9c 367 wxIPV4address addr;
f4ada568 368
7e73fb9c 369 return addr.Hostname(host);
f4ada568
GL
370}
371
8aea37a9
VZ
372wxConnectionBase *wxTCPClient::MakeConnection(const wxString& host,
373 const wxString& serverName,
374 const wxString& topic)
f4ada568 375{
7e73fb9c
VZ
376 wxSockAddress *addr = GetAddressFromName(serverName, host);
377 if ( !addr )
378 return NULL;
0834112f 379
8aea37a9
VZ
380 wxSocketClient * const client = new wxSocketClient(wxSOCKET_WAITALL);
381 wxIPCSocketStreams * const streams = new wxIPCSocketStreams(*client);
f4ada568 382
7e73fb9c
VZ
383 bool ok = client->Connect(*addr);
384 delete addr;
26a25f95 385
7e73fb9c
VZ
386 if ( ok )
387 {
7e73fb9c 388 // Send topic name, and enquire whether this has succeeded
8aea37a9 389 IPCOutput(streams).Write(IPC_CONNECT, topic);
0834112f 390
8aea37a9 391 unsigned char msg = streams->Read8();
0834112f 392
7e73fb9c
VZ
393 // OK! Confirmation.
394 if (msg == IPC_CONNECT)
3adb47a9 395 {
7e73fb9c
VZ
396 wxTCPConnection *
397 connection = (wxTCPConnection *)OnMakeConnection ();
398
399 if (connection)
400 {
345c78ca 401 if (wxDynamicCast(connection, wxTCPConnection))
7e73fb9c
VZ
402 {
403 connection->m_topic = topic;
404 connection->m_sock = client;
8aea37a9 405 connection->m_streams = streams;
01f3d275
VZ
406 client->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
407 _CLIENT_ONREQUEST_ID);
7e73fb9c
VZ
408 client->SetClientData(connection);
409 client->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
410 client->Notify(true);
411 return connection;
412 }
413 else
414 {
415 delete connection;
416 // and fall through to delete everything else
417 }
418 }
3adb47a9 419 }
f4ada568 420 }
0834112f 421
7e73fb9c 422 // Something went wrong, delete everything
8aea37a9 423 delete streams;
7e73fb9c 424 client->Destroy();
3adb47a9 425
7e73fb9c 426 return NULL;
f4ada568
GL
427}
428
429wxConnectionBase *wxTCPClient::OnMakeConnection()
430{
7e73fb9c 431 return new wxTCPConnection();
f4ada568
GL
432}
433
cdc59bb6 434// --------------------------------------------------------------------------
f4ada568 435// wxTCPServer
cdc59bb6 436// --------------------------------------------------------------------------
f4ada568 437
7e73fb9c
VZ
438wxTCPServer::wxTCPServer()
439 : wxServerBase()
f4ada568 440{
7e73fb9c 441 m_server = NULL;
f4ada568
GL
442}
443
f6bcfd97 444bool wxTCPServer::Create(const wxString& serverName)
f4ada568 445{
7e73fb9c
VZ
446 // Destroy previous server, if any
447 if (m_server)
448 {
449 m_server->SetClientData(NULL);
450 m_server->Destroy();
451 m_server = NULL;
452 }
f4ada568 453
7e73fb9c
VZ
454 wxSockAddress *addr = GetAddressFromName(serverName);
455 if ( !addr )
456 return false;
0dbfd66d
VZ
457
458#ifdef __UNIX_LIKE__
7e73fb9c
VZ
459 mode_t umaskOld;
460 if ( addr->Type() == wxSockAddress::UNIX )
461 {
462 // ensure that the file doesn't exist as otherwise calling socket()
463 // would fail
464 int rc = remove(serverName.fn_str());
465 if ( rc < 0 && errno != ENOENT )
466 {
467 delete addr;
468
469 return false;
470 }
471
472 // also set the umask to prevent the others from reading our file
473 umaskOld = umask(077);
474 }
475 else
476 {
477 // unused anyhow but shut down the compiler warnings
478 umaskOld = 0;
479 }
0dbfd66d 480#endif // __UNIX_LIKE__
f4ada568 481
8aea37a9
VZ
482 // Create a socket listening on the specified port (reusing it to allow
483 // restarting the server listening on the same port as was used by the
484 // previous instance of this server)
485 m_server = new wxSocketServer(*addr, wxSOCKET_WAITALL | wxSOCKET_REUSEADDR);
0dbfd66d
VZ
486
487#ifdef __UNIX_LIKE__
7e73fb9c
VZ
488 if ( addr->Type() == wxSockAddress::UNIX )
489 {
490 // restore the umask
491 umask(umaskOld);
492
493 // save the file name to remove it later
494 m_filename = serverName;
495 }
0dbfd66d
VZ
496#endif // __UNIX_LIKE__
497
7e73fb9c 498 delete addr;
f6bcfd97 499
a1b806b9 500 if (!m_server->IsOk())
7e73fb9c
VZ
501 {
502 m_server->Destroy();
503 m_server = NULL;
f6bcfd97 504
7e73fb9c
VZ
505 return false;
506 }
f6bcfd97 507
01f3d275
VZ
508 m_server->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
509 _SERVER_ONREQUEST_ID);
7e73fb9c
VZ
510 m_server->SetClientData(this);
511 m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
512 m_server->Notify(true);
f4ada568 513
7e73fb9c 514 return true;
f4ada568
GL
515}
516
6e31e940 517wxTCPServer::~wxTCPServer()
f4ada568 518{
7e73fb9c 519 if ( m_server )
0dbfd66d
VZ
520 {
521 m_server->SetClientData(NULL);
522 m_server->Destroy();
523 }
524
525#ifdef __UNIX_LIKE__
526 if ( !m_filename.empty() )
527 {
401eb3de 528 if ( remove(m_filename.fn_str()) != 0 )
0dbfd66d 529 {
9a83f860 530 wxLogDebug(wxT("Stale AF_UNIX file '%s' left."), m_filename.c_str());
0dbfd66d
VZ
531 }
532 }
533#endif // __UNIX_LIKE__
f4ada568
GL
534}
535
7e73fb9c
VZ
536wxConnectionBase *
537wxTCPServer::OnAcceptConnection(const wxString& WXUNUSED(topic))
f4ada568 538{
7e73fb9c 539 return new wxTCPConnection();
f4ada568
GL
540}
541
cdc59bb6 542// --------------------------------------------------------------------------
f4ada568 543// wxTCPConnection
cdc59bb6 544// --------------------------------------------------------------------------
f4ada568 545
7e73fb9c 546void wxTCPConnection::Init()
f4ada568 547{
8aea37a9
VZ
548 m_sock = NULL;
549 m_streams = NULL;
f4ada568
GL
550}
551
7e73fb9c 552wxTCPConnection::~wxTCPConnection()
7921cf2b 553{
7e73fb9c 554 Disconnect();
7921cf2b 555
7e73fb9c
VZ
556 if ( m_sock )
557 {
558 m_sock->SetClientData(NULL);
559 m_sock->Destroy();
560 }
561
8aea37a9 562 delete m_streams;
f4ada568
GL
563}
564
cb43b372 565void wxTCPConnection::Compress(bool WXUNUSED(on))
f4ada568 566{
7e73fb9c 567 // TODO
f4ada568
GL
568}
569
570// Calls that CLIENT can make.
7e73fb9c 571bool wxTCPConnection::Disconnect()
f4ada568 572{
7e73fb9c
VZ
573 if ( !GetConnected() )
574 return true;
575
576 // Send the disconnect message to the peer.
8aea37a9 577 IPCOutput(m_streams).Write8(IPC_DISCONNECT);
82c91ef5 578
7e73fb9c
VZ
579 if ( m_sock )
580 {
581 m_sock->Notify(false);
582 m_sock->Close();
583 }
82c91ef5 584
7e73fb9c 585 SetConnected(false);
f4ada568 586
7e73fb9c 587 return true;
f4ada568
GL
588}
589
7e73fb9c
VZ
590bool wxTCPConnection::DoExecute(const void *data,
591 size_t size,
592 wxIPCFormat format)
f4ada568 593{
7e73fb9c
VZ
594 if ( !m_sock->IsConnected() )
595 return false;
f4ada568 596
7e73fb9c 597 // Prepare EXECUTE message
8aea37a9
VZ
598 IPCOutput out(m_streams);
599 out.Write8(IPC_EXECUTE);
600 out.Write8(format);
0834112f 601
8aea37a9 602 out.WriteData(data, size);
f4ada568 603
7e73fb9c 604 return true;
f4ada568
GL
605}
606
7e73fb9c
VZ
607const void *wxTCPConnection::Request(const wxString& item,
608 size_t *size,
609 wxIPCFormat format)
f4ada568 610{
7e73fb9c
VZ
611 if ( !m_sock->IsConnected() )
612 return NULL;
f4ada568 613
8aea37a9 614 IPCOutput(m_streams).Write(IPC_REQUEST, item, format);
f4ada568 615
d730bd8a
VZ
616 const int ret = m_streams->Read8();
617 if ( ret != IPC_REQUEST_REPLY )
7e73fb9c 618 return NULL;
f4ada568 619
ea22bf81
VZ
620 // ReadData() needs a non-NULL size pointer but the client code can call us
621 // with NULL pointer (this makes sense if it knows that it always works
622 // with NUL-terminated strings)
623 size_t sizeFallback;
624 return m_streams->ReadData(this, size ? size : &sizeFallback);
f4ada568
GL
625}
626
7e73fb9c
VZ
627bool wxTCPConnection::DoPoke(const wxString& item,
628 const void *data,
629 size_t size,
630 wxIPCFormat format)
f4ada568 631{
7e73fb9c
VZ
632 if ( !m_sock->IsConnected() )
633 return false;
f4ada568 634
8aea37a9
VZ
635 IPCOutput out(m_streams);
636 out.Write(IPC_POKE, item, format);
637 out.WriteData(data, size);
f4ada568 638
7e73fb9c 639 return true;
f4ada568
GL
640}
641
8aea37a9 642bool wxTCPConnection::StartAdvise(const wxString& item)
f4ada568 643{
7e73fb9c
VZ
644 if ( !m_sock->IsConnected() )
645 return false;
f4ada568 646
8aea37a9 647 IPCOutput(m_streams).Write(IPC_ADVISE_START, item);
f4ada568 648
d730bd8a
VZ
649 const int ret = m_streams->Read8();
650
651 return ret == IPC_ADVISE_START;
f4ada568
GL
652}
653
654bool wxTCPConnection::StopAdvise (const wxString& item)
655{
7e73fb9c
VZ
656 if ( !m_sock->IsConnected() )
657 return false;
f4ada568 658
8aea37a9 659 IPCOutput(m_streams).Write(IPC_ADVISE_STOP, item);
f4ada568 660
d730bd8a 661 const int ret = m_streams->Read8();
f4ada568 662
d730bd8a 663 return ret == IPC_ADVISE_STOP;
f4ada568
GL
664}
665
666// Calls that SERVER can make
7e73fb9c
VZ
667bool wxTCPConnection::DoAdvise(const wxString& item,
668 const void *data,
669 size_t size,
670 wxIPCFormat format)
f4ada568 671{
7e73fb9c
VZ
672 if ( !m_sock->IsConnected() )
673 return false;
f4ada568 674
8aea37a9
VZ
675 IPCOutput out(m_streams);
676 out.Write(IPC_ADVISE, item, format);
677 out.WriteData(data, size);
f4ada568 678
7e73fb9c 679 return true;
f4ada568
GL
680}
681
cdc59bb6
GRG
682// --------------------------------------------------------------------------
683// wxTCPEventHandler (private class)
684// --------------------------------------------------------------------------
685
686BEGIN_EVENT_TABLE(wxTCPEventHandler, wxEvtHandler)
7e73fb9c
VZ
687 EVT_SOCKET(_CLIENT_ONREQUEST_ID, wxTCPEventHandler::Client_OnRequest)
688 EVT_SOCKET(_SERVER_ONREQUEST_ID, wxTCPEventHandler::Server_OnRequest)
cdc59bb6
GRG
689END_EVENT_TABLE()
690
64be91ed
VZ
691void wxTCPEventHandler::HandleDisconnect(wxTCPConnection *connection)
692{
693 // connection was closed (either gracefully or not): destroy everything
694 connection->m_sock->Notify(false);
695 connection->m_sock->Close();
696
3185abc2
VZ
697 // don't leave references to this soon-to-be-dangling connection in the
698 // socket as it won't be destroyed immediately as its destruction will be
699 // delayed in case there are more events pending for it
700 connection->m_sock->SetClientData(NULL);
701
64be91ed
VZ
702 connection->SetConnected(false);
703 connection->OnDisconnect();
704}
705
cdc59bb6 706void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
f4ada568 707{
7e73fb9c
VZ
708 wxSocketBase *sock = event.GetSocket();
709 if (!sock)
64be91ed 710 return;
f4ada568 711
7e73fb9c 712 wxSocketNotify evt = event.GetSocketEvent();
64be91ed
VZ
713 wxTCPConnection * const
714 connection = static_cast<wxTCPConnection *>(sock->GetClientData());
f4ada568 715
7e73fb9c
VZ
716 // This socket is being deleted; skip this event
717 if (!connection)
718 return;
f4ada568 719
64be91ed 720 if ( evt == wxSOCKET_LOST )
7e73fb9c 721 {
64be91ed 722 HandleDisconnect(connection);
7e73fb9c
VZ
723 return;
724 }
f4ada568 725
7e73fb9c 726 // Receive message number.
8aea37a9 727 wxIPCSocketStreams * const streams = connection->m_streams;
f4ada568 728
8aea37a9
VZ
729 const wxString topic = connection->m_topic;
730 wxString item;
731
428dca1c
VZ
732 bool error = false;
733
22a9029e
VZ
734 const int msg = streams->Read8();
735 switch ( msg )
0834112f 736 {
7e73fb9c
VZ
737 case IPC_EXECUTE:
738 {
7e73fb9c 739 wxIPCFormat format;
428dca1c 740 size_t size wxDUMMY_INITIALIZE(0);
8aea37a9
VZ
741 void * const
742 data = streams->ReadFormatData(connection, &format, &size);
428dca1c
VZ
743 if ( data )
744 connection->OnExecute(topic, data, size, format);
745 else
746 error = true;
7e73fb9c 747 }
8aea37a9
VZ
748 break;
749
7e73fb9c
VZ
750 case IPC_ADVISE:
751 {
8aea37a9 752 item = streams->ReadString();
7e73fb9c 753
8aea37a9 754 wxIPCFormat format;
428dca1c 755 size_t size wxDUMMY_INITIALIZE(0);
8aea37a9
VZ
756 void * const
757 data = streams->ReadFormatData(connection, &format, &size);
7e73fb9c 758
428dca1c
VZ
759 if ( data )
760 connection->OnAdvise(topic, item, data, size, format);
761 else
762 error = true;
7e73fb9c 763 }
8aea37a9
VZ
764 break;
765
7e73fb9c
VZ
766 case IPC_ADVISE_START:
767 {
8aea37a9 768 item = streams->ReadString();
7e73fb9c 769
8aea37a9
VZ
770 IPCOutput(streams).Write8(connection->OnStartAdvise(topic, item)
771 ? IPC_ADVISE_START
772 : IPC_FAIL);
7e73fb9c 773 }
8aea37a9
VZ
774 break;
775
7e73fb9c
VZ
776 case IPC_ADVISE_STOP:
777 {
8aea37a9 778 item = streams->ReadString();
7e73fb9c 779
8aea37a9
VZ
780 IPCOutput(streams).Write8(connection->OnStopAdvise(topic, item)
781 ? IPC_ADVISE_STOP
782 : IPC_FAIL);
7e73fb9c 783 }
8aea37a9
VZ
784 break;
785
7e73fb9c
VZ
786 case IPC_POKE:
787 {
8aea37a9
VZ
788 item = streams->ReadString();
789 wxIPCFormat format = (wxIPCFormat)streams->Read8();
7e73fb9c 790
428dca1c 791 size_t size wxDUMMY_INITIALIZE(0);
8aea37a9 792 void * const data = streams->ReadData(connection, &size);
7e73fb9c 793
428dca1c
VZ
794 if ( data )
795 connection->OnPoke(topic, item, data, size, format);
796 else
797 error = true;
7e73fb9c 798 }
8aea37a9
VZ
799 break;
800
7e73fb9c
VZ
801 case IPC_REQUEST:
802 {
8aea37a9 803 item = streams->ReadString();
7e73fb9c 804
8aea37a9 805 wxIPCFormat format = (wxIPCFormat)streams->Read8();
7e73fb9c
VZ
806
807 size_t user_size = wxNO_LEN;
8aea37a9 808 const void *user_data = connection->OnRequest(topic,
7e73fb9c
VZ
809 item,
810 &user_size,
811 format);
812
8aea37a9 813 if ( !user_data )
7e73fb9c 814 {
8aea37a9
VZ
815 IPCOutput(streams).Write8(IPC_FAIL);
816 break;
817 }
818
819 IPCOutput out(streams);
820 out.Write8(IPC_REQUEST_REPLY);
7e73fb9c 821
8aea37a9
VZ
822 if ( user_size == wxNO_LEN )
823 {
824 switch ( format )
7e73fb9c 825 {
8aea37a9
VZ
826 case wxIPC_TEXT:
827 case wxIPC_UTF8TEXT:
828 user_size = strlen((const char *)user_data) + 1; // includes final NUL
829 break;
830 case wxIPC_UNICODETEXT:
831 user_size = (wcslen((const wchar_t *)user_data) + 1) * sizeof(wchar_t); // includes final NUL
832 break;
833 default:
834 user_size = 0;
7e73fb9c 835 }
7e73fb9c 836 }
7e73fb9c 837
8aea37a9 838 out.WriteData(user_data, user_size);
7e73fb9c 839 }
8aea37a9
VZ
840 break;
841
7e73fb9c 842 case IPC_DISCONNECT:
64be91ed 843 HandleDisconnect(connection);
8aea37a9
VZ
844 break;
845
d730bd8a
VZ
846 case IPC_FAIL:
847 wxLogDebug("Unexpected IPC_FAIL received");
848 error = true;
849 break;
850
7e73fb9c 851 default:
8aea37a9 852 wxLogDebug("Unknown message code %d received.", msg);
428dca1c 853 error = true;
50c549b9 854 break;
0834112f 855 }
428dca1c
VZ
856
857 if ( error )
858 IPCOutput(streams).Write8(IPC_FAIL);
f4ada568
GL
859}
860
cdc59bb6 861void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
f4ada568 862{
7e73fb9c
VZ
863 wxSocketServer *server = (wxSocketServer *) event.GetSocket();
864 if (!server)
64be91ed 865 return;
7e73fb9c 866 wxTCPServer *ipcserv = (wxTCPServer *) server->GetClientData();
f4ada568 867
7e73fb9c
VZ
868 // This socket is being deleted; skip this event
869 if (!ipcserv)
870 return;
871
872 if (event.GetSocketEvent() != wxSOCKET_CONNECTION)
873 return;
f4ada568 874
7e73fb9c
VZ
875 // Accept the connection, getting a new socket
876 wxSocketBase *sock = server->Accept();
877 if (!sock)
64be91ed 878 return;
a1b806b9 879 if (!sock->IsOk())
7e73fb9c
VZ
880 {
881 sock->Destroy();
882 return;
883 }
f4ada568 884
8aea37a9 885 wxIPCSocketStreams *streams = new wxIPCSocketStreams(*sock);
3adb47a9 886
0834112f 887 {
8aea37a9 888 IPCOutput out(streams);
7e73fb9c 889
8aea37a9
VZ
890 const int msg = streams->Read8();
891 if ( msg == IPC_CONNECT )
7e73fb9c 892 {
8aea37a9
VZ
893 const wxString topic = streams->ReadString();
894
895 wxTCPConnection *new_connection =
896 (wxTCPConnection *)ipcserv->OnAcceptConnection (topic);
897
898 if (new_connection)
7e73fb9c 899 {
345c78ca 900 if (wxDynamicCast(new_connection, wxTCPConnection))
8aea37a9
VZ
901 {
902 // Acknowledge success
903 out.Write8(IPC_CONNECT);
904
905 new_connection->m_sock = sock;
906 new_connection->m_streams = streams;
907 new_connection->m_topic = topic;
01f3d275
VZ
908 sock->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
909 _CLIENT_ONREQUEST_ID);
8aea37a9
VZ
910 sock->SetClientData(new_connection);
911 sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
912 sock->Notify(true);
913 return;
914 }
915 else
916 {
917 delete new_connection;
918 // and fall through to delete everything else
919 }
7e73fb9c
VZ
920 }
921 }
3adb47a9 922
8aea37a9
VZ
923 // Something went wrong, send failure message and delete everything
924 out.Write8(IPC_FAIL);
925 } // IPCOutput object is destroyed here, before destroying stream
3adb47a9 926
8aea37a9 927 delete streams;
7e73fb9c 928 sock->Destroy();
f4ada568 929}
35a4dab7 930
7e73fb9c 931#endif // wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS