]>
git.saurik.com Git - wxWidgets.git/blob - src/common/sckint.cpp
1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: Socket internal classes
4 // Authors: Guilhem Lavaux
7 // Copyright: (C) 1999, 1998, 1997, Guilhem Lavaux
9 // License: see wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "sckint.h"
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
24 #define WXSOCK_INTERNAL
25 #include <wx/object.h>
27 #include <wx/socket.h>
28 #include <wx/thread.h>
29 #include <wx/sckint.h>
31 // IRIX requires bstring.h be included to use select()
42 // -----------------------
43 // System specific headers
44 // -----------------------
47 // in order to avoid problems with our c library and double definitions
48 #define close closesocket
49 #define ioctl ioctlsocket
51 #include <wx/mac/macsock.h>
54 #if defined(__WINDOWS__)
63 #include <sys/socket.h>
65 #include <sys/ioctl.h>
71 #include <sys/filio.h>
84 #define READ_MASK wxSocketBase::REQ_READ | wxSocketBase::REQ_ACCEPT | wxSocketBase::REQ_LOST
85 #define WRITE_MASK wxSocketBase::REQ_WRITE | wxSocketBase::REQ_CONNECT
87 // --------------------------------------------------------------
88 // --------- SocketWaiter ---------------------------------------
89 // --------------------------------------------------------------
92 SocketWaiter::SocketWaiter(wxSocketBase
*socket
,
93 wxSocketInternal
*internal
)
95 m_socket(socket
), m_internal(internal
), m_fd(internal
->GetFD())
99 SocketWaiter::~SocketWaiter()
103 void SocketWaiter::ProcessReadEvent()
108 m_internal
->AcquireFD();
109 ret
= recv(m_fd
, &c
, 1, MSG_PEEK
);
110 m_internal
->ReleaseFD();
112 // We are a server => emit a EVT_ACCEPT event.
113 if (ret
== -1 && m_socket
->GetType() == wxSocketBase::SOCK_SERVER
) {
114 m_socket
->OnRequest(wxSocketBase::EVT_ACCEPT
);
118 // Else, no error => there is something to be read else
119 // we've lost the connection.
121 m_socket
->OnRequest(wxSocketBase::EVT_READ
);
123 m_socket
->OnRequest(wxSocketBase::EVT_LOST
);
124 m_internal
->ReleaseData(); // In that case, we mustn't forget to unlock the mutex.
129 void SocketWaiter::ProcessWriteEvent()
131 if (m_socket
->IsConnected())
132 m_socket
->OnRequest(wxSocketBase::EVT_CONNECT
);
134 m_socket
->OnRequest(wxSocketBase::EVT_WRITE
);
137 void *SocketWaiter::Entry()
140 fd_set sockrd_set
, sockwr_set
;
149 FD_ZERO(&sockrd_set
);
150 FD_ZERO(&sockwr_set
);
152 m_internal
->AcquireData();
154 if ((m_socket
->NeededReq() & READ_MASK
) != 0)
155 FD_SET(m_fd
, &sockrd_set
);
156 if ((m_socket
->NeededReq() & WRITE_MASK
) != 0)
157 FD_SET(m_fd
, &sockwr_set
);
159 m_internal
->AcquireFD();
160 ret
= select(m_fd
+1, &sockrd_set
, &sockwr_set
, NULL
, &tv
);
161 m_internal
->ReleaseFD();
163 if (FD_ISSET(m_fd
, &sockrd_set
))
166 if (FD_ISSET(m_fd
, &sockwr_set
))
169 m_internal
->ReleaseData();
177 // We wait for 100 ms to prevent the CPU from burning.
180 // Check whether we should exit.
187 // --------------------------------------------------------------
188 // --------- SocketRequester ------------------------------------
189 // --------------------------------------------------------------
191 SocketRequester::SocketRequester(wxSocketBase
*socket
,
192 wxSocketInternal
*internal
)
197 m_socket(socket
), m_internal(internal
), m_fd(internal
->GetFD())
201 SocketRequester::~SocketRequester()
205 bool SocketRequester::WaitFor(wxSocketBase::wxRequestNotify req
, int millisec
)
209 fd_set sockrd_set
, sockwr_set
;
212 tv
.tv_sec
= millisec
/ 1000;
213 tv
.tv_usec
= (millisec
% 1000) * 1000;
215 FD_ZERO(&sockrd_set
);
216 FD_ZERO(&sockwr_set
);
217 if ((req
& READ_MASK
) != 0)
218 FD_SET(m_fd
, &sockrd_set
);
219 if ((req
& WRITE_MASK
) != 0)
220 FD_SET(m_fd
, &sockwr_set
);
222 m_internal
->AcquireFD();
223 ret
= select(m_fd
+1, &sockrd_set
, &sockwr_set
, NULL
, &tv
);
224 m_internal
->ReleaseFD();
229 void SocketRequester::ProcessReadEvent(SockRequest
*req
)
234 // We'll wait for the first byte, in case a "timeout event" occurs it returns // immediately
235 if (!WaitFor(wxSocketBase::REQ_READ
, req
->timeout
)) {
236 m_internal
->EndRequest(req
);
240 m_internal
->AcquireFD();
241 ret
= recv(m_fd
, req
->buffer
, req
->size
,
242 (req
->type
== wxSocketBase::REQ_PEEK
) ? MSG_PEEK
: 0);
243 m_internal
->ReleaseFD();
245 // An error occured, we exit.
248 m_internal
->EndRequest(req
);
253 // If the buffer isn't full (and we want it to be full), we don't unqueue it.
254 if ((len
< req
->size
) && (m_socket
->GetFlags() & wxSocketBase::WAITALL
)) {
256 req
->io_nbytes
+= len
;
260 m_internal
->EndRequest(req
);
264 req
->io_nbytes
+= len
;
265 m_internal
->EndRequest(req
);
268 void SocketRequester::ProcessWriteEvent(SockRequest
*req
)
273 if (!WaitFor(wxSocketBase::REQ_WRITE
, req
->timeout
)) {
274 m_internal
->EndRequest(req
);
278 m_internal
->AcquireFD();
279 ret
= send(m_fd
, req
->buffer
, req
->size
, 0);
280 m_internal
->ReleaseFD();
283 m_internal
->EndRequest(req
);
287 if ((len
< req
->size
) && ((m_socket
->GetFlags() & wxSocketBase::WAITALL
) != 0)) {
289 req
->io_nbytes
+= len
;
293 req
->io_nbytes
+= len
;
294 m_internal
->EndRequest(req
);
297 void SocketRequester::ProcessWaitEvent(SockRequest
*req
)
299 if (WaitFor(req
->type
, req
->timeout
))
300 req
->io_nbytes
= 1; // We put 1 in the counter to tell the requester
301 // there is no timeout.
305 m_internal
->EndRequest(req
);
308 void *SocketRequester::Entry()
312 m_internal
->m_request_locker
.Lock();
314 // Wait for a new request or a destroy message.
315 req
= m_internal
->WaitForReq();
316 m_internal
->m_end_requester
.Lock();
318 m_internal
->m_invalid_requester
= TRUE
;
319 m_internal
->m_end_requester
.Unlock();
320 m_internal
->m_request_locker
.Unlock();
323 m_internal
->m_end_requester
.Unlock();
325 if ((req
->type
& wxSocketBase::REQ_WAIT
) != 0) {
326 ProcessWaitEvent(req
);
331 case wxSocketBase::REQ_READ
:
332 case wxSocketBase::REQ_PEEK
:
333 ProcessReadEvent(req
);
335 case wxSocketBase::REQ_WRITE
:
336 ProcessWriteEvent(req
);
344 // --------------------------------------------------------------
345 // --------- wxSocketInternal -----------------------------------
346 // --------------------------------------------------------------
348 wxSocketInternal::wxSocketInternal(wxSocketBase
*socket
)
351 m_thread_requester
= NULL
;
352 m_thread_waiter
= NULL
;
353 m_invalid_requester
= TRUE
;
356 wxSocketInternal::~wxSocketInternal()
359 wxASSERT(m_thread_requester
== NULL
);
361 wxASSERT(m_thread_waiter
== NULL
);
364 // ----------------------------------------------------------------------
365 // WaitForReq: it is called by SocketRequester and should return the next
366 // socket request if available
367 // ----------------------------------------------------------------------
368 SockRequest
*wxSocketInternal::WaitForReq()
374 node
= m_requests
.First();
376 m_socket_cond
.Wait(m_request_locker
, 10, 0);
378 // Second try, if it is unsuccessul we give up.
379 node
= m_requests
.First();
384 return (SockRequest
*)node
->Data();
390 // ----------------------------------------------------------------------
391 // EndRequest: Should be called to finalize a request
392 // ----------------------------------------------------------------------
393 void wxSocketInternal::EndRequest(SockRequest
*req
)
399 node
= m_requests
.Member((wxObject
*)req
);
404 void wxSocketInternal::AcquireData()
407 m_socket_locker
.Lock();
411 void wxSocketInternal::ReleaseData()
414 m_socket_locker
.Unlock();
418 void wxSocketInternal::AcquireFD()
425 void wxSocketInternal::ReleaseFD()
428 m_fd_locker
.Unlock();
432 void wxSocketInternal::ResumeRequester()
437 wxASSERT(m_invalid_requester
);
439 m_end_requester
.Lock();
441 if (m_thread_requester
!= NULL
) {
442 m_thread_requester
->Delete(); // We must join it.
443 delete m_thread_requester
;
446 m_invalid_requester
= FALSE
;
448 m_end_requester
.Unlock();
450 m_thread_requester
= new SocketRequester(m_socket
, this);
452 err
= m_thread_requester
->Create();
453 wxASSERT(err
== wxTHREAD_NO_ERROR
);
455 err
= m_thread_requester
->Run();
456 wxASSERT(err
== wxTHREAD_NO_ERROR
);
458 if (!m_invalid_requester
)
460 m_thread_requester
= new SocketRequester(m_socket
, this);
461 m_invalid_requester
= FALSE
;
465 void wxSocketInternal::StopRequester()
468 m_end_requester
.Lock();
469 if (m_invalid_requester
) {
470 m_end_requester
.Unlock();
471 if (m_thread_requester
) {
472 m_thread_requester
->Delete();
473 delete m_thread_requester
;
474 m_thread_requester
= NULL
;
476 m_invalid_requester
= TRUE
;
479 m_end_requester
.Unlock();
481 wxASSERT(m_thread_requester
!= NULL
);
483 m_request_locker
.Lock();
485 // Send a signal to the requester.
486 m_socket_cond
.Signal();
488 m_request_locker
.Unlock();
490 // Finish the destruction of the requester.
491 m_thread_requester
->Delete();
493 delete m_thread_requester
;
494 m_thread_requester
= NULL
;
495 m_invalid_requester
= TRUE
;
497 delete m_thread_requester
;
498 m_thread_requester
= NULL
;
499 m_invalid_requester
= TRUE
;
503 void wxSocketInternal::ResumeWaiter()
508 if (m_thread_waiter
!= NULL
)
511 m_thread_waiter
= new SocketWaiter(m_socket
, this);
513 m_thread_waiter
->SetPriority(WXTHREAD_MIN_PRIORITY
);
515 err
= m_thread_waiter
->Create();
516 wxASSERT(err
== wxTHREAD_NO_ERROR
);
518 err
= m_thread_waiter
->Run();
519 wxASSERT(err
== wxTHREAD_NO_ERROR
);
523 void wxSocketInternal::StopWaiter()
526 if (m_thread_waiter
== NULL
)
529 m_thread_waiter
->Delete();
531 delete m_thread_waiter
;
532 m_thread_waiter
= NULL
;
536 // ----------------------------------------------------------------------
538 // ----------------------------------------------------------------------
539 void wxSocketInternal::QueueRequest(SockRequest
*request
, bool async
)
541 if (m_invalid_requester
)
547 m_request_locker
.Lock();
548 request
->done
= FALSE
;
549 m_requests
.Append((wxObject
*)request
);
550 m_socket_cond
.Signal();
551 m_request_locker
.Unlock();
556 if (wxThread::IsMain())
557 while (!request
->done
) {
561 while (!request
->done
) {
566 m_request_locker
.Lock();
569 if ((request
->type
& wxSocketBase::REQ_WAIT
) != 0) {
570 m_thread_requester
->ProcessWaitEvent(request
);
573 request
->done
= FALSE
;
575 switch (request
->type
) {
576 case wxSocketBase::REQ_PEEK
:
577 case wxSocketBase::REQ_READ
:
578 m_thread_requester
->ProcessReadEvent(request
);
580 case wxSocketBase::REQ_WRITE
:
581 m_thread_requester
->ProcessWriteEvent(request
);
585 request
->done
= TRUE
;
587 m_request_locker
.Unlock();
592 void wxSocketInternal::WaitForEnd(SockRequest
*request
)