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