]> git.saurik.com Git - wxWidgets.git/blame - src/common/sckipc.cpp
Ensure that component levels map is initialized before it's used (closes #10990).
[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:
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
7e73fb9c
VZ
501 if (!m_server->Ok())
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
VZ
530 {
531 wxLogDebug(_T("Stale AF_UNIX file '%s' left."), m_filename.c_str());
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
698 connection->SetConnected(false);
699 connection->OnDisconnect();
700}
701
cdc59bb6 702void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
f4ada568 703{
7e73fb9c
VZ
704 wxSocketBase *sock = event.GetSocket();
705 if (!sock)
64be91ed 706 return;
f4ada568 707
7e73fb9c 708 wxSocketNotify evt = event.GetSocketEvent();
64be91ed
VZ
709 wxTCPConnection * const
710 connection = static_cast<wxTCPConnection *>(sock->GetClientData());
f4ada568 711
7e73fb9c
VZ
712 // This socket is being deleted; skip this event
713 if (!connection)
714 return;
f4ada568 715
64be91ed 716 if ( evt == wxSOCKET_LOST )
7e73fb9c 717 {
64be91ed 718 HandleDisconnect(connection);
7e73fb9c
VZ
719 return;
720 }
f4ada568 721
7e73fb9c 722 // Receive message number.
8aea37a9 723 wxIPCSocketStreams * const streams = connection->m_streams;
f4ada568 724
8aea37a9
VZ
725 const wxString topic = connection->m_topic;
726 wxString item;
727
428dca1c
VZ
728 bool error = false;
729
22a9029e
VZ
730 const int msg = streams->Read8();
731 switch ( msg )
0834112f 732 {
7e73fb9c
VZ
733 case IPC_EXECUTE:
734 {
7e73fb9c 735 wxIPCFormat format;
428dca1c 736 size_t size wxDUMMY_INITIALIZE(0);
8aea37a9
VZ
737 void * const
738 data = streams->ReadFormatData(connection, &format, &size);
428dca1c
VZ
739 if ( data )
740 connection->OnExecute(topic, data, size, format);
741 else
742 error = true;
7e73fb9c 743 }
8aea37a9
VZ
744 break;
745
7e73fb9c
VZ
746 case IPC_ADVISE:
747 {
8aea37a9 748 item = streams->ReadString();
7e73fb9c 749
8aea37a9 750 wxIPCFormat format;
428dca1c 751 size_t size wxDUMMY_INITIALIZE(0);
8aea37a9
VZ
752 void * const
753 data = streams->ReadFormatData(connection, &format, &size);
7e73fb9c 754
428dca1c
VZ
755 if ( data )
756 connection->OnAdvise(topic, item, data, size, format);
757 else
758 error = true;
7e73fb9c 759 }
8aea37a9
VZ
760 break;
761
7e73fb9c
VZ
762 case IPC_ADVISE_START:
763 {
8aea37a9 764 item = streams->ReadString();
7e73fb9c 765
8aea37a9
VZ
766 IPCOutput(streams).Write8(connection->OnStartAdvise(topic, item)
767 ? IPC_ADVISE_START
768 : IPC_FAIL);
7e73fb9c 769 }
8aea37a9
VZ
770 break;
771
7e73fb9c
VZ
772 case IPC_ADVISE_STOP:
773 {
8aea37a9 774 item = streams->ReadString();
7e73fb9c 775
8aea37a9
VZ
776 IPCOutput(streams).Write8(connection->OnStopAdvise(topic, item)
777 ? IPC_ADVISE_STOP
778 : IPC_FAIL);
7e73fb9c 779 }
8aea37a9
VZ
780 break;
781
7e73fb9c
VZ
782 case IPC_POKE:
783 {
8aea37a9
VZ
784 item = streams->ReadString();
785 wxIPCFormat format = (wxIPCFormat)streams->Read8();
7e73fb9c 786
428dca1c 787 size_t size wxDUMMY_INITIALIZE(0);
8aea37a9 788 void * const data = streams->ReadData(connection, &size);
7e73fb9c 789
428dca1c
VZ
790 if ( data )
791 connection->OnPoke(topic, item, data, size, format);
792 else
793 error = true;
7e73fb9c 794 }
8aea37a9
VZ
795 break;
796
7e73fb9c
VZ
797 case IPC_REQUEST:
798 {
8aea37a9 799 item = streams->ReadString();
7e73fb9c 800
8aea37a9 801 wxIPCFormat format = (wxIPCFormat)streams->Read8();
7e73fb9c
VZ
802
803 size_t user_size = wxNO_LEN;
8aea37a9 804 const void *user_data = connection->OnRequest(topic,
7e73fb9c
VZ
805 item,
806 &user_size,
807 format);
808
8aea37a9 809 if ( !user_data )
7e73fb9c 810 {
8aea37a9
VZ
811 IPCOutput(streams).Write8(IPC_FAIL);
812 break;
813 }
814
815 IPCOutput out(streams);
816 out.Write8(IPC_REQUEST_REPLY);
7e73fb9c 817
8aea37a9
VZ
818 if ( user_size == wxNO_LEN )
819 {
820 switch ( format )
7e73fb9c 821 {
8aea37a9
VZ
822 case wxIPC_TEXT:
823 case wxIPC_UTF8TEXT:
824 user_size = strlen((const char *)user_data) + 1; // includes final NUL
825 break;
826 case wxIPC_UNICODETEXT:
827 user_size = (wcslen((const wchar_t *)user_data) + 1) * sizeof(wchar_t); // includes final NUL
828 break;
829 default:
830 user_size = 0;
7e73fb9c 831 }
7e73fb9c 832 }
7e73fb9c 833
8aea37a9 834 out.WriteData(user_data, user_size);
7e73fb9c 835 }
8aea37a9
VZ
836 break;
837
7e73fb9c 838 case IPC_DISCONNECT:
64be91ed 839 HandleDisconnect(connection);
8aea37a9
VZ
840 break;
841
d730bd8a
VZ
842 case IPC_FAIL:
843 wxLogDebug("Unexpected IPC_FAIL received");
844 error = true;
845 break;
846
7e73fb9c 847 default:
8aea37a9 848 wxLogDebug("Unknown message code %d received.", msg);
428dca1c 849 error = true;
50c549b9 850 break;
0834112f 851 }
428dca1c
VZ
852
853 if ( error )
854 IPCOutput(streams).Write8(IPC_FAIL);
f4ada568
GL
855}
856
cdc59bb6 857void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
f4ada568 858{
7e73fb9c
VZ
859 wxSocketServer *server = (wxSocketServer *) event.GetSocket();
860 if (!server)
64be91ed 861 return;
7e73fb9c 862 wxTCPServer *ipcserv = (wxTCPServer *) server->GetClientData();
f4ada568 863
7e73fb9c
VZ
864 // This socket is being deleted; skip this event
865 if (!ipcserv)
866 return;
867
868 if (event.GetSocketEvent() != wxSOCKET_CONNECTION)
869 return;
f4ada568 870
7e73fb9c
VZ
871 // Accept the connection, getting a new socket
872 wxSocketBase *sock = server->Accept();
873 if (!sock)
64be91ed 874 return;
7e73fb9c
VZ
875 if (!sock->Ok())
876 {
877 sock->Destroy();
878 return;
879 }
f4ada568 880
8aea37a9 881 wxIPCSocketStreams *streams = new wxIPCSocketStreams(*sock);
3adb47a9 882
0834112f 883 {
8aea37a9 884 IPCOutput out(streams);
7e73fb9c 885
8aea37a9
VZ
886 const int msg = streams->Read8();
887 if ( msg == IPC_CONNECT )
7e73fb9c 888 {
8aea37a9
VZ
889 const wxString topic = streams->ReadString();
890
891 wxTCPConnection *new_connection =
892 (wxTCPConnection *)ipcserv->OnAcceptConnection (topic);
893
894 if (new_connection)
7e73fb9c 895 {
8aea37a9
VZ
896 if (new_connection->IsKindOf(CLASSINFO(wxTCPConnection)))
897 {
898 // Acknowledge success
899 out.Write8(IPC_CONNECT);
900
901 new_connection->m_sock = sock;
902 new_connection->m_streams = streams;
903 new_connection->m_topic = topic;
01f3d275
VZ
904 sock->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
905 _CLIENT_ONREQUEST_ID);
8aea37a9
VZ
906 sock->SetClientData(new_connection);
907 sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
908 sock->Notify(true);
909 return;
910 }
911 else
912 {
913 delete new_connection;
914 // and fall through to delete everything else
915 }
7e73fb9c
VZ
916 }
917 }
3adb47a9 918
8aea37a9
VZ
919 // Something went wrong, send failure message and delete everything
920 out.Write8(IPC_FAIL);
921 } // IPCOutput object is destroyed here, before destroying stream
3adb47a9 922
8aea37a9 923 delete streams;
7e73fb9c 924 sock->Destroy();
f4ada568 925}
35a4dab7 926
7e73fb9c 927#endif // wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS