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