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