]> git.saurik.com Git - wxWidgets.git/blob - src/common/sckint.cpp
* implemented VZ's idea about creating and destroying bg threads.
[wxWidgets.git] / src / common / sckint.cpp
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
87 SocketWaiter::SocketWaiter(wxSocketBase *socket,
88 wxSocketInternal *internal)
89 : m_socket(socket), m_internal(internal), m_fd(internal->GetFD())
90 {
91 }
92
93 SocketWaiter::~SocketWaiter()
94 {
95 }
96
97 void 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
120 void 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
128 void *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 wxUSE_THREADS
159 #ifdef Yield
160 #undef Yield
161 #endif
162 #endif
163
164 /*
165 if (ret == 0)
166 // If nothing happened, we wait for 100 ms.
167 wxUsleep(10);
168 */
169
170 // Check whether we should exit.
171 if (TestDestroy()) {
172 return NULL;
173 }
174 }
175 return NULL;
176 }
177
178 // --------------------------------------------------------------
179 // --------- SocketRequester ------------------------------------
180 // --------------------------------------------------------------
181
182 SocketRequester::SocketRequester(wxSocketBase *socket,
183 wxSocketInternal *internal)
184 : m_socket(socket), m_internal(internal), m_fd(internal->GetFD())
185 {
186 }
187
188 SocketRequester::~SocketRequester()
189 {
190 }
191
192 bool SocketRequester::WaitFor(wxSocketBase::wxRequestNotify req, int millisec)
193 {
194 int ret;
195 struct timeval tv;
196 fd_set sockrd_set, sockwr_set;
197
198 // We won't wait.
199 tv.tv_sec = millisec / 1000;
200 tv.tv_usec = (millisec % 1000) * 1000;
201
202 if ((req & READ_MASK) != 0)
203 FD_ZERO(&sockrd_set);
204 FD_ZERO(&sockwr_set);
205
206 FD_SET(m_fd, &sockrd_set);
207 FD_SET(m_fd, &sockwr_set);
208
209 m_internal->AcquireFD();
210 ret = select(FD_SETSIZE, &sockrd_set, &sockwr_set, NULL, &tv);
211 m_internal->ReleaseFD();
212
213 return (ret != 0);
214 }
215
216 void SocketRequester::ProcessReadEvent(SockRequest *req)
217 {
218 int ret;
219 size_t len;
220
221 // We'll wait for the first byte, in case a "timeout event" occurs it returns // immediately
222 if (!WaitFor(wxSocketBase::REQ_READ, req->timeout)) {
223 m_internal->EndRequest(req);
224 return;
225 }
226
227 m_internal->AcquireFD();
228 ret = recv(m_fd, req->buffer, req->size,
229 (req->type == wxSocketBase::REQ_PEEK) ? MSG_PEEK : 0);
230 m_internal->ReleaseFD();
231
232 // An error occured, we exit.
233 if (ret < 0) {
234 req->error = errno;
235 m_internal->EndRequest(req);
236 return;
237 }
238 len = ret;
239
240 // If the buffer isn't full (and we want it to be full), we don't unqueue it.
241 if ((len < req->size) && (m_socket->GetFlags() & wxSocketBase::WAITALL)) {
242 req->size -= len;
243 req->io_nbytes += len;
244 req->buffer += len;
245 return;
246 }
247 // The End.
248 req->io_nbytes += len;
249 m_internal->EndRequest(req);
250 }
251
252 void SocketRequester::ProcessWriteEvent(SockRequest *req)
253 {
254 int ret;
255 size_t len;
256
257 m_internal->AcquireFD();
258 ret = send(m_fd, req->buffer, req->size, 0);
259 m_internal->ReleaseFD();
260 if (ret < 0) {
261 req->error = errno;
262 m_internal->EndRequest(req);
263 return;
264 }
265 len = ret;
266 if ((len < req->size) && ((m_socket->GetFlags() & wxSocketBase::WAITALL) != 0)) {
267 req->size -= len;
268 req->io_nbytes += len;
269 req->buffer += len;
270 return;
271 }
272 req->io_nbytes += len;
273 m_internal->EndRequest(req);
274 }
275
276 void SocketRequester::ProcessWaitEvent(SockRequest *req)
277 {
278 if (WaitFor(req->type, req->timeout))
279 req->io_nbytes = 1; // We put 1 in the counter to tell the requester
280 // there is no timeout.
281 else
282 req->io_nbytes = 0;
283
284 m_internal->EndRequest(req);
285 }
286
287 void *SocketRequester::Entry()
288 {
289 SockRequest *req;
290
291 while (1) {
292 // Wait for a new request or a destroy message.
293 req = m_internal->WaitForReq();
294 if (TestDestroy() || req == NULL)
295 return NULL;
296
297 if ((req->type & wxSocketBase::REQ_WAIT) != 0) {
298 ProcessWaitEvent(req);
299 continue;
300 }
301
302 switch (req->type) {
303 case wxSocketBase::REQ_READ:
304 case wxSocketBase::REQ_PEEK:
305 ProcessReadEvent(req);
306 break;
307 case wxSocketBase::REQ_WRITE:
308 ProcessWriteEvent(req);
309 break;
310 }
311 }
312 return NULL;
313 }
314
315 // --------------------------------------------------------------
316 // --------- wxSocketInternal -----------------------------------
317 // --------------------------------------------------------------
318
319 wxSocketInternal::wxSocketInternal(wxSocketBase *socket)
320 {
321 m_socket = socket;
322 m_thread_requester = NULL;
323 m_thread_waiter = NULL;
324 m_request_locker.Lock();
325 }
326
327 wxSocketInternal::~wxSocketInternal()
328 {
329 wxASSERT(m_thread_requester == NULL);
330 wxASSERT(m_thread_waiter == NULL);
331 m_request_locker.Unlock();
332 }
333
334 // ----------------------------------------------------------------------
335 // WaitForReq: it is called by SocketRequester and should return the next
336 // socket request if available
337 // ----------------------------------------------------------------------
338 SockRequest *wxSocketInternal::WaitForReq()
339 {
340 wxNode *node;
341
342 node = m_requests.First();
343 if (node == NULL) {
344 m_socket_cond.Wait(m_request_locker);
345
346 node = m_requests.First();
347 if (node == NULL)
348 return NULL;
349 }
350
351 return (SockRequest *)node->Data();
352 }
353
354 // ----------------------------------------------------------------------
355 // EndRequest: Should be called to finalize a request
356 // ----------------------------------------------------------------------
357 void wxSocketInternal::EndRequest(SockRequest *req)
358 {
359 wxNode *node = NULL;
360
361 req->done = TRUE;
362
363 node = m_requests.Member((wxObject *)req);
364 if (node != NULL)
365 delete node;
366 }
367
368 void wxSocketInternal::AcquireFD()
369 {
370 m_fd_locker.Lock();
371 }
372
373 void wxSocketInternal::ReleaseFD()
374 {
375 m_fd_locker.Unlock();
376 }
377
378 void wxSocketInternal::ResumeRequester()
379 {
380 wxThreadError err;
381
382 wxASSERT(m_thread_requester == NULL);
383
384 m_thread_requester = new SocketRequester(m_socket, this);
385 m_thread_requester->m_fd = m_socket->m_fd;
386
387 err = m_thread_requester->Create();
388 wxASSERT(err == wxTHREAD_NO_ERROR);
389
390 err = m_thread_requester->Run();
391 wxASSERT(err == wxTHREAD_NO_ERROR);
392 }
393
394 void wxSocketInternal::StopRequester()
395 {
396 wxASSERT(m_thread_requester != NULL);
397
398 m_socket_locker.Lock();
399
400 // Send a signal to the requester.
401 if (m_requests.Number() == 0)
402 m_socket_cond.Signal();
403
404 m_socket_locker.Unlock();
405
406 // Finish the destruction of the requester.
407 m_thread_requester->Delete();
408
409 delete m_thread_requester;
410 m_thread_requester = NULL;
411 }
412
413 void wxSocketInternal::ResumeWaiter()
414 {
415 wxThreadError err;
416
417 if (m_thread_waiter != NULL)
418 return;
419
420 m_thread_waiter = new SocketWaiter(m_socket, this);
421 m_thread_waiter->m_fd = m_socket->m_fd;
422
423 err = m_thread_waiter->Create();
424 wxASSERT(err == wxTHREAD_NO_ERROR);
425
426 err = m_thread_waiter->Run();
427 wxASSERT(err == wxTHREAD_NO_ERROR);
428 }
429
430 void wxSocketInternal::StopWaiter()
431 {
432 /*
433 if (m_thread_waiter == NULL)
434 return;
435
436 m_thread_waiter->Delete();
437
438 delete m_thread_waiter;
439 m_thread_waiter = NULL;
440 */
441 }
442
443 // ----------------------------------------------------------------------
444 // QueueRequest:
445 // ----------------------------------------------------------------------
446 void wxSocketInternal::QueueRequest(SockRequest *request, bool async)
447 {
448 if (async) {
449 if (m_thread_requester == NULL)
450 ResumeRequester();
451
452 m_request_locker.Lock();
453 request->done = FALSE;
454 m_requests.Append((wxObject *)request);
455 m_socket_cond.Signal();
456 m_request_locker.Unlock();
457
458 // Wake up
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 } else {
471 m_request_locker.Lock();
472
473 if ((request->type & wxSocketBase::REQ_WAIT) != 0) {
474 m_thread_requester->ProcessWaitEvent(request);
475 } else {
476
477 request->done = FALSE;
478
479 switch (request->type) {
480 case wxSocketBase::REQ_PEEK:
481 case wxSocketBase::REQ_READ:
482 m_thread_requester->ProcessReadEvent(request);
483 break;
484 case wxSocketBase::REQ_WRITE:
485 m_thread_requester->ProcessWriteEvent(request);
486 break;
487 }
488 }
489 request->done = TRUE;
490 m_request_locker.Unlock();
491 }
492 }
493
494 void wxSocketInternal::WaitForEnd(SockRequest *request)
495 {
496 // TODOTODO
497 }
498
499 #endif
500 // __WXSTUBS__
501
502 #endif
503 // wxUSE_SOCKETS