]> git.saurik.com Git - wxWidgets.git/blame - src/common/socket.cpp
bitmap button size was too small when uxtheme functions were used to get the margins
[wxWidgets.git] / src / common / socket.cpp
CommitLineData
56d8adc0 1/////////////////////////////////////////////////////////////////////////////
7fb0a11d 2// Name: src/common/socket.cpp
f4ada568 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 8// RCS_ID: $Id$
7fb0a11d 9// License: wxWindows licence
56d8adc0
GRG
10/////////////////////////////////////////////////////////////////////////////
11
bffc1eaa
GRG
12// ==========================================================================
13// Declarations
14// ==========================================================================
15
fcc6dddd
JS
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
8e3f3880 20 #pragma hdrstop
fcc6dddd
JS
21#endif
22
35a4dab7
GL
23#if wxUSE_SOCKETS
24
df91131c
WS
25#include "wx/socket.h"
26
8e3f3880
WS
27#ifndef WX_PRECOMP
28 #include "wx/object.h"
df91131c 29 #include "wx/string.h"
88a7a4e1 30 #include "wx/intl.h"
e4db172a 31 #include "wx/log.h"
d5da0ce7 32 #include "wx/event.h"
670f9935 33 #include "wx/app.h"
de6185e2 34 #include "wx/utils.h"
c0badb70 35 #include "wx/timer.h"
8e3f3880
WS
36#endif
37
e2478fde 38#include "wx/apptrait.h"
56d8adc0 39#include "wx/module.h"
52a07708 40
56d8adc0 41#include "wx/sckaddr.h"
204b046e 42#include "wx/datetime.h"
3b4183d8 43
34fdf762
VS
44// DLL options compatibility check:
45#include "wx/build.h"
46WX_CHECK_BUILD_OPTIONS("wxNet")
47
bffc1eaa
GRG
48// --------------------------------------------------------------------------
49// macros and constants
50// --------------------------------------------------------------------------
ef57d866 51
dc5c1114
GRG
52// discard buffer
53#define MAX_DISCARD_SIZE (10 * 1024)
96db102a 54
e2478fde
VZ
55// what to do within waits: we have 2 cases: from the main thread itself we
56// have to call wxYield() to let the events (including the GUI events and the
77ffb593 57// low-level (not wxWidgets) events from GSocket) be processed. From another
e2478fde
VZ
58// thread it is enough to just call wxThread::Yield() which will give away the
59// rest of our time slice: the explanation is that the events will be processed
60// by the main thread anyhow, without calling wxYield(), but we don't want to
61// eat the CPU time uselessly while sitting in the loop waiting for the data
62#if wxUSE_THREADS
63 #define PROCESS_EVENTS() \
64 { \
65 if ( wxThread::IsMain() ) \
66 wxYield(); \
67 else \
68 wxThread::Yield(); \
69 }
70#else // !wxUSE_THREADS
71 #define PROCESS_EVENTS() wxYield()
72#endif // wxUSE_THREADS/!wxUSE_THREADS
96db102a 73
007c77ab
RL
74#define wxTRACE_Socket _T("wxSocket")
75
ef57d866 76// --------------------------------------------------------------------------
bffc1eaa 77// wxWin macros
ef57d866 78// --------------------------------------------------------------------------
81b92e17 79
a737331d
GL
80IMPLEMENT_CLASS(wxSocketBase, wxObject)
81IMPLEMENT_CLASS(wxSocketServer, wxSocketBase)
82IMPLEMENT_CLASS(wxSocketClient, wxSocketBase)
dc5c1114 83IMPLEMENT_CLASS(wxDatagramSocket, wxSocketBase)
a737331d 84IMPLEMENT_DYNAMIC_CLASS(wxSocketEvent, wxEvent)
f4ada568 85
bffc1eaa
GRG
86// --------------------------------------------------------------------------
87// private classes
88// --------------------------------------------------------------------------
89
56d8adc0
GRG
90class wxSocketState : public wxObject
91{
a324a7bc 92public:
71622a7a 93 wxSocketFlags m_flags;
bffc1eaa
GRG
94 wxSocketEventFlags m_eventmask;
95 bool m_notify;
96 void *m_clientData;
a324a7bc
GL
97
98public:
99 wxSocketState() : wxObject() {}
22f3361e 100
17a1ebd1 101 DECLARE_NO_COPY_CLASS(wxSocketState)
a324a7bc
GL
102};
103
ef57d866
GRG
104// ==========================================================================
105// wxSocketBase
106// ==========================================================================
107
6c0d0845
VZ
108// --------------------------------------------------------------------------
109// Initialization and shutdown
110// --------------------------------------------------------------------------
111
112// FIXME-MT: all this is MT-unsafe, of course, we should protect all accesses
113// to m_countInit with a crit section
114size_t wxSocketBase::m_countInit = 0;
115
116bool wxSocketBase::IsInitialized()
117{
118 return m_countInit > 0;
119}
120
121bool wxSocketBase::Initialize()
122{
123 if ( !m_countInit++ )
124 {
4cc90442
VZ
125 /*
126 Details: Initialize() creates a hidden window as a sink for socket
127 events, such as 'read completed'. wxMSW has only one message loop
128 for the main thread. If Initialize is called in a secondary thread,
129 the socket window will be created for the secondary thread, but
130 since there is no message loop on this thread, it will never
131 receive events and all socket operations will time out.
132 BTW, the main thread must not be stopped using sleep or block
37340c48 133 on a semaphore (a bad idea in any case) or socket operations
4cc90442 134 will time out.
e59461ff
KH
135
136 On the Mac side, Initialize() stores a pointer to the CFRunLoop for
137 the main thread. Because secondary threads do not have run loops,
138 adding event notifications to the "Current" loop would have no
139 effect at all, events would never fire.
4cc90442 140 */
f938a756 141 wxASSERT_MSG( wxIsMainThread(),
37340c48
VZ
142 wxT("Call wxSocketBase::Initialize() from the main thread first!"));
143
38bb138f
VS
144 wxAppTraits *traits = wxAppConsole::GetInstance() ?
145 wxAppConsole::GetInstance()->GetTraits() : NULL;
37340c48 146 GSocketGUIFunctionsTable *functions =
38bb138f
VS
147 traits ? traits->GetSocketGUIFunctionsTable() : NULL;
148 GSocket_SetGUIFunctions(functions);
37340c48 149
6c0d0845
VZ
150 if ( !GSocket_Init() )
151 {
152 m_countInit--;
153
d775fa82 154 return false;
6c0d0845
VZ
155 }
156 }
157
d775fa82 158 return true;
6c0d0845
VZ
159}
160
161void wxSocketBase::Shutdown()
162{
163 // we should be initialized
164 wxASSERT_MSG( m_countInit, _T("extra call to Shutdown()") );
8d7eaf91 165 if ( --m_countInit == 0 )
6c0d0845
VZ
166 {
167 GSocket_Cleanup();
168 }
169}
170
ef57d866
GRG
171// --------------------------------------------------------------------------
172// Ctor and dtor
173// --------------------------------------------------------------------------
56d8adc0 174
71622a7a 175void wxSocketBase::Init()
f4ada568 176{
71622a7a
GRG
177 m_socket = NULL;
178 m_type = wxSOCKET_UNINIT;
179
180 // state
181 m_flags = 0;
182 m_connected =
183 m_establishing =
184 m_reading =
185 m_writing =
d775fa82 186 m_error = false;
71622a7a
GRG
187 m_lcount = 0;
188 m_timeout = 600;
d775fa82 189 m_beingDeleted = false;
71622a7a
GRG
190
191 // pushback buffer
192 m_unread = NULL;
193 m_unrd_size = 0;
194 m_unrd_cur = 0;
195
196 // events
d775fa82 197 m_id = wxID_ANY;
f187448d
GRG
198 m_handler = NULL;
199 m_clientData = NULL;
d775fa82 200 m_notify = false;
bffc1eaa 201 m_eventmask = 0;
6c0d0845
VZ
202
203 if ( !IsInitialized() )
204 {
205 // this Initialize() will be undone by wxSocketModule::OnExit(), all the
206 // other calls to it should be matched by a call to Shutdown()
207 Initialize();
208 }
f4ada568
GL
209}
210
f187448d
GRG
211wxSocketBase::wxSocketBase()
212{
213 Init();
214}
71622a7a
GRG
215
216wxSocketBase::wxSocketBase(wxSocketFlags flags, wxSocketType type)
f4ada568 217{
71622a7a
GRG
218 Init();
219
220 m_flags = flags;
221 m_type = type;
f4ada568
GL
222}
223
f4ada568
GL
224wxSocketBase::~wxSocketBase()
225{
9181a383
GRG
226 // Just in case the app called Destroy() *and* then deleted
227 // the socket immediately: don't leave dangling pointers.
e2478fde
VZ
228 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
229 if ( traits )
230 traits->RemoveFromPendingDelete(this);
a737331d 231
56d8adc0 232 // Shutdown and close the socket
9181a383
GRG
233 if (!m_beingDeleted)
234 Close();
f4ada568 235
56d8adc0 236 // Destroy the GSocket object
a324a7bc 237 if (m_socket)
8b6fc577 238 delete m_socket;
9181a383
GRG
239
240 // Free the pushback buffer
241 if (m_unread)
242 free(m_unread);
f4ada568
GL
243}
244
ef57d866
GRG
245bool wxSocketBase::Destroy()
246{
247 // Delayed destruction: the socket will be deleted during the next
248 // idle loop iteration. This ensures that all pending events have
249 // been processed.
d775fa82 250 m_beingDeleted = true;
9181a383
GRG
251
252 // Shutdown and close the socket
ef57d866
GRG
253 Close();
254
bffc1eaa 255 // Supress events from now on
d775fa82 256 Notify(false);
bffc1eaa 257
e2478fde
VZ
258 // schedule this object for deletion
259 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
260 if ( traits )
261 {
262 // let the traits object decide what to do with us
263 traits->ScheduleForDestroy(this);
264 }
265 else // no app or no traits
266 {
267 // in wxBase we might have no app object at all, don't leak memory
268 delete this;
269 }
ef57d866 270
d775fa82 271 return true;
ef57d866 272}
9181a383 273
ef57d866 274// --------------------------------------------------------------------------
bffc1eaa 275// Basic IO calls
ef57d866
GRG
276// --------------------------------------------------------------------------
277
278// The following IO operations update m_error and m_lcount:
279// {Read, Write, ReadMsg, WriteMsg, Peek, Unread, Discard}
280//
281// TODO: Should Connect, Accept and AcceptWith update m_error?
282
f4ada568
GL
283bool wxSocketBase::Close()
284{
81b92e17 285 // Interrupt pending waits
02d15cad 286 InterruptWait();
81b92e17 287
31528cd3 288 if (m_socket)
8c14576d 289 {
56d8adc0 290 // Disable callbacks
8b6fc577 291 m_socket->UnsetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
56d8adc0 292 GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG);
f4ada568 293
56d8adc0 294 // Shutdown the connection
8b6fc577 295 m_socket->Shutdown();
f4ada568
GL
296 }
297
d775fa82
WS
298 m_connected = false;
299 m_establishing = false;
300 return true;
f4ada568
GL
301}
302
f187448d 303wxSocketBase& wxSocketBase::Read(void* buffer, wxUint32 nbytes)
f4ada568 304{
96db102a 305 // Mask read events
d775fa82 306 m_reading = true;
a324a7bc 307
96db102a 308 m_lcount = _Read(buffer, nbytes);
17aa2bec 309
d3ea6527
GRG
310 // If in wxSOCKET_WAITALL mode, all bytes should have been read.
311 if (m_flags & wxSOCKET_WAITALL)
96db102a
GRG
312 m_error = (m_lcount != nbytes);
313 else
314 m_error = (m_lcount == 0);
f4ada568 315
dc5c1114 316 // Allow read events from now on
d775fa82 317 m_reading = false;
17aa2bec 318
96db102a
GRG
319 return *this;
320}
321
f187448d 322wxUint32 wxSocketBase::_Read(void* buffer, wxUint32 nbytes)
96db102a
GRG
323{
324 int total;
a324a7bc 325
04e1eb03 326 // Try the pushback buffer first
d775fa82 327 total = GetPushback(buffer, nbytes, false);
96db102a 328 nbytes -= total;
f187448d 329 buffer = (char *)buffer + total;
96db102a 330
5f3629ba
GRG
331 // Return now in one of the following cases:
332 // - the socket is invalid,
635f2bad 333 // - we got all the data
5f3629ba 334 if ( !m_socket ||
635f2bad 335 !nbytes )
96db102a 336 return total;
f4ada568 337
af2fd961 338 // Possible combinations (they are checked in this order)
81b92e17 339 // wxSOCKET_NOWAIT
5c9eff30 340 // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK)
81b92e17
GRG
341 // wxSOCKET_BLOCK
342 // wxSOCKET_NONE
af2fd961 343 //
999836aa 344 int ret;
81b92e17 345 if (m_flags & wxSOCKET_NOWAIT)
af2fd961 346 {
8b6fc577
DE
347 m_socket->SetNonBlocking(1);
348 ret = m_socket->Read((char *)buffer, nbytes);
349 m_socket->SetNonBlocking(0);
af2fd961
GRG
350
351 if (ret > 0)
96db102a 352 total += ret;
af2fd961 353 }
5c9eff30 354 else
56d8adc0 355 {
d775fa82 356 bool more = true;
5c9eff30
GRG
357
358 while (more)
56d8adc0 359 {
5c9eff30
GRG
360 if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForRead() )
361 break;
81b92e17 362
8b6fc577 363 ret = m_socket->Read((char *)buffer, nbytes);
a324a7bc 364
81b92e17
GRG
365 if (ret > 0)
366 {
367 total += ret;
81b92e17 368 nbytes -= ret;
f187448d 369 buffer = (char *)buffer + ret;
81b92e17 370 }
a324a7bc 371
5c9eff30
GRG
372 // If we got here and wxSOCKET_WAITALL is not set, we can leave
373 // now. Otherwise, wait until we recv all the data or until there
374 // is an error.
375 //
376 more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL));
81b92e17 377 }
a324a7bc 378 }
f4ada568 379
96db102a 380 return total;
f4ada568
GL
381}
382
f187448d 383wxSocketBase& wxSocketBase::ReadMsg(void* buffer, wxUint32 nbytes)
062c4861 384{
96db102a
GRG
385 wxUint32 len, len2, sig, total;
386 bool error;
17aa2bec 387 int old_flags;
17aa2bec
GRG
388 struct
389 {
96db102a
GRG
390 unsigned char sig[4];
391 unsigned char len[4];
062c4861
GL
392 } msg;
393
96db102a 394 // Mask read events
d775fa82 395 m_reading = true;
062c4861 396
96db102a 397 total = 0;
d775fa82 398 error = true;
17aa2bec 399 old_flags = m_flags;
81b92e17 400 SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL);
17aa2bec 401
f187448d 402 if (_Read(&msg, sizeof(msg)) != sizeof(msg))
96db102a 403 goto exit;
062c4861 404
f187448d 405 sig = (wxUint32)msg.sig[0];
96db102a
GRG
406 sig |= (wxUint32)(msg.sig[1] << 8);
407 sig |= (wxUint32)(msg.sig[2] << 16);
408 sig |= (wxUint32)(msg.sig[3] << 24);
062c4861
GL
409
410 if (sig != 0xfeeddead)
17aa2bec 411 {
5c9eff30 412 wxLogWarning(_("wxSocket: invalid signature in ReadMsg."));
96db102a 413 goto exit;
17aa2bec
GRG
414 }
415
96db102a
GRG
416 len = (wxUint32)msg.len[0];
417 len |= (wxUint32)(msg.len[1] << 8);
418 len |= (wxUint32)(msg.len[2] << 16);
419 len |= (wxUint32)(msg.len[3] << 24);
420
17aa2bec
GRG
421 if (len > nbytes)
422 {
062c4861
GL
423 len2 = len - nbytes;
424 len = nbytes;
425 }
426 else
427 len2 = 0;
428
04e1eb03 429 // Don't attemp to read if the msg was zero bytes long.
96db102a 430 if (len)
17aa2bec 431 {
96db102a
GRG
432 total = _Read(buffer, len);
433
434 if (total != len)
435 goto exit;
17aa2bec
GRG
436 }
437 if (len2)
438 {
96db102a 439 char *discard_buffer = new char[MAX_DISCARD_SIZE];
17aa2bec
GRG
440 long discard_len;
441
96db102a 442 // NOTE: discarded bytes don't add to m_lcount.
17aa2bec
GRG
443 do
444 {
96db102a 445 discard_len = ((len2 > MAX_DISCARD_SIZE)? MAX_DISCARD_SIZE : len2);
479cd5de
VZ
446 discard_len = _Read(discard_buffer, (wxUint32)discard_len);
447 len2 -= (wxUint32)discard_len;
17aa2bec
GRG
448 }
449 while ((discard_len > 0) && len2);
450
451 delete [] discard_buffer;
452
453 if (len2 != 0)
96db102a 454 goto exit;
17aa2bec 455 }
f187448d 456 if (_Read(&msg, sizeof(msg)) != sizeof(msg))
96db102a 457 goto exit;
062c4861 458
96db102a
GRG
459 sig = (wxUint32)msg.sig[0];
460 sig |= (wxUint32)(msg.sig[1] << 8);
461 sig |= (wxUint32)(msg.sig[2] << 16);
462 sig |= (wxUint32)(msg.sig[3] << 24);
a324a7bc 463
062c4861 464 if (sig != 0xdeadfeed)
17aa2bec 465 {
5c9eff30 466 wxLogWarning(_("wxSocket: invalid signature in ReadMsg."));
96db102a 467 goto exit;
17aa2bec 468 }
062c4861 469
96db102a 470 // everything was OK
d775fa82 471 error = false;
96db102a
GRG
472
473exit:
474 m_error = error;
475 m_lcount = total;
d775fa82 476 m_reading = false;
17aa2bec 477 SetFlags(old_flags);
96db102a 478
062c4861
GL
479 return *this;
480}
481
f187448d 482wxSocketBase& wxSocketBase::Peek(void* buffer, wxUint32 nbytes)
f4ada568 483{
96db102a 484 // Mask read events
d775fa82 485 m_reading = true;
96db102a
GRG
486
487 m_lcount = _Read(buffer, nbytes);
dc5c1114 488 Pushback(buffer, m_lcount);
96db102a 489
81b92e17
GRG
490 // If in wxSOCKET_WAITALL mode, all bytes should have been read.
491 if (m_flags & wxSOCKET_WAITALL)
96db102a
GRG
492 m_error = (m_lcount != nbytes);
493 else
494 m_error = (m_lcount == 0);
495
dc5c1114 496 // Allow read events again
d775fa82 497 m_reading = false;
f4ada568
GL
498
499 return *this;
500}
501
f187448d 502wxSocketBase& wxSocketBase::Write(const void *buffer, wxUint32 nbytes)
f4ada568 503{
96db102a 504 // Mask write events
d775fa82 505 m_writing = true;
56d8adc0 506
96db102a
GRG
507 m_lcount = _Write(buffer, nbytes);
508
81b92e17
GRG
509 // If in wxSOCKET_WAITALL mode, all bytes should have been written.
510 if (m_flags & wxSOCKET_WAITALL)
96db102a
GRG
511 m_error = (m_lcount != nbytes);
512 else
513 m_error = (m_lcount == 0);
514
dc5c1114 515 // Allow write events again
d775fa82 516 m_writing = false;
96db102a 517
96db102a
GRG
518 return *this;
519}
520
f187448d 521wxUint32 wxSocketBase::_Write(const void *buffer, wxUint32 nbytes)
96db102a
GRG
522{
523 wxUint32 total = 0;
56d8adc0 524
5c9eff30
GRG
525 // If the socket is invalid or parameters are ill, return immediately
526 if (!m_socket || !buffer || !nbytes)
96db102a 527 return 0;
a324a7bc 528
af2fd961 529 // Possible combinations (they are checked in this order)
81b92e17 530 // wxSOCKET_NOWAIT
5c9eff30 531 // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK)
81b92e17
GRG
532 // wxSOCKET_BLOCK
533 // wxSOCKET_NONE
af2fd961 534 //
999836aa 535 int ret;
81b92e17 536 if (m_flags & wxSOCKET_NOWAIT)
af2fd961 537 {
8b6fc577
DE
538 m_socket->SetNonBlocking(1);
539 ret = m_socket->Write((const char *)buffer, nbytes);
540 m_socket->SetNonBlocking(0);
af2fd961
GRG
541
542 if (ret > 0)
96db102a 543 total = ret;
af2fd961 544 }
5c9eff30 545 else
56d8adc0 546 {
d775fa82 547 bool more = true;
5c9eff30 548
c3e646b4 549 while (more)
56d8adc0 550 {
5c9eff30
GRG
551 if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() )
552 break;
81b92e17 553
8b6fc577 554 ret = m_socket->Write((const char *)buffer, nbytes);
5c9eff30 555
81b92e17
GRG
556 if (ret > 0)
557 {
558 total += ret;
81b92e17 559 nbytes -= ret;
f187448d 560 buffer = (const char *)buffer + ret;
81b92e17 561 }
a324a7bc 562
5c9eff30
GRG
563 // If we got here and wxSOCKET_WAITALL is not set, we can leave
564 // now. Otherwise, wait until we send all the data or until there
565 // is an error.
566 //
567 more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL));
81b92e17 568 }
56d8adc0 569 }
a324a7bc 570
96db102a 571 return total;
f4ada568
GL
572}
573
f187448d 574wxSocketBase& wxSocketBase::WriteMsg(const void *buffer, wxUint32 nbytes)
062c4861 575{
96db102a
GRG
576 wxUint32 total;
577 bool error;
f187448d
GRG
578 struct
579 {
96db102a
GRG
580 unsigned char sig[4];
581 unsigned char len[4];
062c4861
GL
582 } msg;
583
96db102a 584 // Mask write events
d775fa82 585 m_writing = true;
96db102a 586
d775fa82 587 error = true;
96db102a 588 total = 0;
81b92e17 589 SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL);
96db102a 590
96db102a
GRG
591 msg.sig[0] = (unsigned char) 0xad;
592 msg.sig[1] = (unsigned char) 0xde;
593 msg.sig[2] = (unsigned char) 0xed;
594 msg.sig[3] = (unsigned char) 0xfe;
062c4861 595
04e1eb03
GRG
596 msg.len[0] = (unsigned char) (nbytes & 0xff);
597 msg.len[1] = (unsigned char) ((nbytes >> 8) & 0xff);
598 msg.len[2] = (unsigned char) ((nbytes >> 16) & 0xff);
599 msg.len[3] = (unsigned char) ((nbytes >> 24) & 0xff);
17aa2bec 600
f187448d 601 if (_Write(&msg, sizeof(msg)) < sizeof(msg))
96db102a
GRG
602 goto exit;
603
604 total = _Write(buffer, nbytes);
605
606 if (total < nbytes)
607 goto exit;
062c4861 608
96db102a
GRG
609 msg.sig[0] = (unsigned char) 0xed;
610 msg.sig[1] = (unsigned char) 0xfe;
611 msg.sig[2] = (unsigned char) 0xad;
612 msg.sig[3] = (unsigned char) 0xde;
062c4861 613 msg.len[0] = msg.len[1] = msg.len[2] = msg.len[3] = (char) 0;
062c4861 614
f187448d 615 if ((_Write(&msg, sizeof(msg))) < sizeof(msg))
96db102a 616 goto exit;
17aa2bec 617
96db102a 618 // everything was OK
d775fa82 619 error = false;
96db102a
GRG
620
621exit:
622 m_error = error;
623 m_lcount = total;
d775fa82 624 m_writing = false;
96db102a 625
062c4861 626 return *this;
062c4861
GL
627}
628
f187448d 629wxSocketBase& wxSocketBase::Unread(const void *buffer, wxUint32 nbytes)
f4ada568 630{
56d8adc0 631 if (nbytes != 0)
96db102a 632 Pushback(buffer, nbytes);
f4ada568 633
d775fa82 634 m_error = false;
96db102a 635 m_lcount = nbytes;
f4ada568 636
96db102a 637 return *this;
a324a7bc
GL
638}
639
96db102a 640wxSocketBase& wxSocketBase::Discard()
f4ada568 641{
04e1eb03
GRG
642 char *buffer = new char[MAX_DISCARD_SIZE];
643 wxUint32 ret;
17aa2bec 644 wxUint32 total = 0;
f4ada568 645
96db102a 646 // Mask read events
d775fa82 647 m_reading = true;
96db102a 648
81b92e17 649 SetFlags(wxSOCKET_NOWAIT);
384b4373 650
04e1eb03 651 do
8c14576d 652 {
04e1eb03
GRG
653 ret = _Read(buffer, MAX_DISCARD_SIZE);
654 total += ret;
f4ada568 655 }
04e1eb03 656 while (ret == MAX_DISCARD_SIZE);
f4ada568 657
04e1eb03 658 delete[] buffer;
17aa2bec 659 m_lcount = total;
d775fa82 660 m_error = false;
17aa2bec 661
dc5c1114 662 // Allow read events again
d775fa82 663 m_reading = false;
96db102a 664
96db102a 665 return *this;
f4ada568
GL
666}
667
ef57d866
GRG
668// --------------------------------------------------------------------------
669// Wait functions
670// --------------------------------------------------------------------------
f4ada568 671
ef57d866
GRG
672// All Wait functions poll the socket using GSocket_Select() to
673// check for the specified combination of conditions, until one
674// of these conditions become true, an error occurs, or the
675// timeout elapses. The polling loop calls PROCESS_EVENTS(), so
676// this won't block the GUI.
f4ada568 677
bffc1eaa
GRG
678bool wxSocketBase::_Wait(long seconds,
679 long milliseconds,
d3ea6527 680 wxSocketEventFlags flags)
375abe3d 681{
56d8adc0 682 GSocketEventFlags result;
56d8adc0 683 long timeout;
375abe3d 684
d775fa82
WS
685 // Set this to true to interrupt ongoing waits
686 m_interrupt = false;
81b92e17 687
ef57d866 688 // Check for valid socket
af2fd961 689 if (!m_socket)
d775fa82 690 return false;
af2fd961 691
71622a7a 692 // Check for valid timeout value.
56d8adc0
GRG
693 if (seconds != -1)
694 timeout = seconds * 1000 + milliseconds;
695 else
696 timeout = m_timeout * 1000;
a324a7bc 697
3c57bda5 698 bool has_event_loop = wxTheApp->GetTraits() ? (wxTheApp->GetTraits()->GetSocketGUIFunctionsTable() ? true : false) : false;
f01bca89 699
bffc1eaa 700 // Wait in an active polling loop.
af2fd961 701 //
bffc1eaa
GRG
702 // NOTE: We duplicate some of the code in OnRequest, but this doesn't
703 // hurt. It has to be here because the (GSocket) event might arrive
704 // a bit delayed, and it has to be in OnRequest as well because we
705 // don't know whether the Wait functions are being used.
af2fd961 706 //
96db102a 707 // Do this at least once (important if timeout == 0, when
d3ea6527 708 // we are just polling). Also, if just polling, do not yield.
ef57d866 709
204b046e
KH
710 wxDateTime current_time = wxDateTime::UNow();
711 unsigned int time_limit = (current_time.GetTicks() * 1000) + current_time.GetMillisecond() + timeout;
d775fa82 712 bool done = false;
204b046e
KH
713 bool valid_result = false;
714
8e3f3880 715 if (!has_event_loop)
f01bca89 716 {
204b046e
KH
717 // This is used to avoid a busy loop on wxBase - having a select
718 // timeout of 50 ms per iteration should be enough.
719 if (timeout > 50)
720 m_socket->SetTimeout(50);
721 else
722 m_socket->SetTimeout(timeout);
f01bca89 723 }
71622a7a
GRG
724
725 while (!done)
56d8adc0 726 {
8b6fc577 727 result = m_socket->Select(flags | GSOCK_LOST_FLAG);
af2fd961 728
af2fd961
GRG
729 // Incoming connection (server) or connection established (client)
730 if (result & GSOCK_CONNECTION_FLAG)
731 {
d775fa82
WS
732 m_connected = true;
733 m_establishing = false;
204b046e
KH
734 valid_result = true;
735 break;
af2fd961
GRG
736 }
737
04e1eb03 738 // Data available or output buffer ready
81b92e17 739 if ((result & GSOCK_INPUT_FLAG) || (result & GSOCK_OUTPUT_FLAG))
af2fd961 740 {
204b046e
KH
741 valid_result = true;
742 break;
af2fd961
GRG
743 }
744
c0043a50
GRG
745 // Connection lost
746 if (result & GSOCK_LOST_FLAG)
747 {
d775fa82
WS
748 m_connected = false;
749 m_establishing = false;
204b046e
KH
750 valid_result = ((flags & GSOCK_LOST_FLAG) != 0);
751 break;
c0043a50
GRG
752 }
753
81b92e17 754 // Wait more?
204b046e
KH
755 current_time = wxDateTime::UNow();
756 int time_left = time_limit - ((current_time.GetTicks() * 1000) + current_time.GetMillisecond());
757 if ((!timeout) || (time_left <= 0) || (m_interrupt))
d775fa82 758 done = true;
d3ea6527 759 else
204b046e 760 {
8e3f3880 761 if (has_event_loop)
f01bca89
JS
762 {
763 PROCESS_EVENTS();
764 }
8e3f3880 765 else
f01bca89 766 {
204b046e
KH
767 // If there's less than 50 ms left, just call select with that timeout.
768 if (time_left < 50)
769 m_socket->SetTimeout(time_left);
f01bca89
JS
770 }
771 }
56d8adc0 772 }
f4ada568 773
204b046e 774 // Set timeout back to original value (we overwrote it for polling)
f01bca89
JS
775 if (!has_event_loop)
776 m_socket->SetTimeout(m_timeout*1000);
204b046e
KH
777
778 return valid_result;
f4ada568 779}
f4ada568 780
a737331d 781bool wxSocketBase::Wait(long seconds, long milliseconds)
f4ada568 782{
7fb0a11d
WS
783 return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG |
784 GSOCK_OUTPUT_FLAG |
785 GSOCK_CONNECTION_FLAG |
786 GSOCK_LOST_FLAG);
f4ada568 787}
f4ada568 788
a737331d 789bool wxSocketBase::WaitForRead(long seconds, long milliseconds)
f4ada568 790{
ef57d866 791 // Check pushback buffer before entering _Wait
96db102a 792 if (m_unread)
d775fa82 793 return true;
96db102a 794
ef57d866 795 // Note that GSOCK_INPUT_LOST has to be explicitly passed to
90e572f1 796 // _Wait because of the semantics of WaitForRead: a return
d775fa82 797 // value of true means that a GSocket_Read call will return
ef57d866
GRG
798 // immediately, not that there is actually data to read.
799
800 return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG |
801 GSOCK_LOST_FLAG);
f4ada568
GL
802}
803
bfa7bf7d 804
a737331d 805bool wxSocketBase::WaitForWrite(long seconds, long milliseconds)
f4ada568 806{
7fb0a11d 807 return _Wait(seconds, milliseconds, GSOCK_OUTPUT_FLAG);
a737331d 808}
f4ada568 809
a737331d
GL
810bool wxSocketBase::WaitForLost(long seconds, long milliseconds)
811{
7fb0a11d 812 return _Wait(seconds, milliseconds, GSOCK_LOST_FLAG);
f4ada568 813}
a737331d 814
ef57d866
GRG
815// --------------------------------------------------------------------------
816// Miscellaneous
817// --------------------------------------------------------------------------
818
819//
820// Get local or peer address
821//
822
823bool wxSocketBase::GetPeer(wxSockAddress& addr_man) const
824{
825 GAddress *peer;
826
827 if (!m_socket)
d775fa82 828 return false;
ef57d866 829
8b6fc577 830 peer = m_socket->GetPeer();
007c77ab
RL
831
832 // copying a null address would just trigger an assert anyway
833
834 if (!peer)
d775fa82 835 return false;
007c77ab 836
ef57d866
GRG
837 addr_man.SetAddress(peer);
838 GAddress_destroy(peer);
839
d775fa82 840 return true;
ef57d866
GRG
841}
842
843bool wxSocketBase::GetLocal(wxSockAddress& addr_man) const
844{
7fb0a11d 845 GAddress *local;
ef57d866 846
7fb0a11d
WS
847 if (!m_socket)
848 return false;
ef57d866 849
7fb0a11d
WS
850 local = m_socket->GetLocal();
851 addr_man.SetAddress(local);
852 GAddress_destroy(local);
ef57d866 853
7fb0a11d 854 return true;
ef57d866
GRG
855}
856
857//
858// Save and restore socket state
859//
860
861void wxSocketBase::SaveState()
862{
7fb0a11d 863 wxSocketState *state;
ef57d866 864
7fb0a11d 865 state = new wxSocketState();
ef57d866 866
7fb0a11d
WS
867 state->m_flags = m_flags;
868 state->m_notify = m_notify;
869 state->m_eventmask = m_eventmask;
870 state->m_clientData = m_clientData;
ef57d866 871
7fb0a11d 872 m_states.Append(state);
ef57d866
GRG
873}
874
875void wxSocketBase::RestoreState()
876{
7fb0a11d
WS
877 wxList::compatibility_iterator node;
878 wxSocketState *state;
ef57d866 879
7fb0a11d
WS
880 node = m_states.GetLast();
881 if (!node)
882 return;
ef57d866 883
7fb0a11d 884 state = (wxSocketState *)node->GetData();
ef57d866 885
7fb0a11d
WS
886 m_flags = state->m_flags;
887 m_notify = state->m_notify;
888 m_eventmask = state->m_eventmask;
889 m_clientData = state->m_clientData;
37340c48 890
7fb0a11d
WS
891 m_states.Erase(node);
892 delete state;
ef57d866
GRG
893}
894
895//
896// Timeout and flags
897//
898
17aa2bec
GRG
899void wxSocketBase::SetTimeout(long seconds)
900{
7fb0a11d 901 m_timeout = seconds;
17aa2bec 902
7fb0a11d
WS
903 if (m_socket)
904 m_socket->SetTimeout(m_timeout * 1000);
17aa2bec
GRG
905}
906
71622a7a 907void wxSocketBase::SetFlags(wxSocketFlags flags)
f4ada568 908{
7fb0a11d 909 m_flags = flags;
f4ada568 910}
f0a56ab0 911
f187448d 912
ef57d866 913// --------------------------------------------------------------------------
f187448d 914// Event handling
ef57d866 915// --------------------------------------------------------------------------
a324a7bc 916
bffc1eaa
GRG
917// A note on how events are processed, which is probably the most
918// difficult thing to get working right while keeping the same API
919// and functionality for all platforms.
920//
921// When GSocket detects an event, it calls wx_socket_callback, which in
922// turn just calls wxSocketBase::OnRequest in the corresponding wxSocket
923// object. OnRequest does some housekeeping, and if the event is to be
924// propagated to the user, it creates a new wxSocketEvent object and
925// posts it. The event is not processed immediately, but delayed with
926// AddPendingEvent instead. This is necessary in order to decouple the
927// event processing from wx_socket_callback; otherwise, subsequent IO
928// calls made from the user event handler would fail, as gtk callbacks
929// are not reentrant.
930//
931// Note that, unlike events, user callbacks (now deprecated) are _not_
932// decoupled from wx_socket_callback and thus they suffer from a variety
933// of problems. Avoid them where possible and use events instead.
96db102a 934
90350682
VZ
935extern "C"
936void LINKAGEMODE wx_socket_callback(GSocket * WXUNUSED(socket),
937 GSocketEvent notification,
938 char *cdata)
a324a7bc 939{
7fb0a11d 940 wxSocketBase *sckobj = (wxSocketBase *)cdata;
a324a7bc 941
7fb0a11d 942 sckobj->OnRequest((wxSocketNotify) notification);
56d8adc0 943}
a324a7bc 944
bffc1eaa 945void wxSocketBase::OnRequest(wxSocketNotify notification)
f4ada568 946{
bffc1eaa
GRG
947 // NOTE: We duplicate some of the code in _Wait, but this doesn't
948 // hurt. It has to be here because the (GSocket) event might arrive
949 // a bit delayed, and it has to be in _Wait as well because we don't
950 // know whether the Wait functions are being used.
ef57d866 951
bffc1eaa 952 switch(notification)
d80d1aba 953 {
04e1eb03 954 case wxSOCKET_CONNECTION:
d775fa82
WS
955 m_establishing = false;
956 m_connected = true;
04e1eb03
GRG
957 break;
958
d3ea6527
GRG
959 // If we are in the middle of a R/W operation, do not
960 // propagate events to users. Also, filter 'late' events
961 // which are no longer valid.
ef57d866 962
04e1eb03 963 case wxSOCKET_INPUT:
8b6fc577 964 if (m_reading || !m_socket->Select(GSOCK_INPUT_FLAG))
04e1eb03
GRG
965 return;
966 break;
967
968 case wxSOCKET_OUTPUT:
8b6fc577 969 if (m_writing || !m_socket->Select(GSOCK_OUTPUT_FLAG))
04e1eb03
GRG
970 return;
971 break;
972
973 case wxSOCKET_LOST:
d775fa82
WS
974 m_connected = false;
975 m_establishing = false;
04e1eb03
GRG
976 break;
977
978 default:
979 break;
96db102a
GRG
980 }
981
f187448d
GRG
982 // Schedule the event
983
52fbdb58 984 wxSocketEventFlags flag = 0;
999836aa 985 wxUnusedVar(flag);
bffc1eaa 986 switch (notification)
f187448d
GRG
987 {
988 case GSOCK_INPUT: flag = GSOCK_INPUT_FLAG; break;
989 case GSOCK_OUTPUT: flag = GSOCK_OUTPUT_FLAG; break;
990 case GSOCK_CONNECTION: flag = GSOCK_CONNECTION_FLAG; break;
991 case GSOCK_LOST: flag = GSOCK_LOST_FLAG; break;
52fbdb58 992 default:
5c9eff30 993 wxLogWarning(_("wxSocket: unknown event!."));
52fbdb58 994 return;
f187448d
GRG
995 }
996
bffc1eaa 997 if (((m_eventmask & flag) == flag) && m_notify)
d80d1aba 998 {
f187448d 999 if (m_handler)
bffc1eaa
GRG
1000 {
1001 wxSocketEvent event(m_id);
1002 event.m_event = notification;
1003 event.m_clientData = m_clientData;
1004 event.SetEventObject(this);
1005
f187448d 1006 m_handler->AddPendingEvent(event);
bffc1eaa 1007 }
f4ada568 1008 }
f4ada568
GL
1009}
1010
f187448d
GRG
1011void wxSocketBase::Notify(bool notify)
1012{
7fb0a11d 1013 m_notify = notify;
f187448d
GRG
1014}
1015
1016void wxSocketBase::SetNotify(wxSocketEventFlags flags)
1017{
7fb0a11d 1018 m_eventmask = flags;
f187448d
GRG
1019}
1020
71622a7a 1021void wxSocketBase::SetEventHandler(wxEvtHandler& handler, int id)
f4ada568 1022{
7fb0a11d
WS
1023 m_handler = &handler;
1024 m_id = id;
f4ada568
GL
1025}
1026
ef57d866
GRG
1027// --------------------------------------------------------------------------
1028// Pushback buffer
1029// --------------------------------------------------------------------------
db131261 1030
f187448d 1031void wxSocketBase::Pushback(const void *buffer, wxUint32 size)
f4ada568 1032{
dc5c1114
GRG
1033 if (!size) return;
1034
a324a7bc 1035 if (m_unread == NULL)
f187448d 1036 m_unread = malloc(size);
dc5c1114
GRG
1037 else
1038 {
f187448d 1039 void *tmp;
f4ada568 1040
f187448d
GRG
1041 tmp = malloc(m_unrd_size + size);
1042 memcpy((char *)tmp + size, m_unread, m_unrd_size);
41895a05 1043 free(m_unread);
a324a7bc
GL
1044
1045 m_unread = tmp;
41895a05 1046 }
31528cd3 1047
f4ada568 1048 m_unrd_size += size;
a324a7bc
GL
1049
1050 memcpy(m_unread, buffer, size);
f4ada568
GL
1051}
1052
f187448d 1053wxUint32 wxSocketBase::GetPushback(void *buffer, wxUint32 size, bool peek)
f4ada568
GL
1054{
1055 if (!m_unrd_size)
1056 return 0;
1057
a324a7bc
GL
1058 if (size > (m_unrd_size-m_unrd_cur))
1059 size = m_unrd_size-m_unrd_cur;
96db102a 1060
f187448d 1061 memcpy(buffer, (char *)m_unread + m_unrd_cur, size);
f4ada568 1062
dc5c1114
GRG
1063 if (!peek)
1064 {
a324a7bc 1065 m_unrd_cur += size;
dc5c1114
GRG
1066 if (m_unrd_size == m_unrd_cur)
1067 {
f4ada568
GL
1068 free(m_unread);
1069 m_unread = NULL;
a324a7bc
GL
1070 m_unrd_size = 0;
1071 m_unrd_cur = 0;
f4ada568
GL
1072 }
1073 }
1074
1075 return size;
1076}
1077
f187448d 1078
ef57d866 1079// ==========================================================================
c3e646b4 1080// wxSocketServer
ef57d866 1081// ==========================================================================
f4ada568 1082
ef57d866
GRG
1083// --------------------------------------------------------------------------
1084// Ctor
1085// --------------------------------------------------------------------------
56d8adc0 1086
fbfb8bcc 1087wxSocketServer::wxSocketServer(const wxSockAddress& addr_man,
71622a7a
GRG
1088 wxSocketFlags flags)
1089 : wxSocketBase(flags, wxSOCKET_SERVER)
f4ada568 1090{
007c77ab 1091 wxLogTrace( wxTRACE_Socket, _T("Opening wxSocketServer") );
f4ada568 1092
007c77ab 1093 m_socket = GSocket_new();
384b4373 1094
007c77ab
RL
1095 if (!m_socket)
1096 {
1097 wxLogTrace( wxTRACE_Socket, _T("*** GSocket_new failed") );
1098 return;
1099 }
a737331d 1100
007c77ab 1101 // Setup the socket as server
56d8adc0 1102
8b6fc577 1103 m_socket->SetLocal(addr_man.GetAddress());
d775fa82 1104
74c481d1 1105 if (GetFlags() & wxSOCKET_REUSEADDR) {
8b6fc577 1106 m_socket->SetReusable();
74c481d1
VZ
1107 }
1108
8b6fc577 1109 if (m_socket->SetServer() != GSOCK_NOERROR)
007c77ab 1110 {
8b6fc577 1111 delete m_socket;
007c77ab
RL
1112 m_socket = NULL;
1113
1114 wxLogTrace( wxTRACE_Socket, _T("*** GSocket_SetServer failed") );
1115 return;
1116 }
1117
8b6fc577
DE
1118 m_socket->SetTimeout(m_timeout * 1000);
1119 m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
007c77ab
RL
1120 GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
1121 wx_socket_callback, (char *)this);
f4ada568
GL
1122}
1123
ef57d866
GRG
1124// --------------------------------------------------------------------------
1125// Accept
1126// --------------------------------------------------------------------------
8c14576d 1127
d80d1aba 1128bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait)
f4ada568 1129{
a324a7bc 1130 GSocket *child_socket;
f4ada568 1131
17aa2bec 1132 if (!m_socket)
d775fa82 1133 return false;
17aa2bec 1134
d775fa82 1135 // If wait == false, then the call should be nonblocking.
56d8adc0
GRG
1136 // When we are finished, we put the socket to blocking mode
1137 // again.
d80d1aba
GRG
1138
1139 if (!wait)
8b6fc577 1140 m_socket->SetNonBlocking(1);
d80d1aba 1141
8b6fc577 1142 child_socket = m_socket->WaitConnection();
384b4373 1143
d80d1aba 1144 if (!wait)
8b6fc577 1145 m_socket->SetNonBlocking(0);
d80d1aba 1146
04e1eb03 1147 if (!child_socket)
d775fa82 1148 return false;
d80d1aba 1149
71622a7a 1150 sock.m_type = wxSOCKET_BASE;
a324a7bc 1151 sock.m_socket = child_socket;
d775fa82 1152 sock.m_connected = true;
f4ada568 1153
8b6fc577
DE
1154 sock.m_socket->SetTimeout(sock.m_timeout * 1000);
1155 sock.m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
56d8adc0
GRG
1156 GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
1157 wx_socket_callback, (char *)&sock);
1158
d775fa82 1159 return true;
f4ada568
GL
1160}
1161
d80d1aba 1162wxSocketBase *wxSocketServer::Accept(bool wait)
f4ada568
GL
1163{
1164 wxSocketBase* sock = new wxSocketBase();
1165
71622a7a 1166 sock->SetFlags(m_flags);
f4ada568 1167
d80d1aba 1168 if (!AcceptWith(*sock, wait))
c3e646b4
VZ
1169 {
1170 sock->Destroy();
1171 sock = NULL;
1172 }
f4ada568 1173
f4ada568
GL
1174 return sock;
1175}
1176
17aa2bec 1177bool wxSocketServer::WaitForAccept(long seconds, long milliseconds)
d80d1aba 1178{
7fb0a11d 1179 return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG);
d80d1aba
GRG
1180}
1181
bfa7bf7d
VZ
1182bool wxSocketBase::GetOption(int level, int optname, void *optval, int *optlen)
1183{
11734f8a
JS
1184 wxASSERT_MSG( m_socket, _T("Socket not initialised") );
1185
8b6fc577 1186 if (m_socket->GetSockOpt(level, optname, optval, optlen)
bfa7bf7d
VZ
1187 != GSOCK_NOERROR)
1188 {
d775fa82 1189 return false;
bfa7bf7d 1190 }
d775fa82 1191 return true;
bfa7bf7d
VZ
1192}
1193
37340c48 1194bool wxSocketBase::SetOption(int level, int optname, const void *optval,
bfa7bf7d
VZ
1195 int optlen)
1196{
11734f8a 1197 wxASSERT_MSG( m_socket, _T("Socket not initialised") );
8e3f3880 1198
8b6fc577 1199 if (m_socket->SetSockOpt(level, optname, optval, optlen)
bfa7bf7d
VZ
1200 != GSOCK_NOERROR)
1201 {
d775fa82 1202 return false;
bfa7bf7d 1203 }
d775fa82 1204 return true;
bfa7bf7d
VZ
1205}
1206
30bbf68d 1207bool wxSocketBase::SetLocal(wxIPV4address& local)
33d925b0
KH
1208{
1209 GAddress* la = local.GetAddress();
1210
30bbf68d 1211 // If the address is valid, save it for use when we call Connect
33d925b0
KH
1212 if (la && la->m_addr)
1213 {
30bbf68d 1214 m_localAddress = local;
33d925b0
KH
1215
1216 return true;
1217 }
1218
1219 return false;
1220}
1221
ef57d866 1222// ==========================================================================
8c14576d 1223// wxSocketClient
ef57d866 1224// ==========================================================================
f4ada568 1225
ef57d866
GRG
1226// --------------------------------------------------------------------------
1227// Ctor and dtor
1228// --------------------------------------------------------------------------
56d8adc0 1229
71622a7a
GRG
1230wxSocketClient::wxSocketClient(wxSocketFlags flags)
1231 : wxSocketBase(flags, wxSOCKET_CLIENT)
f4ada568
GL
1232{
1233}
1234
f4ada568
GL
1235wxSocketClient::~wxSocketClient()
1236{
1237}
1238
ef57d866
GRG
1239// --------------------------------------------------------------------------
1240// Connect
1241// --------------------------------------------------------------------------
dc5c1114 1242
33d925b0 1243bool wxSocketClient::DoConnect(wxSockAddress& addr_man, wxSockAddress* local, bool wait)
f4ada568 1244{
791b24c4
GRG
1245 GSocketError err;
1246
ef57d866 1247 if (m_socket)
04e1eb03
GRG
1248 {
1249 // Shutdown and destroy the socket
f4ada568 1250 Close();
8b6fc577 1251 delete m_socket;
04e1eb03 1252 }
a324a7bc 1253
a324a7bc 1254 m_socket = GSocket_new();
d775fa82
WS
1255 m_connected = false;
1256 m_establishing = false;
384b4373 1257
a324a7bc 1258 if (!m_socket)
d775fa82 1259 return false;
384b4373 1260
8b6fc577
DE
1261 m_socket->SetTimeout(m_timeout * 1000);
1262 m_socket->SetCallback(GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
96db102a
GRG
1263 GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
1264 wx_socket_callback, (char *)this);
56d8adc0 1265
d775fa82 1266 // If wait == false, then the call should be nonblocking.
56d8adc0
GRG
1267 // When we are finished, we put the socket to blocking mode
1268 // again.
f4ada568 1269
791b24c4 1270 if (!wait)
8b6fc577 1271 m_socket->SetNonBlocking(1);
791b24c4 1272
33d925b0
KH
1273 // Reuse makes sense for clients too, if we are trying to rebind to the same port
1274 if (GetFlags() & wxSOCKET_REUSEADDR)
1275 {
1276 m_socket->SetReusable();
1277 }
1278
30bbf68d
KH
1279 // If no local address was passed and one has been set, use the one that was Set
1280 if (!local && m_localAddress.GetAddress())
1281 {
1282 local = &m_localAddress;
1283 }
1284
33d925b0
KH
1285 // Bind to the local IP address and port, when provided
1286 if (local)
1287 {
1288 GAddress* la = local->GetAddress();
1289
1290 if (la && la->m_addr)
1291 m_socket->SetLocal(la);
1292 }
1293
8b6fc577
DE
1294 m_socket->SetPeer(addr_man.GetAddress());
1295 err = m_socket->Connect(GSOCK_STREAMED);
791b24c4
GRG
1296
1297 if (!wait)
8b6fc577 1298 m_socket->SetNonBlocking(0);
791b24c4
GRG
1299
1300 if (err != GSOCK_NOERROR)
56d8adc0
GRG
1301 {
1302 if (err == GSOCK_WOULDBLOCK)
d775fa82 1303 m_establishing = true;
56d8adc0 1304
d775fa82 1305 return false;
56d8adc0 1306 }
9111db68 1307
d775fa82
WS
1308 m_connected = true;
1309 return true;
f4ada568
GL
1310}
1311
33d925b0
KH
1312bool wxSocketClient::Connect(wxSockAddress& addr_man, bool wait)
1313{
7fb0a11d 1314 return (DoConnect(addr_man, NULL, wait));
33d925b0
KH
1315}
1316
1317bool wxSocketClient::Connect(wxSockAddress& addr_man, wxSockAddress& local, bool wait)
1318{
7fb0a11d 1319 return (DoConnect(addr_man, &local, wait));
33d925b0
KH
1320}
1321
d80d1aba 1322bool wxSocketClient::WaitOnConnect(long seconds, long milliseconds)
f4ada568 1323{
7fb0a11d
WS
1324 if (m_connected) // Already connected
1325 return true;
d80d1aba 1326
7fb0a11d
WS
1327 if (!m_establishing || !m_socket) // No connection in progress
1328 return false;
d80d1aba 1329
7fb0a11d
WS
1330 return _Wait(seconds, milliseconds, GSOCK_CONNECTION_FLAG |
1331 GSOCK_LOST_FLAG);
f4ada568
GL
1332}
1333
ef57d866 1334// ==========================================================================
dc5c1114 1335// wxDatagramSocket
ef57d866 1336// ==========================================================================
dc5c1114
GRG
1337
1338/* NOTE: experimental stuff - might change */
1339
fbfb8bcc 1340wxDatagramSocket::wxDatagramSocket( const wxSockAddress& addr,
71622a7a
GRG
1341 wxSocketFlags flags )
1342 : wxSocketBase( flags, wxSOCKET_DATAGRAM )
dc5c1114 1343{
7fb0a11d
WS
1344 // Create the socket
1345 m_socket = GSocket_new();
dc5c1114 1346
7fb0a11d
WS
1347 if(!m_socket)
1348 {
1349 wxFAIL_MSG( _T("datagram socket not new'd") );
1350 return;
1351 }
1352 // Setup the socket as non connection oriented
1353 m_socket->SetLocal(addr.GetAddress());
1354 if( m_socket->SetNonOriented() != GSOCK_NOERROR )
1355 {
1356 delete m_socket;
1357 m_socket = NULL;
1358 return;
1359 }
dc5c1114 1360
7fb0a11d
WS
1361 // Initialize all stuff
1362 m_connected = false;
1363 m_establishing = false;
1364 m_socket->SetTimeout( m_timeout );
1365 m_socket->SetCallback( GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
1366 GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
1367 wx_socket_callback, (char*)this );
dc5c1114
GRG
1368}
1369
1370wxDatagramSocket& wxDatagramSocket::RecvFrom( wxSockAddress& addr,
f187448d 1371 void* buf,
dc5c1114
GRG
1372 wxUint32 nBytes )
1373{
1374 Read(buf, nBytes);
1375 GetPeer(addr);
1376 return (*this);
1377}
1378
fbfb8bcc 1379wxDatagramSocket& wxDatagramSocket::SendTo( const wxSockAddress& addr,
f187448d 1380 const void* buf,
dc5c1114
GRG
1381 wxUint32 nBytes )
1382{
11734f8a 1383 wxASSERT_MSG( m_socket, _T("Socket not initialised") );
8e3f3880 1384
8b6fc577 1385 m_socket->SetPeer(addr.GetAddress());
dc5c1114
GRG
1386 Write(buf, nBytes);
1387 return (*this);
1388}
1389
ef57d866 1390// ==========================================================================
a58d5df4 1391// wxSocketModule
ef57d866 1392// ==========================================================================
dc5c1114 1393
ed4c6c69 1394class wxSocketModule : public wxModule
dc5c1114 1395{
dc5c1114 1396public:
6c0d0845
VZ
1397 virtual bool OnInit()
1398 {
1399 // wxSocketBase will call GSocket_Init() itself when/if needed
d775fa82 1400 return true;
6c0d0845
VZ
1401 }
1402
1403 virtual void OnExit()
1404 {
1405 if ( wxSocketBase::IsInitialized() )
1406 wxSocketBase::Shutdown();
1407 }
1408
1409private:
1410 DECLARE_DYNAMIC_CLASS(wxSocketModule)
a58d5df4
GL
1411};
1412
1413IMPLEMENT_DYNAMIC_CLASS(wxSocketModule, wxModule)
1414
35a4dab7
GL
1415#endif
1416 // wxUSE_SOCKETS