fix for using wxDataObjectComposite with the clipboard
[wxWidgets.git] / src / common / sckipc.cpp
CommitLineData
f4ada568
GL
1/////////////////////////////////////////////////////////////////////////////
2// Name: sckipc.cpp
3// Purpose: Interprocess communication implementation (wxSocket version)
0834112f 4// Author: Julian Smart
f4ada568 5// Modified by: Guilhem Lavaux (big rewrite) May 1997, 1998
0834112f 6// Guillermo Rodriguez (updated for wxSocket v2) Jan 2000
cdc59bb6 7// (callbacks deprecated) Mar 2000
f4ada568
GL
8// Created: 1993
9// RCS-ID: $Id$
0834112f
GRG
10// Copyright: (c) Julian Smart 1993
11// (c) Guilhem Lavaux 1997, 1998
12// (c) 2000 Guillermo Rodriguez <guille@iies.es>
f4ada568
GL
13// Licence: wxWindows license
14/////////////////////////////////////////////////////////////////////////////
15
cdc59bb6
GRG
16// ==========================================================================
17// declarations
18// ==========================================================================
19
20// --------------------------------------------------------------------------
21// headers
22// --------------------------------------------------------------------------
23
f4ada568
GL
24#ifdef __GNUG__
25#pragma implementation "sckipc.h"
26#endif
27
fcc6dddd
JS
28// For compilers that support precompilation, includes "wx.h".
29#include "wx/wxprec.h"
f4ada568 30
fcc6dddd
JS
31#ifdef __BORLANDC__
32#pragma hdrstop
f4ada568
GL
33#endif
34
fcc6dddd 35#ifndef WX_PRECOMP
07e829dc 36#include "wx/defs.h"
fcc6dddd
JS
37#endif
38
f6bcfd97 39#if wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS
07e829dc 40
fcc6dddd
JS
41#include <stdlib.h>
42#include <stdio.h>
43
f4ada568
GL
44#include "wx/socket.h"
45#include "wx/sckipc.h"
cdc59bb6
GRG
46#include "wx/module.h"
47#include "wx/event.h"
0834112f 48#include "wx/log.h"
f4ada568
GL
49
50#ifdef __BORLANDC__
51#pragma hdrstop
52#endif
53
cdc59bb6
GRG
54// --------------------------------------------------------------------------
55// macros and constants
56// --------------------------------------------------------------------------
f4ada568
GL
57
58// It seems to be already defined somewhere in the Xt includes.
59#ifndef __XT__
60// Message codes
cdc59bb6
GRG
61enum
62{
f4ada568
GL
63 IPC_EXECUTE = 1,
64 IPC_REQUEST,
65 IPC_POKE,
66 IPC_ADVISE_START,
67 IPC_ADVISE_REQUEST,
68 IPC_ADVISE,
69 IPC_ADVISE_STOP,
70 IPC_REQUEST_REPLY,
71 IPC_FAIL,
72 IPC_CONNECT,
73 IPC_DISCONNECT
74};
75#endif
76
d3ea6527
GRG
77
78// All sockets will be created with the following flags
a24cc774 79#define SCKIPC_FLAGS (wxSOCKET_WAITALL)
d3ea6527 80
cdc59bb6
GRG
81// --------------------------------------------------------------------------
82// wxTCPEventHandler stuff (private class)
83// --------------------------------------------------------------------------
84
85class wxTCPEventHandler : public wxEvtHandler
86{
87public:
88 wxTCPEventHandler() : wxEvtHandler() {};
89
90 void Client_OnRequest(wxSocketEvent& event);
91 void Server_OnRequest(wxSocketEvent& event);
92
93 DECLARE_EVENT_TABLE()
94};
95
96enum
97{
98 _CLIENT_ONREQUEST_ID = 1000,
99 _SERVER_ONREQUEST_ID
100};
101
102static wxTCPEventHandler *gs_handler = NULL;
103
104// ==========================================================================
105// implementation
106// ==========================================================================
107
108IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase)
109IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase)
110IMPLEMENT_CLASS(wxTCPConnection, wxConnectionBase)
111
112// --------------------------------------------------------------------------
f4ada568 113// wxTCPClient
cdc59bb6 114// --------------------------------------------------------------------------
f4ada568 115
cdc59bb6 116wxTCPClient::wxTCPClient () : wxClientBase()
f4ada568
GL
117{
118}
119
6e31e940 120wxTCPClient::~wxTCPClient ()
f4ada568
GL
121{
122}
123
124bool wxTCPClient::ValidHost(const wxString& host)
125{
126 wxIPV4address addr;
127
128 return addr.Hostname(host);
129}
130
131wxConnectionBase *wxTCPClient::MakeConnection (const wxString& host,
132 const wxString& server_name,
133 const wxString& topic)
134{
d3ea6527 135 wxSocketClient *client = new wxSocketClient(SCKIPC_FLAGS);
f4ada568 136 wxSocketStream *stream = new wxSocketStream(*client);
0834112f
GRG
137 wxDataInputStream *data_is = new wxDataInputStream(*stream);
138 wxDataOutputStream *data_os = new wxDataOutputStream(*stream);
139
140 wxIPV4address addr;
f4ada568
GL
141 addr.Service(server_name);
142 addr.Hostname(host);
143
0834112f
GRG
144 if (client->Connect(addr))
145 {
146 unsigned char msg;
f4ada568 147
0834112f
GRG
148 // Send topic name, and enquire whether this has succeeded
149 data_os->Write8(IPC_CONNECT);
150 data_os->WriteString(topic);
f4ada568 151
0834112f
GRG
152 msg = data_is->Read8();
153
154 // OK! Confirmation.
155 if (msg == IPC_CONNECT)
156 {
157 wxTCPConnection *connection = (wxTCPConnection *)OnMakeConnection ();
158
159 if (connection)
160 {
3adb47a9 161 if (connection->IsKindOf(CLASSINFO(wxTCPConnection)))
0834112f
GRG
162 {
163 connection->m_topic = topic;
164 connection->m_sock = client;
165 connection->m_sockstrm = stream;
166 connection->m_codeci = data_is;
167 connection->m_codeco = data_os;
cdc59bb6
GRG
168 client->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID);
169 client->SetClientData(connection);
0834112f
GRG
170 client->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
171 client->Notify(TRUE);
172 return connection;
173 }
3adb47a9
GRG
174 else
175 {
176 delete connection;
177 // and fall through to delete everything else
178 }
f4ada568 179 }
f4ada568 180 }
f4ada568 181 }
0834112f 182
3adb47a9 183 // Something went wrong, delete everything
0834112f
GRG
184 delete data_is;
185 delete data_os;
186 delete stream;
3adb47a9
GRG
187 client->Destroy();
188
0834112f 189 return NULL;
f4ada568
GL
190}
191
192wxConnectionBase *wxTCPClient::OnMakeConnection()
193{
e5b502f3 194 return new wxTCPConnection();
f4ada568
GL
195}
196
cdc59bb6 197// --------------------------------------------------------------------------
f4ada568 198// wxTCPServer
cdc59bb6 199// --------------------------------------------------------------------------
f4ada568 200
cdc59bb6 201wxTCPServer::wxTCPServer () : wxServerBase()
f4ada568 202{
f6bcfd97 203 m_server = NULL;
f4ada568
GL
204}
205
f6bcfd97 206bool wxTCPServer::Create(const wxString& serverName)
f4ada568 207{
f6bcfd97
BP
208 // Destroy previous server, if any
209 if (m_server)
210 {
211 m_server->SetClientData(NULL);
212 m_server->Destroy();
213 m_server = NULL;
214 }
f4ada568 215
d3ea6527
GRG
216 // wxIPV4address defaults to INADDR_ANY:0
217 wxIPV4address addr;
f6bcfd97 218 addr.Service(serverName);
f4ada568 219
f6bcfd97
BP
220 // Create a socket listening on the specified port
221 m_server = new wxSocketServer(addr, SCKIPC_FLAGS);
222
223 if (!m_server->Ok())
224 {
225 m_server->Destroy();
226 m_server = NULL;
227
228 return FALSE;
229 }
230
231 m_server->SetEventHandler(*gs_handler, _SERVER_ONREQUEST_ID);
232 m_server->SetClientData(this);
233 m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
234 m_server->Notify(TRUE);
f4ada568
GL
235
236 return TRUE;
237}
238
6e31e940 239wxTCPServer::~wxTCPServer()
f4ada568 240{
f6bcfd97
BP
241 if (m_server)
242 {
243 m_server->SetClientData(NULL);
244 m_server->Destroy();
245 }
f4ada568
GL
246}
247
e22036dc 248wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) )
f4ada568
GL
249{
250 return new wxTCPConnection();
251}
252
cdc59bb6 253// --------------------------------------------------------------------------
f4ada568 254// wxTCPConnection
cdc59bb6 255// --------------------------------------------------------------------------
f4ada568 256
cdc59bb6 257wxTCPConnection::wxTCPConnection () : wxConnectionBase()
f4ada568 258{
cdc59bb6
GRG
259 m_sock = NULL;
260 m_sockstrm = NULL;
261 m_codeci = NULL;
262 m_codeco = NULL;
f4ada568
GL
263}
264
6e31e940 265wxTCPConnection::wxTCPConnection(char * WXUNUSED(buffer), int WXUNUSED(size))
7921cf2b
JS
266{
267}
268
6e31e940 269wxTCPConnection::~wxTCPConnection ()
f4ada568 270{
75ed1d15
GL
271 wxDELETE(m_codeci);
272 wxDELETE(m_codeco);
f4ada568 273 wxDELETE(m_sockstrm);
3adb47a9 274
e5b502f3
GRG
275 if (m_sock)
276 {
277 m_sock->SetClientData(NULL);
278 m_sock->Destroy();
279 }
f4ada568
GL
280}
281
cb43b372 282void wxTCPConnection::Compress(bool WXUNUSED(on))
f4ada568
GL
283{
284 // Use wxLZWStream
285}
286
287// Calls that CLIENT can make.
6e31e940 288bool wxTCPConnection::Disconnect ()
f4ada568
GL
289{
290 // Send the the disconnect message to the peer.
75ed1d15 291 m_codeco->Write8(IPC_DISCONNECT);
cdc59bb6 292 m_sock->Notify(FALSE);
f4ada568
GL
293 m_sock->Close();
294
295 return TRUE;
296}
297
0834112f 298bool wxTCPConnection::Execute(const wxChar *data, int size, wxIPCFormat format)
f4ada568
GL
299{
300 if (!m_sock->IsConnected())
301 return FALSE;
302
303 // Prepare EXECUTE message
75ed1d15
GL
304 m_codeco->Write8(IPC_EXECUTE);
305 m_codeco->Write8(format);
0834112f 306
f4ada568 307 if (size < 0)
f6bcfd97 308 size = wxStrlen(data) + 1; // includes final NUL
0834112f
GRG
309
310 m_codeco->Write32(size);
311 m_sockstrm->Write(data, size);
f4ada568
GL
312
313 return TRUE;
314}
315
0d2a2b60 316char *wxTCPConnection::Request (const wxString& item, int *size, wxIPCFormat format)
f4ada568
GL
317{
318 if (!m_sock->IsConnected())
319 return NULL;
320
75ed1d15
GL
321 m_codeco->Write8(IPC_REQUEST);
322 m_codeco->WriteString(item);
323 m_codeco->Write8(format);
f4ada568
GL
324
325 // If Unpack doesn't initialize it.
326 int ret;
327
75ed1d15 328 ret = m_codeci->Read8();
f4ada568
GL
329 if (ret == IPC_FAIL)
330 return NULL;
0834112f
GRG
331 else
332 {
f4ada568
GL
333 size_t s;
334 char *data = NULL;
335
75ed1d15 336 s = m_codeci->Read32();
f4ada568 337 data = new char[s];
fae05df5 338 m_sockstrm->Read(data, s);
f4ada568
GL
339
340 if (size)
341 *size = s;
342 return data;
343 }
344}
345
783b6cfd 346bool wxTCPConnection::Poke (const wxString& item, wxChar *data, int size, wxIPCFormat format)
f4ada568
GL
347{
348 if (!m_sock->IsConnected())
349 return FALSE;
350
75ed1d15
GL
351 m_codeco->Write8(IPC_POKE);
352 m_codeco->WriteString(item);
353 m_codeco->Write8(format);
0834112f 354
f4ada568 355 if (size < 0)
f6bcfd97 356 size = wxStrlen(data) + 1; // includes final NUL
0834112f
GRG
357
358 m_codeco->Write32(size);
359 m_sockstrm->Write(data, size);
f4ada568
GL
360
361 return TRUE;
362}
363
364bool wxTCPConnection::StartAdvise (const wxString& item)
365{
366 int ret;
367
368 if (!m_sock->IsConnected())
369 return FALSE;
370
75ed1d15
GL
371 m_codeco->Write8(IPC_ADVISE_START);
372 m_codeco->WriteString(item);
f4ada568 373
75ed1d15 374 ret = m_codeci->Read8();
f4ada568
GL
375
376 if (ret != IPC_FAIL)
377 return TRUE;
378 else
379 return FALSE;
380}
381
382bool wxTCPConnection::StopAdvise (const wxString& item)
383{
384 int msg;
385
386 if (!m_sock->IsConnected())
387 return FALSE;
388
75ed1d15
GL
389 m_codeco->Write8(IPC_ADVISE_STOP);
390 m_codeco->WriteString(item);
f4ada568 391
75ed1d15 392 msg = m_codeci->Read8();
f4ada568
GL
393
394 if (msg != IPC_FAIL)
395 return TRUE;
396 else
397 return FALSE;
398}
399
400// Calls that SERVER can make
401bool wxTCPConnection::Advise (const wxString& item,
783b6cfd 402 wxChar *data, int size, wxIPCFormat format)
f4ada568
GL
403{
404 if (!m_sock->IsConnected())
405 return FALSE;
406
75ed1d15
GL
407 m_codeco->Write8(IPC_ADVISE);
408 m_codeco->WriteString(item);
409 m_codeco->Write8(format);
0834112f 410
f4ada568 411 if (size < 0)
f6bcfd97 412 size = wxStrlen(data) + 1; // includes final NUL
0834112f
GRG
413
414 m_codeco->Write32(size);
415 m_sockstrm->Write(data, size);
f4ada568
GL
416
417 return TRUE;
418}
419
cdc59bb6
GRG
420// --------------------------------------------------------------------------
421// wxTCPEventHandler (private class)
422// --------------------------------------------------------------------------
423
424BEGIN_EVENT_TABLE(wxTCPEventHandler, wxEvtHandler)
425 EVT_SOCKET(_CLIENT_ONREQUEST_ID, wxTCPEventHandler::Client_OnRequest)
426 EVT_SOCKET(_SERVER_ONREQUEST_ID, wxTCPEventHandler::Server_OnRequest)
427END_EVENT_TABLE()
428
429void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
f4ada568 430{
cdc59bb6
GRG
431 wxSocketBase *sock = event.GetSocket();
432 wxSocketNotify evt = event.GetSocketEvent();
1f0500b3 433 wxTCPConnection *connection = (wxTCPConnection *)(sock->GetClientData());
cdc59bb6 434
e5b502f3
GRG
435 // This socket is being deleted; skip this event
436 if (!connection)
437 return;
438
f4ada568 439 int msg = 0;
75ed1d15
GL
440 wxDataInputStream *codeci;
441 wxDataOutputStream *codeco;
fae05df5 442 wxSocketStream *sockstrm;
f4ada568
GL
443 wxString topic_name = connection->m_topic;
444 wxString item;
445
e5b502f3 446 // We lost the connection: destroy everything
0834112f
GRG
447 if (evt == wxSOCKET_LOST)
448 {
cdc59bb6
GRG
449 sock->Notify(FALSE);
450 sock->Close();
f4ada568
GL
451 connection->OnDisconnect();
452 return;
453 }
454
455 // Receive message number.
75ed1d15
GL
456 codeci = connection->m_codeci;
457 codeco = connection->m_codeco;
fae05df5 458 sockstrm = connection->m_sockstrm;
75ed1d15 459 msg = codeci->Read8();
f4ada568 460
0834112f
GRG
461 switch (msg)
462 {
463 case IPC_EXECUTE:
464 {
f4ada568
GL
465 char *data;
466 size_t size;
0d2a2b60 467 wxIPCFormat format;
f4ada568 468
0d2a2b60 469 format = (wxIPCFormat)codeci->Read8();
75ed1d15 470 size = codeci->Read32();
f4ada568 471 data = new char[size];
fae05df5 472 sockstrm->Read(data, size);
f4ada568
GL
473
474 connection->OnExecute (topic_name, data, size, format);
475
476 delete [] data;
477 break;
478 }
0834112f
GRG
479 case IPC_ADVISE:
480 {
f4ada568
GL
481 char *data;
482 size_t size;
0d2a2b60 483 wxIPCFormat format;
f4ada568 484
75ed1d15 485 item = codeci->ReadString();
0d2a2b60 486 format = (wxIPCFormat)codeci->Read8();
75ed1d15 487 size = codeci->Read32();
f4ada568 488 data = new char[size];
fae05df5 489 sockstrm->Read(data, size);
f4ada568
GL
490
491 connection->OnAdvise (topic_name, item, data, size, format);
492
493 delete [] data;
494 break;
495 }
0834112f
GRG
496 case IPC_ADVISE_START:
497 {
75ed1d15 498 item = codeci->ReadString();
f4ada568
GL
499
500 bool ok = connection->OnStartAdvise (topic_name, item);
501 if (ok)
75ed1d15 502 codeco->Write8(IPC_ADVISE_START);
f4ada568 503 else
75ed1d15 504 codeco->Write8(IPC_FAIL);
f4ada568
GL
505
506 break;
507 }
0834112f
GRG
508 case IPC_ADVISE_STOP:
509 {
75ed1d15 510 item = codeci->ReadString();
f4ada568
GL
511
512 bool ok = connection->OnStopAdvise (topic_name, item);
513 if (ok)
75ed1d15 514 codeco->Write8(IPC_ADVISE_STOP);
f4ada568 515 else
75ed1d15 516 codeco->Write8(IPC_FAIL);
f4ada568
GL
517
518 break;
519 }
0834112f
GRG
520 case IPC_POKE:
521 {
0d2a2b60 522 wxIPCFormat format;
f4ada568 523 size_t size;
783b6cfd 524 wxChar *data;
f4ada568 525
75ed1d15 526 item = codeci->ReadString();
0d2a2b60 527 format = (wxIPCFormat)codeci->Read8();
75ed1d15 528 size = codeci->Read32();
783b6cfd 529 data = new wxChar[size];
fae05df5 530 sockstrm->Read(data, size);
f4ada568
GL
531
532 connection->OnPoke (topic_name, item, data, size, format);
533
534 delete [] data;
535
536 break;
537 }
0834112f
GRG
538 case IPC_REQUEST:
539 {
0d2a2b60 540 wxIPCFormat format;
f4ada568 541
75ed1d15 542 item = codeci->ReadString();
0d2a2b60 543 format = (wxIPCFormat)codeci->Read8();
f4ada568
GL
544
545 int user_size = -1;
546 char *user_data = connection->OnRequest (topic_name, item, &user_size, format);
547
0834112f
GRG
548 if (user_data)
549 {
75ed1d15 550 codeco->Write8(IPC_REQUEST_REPLY);
0834112f
GRG
551
552 if (user_size == -1)
553 user_size = strlen(user_data) + 1; // includes final NUL
554
555 codeco->Write32(user_size);
556 sockstrm->Write(user_data, user_size);
557 }
558 else
75ed1d15 559 codeco->Write8(IPC_FAIL);
f4ada568
GL
560
561 break;
562 }
0834112f
GRG
563 case IPC_DISCONNECT:
564 {
cdc59bb6
GRG
565 sock->Notify(FALSE);
566 sock->Close();
f4ada568
GL
567 connection->OnDisconnect();
568 break;
569 }
570 default:
75ed1d15 571 codeco->Write8(IPC_FAIL);
f4ada568
GL
572 break;
573 }
574}
575
cdc59bb6 576void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
f4ada568 577{
cdc59bb6 578 wxSocketServer *server = (wxSocketServer *) event.GetSocket();
f6bcfd97 579 wxTCPServer *ipcserv = (wxTCPServer *) server->GetClientData();
f4ada568 580
e5b502f3
GRG
581 // This socket is being deleted; skip this event
582 if (!ipcserv)
583 return;
584
cdc59bb6 585 if (event.GetSocketEvent() != wxSOCKET_CONNECTION)
f4ada568
GL
586 return;
587
3adb47a9 588 // Accept the connection, getting a new socket
cdc59bb6 589 wxSocketBase *sock = server->Accept();
0834112f 590 if (!sock->Ok())
3adb47a9
GRG
591 {
592 sock->Destroy();
0834112f 593 return;
3adb47a9 594 }
f4ada568 595
cdc59bb6
GRG
596 wxSocketStream *stream = new wxSocketStream(*sock);
597 wxDataInputStream *codeci = new wxDataInputStream(*stream);
598 wxDataOutputStream *codeco = new wxDataOutputStream(*stream);
f4ada568 599
f4ada568 600 int msg;
75ed1d15 601 msg = codeci->Read8();
f4ada568 602
0834112f
GRG
603 if (msg == IPC_CONNECT)
604 {
f4ada568 605 wxString topic_name;
75ed1d15 606 topic_name = codeci->ReadString();
f4ada568 607
f4ada568
GL
608 wxTCPConnection *new_connection =
609 (wxTCPConnection *)ipcserv->OnAcceptConnection (topic_name);
3adb47a9 610
0834112f
GRG
611 if (new_connection)
612 {
3adb47a9 613 if (new_connection->IsKindOf(CLASSINFO(wxTCPConnection)))
0834112f 614 {
3adb47a9
GRG
615 // Acknowledge success
616 codeco->Write8(IPC_CONNECT);
617 new_connection->m_topic = topic_name;
618 new_connection->m_sock = sock;
619 new_connection->m_sockstrm = stream;
620 new_connection->m_codeci = codeci;
621 new_connection->m_codeco = codeco;
cdc59bb6
GRG
622 sock->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID);
623 sock->SetClientData(new_connection);
3adb47a9
GRG
624 sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
625 sock->Notify(TRUE);
f4ada568
GL
626 return;
627 }
3adb47a9
GRG
628 else
629 {
630 delete new_connection;
631 // and fall through to delete everything else
632 }
f4ada568
GL
633 }
634 }
3adb47a9
GRG
635
636 // Something went wrong, send failure message and delete everything
637 codeco->Write8(IPC_FAIL);
638
639 delete codeco;
640 delete codeci;
641 delete stream;
642 sock->Destroy();
f4ada568 643}
35a4dab7 644
cdc59bb6
GRG
645// --------------------------------------------------------------------------
646// wxTCPEventHandlerModule (private class)
647// --------------------------------------------------------------------------
648
649class WXDLLEXPORT wxTCPEventHandlerModule: public wxModule
650{
651 DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule)
652
653public:
654 bool OnInit() { gs_handler = new wxTCPEventHandler(); return TRUE; }
655 void OnExit() { wxDELETE(gs_handler); }
656};
657
658IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule)
659
660
35a4dab7 661#endif
3adb47a9 662 // wxUSE_SOCKETS && wxUSE_IPC