]>
Commit | Line | Data |
---|---|---|
f4ada568 GL |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: sckipc.cpp | |
3 | // Purpose: Interprocess communication implementation (wxSocket version) | |
0834112f | 4 | // Author: Julian Smart |
f4ada568 | 5 | // Modified by: Guilhem Lavaux (big rewrite) May 1997, 1998 |
0834112f | 6 | // Guillermo Rodriguez (updated for wxSocket v2) Jan 2000 |
f4ada568 GL |
7 | // Created: 1993 |
8 | // RCS-ID: $Id$ | |
0834112f GRG |
9 | // Copyright: (c) Julian Smart 1993 |
10 | // (c) Guilhem Lavaux 1997, 1998 | |
11 | // (c) 2000 Guillermo Rodriguez <guille@iies.es> | |
f4ada568 GL |
12 | // Licence: wxWindows license |
13 | ///////////////////////////////////////////////////////////////////////////// | |
14 | ||
15 | #ifdef __GNUG__ | |
16 | #pragma implementation "sckipc.h" | |
17 | #endif | |
18 | ||
fcc6dddd JS |
19 | // For compilers that support precompilation, includes "wx.h". |
20 | #include "wx/wxprec.h" | |
f4ada568 | 21 | |
fcc6dddd JS |
22 | #ifdef __BORLANDC__ |
23 | #pragma hdrstop | |
f4ada568 GL |
24 | #endif |
25 | ||
fcc6dddd | 26 | #ifndef WX_PRECOMP |
07e829dc | 27 | #include "wx/defs.h" |
fcc6dddd JS |
28 | #endif |
29 | ||
07e829dc GRG |
30 | #if wxUSE_SOCKETS |
31 | ||
fcc6dddd JS |
32 | #include <stdlib.h> |
33 | #include <stdio.h> | |
34 | ||
f4ada568 GL |
35 | #include "wx/socket.h" |
36 | #include "wx/sckipc.h" | |
0834112f | 37 | #include "wx/log.h" |
f4ada568 GL |
38 | |
39 | #ifdef __BORLANDC__ | |
40 | #pragma hdrstop | |
41 | #endif | |
42 | ||
f4ada568 GL |
43 | IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase) |
44 | IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase) | |
07e829dc | 45 | IMPLEMENT_CLASS(wxTCPConnection, wxConnectionBase) |
f4ada568 GL |
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, | |
07e829dc GRG |
66 | wxSocketNotify evt, |
67 | char *cdata); | |
f4ada568 | 68 | void Client_OnRequest(wxSocketBase& sock, |
07e829dc GRG |
69 | wxSocketNotify evt, |
70 | char *cdata); | |
f4ada568 GL |
71 | |
72 | // --------------------------------------------------------------------------- | |
73 | // wxTCPClient | |
74 | // --------------------------------------------------------------------------- | |
75 | ||
6e31e940 | 76 | wxTCPClient::wxTCPClient () |
f4ada568 GL |
77 | : wxClientBase() |
78 | { | |
79 | } | |
80 | ||
6e31e940 | 81 | wxTCPClient::~wxTCPClient () |
f4ada568 GL |
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 | { | |
a324a7bc | 96 | wxSocketClient *client = new wxSocketClient(); |
f4ada568 | 97 | wxSocketStream *stream = new wxSocketStream(*client); |
0834112f GRG |
98 | wxDataInputStream *data_is = new wxDataInputStream(*stream); |
99 | wxDataOutputStream *data_os = new wxDataOutputStream(*stream); | |
100 | ||
101 | wxIPV4address addr; | |
f4ada568 GL |
102 | addr.Service(server_name); |
103 | addr.Hostname(host); | |
104 | ||
0834112f GRG |
105 | if (client->Connect(addr)) |
106 | { | |
107 | unsigned char msg; | |
f4ada568 | 108 | |
0834112f GRG |
109 | // Send topic name, and enquire whether this has succeeded |
110 | data_os->Write8(IPC_CONNECT); | |
111 | data_os->WriteString(topic); | |
f4ada568 | 112 | |
0834112f GRG |
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 | } | |
f4ada568 | 140 | } |
f4ada568 | 141 | } |
f4ada568 | 142 | } |
0834112f GRG |
143 | |
144 | // something went wrong | |
145 | delete data_is; | |
146 | delete data_os; | |
147 | delete stream; | |
148 | delete client; | |
149 | return NULL; | |
f4ada568 GL |
150 | } |
151 | ||
152 | wxConnectionBase *wxTCPClient::OnMakeConnection() | |
153 | { | |
154 | return new wxTCPConnection; | |
155 | } | |
156 | ||
157 | // --------------------------------------------------------------------------- | |
158 | // wxTCPServer | |
159 | // --------------------------------------------------------------------------- | |
160 | ||
6e31e940 | 161 | wxTCPServer::wxTCPServer () |
f4ada568 GL |
162 | : wxServerBase() |
163 | { | |
164 | } | |
165 | ||
166 | bool wxTCPServer::Create(const wxString& server_name) | |
167 | { | |
168 | wxIPV4address addr; | |
f4ada568 GL |
169 | wxSocketServer *server; |
170 | ||
0834112f | 171 | addr.LocalHost(); // GRG |
f4ada568 GL |
172 | addr.Service(server_name); |
173 | ||
174 | // Create a socket listening on specified port | |
a324a7bc | 175 | server = new wxSocketServer(addr); |
f4ada568 | 176 | server->Callback((wxSocketBase::wxSockCbk)Server_OnRequest); |
f4ada568 | 177 | server->CallbackData((char *)this); |
0834112f GRG |
178 | server->SetNotify(wxSOCKET_CONNECTION_FLAG); |
179 | server->Notify(TRUE); // GRG | |
f4ada568 GL |
180 | |
181 | return TRUE; | |
182 | } | |
183 | ||
6e31e940 | 184 | wxTCPServer::~wxTCPServer() |
f4ada568 GL |
185 | { |
186 | } | |
187 | ||
e22036dc | 188 | wxConnectionBase *wxTCPServer::OnAcceptConnection( const wxString& WXUNUSED(topic) ) |
f4ada568 GL |
189 | { |
190 | return new wxTCPConnection(); | |
191 | } | |
192 | ||
193 | // --------------------------------------------------------------------------- | |
194 | // wxTCPConnection | |
195 | // --------------------------------------------------------------------------- | |
196 | ||
6e31e940 | 197 | wxTCPConnection::wxTCPConnection () |
f4ada568 | 198 | : wxConnectionBase(), |
75ed1d15 | 199 | m_sock(NULL), m_sockstrm(NULL), m_codeci(NULL), m_codeco(NULL) |
f4ada568 GL |
200 | { |
201 | } | |
202 | ||
6e31e940 | 203 | wxTCPConnection::wxTCPConnection(char * WXUNUSED(buffer), int WXUNUSED(size)) |
7921cf2b JS |
204 | { |
205 | } | |
206 | ||
6e31e940 | 207 | wxTCPConnection::~wxTCPConnection () |
f4ada568 GL |
208 | { |
209 | wxDELETE(m_sock); | |
75ed1d15 GL |
210 | wxDELETE(m_codeci); |
211 | wxDELETE(m_codeco); | |
f4ada568 GL |
212 | wxDELETE(m_sockstrm); |
213 | } | |
214 | ||
cb43b372 | 215 | void wxTCPConnection::Compress(bool WXUNUSED(on)) |
f4ada568 GL |
216 | { |
217 | // Use wxLZWStream | |
218 | } | |
219 | ||
220 | // Calls that CLIENT can make. | |
6e31e940 | 221 | bool wxTCPConnection::Disconnect () |
f4ada568 GL |
222 | { |
223 | // Send the the disconnect message to the peer. | |
75ed1d15 | 224 | m_codeco->Write8(IPC_DISCONNECT); |
f4ada568 GL |
225 | m_sock->Close(); |
226 | ||
227 | return TRUE; | |
228 | } | |
229 | ||
0834112f | 230 | bool wxTCPConnection::Execute(const wxChar *data, int size, wxIPCFormat format) |
f4ada568 GL |
231 | { |
232 | if (!m_sock->IsConnected()) | |
233 | return FALSE; | |
234 | ||
235 | // Prepare EXECUTE message | |
75ed1d15 GL |
236 | m_codeco->Write8(IPC_EXECUTE); |
237 | m_codeco->Write8(format); | |
0834112f | 238 | |
f4ada568 | 239 | if (size < 0) |
0834112f GRG |
240 | size = strlen(data) + 1; // includes final NUL |
241 | ||
242 | m_codeco->Write32(size); | |
243 | m_sockstrm->Write(data, size); | |
f4ada568 GL |
244 | |
245 | return TRUE; | |
246 | } | |
247 | ||
0d2a2b60 | 248 | char *wxTCPConnection::Request (const wxString& item, int *size, wxIPCFormat format) |
f4ada568 GL |
249 | { |
250 | if (!m_sock->IsConnected()) | |
251 | return NULL; | |
252 | ||
75ed1d15 GL |
253 | m_codeco->Write8(IPC_REQUEST); |
254 | m_codeco->WriteString(item); | |
255 | m_codeco->Write8(format); | |
f4ada568 GL |
256 | |
257 | // If Unpack doesn't initialize it. | |
258 | int ret; | |
259 | ||
75ed1d15 | 260 | ret = m_codeci->Read8(); |
f4ada568 GL |
261 | if (ret == IPC_FAIL) |
262 | return NULL; | |
0834112f GRG |
263 | else |
264 | { | |
f4ada568 GL |
265 | size_t s; |
266 | char *data = NULL; | |
267 | ||
75ed1d15 | 268 | s = m_codeci->Read32(); |
f4ada568 | 269 | data = new char[s]; |
fae05df5 | 270 | m_sockstrm->Read(data, s); |
f4ada568 GL |
271 | |
272 | if (size) | |
273 | *size = s; | |
274 | return data; | |
275 | } | |
276 | } | |
277 | ||
783b6cfd | 278 | bool wxTCPConnection::Poke (const wxString& item, wxChar *data, int size, wxIPCFormat format) |
f4ada568 GL |
279 | { |
280 | if (!m_sock->IsConnected()) | |
281 | return FALSE; | |
282 | ||
75ed1d15 GL |
283 | m_codeco->Write8(IPC_POKE); |
284 | m_codeco->WriteString(item); | |
285 | m_codeco->Write8(format); | |
0834112f | 286 | |
f4ada568 | 287 | if (size < 0) |
0834112f GRG |
288 | size = strlen(data) + 1; // includes final NUL |
289 | ||
290 | m_codeco->Write32(size); | |
291 | m_sockstrm->Write(data, size); | |
f4ada568 GL |
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 | ||
75ed1d15 GL |
303 | m_codeco->Write8(IPC_ADVISE_START); |
304 | m_codeco->WriteString(item); | |
f4ada568 | 305 | |
75ed1d15 | 306 | ret = m_codeci->Read8(); |
f4ada568 GL |
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 | ||
75ed1d15 GL |
321 | m_codeco->Write8(IPC_ADVISE_STOP); |
322 | m_codeco->WriteString(item); | |
f4ada568 | 323 | |
75ed1d15 | 324 | msg = m_codeci->Read8(); |
f4ada568 GL |
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, | |
783b6cfd | 334 | wxChar *data, int size, wxIPCFormat format) |
f4ada568 GL |
335 | { |
336 | if (!m_sock->IsConnected()) | |
337 | return FALSE; | |
338 | ||
75ed1d15 GL |
339 | m_codeco->Write8(IPC_ADVISE); |
340 | m_codeco->WriteString(item); | |
341 | m_codeco->Write8(format); | |
0834112f | 342 | |
f4ada568 | 343 | if (size < 0) |
0834112f GRG |
344 | size = strlen(data) + 1; // includes final NUL |
345 | ||
346 | m_codeco->Write32(size); | |
347 | m_sockstrm->Write(data, size); | |
f4ada568 GL |
348 | |
349 | return TRUE; | |
350 | } | |
351 | ||
aa8fb7a0 | 352 | void Client_OnRequest(wxSocketBase& sock, wxSocketNotify evt, |
f4ada568 GL |
353 | char *cdata) |
354 | { | |
355 | int msg = 0; | |
356 | wxTCPConnection *connection = (wxTCPConnection *)cdata; | |
75ed1d15 GL |
357 | wxDataInputStream *codeci; |
358 | wxDataOutputStream *codeco; | |
fae05df5 | 359 | wxSocketStream *sockstrm; |
f4ada568 GL |
360 | wxString topic_name = connection->m_topic; |
361 | wxString item; | |
362 | ||
363 | // The socket handler signals us that we lost the connection: destroy all. | |
0834112f GRG |
364 | if (evt == wxSOCKET_LOST) |
365 | { | |
f4ada568 GL |
366 | sock.Close(); |
367 | connection->OnDisconnect(); | |
368 | return; | |
369 | } | |
370 | ||
371 | // Receive message number. | |
75ed1d15 GL |
372 | codeci = connection->m_codeci; |
373 | codeco = connection->m_codeco; | |
fae05df5 | 374 | sockstrm = connection->m_sockstrm; |
75ed1d15 | 375 | msg = codeci->Read8(); |
f4ada568 | 376 | |
0834112f GRG |
377 | switch (msg) |
378 | { | |
379 | case IPC_EXECUTE: | |
380 | { | |
f4ada568 GL |
381 | char *data; |
382 | size_t size; | |
0d2a2b60 | 383 | wxIPCFormat format; |
f4ada568 | 384 | |
0d2a2b60 | 385 | format = (wxIPCFormat)codeci->Read8(); |
75ed1d15 | 386 | size = codeci->Read32(); |
f4ada568 | 387 | data = new char[size]; |
fae05df5 | 388 | sockstrm->Read(data, size); |
f4ada568 GL |
389 | |
390 | connection->OnExecute (topic_name, data, size, format); | |
391 | ||
392 | delete [] data; | |
393 | break; | |
394 | } | |
0834112f GRG |
395 | case IPC_ADVISE: |
396 | { | |
f4ada568 GL |
397 | char *data; |
398 | size_t size; | |
0d2a2b60 | 399 | wxIPCFormat format; |
f4ada568 | 400 | |
75ed1d15 | 401 | item = codeci->ReadString(); |
0d2a2b60 | 402 | format = (wxIPCFormat)codeci->Read8(); |
75ed1d15 | 403 | size = codeci->Read32(); |
f4ada568 | 404 | data = new char[size]; |
fae05df5 | 405 | sockstrm->Read(data, size); |
f4ada568 GL |
406 | |
407 | connection->OnAdvise (topic_name, item, data, size, format); | |
408 | ||
409 | delete [] data; | |
410 | break; | |
411 | } | |
0834112f GRG |
412 | case IPC_ADVISE_START: |
413 | { | |
75ed1d15 | 414 | item = codeci->ReadString(); |
f4ada568 GL |
415 | |
416 | bool ok = connection->OnStartAdvise (topic_name, item); | |
417 | if (ok) | |
75ed1d15 | 418 | codeco->Write8(IPC_ADVISE_START); |
f4ada568 | 419 | else |
75ed1d15 | 420 | codeco->Write8(IPC_FAIL); |
f4ada568 GL |
421 | |
422 | break; | |
423 | } | |
0834112f GRG |
424 | case IPC_ADVISE_STOP: |
425 | { | |
75ed1d15 | 426 | item = codeci->ReadString(); |
f4ada568 GL |
427 | |
428 | bool ok = connection->OnStopAdvise (topic_name, item); | |
429 | if (ok) | |
75ed1d15 | 430 | codeco->Write8(IPC_ADVISE_STOP); |
f4ada568 | 431 | else |
75ed1d15 | 432 | codeco->Write8(IPC_FAIL); |
f4ada568 GL |
433 | |
434 | break; | |
435 | } | |
0834112f GRG |
436 | case IPC_POKE: |
437 | { | |
0d2a2b60 | 438 | wxIPCFormat format; |
f4ada568 | 439 | size_t size; |
783b6cfd | 440 | wxChar *data; |
f4ada568 | 441 | |
75ed1d15 | 442 | item = codeci->ReadString(); |
0d2a2b60 | 443 | format = (wxIPCFormat)codeci->Read8(); |
75ed1d15 | 444 | size = codeci->Read32(); |
783b6cfd | 445 | data = new wxChar[size]; |
fae05df5 | 446 | sockstrm->Read(data, size); |
f4ada568 GL |
447 | |
448 | connection->OnPoke (topic_name, item, data, size, format); | |
449 | ||
450 | delete [] data; | |
451 | ||
452 | break; | |
453 | } | |
0834112f GRG |
454 | case IPC_REQUEST: |
455 | { | |
0d2a2b60 | 456 | wxIPCFormat format; |
f4ada568 | 457 | |
75ed1d15 | 458 | item = codeci->ReadString(); |
0d2a2b60 | 459 | format = (wxIPCFormat)codeci->Read8(); |
f4ada568 GL |
460 | |
461 | int user_size = -1; | |
462 | char *user_data = connection->OnRequest (topic_name, item, &user_size, format); | |
463 | ||
0834112f GRG |
464 | if (user_data) |
465 | { | |
75ed1d15 | 466 | codeco->Write8(IPC_REQUEST_REPLY); |
0834112f GRG |
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 | |
75ed1d15 | 475 | codeco->Write8(IPC_FAIL); |
f4ada568 GL |
476 | |
477 | break; | |
478 | } | |
0834112f GRG |
479 | case IPC_DISCONNECT: |
480 | { | |
f4ada568 GL |
481 | sock.Close(); |
482 | connection->OnDisconnect(); | |
483 | break; | |
484 | } | |
485 | default: | |
75ed1d15 | 486 | codeco->Write8(IPC_FAIL); |
f4ada568 GL |
487 | break; |
488 | } | |
489 | } | |
490 | ||
491 | void Server_OnRequest(wxSocketServer& server, | |
aa8fb7a0 | 492 | wxSocketNotify evt, char *cdata) |
f4ada568 GL |
493 | { |
494 | wxTCPServer *ipcserv = (wxTCPServer *)cdata; | |
495 | wxSocketStream *stream; | |
75ed1d15 GL |
496 | wxDataInputStream *codeci; |
497 | wxDataOutputStream *codeco; | |
f4ada568 | 498 | |
aa8fb7a0 | 499 | if (evt != wxSOCKET_CONNECTION) |
f4ada568 GL |
500 | return; |
501 | ||
502 | /* Accept the connection, getting a new socket */ | |
503 | wxSocketBase *sock = server.Accept(); | |
0834112f GRG |
504 | if (!sock->Ok()) |
505 | return; | |
f4ada568 GL |
506 | |
507 | stream = new wxSocketStream(*sock); | |
75ed1d15 GL |
508 | codeci = new wxDataInputStream(*stream); |
509 | codeco = new wxDataOutputStream(*stream); | |
f4ada568 | 510 | |
f4ada568 | 511 | int msg; |
75ed1d15 | 512 | msg = codeci->Read8(); |
f4ada568 | 513 | |
0834112f GRG |
514 | if (msg == IPC_CONNECT) |
515 | { | |
f4ada568 | 516 | wxString topic_name; |
75ed1d15 | 517 | topic_name = codeci->ReadString(); |
f4ada568 GL |
518 | |
519 | /* Register new socket with the notifier */ | |
520 | wxTCPConnection *new_connection = | |
521 | (wxTCPConnection *)ipcserv->OnAcceptConnection (topic_name); | |
0834112f GRG |
522 | if (new_connection) |
523 | { | |
524 | if (!new_connection->IsKindOf(CLASSINFO(wxTCPConnection))) | |
525 | { | |
f4ada568 | 526 | delete new_connection; |
75ed1d15 | 527 | codeco->Write8(IPC_FAIL); |
f4ada568 GL |
528 | return; |
529 | } | |
530 | // Acknowledge success | |
75ed1d15 | 531 | codeco->Write8(IPC_CONNECT); |
f4ada568 | 532 | new_connection->m_topic = topic_name; |
0834112f | 533 | new_connection->m_sock = sock; |
f4ada568 | 534 | new_connection->m_sockstrm = stream; |
75ed1d15 GL |
535 | new_connection->m_codeci = codeci; |
536 | new_connection->m_codeco = codeco; | |
f4ada568 GL |
537 | sock->Callback(Client_OnRequest); |
538 | sock->CallbackData((char *)new_connection); | |
0834112f | 539 | sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); |
f4ada568 | 540 | sock->Notify(TRUE); |
0834112f GRG |
541 | } |
542 | else | |
543 | { | |
f4ada568 | 544 | // Send failure message |
75ed1d15 | 545 | codeco->Write8(IPC_FAIL); |
f4ada568 GL |
546 | } |
547 | } | |
548 | } | |
35a4dab7 GL |
549 | |
550 | #endif | |
551 | // wxUSE_SOCKETS |