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