2
* synergy -- mouse and keyboard sharing utility
3
* Copyright (C) 2002 Chris Schoeneman
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.
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.
15
#include "CArchNetworkBSD.h"
17
#include "XArchUnix.h"
19
# include <sys/types.h>
24
#include <netinet/in.h>
26
#if !defined(TCP_NODELAY)
27
# include <netinet/tcp.h>
29
#include <arpa/inet.h>
34
# include <sys/poll.h>
36
# if HAVE_SYS_SELECT_H
37
# include <sys/select.h>
40
# include <sys/time.h>
44
static const int s_family[] = {
48
static const int s_type[] = {
57
CArchNetworkBSD::CArchNetworkBSD()
59
// create mutex to make some calls thread safe
60
m_mutex = ARCH->newMutex();
63
CArchNetworkBSD::~CArchNetworkBSD()
65
ARCH->closeMutex(m_mutex);
69
CArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type)
71
// allocate socket object
72
CArchSocketImpl* newSocket = new CArchSocketImpl;
75
int fd = socket(s_family[family], s_type[type], 0);
81
newSocket->m_connected = false;
82
newSocket->m_refCount = 1;
87
CArchNetworkBSD::copySocket(CArchSocket s)
91
// ref the socket and return it
92
ARCH->lockMutex(m_mutex);
94
ARCH->unlockMutex(m_mutex);
99
CArchNetworkBSD::closeSocket(CArchSocket s)
103
// unref the socket and note if it should be released
104
ARCH->lockMutex(m_mutex);
105
const bool doClose = (--s->m_refCount == 0);
106
ARCH->unlockMutex(m_mutex);
108
// close the socket if necessary
111
if (close(s->m_fd) == -1) {
115
// interrupted system call
116
ARCH->testCancelThread();
120
// restore the last ref and throw
121
ARCH->lockMutex(m_mutex);
123
ARCH->unlockMutex(m_mutex);
132
CArchNetworkBSD::closeSocketForRead(CArchSocket s)
136
if (shutdown(s->m_fd, 0) == -1) {
137
if (errno != ENOTCONN) {
144
CArchNetworkBSD::closeSocketForWrite(CArchSocket s)
148
if (shutdown(s->m_fd, 1) == -1) {
149
if (errno != ENOTCONN) {
156
CArchNetworkBSD::bindSocket(CArchSocket s, CArchNetAddress addr)
159
assert(addr != NULL);
161
if (bind(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
167
CArchNetworkBSD::listenOnSocket(CArchSocket s)
171
// hardcoding backlog
172
if (listen(s->m_fd, 3) == -1) {
178
CArchNetworkBSD::acceptSocket(CArchSocket s, CArchNetAddress* addr)
182
// if user passed NULL in addr then use scratch space
183
CArchNetAddress dummy;
188
// create new socket and address
189
CArchSocketImpl* newSocket = new CArchSocketImpl;
190
*addr = new CArchNetAddressImpl;
195
fd = accept(s->m_fd, &(*addr)->m_addr, &(*addr)->m_len);
199
// interrupted system call
200
ARCH->testCancelThread();
203
if (err == ECONNABORTED) {
204
// connection was aborted; try again
205
ARCH->testCancelThread();
216
newSocket->m_fd = fd;
217
newSocket->m_connected = true;
218
newSocket->m_refCount = 1;
220
// discard address if not requested
221
if (addr == &dummy) {
222
ARCH->closeAddr(dummy);
229
CArchNetworkBSD::connectSocket(CArchSocket s, CArchNetAddress addr)
232
assert(addr != NULL);
235
if (connect(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
236
if (errno == EINTR) {
237
// interrupted system call
238
ARCH->testCancelThread();
242
if (errno == EISCONN) {
247
if (errno == EAGAIN) {
249
throw XArchNetworkConnecting(new XArchEvalUnix(errno));
256
ARCH->lockMutex(m_mutex);
257
s->m_connected = true;
258
ARCH->unlockMutex(m_mutex);
264
CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
266
assert(pe != NULL || num == 0);
268
// return if nothing to do
271
ARCH->sleep(timeout);
276
// allocate space for translated query
277
struct pollfd* pfd = new struct pollfd[num];
280
for (int i = 0; i < num; ++i) {
281
pfd[i].fd = (pe[i].m_socket == NULL) ? -1 : pe[i].m_socket->m_fd;
283
if ((pe[i].m_events & kPOLLIN) != 0) {
284
pfd[i].events |= POLLIN;
286
if ((pe[i].m_events & kPOLLOUT) != 0) {
287
pfd[i].events |= POLLOUT;
294
n = poll(pfd, num, static_cast<int>(1000.0 * timeout));
296
if (errno == EINTR) {
297
// interrupted system call
298
ARCH->testCancelThread();
307
for (int i = 0; i < num; ++i) {
309
if ((pfd[i].revents & POLLIN) != 0) {
310
pe[i].m_revents |= kPOLLIN;
312
if ((pfd[i].revents & POLLOUT) != 0) {
313
pe[i].m_revents |= kPOLLOUT;
315
if ((pfd[i].revents & POLLERR) != 0) {
316
pe[i].m_revents |= kPOLLERR;
318
if ((pfd[i].revents & POLLNVAL) != 0) {
319
pe[i].m_revents |= kPOLLNVAL;
323
// done with translated query
332
CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
337
// prepare sets for select
339
fd_set readSet, writeSet, errSet;
340
fd_set* readSetP = NULL;
341
fd_set* writeSetP = NULL;
342
fd_set* errSetP = NULL;
346
for (i = 0; i < num; ++i) {
347
// reset return flags
350
// set invalid flag if socket is bogus then go to next socket
351
if (pe[i].m_socket == NULL) {
352
pe[i].m_revents |= kPOLLNVAL;
356
int fdi = pe[i].m_socket->m_fd;
357
if (pe[i].m_events & kPOLLIN) {
358
FD_SET(pe[i].m_socket->m_fd, &readSet);
364
if (pe[i].m_events & kPOLLOUT) {
365
FD_SET(pe[i].m_socket->m_fd, &writeSet);
366
writeSetP = &writeSet;
372
FD_SET(pe[i].m_socket->m_fd, &errSet);
380
// if there are no sockets then don't block forever
381
if (n == 0 && timeout < 0.0) {
385
// prepare timeout for select
386
struct timeval timeout2;
387
struct timeval* timeout2P;
392
timeout2P = &timeout2;
393
timeout2.tv_sec = static_cast<int>(timeout);
394
timeout2.tv_usec = static_cast<int>(1.0e+6 *
395
(timeout - timeout2.tv_sec));
399
n = select((SELECT_TYPE_ARG1) n + 1,
400
SELECT_TYPE_ARG234 readSetP,
401
SELECT_TYPE_ARG234 writeSetP,
402
SELECT_TYPE_ARG234 errSetP,
403
SELECT_TYPE_ARG5 timeout2P);
407
if (errno == EINTR) {
408
// interrupted system call
409
ARCH->testCancelThread();
415
for (i = 0; i < num; ++i) {
416
if (pe[i].m_socket != NULL) {
417
if (FD_ISSET(pe[i].m_socket->m_fd, &readSet)) {
418
pe[i].m_revents |= kPOLLIN;
420
if (FD_ISSET(pe[i].m_socket->m_fd, &writeSet)) {
421
pe[i].m_revents |= kPOLLOUT;
423
if (FD_ISSET(pe[i].m_socket->m_fd, &errSet)) {
424
pe[i].m_revents |= kPOLLERR;
427
if (pe[i].m_revents != 0) {
439
CArchNetworkBSD::readSocket(CArchSocket s, void* buf, size_t len)
445
n = read(s->m_fd, buf, len);
447
if (errno == EINTR) {
448
// interrupted system call
449
ARCH->testCancelThread();
455
ARCH->testCancelThread();
460
CArchNetworkBSD::writeSocket(CArchSocket s, const void* buf, size_t len)
466
n = write(s->m_fd, buf, len);
468
if (errno == EINTR) {
469
// interrupted system call
470
ARCH->testCancelThread();
476
ARCH->testCancelThread();
481
CArchNetworkBSD::throwErrorOnSocket(CArchSocket s)
485
// get the error from the socket layer
487
socklen_t size = sizeof(err);
488
if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR, &err, &size) == -1) {
492
// throw if there's an error
499
CArchNetworkBSD::setBlockingOnSocket(CArchSocket s, bool blocking)
503
int mode = fcntl(s->m_fd, F_GETFL, 0);
507
bool old = ((mode & O_NDELAY) == 0);
514
if (fcntl(s->m_fd, F_SETFL, mode) == -1) {
521
CArchNetworkBSD::setNoDelayOnSocket(CArchSocket s, bool noDelay)
527
socklen_t size = sizeof(oflag);
528
if (getsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, &oflag, &size) == -1) {
532
int flag = noDelay ? 1 : 0;
534
if (setsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, &flag, size) == -1) {
542
CArchNetworkBSD::getHostName()
545
if (gethostname(name, sizeof(name)) == -1) {
549
name[sizeof(name) - 1] = '\0';
555
CArchNetworkBSD::newAnyAddr(EAddressFamily family)
558
CArchNetAddressImpl* addr = new CArchNetAddressImpl;
563
struct sockaddr_in* ipAddr =
564
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
565
ipAddr->sin_family = AF_INET;
566
ipAddr->sin_port = 0;
567
ipAddr->sin_addr.s_addr = INADDR_ANY;
568
addr->m_len = sizeof(struct sockaddr_in);
574
assert(0 && "invalid family");
581
CArchNetworkBSD::copyAddr(CArchNetAddress addr)
583
assert(addr != NULL);
585
// allocate and copy address
586
return new CArchNetAddressImpl(*addr);
590
CArchNetworkBSD::nameToAddr(const std::string& name)
593
CArchNetAddressImpl* addr = new CArchNetAddressImpl;
595
// try to convert assuming an IPv4 dot notation address
596
struct sockaddr_in inaddr;
597
memset(&inaddr, 0, sizeof(inaddr));
598
if (inet_aton(name.c_str(), &inaddr.sin_addr) != 0) {
599
// it's a dot notation address
600
addr->m_len = sizeof(struct sockaddr_in);
601
inaddr.sin_family = AF_INET;
603
memcpy(&addr->m_addr, &inaddr, addr->m_len);
607
// mutexed address lookup (ugh)
608
ARCH->lockMutex(m_mutex);
609
struct hostent* info = gethostbyname(name.c_str());
611
ARCH->unlockMutex(m_mutex);
613
throwNameError(h_errno);
616
// copy over address (only IPv4 currently supported)
617
addr->m_len = sizeof(struct sockaddr_in);
618
inaddr.sin_family = info->h_addrtype;
620
memcpy(&inaddr.sin_addr, info->h_addr_list[0], info->h_length);
621
memcpy(&addr->m_addr, &inaddr, addr->m_len);
623
// done with static buffer
624
ARCH->unlockMutex(m_mutex);
631
CArchNetworkBSD::closeAddr(CArchNetAddress addr)
633
assert(addr != NULL);
639
CArchNetworkBSD::addrToName(CArchNetAddress addr)
641
assert(addr != NULL);
643
// mutexed name lookup (ugh)
644
ARCH->lockMutex(m_mutex);
645
struct hostent* info = gethostbyaddr(
646
reinterpret_cast<const char*>(&addr->m_addr),
647
addr->m_len, addr->m_addr.sa_family);
649
ARCH->unlockMutex(m_mutex);
650
throwNameError(h_errno);
653
// save (primary) name
654
std::string name = info->h_name;
656
// done with static buffer
657
ARCH->unlockMutex(m_mutex);
663
CArchNetworkBSD::addrToString(CArchNetAddress addr)
665
assert(addr != NULL);
667
switch (getAddrFamily(addr)) {
669
struct sockaddr_in* ipAddr =
670
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
671
ARCH->lockMutex(m_mutex);
672
std::string s = inet_ntoa(ipAddr->sin_addr);
673
ARCH->unlockMutex(m_mutex);
678
assert(0 && "unknown address family");
683
IArchNetwork::EAddressFamily
684
CArchNetworkBSD::getAddrFamily(CArchNetAddress addr)
686
assert(addr != NULL);
688
switch (addr->m_addr.sa_family) {
698
CArchNetworkBSD::setAddrPort(CArchNetAddress addr, int port)
700
assert(addr != NULL);
702
switch (getAddrFamily(addr)) {
704
struct sockaddr_in* ipAddr =
705
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
706
ipAddr->sin_port = htons(port);
711
assert(0 && "unknown address family");
717
CArchNetworkBSD::getAddrPort(CArchNetAddress addr)
719
assert(addr != NULL);
721
switch (getAddrFamily(addr)) {
723
struct sockaddr_in* ipAddr =
724
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
725
return ntohs(ipAddr->sin_port);
729
assert(0 && "unknown address family");
735
CArchNetworkBSD::isAnyAddr(CArchNetAddress addr)
737
assert(addr != NULL);
739
switch (getAddrFamily(addr)) {
741
struct sockaddr_in* ipAddr =
742
reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
743
return (ipAddr->sin_addr.s_addr == INADDR_ANY &&
744
addr->m_len == sizeof(struct sockaddr_in));
748
assert(0 && "unknown address family");
754
CArchNetworkBSD::throwError(int err)
758
throw XArchNetworkWouldBlock(new XArchEvalUnix(err));
762
throw XArchNetworkAccess(new XArchEvalUnix(err));
773
throw XArchNetworkResource(new XArchEvalUnix(err));
776
case EPROTONOSUPPORT:
779
case ESOCKTNOSUPPORT:
787
throw XArchNetworkSupport(new XArchEvalUnix(err));
790
throw XArchNetworkIO(new XArchEvalUnix(err));
793
throw XArchNetworkNoAddress(new XArchEvalUnix(err));
796
throw XArchNetworkAddressInUse(new XArchEvalUnix(err));
800
throw XArchNetworkNoRoute(new XArchEvalUnix(err));
803
throw XArchNetworkNotConnected(new XArchEvalUnix(err));
808
throw XArchNetworkDisconnected(new XArchEvalUnix(err));
811
throw XArchNetworkConnectionRefused(new XArchEvalUnix(err));
815
throw XArchNetworkConnecting(new XArchEvalUnix(err));
819
throw XArchNetworkTimedOut(new XArchEvalUnix(err));
822
throw XArchNetwork(new XArchEvalUnix(err));
827
CArchNetworkBSD::throwNameError(int err)
829
static const char* s_msg[] = {
830
"The specified host is unknown",
831
"The requested name is valid but does not have an IP address",
832
"A non-recoverable name server error occurred",
833
"A temporary error occurred on an authoritative name server",
834
"An unknown name server error occurred"
839
throw XArchNetworkNameUnknown(s_msg[0]);
842
throw XArchNetworkNameNoAddress(s_msg[1]);
845
throw XArchNetworkNameFailure(s_msg[2]);
848
throw XArchNetworkNameUnavailable(s_msg[3]);
851
throw XArchNetworkName(s_msg[4]);