Allow handling EVT_UPDATE_UI for wxID_UNDO/REDO at wxDocument level.
[wxWidgets.git] / src / common / sckipc.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/sckipc.cpp
3 // Purpose: Interprocess communication implementation (wxSocket version)
4 // Author: Julian Smart
5 // Modified by: Guilhem Lavaux (big rewrite) May 1997, 1998
6 // Guillermo Rodriguez (updated for wxSocket v2) Jan 2000
7 // (callbacks deprecated) Mar 2000
8 // Vadim Zeitlin (added support for Unix sockets) Apr 2002
9 // (use buffering, many fixes/cleanup) Oct 2008
10 // Created: 1993
11 // RCS-ID: $Id$
12 // Copyright: (c) Julian Smart 1993
13 // (c) Guilhem Lavaux 1997, 1998
14 // (c) 2000 Guillermo Rodriguez <guille@iies.es>
15 // Licence: wxWindows licence
16 /////////////////////////////////////////////////////////////////////////////
17
18 // ==========================================================================
19 // declarations
20 // ==========================================================================
21
22 // --------------------------------------------------------------------------
23 // headers
24 // --------------------------------------------------------------------------
25
26 // For compilers that support precompilation, includes "wx.h".
27 #include "wx/wxprec.h"
28
29 #ifdef __BORLANDC__
30 #pragma hdrstop
31 #endif
32
33 #if wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS
34
35 #include "wx/sckipc.h"
36
37 #ifndef WX_PRECOMP
38 #include "wx/log.h"
39 #include "wx/event.h"
40 #include "wx/module.h"
41 #endif
42
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <errno.h>
46
47 #include "wx/socket.h"
48
49 // --------------------------------------------------------------------------
50 // macros and constants
51 // --------------------------------------------------------------------------
52
53 namespace
54 {
55
56 // Message codes (don't change them to avoid breaking the existing code using
57 // wxIPC protocol!)
58 enum IPCCode
59 {
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
72 };
73
74 } // anonymous namespace
75
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
87 static wxSockAddress *
88 GetAddressFromName(const wxString& serverName,
89 const wxString& host = wxEmptyString)
90 {
91 // we always use INET sockets under non-Unix systems
92 #if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__)
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(wxT('/')) != 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
115 // --------------------------------------------------------------------------
116 // wxTCPEventHandler stuff (private class)
117 // --------------------------------------------------------------------------
118
119 class wxTCPEventHandler : public wxEvtHandler
120 {
121 public:
122 wxTCPEventHandler() : wxEvtHandler() { }
123
124 void Client_OnRequest(wxSocketEvent& event);
125 void Server_OnRequest(wxSocketEvent& event);
126
127 private:
128 void HandleDisconnect(wxTCPConnection *connection);
129
130 DECLARE_EVENT_TABLE()
131 wxDECLARE_NO_COPY_CLASS(wxTCPEventHandler);
132 };
133
134 enum
135 {
136 _CLIENT_ONREQUEST_ID = 1000,
137 _SERVER_ONREQUEST_ID
138 };
139
140 // --------------------------------------------------------------------------
141 // wxTCPEventHandlerModule (private class)
142 // --------------------------------------------------------------------------
143
144 class wxTCPEventHandlerModule : public wxModule
145 {
146 public:
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
162 private:
163 static wxTCPEventHandler *ms_handler;
164
165 DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule)
166 wxDECLARE_NO_COPY_CLASS(wxTCPEventHandlerModule);
167 };
168
169 IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule)
170
171 wxTCPEventHandler *wxTCPEventHandlerModule::ms_handler = NULL;
172
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
183 class wxIPCSocketStreams
184 {
185 public:
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
189 // typical Ethernet MTU (minus TCP header overhead)
190 wxIPCSocketStreams(wxSocketBase& sock)
191 : m_socketStream(sock),
192 #ifdef USE_BUFFER
193 m_bufferedOut(m_socketStream, 1448),
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
269 private:
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
287 wxDECLARE_NO_COPY_CLASS(wxIPCSocketStreams);
288 };
289
290 namespace
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
298 class IPCOutput
299 {
300 public:
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
341 private:
342 wxIPCSocketStreams& m_streams;
343
344 wxDECLARE_NO_COPY_CLASS(IPCOutput);
345 };
346
347 } // anonymous namespace
348
349 // ==========================================================================
350 // implementation
351 // ==========================================================================
352
353 IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase)
354 IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase)
355 IMPLEMENT_CLASS(wxTCPConnection, wxConnectionBase)
356
357 // --------------------------------------------------------------------------
358 // wxTCPClient
359 // --------------------------------------------------------------------------
360
361 wxTCPClient::wxTCPClient()
362 : wxClientBase()
363 {
364 }
365
366 bool wxTCPClient::ValidHost(const wxString& host)
367 {
368 wxIPV4address addr;
369
370 return addr.Hostname(host);
371 }
372
373 wxConnectionBase *wxTCPClient::MakeConnection(const wxString& host,
374 const wxString& serverName,
375 const wxString& topic)
376 {
377 wxSockAddress *addr = GetAddressFromName(serverName, host);
378 if ( !addr )
379 return NULL;
380
381 wxSocketClient * const client = new wxSocketClient(wxSOCKET_WAITALL);
382 wxIPCSocketStreams * const streams = new wxIPCSocketStreams(*client);
383
384 bool ok = client->Connect(*addr);
385 delete addr;
386
387 if ( ok )
388 {
389 // Send topic name, and enquire whether this has succeeded
390 IPCOutput(streams).Write(IPC_CONNECT, topic);
391
392 unsigned char msg = streams->Read8();
393
394 // OK! Confirmation.
395 if (msg == IPC_CONNECT)
396 {
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;
406 connection->m_streams = streams;
407 client->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
408 _CLIENT_ONREQUEST_ID);
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 }
420 }
421 }
422
423 // Something went wrong, delete everything
424 delete streams;
425 client->Destroy();
426
427 return NULL;
428 }
429
430 wxConnectionBase *wxTCPClient::OnMakeConnection()
431 {
432 return new wxTCPConnection();
433 }
434
435 // --------------------------------------------------------------------------
436 // wxTCPServer
437 // --------------------------------------------------------------------------
438
439 wxTCPServer::wxTCPServer()
440 : wxServerBase()
441 {
442 m_server = NULL;
443 }
444
445 bool wxTCPServer::Create(const wxString& serverName)
446 {
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 }
454
455 wxSockAddress *addr = GetAddressFromName(serverName);
456 if ( !addr )
457 return false;
458
459 #ifdef __UNIX_LIKE__
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 }
481 #endif // __UNIX_LIKE__
482
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);
487
488 #ifdef __UNIX_LIKE__
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 }
497 #endif // __UNIX_LIKE__
498
499 delete addr;
500
501 if (!m_server->IsOk())
502 {
503 m_server->Destroy();
504 m_server = NULL;
505
506 return false;
507 }
508
509 m_server->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
510 _SERVER_ONREQUEST_ID);
511 m_server->SetClientData(this);
512 m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
513 m_server->Notify(true);
514
515 return true;
516 }
517
518 wxTCPServer::~wxTCPServer()
519 {
520 if ( m_server )
521 {
522 m_server->SetClientData(NULL);
523 m_server->Destroy();
524 }
525
526 #ifdef __UNIX_LIKE__
527 if ( !m_filename.empty() )
528 {
529 if ( remove(m_filename.fn_str()) != 0 )
530 {
531 wxLogDebug(wxT("Stale AF_UNIX file '%s' left."), m_filename.c_str());
532 }
533 }
534 #endif // __UNIX_LIKE__
535 }
536
537 wxConnectionBase *
538 wxTCPServer::OnAcceptConnection(const wxString& WXUNUSED(topic))
539 {
540 return new wxTCPConnection();
541 }
542
543 // --------------------------------------------------------------------------
544 // wxTCPConnection
545 // --------------------------------------------------------------------------
546
547 void wxTCPConnection::Init()
548 {
549 m_sock = NULL;
550 m_streams = NULL;
551 }
552
553 wxTCPConnection::~wxTCPConnection()
554 {
555 Disconnect();
556
557 if ( m_sock )
558 {
559 m_sock->SetClientData(NULL);
560 m_sock->Destroy();
561 }
562
563 delete m_streams;
564 }
565
566 void wxTCPConnection::Compress(bool WXUNUSED(on))
567 {
568 // TODO
569 }
570
571 // Calls that CLIENT can make.
572 bool wxTCPConnection::Disconnect()
573 {
574 if ( !GetConnected() )
575 return true;
576
577 // Send the disconnect message to the peer.
578 IPCOutput(m_streams).Write8(IPC_DISCONNECT);
579
580 if ( m_sock )
581 {
582 m_sock->Notify(false);
583 m_sock->Close();
584 }
585
586 SetConnected(false);
587
588 return true;
589 }
590
591 bool wxTCPConnection::DoExecute(const void *data,
592 size_t size,
593 wxIPCFormat format)
594 {
595 if ( !m_sock->IsConnected() )
596 return false;
597
598 // Prepare EXECUTE message
599 IPCOutput out(m_streams);
600 out.Write8(IPC_EXECUTE);
601 out.Write8(format);
602
603 out.WriteData(data, size);
604
605 return true;
606 }
607
608 const void *wxTCPConnection::Request(const wxString& item,
609 size_t *size,
610 wxIPCFormat format)
611 {
612 if ( !m_sock->IsConnected() )
613 return NULL;
614
615 IPCOutput(m_streams).Write(IPC_REQUEST, item, format);
616
617 const int ret = m_streams->Read8();
618 if ( ret != IPC_REQUEST_REPLY )
619 return NULL;
620
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);
626 }
627
628 bool wxTCPConnection::DoPoke(const wxString& item,
629 const void *data,
630 size_t size,
631 wxIPCFormat format)
632 {
633 if ( !m_sock->IsConnected() )
634 return false;
635
636 IPCOutput out(m_streams);
637 out.Write(IPC_POKE, item, format);
638 out.WriteData(data, size);
639
640 return true;
641 }
642
643 bool wxTCPConnection::StartAdvise(const wxString& item)
644 {
645 if ( !m_sock->IsConnected() )
646 return false;
647
648 IPCOutput(m_streams).Write(IPC_ADVISE_START, item);
649
650 const int ret = m_streams->Read8();
651
652 return ret == IPC_ADVISE_START;
653 }
654
655 bool wxTCPConnection::StopAdvise (const wxString& item)
656 {
657 if ( !m_sock->IsConnected() )
658 return false;
659
660 IPCOutput(m_streams).Write(IPC_ADVISE_STOP, item);
661
662 const int ret = m_streams->Read8();
663
664 return ret == IPC_ADVISE_STOP;
665 }
666
667 // Calls that SERVER can make
668 bool wxTCPConnection::DoAdvise(const wxString& item,
669 const void *data,
670 size_t size,
671 wxIPCFormat format)
672 {
673 if ( !m_sock->IsConnected() )
674 return false;
675
676 IPCOutput out(m_streams);
677 out.Write(IPC_ADVISE, item, format);
678 out.WriteData(data, size);
679
680 return true;
681 }
682
683 // --------------------------------------------------------------------------
684 // wxTCPEventHandler (private class)
685 // --------------------------------------------------------------------------
686
687 BEGIN_EVENT_TABLE(wxTCPEventHandler, wxEvtHandler)
688 EVT_SOCKET(_CLIENT_ONREQUEST_ID, wxTCPEventHandler::Client_OnRequest)
689 EVT_SOCKET(_SERVER_ONREQUEST_ID, wxTCPEventHandler::Server_OnRequest)
690 END_EVENT_TABLE()
691
692 void 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 // 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
703 connection->SetConnected(false);
704 connection->OnDisconnect();
705 }
706
707 void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
708 {
709 wxSocketBase *sock = event.GetSocket();
710 if (!sock)
711 return;
712
713 wxSocketNotify evt = event.GetSocketEvent();
714 wxTCPConnection * const
715 connection = static_cast<wxTCPConnection *>(sock->GetClientData());
716
717 // This socket is being deleted; skip this event
718 if (!connection)
719 return;
720
721 if ( evt == wxSOCKET_LOST )
722 {
723 HandleDisconnect(connection);
724 return;
725 }
726
727 // Receive message number.
728 wxIPCSocketStreams * const streams = connection->m_streams;
729
730 const wxString topic = connection->m_topic;
731 wxString item;
732
733 bool error = false;
734
735 const int msg = streams->Read8();
736 switch ( msg )
737 {
738 case IPC_EXECUTE:
739 {
740 wxIPCFormat format;
741 size_t size wxDUMMY_INITIALIZE(0);
742 void * const
743 data = streams->ReadFormatData(connection, &format, &size);
744 if ( data )
745 connection->OnExecute(topic, data, size, format);
746 else
747 error = true;
748 }
749 break;
750
751 case IPC_ADVISE:
752 {
753 item = streams->ReadString();
754
755 wxIPCFormat format;
756 size_t size wxDUMMY_INITIALIZE(0);
757 void * const
758 data = streams->ReadFormatData(connection, &format, &size);
759
760 if ( data )
761 connection->OnAdvise(topic, item, data, size, format);
762 else
763 error = true;
764 }
765 break;
766
767 case IPC_ADVISE_START:
768 {
769 item = streams->ReadString();
770
771 IPCOutput(streams).Write8(connection->OnStartAdvise(topic, item)
772 ? IPC_ADVISE_START
773 : IPC_FAIL);
774 }
775 break;
776
777 case IPC_ADVISE_STOP:
778 {
779 item = streams->ReadString();
780
781 IPCOutput(streams).Write8(connection->OnStopAdvise(topic, item)
782 ? IPC_ADVISE_STOP
783 : IPC_FAIL);
784 }
785 break;
786
787 case IPC_POKE:
788 {
789 item = streams->ReadString();
790 wxIPCFormat format = (wxIPCFormat)streams->Read8();
791
792 size_t size wxDUMMY_INITIALIZE(0);
793 void * const data = streams->ReadData(connection, &size);
794
795 if ( data )
796 connection->OnPoke(topic, item, data, size, format);
797 else
798 error = true;
799 }
800 break;
801
802 case IPC_REQUEST:
803 {
804 item = streams->ReadString();
805
806 wxIPCFormat format = (wxIPCFormat)streams->Read8();
807
808 size_t user_size = wxNO_LEN;
809 const void *user_data = connection->OnRequest(topic,
810 item,
811 &user_size,
812 format);
813
814 if ( !user_data )
815 {
816 IPCOutput(streams).Write8(IPC_FAIL);
817 break;
818 }
819
820 IPCOutput out(streams);
821 out.Write8(IPC_REQUEST_REPLY);
822
823 if ( user_size == wxNO_LEN )
824 {
825 switch ( format )
826 {
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;
836 }
837 }
838
839 out.WriteData(user_data, user_size);
840 }
841 break;
842
843 case IPC_DISCONNECT:
844 HandleDisconnect(connection);
845 break;
846
847 case IPC_FAIL:
848 wxLogDebug("Unexpected IPC_FAIL received");
849 error = true;
850 break;
851
852 default:
853 wxLogDebug("Unknown message code %d received.", msg);
854 error = true;
855 break;
856 }
857
858 if ( error )
859 IPCOutput(streams).Write8(IPC_FAIL);
860 }
861
862 void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
863 {
864 wxSocketServer *server = (wxSocketServer *) event.GetSocket();
865 if (!server)
866 return;
867 wxTCPServer *ipcserv = (wxTCPServer *) server->GetClientData();
868
869 // This socket is being deleted; skip this event
870 if (!ipcserv)
871 return;
872
873 if (event.GetSocketEvent() != wxSOCKET_CONNECTION)
874 return;
875
876 // Accept the connection, getting a new socket
877 wxSocketBase *sock = server->Accept();
878 if (!sock)
879 return;
880 if (!sock->IsOk())
881 {
882 sock->Destroy();
883 return;
884 }
885
886 wxIPCSocketStreams *streams = new wxIPCSocketStreams(*sock);
887
888 {
889 IPCOutput out(streams);
890
891 const int msg = streams->Read8();
892 if ( msg == IPC_CONNECT )
893 {
894 const wxString topic = streams->ReadString();
895
896 wxTCPConnection *new_connection =
897 (wxTCPConnection *)ipcserv->OnAcceptConnection (topic);
898
899 if (new_connection)
900 {
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;
909 sock->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
910 _CLIENT_ONREQUEST_ID);
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 }
921 }
922 }
923
924 // Something went wrong, send failure message and delete everything
925 out.Write8(IPC_FAIL);
926 } // IPCOutput object is destroyed here, before destroying stream
927
928 delete streams;
929 sock->Destroy();
930 }
931
932 #endif // wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS