]> git.saurik.com Git - wxWidgets.git/blob - src/common/sckint.cpp
Added wxGTK-only cmn dialogs.
[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 // --------------------------------------------------------------
190 // --------- SocketRequester ------------------------------------
191 // --------------------------------------------------------------
192
193 SocketRequester::SocketRequester(wxSocketBase *socket,
194 wxSocketInternal *internal)
195 :
196 #if wxUSE_THREADS
197 wxThread(),
198 #endif
199 m_socket(socket), m_internal(internal), m_fd(internal->GetFD())
200 {
201 }
202
203 SocketRequester::~SocketRequester()
204 {
205 }
206
207 bool SocketRequester::WaitFor(wxSocketBase::wxRequestNotify req, int millisec)
208 {
209 int ret;
210 struct timeval tv;
211 fd_set sockrd_set, sockwr_set;
212
213 // We won't wait.
214 tv.tv_sec = millisec / 1000;
215 tv.tv_usec = (millisec % 1000) * 1000;
216
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);
223
224 m_internal->AcquireFD();
225 ret = select(m_fd+1, &sockrd_set, &sockwr_set, NULL, &tv);
226 m_internal->ReleaseFD();
227
228 return (ret != 0);
229 }
230
231 void SocketRequester::ProcessReadEvent(SockRequest *req)
232 {
233 int ret;
234 size_t len;
235
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);
239 return;
240 }
241
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();
246
247 // An error occured, we exit.
248 if (ret < 0) {
249 req->error = errno;
250 m_internal->EndRequest(req);
251 return;
252 }
253 len = ret;
254
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)) {
257 req->size -= len;
258 req->io_nbytes += len;
259 req->buffer += len;
260
261 if (len == 0)
262 m_internal->EndRequest(req);
263 return;
264 }
265 // The End.
266 req->io_nbytes += len;
267 m_internal->EndRequest(req);
268 }
269
270 void SocketRequester::ProcessWriteEvent(SockRequest *req)
271 {
272 int ret;
273 size_t len;
274
275 if (!WaitFor(wxSocketBase::REQ_WRITE, req->timeout)) {
276 m_internal->EndRequest(req);
277 return;
278 }
279
280 m_internal->AcquireFD();
281 ret = send(m_fd, req->buffer, req->size, 0);
282 m_internal->ReleaseFD();
283 if (ret < 0) {
284 req->error = errno;
285 m_internal->EndRequest(req);
286 return;
287 }
288 len = ret;
289 if ((len < req->size) && ((m_socket->GetFlags() & wxSocketBase::WAITALL) != 0)) {
290 req->size -= len;
291 req->io_nbytes += len;
292 req->buffer += len;
293 return;
294 }
295 req->io_nbytes += len;
296 m_internal->EndRequest(req);
297 }
298
299 void SocketRequester::ProcessWaitEvent(SockRequest *req)
300 {
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.
304 else
305 req->io_nbytes = 0;
306
307 m_internal->EndRequest(req);
308 }
309
310 void *SocketRequester::Entry()
311 {
312 SockRequest *req;
313
314 m_internal->m_request_locker.Lock();
315 while (1) {
316 // Wait for a new request or a destroy message.
317 req = m_internal->WaitForReq();
318 m_internal->m_end_requester.Lock();
319 if (req == NULL) {
320 m_internal->m_invalid_requester = TRUE;
321 m_internal->m_end_requester.Unlock();
322 m_internal->m_request_locker.Unlock();
323 return NULL;
324 }
325 m_internal->m_end_requester.Unlock();
326
327 if ((req->type & wxSocketBase::REQ_WAIT) != 0) {
328 ProcessWaitEvent(req);
329 continue;
330 }
331
332 switch (req->type) {
333 case wxSocketBase::REQ_READ:
334 case wxSocketBase::REQ_PEEK:
335 ProcessReadEvent(req);
336 break;
337 case wxSocketBase::REQ_WRITE:
338 ProcessWriteEvent(req);
339 break;
340 }
341 }
342 return NULL;
343 }
344 #endif
345
346 // --------------------------------------------------------------
347 // --------- wxSocketInternal -----------------------------------
348 // --------------------------------------------------------------
349
350 wxSocketInternal::wxSocketInternal(wxSocketBase *socket)
351 {
352 m_socket = socket;
353 m_thread_requester = NULL;
354 m_thread_waiter = NULL;
355 m_invalid_requester = TRUE;
356 }
357
358 wxSocketInternal::~wxSocketInternal()
359 {
360 StopRequester();
361 wxASSERT(m_thread_requester == NULL);
362 StopWaiter();
363 wxASSERT(m_thread_waiter == NULL);
364 }
365
366 // ----------------------------------------------------------------------
367 // WaitForReq: it is called by SocketRequester and should return the next
368 // socket request if available
369 // ----------------------------------------------------------------------
370 SockRequest *wxSocketInternal::WaitForReq()
371 {
372 #if wxUSE_THREADS
373 wxNode *node;
374
375 // First try.
376 node = m_requests.First();
377 if (node == NULL) {
378 m_socket_cond.Wait(m_request_locker, 10, 0);
379
380 // Second try, if it is unsuccessul we give up.
381 node = m_requests.First();
382 if (node == NULL)
383 return NULL;
384 }
385
386 return (SockRequest *)node->Data();
387 #else
388 return NULL;
389 #endif
390 }
391
392 // ----------------------------------------------------------------------
393 // EndRequest: Should be called to finalize a request
394 // ----------------------------------------------------------------------
395 void wxSocketInternal::EndRequest(SockRequest *req)
396 {
397 wxNode *node = NULL;
398
399 req->done = TRUE;
400
401 node = m_requests.Member((wxObject *)req);
402 if (node != NULL)
403 delete node;
404 }
405
406 void wxSocketInternal::AcquireData()
407 {
408 #if wxUSE_THREADS
409 m_socket_locker.Lock();
410 #endif
411 }
412
413 void wxSocketInternal::ReleaseData()
414 {
415 #if wxUSE_THREADS
416 m_socket_locker.Unlock();
417 #endif
418 }
419
420 void wxSocketInternal::AcquireFD()
421 {
422 #if wxUSE_THREADS
423 m_fd_locker.Lock();
424 #endif
425 }
426
427 void wxSocketInternal::ReleaseFD()
428 {
429 #if wxUSE_THREADS
430 m_fd_locker.Unlock();
431 #endif
432 }
433
434 void wxSocketInternal::ResumeRequester()
435 {
436 #if wxUSE_THREADS
437 wxThreadError err;
438
439 wxASSERT(m_invalid_requester);
440
441 m_end_requester.Lock();
442
443 if (m_thread_requester != NULL) {
444 m_thread_requester->Delete(); // We must join it.
445 delete m_thread_requester;
446 }
447
448 m_invalid_requester = FALSE;
449
450 m_end_requester.Unlock();
451
452 m_thread_requester = new SocketRequester(m_socket, this);
453
454 err = m_thread_requester->Create();
455 wxASSERT(err == wxTHREAD_NO_ERROR);
456
457 err = m_thread_requester->Run();
458 wxASSERT(err == wxTHREAD_NO_ERROR);
459 #else
460 if (!m_invalid_requester)
461 return;
462 m_thread_requester = new SocketRequester(m_socket, this);
463 m_invalid_requester = FALSE;
464 #endif
465 }
466
467 void wxSocketInternal::StopRequester()
468 {
469 #if wxUSE_THREADS
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;
477 }
478 m_invalid_requester = TRUE;
479 return;
480 }
481 m_end_requester.Unlock();
482
483 wxASSERT(m_thread_requester != NULL);
484
485 m_request_locker.Lock();
486
487 // Send a signal to the requester.
488 m_socket_cond.Signal();
489
490 m_request_locker.Unlock();
491
492 // Finish the destruction of the requester.
493 m_thread_requester->Delete();
494
495 delete m_thread_requester;
496 m_thread_requester = NULL;
497 m_invalid_requester = TRUE;
498 #else
499 delete m_thread_requester;
500 m_thread_requester = NULL;
501 m_invalid_requester = TRUE;
502 #endif
503 }
504
505 void wxSocketInternal::ResumeWaiter()
506 {
507 #if wxUSE_THREADS
508 wxThreadError err;
509
510 if (m_thread_waiter != NULL)
511 return;
512
513 m_thread_waiter = new SocketWaiter(m_socket, this);
514
515 m_thread_waiter->SetPriority(WXTHREAD_MIN_PRIORITY);
516
517 err = m_thread_waiter->Create();
518 wxASSERT(err == wxTHREAD_NO_ERROR);
519
520 err = m_thread_waiter->Run();
521 wxASSERT(err == wxTHREAD_NO_ERROR);
522 #endif
523 }
524
525 void wxSocketInternal::StopWaiter()
526 {
527 #if wxUSE_THREADS
528 if (m_thread_waiter == NULL)
529 return;
530
531 m_thread_waiter->Delete();
532
533 delete m_thread_waiter;
534 m_thread_waiter = NULL;
535 #endif
536 }
537
538 // ----------------------------------------------------------------------
539 // QueueRequest:
540 // ----------------------------------------------------------------------
541 void wxSocketInternal::QueueRequest(SockRequest *request, bool async)
542 {
543 if (m_invalid_requester)
544 ResumeRequester();
545
546 #if wxUSE_THREADS
547 if (async) {
548
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();
554
555 // Wake up
556
557 if (request->wait) {
558 if (wxThread::IsMain())
559 while (!request->done) {
560 wxYield();
561 }
562 else
563 while (!request->done) {
564 wxThread::Yield();
565 }
566 }
567 } else {
568 m_request_locker.Lock();
569 #endif
570
571 if ((request->type & wxSocketBase::REQ_WAIT) != 0) {
572 m_thread_requester->ProcessWaitEvent(request);
573 } else {
574
575 request->done = FALSE;
576
577 switch (request->type) {
578 case wxSocketBase::REQ_PEEK:
579 case wxSocketBase::REQ_READ:
580 m_thread_requester->ProcessReadEvent(request);
581 break;
582 case wxSocketBase::REQ_WRITE:
583 m_thread_requester->ProcessWriteEvent(request);
584 break;
585 }
586 }
587 request->done = TRUE;
588 #if wxUSE_THREADS
589 m_request_locker.Unlock();
590 }
591 #endif
592 }
593
594 void wxSocketInternal::WaitForEnd(SockRequest *request)
595 {
596 #if wxUSE_THREADS
597 // TODOTODO
598 #endif
599 }
600
601 #endif
602 // __WXSTUBS__
603
604 #endif
605 // wxUSE_SOCKETS