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