]> git.saurik.com Git - wxWidgets.git/blob - src/common/sckipc.cpp
implemented better paths handling: dir1/../dir2/file is replaced by dir2/file
[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
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_NONE
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 delete connection;
130 // and fall through to delete everything else
131 }
132 else
133 {
134 connection->m_topic = topic;
135 connection->m_sock = client;
136 connection->m_sockstrm = stream;
137 connection->m_codeci = data_is;
138 connection->m_codeco = data_os;
139 client->Callback(Client_OnRequest);
140 client->CallbackData((char *)connection);
141 client->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
142 client->Notify(TRUE);
143 return connection;
144 }
145 }
146 }
147 }
148
149 // something went wrong
150 delete data_is;
151 delete data_os;
152 delete stream;
153 delete client;
154 return NULL;
155 }
156
157 wxConnectionBase *wxTCPClient::OnMakeConnection()
158 {
159 return new wxTCPConnection;
160 }
161
162 // ---------------------------------------------------------------------------
163 // wxTCPServer
164 // ---------------------------------------------------------------------------
165
166 wxTCPServer::wxTCPServer ()
167 : wxServerBase()
168 {
169 }
170
171 bool wxTCPServer::Create(const wxString& server_name)
172 {
173 wxSocketServer *server;
174
175 // wxIPV4address defaults to INADDR_ANY:0
176 wxIPV4address addr;
177 addr.Service(server_name);
178
179 // Create a socket listening on specified port
180 server = new wxSocketServer(addr, SCKIPC_FLAGS);
181 server->Callback((wxSocketBase::wxSockCbk)Server_OnRequest);
182 server->CallbackData((char *)this);
183 server->SetNotify(wxSOCKET_CONNECTION_FLAG);
184 server->Notify(TRUE);
185
186 return TRUE;
187 }
188
189 wxTCPServer::~wxTCPServer()
190 {
191 }
192
193 wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) )
194 {
195 return new wxTCPConnection();
196 }
197
198 // ---------------------------------------------------------------------------
199 // wxTCPConnection
200 // ---------------------------------------------------------------------------
201
202 wxTCPConnection::wxTCPConnection ()
203 : wxConnectionBase(),
204 m_sock(NULL), m_sockstrm(NULL), m_codeci(NULL), m_codeco(NULL)
205 {
206 }
207
208 wxTCPConnection::wxTCPConnection(char * WXUNUSED(buffer), int WXUNUSED(size))
209 {
210 }
211
212 wxTCPConnection::~wxTCPConnection ()
213 {
214 wxDELETE(m_sock);
215 wxDELETE(m_codeci);
216 wxDELETE(m_codeco);
217 wxDELETE(m_sockstrm);
218 }
219
220 void wxTCPConnection::Compress(bool WXUNUSED(on))
221 {
222 // Use wxLZWStream
223 }
224
225 // Calls that CLIENT can make.
226 bool wxTCPConnection::Disconnect ()
227 {
228 // Send the the disconnect message to the peer.
229 m_codeco->Write8(IPC_DISCONNECT);
230 m_sock->Close();
231
232 return TRUE;
233 }
234
235 bool wxTCPConnection::Execute(const wxChar *data, int size, wxIPCFormat format)
236 {
237 if (!m_sock->IsConnected())
238 return FALSE;
239
240 // Prepare EXECUTE message
241 m_codeco->Write8(IPC_EXECUTE);
242 m_codeco->Write8(format);
243
244 if (size < 0)
245 size = strlen(data) + 1; // includes final NUL
246
247 m_codeco->Write32(size);
248 m_sockstrm->Write(data, size);
249
250 return TRUE;
251 }
252
253 char *wxTCPConnection::Request (const wxString& item, int *size, wxIPCFormat format)
254 {
255 if (!m_sock->IsConnected())
256 return NULL;
257
258 m_codeco->Write8(IPC_REQUEST);
259 m_codeco->WriteString(item);
260 m_codeco->Write8(format);
261
262 // If Unpack doesn't initialize it.
263 int ret;
264
265 ret = m_codeci->Read8();
266 if (ret == IPC_FAIL)
267 return NULL;
268 else
269 {
270 size_t s;
271 char *data = NULL;
272
273 s = m_codeci->Read32();
274 data = new char[s];
275 m_sockstrm->Read(data, s);
276
277 if (size)
278 *size = s;
279 return data;
280 }
281 }
282
283 bool wxTCPConnection::Poke (const wxString& item, wxChar *data, int size, wxIPCFormat format)
284 {
285 if (!m_sock->IsConnected())
286 return FALSE;
287
288 m_codeco->Write8(IPC_POKE);
289 m_codeco->WriteString(item);
290 m_codeco->Write8(format);
291
292 if (size < 0)
293 size = strlen(data) + 1; // includes final NUL
294
295 m_codeco->Write32(size);
296 m_sockstrm->Write(data, size);
297
298 return TRUE;
299 }
300
301 bool wxTCPConnection::StartAdvise (const wxString& item)
302 {
303 int ret;
304
305 if (!m_sock->IsConnected())
306 return FALSE;
307
308 m_codeco->Write8(IPC_ADVISE_START);
309 m_codeco->WriteString(item);
310
311 ret = m_codeci->Read8();
312
313 if (ret != IPC_FAIL)
314 return TRUE;
315 else
316 return FALSE;
317 }
318
319 bool wxTCPConnection::StopAdvise (const wxString& item)
320 {
321 int msg;
322
323 if (!m_sock->IsConnected())
324 return FALSE;
325
326 m_codeco->Write8(IPC_ADVISE_STOP);
327 m_codeco->WriteString(item);
328
329 msg = m_codeci->Read8();
330
331 if (msg != IPC_FAIL)
332 return TRUE;
333 else
334 return FALSE;
335 }
336
337 // Calls that SERVER can make
338 bool wxTCPConnection::Advise (const wxString& item,
339 wxChar *data, int size, wxIPCFormat format)
340 {
341 if (!m_sock->IsConnected())
342 return FALSE;
343
344 m_codeco->Write8(IPC_ADVISE);
345 m_codeco->WriteString(item);
346 m_codeco->Write8(format);
347
348 if (size < 0)
349 size = strlen(data) + 1; // includes final NUL
350
351 m_codeco->Write32(size);
352 m_sockstrm->Write(data, size);
353
354 return TRUE;
355 }
356
357 void Client_OnRequest(wxSocketBase& sock, wxSocketNotify evt,
358 char *cdata)
359 {
360 int msg = 0;
361 wxTCPConnection *connection = (wxTCPConnection *)cdata;
362 wxDataInputStream *codeci;
363 wxDataOutputStream *codeco;
364 wxSocketStream *sockstrm;
365 wxString topic_name = connection->m_topic;
366 wxString item;
367
368 // The socket handler signals us that we lost the connection: destroy all.
369 if (evt == wxSOCKET_LOST)
370 {
371 sock.Close();
372 connection->OnDisconnect();
373 return;
374 }
375
376 // Receive message number.
377 codeci = connection->m_codeci;
378 codeco = connection->m_codeco;
379 sockstrm = connection->m_sockstrm;
380 msg = codeci->Read8();
381
382 switch (msg)
383 {
384 case IPC_EXECUTE:
385 {
386 char *data;
387 size_t size;
388 wxIPCFormat format;
389
390 format = (wxIPCFormat)codeci->Read8();
391 size = codeci->Read32();
392 data = new char[size];
393 sockstrm->Read(data, size);
394
395 connection->OnExecute (topic_name, data, size, format);
396
397 delete [] data;
398 break;
399 }
400 case IPC_ADVISE:
401 {
402 char *data;
403 size_t size;
404 wxIPCFormat format;
405
406 item = codeci->ReadString();
407 format = (wxIPCFormat)codeci->Read8();
408 size = codeci->Read32();
409 data = new char[size];
410 sockstrm->Read(data, size);
411
412 connection->OnAdvise (topic_name, item, data, size, format);
413
414 delete [] data;
415 break;
416 }
417 case IPC_ADVISE_START:
418 {
419 item = codeci->ReadString();
420
421 bool ok = connection->OnStartAdvise (topic_name, item);
422 if (ok)
423 codeco->Write8(IPC_ADVISE_START);
424 else
425 codeco->Write8(IPC_FAIL);
426
427 break;
428 }
429 case IPC_ADVISE_STOP:
430 {
431 item = codeci->ReadString();
432
433 bool ok = connection->OnStopAdvise (topic_name, item);
434 if (ok)
435 codeco->Write8(IPC_ADVISE_STOP);
436 else
437 codeco->Write8(IPC_FAIL);
438
439 break;
440 }
441 case IPC_POKE:
442 {
443 wxIPCFormat format;
444 size_t size;
445 wxChar *data;
446
447 item = codeci->ReadString();
448 format = (wxIPCFormat)codeci->Read8();
449 size = codeci->Read32();
450 data = new wxChar[size];
451 sockstrm->Read(data, size);
452
453 connection->OnPoke (topic_name, item, data, size, format);
454
455 delete [] data;
456
457 break;
458 }
459 case IPC_REQUEST:
460 {
461 wxIPCFormat format;
462
463 item = codeci->ReadString();
464 format = (wxIPCFormat)codeci->Read8();
465
466 int user_size = -1;
467 char *user_data = connection->OnRequest (topic_name, item, &user_size, format);
468
469 if (user_data)
470 {
471 codeco->Write8(IPC_REQUEST_REPLY);
472
473 if (user_size == -1)
474 user_size = strlen(user_data) + 1; // includes final NUL
475
476 codeco->Write32(user_size);
477 sockstrm->Write(user_data, user_size);
478 }
479 else
480 codeco->Write8(IPC_FAIL);
481
482 break;
483 }
484 case IPC_DISCONNECT:
485 {
486 sock.Close();
487 connection->OnDisconnect();
488 break;
489 }
490 default:
491 codeco->Write8(IPC_FAIL);
492 break;
493 }
494 }
495
496 void Server_OnRequest(wxSocketServer& server,
497 wxSocketNotify evt, char *cdata)
498 {
499 wxTCPServer *ipcserv = (wxTCPServer *)cdata;
500 wxSocketStream *stream;
501 wxDataInputStream *codeci;
502 wxDataOutputStream *codeco;
503
504 if (evt != wxSOCKET_CONNECTION)
505 return;
506
507 /* Accept the connection, getting a new socket */
508 wxSocketBase *sock = server.Accept();
509 if (!sock->Ok())
510 return;
511
512 stream = new wxSocketStream(*sock);
513 codeci = new wxDataInputStream(*stream);
514 codeco = new wxDataOutputStream(*stream);
515
516 int msg;
517 msg = codeci->Read8();
518
519 if (msg == IPC_CONNECT)
520 {
521 wxString topic_name;
522 topic_name = codeci->ReadString();
523
524 /* Register new socket with the notifier */
525 wxTCPConnection *new_connection =
526 (wxTCPConnection *)ipcserv->OnAcceptConnection (topic_name);
527 if (new_connection)
528 {
529 if (!new_connection->IsKindOf(CLASSINFO(wxTCPConnection)))
530 {
531 delete new_connection;
532 codeco->Write8(IPC_FAIL);
533 return;
534 }
535 // Acknowledge success
536 codeco->Write8(IPC_CONNECT);
537 new_connection->m_topic = topic_name;
538 new_connection->m_sock = sock;
539 new_connection->m_sockstrm = stream;
540 new_connection->m_codeci = codeci;
541 new_connection->m_codeco = codeco;
542 sock->Callback(Client_OnRequest);
543 sock->CallbackData((char *)new_connection);
544 sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
545 sock->Notify(TRUE);
546 }
547 else
548 {
549 // Send failure message
550 codeco->Write8(IPC_FAIL);
551 }
552 }
553 }
554
555 #endif
556 // wxUSE_SOCKETS