]> git.saurik.com Git - wxWidgets.git/blob - src/common/sckipc.cpp
*** empty log message ***
[wxWidgets.git] / src / common / sckipc.cpp
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
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28
29 #include "wx/socket.h"
30 #include "wx/sckipc.h"
31
32 #ifdef __BORLANDC__
33 #pragma hdrstop
34 #endif
35
36 #if !USE_SHARED_LIBRARY
37 IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase)
38 IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase)
39 IMPLEMENT_DYNAMIC_CLASS(wxTCPConnection, wxConnectionBase)
40 #endif
41
42 // It seems to be already defined somewhere in the Xt includes.
43 #ifndef __XT__
44 // Message codes
45 enum {
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
60 void Server_OnRequest(wxSocketServer& server,
61 wxSocketBase::wxRequestEvent evt,
62 char *cdata);
63 void Client_OnRequest(wxSocketBase& sock,
64 wxSocketBase::wxRequestEvent evt,
65 char *cdata);
66
67 // ---------------------------------------------------------------------------
68 // wxTCPClient
69 // ---------------------------------------------------------------------------
70
71 wxTCPClient::wxTCPClient (void)
72 : wxClientBase()
73 {
74 }
75
76 wxTCPClient::~wxTCPClient (void)
77 {
78 }
79
80 bool wxTCPClient::ValidHost(const wxString& host)
81 {
82 wxIPV4address addr;
83
84 return addr.Hostname(host);
85 }
86
87 wxConnectionBase *wxTCPClient::MakeConnection (const wxString& host,
88 const wxString& server_name,
89 const wxString& topic)
90 {
91 wxIPV4address addr;
92 wxSocketHandler *hsock = &wxSocketHandler::Master();
93 wxSocketClient *client = hsock->CreateClient();
94 wxSocketStream *stream = new wxSocketStream(*client);
95 wxDataStream data_s(*stream);
96
97 client->SetNotify(wxSocketBase::REQ_READ | wxSocketBase::REQ_LOST);
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
110 data_s.Write8(IPC_CONNECT);
111 data_s.WriteString(topic);
112
113 msg = data_s.Read8();
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 }
136 return NULL;
137 }
138
139 wxConnectionBase *wxTCPClient::OnMakeConnection()
140 {
141 return new wxTCPConnection;
142 }
143
144 // ---------------------------------------------------------------------------
145 // wxTCPServer
146 // ---------------------------------------------------------------------------
147
148 wxTCPServer::wxTCPServer (void)
149 : wxServerBase()
150 {
151 }
152
153 bool wxTCPServer::Create(const wxString& server_name)
154 {
155 wxIPV4address addr;
156 wxSocketHandler *hsock = &wxSocketHandler::Master();
157 wxSocketServer *server;
158
159 addr.Service(server_name);
160
161 // Create a socket listening on specified port
162 server = hsock->CreateServer(addr);
163 server->Callback((wxSocketBase::wxSockCbk)Server_OnRequest);
164 server->SetNotify(wxSocketBase::REQ_ACCEPT);
165
166 server->CallbackData((char *)this);
167
168 return TRUE;
169 }
170
171 wxTCPServer::~wxTCPServer(void)
172 {
173 }
174
175 wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) )
176 {
177 return new wxTCPConnection();
178 }
179
180 // ---------------------------------------------------------------------------
181 // wxTCPConnection
182 // ---------------------------------------------------------------------------
183
184 wxTCPConnection::wxTCPConnection (void)
185 : wxConnectionBase(),
186 m_sock(NULL), m_sockstrm(NULL), m_codec(NULL)
187 {
188 }
189
190 wxTCPConnection::~wxTCPConnection (void)
191 {
192 wxDELETE(m_sock);
193 wxDELETE(m_codec);
194 wxDELETE(m_sockstrm);
195 }
196
197 void wxTCPConnection::Compress(bool WXUNUSED(on))
198 {
199 // Use wxLZWStream
200 }
201
202 // Calls that CLIENT can make.
203 bool wxTCPConnection::Disconnect (void)
204 {
205 // Send the the disconnect message to the peer.
206 m_codec->Write8(IPC_DISCONNECT);
207 m_sock->Close();
208
209 return TRUE;
210 }
211
212 bool wxTCPConnection::Execute (char *data, int size, wxDataFormat format)
213 {
214 if (!m_sock->IsConnected())
215 return FALSE;
216
217 // Prepare EXECUTE message
218 m_codec->Write8(IPC_EXECUTE);
219 m_codec->Write8(format);
220 if (size < 0)
221 m_codec->WriteString(data);
222 else {
223 m_codec->Write32(size);
224 m_codec->Write(data, size);
225 }
226
227 return TRUE;
228 }
229
230 char *wxTCPConnection::Request (const wxString& item, int *size, wxDataFormat format)
231 {
232 if (!m_sock->IsConnected())
233 return NULL;
234
235 m_codec->Write8(IPC_REQUEST);
236 m_codec->WriteString(item);
237 m_codec->Write8(format);
238
239 // If Unpack doesn't initialize it.
240 int ret;
241
242 ret = m_codec->Read8();
243 if (ret == IPC_FAIL)
244 return NULL;
245 else {
246 size_t s;
247 char *data = NULL;
248
249 s = m_codec->Read32();
250 data = new char[s];
251 m_codec->Read(data, s);
252
253 if (size)
254 *size = s;
255 return data;
256 }
257 }
258
259 bool wxTCPConnection::Poke (const wxString& item, char *data, int size, wxDataFormat format)
260 {
261 if (!m_sock->IsConnected())
262 return FALSE;
263
264 m_codec->Write8(IPC_POKE);
265 m_codec->WriteString(item);
266 m_codec->Write8(format);
267 if (size < 0)
268 m_codec->WriteString(data);
269 else {
270 m_codec->Write32(size);
271 m_codec->Write(data, size);
272 }
273
274 return TRUE;
275 }
276
277 bool wxTCPConnection::StartAdvise (const wxString& item)
278 {
279 int ret;
280
281 if (!m_sock->IsConnected())
282 return FALSE;
283
284 m_codec->Write8(IPC_ADVISE_START);
285 m_codec->WriteString(item);
286
287 ret = m_codec->Read8();
288
289 if (ret != IPC_FAIL)
290 return TRUE;
291 else
292 return FALSE;
293 }
294
295 bool wxTCPConnection::StopAdvise (const wxString& item)
296 {
297 int msg;
298
299 if (!m_sock->IsConnected())
300 return FALSE;
301
302 m_codec->Write8(IPC_ADVISE_STOP);
303 m_codec->WriteString(item);
304
305 msg = m_codec->Read8();
306
307 if (msg != IPC_FAIL)
308 return TRUE;
309 else
310 return FALSE;
311 }
312
313 // Calls that SERVER can make
314 bool wxTCPConnection::Advise (const wxString& item,
315 char *data, int size, wxDataFormat format)
316 {
317 if (!m_sock->IsConnected())
318 return FALSE;
319
320 m_codec->Write8(IPC_ADVISE);
321 m_codec->WriteString(item);
322 m_codec->Write8(format);
323 if (size < 0)
324 m_codec->WriteString(data);
325 else {
326 m_codec->Write32(size);
327 m_codec->Write(data, size);
328 }
329
330 return TRUE;
331 }
332
333 void Client_OnRequest(wxSocketBase& sock, wxSocketBase::wxRequestEvent evt,
334 char *cdata)
335 {
336 int msg = 0;
337 wxTCPConnection *connection = (wxTCPConnection *)cdata;
338 wxDataStream *codec;
339 wxString topic_name = connection->m_topic;
340 wxString item;
341
342 // The socket handler signals us that we lost the connection: destroy all.
343 if (evt == wxSocketBase::EVT_LOST) {
344 sock.Close();
345 connection->OnDisconnect();
346 return;
347 }
348
349 // Receive message number.
350 codec = connection->m_codec;
351 msg = codec->Read8();
352
353 switch (msg) {
354 case IPC_EXECUTE: {
355 char *data;
356 size_t size;
357 wxDataFormat format;
358
359 format = (wxDataFormat)codec->Read8();
360 size = codec->Read32();
361 data = new char[size];
362 codec->Read(data, size);
363
364 connection->OnExecute (topic_name, data, size, format);
365
366 delete [] data;
367 break;
368 }
369 case IPC_ADVISE: {
370 char *data;
371 size_t size;
372 wxDataFormat format;
373
374 item = codec->ReadString();
375 format = (wxDataFormat)codec->Read8();
376 size = codec->Read32();
377 data = new char[size];
378 codec->Read(data, size);
379
380 connection->OnAdvise (topic_name, item, data, size, format);
381
382 delete [] data;
383 break;
384 }
385 case IPC_ADVISE_START: {
386 item = codec->ReadString();
387
388 bool ok = connection->OnStartAdvise (topic_name, item);
389 if (ok)
390 codec->Write8(IPC_ADVISE_START);
391 else
392 codec->Write8(IPC_FAIL);
393
394 break;
395 }
396 case IPC_ADVISE_STOP: {
397 item = codec->ReadString();
398
399 bool ok = connection->OnStopAdvise (topic_name, item);
400 if (ok)
401 codec->Write8(IPC_ADVISE_STOP);
402 else
403 codec->Write8(IPC_FAIL);
404
405 break;
406 }
407 case IPC_POKE: {
408 wxDataFormat format;
409 size_t size;
410 char *data;
411
412 item = codec->ReadString();
413 format = (wxDataFormat)codec->Read8();
414 size = codec->Read32();
415 data = new char[size];
416 codec->Read(data, size);
417
418 connection->OnPoke (topic_name, item, data, size, format);
419
420 delete [] data;
421
422 break;
423 }
424 case IPC_REQUEST: {
425 wxDataFormat format;
426
427 item = codec->ReadString();
428 format = (wxDataFormat)codec->Read8();
429
430 int user_size = -1;
431 char *user_data = connection->OnRequest (topic_name, item, &user_size, format);
432
433 if (user_data) {
434 codec->Write8(IPC_REQUEST_REPLY);
435 if (user_size != -1) {
436 codec->Write32(user_size);
437 codec->Write(user_data, user_size);
438 } else
439 codec->WriteString(user_data);
440 } else
441 codec->Write8(IPC_FAIL);
442
443 break;
444 }
445 case IPC_DISCONNECT: {
446 sock.Close();
447 connection->OnDisconnect();
448 break;
449 }
450 default:
451 codec->Write8(IPC_FAIL);
452 break;
453 }
454 }
455
456 void Server_OnRequest(wxSocketServer& server,
457 wxSocketBase::wxRequestEvent evt, char *cdata)
458 {
459 wxTCPServer *ipcserv = (wxTCPServer *)cdata;
460 wxSocketStream *stream;
461 wxDataStream *codec;
462
463 if (evt != wxSocketBase::EVT_ACCEPT)
464 return;
465
466 /* Accept the connection, getting a new socket */
467 wxSocketBase *sock = server.Accept();
468 sock->Notify(FALSE);
469 sock->SetNotify(wxSocketBase::REQ_READ | wxSocketBase::REQ_LOST);
470
471 stream = new wxSocketStream(*sock);
472 codec = new wxDataStream(*stream);
473
474 if (!sock->Ok())
475 return;
476
477 int msg;
478 msg = codec->Read8();
479
480 if (msg == IPC_CONNECT) {
481 wxString topic_name;
482 topic_name = codec->ReadString();
483
484 /* Register new socket with the notifier */
485 wxTCPConnection *new_connection =
486 (wxTCPConnection *)ipcserv->OnAcceptConnection (topic_name);
487 if (new_connection) {
488 if (!new_connection->IsKindOf(CLASSINFO(wxTCPConnection))) {
489 delete new_connection;
490 codec->Write8(IPC_FAIL);
491 return;
492 }
493 // Acknowledge success
494 codec->Write8(IPC_CONNECT);
495
496 new_connection->m_topic = topic_name;
497 new_connection->m_sockstrm = stream;
498 new_connection->m_codec = codec;
499 sock->Callback(Client_OnRequest);
500 sock->CallbackData((char *)new_connection);
501 sock->Notify(TRUE);
502 } else {
503 // Send failure message
504 codec->Write8(IPC_FAIL);
505 }
506 }
507 }