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