]>
git.saurik.com Git - wxWidgets.git/blob - src/common/sckint.cpp
1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: Socket handler classes
4 // Authors: Guilhem Lavaux (completely rewritten from a basic API of Andrew
5 // Davidson(1995) in wxWeb)
8 // Copyright: (C) 1999, 1998, 1997, Guilhem Lavaux
10 // License: see wxWindows license
11 ///////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "sckint.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
25 #define WXSOCK_INTERNAL
26 #include <wx/object.h>
28 #include <wx/socket.h>
29 #include <wx/thread.h>
30 #include <wx/sckint.h>
38 // -----------------------
39 // System specific headers
40 // -----------------------
43 // in order to avoid problems with our c library and double definitions
44 #define close closesocket
45 #define ioctl ioctlsocket
47 #include <wx/mac/macsock.h>
50 #if defined(__WINDOWS__)
59 #include <sys/socket.h>
61 #include <sys/ioctl.h>
67 #include <sys/filio.h>
80 #define READ_MASK wxSocketBase::REQ_READ | wxSocketBase::REQ_ACCEPT | wxSocketBase::REQ_LOST
81 #define WRITE_MASK wxSocketBase::REQ_WRITE | wxSocketBase::REQ_CONNECT
83 // --------------------------------------------------------------
84 // --------- SocketWaiter ---------------------------------------
85 // --------------------------------------------------------------
87 SocketWaiter::SocketWaiter(wxSocketBase
*socket
,
88 wxSocketInternal
*internal
)
89 : m_socket(socket
), m_internal(internal
), m_fd(internal
->GetFD())
93 SocketWaiter::~SocketWaiter()
97 void SocketWaiter::ProcessReadEvent()
102 ret
= recv(m_fd
, &c
, 1, MSG_PEEK
);
104 // We are a server => emit a EVT_ACCEPT event.
105 if (ret
== -1 && m_socket
->GetType() == wxSocketBase::SOCK_SERVER
) {
106 m_socket
->OnRequest(wxSocketBase::EVT_ACCEPT
);
110 // Else, no error => there is something to be read else
111 // we've lost the connection.
113 m_socket
->OnRequest(wxSocketBase::EVT_READ
);
115 m_socket
->OnRequest(wxSocketBase::EVT_LOST
);
120 void SocketWaiter::ProcessWriteEvent()
122 if (m_socket
->IsConnected())
123 m_socket
->OnRequest(wxSocketBase::EVT_CONNECT
);
125 m_socket
->OnRequest(wxSocketBase::EVT_WRITE
);
128 void *SocketWaiter::Entry()
131 fd_set sockrd_set
, sockwr_set
;
140 FD_ZERO(&sockrd_set
);
141 FD_ZERO(&sockwr_set
);
143 if ((m_socket
->NeededReq() & READ_MASK
) != 0)
144 FD_SET(m_fd
, &sockrd_set
);
145 if ((m_socket
->NeededReq() & WRITE_MASK
) != 0)
146 FD_SET(m_fd
, &sockwr_set
);
148 m_internal
->AcquireFD();
149 ret
= select(FD_SETSIZE
, &sockrd_set
, &sockwr_set
, NULL
, &tv
);
150 m_internal
->ReleaseFD();
152 if (FD_ISSET(m_fd
, &sockrd_set
))
155 if (FD_ISSET(m_fd
, &sockwr_set
))
164 // If nothing happened, we wait for 100 ms.
170 // If nothing happened, we wait for 100 ms.
176 // Check whether we should exit.
183 // --------------------------------------------------------------
184 // --------- SocketRequester ------------------------------------
185 // --------------------------------------------------------------
187 SocketRequester::SocketRequester(wxSocketBase
*socket
,
188 wxSocketInternal
*internal
)
189 : m_socket(socket
), m_internal(internal
), m_fd(internal
->GetFD())
193 SocketRequester::~SocketRequester()
197 bool SocketRequester::WaitFor(wxSocketBase::wxRequestNotify req
, int millisec
)
201 fd_set sockrd_set
, sockwr_set
;
204 tv
.tv_sec
= millisec
/ 1000;
205 tv
.tv_usec
= (millisec
% 1000) * 1000;
207 if ((req
& READ_MASK
) != 0)
208 FD_ZERO(&sockrd_set
);
209 FD_ZERO(&sockwr_set
);
211 FD_SET(m_fd
, &sockrd_set
);
212 FD_SET(m_fd
, &sockwr_set
);
214 m_internal
->AcquireFD();
215 ret
= select(FD_SETSIZE
, &sockrd_set
, &sockwr_set
, NULL
, &tv
);
216 m_internal
->ReleaseFD();
221 void SocketRequester::ProcessReadEvent(SockRequest
*req
)
226 // We'll wait for the first byte, in case a "timeout event" occurs it returns // immediately
227 if (!WaitFor(wxSocketBase::REQ_READ
, req
->timeout
)) {
228 m_internal
->EndRequest(req
);
232 m_internal
->AcquireFD();
233 ret
= recv(m_fd
, req
->buffer
, req
->size
,
234 (req
->type
== wxSocketBase::REQ_PEEK
) ? MSG_PEEK
: 0);
235 m_internal
->ReleaseFD();
237 // An error occured, we exit.
240 m_internal
->EndRequest(req
);
245 // If the buffer isn't full (and we want it to be full), we don't unqueue it.
246 if ((len
< req
->size
) && (m_socket
->GetFlags() & wxSocketBase::WAITALL
)) {
248 req
->io_nbytes
+= len
;
253 req
->io_nbytes
+= len
;
254 m_internal
->EndRequest(req
);
257 void SocketRequester::ProcessWriteEvent(SockRequest
*req
)
262 m_internal
->AcquireFD();
263 ret
= send(m_fd
, req
->buffer
, req
->size
, 0);
264 m_internal
->ReleaseFD();
267 m_internal
->EndRequest(req
);
271 if ((len
< req
->size
) && ((m_socket
->GetFlags() & wxSocketBase::WAITALL
) != 0)) {
273 req
->io_nbytes
+= len
;
277 req
->io_nbytes
+= len
;
278 m_internal
->EndRequest(req
);
281 void SocketRequester::ProcessWaitEvent(SockRequest
*req
)
283 if (WaitFor(req
->type
, req
->timeout
))
284 req
->io_nbytes
= 1; // We put 1 in the counter to tell the requester
285 // there is no timeout.
289 m_internal
->EndRequest(req
);
292 void *SocketRequester::Entry()
297 // Wait for a new request or a destroy message.
298 req
= m_internal
->WaitForReq();
299 if (TestDestroy() || req
== NULL
)
302 if ((req
->type
& wxSocketBase::REQ_WAIT
) != 0) {
303 ProcessWaitEvent(req
);
308 case wxSocketBase::REQ_READ
:
309 case wxSocketBase::REQ_PEEK
:
310 ProcessReadEvent(req
);
312 case wxSocketBase::REQ_WRITE
:
313 ProcessWriteEvent(req
);
320 // --------------------------------------------------------------
321 // --------- wxSocketInternal -----------------------------------
322 // --------------------------------------------------------------
324 wxSocketInternal::wxSocketInternal(wxSocketBase
*socket
)
327 m_thread_waiter
= new SocketWaiter(socket
, this);
328 m_thread_requester
= new SocketRequester(socket
, this);
329 m_request_locker
.Lock();
332 wxSocketInternal::~wxSocketInternal()
334 // wxASSERT(!m_finalized); there is no m_finalized anywhere, RR
335 m_request_locker
.Unlock();
336 delete m_thread_waiter
;
337 delete m_thread_requester
;
340 // ----------------------------------------------------------------------
341 // WaitForReq: it is called by SocketRequester and should return the next
342 // socket request if available
343 // ----------------------------------------------------------------------
344 SockRequest
*wxSocketInternal::WaitForReq()
348 node
= m_requests
.First();
350 m_socket_cond
.Wait(m_request_locker
);
352 node
= m_requests
.First();
357 return (SockRequest
*)node
->Data();
360 // ----------------------------------------------------------------------
361 // EndRequest: Should be called to finalize a request
362 // ----------------------------------------------------------------------
363 void wxSocketInternal::EndRequest(SockRequest
*req
)
369 node
= m_requests
.Member((wxObject
*)req
);
374 void wxSocketInternal::AcquireFD()
379 void wxSocketInternal::ReleaseFD()
381 m_fd_locker
.Unlock();
384 // ----------------------------------------------------------------------
385 // InitializeSocket: called by wxSocketBase to initialize the daemons with
386 // a new file descriptor and to create them
387 // ----------------------------------------------------------------------
388 void wxSocketInternal::InitializeSocket()
390 // wxASSERT( ((m_thread_waiter->IsAlive() && !m_thread_waiter->IsPaused()) ||
391 // (m_thread_requester->IsAlive() && !m_thread_requester->IsPaused())));
393 m_thread_waiter
->m_fd
= m_socket
->m_fd
;
394 m_thread_requester
->m_fd
= m_socket
->m_fd
;
396 if (m_thread_waiter
->IsPaused())
400 if (m_thread_waiter
->Create() != wxTHREAD_NO_ERROR
) {
401 // Something should be done here.
405 if (m_thread_requester
->Create() != wxTHREAD_NO_ERROR
) {
406 // Something should be done here.
410 m_thread_waiter
->Run();
411 m_thread_requester
->Run();
416 // ----------------------------------------------------------------------
417 // InitializeSocket: called by wxSocketBase to destroy daemons
418 // ----------------------------------------------------------------------
419 void wxSocketInternal::FinalizeSocket()
421 wxASSERT( (!m_thread_waiter
->IsAlive() && !m_thread_requester
->IsAlive()) );
425 m_thread_waiter
->Delete();
426 m_socket_locker
.Lock();
427 if (m_requests
.Number() == 0)
428 m_socket_cond
.Signal();
429 m_socket_locker
.Unlock();
431 m_thread_requester
->Delete();
434 void wxSocketInternal::PauseSocket()
436 if (m_thread_waiter
!= NULL
&& !m_thread_waiter
->IsPaused())
437 m_thread_waiter
->Pause();
440 void wxSocketInternal::ResumeSocket()
442 if (m_thread_waiter
!= NULL
&& m_thread_waiter
->IsPaused())
443 m_thread_waiter
->Resume();
446 void wxSocketInternal::EnableWaiter()
448 if (m_thread_waiter
!= NULL
&& m_thread_waiter
->IsPaused())
449 m_thread_waiter
->Resume();
452 void wxSocketInternal::DisableWaiter()
454 if (m_thread_waiter
!= NULL
&& !m_thread_waiter
->IsPaused())
455 m_thread_waiter
->Pause();
458 // ----------------------------------------------------------------------
460 // ----------------------------------------------------------------------
461 void wxSocketInternal::QueueRequest(SockRequest
*request
, bool async
)
464 m_request_locker
.Lock();
465 request
->done
= FALSE
;
466 m_requests
.Append((wxObject
*)request
);
467 m_request_locker
.Unlock();
470 m_socket_cond
.Signal();
473 if (wxThread::IsMain())
474 while (!request
->done
) {
478 while (!request
->done
) {
484 m_request_locker
.Lock();
486 if ((request
->type
& wxSocketBase::REQ_WAIT
) != 0) {
487 m_thread_requester
->ProcessWaitEvent(request
);
490 request
->done
= FALSE
;
492 switch (request
->type
) {
493 case wxSocketBase::REQ_PEEK
:
494 case wxSocketBase::REQ_READ
:
495 m_thread_requester
->ProcessReadEvent(request
);
497 case wxSocketBase::REQ_WRITE
:
498 m_thread_requester
->ProcessWriteEvent(request
);
502 request
->done
= TRUE
;
503 m_request_locker
.Unlock();
507 void wxSocketInternal::WaitForEnd(SockRequest
*request
)