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