]> git.saurik.com Git - wxWidgets.git/blob - src/common/sckipc.cpp
fix from Robert
[wxWidgets.git] / src / common / sckipc.cpp
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
61 enum
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
85 class wxTCPEventHandler : public wxEvtHandler
86 {
87 public:
88 wxTCPEventHandler() : wxEvtHandler() {};
89
90 void Client_OnRequest(wxSocketEvent& event);
91 void Server_OnRequest(wxSocketEvent& event);
92
93 DECLARE_EVENT_TABLE()
94 };
95
96 enum
97 {
98 _CLIENT_ONREQUEST_ID = 1000,
99 _SERVER_ONREQUEST_ID
100 };
101
102 static wxTCPEventHandler *gs_handler = NULL;
103
104 // ==========================================================================
105 // implementation
106 // ==========================================================================
107
108 IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase)
109 IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase)
110 IMPLEMENT_CLASS(wxTCPConnection, wxConnectionBase)
111
112 // --------------------------------------------------------------------------
113 // wxTCPClient
114 // --------------------------------------------------------------------------
115
116 wxTCPClient::wxTCPClient () : wxClientBase()
117 {
118 }
119
120 wxTCPClient::~wxTCPClient ()
121 {
122 }
123
124 bool wxTCPClient::ValidHost(const wxString& host)
125 {
126 wxIPV4address addr;
127
128 return addr.Hostname(host);
129 }
130
131 wxConnectionBase *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
192 wxConnectionBase *wxTCPClient::OnMakeConnection()
193 {
194 return new wxTCPConnection();
195 }
196
197 // --------------------------------------------------------------------------
198 // wxTCPServer
199 // --------------------------------------------------------------------------
200
201 wxTCPServer::wxTCPServer () : wxServerBase()
202 {
203 m_server = NULL;
204 }
205
206 bool 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
239 wxTCPServer::~wxTCPServer()
240 {
241 if (m_server)
242 {
243 m_server->SetClientData(NULL);
244 m_server->Destroy();
245 }
246 }
247
248 wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) )
249 {
250 return new wxTCPConnection();
251 }
252
253 // --------------------------------------------------------------------------
254 // wxTCPConnection
255 // --------------------------------------------------------------------------
256
257 wxTCPConnection::wxTCPConnection () : wxConnectionBase()
258 {
259 m_sock = NULL;
260 m_sockstrm = NULL;
261 m_codeci = NULL;
262 m_codeco = NULL;
263 }
264
265 wxTCPConnection::wxTCPConnection(char * WXUNUSED(buffer), int WXUNUSED(size))
266 {
267 }
268
269 wxTCPConnection::~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
282 void wxTCPConnection::Compress(bool WXUNUSED(on))
283 {
284 // Use wxLZWStream
285 }
286
287 // Calls that CLIENT can make.
288 bool 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
298 bool 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
316 char *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
346 bool 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
364 bool 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
382 bool 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
401 bool 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
424 BEGIN_EVENT_TABLE(wxTCPEventHandler, wxEvtHandler)
425 EVT_SOCKET(_CLIENT_ONREQUEST_ID, wxTCPEventHandler::Client_OnRequest)
426 EVT_SOCKET(_SERVER_ONREQUEST_ID, wxTCPEventHandler::Server_OnRequest)
427 END_EVENT_TABLE()
428
429 void 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
576 void 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
649 class WXDLLEXPORT wxTCPEventHandlerModule: public wxModule
650 {
651 DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule)
652
653 public:
654 bool OnInit() { gs_handler = new wxTCPEventHandler(); return TRUE; }
655 void OnExit() { wxDELETE(gs_handler); }
656 };
657
658 IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule)
659
660
661 #endif
662 // wxUSE_SOCKETS && wxUSE_IPC