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