]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/sckipc.cpp
Found bug that skrewed up display wrt horizontal
[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
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}
204
205bool 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
223wxTCPServer::~wxTCPServer()
224{
225}
226
227wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) )
228{
229 return new wxTCPConnection();
230}
231
232// --------------------------------------------------------------------------
233// wxTCPConnection
234// --------------------------------------------------------------------------
235
236wxTCPConnection::wxTCPConnection () : wxConnectionBase()
237{
238 m_sock = NULL;
239 m_sockstrm = NULL;
240 m_codeci = NULL;
241 m_codeco = NULL;
242}
243
244wxTCPConnection::wxTCPConnection(char * WXUNUSED(buffer), int WXUNUSED(size))
245{
246}
247
248wxTCPConnection::~wxTCPConnection ()
249{
250 wxDELETE(m_codeci);
251 wxDELETE(m_codeco);
252 wxDELETE(m_sockstrm);
253
254 if (m_sock) m_sock->Destroy();
255}
256
257void wxTCPConnection::Compress(bool WXUNUSED(on))
258{
259 // Use wxLZWStream
260}
261
262// Calls that CLIENT can make.
263bool 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
273bool 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
291char *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
321bool 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
339bool 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
357bool 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
376bool 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
399BEGIN_EVENT_TABLE(wxTCPEventHandler, wxEvtHandler)
400 EVT_SOCKET(_CLIENT_ONREQUEST_ID, wxTCPEventHandler::Client_OnRequest)
401 EVT_SOCKET(_SERVER_ONREQUEST_ID, wxTCPEventHandler::Server_OnRequest)
402END_EVENT_TABLE()
403
404void 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
547void 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
616class WXDLLEXPORT wxTCPEventHandlerModule: public wxModule
617{
618 DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule)
619
620public:
621 bool OnInit() { gs_handler = new wxTCPEventHandler(); return TRUE; }
622 void OnExit() { wxDELETE(gs_handler); }
623};
624
625IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule)
626
627
628#endif
629 // wxUSE_SOCKETS && wxUSE_IPC