]>
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"
30 #include "wx/sckint.h"
33 // IRIX requires bstring.h be included to use select()
44 // -----------------------
45 // System specific headers
46 // -----------------------
49 // in order to avoid problems with our c library and double definitions
50 #define close closesocket
51 #define ioctl ioctlsocket
53 #include <wx/mac/macsock.h>
56 #if defined(__WINDOWS__)
65 #include <sys/socket.h>
67 #include <sys/ioctl.h>
73 #include <sys/filio.h>
86 #define READ_MASK wxSocketBase::REQ_READ | wxSocketBase::REQ_ACCEPT | wxSocketBase::REQ_LOST
87 #define WRITE_MASK wxSocketBase::REQ_WRITE | wxSocketBase::REQ_CONNECT
89 // --------------------------------------------------------------
90 // --------- SocketWaiter ---------------------------------------
91 // --------------------------------------------------------------
94 SocketWaiter::SocketWaiter(wxSocketBase
*socket
,
95 wxSocketInternal
*internal
)
97 m_socket(socket
), m_internal(internal
), m_fd(internal
->GetFD())
101 SocketWaiter::~SocketWaiter()
105 void SocketWaiter::ProcessReadEvent()
110 m_internal
->AcquireFD();
111 ret
= recv(m_fd
, &c
, 1, MSG_PEEK
);
112 m_internal
->ReleaseFD();
114 // We are a server => emit a EVT_ACCEPT event.
115 if (ret
== -1 && m_socket
->GetType() == wxSocketBase::SOCK_SERVER
) {
116 m_socket
->OnRequest(wxSocketBase::EVT_ACCEPT
);
120 // Else, no error => there is something to be read else
121 // we've lost the connection.
123 m_socket
->OnRequest(wxSocketBase::EVT_READ
);
125 m_socket
->OnRequest(wxSocketBase::EVT_LOST
);
126 m_internal
->ReleaseData(); // In that case, we mustn't forget to unlock the mutex.
131 void SocketWaiter::ProcessWriteEvent()
133 if (m_socket
->IsConnected())
134 m_socket
->OnRequest(wxSocketBase::EVT_CONNECT
);
136 m_socket
->OnRequest(wxSocketBase::EVT_WRITE
);
139 void *SocketWaiter::Entry()
142 fd_set sockrd_set
, sockwr_set
;
151 FD_ZERO(&sockrd_set
);
152 FD_ZERO(&sockwr_set
);
154 m_internal
->AcquireData();
156 if ((m_socket
->NeededReq() & READ_MASK
) != 0)
157 FD_SET(m_fd
, &sockrd_set
);
158 if ((m_socket
->NeededReq() & WRITE_MASK
) != 0)
159 FD_SET(m_fd
, &sockwr_set
);
161 m_internal
->AcquireFD();
162 ret
= select(m_fd
+1, &sockrd_set
, &sockwr_set
, NULL
, &tv
);
163 m_internal
->ReleaseFD();
165 if (FD_ISSET(m_fd
, &sockrd_set
))
168 if (FD_ISSET(m_fd
, &sockwr_set
))
171 m_internal
->ReleaseData();
179 // We wait for 100 ms to prevent the CPU from burning.
182 // Check whether we should exit.
189 // --------------------------------------------------------------
190 // --------- SocketRequester ------------------------------------
191 // --------------------------------------------------------------
193 SocketRequester::SocketRequester(wxSocketBase
*socket
,
194 wxSocketInternal
*internal
)
199 m_socket(socket
), m_internal(internal
), m_fd(internal
->GetFD())
203 SocketRequester::~SocketRequester()
207 bool SocketRequester::WaitFor(wxSocketBase::wxRequestNotify req
, int millisec
)
211 fd_set sockrd_set
, sockwr_set
;
214 tv
.tv_sec
= millisec
/ 1000;
215 tv
.tv_usec
= (millisec
% 1000) * 1000;
217 FD_ZERO(&sockrd_set
);
218 FD_ZERO(&sockwr_set
);
219 if ((req
& READ_MASK
) != 0)
220 FD_SET(m_fd
, &sockrd_set
);
221 if ((req
& WRITE_MASK
) != 0)
222 FD_SET(m_fd
, &sockwr_set
);
224 m_internal
->AcquireFD();
225 ret
= select(m_fd
+1, &sockrd_set
, &sockwr_set
, NULL
, &tv
);
226 m_internal
->ReleaseFD();
231 void SocketRequester::ProcessReadEvent(SockRequest
*req
)
236 // We'll wait for the first byte, in case a "timeout event" occurs it returns // immediately
237 if (!WaitFor(wxSocketBase::REQ_READ
, req
->timeout
)) {
238 m_internal
->EndRequest(req
);
242 m_internal
->AcquireFD();
243 ret
= recv(m_fd
, req
->buffer
, req
->size
,
244 (req
->type
== wxSocketBase::REQ_PEEK
) ? MSG_PEEK
: 0);
245 m_internal
->ReleaseFD();
247 // An error occured, we exit.
250 m_internal
->EndRequest(req
);
255 // If the buffer isn't full (and we want it to be full), we don't unqueue it.
256 if ((len
< req
->size
) && (m_socket
->GetFlags() & wxSocketBase::WAITALL
)) {
258 req
->io_nbytes
+= len
;
262 m_internal
->EndRequest(req
);
266 req
->io_nbytes
+= len
;
267 m_internal
->EndRequest(req
);
270 void SocketRequester::ProcessWriteEvent(SockRequest
*req
)
275 if (!WaitFor(wxSocketBase::REQ_WRITE
, req
->timeout
)) {
276 m_internal
->EndRequest(req
);
280 m_internal
->AcquireFD();
281 ret
= send(m_fd
, req
->buffer
, req
->size
, 0);
282 m_internal
->ReleaseFD();
285 m_internal
->EndRequest(req
);
289 if ((len
< req
->size
) && ((m_socket
->GetFlags() & wxSocketBase::WAITALL
) != 0)) {
291 req
->io_nbytes
+= len
;
295 req
->io_nbytes
+= len
;
296 m_internal
->EndRequest(req
);
299 void SocketRequester::ProcessWaitEvent(SockRequest
*req
)
301 if (WaitFor(req
->type
, req
->timeout
))
302 req
->io_nbytes
= 1; // We put 1 in the counter to tell the requester
303 // there is no timeout.
307 m_internal
->EndRequest(req
);
310 void *SocketRequester::Entry()
314 m_internal
->m_request_locker
.Lock();
316 // Wait for a new request or a destroy message.
317 req
= m_internal
->WaitForReq();
318 m_internal
->m_end_requester
.Lock();
320 m_internal
->m_invalid_requester
= TRUE
;
321 m_internal
->m_end_requester
.Unlock();
322 m_internal
->m_request_locker
.Unlock();
325 m_internal
->m_end_requester
.Unlock();
327 if ((req
->type
& wxSocketBase::REQ_WAIT
) != 0) {
328 ProcessWaitEvent(req
);
333 case wxSocketBase::REQ_READ
:
334 case wxSocketBase::REQ_PEEK
:
335 ProcessReadEvent(req
);
337 case wxSocketBase::REQ_WRITE
:
338 ProcessWriteEvent(req
);
346 // --------------------------------------------------------------
347 // --------- wxSocketInternal -----------------------------------
348 // --------------------------------------------------------------
350 wxSocketInternal::wxSocketInternal(wxSocketBase
*socket
)
353 m_thread_requester
= NULL
;
354 m_thread_waiter
= NULL
;
355 m_invalid_requester
= TRUE
;
358 wxSocketInternal::~wxSocketInternal()
361 wxASSERT(m_thread_requester
== NULL
);
363 wxASSERT(m_thread_waiter
== NULL
);
366 // ----------------------------------------------------------------------
367 // WaitForReq: it is called by SocketRequester and should return the next
368 // socket request if available
369 // ----------------------------------------------------------------------
370 SockRequest
*wxSocketInternal::WaitForReq()
376 node
= m_requests
.First();
378 m_socket_cond
.Wait(m_request_locker
, 10, 0);
380 // Second try, if it is unsuccessul we give up.
381 node
= m_requests
.First();
386 return (SockRequest
*)node
->Data();
392 // ----------------------------------------------------------------------
393 // EndRequest: Should be called to finalize a request
394 // ----------------------------------------------------------------------
395 void wxSocketInternal::EndRequest(SockRequest
*req
)
401 node
= m_requests
.Member((wxObject
*)req
);
406 void wxSocketInternal::AcquireData()
409 m_socket_locker
.Lock();
413 void wxSocketInternal::ReleaseData()
416 m_socket_locker
.Unlock();
420 void wxSocketInternal::AcquireFD()
427 void wxSocketInternal::ReleaseFD()
430 m_fd_locker
.Unlock();
434 void wxSocketInternal::ResumeRequester()
439 wxASSERT(m_invalid_requester
);
441 m_end_requester
.Lock();
443 if (m_thread_requester
!= NULL
) {
444 m_thread_requester
->Delete(); // We must join it.
445 delete m_thread_requester
;
448 m_invalid_requester
= FALSE
;
450 m_end_requester
.Unlock();
452 m_thread_requester
= new SocketRequester(m_socket
, this);
454 err
= m_thread_requester
->Create();
455 wxASSERT(err
== wxTHREAD_NO_ERROR
);
457 err
= m_thread_requester
->Run();
458 wxASSERT(err
== wxTHREAD_NO_ERROR
);
460 if (!m_invalid_requester
)
462 m_thread_requester
= new SocketRequester(m_socket
, this);
463 m_invalid_requester
= FALSE
;
467 void wxSocketInternal::StopRequester()
470 m_end_requester
.Lock();
471 if (m_invalid_requester
) {
472 m_end_requester
.Unlock();
473 if (m_thread_requester
) {
474 m_thread_requester
->Delete();
475 delete m_thread_requester
;
476 m_thread_requester
= NULL
;
478 m_invalid_requester
= TRUE
;
481 m_end_requester
.Unlock();
483 wxASSERT(m_thread_requester
!= NULL
);
485 m_request_locker
.Lock();
487 // Send a signal to the requester.
488 m_socket_cond
.Signal();
490 m_request_locker
.Unlock();
492 // Finish the destruction of the requester.
493 m_thread_requester
->Delete();
495 delete m_thread_requester
;
496 m_thread_requester
= NULL
;
497 m_invalid_requester
= TRUE
;
499 delete m_thread_requester
;
500 m_thread_requester
= NULL
;
501 m_invalid_requester
= TRUE
;
505 void wxSocketInternal::ResumeWaiter()
510 if (m_thread_waiter
!= NULL
)
513 m_thread_waiter
= new SocketWaiter(m_socket
, this);
515 m_thread_waiter
->SetPriority(WXTHREAD_MIN_PRIORITY
);
517 err
= m_thread_waiter
->Create();
518 wxASSERT(err
== wxTHREAD_NO_ERROR
);
520 err
= m_thread_waiter
->Run();
521 wxASSERT(err
== wxTHREAD_NO_ERROR
);
525 void wxSocketInternal::StopWaiter()
528 if (m_thread_waiter
== NULL
)
531 m_thread_waiter
->Delete();
533 delete m_thread_waiter
;
534 m_thread_waiter
= NULL
;
538 // ----------------------------------------------------------------------
540 // ----------------------------------------------------------------------
541 void wxSocketInternal::QueueRequest(SockRequest
*request
, bool async
)
543 if (m_invalid_requester
)
549 m_request_locker
.Lock();
550 request
->done
= FALSE
;
551 m_requests
.Append((wxObject
*)request
);
552 m_socket_cond
.Signal();
553 m_request_locker
.Unlock();
558 if (wxThread::IsMain())
559 while (!request
->done
) {
563 while (!request
->done
) {
568 m_request_locker
.Lock();
571 if ((request
->type
& wxSocketBase::REQ_WAIT
) != 0) {
572 m_thread_requester
->ProcessWaitEvent(request
);
575 request
->done
= FALSE
;
577 switch (request
->type
) {
578 case wxSocketBase::REQ_PEEK
:
579 case wxSocketBase::REQ_READ
:
580 m_thread_requester
->ProcessReadEvent(request
);
582 case wxSocketBase::REQ_WRITE
:
583 m_thread_requester
->ProcessWriteEvent(request
);
587 request
->done
= TRUE
;
589 m_request_locker
.Unlock();
594 void wxSocketInternal::WaitForEnd(SockRequest
*request
)