]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/sckipc.cpp
added wxSockAddress copy ctor which, in particular, fixes Clone() and fixed its opera...
[wxWidgets.git] / src / common / sckipc.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: 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// Created: 1993
9// RCS-ID: $Id$
10// Copyright: (c) Julian Smart 1993
11// (c) Guilhem Lavaux 1997, 1998
12// (c) 2000 Guillermo Rodriguez <guille@iies.es>
13// Licence: wxWindows license
14/////////////////////////////////////////////////////////////////////////////
15
16// ==========================================================================
17// declarations
18// ==========================================================================
19
20// --------------------------------------------------------------------------
21// headers
22// --------------------------------------------------------------------------
23
24#ifdef __GNUG__
25#pragma implementation "sckipc.h"
26#endif
27
28// For compilers that support precompilation, includes "wx.h".
29#include "wx/wxprec.h"
30
31#ifdef __BORLANDC__
32#pragma hdrstop
33#endif
34
35#ifndef WX_PRECOMP
36#include "wx/defs.h"
37#endif
38
39#if wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS
40
41#include <stdlib.h>
42#include <stdio.h>
43
44#include "wx/socket.h"
45#include "wx/sckipc.h"
46#include "wx/module.h"
47#include "wx/event.h"
48#include "wx/log.h"
49
50#ifdef __BORLANDC__
51#pragma hdrstop
52#endif
53
54// --------------------------------------------------------------------------
55// macros and constants
56// --------------------------------------------------------------------------
57
58// It seems to be already defined somewhere in the Xt includes.
59#ifndef __XT__
60// Message codes
61enum
62{
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
77
78// All sockets will be created with the following flags
79#define SCKIPC_FLAGS (wxSOCKET_WAITALL)
80
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// --------------------------------------------------------------------------
113// wxTCPClient
114// --------------------------------------------------------------------------
115
116wxTCPClient::wxTCPClient () : wxClientBase()
117{
118}
119
120wxTCPClient::~wxTCPClient ()
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{
135 wxSocketClient *client = new wxSocketClient(SCKIPC_FLAGS);
136 wxSocketStream *stream = new wxSocketStream(*client);
137 wxDataInputStream *data_is = new wxDataInputStream(*stream);
138 wxDataOutputStream *data_os = new wxDataOutputStream(*stream);
139
140 wxIPV4address addr;
141 addr.Service(server_name);
142 addr.Hostname(host);
143
144 if (client->Connect(addr))
145 {
146 unsigned char msg;
147
148 // Send topic name, and enquire whether this has succeeded
149 data_os->Write8(IPC_CONNECT);
150 data_os->WriteString(topic);
151
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 {
161 if (connection->IsKindOf(CLASSINFO(wxTCPConnection)))
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;
168 client->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID);
169 client->SetClientData(connection);
170 client->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
171 client->Notify(TRUE);
172 return connection;
173 }
174 else
175 {
176 delete connection;
177 // and fall through to delete everything else
178 }
179 }
180 }
181 }
182
183 // Something went wrong, delete everything
184 delete data_is;
185 delete data_os;
186 delete stream;
187 client->Destroy();
188
189 return NULL;
190}
191
192wxConnectionBase *wxTCPClient::OnMakeConnection()
193{
194 return new wxTCPConnection();
195}
196
197// --------------------------------------------------------------------------
198// wxTCPServer
199// --------------------------------------------------------------------------
200
201wxTCPServer::wxTCPServer () : wxServerBase()
202{
203 m_server = NULL;
204}
205
206bool wxTCPServer::Create(const wxString& serverName)
207{
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 }
215
216 // wxIPV4address defaults to INADDR_ANY:0
217 wxIPV4address addr;
218 addr.Service(serverName);
219
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);
235
236 return TRUE;
237}
238
239wxTCPServer::~wxTCPServer()
240{
241 if (m_server)
242 {
243 m_server->SetClientData(NULL);
244 m_server->Destroy();
245 }
246}
247
248wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) )
249{
250 return new wxTCPConnection();
251}
252
253// --------------------------------------------------------------------------
254// wxTCPConnection
255// --------------------------------------------------------------------------
256
257wxTCPConnection::wxTCPConnection () : wxConnectionBase()
258{
259 m_sock = NULL;
260 m_sockstrm = NULL;
261 m_codeci = NULL;
262 m_codeco = NULL;
263}
264
265wxTCPConnection::wxTCPConnection(char * WXUNUSED(buffer), int WXUNUSED(size))
266{
267}
268
269wxTCPConnection::~wxTCPConnection ()
270{
271 wxDELETE(m_codeci);
272 wxDELETE(m_codeco);
273 wxDELETE(m_sockstrm);
274
275 if (m_sock)
276 {
277 m_sock->SetClientData(NULL);
278 m_sock->Destroy();
279 }
280}
281
282void wxTCPConnection::Compress(bool WXUNUSED(on))
283{
284 // Use wxLZWStream
285}
286
287// Calls that CLIENT can make.
288bool wxTCPConnection::Disconnect ()
289{
290 // Send the the disconnect message to the peer.
291 m_codeco->Write8(IPC_DISCONNECT);
292 m_sock->Notify(FALSE);
293 m_sock->Close();
294
295 return TRUE;
296}
297
298bool wxTCPConnection::Execute(const wxChar *data, int size, wxIPCFormat format)
299{
300 if (!m_sock->IsConnected())
301 return FALSE;
302
303 // Prepare EXECUTE message
304 m_codeco->Write8(IPC_EXECUTE);
305 m_codeco->Write8(format);
306
307 if (size < 0)
308 size = wxStrlen(data) + 1; // includes final NUL
309
310 m_codeco->Write32(size);
311 m_sockstrm->Write(data, size);
312
313 return TRUE;
314}
315
316char *wxTCPConnection::Request (const wxString& item, int *size, wxIPCFormat format)
317{
318 if (!m_sock->IsConnected())
319 return NULL;
320
321 m_codeco->Write8(IPC_REQUEST);
322 m_codeco->WriteString(item);
323 m_codeco->Write8(format);
324
325 // If Unpack doesn't initialize it.
326 int ret;
327
328 ret = m_codeci->Read8();
329 if (ret == IPC_FAIL)
330 return NULL;
331 else
332 {
333 size_t s;
334 char *data = NULL;
335
336 s = m_codeci->Read32();
337 data = new char[s];
338 m_sockstrm->Read(data, s);
339
340 if (size)
341 *size = s;
342 return data;
343 }
344}
345
346bool wxTCPConnection::Poke (const wxString& item, wxChar *data, int size, wxIPCFormat format)
347{
348 if (!m_sock->IsConnected())
349 return FALSE;
350
351 m_codeco->Write8(IPC_POKE);
352 m_codeco->WriteString(item);
353 m_codeco->Write8(format);
354
355 if (size < 0)
356 size = wxStrlen(data) + 1; // includes final NUL
357
358 m_codeco->Write32(size);
359 m_sockstrm->Write(data, size);
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
371 m_codeco->Write8(IPC_ADVISE_START);
372 m_codeco->WriteString(item);
373
374 ret = m_codeci->Read8();
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
389 m_codeco->Write8(IPC_ADVISE_STOP);
390 m_codeco->WriteString(item);
391
392 msg = m_codeci->Read8();
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,
402 wxChar *data, int size, wxIPCFormat format)
403{
404 if (!m_sock->IsConnected())
405 return FALSE;
406
407 m_codeco->Write8(IPC_ADVISE);
408 m_codeco->WriteString(item);
409 m_codeco->Write8(format);
410
411 if (size < 0)
412 size = wxStrlen(data) + 1; // includes final NUL
413
414 m_codeco->Write32(size);
415 m_sockstrm->Write(data, size);
416
417 return TRUE;
418}
419
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)
430{
431 wxSocketBase *sock = event.GetSocket();
432 wxSocketNotify evt = event.GetSocketEvent();
433 wxTCPConnection *connection = (wxTCPConnection *)(sock->GetClientData());
434
435 // This socket is being deleted; skip this event
436 if (!connection)
437 return;
438
439 int msg = 0;
440 wxDataInputStream *codeci;
441 wxDataOutputStream *codeco;
442 wxSocketStream *sockstrm;
443 wxString topic_name = connection->m_topic;
444 wxString item;
445
446 // We lost the connection: destroy everything
447 if (evt == wxSOCKET_LOST)
448 {
449 sock->Notify(FALSE);
450 sock->Close();
451 connection->OnDisconnect();
452 return;
453 }
454
455 // Receive message number.
456 codeci = connection->m_codeci;
457 codeco = connection->m_codeco;
458 sockstrm = connection->m_sockstrm;
459 msg = codeci->Read8();
460
461 switch (msg)
462 {
463 case IPC_EXECUTE:
464 {
465 char *data;
466 size_t size;
467 wxIPCFormat format;
468
469 format = (wxIPCFormat)codeci->Read8();
470 size = codeci->Read32();
471 data = new char[size];
472 sockstrm->Read(data, size);
473
474 connection->OnExecute (topic_name, data, size, format);
475
476 delete [] data;
477 break;
478 }
479 case IPC_ADVISE:
480 {
481 char *data;
482 size_t size;
483 wxIPCFormat format;
484
485 item = codeci->ReadString();
486 format = (wxIPCFormat)codeci->Read8();
487 size = codeci->Read32();
488 data = new char[size];
489 sockstrm->Read(data, size);
490
491 connection->OnAdvise (topic_name, item, data, size, format);
492
493 delete [] data;
494 break;
495 }
496 case IPC_ADVISE_START:
497 {
498 item = codeci->ReadString();
499
500 bool ok = connection->OnStartAdvise (topic_name, item);
501 if (ok)
502 codeco->Write8(IPC_ADVISE_START);
503 else
504 codeco->Write8(IPC_FAIL);
505
506 break;
507 }
508 case IPC_ADVISE_STOP:
509 {
510 item = codeci->ReadString();
511
512 bool ok = connection->OnStopAdvise (topic_name, item);
513 if (ok)
514 codeco->Write8(IPC_ADVISE_STOP);
515 else
516 codeco->Write8(IPC_FAIL);
517
518 break;
519 }
520 case IPC_POKE:
521 {
522 wxIPCFormat format;
523 size_t size;
524 wxChar *data;
525
526 item = codeci->ReadString();
527 format = (wxIPCFormat)codeci->Read8();
528 size = codeci->Read32();
529 data = new wxChar[size];
530 sockstrm->Read(data, size);
531
532 connection->OnPoke (topic_name, item, data, size, format);
533
534 delete [] data;
535
536 break;
537 }
538 case IPC_REQUEST:
539 {
540 wxIPCFormat format;
541
542 item = codeci->ReadString();
543 format = (wxIPCFormat)codeci->Read8();
544
545 int user_size = -1;
546 char *user_data = connection->OnRequest (topic_name, item, &user_size, format);
547
548 if (user_data)
549 {
550 codeco->Write8(IPC_REQUEST_REPLY);
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
559 codeco->Write8(IPC_FAIL);
560
561 break;
562 }
563 case IPC_DISCONNECT:
564 {
565 sock->Notify(FALSE);
566 sock->Close();
567 connection->OnDisconnect();
568 break;
569 }
570 default:
571 codeco->Write8(IPC_FAIL);
572 break;
573 }
574}
575
576void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
577{
578 wxSocketServer *server = (wxSocketServer *) event.GetSocket();
579 wxTCPServer *ipcserv = (wxTCPServer *) server->GetClientData();
580
581 // This socket is being deleted; skip this event
582 if (!ipcserv)
583 return;
584
585 if (event.GetSocketEvent() != wxSOCKET_CONNECTION)
586 return;
587
588 // Accept the connection, getting a new socket
589 wxSocketBase *sock = server->Accept();
590 if (!sock->Ok())
591 {
592 sock->Destroy();
593 return;
594 }
595
596 wxSocketStream *stream = new wxSocketStream(*sock);
597 wxDataInputStream *codeci = new wxDataInputStream(*stream);
598 wxDataOutputStream *codeco = new wxDataOutputStream(*stream);
599
600 int msg;
601 msg = codeci->Read8();
602
603 if (msg == IPC_CONNECT)
604 {
605 wxString topic_name;
606 topic_name = codeci->ReadString();
607
608 wxTCPConnection *new_connection =
609 (wxTCPConnection *)ipcserv->OnAcceptConnection (topic_name);
610
611 if (new_connection)
612 {
613 if (new_connection->IsKindOf(CLASSINFO(wxTCPConnection)))
614 {
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;
622 sock->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID);
623 sock->SetClientData(new_connection);
624 sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
625 sock->Notify(TRUE);
626 return;
627 }
628 else
629 {
630 delete new_connection;
631 // and fall through to delete everything else
632 }
633 }
634 }
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();
643}
644
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
661#endif
662 // wxUSE_SOCKETS && wxUSE_IPC