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