]> git.saurik.com Git - wxWidgets.git/blame - src/common/sckint.cpp
more 2.0b9 updates
[wxWidgets.git] / src / common / sckint.cpp
CommitLineData
a737331d
GL
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: April 1999
8// Copyright: (C) 1999, 1998, 1997, Guilhem Lavaux
9// RCS_ID: $Id$
10// License: see wxWindows license
11///////////////////////////////////////////////////////////////////////////////
12#ifdef __GNUG__
13#pragma implementation "sckint.h"
14#endif
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
20#pragma hdrstop
21#endif
22
23#if wxUSE_SOCKETS
24
25#define WXSOCK_INTERNAL
26#include <wx/object.h>
27#include <wx/list.h>
28#include <wx/socket.h>
29#include <wx/thread.h>
30#include <wx/sckint.h>
31
32#ifndef __WXSTUBS__
33
34#include <stdlib.h>
35#include <string.h>
36#include <ctype.h>
37
38// -----------------------
39// System specific headers
40// -----------------------
41
42#ifdef __WXMAC__
43// in order to avoid problems with our c library and double definitions
44#define close closesocket
45#define ioctl ioctlsocket
46
47#include <wx/mac/macsock.h>
48#endif
49
50#if defined(__WINDOWS__)
51#include <winsock.h>
52#endif // __WINDOWS__
53
54#if defined(__UNIX__)
55
56#ifdef VMS
57#include <socket.h>
58#else
59#include <sys/socket.h>
60#endif
61#include <sys/ioctl.h>
62
63#include <sys/time.h>
64#include <unistd.h>
65
66#ifdef sun
67#include <sys/filio.h>
68#endif
69
70#endif // __UNIX__
71
72#include <signal.h>
73#include <errno.h>
74
75#ifdef __VISUALC__
76#include <io.h>
77#endif
78
79// Constants
80#define READ_MASK wxSocketBase::REQ_READ | wxSocketBase::REQ_ACCEPT | wxSocketBase::REQ_LOST
81#define WRITE_MASK wxSocketBase::REQ_WRITE | wxSocketBase::REQ_CONNECT
82
83// --------------------------------------------------------------
84// --------- SocketWaiter ---------------------------------------
85// --------------------------------------------------------------
86
87SocketWaiter::SocketWaiter(wxSocketBase *socket,
88 wxSocketInternal *internal)
89 : m_socket(socket), m_internal(internal), m_fd(internal->GetFD())
90{
91}
92
93SocketWaiter::~SocketWaiter()
94{
95}
96
97void SocketWaiter::ProcessReadEvent()
98{
99 int ret;
100 char c;
101
102 ret = recv(m_fd, &c, 1, MSG_PEEK);
103
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);
107 return;
108 }
109
110 // Else, no error => there is something to be read else
111 // we've lost the connection.
112 if (ret > 0)
113 m_socket->OnRequest(wxSocketBase::EVT_READ);
114 else {
115 m_socket->OnRequest(wxSocketBase::EVT_LOST);
116 Exit(NULL);
117 }
118}
119
120void SocketWaiter::ProcessWriteEvent()
121{
122 if (m_socket->IsConnected())
123 m_socket->OnRequest(wxSocketBase::EVT_CONNECT);
124 else
125 m_socket->OnRequest(wxSocketBase::EVT_WRITE);
126}
127
128void *SocketWaiter::Entry()
129{
130 struct timeval tv;
131 fd_set sockrd_set, sockwr_set;
132 wxSocketEvent event;
133 int ret;
134
135 while (1) {
136 // We won't wait.
137 tv.tv_sec = 0;
138 tv.tv_usec = 0;
139
140 FD_ZERO(&sockrd_set);
141 FD_ZERO(&sockwr_set);
142
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);
147
148 m_internal->AcquireFD();
149 ret = select(FD_SETSIZE, &sockrd_set, &sockwr_set, NULL, &tv);
150 m_internal->ReleaseFD();
151
152 if (FD_ISSET(m_fd, &sockrd_set))
153 ProcessReadEvent();
154
155 if (FD_ISSET(m_fd, &sockwr_set))
156 ProcessWriteEvent();
157
158 if (ret == 0)
159 // If nothing happened, we wait for 100 ms.
160 wxThread::Sleep(10);
161 else
162 wxThread::Yield();
163
164 // Check whether we should exit.
165 if (TestDestroy())
166 return NULL;
167 }
168 return NULL;
169}
170
171// --------------------------------------------------------------
172// --------- SocketRequester ------------------------------------
173// --------------------------------------------------------------
174
175SocketRequester::SocketRequester(wxSocketBase *socket,
176 wxSocketInternal *internal)
177 : m_socket(socket), m_internal(internal), m_fd(internal->GetFD())
178{
179}
180
181SocketRequester::~SocketRequester()
182{
183}
184
185bool SocketRequester::WaitFor(wxSocketBase::wxRequestNotify req, int millisec)
186{
187 int ret;
188 struct timeval tv;
189 fd_set sockrd_set, sockwr_set;
190
191 // We won't wait.
192 tv.tv_sec = millisec / 1000;
193 tv.tv_usec = (millisec % 1000) * 1000;
194
195 if ((req & READ_MASK) != 0)
196 FD_ZERO(&sockrd_set);
197 FD_ZERO(&sockwr_set);
198
199 FD_SET(m_fd, &sockrd_set);
200 FD_SET(m_fd, &sockwr_set);
201
202 m_internal->AcquireFD();
203 ret = select(FD_SETSIZE, &sockrd_set, &sockwr_set, NULL, &tv);
204 m_internal->ReleaseFD();
205
206 return (ret != 0);
207}
208
209void SocketRequester::ProcessReadEvent(SockRequest *req)
210{
211 int ret;
212 size_t len;
213
214 // We'll wait for the first byte, in case a "timeout event" occurs it returns // immediately
215 if (!WaitFor(wxSocketBase::REQ_READ, req->timeout)) {
216 m_internal->EndRequest(req);
217 return;
218 }
219
220 m_internal->AcquireFD();
221 ret = recv(m_fd, req->buffer, req->size,
222 (req->type == wxSocketBase::REQ_PEEK) ? MSG_PEEK : 0);
223 m_internal->ReleaseFD();
224
225 // An error occured, we exit.
226 if (ret < 0) {
227 req->error = errno;
228 m_internal->EndRequest(req);
229 return;
230 }
231 len = ret;
232
233 // If the buffer isn't full (and we want it to be full), we don't unqueue it.
234 if ((len < req->size) && (m_socket->GetFlags() & wxSocketBase::WAITALL)) {
235 req->size -= len;
236 req->io_nbytes += len;
237 req->buffer += len;
238 return;
239 }
240 // The End.
241 req->io_nbytes += len;
242 m_internal->EndRequest(req);
243}
244
245void SocketRequester::ProcessWriteEvent(SockRequest *req)
246{
247 int ret;
248 size_t len;
249
250 m_internal->AcquireFD();
251 ret = send(m_fd, req->buffer, req->size, 0);
252 m_internal->ReleaseFD();
253 if (ret < 0) {
254 req->error = errno;
255 m_internal->EndRequest(req);
256 return;
257 }
258 len = ret;
259 if ((len < req->size) && ((m_socket->GetFlags() & wxSocketBase::WAITALL) != 0)) {
260 req->size -= len;
261 req->io_nbytes += len;
262 req->buffer += len;
263 return;
264 }
265 req->io_nbytes += len;
266 m_internal->EndRequest(req);
267}
268
269void SocketRequester::ProcessWaitEvent(SockRequest *req)
270{
271 if (WaitFor(req->type, req->timeout))
272 req->io_nbytes = 1; // We put 1 in the counter to tell the requester
273 // there is no timeout.
274 else
275 req->io_nbytes = 0;
276
277 m_internal->EndRequest(req);
278}
279
280void *SocketRequester::Entry()
281{
282 SockRequest *req;
283
284 while (1) {
285 // Wait for a new request or a destroy message.
286 req = m_internal->WaitForReq();
287 if (TestDestroy() || req == NULL)
288 return NULL;
289
290 if ((req->type & wxSocketBase::REQ_WAIT) != 0) {
291 ProcessWaitEvent(req);
292 continue;
293 }
294
295 switch (req->type) {
296 case wxSocketBase::REQ_READ:
297 case wxSocketBase::REQ_PEEK:
298 ProcessReadEvent(req);
299 break;
300 case wxSocketBase::REQ_WRITE:
301 ProcessWriteEvent(req);
302 break;
303 }
304 }
305 return NULL;
306}
307
308// --------------------------------------------------------------
309// --------- wxSocketInternal -----------------------------------
310// --------------------------------------------------------------
311
312wxSocketInternal::wxSocketInternal(wxSocketBase *socket)
313{
314 m_socket = socket;
315 m_thread_waiter = new SocketWaiter(socket, this);
316 m_thread_requester = new SocketRequester(socket, this);
317 m_request_locker.Lock();
318}
319
320wxSocketInternal::~wxSocketInternal()
321{
fafd7fd9 322// wxASSERT(!m_finalized); there is no m_finalized anywhere, RR
a737331d
GL
323 m_request_locker.Unlock();
324 delete m_thread_waiter;
325 delete m_thread_requester;
326}
327
328// ----------------------------------------------------------------------
329// WaitForReq: it is called by SocketRequester and should return the next
330// socket request if available
331// ----------------------------------------------------------------------
332SockRequest *wxSocketInternal::WaitForReq()
333{
334 wxNode *node;
335
336 node = m_requests.First();
337 if (node == NULL) {
338 m_socket_cond.Wait(m_request_locker);
339
340 node = m_requests.First();
341 if (node == NULL)
342 return NULL;
343 }
344
345 return (SockRequest *)node->Data();
346}
347
348// ----------------------------------------------------------------------
349// EndRequest: Should be called to finalize a request
350// ----------------------------------------------------------------------
351void wxSocketInternal::EndRequest(SockRequest *req)
352{
353 wxNode *node = NULL;
354
355 req->done = TRUE;
356
357 node = m_requests.Member((wxObject *)req);
358 if (node != NULL)
359 delete node;
360}
361
362void wxSocketInternal::AcquireFD()
363{
364 m_fd_locker.Lock();
365}
366
367void wxSocketInternal::ReleaseFD()
368{
369 m_fd_locker.Unlock();
370}
371
372// ----------------------------------------------------------------------
373// InitializeSocket: called by wxSocketBase to initialize the daemons with
374// a new file descriptor and to create them
375// ----------------------------------------------------------------------
376void wxSocketInternal::InitializeSocket()
377{
288bf129
RR
378// wxASSERT( ((m_thread_waiter->IsAlive() && !m_thread_waiter->IsPaused()) ||
379// (m_thread_requester->IsAlive() && !m_thread_requester->IsPaused())));
a737331d
GL
380
381 m_thread_waiter->m_fd = m_socket->m_fd;
382 m_thread_requester->m_fd = m_socket->m_fd;
383
384 if (m_thread_waiter->IsPaused())
385 ResumeSocket();
386 else {
387
388 if (m_thread_waiter->Create() != wxTHREAD_NO_ERROR) {
389 // Something should be done here.
390 return;
391 }
392
393 if (m_thread_requester->Create() != wxTHREAD_NO_ERROR) {
394 // Something should be done here.
395 return;
396 }
397
398 m_thread_waiter->Run();
399 m_thread_requester->Run();
400 }
401}
402
403
404// ----------------------------------------------------------------------
405// InitializeSocket: called by wxSocketBase to destroy daemons
406// ----------------------------------------------------------------------
407void wxSocketInternal::FinalizeSocket()
408{
409 wxASSERT( (!m_thread_waiter->IsAlive() && !m_thread_requester->IsAlive()) );
410
411 ResumeSocket();
412
413 m_thread_waiter->Delete();
414 m_socket_locker.Lock();
415 if (m_requests.Number() == 0)
416 m_socket_cond.Signal();
417 m_socket_locker.Unlock();
418
419 m_thread_requester->Delete();
420}
421
422void wxSocketInternal::PauseSocket()
423{
424 if (m_thread_waiter != NULL && !m_thread_waiter->IsPaused())
425 m_thread_waiter->Pause();
426}
427
428void wxSocketInternal::ResumeSocket()
429{
430 if (m_thread_waiter != NULL && m_thread_waiter->IsPaused())
431 m_thread_waiter->Resume();
432}
433
434void wxSocketInternal::EnableWaiter()
435{
436 if (m_thread_waiter != NULL && m_thread_waiter->IsPaused())
437 m_thread_waiter->Resume();
438}
439
440void wxSocketInternal::DisableWaiter()
441{
442 if (m_thread_waiter != NULL && !m_thread_waiter->IsPaused())
443 m_thread_waiter->Pause();
444}
445
446// ----------------------------------------------------------------------
447// QueueRequest:
448// ----------------------------------------------------------------------
449void wxSocketInternal::QueueRequest(SockRequest *request, bool async)
450{
451 if (async) {
452 m_request_locker.Lock();
453 request->done = FALSE;
454 m_requests.Append((wxObject *)request);
455 m_request_locker.Unlock();
456
457 // Wake up
458 m_socket_cond.Signal();
459
460 if (request->wait) {
461 if (wxThread::IsMain())
462 while (!request->done) {
463 wxYield();
464 }
465 else
466 while (!request->done) {
467 wxThread::Yield();
468 }
469 }
470
471 } else {
472 m_request_locker.Lock();
473
474 if ((request->type & wxSocketBase::REQ_WAIT) != 0) {
475 m_thread_requester->ProcessWaitEvent(request);
476 } else {
477
478 request->done = FALSE;
479
480 switch (request->type) {
481 case wxSocketBase::REQ_PEEK:
482 case wxSocketBase::REQ_READ:
483 m_thread_requester->ProcessReadEvent(request);
484 break;
485 case wxSocketBase::REQ_WRITE:
486 m_thread_requester->ProcessWriteEvent(request);
487 break;
488 }
489 }
490 request->done = TRUE;
491 m_request_locker.Unlock();
492 }
493}
494
495void wxSocketInternal::WaitForEnd(SockRequest *request)
496{
497 // TODOTODO
498}
499
500#endif
501 // __WXSTUBS__
502
503#endif
504 // wxUSE_SOCKETS