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