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