]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/socket.cpp
Fillid in many more missing functions (such as Enable())
[wxWidgets.git] / src / common / socket.cpp
... / ...
CommitLineData
1////////////////////////////////////////////////////////////////////////////////
2// Name: socket.cpp
3// Purpose: Socket handler classes
4// Authors: Guilhem Lavaux (completely rewritten from a basic API of Andrew
5// Davidson(1995) in wxWeb)
6// Created: April 1997
7// Updated: March 1998
8// Copyright: (C) 1998, 1997, Guilhem Lavaux
9// RCS_ID: $Id$
10// License: see wxWindows license
11////////////////////////////////////////////////////////////////////////////////
12#ifdef __GNUG__
13#pragma implementation "socket.h"
14#pragma interface
15#pragma implementation "socket.cpp"
16#endif
17
18/////////////////////////////////////////////////////////////////////////////
19// wxWindows headers
20/////////////////////////////////////////////////////////////////////////////
21#include <wx/defs.h>
22#include <wx/object.h>
23#include <wx/string.h>
24#include <wx/timer.h>
25#include <wx/utils.h>
26
27#include <stdlib.h>
28#include <string.h>
29#include <ctype.h>
30
31/////////////////////////////////////////////////////////////////////////////
32// System specific headers
33/////////////////////////////////////////////////////////////////////////////
34#if defined(__WINDOWS__)
35#include <winsock.h>
36#endif // __WINDOWS__
37
38#if defined(__UNIX__)
39
40#ifdef VMS
41#include <socket.h>
42#else
43#include <sys/socket.h>
44#endif
45#include <sys/ioctl.h>
46
47#include <sys/time.h>
48#include <unistd.h>
49
50#endif // __UNIX__
51
52#include <signal.h>
53#include <errno.h>
54
55#if defined(__WXMOTIF__) || defined(__WXXT__)
56#include <X11/Intrinsic.h>
57
58/////////////////////////////
59// Needs internal variables
60/////////////////////////////
61#ifdef __WXXT__
62#define Uses_XtIntrinsic
63#endif
64
65#endif
66
67#if defined(__WXGTK__)
68#include <gtk/gtk.h>
69#endif
70
71/////////////////////////////////////////////////////////////////////////////
72// wxSocket headers
73/////////////////////////////////////////////////////////////////////////////
74#define WXSOCK_INTERNAL
75#include "wx/sckaddr.h"
76#include "wx/socket.h"
77
78#ifdef __BORLANDC__
79#pragma hdrstop
80#endif
81
82/////////////////////////////////////////////////////////////////////////////
83// Some patch ///// BEGIN
84/////////////////////////////////////////////////////////////////////////////
85#ifdef __WINDOWS__
86#define close closesocket
87#define ioctl ioctlsocket
88#define errno WSAGetLastError()
89#ifdef EWOULDBLOCK
90#undef EWOULDBLOCK
91#endif
92#define EWOULDBLOCK WSAEWOULDBLOCK
93#define ETIMEDOUT WSAETIMEDOUT
94#undef EINTR
95#define EINTR WSAEINTR
96#endif
97
98#ifndef __WINDOWS__
99#define INVALID_SOCKET -1
100#endif
101
102#ifdef __WXMOTIF__
103#define wxAPP_CONTEXT wxTheApp->appContext
104#endif
105
106#ifdef __WINDOWS__
107// This is an MS TCP/IP routine and is not needed here. Some WinSock
108// implementations (such as PC-NFS) will require you to include this
109// or a similar routine (see appendix in WinSock doc or help file).
110
111#if defined( NEED_WSAFDIsSet ) || defined( _MSC_VER )
112int PASCAL FAR __WSAFDIsSet(SOCKET fd, fd_set FAR *set)
113{
114 int i = set->fd_count;
115
116 while (i--)
117 {
118 if (set->fd_array[i] == fd)
119 return 1;
120 }
121
122 return 0;
123}
124#endif
125#endif
126
127#if defined(__WINDOWS__)
128#define PROCESS_EVENTS() wxYield()
129#elif defined(__WXXT__) || defined(__WXMOTIF__)
130#define PROCESS_EVENTS() XtAppProcessEvent(wxAPP_CONTEXT, XtIMAll)
131#elif defined(__WXGTK__)
132#define PROCESS_EVENTS() gtk_main_iteration()
133#endif
134
135/////////////////////////////////////////////////////////////////////////////
136// Some patch ///// END
137/////////////////////////////////////////////////////////////////////////////
138
139// --------------------------------------------------------------
140// ClassInfos
141// --------------------------------------------------------------
142#if !USE_SHARED_LIBRARY
143IMPLEMENT_CLASS(wxSocketBase, wxObject)
144IMPLEMENT_CLASS(wxSocketServer, wxSocketBase)
145IMPLEMENT_CLASS(wxSocketClient, wxSocketBase)
146IMPLEMENT_CLASS(wxSocketHandler, wxObject)
147IMPLEMENT_DYNAMIC_CLASS(wxSocketEvent, wxEvent)
148#endif
149
150class wxSockWakeUp : public wxTimer {
151public:
152 int *my_id;
153 int n_val;
154 wxSocketBase *sock;
155
156 wxSockWakeUp(wxSocketBase *_sock, int *id, int new_val) {
157 my_id = id; n_val = new_val;
158 sock = _sock;
159 }
160 virtual void Notify() {
161 *my_id = n_val;
162 if (sock) sock->Notify(FALSE);
163 }
164};
165
166/// Socket request
167class SockRequest : public wxObject {
168public:
169 char *buffer;
170 size_t size, nbytes;
171 bool done;
172 int error;
173 wxSockWakeUp *auto_wakeup;
174 wxSocketBase::wxRequestNotify type;
175};
176
177
178/////////////////////////////////////////////////////////////////////////////
179// Some internal define
180/////////////////////////////////////////////////////////////////////////////
181
182// --------------------------------------------------------------
183// --------- wxSocketBase CONSTRUCTOR ---------------------------
184// --------------------------------------------------------------
185wxSocketBase::wxSocketBase(wxSocketBase::wxSockFlags _flags,
186 wxSocketBase::wxSockType _type) :
187 wxEvtHandler(),
188 m_flags(_flags), m_type(_type), m_connected(FALSE), m_connecting(FALSE),
189 m_fd(INVALID_SOCKET), m_waitflags(0), m_cbk(0), m_cdata(0), m_id(-1),
190 m_handler(0),
191 m_neededreq((wxRequestNotify)(REQ_READ | REQ_LOST)),
192 m_cbkon(FALSE),
193 m_unread(NULL), m_unrd_size(0),
194 m_processing(FALSE),
195 m_timeout(3600), m_wantbuf(0)
196{
197 m_internal = new wxSockInternal;
198#if defined(__WXXT__) || defined(__WXMOTIF__) || defined(__WXGTK__)
199 m_internal->sock_inputid = 0;
200 m_internal->sock_outputid = 0;
201 m_internal->sock_exceptid = 0;
202#endif
203#ifdef __WINDOWS__
204 m_internal->my_msg = 0;
205#endif
206}
207
208wxSocketBase::wxSocketBase() :
209 wxEvtHandler(),
210 m_flags(WAITALL), m_type(SOCK_UNINIT), m_connected(FALSE),
211 m_connecting(FALSE), m_fd(INVALID_SOCKET), m_waitflags(0),
212 m_cbk(0), m_cdata(0),
213 m_id(-1), m_handler(0),
214 m_neededreq((wxRequestNotify)(REQ_READ | REQ_LOST)),
215 m_cbkon(FALSE),
216 m_unread(NULL), m_unrd_size(0),
217 m_processing(FALSE),
218 m_timeout(3600), m_wantbuf(0)
219{
220 m_internal = new wxSockInternal;
221#if defined(__WXXT__) || defined(__WXMOTIF__) || defined(__WXGTK__)
222 m_internal->sock_inputid = 0;
223 m_internal->sock_outputid = 0;
224 m_internal->sock_exceptid = 0;
225#endif
226#ifdef __WINDOWS__
227 m_internal->my_msg = 0;
228#endif
229}
230
231// --------------------------------------------------------------
232// --------- wxSocketBase CONSTRUCTOR ---------------------------
233// --------------------------------------------------------------
234wxSocketBase::~wxSocketBase()
235{
236 DestroyCallbacks();
237 Close();
238
239 if (m_unread)
240 free(m_unread);
241 if (m_handler) {
242#ifdef __WINDOWS__
243 if (m_internal->my_msg)
244 m_handler->DestroyMessage(m_internal->my_msg);
245#endif
246 m_handler->UnRegister(this);
247 }
248 m_states.DeleteContents(TRUE);
249
250 delete m_internal;
251}
252
253bool wxSocketBase::Close()
254{
255 if (m_fd != INVALID_SOCKET) {
256 for (int i=0;i<3;i++) {
257 wxNode *n, *node = req_list[i].First();
258
259 while (node) {
260 SockRequest *req = (SockRequest *)node->Data();
261 req->done = TRUE;
262
263 n = node->Next();
264 delete node;
265 node = n;
266 }
267 }
268
269 DestroyCallbacks();
270 shutdown(m_fd, 2);
271 close(m_fd);
272 m_fd = INVALID_SOCKET;
273 m_connected = FALSE;
274 }
275
276 return TRUE;
277}
278
279// --------------------------------------------------------------
280// --------- wxSocketBase base IO functions ---------------------
281// --------------------------------------------------------------
282wxSocketBase& wxSocketBase::Read(char* buffer, size_t nbytes)
283{
284 m_lcount = GetPushback(buffer, nbytes, FALSE);
285
286 // If we have got the whole needed buffer or if we don't want to
287 // wait then it returns immediately.
288 if (!nbytes || (m_lcount && !(m_flags & WAITALL)) )
289 return *this;
290
291 WantBuffer(buffer, nbytes, EVT_READ);
292
293 return *this;
294}
295
296wxSocketBase& wxSocketBase::Peek(char* buffer, size_t nbytes)
297{
298 size_t nbytes_old = nbytes;
299
300 nbytes -= GetPushback(buffer, nbytes, TRUE);
301 if (!nbytes) {
302 m_lcount = nbytes_old;
303 return *this;
304 }
305
306 WantBuffer(buffer, nbytes, EVT_PEEK);
307
308 return *this;
309}
310
311wxSocketBase& wxSocketBase::Write(const char *buffer, size_t nbytes)
312{
313 WantBuffer((char *)buffer, nbytes, EVT_WRITE);
314 return *this;
315}
316
317wxSocketBase& wxSocketBase::ReadMsg(char* buffer, size_t nbytes)
318{
319 SockMsg msg;
320 size_t len, len2, sig;
321
322 Read((char *)&msg, sizeof(msg));
323 if (m_lcount != sizeof(msg))
324 return *this;
325
326 sig = msg.sig[0] & 0xff;
327 sig |= (size_t)(msg.sig[1] & 0xff) << 8;
328 sig |= (size_t)(msg.sig[2] & 0xff) << 16;
329 sig |= (size_t)(msg.sig[3] & 0xff) << 24;
330
331 if (sig != 0xfeeddead)
332 return *this;
333 len = msg.len[0] & 0xff;
334 len |= (size_t)(msg.len[1] & 0xff) << 8;
335 len |= (size_t)(msg.len[2] & 0xff) << 16;
336 len |= (size_t)(msg.len[3] & 0xff) << 24;
337 len2 = len;
338 if (len > nbytes)
339 len = nbytes;
340 else
341 len2 = 0;
342
343 if (Read(buffer, len).LastCount() != len)
344 return *this;
345 if (len2 && (Read(NULL, len2).LastCount() != len2))
346 return *this;
347 if (Read((char *)&msg, sizeof(msg)).LastCount() != sizeof(msg))
348 return *this;
349
350 sig = msg.sig[0] & 0xff;
351 sig |= (size_t)(msg.sig[1] & 0xff) << 8;
352 sig |= (size_t)(msg.sig[2] & 0xff) << 16;
353 sig |= (size_t)(msg.sig[3] & 0xff) << 24;
354// ERROR
355 if (sig != 0xdeadfeed)
356 return *this;
357
358 return *this;
359}
360
361wxSocketBase& wxSocketBase::WriteMsg(const char *buffer, size_t nbytes)
362{
363 SockMsg msg;
364
365 msg.sig[0] = 0xad;
366 msg.sig[1] = 0xde;
367 msg.sig[2] = 0xed;
368 msg.sig[3] = 0xfe;
369
370 msg.len[0] = nbytes & 0xff;
371 msg.len[1] = (nbytes >> 8) & 0xff;
372 msg.len[2] = (nbytes >> 16) & 0xff;
373 msg.len[3] = (nbytes >> 24) & 0xff;
374
375 if (Write((char *)&msg, sizeof(msg)).LastCount() < sizeof(msg))
376 return *this;
377 if (Write(buffer, nbytes).LastCount() < nbytes)
378 return *this;
379
380 msg.sig[0] = 0xed;
381 msg.sig[1] = 0xfe;
382 msg.sig[2] = 0xad;
383 msg.sig[3] = 0xde;
384 msg.len[0] = msg.len[1] = msg.len[2] = msg.len[3] = 0;
385 Write((char *)&msg, sizeof(msg));
386
387 return *this;
388}
389
390wxSocketBase& wxSocketBase::Unread(const char *buffer, size_t nbytes)
391{
392 CreatePushbackAfter(buffer, nbytes);
393 return *this;
394}
395
396bool wxSocketBase::IsData() const
397{
398 struct timeval tv;
399 fd_set sock_set;
400
401 if (m_fd < 0)
402 return FALSE;
403 if (m_unrd_size > 0)
404 return TRUE;
405
406 tv.tv_sec = 0;
407 tv.tv_usec = 0;
408 FD_ZERO(&sock_set);
409 FD_SET(m_fd, &sock_set);
410 select(FD_SETSIZE, &sock_set, NULL, NULL, &tv);
411 return FD_ISSET(m_fd, &sock_set);
412}
413
414// ---------------------------------------------------------------------
415// --------- wxSocketBase Discard(): deletes all byte in the input queue
416// ---------------------------------------------------------------------
417void wxSocketBase::Discard()
418{
419#define MAX_BUFSIZE (10*1024)
420 char *my_data = new char[MAX_BUFSIZE];
421 size_t recv_size = MAX_BUFSIZE;
422
423 SaveState();
424 SetFlags((wxSockFlags)(NOWAIT | SPEED));
425
426 while (recv_size == MAX_BUFSIZE) {
427 recv_size = Read(my_data, MAX_BUFSIZE).LastCount();
428 }
429
430 RestoreState();
431 delete [] my_data;
432
433#undef MAX_BUFSIZE
434}
435
436// --------------------------------------------------------------
437// --------- wxSocketBase socket info functions -----------------
438// --------------------------------------------------------------
439bool wxSocketBase::GetPeer(wxSockAddress& addr_man) const
440{
441 struct sockaddr my_addr;
442 size_t len_addr = sizeof(my_addr);
443
444 if (m_fd < 0)
445 return FALSE;
446
447#ifdef __WINDOWS__
448 if (getpeername(m_fd, (struct sockaddr *)&my_addr, (int *)&len_addr) < 0)
449#else
450 if (getpeername(m_fd, (struct sockaddr *)&my_addr, (unsigned int *)&len_addr) < 0)
451#endif
452 return FALSE;
453
454 addr_man.Disassemble(&my_addr, len_addr);
455 return TRUE;
456}
457
458bool wxSocketBase::GetLocal(wxSockAddress& addr_man) const
459{
460 struct sockaddr my_addr;
461 size_t len_addr = sizeof(my_addr);
462
463 if (m_fd < 0)
464 return FALSE;
465
466#ifdef __WINDOWS__
467 if (getsockname(m_fd, (struct sockaddr *)&my_addr, (int *)&len_addr) < 0)
468#else
469 if (getsockname(m_fd, (struct sockaddr *)&my_addr, (unsigned int *)&len_addr) < 0)
470#endif
471 return FALSE;
472
473 addr_man.Disassemble(&my_addr, len_addr);
474 return TRUE;
475}
476
477// --------------------------------------------------------------
478// --------- wxSocketBase wait functions ------------------------
479// --------------------------------------------------------------
480void wxSocketBase::SaveState()
481{
482 wxSockState *state = new wxSockState;
483
484 state->cbk_on = m_cbkon;
485 state->cbk_set= m_neededreq;
486 state->cbk = m_cbk;
487 state->cdata = m_cdata;
488 state->flags = m_flags;
489 state->notif = m_notifyme;
490
491 m_states.Append(state);
492}
493
494void wxSocketBase::RestoreState()
495{
496 wxNode *node;
497
498 node = m_states.Last();
499 if (!node)
500 return;
501
502 wxSockState *state = (wxSockState *)node->Data();
503
504 SetFlags(state->flags);
505 m_neededreq = state->cbk_set;
506 m_cbk = state->cbk;
507 m_cdata = state->cdata;
508 m_notifyme = state->notif;
509 if (state->cbk_on)
510 SetupCallbacks();
511 else
512 DestroyCallbacks();
513
514 delete node;
515 delete state;
516}
517
518// --------------------------------------------------------------
519// --------- wxSocketBase wait functions ------------------------
520// --------------------------------------------------------------
521//
522bool wxSocketBase::_Wait(long seconds, long microseconds, int type)
523{
524 if ((!m_connected && !m_connecting) || m_fd < 0)
525 return FALSE;
526
527 wxSockWakeUp wakeup(this, &m_waitflags, 0);
528
529 SaveState();
530 SetNotify((wxRequestNotify)type);
531 SetupCallbacks();
532
533 if (seconds != -1)
534 wakeup.Start((int)(seconds*1000 + (microseconds / 1000)), TRUE);
535
536 m_waitflags = 0x80 | type;
537 while (m_waitflags & 0x80)
538 PROCESS_EVENTS();
539
540 RestoreState();
541
542 if (m_waitflags & 0x40) {
543 m_waitflags = 0;
544 return TRUE;
545 }
546 m_waitflags = 0;
547
548 return FALSE;
549}
550
551bool wxSocketBase::Wait(long seconds, long microseconds)
552{
553 return _Wait(seconds, microseconds, REQ_ACCEPT | REQ_CONNECT |
554 REQ_READ | REQ_WRITE | REQ_LOST);
555}
556
557bool wxSocketBase::WaitForRead(long seconds, long microseconds)
558{
559 return _Wait(seconds, microseconds, REQ_READ | REQ_LOST);
560}
561
562bool wxSocketBase::WaitForWrite(long seconds, long microseconds)
563{
564 return _Wait(seconds, microseconds, REQ_WRITE);
565}
566
567bool wxSocketBase::WaitForLost(long seconds, long microseconds)
568{
569 return _Wait(seconds, microseconds, REQ_LOST);
570}
571
572// --------------------------------------------------------------
573// --------- wxSocketBase callback management -------------------
574// --------------------------------------------------------------
575
576#if defined(__WXMOTIF__) || defined(__WXXT__) || defined(__WXGTK__)
577#if defined(__WXMOTIF__) || defined(__WXXT__)
578static void wx_socket_read(XtPointer client, int *fid,
579 XtInputId *WXUNUSED(id))
580#define fd *fid
581#else
582static void wx_socket_read(gpointer client, gint fd,
583 GdkInputCondition WXUNUSED(cond))
584#define fd fd
585#endif
586{
587 wxSocketBase *sock = (wxSocketBase *)client;
588 char c;
589 int i;
590
591 i = recv(fd, &c, 1, MSG_PEEK);
592
593 if (i == -1 && (sock->NeededReq() & wxSocketBase::REQ_ACCEPT)) {
594 sock->OnRequest(wxSocketBase::EVT_ACCEPT);
595 return;
596 }
597
598 if (i != 0) {
599 if (!(sock->NeededReq() & wxSocketBase::REQ_READ))
600 return;
601
602 sock->OnRequest(wxSocketBase::EVT_READ);
603 } else {
604 if (!(sock->NeededReq() & wxSocketBase::REQ_LOST)) {
605 sock->Close();
606 return;
607 }
608
609 sock->OnRequest(wxSocketBase::EVT_LOST);
610 }
611}
612#undef fd
613
614#if defined(__WXMOTIF__) || defined(__WXXT__)
615static void wx_socket_write(XtPointer client, int *WXUNUSED(fid),
616 XtInputId *WXUNUSED(id))
617#else
618static void wx_socket_write(gpointer client, gint WXUNUSED(fd),
619 GdkInputCondition WXUNUSED(cond))
620#endif
621{
622 wxSocketBase *sock = (wxSocketBase *)client;
623
624 if (!sock->IsConnected())
625 sock->OnRequest(wxSocketBase::EVT_CONNECT);
626 else
627 sock->OnRequest(wxSocketBase::EVT_WRITE);
628}
629#endif
630
631#ifdef wx_xview
632Notify_value wx_sock_read_xview (Notify_client client, int fd)
633{
634 wxSocketBase *sock = (wxSocketBase *)client;
635 char c;
636 int i;
637
638 i = recv(fd, &c, 1, MSG_PEEK);
639
640 if (i == -1 && (sock->NeededReq() & wxSocketBase::REQ_ACCEPT)) {
641 sock->OnRequest(wxSocketBase::EVT_ACCEPT);
642 return;
643 }
644
645 /* Bytes arrived */
646 if (i != 0) {
647 if (!(sock->NeededReq() & wxSocketBase::REQ_READ))
648 return (Notify_value) FALSE;
649
650 sock->OnRequest(wxSocketBase::EVT_READ);
651 } else {
652 if (!(sock->NeededReq() & wxSocketBase::REQ_LOST))
653 return;
654
655 sock->OnRequest(wxSocketBase::EVT_LOST);
656 }
657
658 return (Notify_value) FALSE;
659}
660
661Notify_value wx_sock_write_xview (Notify_client client, int fd)
662{
663 wxSocketBase *sock = (wxSocketBase *)client;
664
665 if (!sock->IsConnected())
666 sock->OnRequest(wxSocketBase::EVT_CONNECT);
667 else
668 sock->OnRequest(wxSocketBase::EVT_WRITE);
669
670 return (Notify_value) TRUE;
671}
672#endif
673
674wxSocketBase::wxRequestNotify wxSocketBase::EventToNotify(wxRequestEvent evt)
675{
676 switch (evt) {
677 case EVT_READ:
678 return REQ_READ;
679 case EVT_PEEK:
680 return REQ_PEEK;
681 case EVT_WRITE:
682 return REQ_WRITE;
683 case EVT_LOST:
684 return REQ_LOST;
685 case EVT_ACCEPT:
686 return REQ_ACCEPT;
687 case EVT_CONNECT:
688 return REQ_CONNECT;
689 }
690 return 0;
691}
692
693void wxSocketBase::SetFlags(wxSockFlags _flags)
694{
695 m_flags = _flags;
696 if (_flags & SPEED) {
697 unsigned long flag = 0;
698 ioctl(m_fd, FIONBIO, &flag);
699
700 // SPEED and WAITALL are antagonists.
701 m_flags = (wxSockFlags)(m_flags & ~WAITALL);
702
703 Notify(FALSE);
704 } else {
705 unsigned long flag = 1;
706 ioctl(m_fd, FIONBIO, &flag);
707 }
708}
709
710void wxSocketBase::SetNotify(wxRequestNotify flags)
711{
712 wxRequestNotify old_needed_req = m_neededreq;
713 if (flags & REQ_ACCEPT) {
714 /* Check if server */
715 if (!(GetClassInfo()->IsKindOf(CLASSINFO(wxSocketServer))))
716 flags &= ~REQ_ACCEPT;
717 }
718 m_neededreq = flags;
719 if (m_cbkon && old_needed_req != flags)
720 SetupCallbacks();
721}
722
723void wxSocketBase::SetupCallbacks()
724{
725 if (m_fd == INVALID_SOCKET || !m_handler || (m_flags & SPEED))
726 return;
727
728#if defined(__WXMOTIF__) || defined(__WXXT__) || defined(__WXGTK__)
729 if (m_cbkon)
730 DestroyCallbacks();
731 if (m_neededreq & (REQ_ACCEPT | REQ_READ | REQ_LOST)) {
732#ifdef __WXGTK__
733 m_internal->sock_inputid = gdk_input_add(m_fd, GDK_INPUT_READ,
734 wx_socket_read, (gpointer)this);
735#else
736 m_internal->sock_inputid = XtAppAddInput (wxAPP_CONTEXT, m_fd,
737 (XtPointer *) XtInputReadMask,
738 (XtInputCallbackProc) wx_socket_read,
739 (XtPointer) this);
740#endif
741 }
742 if (m_neededreq & (REQ_CONNECT | REQ_WRITE)) {
743#ifdef __WXGTK__
744 m_internal->sock_inputid = gdk_input_add(m_fd, GDK_INPUT_WRITE,
745 wx_socket_write, (gpointer)this);
746#else
747 m_internal->sock_outputid = XtAppAddInput (wxAPP_CONTEXT, m_fd,
748 (XtPointer *) XtInputWriteMask,
749 (XtInputCallbackProc) wx_socket_write,
750 (XtPointer) this);
751#endif
752 }
753#endif
754#ifdef __WINDOWS__
755 WORD mask = 0;
756
757 if (m_neededreq & REQ_READ)
758 mask |= FD_READ;
759 if (m_neededreq & REQ_WRITE)
760 mask |= FD_WRITE;
761 if (m_neededreq & REQ_LOST)
762 mask |= FD_CLOSE;
763 if (m_neededreq & REQ_ACCEPT)
764 mask |= FD_ACCEPT;
765 if (m_neededreq & REQ_CONNECT)
766 mask |= FD_CONNECT;
767
768 if (!m_internal->my_msg)
769 m_internal->my_msg = m_handler->NewMessage(this);
770 WSAAsyncSelect(m_fd, m_handler->GetHWND(), m_internal->my_msg, mask);
771#endif
772 m_cbkon = TRUE;
773 m_processing = FALSE;
774}
775
776void wxSocketBase::DestroyCallbacks()
777{
778 if (!m_cbkon || !m_handler)
779 return;
780 m_cbkon = FALSE;
781 m_processing = FALSE;
782#if defined(__WXMOTIF__) || defined(__WXXT__)
783 if (m_internal->sock_inputid > 0)
784 XtRemoveInput(m_internal->sock_inputid);
785 m_internal->sock_inputid = 0;
786 if (m_internal->sock_outputid > 0)
787 XtRemoveInput(m_internal->sock_outputid);
788 m_internal->sock_outputid = 0;
789#endif
790#ifdef __WXGTK__
791 if (m_internal->sock_inputid > 0)
792 gdk_input_remove(m_internal->sock_inputid);
793 m_internal->sock_inputid = 0;
794 if (m_internal->sock_outputid > 0)
795 gdk_input_remove(m_internal->sock_outputid);
796 m_internal->sock_outputid = 0;
797#endif
798#ifdef __WINDOWS__
799 WSAAsyncSelect(m_fd, m_handler->GetHWND(), 0, 0);
800#endif
801}
802
803void wxSocketBase::Notify(bool notify)
804{
805 if (m_notifyme == notify)
806 return;
807 if (notify)
808 SetupCallbacks();
809 else
810 DestroyCallbacks();
811 m_notifyme = notify;
812}
813
814void wxSocketBase::OnRequest(wxRequestEvent req_evt)
815{
816 wxRequestNotify req_notif = EventToNotify(req_evt);
817
818 // Mask the current event
819 SetNotify(m_neededreq & ~req_notif);
820
821 if (req_evt <= EVT_WRITE && DoRequests(req_evt))
822 return;
823
824 if (m_waitflags & 0xF0) {
825 // Wake up
826 if ((m_waitflags & 0x0F) == req_evt) {
827 m_waitflags = 0x80;
828#ifndef __WXGTK__
829 DestroyCallbacks(); // I disable it to prevent infinite loop on X11.
830#endif
831 }
832 return;
833 }
834
835 if (req_evt == EVT_LOST) {
836 m_connected = FALSE;
837 Close();
838 }
839 if (m_notifyme)
840 OldOnNotify(req_evt);
841
842 // Unmask
843 SetNotify(m_neededreq | req_notif);
844}
845
846wxSocketEvent::wxSocketEvent(int id)
847 : wxEvent(id)
848{
849 wxEventType type = (wxEventType)wxEVT_SOCKET;
850
851 SetEventType(type);
852}
853
854void wxSocketBase::OldOnNotify(wxRequestEvent evt)
855{
856 wxSocketEvent event(m_id);
857
858 event.SetEventObject(this);
859 event.m_skevt = evt;
860 ProcessEvent(event);
861
862 if (m_cbk)
863 m_cbk(*this, evt, m_cdata);
864}
865
866// --------------------------------------------------------------
867// --------- wxSocketBase functions [Callback, CallbackData] ----
868// --------------------------------------------------------------
869wxSocketBase::wxSockCbk wxSocketBase::Callback(wxSocketBase::wxSockCbk _cbk)
870{
871 wxSockCbk old_cbk = m_cbk;
872
873 m_cbk = _cbk;
874 return old_cbk;
875}
876
877char *wxSocketBase::CallbackData(char *cdata_)
878{
879 char *old_cdata = m_cdata;
880
881 m_cdata = cdata_;
882 return old_cdata;
883}
884
885void wxSocketBase::SetEventHandler(wxEvtHandler& h_evt, int id)
886{
887 SetNextHandler(&h_evt);
888 m_id = id;
889}
890
891// --------------------------------------------------------------
892// --------- wxSocketBase pushback library ----------------------
893// --------------------------------------------------------------
894void wxSocketBase::CreatePushbackAfter(const char *buffer, size_t size)
895{
896 char *curr_pos;
897
898 m_unread = (char *) realloc(m_unread, m_unrd_size+size);
899 curr_pos = m_unread + m_unrd_size;
900
901 memcpy(curr_pos, buffer, size);
902 m_unrd_size += size;
903}
904
905void wxSocketBase::CreatePushbackBefore(const char *buffer, size_t size)
906{
907 char *curr_pos, *new_buf;
908
909 new_buf = (char *) malloc(m_unrd_size+size);
910 curr_pos = new_buf + size;
911
912 memcpy(new_buf, buffer, size);
913 memcpy(curr_pos, m_unread, m_unrd_size);
914
915 free(m_unread);
916 m_unread = new_buf;
917 m_unrd_size += size;
918}
919
920size_t wxSocketBase::GetPushback(char *buffer, size_t size, bool peek)
921{
922 if (!m_unrd_size)
923 return 0;
924
925 if (size > m_unrd_size)
926 size = m_unrd_size;
927 memcpy(buffer, m_unread, size);
928
929 if (!peek) {
930 m_unrd_size -= size;
931 if (!m_unrd_size) {
932 free(m_unread);
933 m_unread = NULL;
934 }
935 }
936
937 return size;
938}
939
940// --------------------------------------------------------------
941// --------- wxSocketBase "multi-thread" core -------------------
942// --------------------------------------------------------------
943
944bool wxSocketBase::DoRequests(wxRequestEvent req_flag)
945{
946 wxNode *node = req_list[req_flag].First();
947 size_t len;
948 int ret;
949
950 if (!node)
951 return FALSE;
952
953 SockRequest *req = (SockRequest *)node->Data();
954
955 delete node;
956
957 switch (req->type) {
958 case EVT_READ:
959 case EVT_PEEK:
960 ret = recv(m_fd, req->buffer, req->size,
961 (req->type == EVT_PEEK) ? MSG_PEEK : 0);
962 if (ret < 0) {
963 req->error = errno;
964 req->done = TRUE;
965 break;
966 }
967 len = ret;
968 if ((len < req->size) && (m_flags & WAITALL)) {
969 req->size -= len;
970 req->nbytes += len;
971 req->buffer += len;
972 req->auto_wakeup->Start(m_timeout*1000, TRUE);
973 req_list[req_flag].Insert(req);
974 break;
975 }
976 req->done = TRUE;
977 req->nbytes += len;
978#ifndef __WXGTK__
979 DestroyCallbacks();
980#endif
981 break;
982 case EVT_WRITE:
983 ret = send(m_fd, req->buffer, req->size, 0);
984 if (ret < 0) {
985 req->error = errno;
986 req->done = TRUE;
987 break;
988 }
989 len = ret;
990 if ((len < req->size) && (m_flags & WAITALL)) {
991 req->size -= len;
992 req->nbytes += len;
993 req->buffer += len;
994 req->auto_wakeup->Start(m_timeout*1000, TRUE);
995 req_list[req_flag].Insert(req);
996 break;
997 }
998 req->done = TRUE;
999 req->nbytes += len;
1000#ifndef __WXGTK__
1001 DestroyCallbacks();
1002#endif
1003 break;
1004 default:
1005 return FALSE;
1006 }
1007 return TRUE;
1008}
1009
1010void wxSocketBase::WantSpeedBuffer(char *buffer, size_t nbytes,
1011 wxRequestEvent evt)
1012{
1013 int ret;
1014
1015 switch (evt) {
1016 case EVT_PEEK:
1017 case EVT_READ:
1018 ret = read(m_fd, buffer, nbytes);
1019 break;
1020 case EVT_WRITE:
1021 ret = write(m_fd, buffer, nbytes);
1022 break;
1023 }
1024 if (ret < 0) {
1025 m_lcount = 0;
1026 m_error = errno;
1027 } else
1028 m_lcount = ret;
1029}
1030
1031void wxSocketBase::WantBuffer(char *buffer, size_t nbytes,
1032 wxRequestEvent evt)
1033{
1034 bool buf_timed_out;
1035
1036 if (m_fd == INVALID_SOCKET || !m_handler || !m_connected)
1037 return;
1038
1039 if (m_flags & SPEED) {
1040 WantSpeedBuffer(buffer, nbytes, evt);
1041 return;
1042 }
1043
1044 SockRequest *buf = new SockRequest;
1045 wxSockWakeUp s_wake(NULL, (int *)&buf_timed_out, (int)TRUE);
1046
1047 m_wantbuf++;
1048 req_list[evt].Append(buf);
1049
1050 SaveState();
1051 SetNotify(REQ_LOST | EventToNotify(evt));
1052 SetupCallbacks();
1053 buf->buffer = buffer;
1054 buf->size = nbytes;
1055 buf->done = FALSE;
1056 buf->type = evt;
1057 buf->nbytes = 0;
1058 buf->auto_wakeup = &s_wake;
1059 buf->error = 0;
1060 buf_timed_out = FALSE;
1061
1062 s_wake.Start(m_timeout*1000, TRUE);
1063 if (m_flags & NOWAIT) {
1064 DoRequests(evt);
1065 } else {
1066 while (!buf->done && !buf_timed_out)
1067 PROCESS_EVENTS();
1068 }
1069 m_wantbuf--;
1070 m_lcount = buf->nbytes;
1071 if (buf_timed_out)
1072 m_error = ETIMEDOUT;
1073 else
1074 m_error = buf->error;
1075
1076 delete buf;
1077 RestoreState();
1078}
1079
1080// --------------------------------------------------------------
1081// wxSocketServer ///////////////////////////////////////////////
1082// --------------------------------------------------------------
1083
1084// --------------------------------------------------------------
1085// --------- wxSocketServer CONSTRUCTOR -------------------------
1086// --------------------------------------------------------------
1087wxSocketServer::wxSocketServer(wxSockAddress& addr_man,
1088 wxSockFlags flags) :
1089 wxSocketBase(flags, SOCK_SERVER)
1090{
1091 m_fd = socket(addr_man.GetFamily(), SOCK_STREAM, 0);
1092
1093 if (m_fd == INVALID_SOCKET)
1094 return;
1095
1096 int flag = 1;
1097 setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(int));
1098
1099 struct sockaddr *myaddr;
1100 size_t len;
1101
1102 addr_man.Build(myaddr, len);
1103 if (bind(m_fd, myaddr, addr_man.SockAddrLen()) < 0)
1104 return;
1105
1106 if (listen(m_fd, 5) < 0) {
1107 m_fd = INVALID_SOCKET;
1108 return;
1109 }
1110}
1111
1112// --------------------------------------------------------------
1113// --------- wxSocketServer Accept ------------------------------
1114// --------------------------------------------------------------
1115bool wxSocketServer::AcceptWith(wxSocketBase& sock)
1116{
1117 int fd2;
1118
1119 if ((fd2 = accept(m_fd, 0, 0)) < 0)
1120 return FALSE;
1121
1122 struct linger linger;
1123 linger.l_onoff = 0;
1124 linger.l_linger = 1;
1125
1126 setsockopt(fd2, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger));
1127
1128 int flag = 0;
1129 setsockopt(fd2, SOL_SOCKET, SO_KEEPALIVE, (char*)&flag, sizeof(int));
1130
1131 if (!(sock.m_flags & SPEED)) {
1132 unsigned long flag2 = 1;
1133 ioctl(fd2, FIONBIO, &flag2);
1134 }
1135
1136 sock.m_type = SOCK_INTERNAL;
1137 sock.m_fd = fd2;
1138 sock.m_connected = TRUE;
1139
1140 return TRUE;
1141}
1142
1143wxSocketBase *wxSocketServer::Accept()
1144{
1145 wxSocketBase* sock = new wxSocketBase();
1146
1147 sock->SetFlags((wxSockFlags)m_flags);
1148
1149 if (!AcceptWith(*sock))
1150 return NULL;
1151
1152 if (m_handler)
1153 m_handler->Register(sock);
1154
1155 return sock;
1156}
1157
1158// --------------------------------------------------------------
1159// --------- wxSocketServer callbacks ---------------------------
1160// --------------------------------------------------------------
1161void wxSocketServer::OnRequest(wxRequestEvent evt)
1162{
1163 if (evt == EVT_ACCEPT) {
1164 OldOnNotify(EVT_ACCEPT);
1165 }
1166}
1167
1168// --------------------------------------------------------------
1169// wxSocketClient ///////////////////////////////////////////////
1170// --------------------------------------------------------------
1171
1172// --------- wxSocketClient CONSTRUCTOR -------------------------
1173// --------------------------------------------------------------
1174wxSocketClient::wxSocketClient(wxSockFlags _flags) :
1175 wxSocketBase(_flags, SOCK_CLIENT)
1176{
1177}
1178
1179// --------------------------------------------------------------
1180// --------- wxSocketClient DESTRUCTOR --------------------------
1181// --------------------------------------------------------------
1182wxSocketClient::~wxSocketClient()
1183{
1184}
1185
1186// --------------------------------------------------------------
1187// --------- wxSocketClient Connect functions -------------------
1188// --------------------------------------------------------------
1189bool wxSocketClient::Connect(wxSockAddress& addr_man, bool wait)
1190{
1191 struct linger linger;
1192
1193 if (IsConnected())
1194 Close();
1195
1196 m_fd = socket(addr_man.GetFamily(), SOCK_STREAM, 0);
1197
1198 if (m_fd < 0)
1199 return FALSE;
1200
1201 m_connected = FALSE;
1202
1203 linger.l_onoff = 1;
1204 linger.l_linger = 5;
1205 setsockopt(m_fd, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger));
1206
1207 // Stay in touch with the state of things...
1208
1209 unsigned long flag = 1;
1210 setsockopt(m_fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&flag, sizeof(int));
1211
1212 // Disable the nagle algorithm, which delays sends till the
1213 // buffer is full (or a certain time period has passed?)...
1214
1215#if defined(__WINDOWS__) || (defined(IPPROTO_TCP) && defined(TCP_NODELAY))
1216 flag = 1;
1217 setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(int));
1218#endif
1219
1220 struct sockaddr *remote;
1221 size_t len;
1222
1223 addr_man.Build(remote, len);
1224
1225 if (connect(m_fd, remote, len) != 0)
1226 return FALSE;
1227
1228 if (!(m_flags & SPEED)) {
1229 flag = 1;
1230 ioctl(m_fd, FIONBIO, &flag);
1231 }
1232
1233 Notify(TRUE);
1234
1235 m_connected = TRUE;
1236 return TRUE;
1237}
1238
1239bool wxSocketClient::WaitOnConnect(long seconds)
1240{
1241 int ret = _Wait(seconds, 0, REQ_CONNECT | REQ_LOST);
1242
1243 if (ret)
1244 m_connected = TRUE;
1245
1246 return m_connected;
1247}
1248
1249void wxSocketClient::OnRequest(wxRequestEvent evt)
1250{
1251 if (evt == EVT_CONNECT) {
1252 if (m_connected) {
1253 SetNotify(m_neededreq & ~REQ_CONNECT);
1254 return;
1255 }
1256 m_waitflags = 0x40;
1257 m_connected = TRUE;
1258 OldOnNotify(EVT_CONNECT);
1259 DestroyCallbacks();
1260 return;
1261 }
1262 wxSocketBase::OnRequest(evt);
1263}
1264
1265/////////////////////////////////////////////////////////////////
1266// wxSocketHandler ///////////////////////////////////////////////
1267/////////////////////////////////////////////////////////////////
1268
1269wxSocketHandler *wxSocketHandler::master = NULL;
1270#if defined(__WINDOWS__)
1271static int win_initialized = 0;
1272#endif
1273
1274// --------------------------------------------------------------
1275// --------- wxSocketHandler CONSTRUCTOR ------------------------
1276// --------------------------------------------------------------
1277#ifdef __WINDOWS__
1278
1279extern char wxPanelClassName[];
1280
1281LRESULT APIENTRY _EXPORT wxSocketHandlerWndProc(HWND hWnd, UINT message,
1282 WPARAM wParam, LPARAM lParam)
1283{
1284 wxSocketHandler *h_sock = (wxSocketHandler *)GetWindowLong(hWnd, GWL_USERDATA);
1285 wxNode *node = h_sock->smsg_list->Find(message);
1286 wxSocketBase *sock;
1287 wxSocketBase::wxRequestEvent sk_req;
1288 UINT event = WSAGETSELECTEVENT(lParam);
1289
1290 if (!node)
1291 return DefWindowProc(hWnd, message, wParam, lParam);
1292
1293 sock = (wxSocketBase *)node->Data();
1294
1295 switch (event) {
1296 case FD_READ:
1297 sk_req = wxSocketBase::EVT_READ;
1298 break;
1299 case FD_WRITE:
1300 sk_req = wxSocketBase::EVT_WRITE;
1301 break;
1302 case FD_CLOSE:
1303 sk_req = wxSocketBase::EVT_LOST;
1304 break;
1305 case FD_ACCEPT:
1306 sk_req = wxSocketBase::EVT_ACCEPT;
1307 break;
1308 case FD_CONNECT:
1309 sk_req = wxSocketBase::EVT_CONNECT;
1310 break;
1311 }
1312 sock->OnRequest(sk_req);
1313
1314 return (LRESULT)0;
1315}
1316
1317FARPROC wxSocketSubClassProc = NULL;
1318
1319#endif
1320
1321wxSocketHandler::wxSocketHandler()
1322{
1323#if defined(__WINDOWS__)
1324 if (!win_initialized) {
1325 WSADATA wsaData;
1326
1327 WSAStartup((1 << 8) | 1, &wsaData);
1328 win_initialized = 1;
1329 }
1330 internal = new wxSockHandlerInternal;
1331 internal->sockWin = ::CreateWindow(wxPanelClassName, NULL, 0,
1332 0, 0, 0, 0, NULL, (HMENU) NULL,
1333 wxhInstance, 0);
1334
1335 // Subclass the window
1336 if (!wxSocketSubClassProc)
1337 wxSocketSubClassProc = MakeProcInstance((FARPROC) wxSocketHandlerWndProc, wxhInstance);
1338 ::SetWindowLong(internal->sockWin, GWL_WNDPROC, (LONG) wxSocketSubClassProc);
1339 ::SetWindowLong(internal->sockWin, GWL_USERDATA, (LONG) this);
1340
1341 internal->firstAvailableMsg = 5000;
1342 smsg_list = new wxList(wxKEY_INTEGER);
1343#endif
1344
1345 socks = new wxList;
1346
1347#ifndef __WINDOWS__
1348 signal(SIGPIPE, SIG_IGN);
1349#endif
1350}
1351
1352// --------------------------------------------------------------
1353// --------- wxSocketHandler DESTRUCTOR -------------------------
1354// --------------------------------------------------------------
1355wxSocketHandler::~wxSocketHandler()
1356{
1357 wxNode *next_node, *node = socks->First();
1358
1359 while (node) {
1360 wxSocketBase* sock = (wxSocketBase*)node->Data();
1361
1362 delete sock;
1363 next_node = node->Next();
1364 delete node;
1365 node = next_node;
1366 }
1367
1368 delete socks;
1369
1370#ifdef __WINDOWS__
1371 delete smsg_list;
1372
1373 ::DestroyWindow(internal->sockWin);
1374 WSACleanup();
1375 win_initialized = 0;
1376
1377 delete internal;
1378#endif
1379}
1380
1381// --------------------------------------------------------------
1382// --------- wxSocketHandler registering functions --------------
1383// --------------------------------------------------------------
1384void wxSocketHandler::Register(wxSocketBase* sock)
1385{
1386 wxNode *node;
1387
1388 for (node = socks->First(); node != NULL; node = node->Next()) {
1389 wxSocketBase* s = (wxSocketBase*)node->Data();
1390
1391 if (s == sock)
1392 return;
1393 }
1394
1395 if (sock) {
1396 socks->Append(sock);
1397 sock->SetHandler(this);
1398 sock->SetupCallbacks();
1399 }
1400}
1401
1402void wxSocketHandler::UnRegister(wxSocketBase* sock)
1403{
1404 wxNode *node;
1405
1406 for (node = socks->First(); node; node = node->Next()) {
1407 wxSocketBase* s = (wxSocketBase*)node->Data();
1408
1409 if (s == sock) {
1410 delete node;
1411 sock->DestroyCallbacks();
1412 sock->SetHandler(NULL);
1413 return;
1414 }
1415 }
1416}
1417
1418unsigned long wxSocketHandler::Count() const
1419{
1420 return socks->Number();
1421}
1422
1423// --------------------------------------------------------------
1424// --------- wxSocketHandler "big" wait functions ---------------
1425// --------------------------------------------------------------
1426void handler_cbk(wxSocketBase& sock,
1427 wxSocketBase::wxRequestEvent WXUNUSED(flags),
1428 char *cdata)
1429{
1430 int *a_wait = (int *)cdata;
1431
1432 (*a_wait)++;
1433 sock.Notify(FALSE);
1434}
1435
1436int wxSocketHandler::Wait(long seconds, long microseconds)
1437{
1438 int i;
1439 int on_wait;
1440 wxSockWakeUp s_wake(NULL, &on_wait, -2);
1441 wxNode *node;
1442
1443 for (node = socks->First(), i=0; node; node = node->Next(), i++) {
1444 wxSocketBase *sock = (wxSocketBase *)node->Data();
1445
1446 sock->SaveState();
1447
1448 sock->SetupCallbacks();
1449
1450 sock->Callback(handler_cbk);
1451 sock->CallbackData((char *)&on_wait);
1452 }
1453 on_wait = 0;
1454 if (seconds != -1)
1455 s_wake.Start((seconds*1000) + (microseconds/1000), TRUE);
1456
1457 while (!on_wait)
1458 PROCESS_EVENTS();
1459
1460 for (node = socks->First(), i=0; node; node = node->Next(), i++) {
1461 wxSocketBase *sock = (wxSocketBase *)node->Data();
1462
1463 sock->RestoreState();
1464 }
1465
1466 if (on_wait == -2)
1467 return 0;
1468
1469 return on_wait;
1470}
1471
1472void wxSocketHandler::YieldSock()
1473{
1474 wxNode *node;
1475
1476 for (node = socks->First(); node; node = node->Next() ) {
1477 wxSocketBase *sock = (wxSocketBase *)node->Data();
1478
1479 sock->SaveState();
1480
1481 sock->SetFlags(wxSocketBase::SPEED);
1482 if (sock->IsData())
1483 sock->DoRequests(wxSocketBase::EVT_READ);
1484 sock->DoRequests(wxSocketBase::EVT_WRITE);
1485
1486 sock->RestoreState();
1487 }
1488}
1489
1490// --------------------------------------------------------------
1491// --------- wxSocketHandler: create and register the socket ----
1492// --------------------------------------------------------------
1493wxSocketServer *wxSocketHandler::CreateServer(wxSockAddress& addr,
1494 wxSocketBase::wxSockFlags flags)
1495{
1496 wxSocketServer *serv = new wxSocketServer(addr, flags);
1497
1498 Register(serv);
1499 return serv;
1500}
1501
1502wxSocketClient *wxSocketHandler::CreateClient(wxSocketBase::wxSockFlags flags)
1503{
1504 wxSocketClient *client = new wxSocketClient(flags);
1505
1506 Register(client);
1507 return client;
1508}
1509
1510#ifdef __WINDOWS__
1511// --------------------------------------------------------------
1512// --------- wxSocketHandler: Windows specific methods ----------
1513// --------------------------------------------------------------
1514UINT wxSocketHandler::NewMessage(wxSocketBase *sock)
1515{
1516 internal->firstAvailableMsg++;
1517 smsg_list->Append(internal->firstAvailableMsg, sock);
1518 return internal->firstAvailableMsg;
1519}
1520
1521void wxSocketHandler::DestroyMessage(UINT msg)
1522{
1523 wxNode *node = smsg_list->Find(msg);
1524 delete node;
1525}
1526
1527HWND wxSocketHandler::GetHWND() const
1528{
1529 return internal->sockWin;
1530}
1531
1532#endif