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