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