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