]> git.saurik.com Git - wxWidgets.git/blame - src/common/sckipc.cpp
Small bugfix
[wxWidgets.git] / src / common / sckipc.cpp
CommitLineData
f4ada568
GL
1/////////////////////////////////////////////////////////////////////////////
2// Name: sckipc.cpp
3// Purpose: Interprocess communication implementation (wxSocket version)
4// Author: Julian Smart, Guilhem Lavaux
5// Modified by: Guilhem Lavaux (big rewrite) May 1997, 1998
6// Created: 1993
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart 1993, Guilhem Lavaux 1997, 1998
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "sckipc.h"
14#endif
15
fcc6dddd
JS
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
f4ada568 18
fcc6dddd
JS
19#ifdef __BORLANDC__
20#pragma hdrstop
f4ada568
GL
21#endif
22
35a4dab7
GL
23#if wxUSE_SOCKETS
24
fcc6dddd
JS
25#ifndef WX_PRECOMP
26#endif
27
28#include <stdlib.h>
29#include <stdio.h>
30
f4ada568
GL
31#include "wx/socket.h"
32#include "wx/sckipc.h"
33
34#ifdef __BORLANDC__
35#pragma hdrstop
36#endif
37
f4ada568
GL
38IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase)
39IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase)
40IMPLEMENT_DYNAMIC_CLASS(wxTCPConnection, wxConnectionBase)
f4ada568
GL
41
42// It seems to be already defined somewhere in the Xt includes.
43#ifndef __XT__
44// Message codes
45enum {
46 IPC_EXECUTE = 1,
47 IPC_REQUEST,
48 IPC_POKE,
49 IPC_ADVISE_START,
50 IPC_ADVISE_REQUEST,
51 IPC_ADVISE,
52 IPC_ADVISE_STOP,
53 IPC_REQUEST_REPLY,
54 IPC_FAIL,
55 IPC_CONNECT,
56 IPC_DISCONNECT
57};
58#endif
59
60void Server_OnRequest(wxSocketServer& server,
aa8fb7a0 61 wxSocketNotify evt,
f4ada568
GL
62 char *cdata);
63void Client_OnRequest(wxSocketBase& sock,
aa8fb7a0 64 wxSocketNotify evt,
f4ada568
GL
65 char *cdata);
66
67// ---------------------------------------------------------------------------
68// wxTCPClient
69// ---------------------------------------------------------------------------
70
6e31e940 71wxTCPClient::wxTCPClient ()
f4ada568
GL
72 : wxClientBase()
73{
74}
75
6e31e940 76wxTCPClient::~wxTCPClient ()
f4ada568
GL
77{
78}
79
80bool wxTCPClient::ValidHost(const wxString& host)
81{
82 wxIPV4address addr;
83
84 return addr.Hostname(host);
85}
86
87wxConnectionBase *wxTCPClient::MakeConnection (const wxString& host,
88 const wxString& server_name,
89 const wxString& topic)
90{
91 wxIPV4address addr;
a324a7bc 92 wxSocketClient *client = new wxSocketClient();
f4ada568 93 wxSocketStream *stream = new wxSocketStream(*client);
75ed1d15
GL
94 wxDataInputStream data_is(*stream);
95 wxDataOutputStream data_os(*stream);
f4ada568 96
aa8fb7a0 97 client->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
f4ada568
GL
98 addr.Service(server_name);
99 addr.Hostname(host);
100
101 if (!client->Connect(addr)) {
102 delete client;
103 return NULL;
104 }
105 client->Notify(FALSE);
106
107 // Send topic name, and enquire whether this has succeeded
108 unsigned char msg;
109
75ed1d15
GL
110 data_os.Write8(IPC_CONNECT);
111 data_os.WriteString(topic);
f4ada568 112
75ed1d15 113 msg = data_is.Read8();
f4ada568
GL
114
115 // OK! Confirmation.
116 if (msg == IPC_CONNECT) {
117 wxTCPConnection *connection = (wxTCPConnection *)OnMakeConnection ();
118 if (connection) {
119 if (!connection->IsKindOf(CLASSINFO(wxTCPConnection))) {
120 delete connection;
121 return NULL;
122 }
123 connection->m_topic = topic;
124 client->Callback(Client_OnRequest);
125 client->CallbackData((char *)connection);
126 client->Notify(TRUE);
127 return connection;
128 } else {
129 delete client;
130 return NULL;
131 }
132 } else {
133 delete client;
134 return NULL;
135 }
f4ada568
GL
136}
137
138wxConnectionBase *wxTCPClient::OnMakeConnection()
139{
140 return new wxTCPConnection;
141}
142
143// ---------------------------------------------------------------------------
144// wxTCPServer
145// ---------------------------------------------------------------------------
146
6e31e940 147wxTCPServer::wxTCPServer ()
f4ada568
GL
148 : wxServerBase()
149{
150}
151
152bool wxTCPServer::Create(const wxString& server_name)
153{
154 wxIPV4address addr;
f4ada568
GL
155 wxSocketServer *server;
156
157 addr.Service(server_name);
158
159 // Create a socket listening on specified port
a324a7bc 160 server = new wxSocketServer(addr);
f4ada568 161 server->Callback((wxSocketBase::wxSockCbk)Server_OnRequest);
aa8fb7a0 162 server->SetNotify(wxSOCKET_CONNECTION_FLAG);
f4ada568
GL
163
164 server->CallbackData((char *)this);
165
166 return TRUE;
167}
168
6e31e940 169wxTCPServer::~wxTCPServer()
f4ada568
GL
170{
171}
172
e22036dc 173wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) )
f4ada568
GL
174{
175 return new wxTCPConnection();
176}
177
178// ---------------------------------------------------------------------------
179// wxTCPConnection
180// ---------------------------------------------------------------------------
181
6e31e940 182wxTCPConnection::wxTCPConnection ()
f4ada568 183 : wxConnectionBase(),
75ed1d15 184 m_sock(NULL), m_sockstrm(NULL), m_codeci(NULL), m_codeco(NULL)
f4ada568
GL
185{
186}
187
6e31e940 188wxTCPConnection::wxTCPConnection(char * WXUNUSED(buffer), int WXUNUSED(size))
7921cf2b
JS
189{
190}
191
6e31e940 192wxTCPConnection::~wxTCPConnection ()
f4ada568
GL
193{
194 wxDELETE(m_sock);
75ed1d15
GL
195 wxDELETE(m_codeci);
196 wxDELETE(m_codeco);
f4ada568
GL
197 wxDELETE(m_sockstrm);
198}
199
cb43b372 200void wxTCPConnection::Compress(bool WXUNUSED(on))
f4ada568
GL
201{
202 // Use wxLZWStream
203}
204
205// Calls that CLIENT can make.
6e31e940 206bool wxTCPConnection::Disconnect ()
f4ada568
GL
207{
208 // Send the the disconnect message to the peer.
75ed1d15 209 m_codeco->Write8(IPC_DISCONNECT);
f4ada568
GL
210 m_sock->Close();
211
212 return TRUE;
213}
214
e90c1d2a 215bool wxTCPConnection::Execute (const wxChar *data, int size, wxIPCFormat format)
f4ada568
GL
216{
217 if (!m_sock->IsConnected())
218 return FALSE;
219
220 // Prepare EXECUTE message
75ed1d15
GL
221 m_codeco->Write8(IPC_EXECUTE);
222 m_codeco->Write8(format);
f4ada568 223 if (size < 0)
75ed1d15 224 m_codeco->WriteString(data);
f4ada568 225 else {
75ed1d15 226 m_codeco->Write32(size);
fae05df5 227 m_sockstrm->Write(data, size);
f4ada568
GL
228 }
229
230 return TRUE;
231}
232
0d2a2b60 233char *wxTCPConnection::Request (const wxString& item, int *size, wxIPCFormat format)
f4ada568
GL
234{
235 if (!m_sock->IsConnected())
236 return NULL;
237
75ed1d15
GL
238 m_codeco->Write8(IPC_REQUEST);
239 m_codeco->WriteString(item);
240 m_codeco->Write8(format);
f4ada568
GL
241
242 // If Unpack doesn't initialize it.
243 int ret;
244
75ed1d15 245 ret = m_codeci->Read8();
f4ada568
GL
246 if (ret == IPC_FAIL)
247 return NULL;
248 else {
249 size_t s;
250 char *data = NULL;
251
75ed1d15 252 s = m_codeci->Read32();
f4ada568 253 data = new char[s];
fae05df5 254 m_sockstrm->Read(data, s);
f4ada568
GL
255
256 if (size)
257 *size = s;
258 return data;
259 }
260}
261
783b6cfd 262bool wxTCPConnection::Poke (const wxString& item, wxChar *data, int size, wxIPCFormat format)
f4ada568
GL
263{
264 if (!m_sock->IsConnected())
265 return FALSE;
266
75ed1d15
GL
267 m_codeco->Write8(IPC_POKE);
268 m_codeco->WriteString(item);
269 m_codeco->Write8(format);
f4ada568 270 if (size < 0)
75ed1d15 271 m_codeco->WriteString(data);
f4ada568 272 else {
75ed1d15 273 m_codeco->Write32(size);
fae05df5 274 m_sockstrm->Write(data, size);
f4ada568
GL
275 }
276
277 return TRUE;
278}
279
280bool wxTCPConnection::StartAdvise (const wxString& item)
281{
282 int ret;
283
284 if (!m_sock->IsConnected())
285 return FALSE;
286
75ed1d15
GL
287 m_codeco->Write8(IPC_ADVISE_START);
288 m_codeco->WriteString(item);
f4ada568 289
75ed1d15 290 ret = m_codeci->Read8();
f4ada568
GL
291
292 if (ret != IPC_FAIL)
293 return TRUE;
294 else
295 return FALSE;
296}
297
298bool wxTCPConnection::StopAdvise (const wxString& item)
299{
300 int msg;
301
302 if (!m_sock->IsConnected())
303 return FALSE;
304
75ed1d15
GL
305 m_codeco->Write8(IPC_ADVISE_STOP);
306 m_codeco->WriteString(item);
f4ada568 307
75ed1d15 308 msg = m_codeci->Read8();
f4ada568
GL
309
310 if (msg != IPC_FAIL)
311 return TRUE;
312 else
313 return FALSE;
314}
315
316// Calls that SERVER can make
317bool wxTCPConnection::Advise (const wxString& item,
783b6cfd 318 wxChar *data, int size, wxIPCFormat format)
f4ada568
GL
319{
320 if (!m_sock->IsConnected())
321 return FALSE;
322
75ed1d15
GL
323 m_codeco->Write8(IPC_ADVISE);
324 m_codeco->WriteString(item);
325 m_codeco->Write8(format);
f4ada568 326 if (size < 0)
75ed1d15 327 m_codeco->WriteString(data);
f4ada568 328 else {
75ed1d15 329 m_codeco->Write32(size);
fae05df5 330 m_sockstrm->Write(data, size);
f4ada568
GL
331 }
332
333 return TRUE;
334}
335
aa8fb7a0 336void Client_OnRequest(wxSocketBase& sock, wxSocketNotify evt,
f4ada568
GL
337 char *cdata)
338{
339 int msg = 0;
340 wxTCPConnection *connection = (wxTCPConnection *)cdata;
75ed1d15
GL
341 wxDataInputStream *codeci;
342 wxDataOutputStream *codeco;
fae05df5 343 wxSocketStream *sockstrm;
f4ada568
GL
344 wxString topic_name = connection->m_topic;
345 wxString item;
346
347 // The socket handler signals us that we lost the connection: destroy all.
aa8fb7a0 348 if (evt == wxSOCKET_LOST) {
f4ada568
GL
349 sock.Close();
350 connection->OnDisconnect();
351 return;
352 }
353
354 // Receive message number.
75ed1d15
GL
355 codeci = connection->m_codeci;
356 codeco = connection->m_codeco;
fae05df5 357 sockstrm = connection->m_sockstrm;
75ed1d15 358 msg = codeci->Read8();
f4ada568
GL
359
360 switch (msg) {
361 case IPC_EXECUTE: {
362 char *data;
363 size_t size;
0d2a2b60 364 wxIPCFormat format;
f4ada568 365
0d2a2b60 366 format = (wxIPCFormat)codeci->Read8();
75ed1d15 367 size = codeci->Read32();
f4ada568 368 data = new char[size];
fae05df5 369 sockstrm->Read(data, size);
f4ada568
GL
370
371 connection->OnExecute (topic_name, data, size, format);
372
373 delete [] data;
374 break;
375 }
376 case IPC_ADVISE: {
377 char *data;
378 size_t size;
0d2a2b60 379 wxIPCFormat format;
f4ada568 380
75ed1d15 381 item = codeci->ReadString();
0d2a2b60 382 format = (wxIPCFormat)codeci->Read8();
75ed1d15 383 size = codeci->Read32();
f4ada568 384 data = new char[size];
fae05df5 385 sockstrm->Read(data, size);
f4ada568
GL
386
387 connection->OnAdvise (topic_name, item, data, size, format);
388
389 delete [] data;
390 break;
391 }
392 case IPC_ADVISE_START: {
75ed1d15 393 item = codeci->ReadString();
f4ada568
GL
394
395 bool ok = connection->OnStartAdvise (topic_name, item);
396 if (ok)
75ed1d15 397 codeco->Write8(IPC_ADVISE_START);
f4ada568 398 else
75ed1d15 399 codeco->Write8(IPC_FAIL);
f4ada568
GL
400
401 break;
402 }
403 case IPC_ADVISE_STOP: {
75ed1d15 404 item = codeci->ReadString();
f4ada568
GL
405
406 bool ok = connection->OnStopAdvise (topic_name, item);
407 if (ok)
75ed1d15 408 codeco->Write8(IPC_ADVISE_STOP);
f4ada568 409 else
75ed1d15 410 codeco->Write8(IPC_FAIL);
f4ada568
GL
411
412 break;
413 }
414 case IPC_POKE: {
0d2a2b60 415 wxIPCFormat format;
f4ada568 416 size_t size;
783b6cfd 417 wxChar *data;
f4ada568 418
75ed1d15 419 item = codeci->ReadString();
0d2a2b60 420 format = (wxIPCFormat)codeci->Read8();
75ed1d15 421 size = codeci->Read32();
783b6cfd 422 data = new wxChar[size];
fae05df5 423 sockstrm->Read(data, size);
f4ada568
GL
424
425 connection->OnPoke (topic_name, item, data, size, format);
426
427 delete [] data;
428
429 break;
430 }
431 case IPC_REQUEST: {
0d2a2b60 432 wxIPCFormat format;
f4ada568 433
75ed1d15 434 item = codeci->ReadString();
0d2a2b60 435 format = (wxIPCFormat)codeci->Read8();
f4ada568
GL
436
437 int user_size = -1;
438 char *user_data = connection->OnRequest (topic_name, item, &user_size, format);
439
440 if (user_data) {
75ed1d15 441 codeco->Write8(IPC_REQUEST_REPLY);
f4ada568 442 if (user_size != -1) {
75ed1d15 443 codeco->Write32(user_size);
fae05df5 444 sockstrm->Write(user_data, user_size);
f4ada568 445 } else
75ed1d15 446 codeco->WriteString(user_data);
f4ada568 447 } else
75ed1d15 448 codeco->Write8(IPC_FAIL);
f4ada568
GL
449
450 break;
451 }
452 case IPC_DISCONNECT: {
453 sock.Close();
454 connection->OnDisconnect();
455 break;
456 }
457 default:
75ed1d15 458 codeco->Write8(IPC_FAIL);
f4ada568
GL
459 break;
460 }
461}
462
463void Server_OnRequest(wxSocketServer& server,
aa8fb7a0 464 wxSocketNotify evt, char *cdata)
f4ada568
GL
465{
466 wxTCPServer *ipcserv = (wxTCPServer *)cdata;
467 wxSocketStream *stream;
75ed1d15
GL
468 wxDataInputStream *codeci;
469 wxDataOutputStream *codeco;
f4ada568 470
aa8fb7a0 471 if (evt != wxSOCKET_CONNECTION)
f4ada568
GL
472 return;
473
474 /* Accept the connection, getting a new socket */
475 wxSocketBase *sock = server.Accept();
476 sock->Notify(FALSE);
aa8fb7a0 477 sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
f4ada568
GL
478
479 stream = new wxSocketStream(*sock);
75ed1d15
GL
480 codeci = new wxDataInputStream(*stream);
481 codeco = new wxDataOutputStream(*stream);
f4ada568
GL
482
483 if (!sock->Ok())
484 return;
485
486 int msg;
75ed1d15 487 msg = codeci->Read8();
f4ada568
GL
488
489 if (msg == IPC_CONNECT) {
490 wxString topic_name;
75ed1d15 491 topic_name = codeci->ReadString();
f4ada568
GL
492
493 /* Register new socket with the notifier */
494 wxTCPConnection *new_connection =
495 (wxTCPConnection *)ipcserv->OnAcceptConnection (topic_name);
496 if (new_connection) {
497 if (!new_connection->IsKindOf(CLASSINFO(wxTCPConnection))) {
498 delete new_connection;
75ed1d15 499 codeco->Write8(IPC_FAIL);
f4ada568
GL
500 return;
501 }
502 // Acknowledge success
75ed1d15 503 codeco->Write8(IPC_CONNECT);
f4ada568
GL
504
505 new_connection->m_topic = topic_name;
506 new_connection->m_sockstrm = stream;
75ed1d15
GL
507 new_connection->m_codeci = codeci;
508 new_connection->m_codeco = codeco;
f4ada568
GL
509 sock->Callback(Client_OnRequest);
510 sock->CallbackData((char *)new_connection);
511 sock->Notify(TRUE);
512 } else {
513 // Send failure message
75ed1d15 514 codeco->Write8(IPC_FAIL);
f4ada568
GL
515 }
516 }
517}
35a4dab7
GL
518
519#endif
520 // wxUSE_SOCKETS