]> git.saurik.com Git - wxWidgets.git/blob - src/common/sckipc.cpp
1. some patches from Janos Vegh to docview template detection
[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
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 }
204
205 bool wxTCPServer::Create(const wxString& server_name)
206 {
207 wxSocketServer *server;
208
209 // wxIPV4address defaults to INADDR_ANY:0
210 wxIPV4address addr;
211 addr.Service(server_name);
212
213 // Create a socket listening on specified port
214 server = new wxSocketServer(addr, SCKIPC_FLAGS);
215 server->SetEventHandler(*gs_handler, _SERVER_ONREQUEST_ID);
216 server->SetClientData(this);
217 server->SetNotify(wxSOCKET_CONNECTION_FLAG);
218 server->Notify(TRUE);
219
220 return TRUE;
221 }
222
223 wxTCPServer::~wxTCPServer()
224 {
225 }
226
227 wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) )
228 {
229 return new wxTCPConnection();
230 }
231
232 // --------------------------------------------------------------------------
233 // wxTCPConnection
234 // --------------------------------------------------------------------------
235
236 wxTCPConnection::wxTCPConnection () : wxConnectionBase()
237 {
238 m_sock = NULL;
239 m_sockstrm = NULL;
240 m_codeci = NULL;
241 m_codeco = NULL;
242 }
243
244 wxTCPConnection::wxTCPConnection(char * WXUNUSED(buffer), int WXUNUSED(size))
245 {
246 }
247
248 wxTCPConnection::~wxTCPConnection ()
249 {
250 wxDELETE(m_codeci);
251 wxDELETE(m_codeco);
252 wxDELETE(m_sockstrm);
253
254 if (m_sock) m_sock->Destroy();
255 }
256
257 void wxTCPConnection::Compress(bool WXUNUSED(on))
258 {
259 // Use wxLZWStream
260 }
261
262 // Calls that CLIENT can make.
263 bool wxTCPConnection::Disconnect ()
264 {
265 // Send the the disconnect message to the peer.
266 m_codeco->Write8(IPC_DISCONNECT);
267 m_sock->Notify(FALSE);
268 m_sock->Close();
269
270 return TRUE;
271 }
272
273 bool wxTCPConnection::Execute(const wxChar *data, int size, wxIPCFormat format)
274 {
275 if (!m_sock->IsConnected())
276 return FALSE;
277
278 // Prepare EXECUTE message
279 m_codeco->Write8(IPC_EXECUTE);
280 m_codeco->Write8(format);
281
282 if (size < 0)
283 size = strlen(data) + 1; // includes final NUL
284
285 m_codeco->Write32(size);
286 m_sockstrm->Write(data, size);
287
288 return TRUE;
289 }
290
291 char *wxTCPConnection::Request (const wxString& item, int *size, wxIPCFormat format)
292 {
293 if (!m_sock->IsConnected())
294 return NULL;
295
296 m_codeco->Write8(IPC_REQUEST);
297 m_codeco->WriteString(item);
298 m_codeco->Write8(format);
299
300 // If Unpack doesn't initialize it.
301 int ret;
302
303 ret = m_codeci->Read8();
304 if (ret == IPC_FAIL)
305 return NULL;
306 else
307 {
308 size_t s;
309 char *data = NULL;
310
311 s = m_codeci->Read32();
312 data = new char[s];
313 m_sockstrm->Read(data, s);
314
315 if (size)
316 *size = s;
317 return data;
318 }
319 }
320
321 bool wxTCPConnection::Poke (const wxString& item, wxChar *data, int size, wxIPCFormat format)
322 {
323 if (!m_sock->IsConnected())
324 return FALSE;
325
326 m_codeco->Write8(IPC_POKE);
327 m_codeco->WriteString(item);
328 m_codeco->Write8(format);
329
330 if (size < 0)
331 size = strlen(data) + 1; // includes final NUL
332
333 m_codeco->Write32(size);
334 m_sockstrm->Write(data, size);
335
336 return TRUE;
337 }
338
339 bool wxTCPConnection::StartAdvise (const wxString& item)
340 {
341 int ret;
342
343 if (!m_sock->IsConnected())
344 return FALSE;
345
346 m_codeco->Write8(IPC_ADVISE_START);
347 m_codeco->WriteString(item);
348
349 ret = m_codeci->Read8();
350
351 if (ret != IPC_FAIL)
352 return TRUE;
353 else
354 return FALSE;
355 }
356
357 bool wxTCPConnection::StopAdvise (const wxString& item)
358 {
359 int msg;
360
361 if (!m_sock->IsConnected())
362 return FALSE;
363
364 m_codeco->Write8(IPC_ADVISE_STOP);
365 m_codeco->WriteString(item);
366
367 msg = m_codeci->Read8();
368
369 if (msg != IPC_FAIL)
370 return TRUE;
371 else
372 return FALSE;
373 }
374
375 // Calls that SERVER can make
376 bool wxTCPConnection::Advise (const wxString& item,
377 wxChar *data, int size, wxIPCFormat format)
378 {
379 if (!m_sock->IsConnected())
380 return FALSE;
381
382 m_codeco->Write8(IPC_ADVISE);
383 m_codeco->WriteString(item);
384 m_codeco->Write8(format);
385
386 if (size < 0)
387 size = strlen(data) + 1; // includes final NUL
388
389 m_codeco->Write32(size);
390 m_sockstrm->Write(data, size);
391
392 return TRUE;
393 }
394
395 // --------------------------------------------------------------------------
396 // wxTCPEventHandler (private class)
397 // --------------------------------------------------------------------------
398
399 BEGIN_EVENT_TABLE(wxTCPEventHandler, wxEvtHandler)
400 EVT_SOCKET(_CLIENT_ONREQUEST_ID, wxTCPEventHandler::Client_OnRequest)
401 EVT_SOCKET(_SERVER_ONREQUEST_ID, wxTCPEventHandler::Server_OnRequest)
402 END_EVENT_TABLE()
403
404 void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
405 {
406 wxSocketBase *sock = event.GetSocket();
407 wxSocketNotify evt = event.GetSocketEvent();
408 wxTCPConnection *connection = (wxTCPConnection *)(event.GetClientData());
409
410 int msg = 0;
411 wxDataInputStream *codeci;
412 wxDataOutputStream *codeco;
413 wxSocketStream *sockstrm;
414 wxString topic_name = connection->m_topic;
415 wxString item;
416
417 // The socket handler signals us that we lost the connection: destroy all.
418 if (evt == wxSOCKET_LOST)
419 {
420 sock->Notify(FALSE);
421 sock->Close();
422 connection->OnDisconnect();
423 return;
424 }
425
426 // Receive message number.
427 codeci = connection->m_codeci;
428 codeco = connection->m_codeco;
429 sockstrm = connection->m_sockstrm;
430 msg = codeci->Read8();
431
432 switch (msg)
433 {
434 case IPC_EXECUTE:
435 {
436 char *data;
437 size_t size;
438 wxIPCFormat format;
439
440 format = (wxIPCFormat)codeci->Read8();
441 size = codeci->Read32();
442 data = new char[size];
443 sockstrm->Read(data, size);
444
445 connection->OnExecute (topic_name, data, size, format);
446
447 delete [] data;
448 break;
449 }
450 case IPC_ADVISE:
451 {
452 char *data;
453 size_t size;
454 wxIPCFormat format;
455
456 item = codeci->ReadString();
457 format = (wxIPCFormat)codeci->Read8();
458 size = codeci->Read32();
459 data = new char[size];
460 sockstrm->Read(data, size);
461
462 connection->OnAdvise (topic_name, item, data, size, format);
463
464 delete [] data;
465 break;
466 }
467 case IPC_ADVISE_START:
468 {
469 item = codeci->ReadString();
470
471 bool ok = connection->OnStartAdvise (topic_name, item);
472 if (ok)
473 codeco->Write8(IPC_ADVISE_START);
474 else
475 codeco->Write8(IPC_FAIL);
476
477 break;
478 }
479 case IPC_ADVISE_STOP:
480 {
481 item = codeci->ReadString();
482
483 bool ok = connection->OnStopAdvise (topic_name, item);
484 if (ok)
485 codeco->Write8(IPC_ADVISE_STOP);
486 else
487 codeco->Write8(IPC_FAIL);
488
489 break;
490 }
491 case IPC_POKE:
492 {
493 wxIPCFormat format;
494 size_t size;
495 wxChar *data;
496
497 item = codeci->ReadString();
498 format = (wxIPCFormat)codeci->Read8();
499 size = codeci->Read32();
500 data = new wxChar[size];
501 sockstrm->Read(data, size);
502
503 connection->OnPoke (topic_name, item, data, size, format);
504
505 delete [] data;
506
507 break;
508 }
509 case IPC_REQUEST:
510 {
511 wxIPCFormat format;
512
513 item = codeci->ReadString();
514 format = (wxIPCFormat)codeci->Read8();
515
516 int user_size = -1;
517 char *user_data = connection->OnRequest (topic_name, item, &user_size, format);
518
519 if (user_data)
520 {
521 codeco->Write8(IPC_REQUEST_REPLY);
522
523 if (user_size == -1)
524 user_size = strlen(user_data) + 1; // includes final NUL
525
526 codeco->Write32(user_size);
527 sockstrm->Write(user_data, user_size);
528 }
529 else
530 codeco->Write8(IPC_FAIL);
531
532 break;
533 }
534 case IPC_DISCONNECT:
535 {
536 sock->Notify(FALSE);
537 sock->Close();
538 connection->OnDisconnect();
539 break;
540 }
541 default:
542 codeco->Write8(IPC_FAIL);
543 break;
544 }
545 }
546
547 void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
548 {
549 wxSocketServer *server = (wxSocketServer *) event.GetSocket();
550 wxTCPServer *ipcserv = (wxTCPServer *) event.GetClientData();
551
552 if (event.GetSocketEvent() != wxSOCKET_CONNECTION)
553 return;
554
555 // Accept the connection, getting a new socket
556 wxSocketBase *sock = server->Accept();
557 if (!sock->Ok())
558 {
559 sock->Destroy();
560 return;
561 }
562
563 wxSocketStream *stream = new wxSocketStream(*sock);
564 wxDataInputStream *codeci = new wxDataInputStream(*stream);
565 wxDataOutputStream *codeco = new wxDataOutputStream(*stream);
566
567 int msg;
568 msg = codeci->Read8();
569
570 if (msg == IPC_CONNECT)
571 {
572 wxString topic_name;
573 topic_name = codeci->ReadString();
574
575 wxTCPConnection *new_connection =
576 (wxTCPConnection *)ipcserv->OnAcceptConnection (topic_name);
577
578 if (new_connection)
579 {
580 if (new_connection->IsKindOf(CLASSINFO(wxTCPConnection)))
581 {
582 // Acknowledge success
583 codeco->Write8(IPC_CONNECT);
584 new_connection->m_topic = topic_name;
585 new_connection->m_sock = sock;
586 new_connection->m_sockstrm = stream;
587 new_connection->m_codeci = codeci;
588 new_connection->m_codeco = codeco;
589 sock->SetEventHandler(*gs_handler, _CLIENT_ONREQUEST_ID);
590 sock->SetClientData(new_connection);
591 sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
592 sock->Notify(TRUE);
593 return;
594 }
595 else
596 {
597 delete new_connection;
598 // and fall through to delete everything else
599 }
600 }
601 }
602
603 // Something went wrong, send failure message and delete everything
604 codeco->Write8(IPC_FAIL);
605
606 delete codeco;
607 delete codeci;
608 delete stream;
609 sock->Destroy();
610 }
611
612 // --------------------------------------------------------------------------
613 // wxTCPEventHandlerModule (private class)
614 // --------------------------------------------------------------------------
615
616 class WXDLLEXPORT wxTCPEventHandlerModule: public wxModule
617 {
618 DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule)
619
620 public:
621 bool OnInit() { gs_handler = new wxTCPEventHandler(); return TRUE; }
622 void OnExit() { wxDELETE(gs_handler); }
623 };
624
625 IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule)
626
627
628 #endif
629 // wxUSE_SOCKETS && wxUSE_IPC