]> git.saurik.com Git - wxWidgets.git/blob - src/common/sckint.cpp
* wxStream doc update
[wxWidgets.git] / src / common / sckint.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: sckint.cpp
3 // Purpose: Socket internal classes
4 // Authors: Guilhem Lavaux
5 // Created: April 1999
6 // Updated:
7 // Copyright: (C) 1999, 1998, 1997, Guilhem Lavaux
8 // RCS_ID: $Id$
9 // License: see wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11 #ifdef __GNUG__
12 #pragma implementation "sckint.h"
13 #endif
14
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #if wxUSE_SOCKETS
23
24 #define WXSOCK_INTERNAL
25 #include "wx/object.h"
26 #include "wx/list.h"
27 #include "wx/socket.h"
28 #include "wx/thread.h"
29 #include "wx/sckint.h"
30 #include "wx/sckint.h"
31 #include "wx/utils.h"
32
33 // IRIX requires bstring.h be included to use select()
34 #ifdef sgi
35 #include <bstring.h>
36 #endif // IRIX
37
38 #ifndef __WXSTUBS__
39
40 #include <stdlib.h>
41 #include <string.h>
42 #include <ctype.h>
43
44 // -----------------------
45 // System specific headers
46 // -----------------------
47
48 #ifdef __WXMAC__
49 // in order to avoid problems with our c library and double definitions
50 #define close closesocket
51 #define ioctl ioctlsocket
52
53 #include <wx/mac/macsock.h>
54 #endif
55
56 #if defined(__WINDOWS__)
57 #include <winsock.h>
58 #endif // __WINDOWS__
59
60 #if defined(__UNIX__)
61
62 #ifdef VMS
63 #include <socket.h>
64 #else
65 #include <sys/socket.h>
66 #endif
67 #include <sys/ioctl.h>
68
69 #include <sys/time.h>
70 #include <unistd.h>
71
72 #ifdef sun
73 #include <sys/filio.h>
74 #endif
75
76 #endif // __UNIX__
77
78 #include <signal.h>
79 #include <errno.h>
80
81 #ifdef __VISUALC__
82 #include <io.h>
83 #endif
84
85 // Constants
86 #define READ_MASK wxSocketBase::REQ_READ | wxSocketBase::REQ_ACCEPT | wxSocketBase::REQ_LOST
87 #define WRITE_MASK wxSocketBase::REQ_WRITE | wxSocketBase::REQ_CONNECT
88
89 // --------------------------------------------------------------
90 // --------- SocketWaiter ---------------------------------------
91 // --------------------------------------------------------------
92
93 #if wxUSE_THREADS
94 SocketWaiter::SocketWaiter(wxSocketBase *socket,
95 wxSocketInternal *internal)
96 : wxThread(),
97 m_socket(socket), m_internal(internal), m_fd(internal->GetFD())
98 {
99 }
100
101 SocketWaiter::~SocketWaiter()
102 {
103 }
104
105 void SocketWaiter::ProcessReadEvent()
106 {
107 int ret;
108 char c;
109
110 m_internal->AcquireFD();
111 ret = recv(m_fd, &c, 1, MSG_PEEK);
112 m_internal->ReleaseFD();
113
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);
117 return;
118 }
119
120 // Else, no error => there is something to be read else
121 // we've lost the connection.
122 if (ret > 0) {
123 m_socket->OnRequest(wxSocketBase::EVT_READ);
124 } else {
125 m_socket->OnRequest(wxSocketBase::EVT_LOST);
126 m_internal->ReleaseData(); // In that case, we mustn't forget to unlock the mutex.
127 Exit(NULL);
128 }
129 }
130
131 void SocketWaiter::ProcessWriteEvent()
132 {
133 if (m_socket->IsConnected())
134 m_socket->OnRequest(wxSocketBase::EVT_CONNECT);
135 else
136 m_socket->OnRequest(wxSocketBase::EVT_WRITE);
137 }
138
139 void *SocketWaiter::Entry()
140 {
141 struct timeval tv;
142 fd_set sockrd_set, sockwr_set;
143 wxSocketEvent event;
144 int ret;
145
146 while (1) {
147 // We won't wait.
148 tv.tv_sec = 0;
149 tv.tv_usec = 0;
150
151 FD_ZERO(&sockrd_set);
152 FD_ZERO(&sockwr_set);
153
154 m_internal->AcquireData();
155
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);
160
161 m_internal->AcquireFD();
162 ret = select(m_fd+1, &sockrd_set, &sockwr_set, NULL, &tv);
163 m_internal->ReleaseFD();
164
165 if (FD_ISSET(m_fd, &sockrd_set))
166 ProcessReadEvent();
167
168 if (FD_ISSET(m_fd, &sockwr_set))
169 ProcessWriteEvent();
170
171 m_internal->ReleaseData();
172
173 #if wxUSE_THREADS
174 #ifdef Yield
175 #undef Yield
176 #endif
177 #endif
178
179 // We wait for 100 ms to prevent the CPU from burning.
180 wxUsleep(100);
181
182 // Check whether we should exit.
183 if (TestDestroy())
184 return NULL;
185 }
186 return NULL;
187 }
188
189 #endif
190
191 // --------------------------------------------------------------
192 // --------- SocketRequester ------------------------------------
193 // --------------------------------------------------------------
194
195 SocketRequester::SocketRequester(wxSocketBase *socket,
196 wxSocketInternal *internal)
197 :
198 #if wxUSE_THREADS
199 wxThread(),
200 #endif
201 m_socket(socket), m_internal(internal), m_fd(internal->GetFD())
202 {
203 }
204
205 SocketRequester::~SocketRequester()
206 {
207 }
208
209 bool SocketRequester::WaitFor(wxSocketBase::wxRequestNotify req, int millisec)
210 {
211 int ret;
212 struct timeval tv;
213 fd_set sockrd_set, sockwr_set;
214
215 // We won't wait.
216 tv.tv_sec = millisec / 1000;
217 tv.tv_usec = (millisec % 1000) * 1000;
218
219 FD_ZERO(&sockrd_set);
220 FD_ZERO(&sockwr_set);
221 if ((req & READ_MASK) != 0)
222 FD_SET(m_fd, &sockrd_set);
223 if ((req & WRITE_MASK) != 0)
224 FD_SET(m_fd, &sockwr_set);
225
226 m_internal->AcquireFD();
227 ret = select(m_fd+1, &sockrd_set, &sockwr_set, NULL, &tv);
228 m_internal->ReleaseFD();
229
230 return (ret != 0);
231 }
232
233 void SocketRequester::ProcessReadEvent(SockRequest *req)
234 {
235 int ret;
236 size_t len;
237
238 // We'll wait for the first byte, in case a "timeout event" occurs it returns // immediately
239 if (!WaitFor(wxSocketBase::REQ_READ, req->timeout)) {
240 m_internal->EndRequest(req);
241 return;
242 }
243
244 m_internal->AcquireFD();
245 ret = recv(m_fd, req->buffer, req->size,
246 (req->type == wxSocketBase::REQ_PEEK) ? MSG_PEEK : 0);
247 m_internal->ReleaseFD();
248
249 // An error occured, we exit.
250 if (ret < 0) {
251 req->error = errno;
252 m_internal->EndRequest(req);
253 return;
254 }
255 len = ret;
256
257 // If the buffer isn't full (and we want it to be full), we don't unqueue it.
258 if ((len < req->size) && (m_socket->GetFlags() & wxSocketBase::WAITALL)) {
259 req->size -= len;
260 req->io_nbytes += len;
261 req->buffer += len;
262
263 if (len == 0)
264 m_internal->EndRequest(req);
265 return;
266 }
267 // The End.
268 req->io_nbytes += len;
269 m_internal->EndRequest(req);
270 }
271
272 void SocketRequester::ProcessWriteEvent(SockRequest *req)
273 {
274 int ret;
275 size_t len;
276
277 if (!WaitFor(wxSocketBase::REQ_WRITE, req->timeout)) {
278 m_internal->EndRequest(req);
279 return;
280 }
281
282 m_internal->AcquireFD();
283 ret = send(m_fd, req->buffer, req->size, 0);
284 m_internal->ReleaseFD();
285 if (ret < 0) {
286 req->error = errno;
287 m_internal->EndRequest(req);
288 return;
289 }
290 len = ret;
291 if ((len < req->size) && ((m_socket->GetFlags() & wxSocketBase::WAITALL) != 0)) {
292 req->size -= len;
293 req->io_nbytes += len;
294 req->buffer += len;
295 return;
296 }
297 req->io_nbytes += len;
298 m_internal->EndRequest(req);
299 }
300
301 void SocketRequester::ProcessWaitEvent(SockRequest *req)
302 {
303 if (WaitFor(req->type, req->timeout))
304 req->io_nbytes = 1; // We put 1 in the counter to tell the requester
305 // there is no timeout.
306 else
307 req->io_nbytes = 0;
308
309 m_internal->EndRequest(req);
310 }
311
312
313 #if wxUSE_THREADS
314 void *SocketRequester::Entry()
315 {
316 SockRequest *req;
317
318 m_internal->m_request_locker.Lock();
319 while (1) {
320 // Wait for a new request or a destroy message.
321 req = m_internal->WaitForReq();
322 m_internal->m_end_requester.Lock();
323 if (req == NULL) {
324 m_internal->m_invalid_requester = TRUE;
325 m_internal->m_end_requester.Unlock();
326 m_internal->m_request_locker.Unlock();
327 return NULL;
328 }
329 m_internal->m_end_requester.Unlock();
330
331 if ((req->type & wxSocketBase::REQ_WAIT) != 0) {
332 ProcessWaitEvent(req);
333 continue;
334 }
335
336 switch (req->type) {
337 case wxSocketBase::REQ_READ:
338 case wxSocketBase::REQ_PEEK:
339 ProcessReadEvent(req);
340 break;
341 case wxSocketBase::REQ_WRITE:
342 ProcessWriteEvent(req);
343 break;
344 }
345 }
346 return NULL;
347 }
348 #endif
349
350 // --------------------------------------------------------------
351 // --------- wxSocketInternal -----------------------------------
352 // --------------------------------------------------------------
353
354 wxSocketInternal::wxSocketInternal(wxSocketBase *socket)
355 {
356 m_socket = socket;
357 m_thread_requester = NULL;
358 m_thread_waiter = NULL;
359 m_invalid_requester = TRUE;
360 }
361
362 wxSocketInternal::~wxSocketInternal()
363 {
364 StopRequester();
365 wxASSERT(m_thread_requester == NULL);
366 StopWaiter();
367 wxASSERT(m_thread_waiter == NULL);
368 }
369
370 // ----------------------------------------------------------------------
371 // WaitForReq: it is called by SocketRequester and should return the next
372 // socket request if available
373 // ----------------------------------------------------------------------
374 SockRequest *wxSocketInternal::WaitForReq()
375 {
376 #if wxUSE_THREADS
377 wxNode *node;
378
379 // First try.
380 node = m_requests.First();
381 if (node == NULL) {
382 m_socket_cond.Wait(m_request_locker, 10, 0);
383
384 // Second try, if it is unsuccessul we give up.
385 node = m_requests.First();
386 if (node == NULL)
387 return NULL;
388 }
389
390 return (SockRequest *)node->Data();
391 #else
392 return NULL;
393 #endif
394 }
395
396 // ----------------------------------------------------------------------
397 // EndRequest: Should be called to finalize a request
398 // ----------------------------------------------------------------------
399 void wxSocketInternal::EndRequest(SockRequest *req)
400 {
401 wxNode *node = NULL;
402
403 req->done = TRUE;
404
405 node = m_requests.Member((wxObject *)req);
406 if (node != NULL)
407 delete node;
408 }
409
410 void wxSocketInternal::AcquireData()
411 {
412 #if wxUSE_THREADS
413 m_socket_locker.Lock();
414 #endif
415 }
416
417 void wxSocketInternal::ReleaseData()
418 {
419 #if wxUSE_THREADS
420 m_socket_locker.Unlock();
421 #endif
422 }
423
424 void wxSocketInternal::AcquireFD()
425 {
426 #if wxUSE_THREADS
427 m_fd_locker.Lock();
428 #endif
429 }
430
431 void wxSocketInternal::ReleaseFD()
432 {
433 #if wxUSE_THREADS
434 m_fd_locker.Unlock();
435 #endif
436 }
437
438 void wxSocketInternal::ResumeRequester()
439 {
440 #if wxUSE_THREADS
441 wxThreadError err;
442
443 wxASSERT(m_invalid_requester);
444
445 m_end_requester.Lock();
446
447 if (m_thread_requester != NULL) {
448 m_thread_requester->Delete(); // We must join it.
449 delete m_thread_requester;
450 }
451
452 m_invalid_requester = FALSE;
453
454 m_end_requester.Unlock();
455
456 m_thread_requester = new SocketRequester(m_socket, this);
457
458 err = m_thread_requester->Create();
459 wxASSERT(err == wxTHREAD_NO_ERROR);
460
461 err = m_thread_requester->Run();
462 wxASSERT(err == wxTHREAD_NO_ERROR);
463 #else
464 if (!m_invalid_requester)
465 return;
466 m_thread_requester = new SocketRequester(m_socket, this);
467 m_invalid_requester = FALSE;
468 #endif
469 }
470
471 void wxSocketInternal::StopRequester()
472 {
473 #if wxUSE_THREADS
474 m_end_requester.Lock();
475 if (m_invalid_requester) {
476 m_end_requester.Unlock();
477 if (m_thread_requester) {
478 m_thread_requester->Delete();
479 delete m_thread_requester;
480 m_thread_requester = NULL;
481 }
482 m_invalid_requester = TRUE;
483 return;
484 }
485 m_end_requester.Unlock();
486
487 wxASSERT(m_thread_requester != NULL);
488
489 m_request_locker.Lock();
490
491 // Send a signal to the requester.
492 m_socket_cond.Signal();
493
494 m_request_locker.Unlock();
495
496 // Finish the destruction of the requester.
497 m_thread_requester->Delete();
498
499 delete m_thread_requester;
500 m_thread_requester = NULL;
501 m_invalid_requester = TRUE;
502 #else
503 delete m_thread_requester;
504 m_thread_requester = NULL;
505 m_invalid_requester = TRUE;
506 #endif
507 }
508
509 void wxSocketInternal::ResumeWaiter()
510 {
511 #if wxUSE_THREADS
512 wxThreadError err;
513
514 if (m_thread_waiter != NULL)
515 return;
516
517 m_thread_waiter = new SocketWaiter(m_socket, this);
518
519 m_thread_waiter->SetPriority(WXTHREAD_MIN_PRIORITY);
520
521 err = m_thread_waiter->Create();
522 wxASSERT(err == wxTHREAD_NO_ERROR);
523
524 err = m_thread_waiter->Run();
525 wxASSERT(err == wxTHREAD_NO_ERROR);
526 #endif
527 }
528
529 void wxSocketInternal::StopWaiter()
530 {
531 #if wxUSE_THREADS
532 if (m_thread_waiter == NULL)
533 return;
534
535 m_thread_waiter->Delete();
536
537 delete m_thread_waiter;
538 m_thread_waiter = NULL;
539 #endif
540 }
541
542 // ----------------------------------------------------------------------
543 // QueueRequest:
544 // ----------------------------------------------------------------------
545 void wxSocketInternal::QueueRequest(SockRequest *request, bool async)
546 {
547 if (m_invalid_requester)
548 ResumeRequester();
549
550 #if wxUSE_THREADS
551 if (async) {
552
553 m_request_locker.Lock();
554 request->done = FALSE;
555 m_requests.Append((wxObject *)request);
556 m_socket_cond.Signal();
557 m_request_locker.Unlock();
558
559 // Wake up
560
561 if (request->wait) {
562 if (wxThread::IsMain())
563 while (!request->done) {
564 wxYield();
565 }
566 else
567 while (!request->done) {
568 wxThread::Yield();
569 }
570 }
571 } else {
572 m_request_locker.Lock();
573 #endif
574
575 if ((request->type & wxSocketBase::REQ_WAIT) != 0) {
576 m_thread_requester->ProcessWaitEvent(request);
577 } else {
578
579 request->done = FALSE;
580
581 switch (request->type) {
582 case wxSocketBase::REQ_PEEK:
583 case wxSocketBase::REQ_READ:
584 m_thread_requester->ProcessReadEvent(request);
585 break;
586 case wxSocketBase::REQ_WRITE:
587 m_thread_requester->ProcessWriteEvent(request);
588 break;
589 }
590 }
591 request->done = TRUE;
592 #if wxUSE_THREADS
593 m_request_locker.Unlock();
594 }
595 #endif
596 }
597
598 void wxSocketInternal::WaitForEnd(SockRequest *request)
599 {
600 #if wxUSE_THREADS
601 // TODOTODO
602 #endif
603 }
604
605 #endif
606 // __WXSTUBS__
607
608 #endif
609 // wxUSE_SOCKETS