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