]> git.saurik.com Git - wxWidgets.git/blame - src/common/socket.cpp
compilation fix after last change
[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 6// Copyright: (C) 1999-1997, Guilhem Lavaux
51fe4b60
VZ
7// (C) 1999-2000, Guillermo Rodriguez Garcia
8// (C) 2008 Vadim Zeitlin
f4ada568 9// RCS_ID: $Id$
7fb0a11d 10// License: wxWindows licence
56d8adc0
GRG
11/////////////////////////////////////////////////////////////////////////////
12
bffc1eaa
GRG
13// ==========================================================================
14// Declarations
15// ==========================================================================
16
fcc6dddd
JS
17// For compilers that support precompilation, includes "wx.h".
18#include "wx/wxprec.h"
19
20#ifdef __BORLANDC__
8e3f3880 21 #pragma hdrstop
fcc6dddd
JS
22#endif
23
35a4dab7
GL
24#if wxUSE_SOCKETS
25
df91131c
WS
26#include "wx/socket.h"
27
8e3f3880
WS
28#ifndef WX_PRECOMP
29 #include "wx/object.h"
df91131c 30 #include "wx/string.h"
88a7a4e1 31 #include "wx/intl.h"
e4db172a 32 #include "wx/log.h"
d5da0ce7 33 #include "wx/event.h"
670f9935 34 #include "wx/app.h"
de6185e2 35 #include "wx/utils.h"
c0badb70 36 #include "wx/timer.h"
02761f6c 37 #include "wx/module.h"
8e3f3880
WS
38#endif
39
e2478fde 40#include "wx/apptrait.h"
56d8adc0 41#include "wx/sckaddr.h"
4252569b 42#include "wx/stopwatch.h"
204abcd4 43#include "wx/thread.h"
2804f77d 44#include "wx/evtloop.h"
02564412 45
40e7c0b9 46#include "wx/private/fd.h"
60913641 47#include "wx/private/socket.h"
3b4183d8 48
14372de8
VZ
49#ifdef __UNIX__
50 #include <errno.h>
51#endif
52
53// we use MSG_NOSIGNAL to avoid getting SIGPIPE when sending data to a remote
54// host which closed the connection if it is available, otherwise we rely on
55// SO_NOSIGPIPE existency
56//
57// this should cover all the current Unix systems (Windows never sends any
58// signals anyhow) but if we find one that has neither we should explicitly
59// ignore SIGPIPE for it
60#ifdef MSG_NOSIGNAL
61 #define wxSOCKET_MSG_NOSIGNAL MSG_NOSIGNAL
62#else // MSG_NOSIGNAL not available (BSD including OS X)
63 #if defined(__UNIX__) && !defined(SO_NOSIGPIPE)
64 #error "Writing to socket could generate unhandled SIGPIPE."
65 #error "Please post information about your system to wx-dev."
66 #endif
67
68 #define wxSOCKET_MSG_NOSIGNAL 0
69#endif
70
34fdf762
VS
71// DLL options compatibility check:
72#include "wx/build.h"
73WX_CHECK_BUILD_OPTIONS("wxNet")
74
bffc1eaa
GRG
75// --------------------------------------------------------------------------
76// macros and constants
77// --------------------------------------------------------------------------
ef57d866 78
dc5c1114
GRG
79// discard buffer
80#define MAX_DISCARD_SIZE (10 * 1024)
96db102a 81
007c77ab
RL
82#define wxTRACE_Socket _T("wxSocket")
83
ef57d866 84// --------------------------------------------------------------------------
bffc1eaa 85// wxWin macros
ef57d866 86// --------------------------------------------------------------------------
81b92e17 87
a737331d
GL
88IMPLEMENT_CLASS(wxSocketBase, wxObject)
89IMPLEMENT_CLASS(wxSocketServer, wxSocketBase)
90IMPLEMENT_CLASS(wxSocketClient, wxSocketBase)
dc5c1114 91IMPLEMENT_CLASS(wxDatagramSocket, wxSocketBase)
a737331d 92IMPLEMENT_DYNAMIC_CLASS(wxSocketEvent, wxEvent)
f4ada568 93
00414faf
VZ
94// ----------------------------------------------------------------------------
95// private functions
96// ----------------------------------------------------------------------------
97
98namespace
99{
100
101void SetTimeValFromMS(timeval& tv, unsigned long ms)
102{
103 tv.tv_sec = (ms / 1000);
104 tv.tv_usec = (ms % 1000) * 1000;
105}
106
107} // anonymous namespace
108
bffc1eaa
GRG
109// --------------------------------------------------------------------------
110// private classes
111// --------------------------------------------------------------------------
112
56d8adc0
GRG
113class wxSocketState : public wxObject
114{
a324a7bc 115public:
c2116a35
VZ
116 wxSocketFlags m_flags;
117 wxSocketEventFlags m_eventmask;
118 bool m_notify;
119 void *m_clientData;
a324a7bc
GL
120
121public:
c2116a35 122 wxSocketState() : wxObject() {}
22f3361e 123
c2116a35 124 DECLARE_NO_COPY_CLASS(wxSocketState)
a324a7bc
GL
125};
126
2804f77d 127// ============================================================================
51fe4b60 128// wxSocketManager
2804f77d
VZ
129// ============================================================================
130
51fe4b60 131wxSocketManager *wxSocketManager::ms_manager = NULL;
2804f77d
VZ
132
133/* static */
51fe4b60 134void wxSocketManager::Set(wxSocketManager *manager)
2804f77d
VZ
135{
136 wxASSERT_MSG( !ms_manager, "too late to set manager now" );
137
138 ms_manager = manager;
139}
140
141/* static */
51fe4b60 142void wxSocketManager::Init()
2804f77d
VZ
143{
144 wxASSERT_MSG( !ms_manager, "shouldn't be initialized twice" );
145
146 /*
147 Details: Initialize() creates a hidden window as a sink for socket
148 events, such as 'read completed'. wxMSW has only one message loop
149 for the main thread. If Initialize is called in a secondary thread,
150 the socket window will be created for the secondary thread, but
151 since there is no message loop on this thread, it will never
152 receive events and all socket operations will time out.
153 BTW, the main thread must not be stopped using sleep or block
154 on a semaphore (a bad idea in any case) or socket operations
155 will time out.
156
157 On the Mac side, Initialize() stores a pointer to the CFRunLoop for
158 the main thread. Because secondary threads do not have run loops,
159 adding event notifications to the "Current" loop would have no
160 effect at all, events would never fire.
161 */
162 wxASSERT_MSG( wxIsMainThread(),
163 "sockets must be initialized from the main thread" );
164
165 wxAppConsole * const app = wxAppConsole::GetInstance();
166 wxCHECK_RET( app, "sockets can't be initialized without wxApp" );
167
168 ms_manager = app->GetTraits()->GetSocketManager();
169}
170
eb97543d 171// ==========================================================================
51fe4b60 172// wxSocketImpl
eb97543d
VZ
173// ==========================================================================
174
51fe4b60 175wxSocketImpl::wxSocketImpl(wxSocketBase& wxsocket)
53a161e1 176 : m_wxsocket(&wxsocket)
eb97543d
VZ
177{
178 m_fd = INVALID_SOCKET;
51fe4b60 179 m_error = wxSOCKET_NOERROR;
eb97543d
VZ
180 m_server = false;
181 m_stream = true;
53a161e1
VZ
182
183 SetTimeout(wxsocket.GetTimeout() * 1000);
eb97543d
VZ
184
185 m_establishing = false;
186 m_reusable = false;
187 m_broadcast = false;
188 m_dobind = true;
189 m_initialRecvBufferSize = -1;
190 m_initialSendBufferSize = -1;
eb97543d
VZ
191}
192
51fe4b60 193wxSocketImpl::~wxSocketImpl()
eb97543d 194{
c9bccf23 195 if ( m_fd != INVALID_SOCKET )
eb97543d 196 Shutdown();
51fe4b60
VZ
197}
198
c9bccf23 199bool wxSocketImpl::PreCreateCheck(const wxSockAddressImpl& addr)
51fe4b60
VZ
200{
201 if ( m_fd != INVALID_SOCKET )
202 {
203 m_error = wxSOCKET_INVSOCK;
204 return false;
205 }
206
c9bccf23 207 if ( !addr.IsOk() )
51fe4b60
VZ
208 {
209 m_error = wxSOCKET_INVADDR;
210 return false;
211 }
212
213 return true;
214}
215
216void wxSocketImpl::PostCreation()
217{
218 // FreeBSD variants can't use MSG_NOSIGNAL, and instead use a socket option
219#ifdef SO_NOSIGPIPE
220 EnableSocketOption(SO_NOSIGPIPE);
221#endif
222
223 if ( m_reusable )
224 EnableSocketOption(SO_REUSEADDR);
225
226 if ( m_broadcast )
227 {
228 wxASSERT_MSG( !m_stream, "broadcasting is for datagram sockets only" );
229
230 EnableSocketOption(SO_BROADCAST);
231 }
232
233 if ( m_initialRecvBufferSize >= 0 )
234 SetSocketOption(SO_RCVBUF, m_initialRecvBufferSize);
235 if ( m_initialSendBufferSize >= 0 )
236 SetSocketOption(SO_SNDBUF, m_initialSendBufferSize);
eb97543d 237
2b036c4b
VZ
238 // we always put our sockets in unblocked mode and handle blocking
239 // ourselves in DoRead/Write() if wxSOCKET_WAITALL is specified
51fe4b60 240 UnblockAndRegisterWithEventLoop();
eb97543d
VZ
241}
242
51fe4b60
VZ
243wxSocketError wxSocketImpl::UpdateLocalAddress()
244{
c9bccf23
VZ
245 WX_SOCKLEN_T lenAddr = m_local.GetLen();
246 if ( getsockname(m_fd, m_local.GetWritableAddr(), &lenAddr) != 0 )
51fe4b60
VZ
247 {
248 Close();
249 m_error = wxSOCKET_IOERR;
250 return m_error;
251 }
252
51fe4b60
VZ
253 return wxSOCKET_NOERROR;
254}
255
256wxSocketError wxSocketImpl::CreateServer()
257{
258 if ( !PreCreateCheck(m_local) )
259 return m_error;
260
261 m_server = true;
262 m_stream = true;
263
264 // do create the socket
c9bccf23 265 m_fd = socket(m_local.GetFamily(), SOCK_STREAM, 0);
51fe4b60
VZ
266
267 if ( m_fd == INVALID_SOCKET )
268 {
269 m_error = wxSOCKET_IOERR;
270 return wxSOCKET_IOERR;
271 }
272
273 PostCreation();
274
275 // and then bind to and listen on it
276 //
277 // FIXME: should we test for m_dobind here?
c9bccf23 278 if ( bind(m_fd, m_local.GetAddr(), m_local.GetLen()) != 0 )
51fe4b60
VZ
279 m_error = wxSOCKET_IOERR;
280
281 if ( IsOk() )
282 {
283 if ( listen(m_fd, 5) != 0 )
284 m_error = wxSOCKET_IOERR;
285 }
286
287 if ( !IsOk() )
288 {
289 Close();
290 return m_error;
291 }
292
293 // finally retrieve the address we effectively bound to
294 return UpdateLocalAddress();
295}
296
2b036c4b 297wxSocketError wxSocketImpl::CreateClient(bool wait)
51fe4b60
VZ
298{
299 if ( !PreCreateCheck(m_peer) )
300 return m_error;
301
c9bccf23 302 m_fd = socket(m_peer.GetFamily(), SOCK_STREAM, 0);
51fe4b60
VZ
303
304 if ( m_fd == INVALID_SOCKET )
305 {
2b036c4b
VZ
306 m_error = wxSOCKET_IOERR;
307 return wxSOCKET_IOERR;
51fe4b60
VZ
308 }
309
310 PostCreation();
311
312 // If a local address has been set, then bind to it before calling connect
c9bccf23 313 if ( m_local.IsOk() )
51fe4b60 314 {
c9bccf23 315 if ( bind(m_fd, m_local.GetAddr(), m_local.GetLen()) != 0 )
51fe4b60
VZ
316 {
317 Close();
318 m_error = wxSOCKET_IOERR;
319 return m_error;
320 }
321 }
322
2b036c4b 323 // Do connect now
c9bccf23 324 int rc = connect(m_fd, m_peer.GetAddr(), m_peer.GetLen());
2b036c4b
VZ
325 if ( rc == SOCKET_ERROR )
326 {
327 wxSocketError err = GetLastError();
328 if ( err == wxSOCKET_WOULDBLOCK )
329 {
330 m_establishing = true;
331
332 // block waiting for connection if we should (otherwise just return
333 // wxSOCKET_WOULDBLOCK to the caller)
334 if ( wait )
335 {
336 err = SelectWithTimeout(wxSOCKET_CONNECTION_FLAG)
337 ? wxSOCKET_NOERROR
338 : wxSOCKET_TIMEDOUT;
339 m_establishing = false;
340 }
341 }
342
343 m_error = err;
344 }
345 else // connected
346 {
347 m_error = wxSOCKET_NOERROR;
348 }
349
350 return m_error;
51fe4b60
VZ
351}
352
353
354wxSocketError wxSocketImpl::CreateUDP()
355{
356 if ( !PreCreateCheck(m_local) )
357 return m_error;
358
359 m_stream = false;
360 m_server = false;
361
c9bccf23 362 m_fd = socket(m_local.GetFamily(), SOCK_DGRAM, 0);
51fe4b60
VZ
363
364 if ( m_fd == INVALID_SOCKET )
365 {
366 m_error = wxSOCKET_IOERR;
367 return wxSOCKET_IOERR;
368 }
369
370 PostCreation();
371
372 if ( m_dobind )
373 {
c9bccf23 374 if ( bind(m_fd, m_local.GetAddr(), m_local.GetLen()) != 0 )
51fe4b60
VZ
375 {
376 Close();
377 m_error = wxSOCKET_IOERR;
378 return m_error;
379 }
380
381 return UpdateLocalAddress();
382 }
383
384 return wxSOCKET_NOERROR;
385}
386
2b036c4b
VZ
387wxSocketImpl *wxSocketImpl::Accept(wxSocketBase& wxsocket)
388{
c9bccf23 389 wxSockAddressStorage from;
2b036c4b 390 WX_SOCKLEN_T fromlen = sizeof(from);
c9bccf23 391 const SOCKET fd = accept(m_fd, &from.addr, &fromlen);
2b036c4b
VZ
392
393 if ( fd == INVALID_SOCKET )
394 return NULL;
395
396 wxSocketImpl * const sock = Create(wxsocket);
397 sock->m_fd = fd;
c9bccf23 398 sock->m_peer = wxSockAddressImpl(from.addr, fromlen);
2b036c4b
VZ
399
400 sock->UnblockAndRegisterWithEventLoop();
401
402 return sock;
403}
404
51fe4b60
VZ
405
406void wxSocketImpl::Close()
f0fbbe23
VZ
407{
408 if ( m_fd != INVALID_SOCKET )
409 {
51fe4b60 410 DoClose();
f0fbbe23
VZ
411 m_fd = INVALID_SOCKET;
412 }
413}
414
51fe4b60 415/*
eb97543d
VZ
416 * Disallow further read/write operations on this socket, close
417 * the fd and disable all callbacks.
418 */
51fe4b60 419void wxSocketImpl::Shutdown()
eb97543d
VZ
420{
421 if ( m_fd != INVALID_SOCKET )
422 {
423 shutdown(m_fd, 1 /* SD_SEND */);
424 Close();
425 }
eb97543d
VZ
426}
427
51fe4b60 428/*
53a161e1
VZ
429 * Sets the timeout for blocking calls. Time is expressed in
430 * milliseconds.
431 */
51fe4b60 432void wxSocketImpl::SetTimeout(unsigned long millis)
53a161e1 433{
00414faf 434 SetTimeValFromMS(m_timeout, millis);
53a161e1
VZ
435}
436
51fe4b60 437void wxSocketImpl::NotifyOnStateChange(wxSocketNotify event)
53a161e1 438{
51fe4b60 439 m_wxsocket->OnRequest(event);
53a161e1
VZ
440}
441
02564412 442/* Address handling */
c9bccf23 443wxSocketError wxSocketImpl::SetLocal(const wxSockAddressImpl& local)
02564412 444{
c9bccf23
VZ
445 /* the socket must be initialized, or it must be a server */
446 if (m_fd != INVALID_SOCKET && !m_server)
447 {
448 m_error = wxSOCKET_INVSOCK;
449 return wxSOCKET_INVSOCK;
450 }
02564412 451
c9bccf23
VZ
452 if ( !local.IsOk() )
453 {
454 m_error = wxSOCKET_INVADDR;
455 return wxSOCKET_INVADDR;
456 }
02564412 457
c9bccf23 458 m_local = local;
02564412 459
c9bccf23 460 return wxSOCKET_NOERROR;
02564412
VZ
461}
462
c9bccf23 463wxSocketError wxSocketImpl::SetPeer(const wxSockAddressImpl& peer)
02564412 464{
c9bccf23
VZ
465 if ( !peer.IsOk() )
466 {
467 m_error = wxSOCKET_INVADDR;
468 return wxSOCKET_INVADDR;
469 }
02564412 470
c9bccf23 471 m_peer = peer;
02564412 472
c9bccf23 473 return wxSOCKET_NOERROR;
02564412
VZ
474}
475
c9bccf23 476const wxSockAddressImpl& wxSocketImpl::GetLocal()
02564412 477{
c9bccf23
VZ
478 if ( !m_local.IsOk() )
479 UpdateLocalAddress();
02564412 480
c9bccf23 481 return m_local;
02564412
VZ
482}
483
14372de8
VZ
484// ----------------------------------------------------------------------------
485// wxSocketImpl IO
486// ----------------------------------------------------------------------------
487
488// this macro wraps the given expression (normally a syscall) in a loop which
489// ignores any interruptions, i.e. reevaluates it again if it failed and errno
490// is EINTR
491#ifdef __UNIX__
492 #define DO_WHILE_EINTR( rc, syscall ) \
493 do { \
494 rc = (syscall); \
495 } \
496 while ( rc == -1 && errno == EINTR )
497#else
498 #define DO_WHILE_EINTR( rc, syscall ) rc = (syscall)
499#endif
500
501int wxSocketImpl::RecvStream(void *buffer, int size)
502{
503 int ret;
504 DO_WHILE_EINTR( ret, recv(m_fd, static_cast<char *>(buffer), size, 0) );
505
506 if ( !ret )
507 {
508 // receiving 0 bytes for a TCP socket indicates that the connection was
509 // closed by peer so shut down our end as well (for UDP sockets empty
510 // datagrams are also possible)
511 m_establishing = false;
512 NotifyOnStateChange(wxSOCKET_LOST);
513
514 Shutdown();
515
516 // do not return an error in this case however
517 }
518
519 return ret;
520}
521
522int wxSocketImpl::SendStream(const void *buffer, int size)
523{
524 int ret;
525 DO_WHILE_EINTR( ret, send(m_fd, static_cast<const char *>(buffer), size,
526 wxSOCKET_MSG_NOSIGNAL) );
527
528 return ret;
529}
530
531int wxSocketImpl::RecvDgram(void *buffer, int size)
532{
c9bccf23 533 wxSockAddressStorage from;
14372de8
VZ
534 WX_SOCKLEN_T fromlen = sizeof(from);
535
536 int ret;
537 DO_WHILE_EINTR( ret, recvfrom(m_fd, static_cast<char *>(buffer), size,
c9bccf23 538 0, &from.addr, &fromlen) );
14372de8
VZ
539
540 if ( ret == SOCKET_ERROR )
541 return SOCKET_ERROR;
542
c9bccf23
VZ
543 m_peer = wxSockAddressImpl(from.addr, fromlen);
544 if ( !m_peer.IsOk() )
14372de8 545 return -1;
14372de8
VZ
546
547 return ret;
548}
549
550int wxSocketImpl::SendDgram(const void *buffer, int size)
551{
c9bccf23 552 if ( !m_peer.IsOk() )
14372de8
VZ
553 {
554 m_error = wxSOCKET_INVADDR;
555 return -1;
556 }
557
14372de8
VZ
558 int ret;
559 DO_WHILE_EINTR( ret, sendto(m_fd, static_cast<const char *>(buffer), size,
c9bccf23 560 0, m_peer.GetAddr(), m_peer.GetLen()) );
14372de8
VZ
561
562 return ret;
563}
564
565int wxSocketImpl::Read(void *buffer, int size)
566{
567 // server sockets can't be used for IO, only to accept new connections
568 if ( m_fd == INVALID_SOCKET || m_server )
569 {
570 m_error = wxSOCKET_INVSOCK;
571 return -1;
572 }
573
574 int ret = m_stream ? RecvStream(buffer, size)
575 : RecvDgram(buffer, size);
576
577 m_error = ret == SOCKET_ERROR ? GetLastError() : wxSOCKET_NOERROR;
578
579 return ret;
580}
581
582int wxSocketImpl::Write(const void *buffer, int size)
583{
584 if ( m_fd == INVALID_SOCKET || m_server )
585 {
586 m_error = wxSOCKET_INVSOCK;
587 return -1;
588 }
589
590 int ret = m_stream ? SendStream(buffer, size)
591 : SendDgram(buffer, size);
592
593 m_error = ret == SOCKET_ERROR ? GetLastError() : wxSOCKET_NOERROR;
594
595 return ret;
596}
597
ef57d866
GRG
598// ==========================================================================
599// wxSocketBase
600// ==========================================================================
601
6c0d0845
VZ
602// --------------------------------------------------------------------------
603// Initialization and shutdown
604// --------------------------------------------------------------------------
605
606// FIXME-MT: all this is MT-unsafe, of course, we should protect all accesses
607// to m_countInit with a crit section
608size_t wxSocketBase::m_countInit = 0;
609
610bool wxSocketBase::IsInitialized()
611{
612 return m_countInit > 0;
613}
614
615bool wxSocketBase::Initialize()
616{
617 if ( !m_countInit++ )
618 {
51fe4b60
VZ
619 wxSocketManager * const manager = wxSocketManager::Get();
620 if ( !manager || !manager->OnInit() )
6c0d0845
VZ
621 {
622 m_countInit--;
623
d775fa82 624 return false;
6c0d0845
VZ
625 }
626 }
627
d775fa82 628 return true;
6c0d0845
VZ
629}
630
631void wxSocketBase::Shutdown()
632{
633 // we should be initialized
2804f77d 634 wxASSERT_MSG( m_countInit > 0, _T("extra call to Shutdown()") );
8d7eaf91 635 if ( --m_countInit == 0 )
6c0d0845 636 {
51fe4b60
VZ
637 wxSocketManager * const manager = wxSocketManager::Get();
638 wxCHECK_RET( manager, "should have a socket manager" );
639
640 manager->OnExit();
6c0d0845
VZ
641 }
642}
643
ef57d866
GRG
644// --------------------------------------------------------------------------
645// Ctor and dtor
646// --------------------------------------------------------------------------
56d8adc0 647
71622a7a 648void wxSocketBase::Init()
f4ada568 649{
51fe4b60 650 m_impl = NULL;
c2116a35
VZ
651 m_type = wxSOCKET_UNINIT;
652
653 // state
654 m_flags = 0;
655 m_connected =
656 m_establishing =
657 m_reading =
658 m_writing =
c2116a35
VZ
659 m_closed = false;
660 m_lcount = 0;
661 m_timeout = 600;
662 m_beingDeleted = false;
663
664 // pushback buffer
665 m_unread = NULL;
666 m_unrd_size = 0;
667 m_unrd_cur = 0;
668
669 // events
670 m_id = wxID_ANY;
671 m_handler = NULL;
672 m_clientData = NULL;
673 m_notify = false;
5c1193e0
VZ
674 m_eventmask =
675 m_eventsgot = 0;
c2116a35
VZ
676
677 if ( !IsInitialized() )
678 {
679 // this Initialize() will be undone by wxSocketModule::OnExit(), all
680 // the other calls to it should be matched by a call to Shutdown()
681 Initialize();
682 }
f4ada568
GL
683}
684
f187448d
GRG
685wxSocketBase::wxSocketBase()
686{
c2116a35 687 Init();
f187448d 688}
71622a7a
GRG
689
690wxSocketBase::wxSocketBase(wxSocketFlags flags, wxSocketType type)
f4ada568 691{
c2116a35 692 Init();
71622a7a 693
cc0972a2
VZ
694 SetFlags(flags);
695
696 m_type = type;
f4ada568
GL
697}
698
f4ada568
GL
699wxSocketBase::~wxSocketBase()
700{
c2116a35
VZ
701 // Just in case the app called Destroy() *and* then deleted the socket
702 // immediately: don't leave dangling pointers.
703 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
704 if ( traits )
705 traits->RemoveFromPendingDelete(this);
f4ada568 706
c2116a35
VZ
707 // Shutdown and close the socket
708 if (!m_beingDeleted)
709 Close();
9181a383 710
51fe4b60
VZ
711 // Destroy the implementation object
712 delete m_impl;
c2116a35
VZ
713
714 // Free the pushback buffer
715 if (m_unread)
716 free(m_unread);
f4ada568
GL
717}
718
ef57d866
GRG
719bool wxSocketBase::Destroy()
720{
c2116a35
VZ
721 // Delayed destruction: the socket will be deleted during the next idle
722 // loop iteration. This ensures that all pending events have been
723 // processed.
724 m_beingDeleted = true;
725
726 // Shutdown and close the socket
727 Close();
728
22185a1f 729 // Suppress events from now on
c2116a35
VZ
730 Notify(false);
731
732 // schedule this object for deletion
733 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
734 if ( traits )
735 {
736 // let the traits object decide what to do with us
737 traits->ScheduleForDestroy(this);
738 }
739 else // no app or no traits
740 {
741 // in wxBase we might have no app object at all, don't leak memory
742 delete this;
743 }
744
745 return true;
ef57d866 746}
9181a383 747
51fe4b60 748// ----------------------------------------------------------------------------
64b1cea0 749// simple accessors
51fe4b60
VZ
750// ----------------------------------------------------------------------------
751
64b1cea0
VZ
752void wxSocketBase::SetError(wxSocketError error)
753{
754 m_impl->m_error = error;
755}
756
51fe4b60
VZ
757wxSocketError wxSocketBase::LastError() const
758{
759 return m_impl->GetError();
760}
761
ef57d866 762// --------------------------------------------------------------------------
bffc1eaa 763// Basic IO calls
ef57d866
GRG
764// --------------------------------------------------------------------------
765
64b1cea0 766// The following IO operations update m_lcount:
ef57d866 767// {Read, Write, ReadMsg, WriteMsg, Peek, Unread, Discard}
f4ada568
GL
768bool wxSocketBase::Close()
769{
c2116a35
VZ
770 // Interrupt pending waits
771 InterruptWait();
772
b67397a7 773 ShutdownOutput();
c2116a35
VZ
774
775 m_connected = false;
776 m_establishing = false;
777 return true;
f4ada568
GL
778}
779
b67397a7
VZ
780void wxSocketBase::ShutdownOutput()
781{
782 if ( m_impl )
783 m_impl->Shutdown();
784}
785
f187448d 786wxSocketBase& wxSocketBase::Read(void* buffer, wxUint32 nbytes)
f4ada568 787{
c2116a35
VZ
788 // Mask read events
789 m_reading = true;
a324a7bc 790
cc0972a2 791 m_lcount = DoRead(buffer, nbytes);
17aa2bec 792
c2116a35
VZ
793 // Allow read events from now on
794 m_reading = false;
17aa2bec 795
c2116a35 796 return *this;
96db102a
GRG
797}
798
cc0972a2 799wxUint32 wxSocketBase::DoRead(void* buffer_, wxUint32 nbytes)
96db102a 800{
f5395600
VZ
801 wxCHECK_MSG( m_impl, 0, "socket must be valid" );
802
cc0972a2
VZ
803 // We use pointer arithmetic here which doesn't work with void pointers.
804 char *buffer = static_cast<char *>(buffer_);
f5395600 805 wxCHECK_MSG( buffer, 0, "NULL buffer" );
c2116a35 806
cc0972a2
VZ
807 // Try the push back buffer first, even before checking whether the socket
808 // is valid to allow reading previously pushed back data from an already
809 // closed socket.
810 wxUint32 total = GetPushback(buffer, nbytes, false);
c2116a35 811 nbytes -= total;
cc0972a2 812 buffer += total;
c2116a35 813
f5395600 814 while ( nbytes )
cc0972a2 815 {
f5395600
VZ
816 // our socket is non-blocking so Read() will return immediately if
817 // there is nothing to read yet and it's more efficient to try it first
818 // before entering WaitForRead() which is going to start dispatching
819 // GUI events and, even more importantly, we must do this under Windows
820 // where we're not going to get notifications about socket being ready
821 // for reading before we read all the existing data from it
f1763270 822 const int ret = m_connected ? m_impl->Read(buffer, nbytes) : 0;
64b1cea0
VZ
823 if ( ret == -1 )
824 {
f5395600 825 if ( m_impl->GetLastError() == wxSOCKET_WOULDBLOCK )
c2116a35 826 {
f5395600
VZ
827 // if we don't want to wait, just return immediately
828 if ( m_flags & wxSOCKET_NOWAIT )
829 break;
c2116a35 830
f5395600
VZ
831 // otherwise wait until the socket becomes ready for reading
832 if ( !WaitForRead() )
833 {
834 // and exit if the timeout elapsed before it did
835 SetError(wxSOCKET_TIMEDOUT);
836 break;
837 }
c2116a35 838
f5395600
VZ
839 // retry reading
840 continue;
841 }
842 else // "real" error
843 {
844 SetError(wxSOCKET_IOERR);
c2116a35 845 break;
f5395600
VZ
846 }
847 }
848 else if ( ret == 0 )
849 {
850 // for connection-oriented (e.g. TCP) sockets we can only read
851 // 0 bytes if the other end has been closed, and for connectionless
852 // ones (UDP) this flag doesn't make sense anyhow so we can set it
853 // to true too without doing any harm
854 m_closed = true;
855
856 // we're not going to read anything else and so if we haven't read
857 // anything (or not everything in wxSOCKET_WAITALL case) already,
858 // signal an error
859 if ( (m_flags & wxSOCKET_WAITALL) || !total )
860 SetError(wxSOCKET_IOERR);
861 break;
862 }
c2116a35 863
f5395600 864 total += ret;
c2116a35 865
f5395600
VZ
866 // if we are happy to read something and not the entire nbytes bytes,
867 // then we're done
868 if ( !(m_flags & wxSOCKET_WAITALL) )
869 break;
64b1cea0 870
f5395600
VZ
871 nbytes -= ret;
872 buffer += ret;
c2116a35 873 }
96db102a 874
96db102a 875 return total;
c2116a35 876}
f4ada568 877
c2116a35
VZ
878wxSocketBase& wxSocketBase::ReadMsg(void* buffer, wxUint32 nbytes)
879{
c2116a35
VZ
880 struct
881 {
882 unsigned char sig[4];
883 unsigned char len[4];
884 } msg;
885
886 // Mask read events
887 m_reading = true;
888
64b1cea0 889 int old_flags = m_flags;
c2116a35 890 SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL);
c9157492 891
64b1cea0
VZ
892 bool ok = false;
893 if ( DoRead(&msg, sizeof(msg)) == sizeof(msg) )
56d8adc0 894 {
64b1cea0
VZ
895 wxUint32 sig = (wxUint32)msg.sig[0];
896 sig |= (wxUint32)(msg.sig[1] << 8);
897 sig |= (wxUint32)(msg.sig[2] << 16);
898 sig |= (wxUint32)(msg.sig[3] << 24);
f4ada568 899
64b1cea0
VZ
900 if ( sig == 0xfeeddead )
901 {
902 wxUint32 len = (wxUint32)msg.len[0];
903 len |= (wxUint32)(msg.len[1] << 8);
904 len |= (wxUint32)(msg.len[2] << 16);
905 len |= (wxUint32)(msg.len[3] << 24);
f4ada568 906
64b1cea0
VZ
907 wxUint32 len2;
908 if (len > nbytes)
909 {
910 len2 = len - nbytes;
911 len = nbytes;
912 }
913 else
914 len2 = 0;
c2116a35 915
64b1cea0
VZ
916 // Don't attempt to read if the msg was zero bytes long.
917 m_lcount = len ? DoRead(buffer, len) : 0;
c2116a35 918
64b1cea0
VZ
919 if ( len2 )
920 {
921 char discard_buffer[MAX_DISCARD_SIZE];
922 long discard_len;
923
924 // NOTE: discarded bytes don't add to m_lcount.
925 do
926 {
927 discard_len = len2 > MAX_DISCARD_SIZE
928 ? MAX_DISCARD_SIZE
929 : len2;
930 discard_len = DoRead(discard_buffer, (wxUint32)discard_len);
931 len2 -= (wxUint32)discard_len;
932 }
933 while ((discard_len > 0) && len2);
934 }
17aa2bec 935
64b1cea0
VZ
936 if ( !len2 && DoRead(&msg, sizeof(msg)) == sizeof(msg) )
937 {
938 sig = (wxUint32)msg.sig[0];
939 sig |= (wxUint32)(msg.sig[1] << 8);
940 sig |= (wxUint32)(msg.sig[2] << 16);
941 sig |= (wxUint32)(msg.sig[3] << 24);
c2116a35 942
64b1cea0
VZ
943 if ( sig == 0xdeadfeed )
944 ok = true;
945 }
c2116a35 946 }
c2116a35 947 }
062c4861 948
64b1cea0
VZ
949 if ( !ok )
950 SetError(wxSOCKET_IOERR);
96db102a 951
c2116a35
VZ
952 m_reading = false;
953 SetFlags(old_flags);
96db102a 954
c2116a35 955 return *this;
062c4861
GL
956}
957
f187448d 958wxSocketBase& wxSocketBase::Peek(void* buffer, wxUint32 nbytes)
f4ada568 959{
c2116a35
VZ
960 // Mask read events
961 m_reading = true;
96db102a 962
cc0972a2 963 m_lcount = DoRead(buffer, nbytes);
c2116a35 964 Pushback(buffer, m_lcount);
96db102a 965
c2116a35
VZ
966 // Allow read events again
967 m_reading = false;
f4ada568 968
c2116a35 969 return *this;
f4ada568
GL
970}
971
f187448d 972wxSocketBase& wxSocketBase::Write(const void *buffer, wxUint32 nbytes)
f4ada568 973{
c2116a35
VZ
974 // Mask write events
975 m_writing = true;
56d8adc0 976
cc0972a2 977 m_lcount = DoWrite(buffer, nbytes);
96db102a 978
c2116a35
VZ
979 // Allow write events again
980 m_writing = false;
96db102a 981
c2116a35 982 return *this;
96db102a
GRG
983}
984
cc0972a2 985// This function is a mirror image of DoRead() except that it doesn't use the
f5395600
VZ
986// push back buffer and doesn't treat 0 return value specially (normally this
987// shouldn't happen at all here), so please see comments there for explanations
cc0972a2 988wxUint32 wxSocketBase::DoWrite(const void *buffer_, wxUint32 nbytes)
96db102a 989{
f5395600
VZ
990 wxCHECK_MSG( m_impl, 0, "socket must be valid" );
991
cc0972a2 992 const char *buffer = static_cast<const char *>(buffer_);
f5395600 993 wxCHECK_MSG( buffer, 0, "NULL buffer" );
c2116a35 994
cc0972a2 995 wxUint32 total = 0;
f5395600 996 while ( nbytes )
cc0972a2 997 {
f1763270
VZ
998 if ( !m_connected )
999 {
1000 if ( (m_flags & wxSOCKET_WAITALL) || !total )
1001 SetError(wxSOCKET_IOERR);
1002 break;
1003 }
1004
51fe4b60 1005 const int ret = m_impl->Write(buffer, nbytes);
64b1cea0
VZ
1006 if ( ret == -1 )
1007 {
f5395600 1008 if ( m_impl->GetLastError() == wxSOCKET_WOULDBLOCK )
c2116a35 1009 {
f5395600
VZ
1010 if ( m_flags & wxSOCKET_NOWAIT )
1011 break;
5c9eff30 1012
f5395600
VZ
1013 if ( !WaitForWrite() )
1014 {
1015 SetError(wxSOCKET_TIMEDOUT);
1016 break;
1017 }
a324a7bc 1018
f5395600
VZ
1019 continue;
1020 }
1021 else // "real" error
1022 {
1023 SetError(wxSOCKET_IOERR);
c2116a35 1024 break;
f5395600
VZ
1025 }
1026 }
c9157492 1027
f5395600 1028 total += ret;
c9157492 1029
f5395600
VZ
1030 if ( !(m_flags & wxSOCKET_WAITALL) )
1031 break;
64b1cea0 1032
f5395600
VZ
1033 nbytes -= ret;
1034 buffer += ret;
81b92e17 1035 }
a324a7bc 1036
c2116a35 1037 return total;
f4ada568
GL
1038}
1039
f187448d 1040wxSocketBase& wxSocketBase::WriteMsg(const void *buffer, wxUint32 nbytes)
062c4861 1041{
c2116a35
VZ
1042 struct
1043 {
1044 unsigned char sig[4];
1045 unsigned char len[4];
1046 } msg;
062c4861 1047
c2116a35
VZ
1048 // Mask write events
1049 m_writing = true;
96db102a 1050
64b1cea0 1051 const int old_flags = m_flags;
c2116a35 1052 SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL);
96db102a 1053
c2116a35
VZ
1054 msg.sig[0] = (unsigned char) 0xad;
1055 msg.sig[1] = (unsigned char) 0xde;
1056 msg.sig[2] = (unsigned char) 0xed;
1057 msg.sig[3] = (unsigned char) 0xfe;
062c4861 1058
c2116a35
VZ
1059 msg.len[0] = (unsigned char) (nbytes & 0xff);
1060 msg.len[1] = (unsigned char) ((nbytes >> 8) & 0xff);
1061 msg.len[2] = (unsigned char) ((nbytes >> 16) & 0xff);
1062 msg.len[3] = (unsigned char) ((nbytes >> 24) & 0xff);
17aa2bec 1063
64b1cea0
VZ
1064 bool ok = false;
1065 if ( DoWrite(&msg, sizeof(msg)) == sizeof(msg) )
1066 {
1067 m_lcount = DoWrite(buffer, nbytes);
1068 if ( m_lcount == nbytes )
1069 {
1070 msg.sig[0] = (unsigned char) 0xed;
1071 msg.sig[1] = (unsigned char) 0xfe;
1072 msg.sig[2] = (unsigned char) 0xad;
1073 msg.sig[3] = (unsigned char) 0xde;
1074 msg.len[0] =
1075 msg.len[1] =
1076 msg.len[2] =
1077 msg.len[3] = (char) 0;
1078
1079 if ( DoWrite(&msg, sizeof(msg)) == sizeof(msg))
1080 ok = true;
1081 }
1082 }
17aa2bec 1083
64b1cea0
VZ
1084 if ( !ok )
1085 SetError(wxSOCKET_IOERR);
96db102a 1086
c2116a35 1087 m_writing = false;
64b1cea0 1088 SetFlags(old_flags);
96db102a 1089
c2116a35 1090 return *this;
062c4861
GL
1091}
1092
f187448d 1093wxSocketBase& wxSocketBase::Unread(const void *buffer, wxUint32 nbytes)
f4ada568 1094{
c2116a35
VZ
1095 if (nbytes != 0)
1096 Pushback(buffer, nbytes);
f4ada568 1097
64b1cea0 1098 SetError(wxSOCKET_NOERROR);
c2116a35 1099 m_lcount = nbytes;
f4ada568 1100
c2116a35 1101 return *this;
a324a7bc
GL
1102}
1103
96db102a 1104wxSocketBase& wxSocketBase::Discard()
f4ada568 1105{
c2116a35
VZ
1106 char *buffer = new char[MAX_DISCARD_SIZE];
1107 wxUint32 ret;
1108 wxUint32 total = 0;
f4ada568 1109
c2116a35
VZ
1110 // Mask read events
1111 m_reading = true;
96db102a 1112
64b1cea0 1113 const int old_flags = m_flags;
c2116a35 1114 SetFlags(wxSOCKET_NOWAIT);
384b4373 1115
c2116a35
VZ
1116 do
1117 {
cc0972a2 1118 ret = DoRead(buffer, MAX_DISCARD_SIZE);
c2116a35
VZ
1119 total += ret;
1120 }
1121 while (ret == MAX_DISCARD_SIZE);
f4ada568 1122
c2116a35
VZ
1123 delete[] buffer;
1124 m_lcount = total;
64b1cea0 1125 SetError(wxSOCKET_NOERROR);
17aa2bec 1126
c2116a35
VZ
1127 // Allow read events again
1128 m_reading = false;
96db102a 1129
64b1cea0
VZ
1130 SetFlags(old_flags);
1131
c2116a35 1132 return *this;
f4ada568
GL
1133}
1134
ef57d866
GRG
1135// --------------------------------------------------------------------------
1136// Wait functions
1137// --------------------------------------------------------------------------
f4ada568 1138
51fe4b60 1139/*
00414faf
VZ
1140 This function will check for the events specified in the flags parameter,
1141 and it will return a mask indicating which operations can be performed.
f0db5d75 1142 */
00414faf 1143wxSocketEventFlags wxSocketImpl::Select(wxSocketEventFlags flags,
2b036c4b 1144 const timeval *timeout)
f0db5d75 1145{
5e9238f9
VZ
1146 if ( m_fd == INVALID_SOCKET )
1147 return (wxSOCKET_LOST_FLAG & flags);
f0db5d75 1148
5e9238f9
VZ
1149 struct timeval tv;
1150 if ( timeout )
1151 tv = *timeout;
1152 else
1153 tv.tv_sec = tv.tv_usec = 0;
f0db5d75 1154
5e9238f9
VZ
1155 // prepare the FD sets, passing NULL for the one(s) we don't use
1156 fd_set
1157 readfds, *preadfds = NULL,
1158 writefds, *pwritefds = NULL,
1159 exceptfds; // always want to know about errors
f0db5d75 1160
5e9238f9
VZ
1161 if ( flags & wxSOCKET_INPUT_FLAG )
1162 {
1163 preadfds = &readfds;
1164 wxFD_ZERO(preadfds);
1165 wxFD_SET(m_fd, preadfds);
1166 }
f0db5d75 1167
5e9238f9
VZ
1168 // when using non-blocking connect() the socket becomes connected
1169 // (successfully or not) when it becomes writable
1170 if ( flags & (wxSOCKET_OUTPUT_FLAG | wxSOCKET_CONNECTION_FLAG) )
1171 {
1172 pwritefds = &writefds;
1173 wxFD_ZERO(pwritefds);
1174 wxFD_SET(m_fd, pwritefds);
1175 }
f0db5d75 1176
5e9238f9
VZ
1177 wxFD_ZERO(&exceptfds);
1178 wxFD_SET(m_fd, &exceptfds);
f0db5d75 1179
5e9238f9
VZ
1180 const int rc = select(m_fd + 1, preadfds, pwritefds, &exceptfds, &tv);
1181
1182 // check for errors first
1183 if ( rc == -1 || wxFD_ISSET(m_fd, &exceptfds) )
f0db5d75 1184 {
5e9238f9
VZ
1185 m_establishing = false;
1186
1187 return wxSOCKET_LOST_FLAG & flags;
f0db5d75 1188 }
f0db5d75 1189
5e9238f9
VZ
1190 if ( rc == 0 )
1191 return 0;
f0db5d75 1192
5e9238f9 1193 wxASSERT_MSG( rc == 1, "unexpected select() return value" );
f0db5d75 1194
5e9238f9
VZ
1195 wxSocketEventFlags detected = 0;
1196 if ( preadfds && wxFD_ISSET(m_fd, preadfds) )
1197 detected |= wxSOCKET_INPUT_FLAG;
1198
1199 if ( pwritefds && wxFD_ISSET(m_fd, pwritefds) )
f0db5d75 1200 {
5e9238f9
VZ
1201 // check for the case of non-blocking connect()
1202 if ( m_establishing && !m_server )
1203 {
1204 int error;
1205 SOCKOPTLEN_T len = sizeof(error);
1206 m_establishing = false;
1207 getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
1208
1209 if ( error )
1210 detected = wxSOCKET_LOST_FLAG;
1211 else
1212 detected |= wxSOCKET_CONNECTION_FLAG;
1213 }
1214 else // not called to get non-blocking connect() status
1215 {
1216 detected |= wxSOCKET_OUTPUT_FLAG;
1217 }
f0db5d75 1218 }
f0db5d75 1219
5e9238f9 1220 return detected & flags;
f0db5d75
VZ
1221}
1222
60ee0172
VZ
1223bool
1224wxSocketBase::DoWait(long seconds, long milliseconds, wxSocketEventFlags flags)
375abe3d 1225{
51fe4b60 1226 wxCHECK_MSG( m_impl, false, "can't wait on invalid socket" );
375abe3d 1227
9588640d
VZ
1228 // we're never going to become ready if we're not connected (any more)
1229 if ( !m_connected && !m_establishing )
1230 return (flags & wxSOCKET_LOST_FLAG) != 0;
1231
60ee0172 1232 // This can be set to true from Interrupt() to exit this function a.s.a.p.
c2116a35 1233 m_interrupt = false;
81b92e17 1234
af2fd961 1235
60ee0172
VZ
1236 // Use either the provided timeout or the default timeout value associated
1237 // with this socket.
1238 //
1239 // TODO: allow waiting forever, see #9443
1240 const long timeout = seconds == -1 ? m_timeout * 1000
1241 : seconds * 1000 + milliseconds;
1242 const wxMilliClock_t timeEnd = wxGetLocalTimeMillis() + timeout;
1243
1244 // Get the active event loop which we'll use for the message dispatching
2b036c4b
VZ
1245 // when running in the main thread unless this was explicitly disabled by
1246 // setting wxSOCKET_BLOCK flag
60ee0172 1247 wxEventLoopBase *eventLoop;
2b036c4b 1248 if ( !(m_flags & wxSOCKET_BLOCK) && wxIsMainThread() )
60ee0172
VZ
1249 {
1250 eventLoop = wxEventLoop::GetActive();
60ee0172
VZ
1251 }
1252 else // in worker thread
af2fd961 1253 {
60ee0172
VZ
1254 // We never dispatch messages from threads other than the main one.
1255 eventLoop = NULL;
af2fd961
GRG
1256 }
1257
00414faf
VZ
1258 // Wait until we receive the event we're waiting for or the timeout expires
1259 // (but note that we always execute the loop at least once, even if timeout
1260 // is 0 as this is used for polling)
60ee0172 1261 bool gotEvent = false;
00414faf 1262 for ( bool firstTime = true; !m_interrupt ; firstTime = false )
af2fd961 1263 {
00414faf
VZ
1264 long timeLeft = wxMilliClockToLong(timeEnd - wxGetLocalTimeMillis());
1265 if ( timeLeft < 0 )
1266 {
1267 if ( !firstTime )
1268 break; // timed out
1269
1270 timeLeft = 0;
1271 }
1272
2f1c8faf
VZ
1273 wxSocketEventFlags events;
1274 if ( eventLoop )
1275 {
00414faf
VZ
1276 // reset them before starting to wait
1277 m_eventsgot = 0;
1278
1279 eventLoop->DispatchTimeout(timeLeft);
2f1c8faf
VZ
1280
1281 events = m_eventsgot;
1282 }
00414faf
VZ
1283 else // no event loop or waiting in another thread
1284 {
1285 // as explained below, we should always check for wxSOCKET_LOST_FLAG
2b036c4b
VZ
1286 timeval tv;
1287 SetTimeValFromMS(tv, timeLeft);
1288 events = m_impl->Select(flags | wxSOCKET_LOST_FLAG, &tv);
00414faf
VZ
1289 }
1290
1291 // always check for wxSOCKET_LOST_FLAG, even if flags doesn't include
1292 // it, as continuing to wait for anything else after getting it is
1293 // pointless
1294 if ( events & wxSOCKET_LOST_FLAG )
2f1c8faf 1295 {
00414faf
VZ
1296 m_connected = false;
1297 m_establishing = false;
1298 if ( flags & wxSOCKET_LOST_FLAG )
1299 gotEvent = true;
1300 break;
2f1c8faf 1301 }
60ee0172 1302
00414faf
VZ
1303 // otherwise mask out the bits we're not interested in
1304 events &= flags;
1305
60ee0172 1306 // Incoming connection (server) or connection established (client)?
2f1c8faf 1307 if ( events & wxSOCKET_CONNECTION_FLAG )
c2116a35
VZ
1308 {
1309 m_connected = true;
1310 m_establishing = false;
60ee0172 1311 gotEvent = true;
c2116a35
VZ
1312 break;
1313 }
c0043a50 1314
60ee0172 1315 // Data available or output buffer ready?
2f1c8faf 1316 if ( (events & wxSOCKET_INPUT_FLAG) || (events & wxSOCKET_OUTPUT_FLAG) )
b8d1915d 1317 {
60ee0172 1318 gotEvent = true;
c2116a35 1319 break;
b8d1915d 1320 }
f01bca89 1321 }
f4ada568 1322
60ee0172 1323 return gotEvent;
f4ada568 1324}
f4ada568 1325
a737331d 1326bool wxSocketBase::Wait(long seconds, long milliseconds)
f4ada568 1327{
60ee0172 1328 return DoWait(seconds, milliseconds,
51fe4b60
VZ
1329 wxSOCKET_INPUT_FLAG |
1330 wxSOCKET_OUTPUT_FLAG |
1331 wxSOCKET_CONNECTION_FLAG |
1332 wxSOCKET_LOST_FLAG
60ee0172 1333 );
f4ada568 1334}
f4ada568 1335
a737331d 1336bool wxSocketBase::WaitForRead(long seconds, long milliseconds)
f4ada568 1337{
60ee0172
VZ
1338 // Check pushback buffer before entering DoWait
1339 if ( m_unread )
c2116a35 1340 return true;
96db102a 1341
51fe4b60 1342 // Note that wxSOCKET_INPUT_LOST has to be explicitly passed to DoWait
60ee0172 1343 // because of the semantics of WaitForRead: a return value of true means
51fe4b60 1344 // that a Read call will return immediately, not that there is
60ee0172 1345 // actually data to read.
51fe4b60 1346 return DoWait(seconds, milliseconds, wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
f4ada568
GL
1347}
1348
bfa7bf7d 1349
a737331d 1350bool wxSocketBase::WaitForWrite(long seconds, long milliseconds)
f4ada568 1351{
51fe4b60 1352 return DoWait(seconds, milliseconds, wxSOCKET_OUTPUT_FLAG | wxSOCKET_LOST_FLAG);
a737331d 1353}
f4ada568 1354
a737331d
GL
1355bool wxSocketBase::WaitForLost(long seconds, long milliseconds)
1356{
51fe4b60 1357 return DoWait(seconds, milliseconds, wxSOCKET_LOST_FLAG);
f4ada568 1358}
a737331d 1359
ef57d866
GRG
1360// --------------------------------------------------------------------------
1361// Miscellaneous
1362// --------------------------------------------------------------------------
1363
1364//
1365// Get local or peer address
1366//
1367
c9bccf23 1368bool wxSocketBase::GetPeer(wxSockAddress& addr) const
ef57d866 1369{
c9bccf23 1370 wxCHECK_MSG( m_impl, false, "invalid socket" );
ef57d866 1371
c9bccf23
VZ
1372 const wxSockAddressImpl& peer = m_impl->GetPeer();
1373 if ( !peer.IsOk() )
c2116a35 1374 return false;
007c77ab 1375
c9bccf23 1376 addr.SetAddress(peer);
ef57d866 1377
c2116a35 1378 return true;
ef57d866
GRG
1379}
1380
c9bccf23 1381bool wxSocketBase::GetLocal(wxSockAddress& addr) const
ef57d866 1382{
c9bccf23 1383 wxCHECK_MSG( m_impl, false, "invalid socket" );
ef57d866 1384
c9bccf23
VZ
1385 const wxSockAddressImpl& local = m_impl->GetLocal();
1386 if ( !local.IsOk() )
7fb0a11d 1387 return false;
ef57d866 1388
c9bccf23 1389 addr.SetAddress(local);
ef57d866 1390
7fb0a11d 1391 return true;
ef57d866
GRG
1392}
1393
1394//
1395// Save and restore socket state
1396//
1397
1398void wxSocketBase::SaveState()
1399{
7fb0a11d 1400 wxSocketState *state;
ef57d866 1401
7fb0a11d 1402 state = new wxSocketState();
ef57d866 1403
7fb0a11d
WS
1404 state->m_flags = m_flags;
1405 state->m_notify = m_notify;
1406 state->m_eventmask = m_eventmask;
1407 state->m_clientData = m_clientData;
ef57d866 1408
7fb0a11d 1409 m_states.Append(state);
ef57d866
GRG
1410}
1411
1412void wxSocketBase::RestoreState()
1413{
7fb0a11d
WS
1414 wxList::compatibility_iterator node;
1415 wxSocketState *state;
ef57d866 1416
7fb0a11d
WS
1417 node = m_states.GetLast();
1418 if (!node)
1419 return;
ef57d866 1420
7fb0a11d 1421 state = (wxSocketState *)node->GetData();
ef57d866 1422
7fb0a11d
WS
1423 m_flags = state->m_flags;
1424 m_notify = state->m_notify;
1425 m_eventmask = state->m_eventmask;
1426 m_clientData = state->m_clientData;
37340c48 1427
7fb0a11d
WS
1428 m_states.Erase(node);
1429 delete state;
ef57d866
GRG
1430}
1431
1432//
1433// Timeout and flags
1434//
1435
17aa2bec
GRG
1436void wxSocketBase::SetTimeout(long seconds)
1437{
7fb0a11d 1438 m_timeout = seconds;
17aa2bec 1439
51fe4b60
VZ
1440 if (m_impl)
1441 m_impl->SetTimeout(m_timeout * 1000);
17aa2bec
GRG
1442}
1443
71622a7a 1444void wxSocketBase::SetFlags(wxSocketFlags flags)
f4ada568 1445{
cc0972a2
VZ
1446 // Do some sanity checking on the flags used: not all values can be used
1447 // together.
1448 wxASSERT_MSG( !(flags & wxSOCKET_NOWAIT) ||
1449 !(flags & (wxSOCKET_WAITALL | wxSOCKET_BLOCK)),
1450 "Using wxSOCKET_WAITALL or wxSOCKET_BLOCK with "
1451 "wxSOCKET_NOWAIT doesn't make sense" );
1452
7fb0a11d 1453 m_flags = flags;
f4ada568 1454}
f0a56ab0 1455
f187448d 1456
ef57d866 1457// --------------------------------------------------------------------------
f187448d 1458// Event handling
ef57d866 1459// --------------------------------------------------------------------------
a324a7bc 1460
bffc1eaa 1461void wxSocketBase::OnRequest(wxSocketNotify notification)
f4ada568 1462{
c2116a35 1463 wxSocketEventFlags flag = 0;
5c1193e0 1464 switch ( notification )
c2116a35 1465 {
5c1193e0
VZ
1466 case wxSOCKET_INPUT:
1467 flag = wxSOCKET_INPUT_FLAG;
1468 break;
1469
1470 case wxSOCKET_OUTPUT:
1471 flag = wxSOCKET_OUTPUT_FLAG;
1472 break;
1473
1474 case wxSOCKET_CONNECTION:
1475 flag = wxSOCKET_CONNECTION_FLAG;
1476 break;
1477
1478 case wxSOCKET_LOST:
1479 flag = wxSOCKET_LOST_FLAG;
1480 break;
1481
c2116a35 1482 default:
5c1193e0 1483 wxFAIL_MSG( "unknown wxSocket notification" );
c2116a35
VZ
1484 }
1485
437a8892
VZ
1486 // if we lost the connection the socket is now closed
1487 if ( notification == wxSOCKET_LOST )
1488 m_closed = true;
1489
5c1193e0
VZ
1490 // remember the events which were generated for this socket, we're going to
1491 // use this in DoWait()
1492 m_eventsgot |= flag;
1493
1494 // send the wx event if enabled and we're interested in it
1495 if ( m_notify && (m_eventmask & flag) && m_handler )
c2116a35 1496 {
00414faf
VZ
1497 // If we are in the middle of a R/W operation, do not propagate events
1498 // to users. Also, filter 'late' events which are no longer valid.
1499 if ( notification == wxSOCKET_INPUT )
1500 {
1501 if ( m_reading || !m_impl->Select(wxSOCKET_INPUT_FLAG) )
1502 return;
1503 }
1504 else if ( notification == wxSOCKET_OUTPUT )
1505 {
1506 if ( m_writing || !m_impl->Select(wxSOCKET_OUTPUT_FLAG) )
1507 return;
1508 }
1509
5c1193e0
VZ
1510 wxSocketEvent event(m_id);
1511 event.m_event = notification;
1512 event.m_clientData = m_clientData;
1513 event.SetEventObject(this);
c2116a35 1514
5c1193e0 1515 m_handler->AddPendingEvent(event);
bffc1eaa 1516 }
f4ada568
GL
1517}
1518
f187448d
GRG
1519void wxSocketBase::Notify(bool notify)
1520{
7fb0a11d 1521 m_notify = notify;
f187448d
GRG
1522}
1523
1524void wxSocketBase::SetNotify(wxSocketEventFlags flags)
1525{
7fb0a11d 1526 m_eventmask = flags;
f187448d
GRG
1527}
1528
71622a7a 1529void wxSocketBase::SetEventHandler(wxEvtHandler& handler, int id)
f4ada568 1530{
7fb0a11d
WS
1531 m_handler = &handler;
1532 m_id = id;
f4ada568
GL
1533}
1534
ef57d866
GRG
1535// --------------------------------------------------------------------------
1536// Pushback buffer
1537// --------------------------------------------------------------------------
db131261 1538
f187448d 1539void wxSocketBase::Pushback(const void *buffer, wxUint32 size)
f4ada568 1540{
c2116a35 1541 if (!size) return;
dc5c1114 1542
c2116a35
VZ
1543 if (m_unread == NULL)
1544 m_unread = malloc(size);
1545 else
1546 {
1547 void *tmp;
f4ada568 1548
c2116a35
VZ
1549 tmp = malloc(m_unrd_size + size);
1550 memcpy((char *)tmp + size, m_unread, m_unrd_size);
1551 free(m_unread);
a324a7bc 1552
c2116a35
VZ
1553 m_unread = tmp;
1554 }
31528cd3 1555
c2116a35 1556 m_unrd_size += size;
a324a7bc 1557
c2116a35 1558 memcpy(m_unread, buffer, size);
f4ada568
GL
1559}
1560
f187448d 1561wxUint32 wxSocketBase::GetPushback(void *buffer, wxUint32 size, bool peek)
f4ada568 1562{
cc0972a2
VZ
1563 wxCHECK_MSG( buffer, 0, "NULL buffer" );
1564
c2116a35
VZ
1565 if (!m_unrd_size)
1566 return 0;
f4ada568 1567
c2116a35
VZ
1568 if (size > (m_unrd_size-m_unrd_cur))
1569 size = m_unrd_size-m_unrd_cur;
96db102a 1570
c2116a35 1571 memcpy(buffer, (char *)m_unread + m_unrd_cur, size);
f4ada568 1572
c2116a35 1573 if (!peek)
dc5c1114 1574 {
c2116a35
VZ
1575 m_unrd_cur += size;
1576 if (m_unrd_size == m_unrd_cur)
1577 {
1578 free(m_unread);
1579 m_unread = NULL;
1580 m_unrd_size = 0;
1581 m_unrd_cur = 0;
1582 }
f4ada568 1583 }
f4ada568 1584
c2116a35 1585 return size;
f4ada568
GL
1586}
1587
f187448d 1588
ef57d866 1589// ==========================================================================
c3e646b4 1590// wxSocketServer
ef57d866 1591// ==========================================================================
f4ada568 1592
ef57d866
GRG
1593// --------------------------------------------------------------------------
1594// Ctor
1595// --------------------------------------------------------------------------
56d8adc0 1596
c9bccf23 1597wxSocketServer::wxSocketServer(const wxSockAddress& addr,
71622a7a
GRG
1598 wxSocketFlags flags)
1599 : wxSocketBase(flags, wxSOCKET_SERVER)
f4ada568 1600{
007c77ab 1601 wxLogTrace( wxTRACE_Socket, _T("Opening wxSocketServer") );
f4ada568 1602
51fe4b60 1603 m_impl = wxSocketImpl::Create(*this);
384b4373 1604
51fe4b60 1605 if (!m_impl)
007c77ab 1606 {
51fe4b60 1607 wxLogTrace( wxTRACE_Socket, _T("*** Failed to create m_impl") );
007c77ab
RL
1608 return;
1609 }
a737331d 1610
2804f77d 1611 // Setup the socket as server
c9bccf23 1612 m_impl->SetLocal(addr.GetAddress());
d775fa82 1613
74c481d1 1614 if (GetFlags() & wxSOCKET_REUSEADDR) {
51fe4b60 1615 m_impl->SetReusable();
74c481d1 1616 }
60edcf45 1617 if (GetFlags() & wxSOCKET_BROADCAST) {
51fe4b60 1618 m_impl->SetBroadcast();
60edcf45
VZ
1619 }
1620 if (GetFlags() & wxSOCKET_NOBIND) {
51fe4b60 1621 m_impl->DontDoBind();
60edcf45 1622 }
74c481d1 1623
51fe4b60 1624 if (m_impl->CreateServer() != wxSOCKET_NOERROR)
007c77ab 1625 {
51fe4b60
VZ
1626 delete m_impl;
1627 m_impl = NULL;
007c77ab 1628
51fe4b60 1629 wxLogTrace( wxTRACE_Socket, _T("*** CreateServer() failed") );
007c77ab
RL
1630 return;
1631 }
1632
51fe4b60 1633 wxLogTrace( wxTRACE_Socket, _T("wxSocketServer on fd %d"), m_impl->m_fd );
f4ada568
GL
1634}
1635
ef57d866
GRG
1636// --------------------------------------------------------------------------
1637// Accept
1638// --------------------------------------------------------------------------
8c14576d 1639
d80d1aba 1640bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait)
f4ada568 1641{
2b036c4b
VZ
1642 if ( !m_impl || (m_impl->m_fd == INVALID_SOCKET) || !m_impl->IsServer() )
1643 {
1644 wxFAIL_MSG( "can only be called for a valid server socket" );
1645
64b1cea0 1646 SetError(wxSOCKET_INVSOCK);
2b036c4b 1647
c2116a35 1648 return false;
2b036c4b
VZ
1649 }
1650
1651 if ( wait )
1652 {
1653 // wait until we get a connection
1654 if ( !m_impl->SelectWithTimeout(wxSOCKET_INPUT_FLAG) )
1655 {
64b1cea0 1656 SetError(wxSOCKET_TIMEDOUT);
2b036c4b
VZ
1657
1658 return false;
1659 }
1660 }
17aa2bec 1661
2b036c4b 1662 sock.m_impl = m_impl->Accept(sock);
d80d1aba 1663
51fe4b60 1664 if ( !sock.m_impl )
2b036c4b 1665 {
64b1cea0 1666 SetError(m_impl->GetLastError());
2b036c4b 1667
c2116a35 1668 return false;
2b036c4b 1669 }
d80d1aba 1670
c2116a35 1671 sock.m_type = wxSOCKET_BASE;
c2116a35 1672 sock.m_connected = true;
f4ada568 1673
c2116a35 1674 return true;
f4ada568
GL
1675}
1676
d80d1aba 1677wxSocketBase *wxSocketServer::Accept(bool wait)
f4ada568 1678{
c2116a35 1679 wxSocketBase* sock = new wxSocketBase();
f4ada568 1680
c2116a35 1681 sock->SetFlags(m_flags);
f4ada568 1682
c2116a35
VZ
1683 if (!AcceptWith(*sock, wait))
1684 {
1685 sock->Destroy();
1686 sock = NULL;
1687 }
f4ada568 1688
c2116a35 1689 return sock;
f4ada568
GL
1690}
1691
17aa2bec 1692bool wxSocketServer::WaitForAccept(long seconds, long milliseconds)
d80d1aba 1693{
51fe4b60 1694 return DoWait(seconds, milliseconds, wxSOCKET_CONNECTION_FLAG);
d80d1aba
GRG
1695}
1696
bfa7bf7d
VZ
1697bool wxSocketBase::GetOption(int level, int optname, void *optval, int *optlen)
1698{
51fe4b60 1699 wxASSERT_MSG( m_impl, _T("Socket not initialised") );
11734f8a 1700
735ac2bc 1701 SOCKOPTLEN_T lenreal = *optlen;
51fe4b60
VZ
1702 if ( getsockopt(m_impl->m_fd, level, optname,
1703 static_cast<char *>(optval), &lenreal) != 0 )
d775fa82 1704 return false;
51fe4b60
VZ
1705
1706 *optlen = lenreal;
1707
d775fa82 1708 return true;
bfa7bf7d
VZ
1709}
1710
51fe4b60
VZ
1711bool
1712wxSocketBase::SetOption(int level, int optname, const void *optval, int optlen)
bfa7bf7d 1713{
51fe4b60 1714 wxASSERT_MSG( m_impl, _T("Socket not initialised") );
8e3f3880 1715
51fe4b60
VZ
1716 return setsockopt(m_impl->m_fd, level, optname,
1717 static_cast<const char *>(optval), optlen) == 0;
bfa7bf7d
VZ
1718}
1719
72ac4e88 1720bool wxSocketBase::SetLocal(const wxIPV4address& local)
33d925b0 1721{
c9bccf23 1722 m_localAddress = local;
33d925b0 1723
c9bccf23 1724 return true;
33d925b0
KH
1725}
1726
ef57d866 1727// ==========================================================================
8c14576d 1728// wxSocketClient
ef57d866 1729// ==========================================================================
f4ada568 1730
ef57d866
GRG
1731// --------------------------------------------------------------------------
1732// Ctor and dtor
1733// --------------------------------------------------------------------------
56d8adc0 1734
71622a7a
GRG
1735wxSocketClient::wxSocketClient(wxSocketFlags flags)
1736 : wxSocketBase(flags, wxSOCKET_CLIENT)
f4ada568 1737{
089b23d0
VZ
1738 m_initialRecvBufferSize =
1739 m_initialSendBufferSize = -1;
f4ada568
GL
1740}
1741
f4ada568
GL
1742wxSocketClient::~wxSocketClient()
1743{
1744}
1745
ef57d866
GRG
1746// --------------------------------------------------------------------------
1747// Connect
1748// --------------------------------------------------------------------------
dc5c1114 1749
2b036c4b 1750bool wxSocketClient::DoConnect(const wxSockAddress& remote,
72ac4e88
VZ
1751 const wxSockAddress* local,
1752 bool wait)
f4ada568 1753{
2b036c4b 1754 if ( m_impl )
c2116a35 1755 {
2b036c4b 1756 // Shutdown and destroy the old socket
c2116a35 1757 Close();
51fe4b60 1758 delete m_impl;
c2116a35 1759 }
a324a7bc 1760
c2116a35
VZ
1761 m_connected = false;
1762 m_establishing = false;
384b4373 1763
2b036c4b
VZ
1764 // Create and set up the new one
1765 m_impl = wxSocketImpl::Create(*this);
1766 if ( !m_impl )
c2116a35 1767 return false;
384b4373 1768
c2116a35
VZ
1769 // Reuse makes sense for clients too, if we are trying to rebind to the same port
1770 if (GetFlags() & wxSOCKET_REUSEADDR)
51fe4b60 1771 m_impl->SetReusable();
c2116a35 1772 if (GetFlags() & wxSOCKET_BROADCAST)
51fe4b60 1773 m_impl->SetBroadcast();
c2116a35 1774 if (GetFlags() & wxSOCKET_NOBIND)
51fe4b60 1775 m_impl->DontDoBind();
33d925b0 1776
2b036c4b
VZ
1777 // Bind to the local IP address and port, when provided or if one had been
1778 // set before
c9bccf23 1779 if ( !local && m_localAddress.GetAddress().IsOk() )
c2116a35 1780 local = &m_localAddress;
c2116a35 1781
2b036c4b
VZ
1782 if ( local )
1783 m_impl->SetLocal(local->GetAddress());
33d925b0 1784
51fe4b60 1785 m_impl->SetInitialSocketBuffers(m_initialRecvBufferSize, m_initialSendBufferSize);
8c029a5b 1786
2b036c4b
VZ
1787 m_impl->SetPeer(remote.GetAddress());
1788
1789 // Finally do create the socket and connect to the peer
1790 const wxSocketError err = m_impl->CreateClient(wait);
791b24c4 1791
2b036c4b 1792 if ( err != wxSOCKET_NOERROR )
c2116a35 1793 {
2b036c4b
VZ
1794 if ( err == wxSOCKET_WOULDBLOCK )
1795 {
1796 wxASSERT_MSG( !wait, "shouldn't get this for blocking connect" );
1797
c2116a35 1798 m_establishing = true;
2b036c4b 1799 }
56d8adc0 1800
c2116a35
VZ
1801 return false;
1802 }
9111db68 1803
c2116a35
VZ
1804 m_connected = true;
1805 return true;
f4ada568
GL
1806}
1807
2b036c4b 1808bool wxSocketClient::Connect(const wxSockAddress& remote, bool wait)
33d925b0 1809{
2b036c4b 1810 return DoConnect(remote, NULL, wait);
33d925b0
KH
1811}
1812
2b036c4b 1813bool wxSocketClient::Connect(const wxSockAddress& remote,
72ac4e88
VZ
1814 const wxSockAddress& local,
1815 bool wait)
33d925b0 1816{
2b036c4b 1817 return DoConnect(remote, &local, wait);
33d925b0
KH
1818}
1819
d80d1aba 1820bool wxSocketClient::WaitOnConnect(long seconds, long milliseconds)
f4ada568 1821{
60ee0172
VZ
1822 if ( m_connected )
1823 {
1824 // this happens if the initial attempt to connect succeeded without
1825 // blocking
7fb0a11d 1826 return true;
60ee0172 1827 }
d80d1aba 1828
51fe4b60 1829 wxCHECK_MSG( m_establishing && m_impl, false,
60ee0172 1830 "No connection establishment attempt in progress" );
d80d1aba 1831
51fe4b60 1832 // we must specify wxSOCKET_LOST_FLAG here explicitly because we must return
60ee0172
VZ
1833 // true if the connection establishment process is finished, whether it is
1834 // over because we successfully connected or because we were not able to
1835 // connect
1836 return DoWait(seconds, milliseconds,
51fe4b60 1837 wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
f4ada568
GL
1838}
1839
ef57d866 1840// ==========================================================================
dc5c1114 1841// wxDatagramSocket
ef57d866 1842// ==========================================================================
dc5c1114 1843
fbfb8bcc 1844wxDatagramSocket::wxDatagramSocket( const wxSockAddress& addr,
71622a7a
GRG
1845 wxSocketFlags flags )
1846 : wxSocketBase( flags, wxSOCKET_DATAGRAM )
dc5c1114 1847{
7fb0a11d 1848 // Create the socket
51fe4b60 1849 m_impl = wxSocketImpl::Create(*this);
dc5c1114 1850
51fe4b60 1851 if (!m_impl)
7fb0a11d 1852 return;
53a161e1 1853
7fb0a11d 1854 // Setup the socket as non connection oriented
51fe4b60 1855 m_impl->SetLocal(addr.GetAddress());
28bf2f3c
VZ
1856 if (flags & wxSOCKET_REUSEADDR)
1857 {
51fe4b60 1858 m_impl->SetReusable();
28bf2f3c 1859 }
60edcf45
VZ
1860 if (GetFlags() & wxSOCKET_BROADCAST)
1861 {
51fe4b60 1862 m_impl->SetBroadcast();
60edcf45
VZ
1863 }
1864 if (GetFlags() & wxSOCKET_NOBIND)
1865 {
51fe4b60 1866 m_impl->DontDoBind();
60edcf45 1867 }
51fe4b60
VZ
1868
1869 if ( m_impl->CreateUDP() != wxSOCKET_NOERROR )
7fb0a11d 1870 {
51fe4b60
VZ
1871 delete m_impl;
1872 m_impl = NULL;
7fb0a11d
WS
1873 return;
1874 }
dc5c1114 1875
7fb0a11d
WS
1876 // Initialize all stuff
1877 m_connected = false;
1878 m_establishing = false;
dc5c1114
GRG
1879}
1880
1881wxDatagramSocket& wxDatagramSocket::RecvFrom( wxSockAddress& addr,
f187448d 1882 void* buf,
dc5c1114
GRG
1883 wxUint32 nBytes )
1884{
1885 Read(buf, nBytes);
1886 GetPeer(addr);
1887 return (*this);
1888}
1889
fbfb8bcc 1890wxDatagramSocket& wxDatagramSocket::SendTo( const wxSockAddress& addr,
f187448d 1891 const void* buf,
dc5c1114
GRG
1892 wxUint32 nBytes )
1893{
51fe4b60 1894 wxASSERT_MSG( m_impl, _T("Socket not initialised") );
8e3f3880 1895
51fe4b60 1896 m_impl->SetPeer(addr.GetAddress());
dc5c1114
GRG
1897 Write(buf, nBytes);
1898 return (*this);
1899}
1900
ef57d866 1901// ==========================================================================
a58d5df4 1902// wxSocketModule
ef57d866 1903// ==========================================================================
dc5c1114 1904
ed4c6c69 1905class wxSocketModule : public wxModule
dc5c1114 1906{
dc5c1114 1907public:
6c0d0845
VZ
1908 virtual bool OnInit()
1909 {
51fe4b60
VZ
1910 // wxSocketBase will call Initialize() itself only if sockets are
1911 // really used, don't do it from here
d775fa82 1912 return true;
6c0d0845
VZ
1913 }
1914
1915 virtual void OnExit()
1916 {
1917 if ( wxSocketBase::IsInitialized() )
1918 wxSocketBase::Shutdown();
1919 }
1920
1921private:
1922 DECLARE_DYNAMIC_CLASS(wxSocketModule)
a58d5df4
GL
1923};
1924
1925IMPLEMENT_DYNAMIC_CLASS(wxSocketModule, wxModule)
1926
c2116a35 1927#endif // wxUSE_SOCKETS