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