]> git.saurik.com Git - wxWidgets.git/blame - src/common/socket.cpp
search progress bar has smooth gauge under win95 now
[wxWidgets.git] / src / common / socket.cpp
CommitLineData
56d8adc0 1/////////////////////////////////////////////////////////////////////////////
f4ada568
GL
2// Name: socket.cpp
3// Purpose: Socket handler classes
56d8adc0 4// Authors: Guilhem Lavaux, Guillermo Rodriguez Garcia
f4ada568 5// Created: April 1997
af2fd961 6// Updated: September 1999
a324a7bc 7// Copyright: (C) 1999, 1998, 1997, Guilhem Lavaux
af2fd961 8// (C) 1999, Guillermo Rodriguez Garcia
f4ada568
GL
9// RCS_ID: $Id$
10// License: see wxWindows license
56d8adc0
GRG
11/////////////////////////////////////////////////////////////////////////////
12
384b4373 13#ifdef __GNUG__
f4ada568 14#pragma implementation "socket.h"
f4ada568
GL
15#endif
16
fcc6dddd
JS
17// For compilers that support precompilation, includes "wx.h".
18#include "wx/wxprec.h"
19
20#ifdef __BORLANDC__
21#pragma hdrstop
22#endif
23
35a4dab7
GL
24#if wxUSE_SOCKETS
25
f4ada568
GL
26/////////////////////////////////////////////////////////////////////////////
27// wxWindows headers
28/////////////////////////////////////////////////////////////////////////////
81b92e17 29
dc5c1114 30#include "wx/app.h"
56d8adc0
GRG
31#include "wx/defs.h"
32#include "wx/object.h"
33#include "wx/string.h"
34#include "wx/timer.h"
35#include "wx/utils.h"
36#include "wx/module.h"
37#include "wx/log.h"
58c837a4 38#include "wx/intl.h"
7f555861 39
f4ada568
GL
40/////////////////////////////////////////////////////////////////////////////
41// wxSocket headers
42/////////////////////////////////////////////////////////////////////////////
81b92e17 43
56d8adc0
GRG
44#include "wx/sckaddr.h"
45#include "wx/socket.h"
3b4183d8 46
dc5c1114
GRG
47// discard buffer
48#define MAX_DISCARD_SIZE (10 * 1024)
96db102a 49
dc5c1114 50// what to do within waits
81b92e17 51#define PROCESS_EVENTS() wxYield()
96db102a 52
dc5c1114
GRG
53// use wxPostEvent or not
54#define EXPERIMENTAL_USE_POST 1
55
5c15428b 56
f4ada568
GL
57// --------------------------------------------------------------
58// ClassInfos
59// --------------------------------------------------------------
81b92e17 60
a737331d
GL
61IMPLEMENT_CLASS(wxSocketBase, wxObject)
62IMPLEMENT_CLASS(wxSocketServer, wxSocketBase)
63IMPLEMENT_CLASS(wxSocketClient, wxSocketBase)
dc5c1114 64IMPLEMENT_CLASS(wxDatagramSocket, wxSocketBase)
a737331d 65IMPLEMENT_DYNAMIC_CLASS(wxSocketEvent, wxEvent)
f4ada568 66
56d8adc0
GRG
67class wxSocketState : public wxObject
68{
a324a7bc 69public:
81b92e17
GRG
70 bool m_notify_state;
71 GSocketEventFlags m_neededreq;
72 wxSockFlags m_flags;
73 wxSocketBase::wxSockCbk m_cbk;
74 char *m_cdata;
a324a7bc
GL
75
76public:
77 wxSocketState() : wxObject() {}
78};
79
f4ada568 80// --------------------------------------------------------------
56d8adc0 81// wxSocketBase ctor and dtor
f4ada568 82// --------------------------------------------------------------
56d8adc0 83
a64a02ef 84wxSocketBase::wxSocketBase(wxSockFlags _flags, wxSockType _type) :
f4ada568 85 wxEvtHandler(),
dc5c1114 86 m_socket(NULL), m_evt_handler(NULL), m_id(-1),
96db102a
GRG
87 m_flags(_flags), m_type(_type),
88 m_neededreq(0), m_notify_state(FALSE),
d80d1aba 89 m_connected(FALSE), m_establishing(FALSE),
96db102a
GRG
90 m_reading(FALSE), m_writing(FALSE),
91 m_error(FALSE), m_lcount(0), m_timeout(600), m_states(),
92 m_unread(NULL), m_unrd_size(0), m_unrd_cur(0),
96db102a 93 m_cbk(NULL), m_cdata(NULL)
f4ada568 94{
f4ada568
GL
95}
96
97wxSocketBase::wxSocketBase() :
98 wxEvtHandler(),
dc5c1114 99 m_socket(NULL), m_evt_handler(NULL), m_id(-1),
96db102a
GRG
100 m_flags(NONE), m_type(SOCK_UNINIT),
101 m_neededreq(0), m_notify_state(FALSE),
d80d1aba 102 m_connected(FALSE), m_establishing(FALSE),
96db102a
GRG
103 m_reading(FALSE), m_writing(FALSE),
104 m_error(FALSE), m_lcount(0), m_timeout(600), m_states(),
105 m_unread(NULL), m_unrd_size(0), m_unrd_cur(0),
96db102a 106 m_cbk(NULL), m_cdata(NULL)
f4ada568 107{
f4ada568
GL
108}
109
f4ada568
GL
110wxSocketBase::~wxSocketBase()
111{
f4ada568
GL
112 if (m_unread)
113 free(m_unread);
a737331d 114
56d8adc0 115 // Shutdown and close the socket
a324a7bc 116 Close();
f4ada568 117
56d8adc0 118 // Destroy the GSocket object
a324a7bc
GL
119 if (m_socket)
120 GSocket_destroy(m_socket);
f4ada568
GL
121}
122
123bool wxSocketBase::Close()
124{
81b92e17
GRG
125 // Interrupt pending waits
126 InterruptAllWaits();
127
31528cd3 128 if (m_socket)
8c14576d 129 {
56d8adc0
GRG
130 // Disable callbacks
131 GSocket_UnsetCallback(m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
132 GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG);
f4ada568 133
56d8adc0 134 // Shutdown the connection
a324a7bc 135 GSocket_Shutdown(m_socket);
f4ada568 136 m_connected = FALSE;
d80d1aba 137 m_establishing = FALSE;
f4ada568
GL
138 }
139
140 return TRUE;
141}
142
143// --------------------------------------------------------------
56d8adc0 144// wxSocketBase basic IO operations
f4ada568 145// --------------------------------------------------------------
56d8adc0 146
96db102a
GRG
147// All IO operations {Read, Write, ReadMsg, WriteMsg, Peek,
148// Unread, Discard} update m_error and m_lcount.
149//
150// TODO: Should Connect, Accept and AcceptWith update m_error?
17aa2bec 151
56d8adc0
GRG
152class _wxSocketInternalTimer: public wxTimer
153{
154public:
39b91eca 155 int *m_state;
e00f35bb 156 unsigned long m_new_val;
39b91eca
GL
157
158 void Notify()
56d8adc0 159 {
479cd5de 160 *m_state = (int)m_new_val; // Change the value
56d8adc0 161 }
39b91eca 162};
8c14576d 163
aa6d9706 164wxSocketBase& wxSocketBase::Read(char* buffer, wxUint32 nbytes)
f4ada568 165{
96db102a
GRG
166 // Mask read events
167 m_reading = TRUE;
a324a7bc 168
96db102a 169 m_lcount = _Read(buffer, nbytes);
17aa2bec 170
96db102a
GRG
171 // If in WAITALL mode, all bytes should have been read.
172 if (m_flags & WAITALL)
173 m_error = (m_lcount != nbytes);
174 else
175 m_error = (m_lcount == 0);
f4ada568 176
dc5c1114 177 // Allow read events from now on
96db102a 178 m_reading = FALSE;
17aa2bec 179
96db102a
GRG
180 return *this;
181}
182
183wxUint32 wxSocketBase::_Read(char* buffer, wxUint32 nbytes)
184{
185 int total;
186 int ret = 1;
a324a7bc 187
96db102a
GRG
188 // we try this even if the connection has already been closed.
189 total = GetPushback(buffer, nbytes, FALSE);
190 nbytes -= total;
191 buffer += total;
192
193 // If the socket is not connected, or we have got the whole
194 // needed buffer, return immedately
dc5c1114 195 if (!m_socket || !m_connected || !nbytes)
96db102a 196 return total;
f4ada568 197
af2fd961 198 // Possible combinations (they are checked in this order)
81b92e17
GRG
199 // wxSOCKET_NOWAIT
200 // wxSOCKET_WAITALL | wxSOCKET_BLOCK
201 // wxSOCKET_WAITALL
202 // wxSOCKET_BLOCK
203 // wxSOCKET_NONE
af2fd961 204 //
81b92e17 205 if (m_flags & wxSOCKET_NOWAIT)
af2fd961
GRG
206 {
207 GSocket_SetNonBlocking(m_socket, TRUE);
208 ret = GSocket_Read(m_socket, buffer, nbytes);
209 GSocket_SetNonBlocking(m_socket, FALSE);
210
211 if (ret > 0)
96db102a 212 total += ret;
af2fd961 213 }
dc5c1114 214 else if (m_flags & wxSOCKET_WAITALL)
56d8adc0
GRG
215 {
216 while (ret > 0 && nbytes > 0)
217 {
81b92e17
GRG
218 if (!(m_flags & wxSOCKET_BLOCK) && !(WaitForRead()))
219 break;
220
a324a7bc 221 ret = GSocket_Read(m_socket, buffer, nbytes);
a324a7bc 222
81b92e17
GRG
223 if (ret > 0)
224 {
225 total += ret;
226 buffer += ret;
227 nbytes -= ret;
228 }
229 }
56d8adc0 230 }
81b92e17 231 else
56d8adc0 232 {
81b92e17
GRG
233 if ((m_flags & wxSOCKET_BLOCK) || WaitForRead())
234 {
235 ret = GSocket_Read(m_socket, buffer, nbytes);
a324a7bc 236
81b92e17
GRG
237 if (ret > 0)
238 total += ret;
239 }
a324a7bc 240 }
f4ada568 241
96db102a 242 return total;
f4ada568
GL
243}
244
aa6d9706 245wxSocketBase& wxSocketBase::ReadMsg(char* buffer, wxUint32 nbytes)
062c4861 246{
96db102a
GRG
247 wxUint32 len, len2, sig, total;
248 bool error;
17aa2bec 249 int old_flags;
17aa2bec
GRG
250 struct
251 {
96db102a
GRG
252 unsigned char sig[4];
253 unsigned char len[4];
062c4861
GL
254 } msg;
255
96db102a
GRG
256 // Mask read events
257 m_reading = TRUE;
062c4861 258
96db102a
GRG
259 total = 0;
260 error = TRUE;
17aa2bec 261 old_flags = m_flags;
81b92e17 262 SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL);
17aa2bec 263
96db102a
GRG
264 if (_Read((char *)&msg, sizeof(msg)) != sizeof(msg))
265 goto exit;
062c4861 266
96db102a
GRG
267 sig = (wxUint32)msg.sig[0];
268 sig |= (wxUint32)(msg.sig[1] << 8);
269 sig |= (wxUint32)(msg.sig[2] << 16);
270 sig |= (wxUint32)(msg.sig[3] << 24);
062c4861
GL
271
272 if (sig != 0xfeeddead)
17aa2bec 273 {
58c837a4 274 wxLogWarning( _("TCP: invalid signature returned to ReadMsg."));
96db102a 275 goto exit;
17aa2bec
GRG
276 }
277
96db102a
GRG
278 len = (wxUint32)msg.len[0];
279 len |= (wxUint32)(msg.len[1] << 8);
280 len |= (wxUint32)(msg.len[2] << 16);
281 len |= (wxUint32)(msg.len[3] << 24);
282
283 //wxLogMessage("Readmsg: %d %d %d %d -> len == %d",
284 // msg.len[0], msg.len[1], msg.len[2], msg.len[3], len);
062c4861 285
17aa2bec
GRG
286 if (len > nbytes)
287 {
062c4861
GL
288 len2 = len - nbytes;
289 len = nbytes;
290 }
291 else
292 len2 = 0;
293
96db102a
GRG
294 // This check is necessary so that we don't attemp to read if
295 // the msg was zero bytes long.
296 if (len)
17aa2bec 297 {
96db102a
GRG
298 total = _Read(buffer, len);
299
300 if (total != len)
301 goto exit;
17aa2bec
GRG
302 }
303 if (len2)
304 {
96db102a 305 char *discard_buffer = new char[MAX_DISCARD_SIZE];
17aa2bec
GRG
306 long discard_len;
307
96db102a 308 // NOTE: discarded bytes don't add to m_lcount.
17aa2bec
GRG
309 do
310 {
96db102a 311 discard_len = ((len2 > MAX_DISCARD_SIZE)? MAX_DISCARD_SIZE : len2);
479cd5de
VZ
312 discard_len = _Read(discard_buffer, (wxUint32)discard_len);
313 len2 -= (wxUint32)discard_len;
17aa2bec
GRG
314 }
315 while ((discard_len > 0) && len2);
316
317 delete [] discard_buffer;
318
319 if (len2 != 0)
96db102a 320 goto exit;
17aa2bec 321 }
96db102a
GRG
322 if (_Read((char *)&msg, sizeof(msg)) != sizeof(msg))
323 goto exit;
062c4861 324
96db102a
GRG
325 sig = (wxUint32)msg.sig[0];
326 sig |= (wxUint32)(msg.sig[1] << 8);
327 sig |= (wxUint32)(msg.sig[2] << 16);
328 sig |= (wxUint32)(msg.sig[3] << 24);
a324a7bc 329
062c4861 330 if (sig != 0xdeadfeed)
17aa2bec 331 {
223d09f6 332 //wxLogMessage(wxT("Warning: invalid signature returned to ReadMsg"));
96db102a 333 goto exit;
17aa2bec 334 }
062c4861 335
96db102a
GRG
336 // everything was OK
337 error = FALSE;
338
339exit:
340 m_error = error;
341 m_lcount = total;
342 m_reading = FALSE;
17aa2bec 343 SetFlags(old_flags);
96db102a 344
062c4861
GL
345 return *this;
346}
347
aa6d9706 348wxSocketBase& wxSocketBase::Peek(char* buffer, wxUint32 nbytes)
f4ada568 349{
96db102a
GRG
350 // Mask read events
351 m_reading = TRUE;
352
353 m_lcount = _Read(buffer, nbytes);
dc5c1114 354 Pushback(buffer, m_lcount);
96db102a 355
81b92e17
GRG
356 // If in wxSOCKET_WAITALL mode, all bytes should have been read.
357 if (m_flags & wxSOCKET_WAITALL)
96db102a
GRG
358 m_error = (m_lcount != nbytes);
359 else
360 m_error = (m_lcount == 0);
361
dc5c1114 362 // Allow read events again
96db102a 363 m_reading = FALSE;
f4ada568
GL
364
365 return *this;
366}
367
aa6d9706 368wxSocketBase& wxSocketBase::Write(const char *buffer, wxUint32 nbytes)
f4ada568 369{
96db102a
GRG
370 // Mask write events
371 m_writing = TRUE;
56d8adc0 372
96db102a
GRG
373 m_lcount = _Write(buffer, nbytes);
374
81b92e17
GRG
375 // If in wxSOCKET_WAITALL mode, all bytes should have been written.
376 if (m_flags & wxSOCKET_WAITALL)
96db102a
GRG
377 m_error = (m_lcount != nbytes);
378 else
379 m_error = (m_lcount == 0);
380
dc5c1114 381 // Allow write events again
96db102a
GRG
382 m_writing = FALSE;
383
96db102a
GRG
384 return *this;
385}
386
387wxUint32 wxSocketBase::_Write(const char *buffer, wxUint32 nbytes)
388{
389 wxUint32 total = 0;
390 int ret = 1;
56d8adc0 391
17aa2bec 392 if (!m_connected || !m_socket)
96db102a 393 return 0;
a324a7bc 394
af2fd961 395 // Possible combinations (they are checked in this order)
81b92e17
GRG
396 // wxSOCKET_NOWAIT
397 // wxSOCKET_WAITALL | wxSOCKET_BLOCK
398 // wxSOCKET_WAITALL
399 // wxSOCKET_BLOCK
400 // wxSOCKET_NONE
af2fd961 401 //
81b92e17 402 if (m_flags & wxSOCKET_NOWAIT)
af2fd961
GRG
403 {
404 GSocket_SetNonBlocking(m_socket, TRUE);
405 ret = GSocket_Write(m_socket, buffer, nbytes);
406 GSocket_SetNonBlocking(m_socket, FALSE);
407
408 if (ret > 0)
96db102a 409 total = ret;
af2fd961 410 }
81b92e17 411 else if (m_flags & wxSOCKET_WAITALL)
56d8adc0
GRG
412 {
413 while (ret > 0 && nbytes > 0)
414 {
81b92e17
GRG
415 if (!(m_flags & wxSOCKET_BLOCK) && !(WaitForWrite()))
416 break;
417
56d8adc0 418 ret = GSocket_Write(m_socket, buffer, nbytes);
56d8adc0 419
81b92e17
GRG
420 if (ret > 0)
421 {
422 total += ret;
423 buffer += ret;
424 nbytes -= ret;
425 }
426 }
56d8adc0 427 }
81b92e17 428 else
56d8adc0 429 {
81b92e17
GRG
430 if ((m_flags & wxSOCKET_BLOCK) || WaitForWrite())
431 {
432 ret = GSocket_Write(m_socket, buffer, nbytes);
a324a7bc 433
81b92e17
GRG
434 if (ret > 0)
435 total = ret;
436 }
56d8adc0 437 }
a324a7bc 438
96db102a 439 return total;
f4ada568
GL
440}
441
aa6d9706 442wxSocketBase& wxSocketBase::WriteMsg(const char *buffer, wxUint32 nbytes)
062c4861 443{
96db102a
GRG
444 wxUint32 total;
445 bool error;
17aa2bec 446 int old_flags;
062c4861 447 struct {
96db102a
GRG
448 unsigned char sig[4];
449 unsigned char len[4];
062c4861
GL
450 } msg;
451
96db102a
GRG
452 // Mask write events
453 m_writing = TRUE;
454
455 error = TRUE;
456 total = 0;
457 old_flags = m_flags;
81b92e17 458 SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL);
96db102a 459
062c4861
GL
460 // warning about 'cast truncates constant value'
461#ifdef __VISUALC__
96db102a 462# pragma warning(disable: 4310)
062c4861
GL
463#endif // __VISUALC__
464
96db102a
GRG
465 msg.sig[0] = (unsigned char) 0xad;
466 msg.sig[1] = (unsigned char) 0xde;
467 msg.sig[2] = (unsigned char) 0xed;
468 msg.sig[3] = (unsigned char) 0xfe;
062c4861 469
96db102a
GRG
470 msg.len[0] = (unsigned char) nbytes & 0xff;
471 msg.len[1] = (unsigned char) (nbytes >> 8) & 0xff;
472 msg.len[2] = (unsigned char) (nbytes >> 16) & 0xff;
473 msg.len[3] = (unsigned char) (nbytes >> 24) & 0xff;
062c4861 474
96db102a
GRG
475 //wxLogMessage("Writemsg: %d %d %d %d -> %d",
476 // nbytes & 0xff,
477 // (nbytes >> 8) & 0xff,
478 // (nbytes >> 16) & 0xff,
479 // (nbytes >> 24) & 0xff,
480 // nbytes
481 // );
17aa2bec 482
96db102a
GRG
483 if (_Write((char *)&msg, sizeof(msg)) < sizeof(msg))
484 goto exit;
485
486 total = _Write(buffer, nbytes);
487
488 if (total < nbytes)
489 goto exit;
062c4861 490
96db102a
GRG
491 msg.sig[0] = (unsigned char) 0xed;
492 msg.sig[1] = (unsigned char) 0xfe;
493 msg.sig[2] = (unsigned char) 0xad;
494 msg.sig[3] = (unsigned char) 0xde;
062c4861 495 msg.len[0] = msg.len[1] = msg.len[2] = msg.len[3] = (char) 0;
062c4861 496
96db102a
GRG
497 if ((_Write((char *)&msg, sizeof(msg))) < sizeof(msg))
498 goto exit;
17aa2bec 499
96db102a
GRG
500 // everything was OK
501 error = FALSE;
502
503exit:
504 m_error = error;
505 m_lcount = total;
506 m_writing = FALSE;
507
062c4861
GL
508 return *this;
509
510#ifdef __VISUALC__
96db102a 511# pragma warning(default: 4310)
062c4861
GL
512#endif // __VISUALC__
513}
514
aa6d9706 515wxSocketBase& wxSocketBase::Unread(const char *buffer, wxUint32 nbytes)
f4ada568 516{
56d8adc0 517 if (nbytes != 0)
96db102a 518 Pushback(buffer, nbytes);
f4ada568 519
96db102a
GRG
520 m_error = FALSE;
521 m_lcount = nbytes;
f4ada568 522
96db102a 523 return *this;
a324a7bc
GL
524}
525
96db102a 526wxSocketBase& wxSocketBase::Discard()
f4ada568 527{
96db102a 528 int old_flags;
dc5c1114
GRG
529 char *my_data = new char[MAX_DISCARD_SIZE];
530 wxUint32 recv_size = MAX_DISCARD_SIZE;
17aa2bec 531 wxUint32 total = 0;
f4ada568 532
96db102a
GRG
533 // Mask read events
534 m_reading = TRUE;
535
536 old_flags = m_flags;
81b92e17 537 SetFlags(wxSOCKET_NOWAIT);
384b4373 538
dc5c1114 539 while (recv_size == MAX_DISCARD_SIZE)
8c14576d 540 {
dc5c1114 541 recv_size = _Read(my_data, MAX_DISCARD_SIZE);
17aa2bec 542 total += recv_size;
f4ada568
GL
543 }
544
f4ada568 545 delete [] my_data;
17aa2bec
GRG
546 m_lcount = total;
547 m_error = FALSE;
548
dc5c1114 549 // Allow read events again
96db102a
GRG
550 m_reading = FALSE;
551
96db102a 552 return *this;
f4ada568
GL
553}
554
555// --------------------------------------------------------------
56d8adc0 556// wxSocketBase get local or peer addresses
f4ada568 557// --------------------------------------------------------------
8c14576d 558
f4ada568
GL
559bool wxSocketBase::GetPeer(wxSockAddress& addr_man) const
560{
a324a7bc 561 GAddress *peer;
f4ada568 562
a324a7bc 563 if (!m_socket)
f4ada568
GL
564 return FALSE;
565
a324a7bc
GL
566 peer = GSocket_GetPeer(m_socket);
567 addr_man.SetAddress(peer);
568 GAddress_destroy(peer);
a737331d 569
f4ada568
GL
570 return TRUE;
571}
572
573bool wxSocketBase::GetLocal(wxSockAddress& addr_man) const
574{
a324a7bc 575 GAddress *local;
f4ada568 576
a324a7bc 577 if (!m_socket)
f4ada568
GL
578 return FALSE;
579
a324a7bc
GL
580 local = GSocket_GetLocal(m_socket);
581 addr_man.SetAddress(local);
582 GAddress_destroy(local);
f4ada568 583
f4ada568
GL
584 return TRUE;
585}
586
587// --------------------------------------------------------------
56d8adc0 588// wxSocketBase save and restore socket state
f4ada568 589// --------------------------------------------------------------
db131261 590
f4ada568
GL
591void wxSocketBase::SaveState()
592{
a324a7bc
GL
593 wxSocketState *state;
594
595 state = new wxSocketState();
f4ada568 596
81b92e17
GRG
597 state->m_notify_state = m_notify_state;
598 state->m_neededreq = m_neededreq;
599 state->m_flags = m_flags;
600 state->m_cbk = m_cbk;
601 state->m_cdata = m_cdata;
f4ada568 602
a324a7bc 603 m_states.Append(state);
f4ada568
GL
604}
605
606void wxSocketBase::RestoreState()
607{
608 wxNode *node;
a324a7bc 609 wxSocketState *state;
f4ada568
GL
610
611 node = m_states.Last();
612 if (!node)
613 return;
614
a324a7bc 615 state = (wxSocketState *)node->Data();
384b4373 616
81b92e17
GRG
617 SetFlags(state->m_flags);
618 m_cbk = state->m_cbk;
619 m_cdata = state->m_cdata;
620 m_neededreq = state->m_neededreq;
621 Notify(state->m_notify_state);
f4ada568
GL
622
623 delete node;
624 delete state;
625}
626
f4ada568
GL
627
628// --------------------------------------------------------------
56d8adc0 629// wxSocketBase Wait functions
f4ada568
GL
630// --------------------------------------------------------------
631
56d8adc0
GRG
632// GRG: I have completely rewritten this family of functions
633// so that they don't depend on event notifications; instead,
634// they poll the socket, using GSocket_Select(), to check for
635// the specified combination of event flags, until an event
636// occurs or until the timeout ellapses. The polling loop
5c15428b 637// calls PROCESS_EVENTS(), so this won't block the GUI.
a324a7bc 638
56d8adc0 639bool wxSocketBase::_Wait(long seconds, long milliseconds, wxSocketEventFlags flags)
375abe3d 640{
56d8adc0 641 GSocketEventFlags result;
a324a7bc 642 _wxSocketInternalTimer timer;
56d8adc0
GRG
643 long timeout;
644 int state = -1;
375abe3d 645
81b92e17
GRG
646 // Set this to TRUE to interrupt ongoing waits
647 m_interrupt = FALSE;
648
56d8adc0 649 // Check for valid socket
af2fd961
GRG
650 if (!m_socket)
651 return FALSE;
652
653 // If it is not a server, it must be connected or establishing connection
654 if ((m_type != SOCK_SERVER) && (!m_connected && !m_establishing))
a737331d 655 return FALSE;
f4ada568 656
56d8adc0
GRG
657 // Check for valid timeout value
658 if (seconds != -1)
659 timeout = seconds * 1000 + milliseconds;
660 else
661 timeout = m_timeout * 1000;
a324a7bc 662
56d8adc0 663 // Activate timer
96db102a
GRG
664 if (timeout)
665 {
666 timer.m_state = &state;
667 timer.m_new_val = 0;
479cd5de 668 timer.Start((int)timeout, TRUE);
96db102a 669 }
a324a7bc 670
56d8adc0 671 // Active polling (without using events)
af2fd961
GRG
672 //
673 // NOTE: this duplicates some of the code in OnRequest (lost
674 // connection and connection establishment handling) but this
675 // doesn't hurt. It has to be here because the event might
676 // be a bit delayed, and it has to be in OnRequest as well
677 // because maybe the WaitXXX functions are not being used.
678 //
96db102a
GRG
679 // Do this at least once (important if timeout == 0, when
680 // we are just polling)
81b92e17
GRG
681 //
682 while (state == -1)
56d8adc0 683 {
af2fd961
GRG
684 result = GSocket_Select(m_socket, flags | GSOCK_LOST_FLAG);
685
686 // Connection lost
687 if (result & GSOCK_LOST_FLAG)
688 {
689 timer.Stop();
af2fd961
GRG
690 Close();
691 return TRUE;
692 }
693
694 // Incoming connection (server) or connection established (client)
695 if (result & GSOCK_CONNECTION_FLAG)
696 {
697 timer.Stop();
698 m_connected = TRUE;
699 m_establishing = FALSE;
700 return TRUE;
701 }
702
81b92e17 703 if ((result & GSOCK_INPUT_FLAG) || (result & GSOCK_OUTPUT_FLAG))
af2fd961 704 {
81b92e17
GRG
705 timer.Stop();
706 return TRUE;
af2fd961
GRG
707 }
708
81b92e17
GRG
709 // Wait more?
710 if ((timeout == 0) || (m_interrupt))
711 break;
712
713 PROCESS_EVENTS();
56d8adc0 714 }
f4ada568 715
a324a7bc 716 timer.Stop();
af2fd961 717 return FALSE;
f4ada568 718}
f4ada568 719
a737331d 720bool wxSocketBase::Wait(long seconds, long milliseconds)
f4ada568 721{
d80d1aba
GRG
722 return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG |
723 GSOCK_OUTPUT_FLAG |
724 GSOCK_CONNECTION_FLAG |
725 GSOCK_LOST_FLAG);
f4ada568 726}
f4ada568 727
a737331d 728bool wxSocketBase::WaitForRead(long seconds, long milliseconds)
f4ada568 729{
96db102a
GRG
730 // Check pushback buffer
731 if (m_unread)
732 return TRUE;
733
af2fd961 734 return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG);
f4ada568
GL
735}
736
a737331d 737bool wxSocketBase::WaitForWrite(long seconds, long milliseconds)
f4ada568 738{
af2fd961 739 return _Wait(seconds, milliseconds, GSOCK_OUTPUT_FLAG);
a737331d 740}
f4ada568 741
a737331d
GL
742bool wxSocketBase::WaitForLost(long seconds, long milliseconds)
743{
a324a7bc 744 return _Wait(seconds, milliseconds, GSOCK_LOST_FLAG);
f4ada568 745}
a737331d 746
17aa2bec
GRG
747void wxSocketBase::SetTimeout(long seconds)
748{
749 m_timeout = seconds;
750
751 if (m_socket)
e8f4c584 752 GSocket_SetTimeout(m_socket, m_timeout * 1000);
17aa2bec
GRG
753}
754
a737331d 755// --------------------------------------------------------------
56d8adc0 756// wxSocketBase flags
a737331d 757// --------------------------------------------------------------
f4ada568 758
f4ada568
GL
759void wxSocketBase::SetFlags(wxSockFlags _flags)
760{
761 m_flags = _flags;
f4ada568 762}
f0a56ab0 763
56d8adc0
GRG
764// --------------------------------------------------------------
765// wxSocketBase callback management
766// --------------------------------------------------------------
767
768wxSocketBase::wxSockCbk wxSocketBase::Callback(wxSockCbk cbk_)
f4ada568 769{
56d8adc0 770 wxSockCbk old_cbk = cbk_;
f4ada568 771
56d8adc0
GRG
772 m_cbk = cbk_;
773 return old_cbk;
774}
775
776char *wxSocketBase::CallbackData(char *data)
777{
778 char *old_data = m_cdata;
779
780 m_cdata = data;
781 return old_data;
f4ada568
GL
782}
783
a324a7bc 784// --------------------------------------------------------------
56d8adc0 785// wxSocketBase automatic notifier
a324a7bc
GL
786// --------------------------------------------------------------
787
96db102a
GRG
788// All events (INPUT, OUTPUT, CONNECTION, LOST) are now always
789// internally watched; but users will only be notified of those
790// events they are interested in.
791
6e31e940
VZ
792static void LINKAGEMODE wx_socket_callback(GSocket * WXUNUSED(socket),
793 GSocketEvent event, char *cdata)
a324a7bc
GL
794{
795 wxSocketBase *sckobj = (wxSocketBase *)cdata;
796
aa8fb7a0 797 sckobj->OnRequest((wxSocketNotify)event);
a324a7bc
GL
798}
799
56d8adc0 800wxSocketEventFlags wxSocketBase::EventToNotify(wxSocketNotify evt)
f4ada568 801{
56d8adc0
GRG
802 switch (evt)
803 {
804 case GSOCK_INPUT: return GSOCK_INPUT_FLAG;
805 case GSOCK_OUTPUT: return GSOCK_OUTPUT_FLAG;
806 case GSOCK_CONNECTION: return GSOCK_CONNECTION_FLAG;
807 case GSOCK_LOST: return GSOCK_LOST_FLAG;
808 }
809 return 0;
810}
aadbdf11 811
56d8adc0
GRG
812void wxSocketBase::SetNotify(wxSocketEventFlags flags)
813{
814 m_neededreq = flags;
815}
a324a7bc 816
56d8adc0
GRG
817void wxSocketBase::Notify(bool notify)
818{
819 m_notify_state = notify;
f4ada568
GL
820}
821
aa8fb7a0 822void wxSocketBase::OnRequest(wxSocketNotify req_evt)
f4ada568 823{
a737331d 824 wxSocketEvent event(m_id);
56d8adc0 825 wxSocketEventFlags flag = EventToNotify(req_evt);
a324a7bc 826
96db102a
GRG
827 // fprintf(stderr, "%s: Entering OnRequest (evt %d)\n", (m_type == SOCK_CLIENT)? "client" : "server", req_evt);
828
81b92e17
GRG
829 // NOTE: this duplicates some of the code in _Wait, (lost
830 // connections and delayed connection establishment) but
af2fd961
GRG
831 // this doesn't hurt. It has to be here because maybe the
832 // WaitXXX are not being used, and it has to be in _Wait
833 // as well because the event might be a bit delayed.
834 //
81b92e17 835 switch (req_evt)
d80d1aba 836 {
81b92e17 837 case wxSOCKET_CONNECTION :
d80d1aba
GRG
838 m_establishing = FALSE;
839 m_connected = TRUE;
840 break;
841 case wxSOCKET_LOST:
842 Close();
843 break;
f4ada568 844
96db102a
GRG
845 // If we are in the middle of a R/W operation, do not
846 // propagate events to users.
81b92e17
GRG
847 //
848 case wxSOCKET_INPUT:
849 if (m_reading) return;
850
851 case wxSOCKET_OUTPUT:
852 if (m_writing) return;
96db102a
GRG
853 }
854
56d8adc0 855 if (((m_neededreq & flag) == flag) && m_notify_state)
d80d1aba 856 {
96db102a 857 // fprintf(stderr, "%s: Evt %d delivered\n", (m_type == SOCK_CLIENT)? "client" : "server", req_evt);
a737331d 858 event.m_socket = this;
de3131e7 859 event.m_skevt = req_evt;
dc5c1114
GRG
860
861 if (m_evt_handler)
862#if EXPERIMENTAL_USE_POST
863 wxPostEvent(m_evt_handler, event);
864#else
865 ProcessEvent(event);
866#endif
56d8adc0 867
81b92e17 868 OldOnNotify(req_evt);
56d8adc0
GRG
869 if (m_cbk)
870 m_cbk(*this, req_evt, m_cdata);
81b92e17 871
f4ada568 872 }
96db102a
GRG
873
874 // fprintf(stderr, "%s: Exiting OnRequest (evt %d)\n", (m_type == SOCK_CLIENT)? "client" : "server", req_evt);
f4ada568
GL
875}
876
6e31e940 877void wxSocketBase::OldOnNotify(wxSocketNotify WXUNUSED(evt))
f4ada568 878{
f4ada568
GL
879}
880
a737331d 881// --------------------------------------------------------------
56d8adc0 882// wxSocketBase set event handler
a737331d 883// --------------------------------------------------------------
f4ada568
GL
884
885void wxSocketBase::SetEventHandler(wxEvtHandler& h_evt, int id)
886{
dc5c1114 887 m_evt_handler = &h_evt;
f4ada568 888 m_id = id;
dc5c1114
GRG
889
890 SetNextHandler(&h_evt);
f4ada568
GL
891}
892
893// --------------------------------------------------------------
96db102a 894// wxSocketBase pushback
f4ada568 895// --------------------------------------------------------------
db131261 896
96db102a 897void wxSocketBase::Pushback(const char *buffer, wxUint32 size)
f4ada568 898{
dc5c1114
GRG
899 if (!size) return;
900
a324a7bc
GL
901 if (m_unread == NULL)
902 m_unread = (char *)malloc(size);
dc5c1114
GRG
903 else
904 {
a324a7bc 905 char *tmp;
f4ada568 906
a324a7bc
GL
907 tmp = (char *)malloc(m_unrd_size + size);
908 memcpy(tmp+size, m_unread, m_unrd_size);
41895a05 909 free(m_unread);
a324a7bc
GL
910
911 m_unread = tmp;
41895a05 912 }
31528cd3 913
f4ada568 914 m_unrd_size += size;
a324a7bc
GL
915
916 memcpy(m_unread, buffer, size);
f4ada568
GL
917}
918
aa6d9706 919wxUint32 wxSocketBase::GetPushback(char *buffer, wxUint32 size, bool peek)
f4ada568
GL
920{
921 if (!m_unrd_size)
922 return 0;
923
a324a7bc
GL
924 if (size > (m_unrd_size-m_unrd_cur))
925 size = m_unrd_size-m_unrd_cur;
96db102a 926
a324a7bc 927 memcpy(buffer, (m_unread+m_unrd_cur), size);
f4ada568 928
dc5c1114
GRG
929 if (!peek)
930 {
a324a7bc 931 m_unrd_cur += size;
dc5c1114
GRG
932 if (m_unrd_size == m_unrd_cur)
933 {
f4ada568
GL
934 free(m_unread);
935 m_unread = NULL;
a324a7bc
GL
936 m_unrd_size = 0;
937 m_unrd_cur = 0;
f4ada568
GL
938 }
939 }
940
941 return size;
942}
943
f4ada568 944// --------------------------------------------------------------
8c14576d 945// wxSocketServer
f4ada568
GL
946// --------------------------------------------------------------
947
56d8adc0
GRG
948// --------------------------------------------------------------
949// wxSocketServer ctor and dtor
950// --------------------------------------------------------------
951
f4ada568 952wxSocketServer::wxSocketServer(wxSockAddress& addr_man,
17dff81c 953 wxSockFlags flags) :
f4ada568
GL
954 wxSocketBase(flags, SOCK_SERVER)
955{
56d8adc0 956 // Create the socket
a324a7bc 957 m_socket = GSocket_new();
f4ada568 958
a324a7bc 959 if (!m_socket)
f4ada568 960 return;
384b4373 961
56d8adc0 962 // Setup the socket as server
a324a7bc 963 GSocket_SetLocal(m_socket, addr_man.GetAddress());
56d8adc0
GRG
964 if (GSocket_SetServer(m_socket) != GSOCK_NOERROR)
965 {
a324a7bc
GL
966 GSocket_destroy(m_socket);
967 m_socket = NULL;
f4ada568
GL
968 return;
969 }
a737331d 970
e8f4c584 971 GSocket_SetTimeout(m_socket, m_timeout * 1000);
56d8adc0
GRG
972 GSocket_SetCallback(m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
973 GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
974 wx_socket_callback, (char *)this);
975
f4ada568
GL
976}
977
978// --------------------------------------------------------------
8c14576d 979// wxSocketServer Accept
f4ada568 980// --------------------------------------------------------------
8c14576d 981
d80d1aba 982bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait)
f4ada568 983{
a324a7bc 984 GSocket *child_socket;
f4ada568 985
17aa2bec
GRG
986 if (!m_socket)
987 return FALSE;
988
56d8adc0
GRG
989 // GRG: If wait == FALSE, then the call should be nonblocking.
990 // When we are finished, we put the socket to blocking mode
991 // again.
d80d1aba
GRG
992
993 if (!wait)
994 GSocket_SetNonBlocking(m_socket, TRUE);
995
a324a7bc 996 child_socket = GSocket_WaitConnection(m_socket);
384b4373 997
d80d1aba
GRG
998 if (!wait)
999 GSocket_SetNonBlocking(m_socket, FALSE);
1000
1001 // GRG: this was not being handled!
1002 if (child_socket == NULL)
1003 return FALSE;
1004
f4ada568 1005 sock.m_type = SOCK_INTERNAL;
a324a7bc 1006 sock.m_socket = child_socket;
f4ada568
GL
1007 sock.m_connected = TRUE;
1008
e8f4c584 1009 GSocket_SetTimeout(sock.m_socket, sock.m_timeout * 1000);
56d8adc0
GRG
1010 GSocket_SetCallback(sock.m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
1011 GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
1012 wx_socket_callback, (char *)&sock);
1013
f4ada568
GL
1014 return TRUE;
1015}
1016
d80d1aba 1017wxSocketBase *wxSocketServer::Accept(bool wait)
f4ada568
GL
1018{
1019 wxSocketBase* sock = new wxSocketBase();
1020
1021 sock->SetFlags((wxSockFlags)m_flags);
1022
d80d1aba 1023 if (!AcceptWith(*sock, wait))
f4ada568
GL
1024 return NULL;
1025
f4ada568
GL
1026 return sock;
1027}
1028
17aa2bec 1029bool wxSocketServer::WaitForAccept(long seconds, long milliseconds)
d80d1aba 1030{
af2fd961 1031 return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG);
d80d1aba
GRG
1032}
1033
f4ada568 1034// --------------------------------------------------------------
8c14576d 1035// wxSocketClient
f4ada568
GL
1036// --------------------------------------------------------------
1037
f4ada568 1038// --------------------------------------------------------------
56d8adc0
GRG
1039// wxSocketClient ctor and dtor
1040// --------------------------------------------------------------
1041
f4ada568 1042wxSocketClient::wxSocketClient(wxSockFlags _flags) :
17dff81c 1043 wxSocketBase(_flags, SOCK_CLIENT)
f4ada568
GL
1044{
1045}
1046
f4ada568
GL
1047wxSocketClient::~wxSocketClient()
1048{
1049}
1050
1051// --------------------------------------------------------------
56d8adc0 1052// wxSocketClient Connect functions
f4ada568 1053// --------------------------------------------------------------
dc5c1114 1054
791b24c4 1055bool wxSocketClient::Connect(wxSockAddress& addr_man, bool wait)
f4ada568 1056{
791b24c4
GRG
1057 GSocketError err;
1058
f4ada568
GL
1059 if (IsConnected())
1060 Close();
1061
a324a7bc
GL
1062 // This should never happen.
1063 if (m_socket)
1064 GSocket_destroy(m_socket);
1065
56d8adc0 1066 // Initialize all socket stuff ...
a324a7bc 1067 m_socket = GSocket_new();
d80d1aba
GRG
1068 m_connected = FALSE;
1069 m_establishing = FALSE;
384b4373 1070
a324a7bc 1071 if (!m_socket)
f4ada568 1072 return FALSE;
384b4373 1073
e8f4c584 1074 GSocket_SetTimeout(m_socket, m_timeout * 1000);
96db102a
GRG
1075 GSocket_SetCallback(m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
1076 GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
1077 wx_socket_callback, (char *)this);
56d8adc0
GRG
1078
1079 // GRG: If wait == FALSE, then the call should be nonblocking.
1080 // When we are finished, we put the socket to blocking mode
1081 // again.
f4ada568 1082
791b24c4
GRG
1083 if (!wait)
1084 GSocket_SetNonBlocking(m_socket, TRUE);
1085
a324a7bc 1086 GSocket_SetPeer(m_socket, addr_man.GetAddress());
791b24c4
GRG
1087 err = GSocket_Connect(m_socket, GSOCK_STREAMED);
1088
1089 if (!wait)
1090 GSocket_SetNonBlocking(m_socket, FALSE);
1091
1092 if (err != GSOCK_NOERROR)
56d8adc0
GRG
1093 {
1094 if (err == GSOCK_WOULDBLOCK)
1095 m_establishing = TRUE;
1096
f4ada568 1097 return FALSE;
56d8adc0 1098 }
9111db68 1099
f4ada568
GL
1100 m_connected = TRUE;
1101 return TRUE;
1102}
1103
d80d1aba 1104bool wxSocketClient::WaitOnConnect(long seconds, long milliseconds)
f4ada568 1105{
af2fd961 1106 if (m_connected) // Already connected
d80d1aba
GRG
1107 return TRUE;
1108
af2fd961 1109 if (!m_establishing || !m_socket) // No connection in progress
d80d1aba
GRG
1110 return FALSE;
1111
af2fd961 1112 return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG);
f4ada568
GL
1113}
1114
dc5c1114
GRG
1115// --------------------------------------------------------------
1116// wxDatagramSocket
1117// --------------------------------------------------------------
1118
1119/* NOTE: experimental stuff - might change */
1120
1121wxDatagramSocket::wxDatagramSocket( wxSockAddress& addr, wxSockFlags flags )
1122 : wxSocketBase( flags, SOCK_DATAGRAM )
1123{
1124 // Create the socket
1125 m_socket = GSocket_new();
1126
1127 if(!m_socket)
1128 return;
1129
1130 // Setup the socket as non connection oriented
1131 GSocket_SetLocal(m_socket, addr.GetAddress());
1132 if( GSocket_SetNonOriented(m_socket) != GSOCK_NOERROR )
1133 {
1134 GSocket_destroy(m_socket);
1135 m_socket = NULL;
1136 return;
1137 }
1138
1139 // Initialize all stuff
1140 m_connected = FALSE;
1141 m_establishing = FALSE;
1142 GSocket_SetTimeout( m_socket, m_timeout );
1143 GSocket_SetCallback( m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
1144 GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
1145 wx_socket_callback, (char*)this );
1146
1147}
1148
1149wxDatagramSocket& wxDatagramSocket::RecvFrom( wxSockAddress& addr,
1150 char* buf,
1151 wxUint32 nBytes )
1152{
1153 Read(buf, nBytes);
1154 GetPeer(addr);
1155 return (*this);
1156}
1157
1158wxDatagramSocket& wxDatagramSocket::SendTo( wxSockAddress& addr,
1159 const char* buf,
1160 wxUint32 nBytes )
1161{
1162 GSocket_SetPeer(m_socket, addr.GetAddress());
1163 Write(buf, nBytes);
1164 return (*this);
1165}
1166
f4ada568 1167// --------------------------------------------------------------
a324a7bc 1168// wxSocketEvent
f4ada568 1169// --------------------------------------------------------------
f4ada568 1170
a324a7bc
GL
1171wxSocketEvent::wxSocketEvent(int id)
1172 : wxEvent(id)
f4ada568 1173{
a324a7bc 1174 wxEventType type = (wxEventType)wxEVT_SOCKET;
f4ada568 1175
a324a7bc 1176 SetEventType(type);
f4ada568
GL
1177}
1178
a324a7bc 1179void wxSocketEvent::CopyObject(wxObject& obj_d) const
f4ada568 1180{
a324a7bc 1181 wxSocketEvent *event = (wxSocketEvent *)&obj_d;
f4ada568 1182
a324a7bc 1183 wxEvent::CopyObject(obj_d);
3b4183d8 1184
a324a7bc
GL
1185 event->m_skevt = m_skevt;
1186 event->m_socket = m_socket;
3b4183d8
GL
1187}
1188
a58d5df4
GL
1189// --------------------------------------------------------------------------
1190// wxSocketModule
1191// --------------------------------------------------------------------------
dc5c1114
GRG
1192
1193class WXDLLEXPORT wxSocketModule: public wxModule
1194{
a58d5df4 1195 DECLARE_DYNAMIC_CLASS(wxSocketModule)
dc5c1114
GRG
1196public:
1197 bool OnInit()
1198 {
31989b0b 1199 return GSocket_Init();
a58d5df4 1200 }
dc5c1114
GRG
1201 void OnExit()
1202 {
ca17eff3 1203 GSocket_Cleanup();
a58d5df4
GL
1204 }
1205};
1206
1207IMPLEMENT_DYNAMIC_CLASS(wxSocketModule, wxModule)
1208
35a4dab7
GL
1209#endif
1210 // wxUSE_SOCKETS