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