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