source: trunk/synergy/lib/arch/CArchNetworkBSD.cpp

Last change on this file was 2756, checked in by bird, 19 years ago

Use a socketpair instead of a pipe on OS/2.

File size: 19.2 KB
Line 
1/*
2 * synergy -- mouse and keyboard sharing utility
3 * Copyright (C) 2002 Chris Schoeneman
4 *
5 * This package is free software you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * found in the file COPYING that should have accompanied this file.
8 *
9 * This package is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include "CArchNetworkBSD.h"
16#include "CArch.h"
17#include "CArchMultithreadPosix.h"
18#include "XArchUnix.h"
19#if HAVE_UNISTD_H
20# include <unistd.h>
21#endif
22#include <netinet/in.h>
23#include <netdb.h>
24#if !defined(TCP_NODELAY)
25# include <netinet/tcp.h>
26#endif
27#include <arpa/inet.h>
28#include <fcntl.h>
29#include <errno.h>
30#include <string.h>
31
32#if HAVE_POLL
33# include <poll.h>
34#else
35# if HAVE_SYS_SELECT_H
36# include <sys/select.h>
37# endif
38# if HAVE_SYS_TIME_H
39# include <sys/time.h>
40# endif
41#endif
42
43#if !HAVE_INET_ATON
44# include <stdio.h>
45#endif
46
47static const int s_family[] = {
48 PF_UNSPEC,
49 PF_INET
50};
51static const int s_type[] = {
52 SOCK_DGRAM,
53 SOCK_STREAM
54};
55
56#if !HAVE_INET_ATON
57// parse dotted quad addresses. we don't bother with the weird BSD'ism
58// of handling octal and hex and partial forms.
59static
60in_addr_t
61inet_aton(const char* cp, struct in_addr* inp)
62{
63 unsigned int a, b, c, d;
64 if (sscanf(cp, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) {
65 return 0;
66 }
67 if (a >= 256 || b >= 256 || c >= 256 || d >= 256) {
68 return 0;
69 }
70 unsigned char* incp = (unsigned char*)inp;
71 incp[0] = (unsigned char)(a & 0xffu);
72 incp[1] = (unsigned char)(b & 0xffu);
73 incp[2] = (unsigned char)(c & 0xffu);
74 incp[3] = (unsigned char)(d & 0xffu);
75 return inp->s_addr;
76}
77#endif
78
79//
80// CArchNetworkBSD
81//
82
83CArchNetworkBSD::CArchNetworkBSD()
84{
85 // create mutex to make some calls thread safe
86 m_mutex = ARCH->newMutex();
87}
88
89CArchNetworkBSD::~CArchNetworkBSD()
90{
91 ARCH->closeMutex(m_mutex);
92}
93
94CArchSocket
95CArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type)
96{
97 // create socket
98 int fd = socket(s_family[family], s_type[type], 0);
99 if (fd == -1) {
100 throwError(errno);
101 }
102 try {
103 setBlockingOnSocket(fd, false);
104 }
105 catch (...) {
106 close(fd);
107 throw;
108 }
109
110 // allocate socket object
111 CArchSocketImpl* newSocket = new CArchSocketImpl;
112 newSocket->m_fd = fd;
113 newSocket->m_refCount = 1;
114 return newSocket;
115}
116
117CArchSocket
118CArchNetworkBSD::copySocket(CArchSocket s)
119{
120 assert(s != NULL);
121
122 // ref the socket and return it
123 ARCH->lockMutex(m_mutex);
124 ++s->m_refCount;
125 ARCH->unlockMutex(m_mutex);
126 return s;
127}
128
129void
130CArchNetworkBSD::closeSocket(CArchSocket s)
131{
132 assert(s != NULL);
133
134 // unref the socket and note if it should be released
135 ARCH->lockMutex(m_mutex);
136 const bool doClose = (--s->m_refCount == 0);
137 ARCH->unlockMutex(m_mutex);
138
139 // close the socket if necessary
140 if (doClose) {
141 if (close(s->m_fd) == -1) {
142 // close failed. restore the last ref and throw.
143 int err = errno;
144 ARCH->lockMutex(m_mutex);
145 ++s->m_refCount;
146 ARCH->unlockMutex(m_mutex);
147 throwError(err);
148 }
149 delete s;
150 }
151}
152
153void
154CArchNetworkBSD::closeSocketForRead(CArchSocket s)
155{
156 assert(s != NULL);
157
158 if (shutdown(s->m_fd, 0) == -1) {
159 if (errno != ENOTCONN) {
160 throwError(errno);
161 }
162 }
163}
164
165void
166CArchNetworkBSD::closeSocketForWrite(CArchSocket s)
167{
168 assert(s != NULL);
169
170 if (shutdown(s->m_fd, 1) == -1) {
171 if (errno != ENOTCONN) {
172 throwError(errno);
173 }
174 }
175}
176
177void
178CArchNetworkBSD::bindSocket(CArchSocket s, CArchNetAddress addr)
179{
180 assert(s != NULL);
181 assert(addr != NULL);
182
183 if (bind(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
184 throwError(errno);
185 }
186}
187
188void
189CArchNetworkBSD::listenOnSocket(CArchSocket s)
190{
191 assert(s != NULL);
192
193 // hardcoding backlog
194 if (listen(s->m_fd, 3) == -1) {
195 throwError(errno);
196 }
197}
198
199CArchSocket
200CArchNetworkBSD::acceptSocket(CArchSocket s, CArchNetAddress* addr)
201{
202 assert(s != NULL);
203
204 // if user passed NULL in addr then use scratch space
205 CArchNetAddress dummy;
206 if (addr == NULL) {
207 addr = &dummy;
208 }
209
210 // create new socket and address
211 CArchSocketImpl* newSocket = new CArchSocketImpl;
212 *addr = new CArchNetAddressImpl;
213
214 // accept on socket
215 int fd = accept(s->m_fd, &(*addr)->m_addr, &(*addr)->m_len);
216 if (fd == -1) {
217 int err = errno;
218 delete newSocket;
219 delete *addr;
220 *addr = NULL;
221 if (err == EAGAIN) {
222 return NULL;
223 }
224 throwError(err);
225 }
226
227 try {
228 setBlockingOnSocket(fd, false);
229 }
230 catch (...) {
231 close(fd);
232 delete newSocket;
233 delete *addr;
234 *addr = NULL;
235 throw;
236 }
237
238 // initialize socket
239 newSocket->m_fd = fd;
240 newSocket->m_refCount = 1;
241
242 // discard address if not requested
243 if (addr == &dummy) {
244 ARCH->closeAddr(dummy);
245 }
246
247 return newSocket;
248}
249
250bool
251CArchNetworkBSD::connectSocket(CArchSocket s, CArchNetAddress addr)
252{
253 assert(s != NULL);
254 assert(addr != NULL);
255
256 if (connect(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
257 if (errno == EISCONN) {
258 return true;
259 }
260 if (errno == EINPROGRESS) {
261 return false;
262 }
263 throwError(errno);
264 }
265 return true;
266}
267
268#if HAVE_POLL
269
270int
271CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
272{
273 assert(pe != NULL || num == 0);
274
275 // return if nothing to do
276 if (num == 0) {
277 if (timeout > 0.0) {
278 ARCH->sleep(timeout);
279 }
280 return 0;
281 }
282
283 // allocate space for translated query
284 struct pollfd* pfd = new struct pollfd[1 + num];
285
286 // translate query
287 for (int i = 0; i < num; ++i) {
288 pfd[i].fd = (pe[i].m_socket == NULL) ? -1 : pe[i].m_socket->m_fd;
289 pfd[i].events = 0;
290 if ((pe[i].m_events & kPOLLIN) != 0) {
291 pfd[i].events |= POLLIN;
292 }
293 if ((pe[i].m_events & kPOLLOUT) != 0) {
294 pfd[i].events |= POLLOUT;
295 }
296 }
297 int n = num;
298
299 // add the unblock pipe
300 const int* unblockPipe = getUnblockPipe();
301 if (unblockPipe != NULL) {
302 pfd[n].fd = unblockPipe[0];
303 pfd[n].events = POLLIN;
304 ++n;
305 }
306
307 // prepare timeout
308 int t = (timeout < 0.0) ? -1 : static_cast<int>(1000.0 * timeout);
309
310 // do the poll
311 n = poll(pfd, n, t);
312
313 // reset the unblock pipe
314 if (n > 0 && unblockPipe != NULL && (pfd[num].revents & POLLIN) != 0) {
315 // the unblock event was signalled. flush the pipe.
316 char dummy[100];
317 do {
318 read(unblockPipe[0], dummy, sizeof(dummy));
319 } while (errno != EAGAIN);
320
321 // don't count this unblock pipe in return value
322 --n;
323 }
324
325 // handle results
326 if (n == -1) {
327 if (errno == EINTR) {
328 // interrupted system call
329 ARCH->testCancelThread();
330 delete[] pfd;
331 return 0;
332 }
333 delete[] pfd;
334 throwError(errno);
335 }
336
337 // translate back
338 for (int i = 0; i < num; ++i) {
339 pe[i].m_revents = 0;
340 if ((pfd[i].revents & POLLIN) != 0) {
341 pe[i].m_revents |= kPOLLIN;
342 }
343 if ((pfd[i].revents & POLLOUT) != 0) {
344 pe[i].m_revents |= kPOLLOUT;
345 }
346 if ((pfd[i].revents & POLLERR) != 0) {
347 pe[i].m_revents |= kPOLLERR;
348 }
349 if ((pfd[i].revents & POLLNVAL) != 0) {
350 pe[i].m_revents |= kPOLLNVAL;
351 }
352 }
353
354 delete[] pfd;
355 return n;
356}
357
358#else
359
360int
361CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
362{
363 int i, n;
364
365 // prepare sets for select
366 n = 0;
367 fd_set readSet, writeSet, errSet;
368 fd_set* readSetP = NULL;
369 fd_set* writeSetP = NULL;
370 fd_set* errSetP = NULL;
371 FD_ZERO(&readSet);
372 FD_ZERO(&writeSet);
373 FD_ZERO(&errSet);
374 for (i = 0; i < num; ++i) {
375 // reset return flags
376 pe[i].m_revents = 0;
377
378 // set invalid flag if socket is bogus then go to next socket
379 if (pe[i].m_socket == NULL) {
380 pe[i].m_revents |= kPOLLNVAL;
381 continue;
382 }
383
384 int fdi = pe[i].m_socket->m_fd;
385 if (pe[i].m_events & kPOLLIN) {
386 FD_SET(pe[i].m_socket->m_fd, &readSet);
387 readSetP = &readSet;
388 if (fdi > n) {
389 n = fdi;
390 }
391 }
392 if (pe[i].m_events & kPOLLOUT) {
393 FD_SET(pe[i].m_socket->m_fd, &writeSet);
394 writeSetP = &writeSet;
395 if (fdi > n) {
396 n = fdi;
397 }
398 }
399 if (true) {
400 FD_SET(pe[i].m_socket->m_fd, &errSet);
401 errSetP = &errSet;
402 if (fdi > n) {
403 n = fdi;
404 }
405 }
406 }
407
408 // add the unblock pipe
409 const int* unblockPipe = getUnblockPipe();
410 if (unblockPipe != NULL) {
411 FD_SET(unblockPipe[0], &readSet);
412 readSetP = &readSet;
413 if (unblockPipe[0] > n) {
414 n = unblockPipe[0];
415 }
416 }
417
418 // if there are no sockets then don't block forever
419 if (n == 0 && timeout < 0.0) {
420 timeout = 0.0;
421 }
422
423 // prepare timeout for select
424 struct timeval timeout2;
425 struct timeval* timeout2P;
426 if (timeout < 0.0) {
427 timeout2P = NULL;
428 }
429 else {
430 timeout2P = &timeout2;
431 timeout2.tv_sec = static_cast<int>(timeout);
432 timeout2.tv_usec = static_cast<int>(1.0e+6 *
433 (timeout - timeout2.tv_sec));
434 }
435
436 // do the select
437 n = select((SELECT_TYPE_ARG1) n + 1,
438 SELECT_TYPE_ARG234 readSetP,
439 SELECT_TYPE_ARG234 writeSetP,
440 SELECT_TYPE_ARG234 errSetP,
441 SELECT_TYPE_ARG5 timeout2P);
442
443 // reset the unblock pipe
444 if (n > 0 && unblockPipe != NULL && FD_ISSET(unblockPipe[0], &readSet)) {
445 // the unblock event was signalled. flush the pipe.
446 char dummy[100];
447 do {
448 read(unblockPipe[0], dummy, sizeof(dummy));
449 } while (errno != EAGAIN);
450 }
451
452 // handle results
453 if (n == -1) {
454 if (errno == EINTR) {
455 // interrupted system call
456 ARCH->testCancelThread();
457 return 0;
458 }
459 throwError(errno);
460 }
461 n = 0;
462 for (i = 0; i < num; ++i) {
463 if (pe[i].m_socket != NULL) {
464 if (FD_ISSET(pe[i].m_socket->m_fd, &readSet)) {
465 pe[i].m_revents |= kPOLLIN;
466 }
467 if (FD_ISSET(pe[i].m_socket->m_fd, &writeSet)) {
468 pe[i].m_revents |= kPOLLOUT;
469 }
470 if (FD_ISSET(pe[i].m_socket->m_fd, &errSet)) {
471 pe[i].m_revents |= kPOLLERR;
472 }
473 }
474 if (pe[i].m_revents != 0) {
475 ++n;
476 }
477 }
478
479 return n;
480}
481
482#endif
483
484void
485CArchNetworkBSD::unblockPollSocket(CArchThread thread)
486{
487 const int* unblockPipe = getUnblockPipeForThread(thread);
488 if (unblockPipe != NULL) {
489 char dummy = 0;
490 write(unblockPipe[1], &dummy, 1);
491 }
492}
493
494size_t
495CArchNetworkBSD::readSocket(CArchSocket s, void* buf, size_t len)
496{
497 assert(s != NULL);
498
499 ssize_t n = read(s->m_fd, buf, len);
500 if (n == -1) {
501 if (errno == EINTR || errno == EAGAIN) {
502 return 0;
503 }
504 throwError(errno);
505 }
506 return n;
507}
508
509size_t
510CArchNetworkBSD::writeSocket(CArchSocket s, const void* buf, size_t len)
511{
512 assert(s != NULL);
513
514 ssize_t n = write(s->m_fd, buf, len);
515 if (n == -1) {
516 if (errno == EINTR || errno == EAGAIN) {
517 return 0;
518 }
519 throwError(errno);
520 }
521 return n;
522}
523
524void
525CArchNetworkBSD::throwErrorOnSocket(CArchSocket s)
526{
527 assert(s != NULL);
528
529 // get the error from the socket layer
530 int err = 0;
531 socklen_t size = sizeof(err);
532 if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR,
533 (optval_t*)&err, &size) == -1) {
534 err = errno;
535 }
536
537 // throw if there's an error
538 if (err != 0) {
539 throwError(err);
540 }
541}
542
543void
544CArchNetworkBSD::setBlockingOnSocket(int fd, bool blocking)
545{
546 assert(fd != -1);
547
548 int mode = fcntl(fd, F_GETFL, 0);
549 if (mode == -1) {
550 throwError(errno);
551 }
552 if (blocking) {
553 mode &= ~O_NONBLOCK;
554 }
555 else {
556 mode |= O_NONBLOCK;
557 }
558 if (fcntl(fd, F_SETFL, mode) == -1) {
559 throwError(errno);
560 }
561}
562
563bool
564CArchNetworkBSD::setNoDelayOnSocket(CArchSocket s, bool noDelay)
565{
566 assert(s != NULL);
567
568 // get old state
569 int oflag;
570 socklen_t size = sizeof(oflag);
571 if (getsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY,
572 (optval_t*)&oflag, &size) == -1) {
573 throwError(errno);
574 }
575
576 int flag = noDelay ? 1 : 0;
577 size = sizeof(flag);
578 if (setsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY,
579 (optval_t*)&flag, size) == -1) {
580 throwError(errno);
581 }
582
583 return (oflag != 0);
584}
585
586bool
587CArchNetworkBSD::setReuseAddrOnSocket(CArchSocket s, bool reuse)
588{
589 assert(s != NULL);
590
591 // get old state
592 int oflag;
593 socklen_t size = sizeof(oflag);
594 if (getsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR,
595 (optval_t*)&oflag, &size) == -1) {
596 throwError(errno);
597 }
598
599 int flag = reuse ? 1 : 0;
600 size = sizeof(flag);
601 if (setsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR,
602 (optval_t*)&flag, size) == -1) {
603 throwError(errno);
604 }
605
606 return (oflag != 0);
607}
608
609std::string
610CArchNetworkBSD::getHostName()
611{
612 char name[256];
613 if (gethostname(name, sizeof(name)) == -1) {
614 name[0] = '\0';
615 }
616 else {
617 name[sizeof(name) - 1] = '\0';
618 }
619 return name;
620}
621
622CArchNetAddress
623CArchNetworkBSD::newAnyAddr(EAddressFamily family)
624{
625 // allocate address
626 CArchNetAddressImpl* addr = new CArchNetAddressImpl;
627
628 // fill it in
629 switch (family) {
630 case kINET: {
631 struct sockaddr_in* ipAddr =
632 reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
633 ipAddr->sin_family = AF_INET;
634 ipAddr->sin_port = 0;
635 ipAddr->sin_addr.s_addr = INADDR_ANY;
636 addr->m_len = sizeof(struct sockaddr_in);
637 break;
638 }
639
640 default:
641 delete addr;
642 assert(0 && "invalid family");
643 }
644
645 return addr;
646}
647
648CArchNetAddress
649CArchNetworkBSD::copyAddr(CArchNetAddress addr)
650{
651 assert(addr != NULL);
652
653 // allocate and copy address
654 return new CArchNetAddressImpl(*addr);
655}
656
657CArchNetAddress
658CArchNetworkBSD::nameToAddr(const std::string& name)
659{
660 // allocate address
661 CArchNetAddressImpl* addr = new CArchNetAddressImpl;
662
663 // try to convert assuming an IPv4 dot notation address
664 struct sockaddr_in inaddr;
665 memset(&inaddr, 0, sizeof(inaddr));
666 if (inet_aton(name.c_str(), &inaddr.sin_addr) != 0) {
667 // it's a dot notation address
668 addr->m_len = sizeof(struct sockaddr_in);
669 inaddr.sin_family = AF_INET;
670 inaddr.sin_port = 0;
671 memcpy(&addr->m_addr, &inaddr, addr->m_len);
672 }
673
674 else {
675 // mutexed address lookup (ugh)
676 ARCH->lockMutex(m_mutex);
677 struct hostent* info = gethostbyname(name.c_str());
678 if (info == NULL) {
679 ARCH->unlockMutex(m_mutex);
680 delete addr;
681 throwNameError(h_errno);
682 }
683
684 // copy over address (only IPv4 currently supported)
685 if (info->h_addrtype == AF_INET) {
686 addr->m_len = sizeof(struct sockaddr_in);
687 inaddr.sin_family = info->h_addrtype;
688 inaddr.sin_port = 0;
689 memcpy(&inaddr.sin_addr, info->h_addr_list[0],
690 sizeof(inaddr.sin_addr));
691 memcpy(&addr->m_addr, &inaddr, addr->m_len);
692 }
693 else {
694 ARCH->unlockMutex(m_mutex);
695 delete addr;
696 throw XArchNetworkNameUnsupported(
697 "The requested name is valid but "
698 "does not have a supported address family");
699 }
700
701 // done with static buffer
702 ARCH->unlockMutex(m_mutex);
703 }
704
705 return addr;
706}
707
708void
709CArchNetworkBSD::closeAddr(CArchNetAddress addr)
710{
711 assert(addr != NULL);
712
713 delete addr;
714}
715
716std::string
717CArchNetworkBSD::addrToName(CArchNetAddress addr)
718{
719 assert(addr != NULL);
720
721 // mutexed name lookup (ugh)
722 ARCH->lockMutex(m_mutex);
723 struct hostent* info = gethostbyaddr(
724 reinterpret_cast<const char*>(&addr->m_addr),
725 addr->m_len, addr->m_addr.sa_family);
726 if (info == NULL) {
727 ARCH->unlockMutex(m_mutex);
728 throwNameError(h_errno);
729 }
730
731 // save (primary) name
732 std::string name = info->h_name;
733
734 // done with static buffer
735 ARCH->unlockMutex(m_mutex);
736
737 return name;
738}
739
740std::string
741CArchNetworkBSD::addrToString(CArchNetAddress addr)
742{
743 assert(addr != NULL);
744
745 switch (getAddrFamily(addr)) {
746 case kINET: {
747 struct sockaddr_in* ipAddr =
748 reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
749 ARCH->lockMutex(m_mutex);
750 std::string s = inet_ntoa(ipAddr->sin_addr);
751 ARCH->unlockMutex(m_mutex);
752 return s;
753 }
754
755 default:
756 assert(0 && "unknown address family");
757 return "";
758 }
759}
760
761IArchNetwork::EAddressFamily
762CArchNetworkBSD::getAddrFamily(CArchNetAddress addr)
763{
764 assert(addr != NULL);
765
766 switch (addr->m_addr.sa_family) {
767 case AF_INET:
768 return kINET;
769
770 default:
771 return kUNKNOWN;
772 }
773}
774
775void
776CArchNetworkBSD::setAddrPort(CArchNetAddress addr, int port)
777{
778 assert(addr != NULL);
779
780 switch (getAddrFamily(addr)) {
781 case kINET: {
782 struct sockaddr_in* ipAddr =
783 reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
784 ipAddr->sin_port = htons(port);
785 break;
786 }
787
788 default:
789 assert(0 && "unknown address family");
790 break;
791 }
792}
793
794int
795CArchNetworkBSD::getAddrPort(CArchNetAddress addr)
796{
797 assert(addr != NULL);
798
799 switch (getAddrFamily(addr)) {
800 case kINET: {
801 struct sockaddr_in* ipAddr =
802 reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
803 return ntohs(ipAddr->sin_port);
804 }
805
806 default:
807 assert(0 && "unknown address family");
808 return 0;
809 }
810}
811
812bool
813CArchNetworkBSD::isAnyAddr(CArchNetAddress addr)
814{
815 assert(addr != NULL);
816
817 switch (getAddrFamily(addr)) {
818 case kINET: {
819 struct sockaddr_in* ipAddr =
820 reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
821 return (ipAddr->sin_addr.s_addr == INADDR_ANY &&
822 addr->m_len == sizeof(struct sockaddr_in));
823 }
824
825 default:
826 assert(0 && "unknown address family");
827 return true;
828 }
829}
830
831bool
832CArchNetworkBSD::isEqualAddr(CArchNetAddress a, CArchNetAddress b)
833{
834 return (a->m_len == b->m_len &&
835 memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0);
836}
837
838const int*
839CArchNetworkBSD::getUnblockPipe()
840{
841 CArchMultithreadPosix* mt = CArchMultithreadPosix::getInstance();
842 CArchThread thread = mt->newCurrentThread();
843 const int* p = getUnblockPipeForThread(thread);
844 ARCH->closeThread(thread);
845 return p;
846}
847
848const int*
849CArchNetworkBSD::getUnblockPipeForThread(CArchThread thread)
850{
851 CArchMultithreadPosix* mt = CArchMultithreadPosix::getInstance();
852 int* unblockPipe = (int*)mt->getNetworkDataForThread(thread);
853 if (unblockPipe == NULL) {
854 unblockPipe = new int[2];
855#ifdef __OS2__
856 if (!socketpair(PF_LOCAL, SOCK_STREAM, 0, unblockPipe)) {
857#else
858 if (pipe(unblockPipe) != -1) {
859#endif
860 try {
861 setBlockingOnSocket(unblockPipe[0], false);
862 mt->setNetworkDataForCurrentThread(unblockPipe);
863 }
864 catch (...) {
865 delete[] unblockPipe;
866 unblockPipe = NULL;
867 }
868 }
869 else {
870 delete[] unblockPipe;
871 unblockPipe = NULL;
872 }
873 }
874 return unblockPipe;
875}
876
877void
878CArchNetworkBSD::throwError(int err)
879{
880 switch (err) {
881 case EINTR:
882 ARCH->testCancelThread();
883 throw XArchNetworkInterrupted(new XArchEvalUnix(err));
884
885 case EACCES:
886 case EPERM:
887 throw XArchNetworkAccess(new XArchEvalUnix(err));
888
889 case ENFILE:
890 case EMFILE:
891 case ENODEV:
892 case ENOBUFS:
893 case ENOMEM:
894 case ENETDOWN:
895#if defined(ENOSR)
896 case ENOSR:
897#endif
898 throw XArchNetworkResource(new XArchEvalUnix(err));
899
900 case EPROTOTYPE:
901 case EPROTONOSUPPORT:
902 case EAFNOSUPPORT:
903 case EPFNOSUPPORT:
904 case ESOCKTNOSUPPORT:
905 case EINVAL:
906 case ENOPROTOOPT:
907 case EOPNOTSUPP:
908 case ESHUTDOWN:
909#if defined(ENOPKG)
910 case ENOPKG:
911#endif
912 throw XArchNetworkSupport(new XArchEvalUnix(err));
913
914 case EIO:
915 throw XArchNetworkIO(new XArchEvalUnix(err));
916
917 case EADDRNOTAVAIL:
918 throw XArchNetworkNoAddress(new XArchEvalUnix(err));
919
920 case EADDRINUSE:
921 throw XArchNetworkAddressInUse(new XArchEvalUnix(err));
922
923 case EHOSTUNREACH:
924 case ENETUNREACH:
925 throw XArchNetworkNoRoute(new XArchEvalUnix(err));
926
927 case ENOTCONN:
928 throw XArchNetworkNotConnected(new XArchEvalUnix(err));
929
930 case EPIPE:
931 throw XArchNetworkShutdown(new XArchEvalUnix(err));
932
933 case ECONNABORTED:
934 case ECONNRESET:
935 throw XArchNetworkDisconnected(new XArchEvalUnix(err));
936
937 case ECONNREFUSED:
938 throw XArchNetworkConnectionRefused(new XArchEvalUnix(err));
939
940 case EHOSTDOWN:
941 case ETIMEDOUT:
942 throw XArchNetworkTimedOut(new XArchEvalUnix(err));
943
944 default:
945 throw XArchNetwork(new XArchEvalUnix(err));
946 }
947}
948
949void
950CArchNetworkBSD::throwNameError(int err)
951{
952 static const char* s_msg[] = {
953 "The specified host is unknown",
954 "The requested name is valid but does not have an IP address",
955 "A non-recoverable name server error occurred",
956 "A temporary error occurred on an authoritative name server",
957 "An unknown name server error occurred"
958 };
959
960 switch (err) {
961 case HOST_NOT_FOUND:
962 throw XArchNetworkNameUnknown(s_msg[0]);
963
964 case NO_DATA:
965 throw XArchNetworkNameNoAddress(s_msg[1]);
966
967 case NO_RECOVERY:
968 throw XArchNetworkNameFailure(s_msg[2]);
969
970 case TRY_AGAIN:
971 throw XArchNetworkNameUnavailable(s_msg[3]);
972
973 default:
974 throw XArchNetworkName(s_msg[4]);
975 }
976}
Note: See TracBrowser for help on using the repository browser.