2012-06-10 16:50:54 +00:00
|
|
|
/*
|
|
|
|
|
* synergy -- mouse and keyboard sharing utility
|
2016-09-07 14:24:00 +00:00
|
|
|
* Copyright (C) 2012-2016 Symless Ltd.
|
2012-09-04 02:09:56 +00:00
|
|
|
* Copyright (C) 2002 Chris Schoeneman
|
2024-07-02 19:07:06 +00:00
|
|
|
*
|
2012-06-10 16:50:54 +00:00
|
|
|
* This package is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
2015-05-03 02:33:52 +00:00
|
|
|
* found in the file LICENSE that should have accompanied this file.
|
2024-07-02 19:07:06 +00:00
|
|
|
*
|
2012-06-10 16:50:54 +00:00
|
|
|
* This package is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2014-02-28 12:55:14 +00:00
|
|
|
#include "arch/unix/ArchNetworkBSD.h"
|
|
|
|
|
|
2018-03-20 13:53:38 +00:00
|
|
|
#include "arch/Arch.h"
|
2014-02-28 12:55:14 +00:00
|
|
|
#include "arch/unix/ArchMultithreadPosix.h"
|
|
|
|
|
#include "arch/unix/XArchUnix.h"
|
2014-02-28 12:36:45 +00:00
|
|
|
|
2012-06-10 16:50:54 +00:00
|
|
|
#if HAVE_UNISTD_H
|
2024-07-02 19:07:06 +00:00
|
|
|
#include <unistd.h>
|
2012-06-10 16:50:54 +00:00
|
|
|
#endif
|
|
|
|
|
#include <netdb.h>
|
2018-03-20 13:53:38 +00:00
|
|
|
#include <netinet/in.h>
|
2012-06-10 16:50:54 +00:00
|
|
|
#if !defined(TCP_NODELAY)
|
2024-07-02 19:07:06 +00:00
|
|
|
#include <netinet/tcp.h>
|
2012-06-10 16:50:54 +00:00
|
|
|
#endif
|
|
|
|
|
#include <arpa/inet.h>
|
2024-07-02 19:07:06 +00:00
|
|
|
#include <cstring>
|
2012-06-10 16:50:54 +00:00
|
|
|
#include <errno.h>
|
2018-03-20 13:53:38 +00:00
|
|
|
#include <fcntl.h>
|
2012-06-10 16:50:54 +00:00
|
|
|
|
|
|
|
|
#if !HAVE_INET_ATON
|
2024-07-02 19:07:06 +00:00
|
|
|
#include <stdio.h>
|
2012-06-10 16:50:54 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static const int s_family[] = {
|
2016-12-28 11:50:32 +00:00
|
|
|
PF_UNSPEC,
|
2018-03-20 13:53:38 +00:00
|
|
|
PF_INET,
|
|
|
|
|
PF_INET6,
|
2012-06-10 16:50:54 +00:00
|
|
|
};
|
2024-07-02 19:07:06 +00:00
|
|
|
static const int s_type[] = {SOCK_DGRAM, SOCK_STREAM};
|
2012-06-10 16:50:54 +00:00
|
|
|
|
|
|
|
|
#if !HAVE_INET_ATON
|
|
|
|
|
// parse dotted quad addresses. we don't bother with the weird BSD'ism
|
|
|
|
|
// of handling octal and hex and partial forms.
|
2024-07-02 19:07:06 +00:00
|
|
|
static in_addr_t inet_aton(const char *cp, struct in_addr *inp) {
|
|
|
|
|
unsigned int a, b, c, d;
|
|
|
|
|
if (sscanf(cp, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (a >= 256 || b >= 256 || c >= 256 || d >= 256) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
unsigned char *incp = (unsigned char *)inp;
|
|
|
|
|
incp[0] = (unsigned char)(a & 0xffu);
|
|
|
|
|
incp[1] = (unsigned char)(b & 0xffu);
|
|
|
|
|
incp[2] = (unsigned char)(c & 0xffu);
|
|
|
|
|
incp[3] = (unsigned char)(d & 0xffu);
|
|
|
|
|
return inp->s_addr;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//
|
2014-11-11 13:51:47 +00:00
|
|
|
// ArchNetworkBSD
|
2012-06-10 16:50:54 +00:00
|
|
|
//
|
2013-07-24 16:41:12 +00:00
|
|
|
|
2021-01-15 11:24:31 +00:00
|
|
|
ArchNetworkBSD::Connectors ArchNetworkBSD::s_connectors;
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
ArchNetworkBSD::ArchNetworkBSD() = default;
|
2013-07-24 16:41:12 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
ArchNetworkBSD::~ArchNetworkBSD() {
|
|
|
|
|
if (m_mutex)
|
|
|
|
|
ARCH->closeMutex(m_mutex);
|
2013-07-24 16:41:12 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
void ArchNetworkBSD::init() {
|
|
|
|
|
// create mutex to make some calls thread safe
|
|
|
|
|
m_mutex = ARCH->newMutex();
|
2013-07-24 16:41:12 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
ArchSocket ArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type) {
|
|
|
|
|
// create socket
|
|
|
|
|
int fd = socket(s_family[family], s_type[type], 0);
|
|
|
|
|
if (fd == -1) {
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
setBlockingOnSocket(fd, false);
|
|
|
|
|
} catch (...) {
|
|
|
|
|
close(fd);
|
|
|
|
|
throw;
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// allocate socket object
|
|
|
|
|
auto *newSocket = new ArchSocketImpl;
|
|
|
|
|
newSocket->m_fd = fd;
|
|
|
|
|
newSocket->m_refCount = 1;
|
|
|
|
|
return newSocket;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
ArchSocket ArchNetworkBSD::copySocket(ArchSocket s) {
|
|
|
|
|
assert(s != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// ref the socket and return it
|
|
|
|
|
ARCH->lockMutex(m_mutex);
|
|
|
|
|
++s->m_refCount;
|
|
|
|
|
ARCH->unlockMutex(m_mutex);
|
|
|
|
|
return s;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
void ArchNetworkBSD::closeSocket(ArchSocket s) {
|
|
|
|
|
assert(s != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// unref the socket and note if it should be released
|
|
|
|
|
ARCH->lockMutex(m_mutex);
|
|
|
|
|
const bool doClose = (--s->m_refCount == 0);
|
|
|
|
|
ARCH->unlockMutex(m_mutex);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// close the socket if necessary
|
|
|
|
|
if (doClose) {
|
|
|
|
|
if (close(s->m_fd) == -1) {
|
|
|
|
|
// close failed. restore the last ref and throw.
|
|
|
|
|
int err = errno;
|
|
|
|
|
ARCH->lockMutex(m_mutex);
|
|
|
|
|
++s->m_refCount;
|
|
|
|
|
ARCH->unlockMutex(m_mutex);
|
|
|
|
|
throwError(err);
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
delete s;
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
void ArchNetworkBSD::closeSocketForRead(ArchSocket s) {
|
|
|
|
|
assert(s != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
if (shutdown(s->m_fd, 0) == -1) {
|
|
|
|
|
if (errno != ENOTCONN) {
|
|
|
|
|
throwError(errno);
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
void ArchNetworkBSD::closeSocketForWrite(ArchSocket s) {
|
|
|
|
|
assert(s != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
if (shutdown(s->m_fd, 1) == -1) {
|
|
|
|
|
if (errno != ENOTCONN) {
|
|
|
|
|
throwError(errno);
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
void ArchNetworkBSD::bindSocket(ArchSocket s, ArchNetAddress addr) {
|
|
|
|
|
assert(s != NULL);
|
|
|
|
|
assert(addr != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
if (bind(s->m_fd, TYPED_ADDR(struct sockaddr, addr), addr->m_len) == -1) {
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
void ArchNetworkBSD::listenOnSocket(ArchSocket s) {
|
|
|
|
|
assert(s != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// hardcoding backlog
|
|
|
|
|
if (listen(s->m_fd, 3) == -1) {
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
ArchSocket ArchNetworkBSD::acceptSocket(ArchSocket s, ArchNetAddress *addr) {
|
|
|
|
|
assert(s != NULL);
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// if user passed NULL in addr then use scratch space
|
|
|
|
|
ArchNetAddress dummy;
|
|
|
|
|
if (addr == nullptr) {
|
|
|
|
|
addr = &dummy;
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// create new socket and address
|
|
|
|
|
auto *newSocket = new ArchSocketImpl;
|
|
|
|
|
*addr = new ArchNetAddressImpl;
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// accept on socket
|
|
|
|
|
auto len = ((*addr)->m_len);
|
|
|
|
|
int fd = accept(s->m_fd, TYPED_ADDR(struct sockaddr, (*addr)), &len);
|
|
|
|
|
(*addr)->m_len = len;
|
|
|
|
|
if (fd == -1) {
|
|
|
|
|
int err = errno;
|
|
|
|
|
delete newSocket;
|
|
|
|
|
delete *addr;
|
|
|
|
|
*addr = nullptr;
|
|
|
|
|
if (err == EAGAIN) {
|
|
|
|
|
return nullptr;
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
throwError(err);
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
try {
|
|
|
|
|
setBlockingOnSocket(fd, false);
|
|
|
|
|
} catch (...) {
|
|
|
|
|
close(fd);
|
|
|
|
|
delete newSocket;
|
|
|
|
|
delete *addr;
|
|
|
|
|
*addr = nullptr;
|
|
|
|
|
throw;
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// initialize socket
|
|
|
|
|
newSocket->m_fd = fd;
|
|
|
|
|
newSocket->m_refCount = 1;
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// discard address if not requested
|
|
|
|
|
if (addr == &dummy) {
|
|
|
|
|
ARCH->closeAddr(dummy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return newSocket;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
bool ArchNetworkBSD::connectSocket(ArchSocket s, ArchNetAddress addr) {
|
|
|
|
|
assert(s != NULL);
|
|
|
|
|
assert(addr != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
if (connect(s->m_fd, TYPED_ADDR(struct sockaddr, addr), addr->m_len) == -1) {
|
|
|
|
|
if (errno == EISCONN) {
|
|
|
|
|
return true;
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
if (errno == EINPROGRESS) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if HAVE_POLL
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
int ArchNetworkBSD::pollSocket(PollEntry pe[], int num, double timeout) {
|
|
|
|
|
assert(pe != NULL || num == 0);
|
|
|
|
|
|
|
|
|
|
// return if nothing to do
|
|
|
|
|
if (num == 0) {
|
|
|
|
|
if (timeout > 0.0) {
|
|
|
|
|
ARCH->sleep(timeout);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// allocate space for translated query
|
|
|
|
|
auto *pfd = new struct pollfd[1 + num];
|
|
|
|
|
|
|
|
|
|
// translate query
|
|
|
|
|
for (int i = 0; i < num; ++i) {
|
|
|
|
|
pfd[i].fd = (pe[i].m_socket == nullptr) ? -1 : pe[i].m_socket->m_fd;
|
|
|
|
|
pfd[i].events = 0;
|
|
|
|
|
if ((pe[i].m_events & kPOLLIN) != 0) {
|
|
|
|
|
pfd[i].events |= POLLIN;
|
|
|
|
|
}
|
|
|
|
|
if ((pe[i].m_events & kPOLLOUT) != 0) {
|
|
|
|
|
pfd[i].events |= POLLOUT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
int n = num;
|
|
|
|
|
|
|
|
|
|
// add the unblock pipe
|
|
|
|
|
const int *unblockPipe = getUnblockPipe();
|
|
|
|
|
if (unblockPipe != nullptr) {
|
|
|
|
|
pfd[n].fd = unblockPipe[0];
|
|
|
|
|
pfd[n].events = POLLIN;
|
|
|
|
|
++n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// prepare timeout
|
|
|
|
|
int t = (timeout < 0.0) ? -1 : static_cast<int>(1000.0 * timeout);
|
|
|
|
|
|
|
|
|
|
// do the poll
|
|
|
|
|
n = s_connectors.poll_impl(pfd, n, t);
|
|
|
|
|
|
|
|
|
|
// reset the unblock pipe
|
|
|
|
|
if (n > 0 && unblockPipe != nullptr && (pfd[num].revents & POLLIN) != 0) {
|
|
|
|
|
// the unblock event was signalled. flush the pipe.
|
|
|
|
|
char dummy[100];
|
|
|
|
|
int ignore;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
ignore = read(unblockPipe[0], dummy, sizeof(dummy));
|
|
|
|
|
} while (errno != EAGAIN);
|
|
|
|
|
|
|
|
|
|
// don't count this unblock pipe in return value
|
|
|
|
|
--n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handle results
|
|
|
|
|
if (n == -1) {
|
|
|
|
|
if (errno == EINTR) {
|
|
|
|
|
// interrupted system call
|
|
|
|
|
ARCH->testCancelThread();
|
|
|
|
|
delete[] pfd;
|
|
|
|
|
return 0;
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
delete[] pfd;
|
|
|
|
|
throwError(errno);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// translate back
|
|
|
|
|
for (int i = 0; i < num; ++i) {
|
|
|
|
|
pe[i].m_revents = 0;
|
|
|
|
|
if ((pfd[i].revents & POLLIN) != 0) {
|
|
|
|
|
pe[i].m_revents |= kPOLLIN;
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
if ((pfd[i].revents & POLLOUT) != 0) {
|
|
|
|
|
pe[i].m_revents |= kPOLLOUT;
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
if ((pfd[i].revents & POLLERR) != 0) {
|
|
|
|
|
pe[i].m_revents |= kPOLLERR;
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
if ((pfd[i].revents & POLLNVAL) != 0) {
|
|
|
|
|
pe[i].m_revents |= kPOLLNVAL;
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
delete[] pfd;
|
|
|
|
|
return n;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
int ArchNetworkBSD::pollSocket(PollEntry pe[], int num, double timeout) {
|
|
|
|
|
int i, n;
|
|
|
|
|
|
|
|
|
|
// prepare sets for select
|
|
|
|
|
n = 0;
|
|
|
|
|
fd_set readSet, writeSet, errSet;
|
|
|
|
|
fd_set *readSetP = NULL;
|
|
|
|
|
fd_set *writeSetP = NULL;
|
|
|
|
|
fd_set *errSetP = NULL;
|
|
|
|
|
FD_ZERO(&readSet);
|
|
|
|
|
FD_ZERO(&writeSet);
|
|
|
|
|
FD_ZERO(&errSet);
|
|
|
|
|
for (i = 0; i < num; ++i) {
|
|
|
|
|
// reset return flags
|
|
|
|
|
pe[i].m_revents = 0;
|
|
|
|
|
|
|
|
|
|
// set invalid flag if socket is bogus then go to next socket
|
|
|
|
|
if (pe[i].m_socket == NULL) {
|
|
|
|
|
pe[i].m_revents |= kPOLLNVAL;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int fdi = pe[i].m_socket->m_fd;
|
|
|
|
|
if (pe[i].m_events & kPOLLIN) {
|
|
|
|
|
FD_SET(pe[i].m_socket->m_fd, &readSet);
|
|
|
|
|
readSetP = &readSet;
|
|
|
|
|
if (fdi > n) {
|
|
|
|
|
n = fdi;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (pe[i].m_events & kPOLLOUT) {
|
|
|
|
|
FD_SET(pe[i].m_socket->m_fd, &writeSet);
|
|
|
|
|
writeSetP = &writeSet;
|
|
|
|
|
if (fdi > n) {
|
|
|
|
|
n = fdi;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (true) {
|
|
|
|
|
FD_SET(pe[i].m_socket->m_fd, &errSet);
|
|
|
|
|
errSetP = &errSet;
|
|
|
|
|
if (fdi > n) {
|
|
|
|
|
n = fdi;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// add the unblock pipe
|
|
|
|
|
const int *unblockPipe = getUnblockPipe();
|
|
|
|
|
if (unblockPipe != NULL) {
|
|
|
|
|
FD_SET(unblockPipe[0], &readSet);
|
|
|
|
|
readSetP = &readSet;
|
|
|
|
|
if (unblockPipe[0] > n) {
|
|
|
|
|
n = unblockPipe[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if there are no sockets then don't block forever
|
|
|
|
|
if (n == 0 && timeout < 0.0) {
|
|
|
|
|
timeout = 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// prepare timeout for select
|
|
|
|
|
struct timeval timeout2;
|
|
|
|
|
struct timeval *timeout2P;
|
|
|
|
|
if (timeout < 0.0) {
|
|
|
|
|
timeout2P = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
timeout2P = &timeout2;
|
|
|
|
|
timeout2.tv_sec = static_cast<int>(timeout);
|
|
|
|
|
timeout2.tv_usec = static_cast<int>(1.0e+6 * (timeout - timeout2.tv_sec));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do the select
|
|
|
|
|
n = select((SELECT_TYPE_ARG1)n + 1, SELECT_TYPE_ARG234 readSetP,
|
|
|
|
|
SELECT_TYPE_ARG234 writeSetP, SELECT_TYPE_ARG234 errSetP,
|
|
|
|
|
SELECT_TYPE_ARG5 timeout2P);
|
|
|
|
|
|
|
|
|
|
// reset the unblock pipe
|
|
|
|
|
if (n > 0 && unblockPipe != NULL && FD_ISSET(unblockPipe[0], &readSet)) {
|
|
|
|
|
// the unblock event was signalled. flush the pipe.
|
|
|
|
|
char dummy[100];
|
|
|
|
|
do {
|
|
|
|
|
read(unblockPipe[0], dummy, sizeof(dummy));
|
|
|
|
|
} while (errno != EAGAIN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handle results
|
|
|
|
|
if (n == -1) {
|
|
|
|
|
if (errno == EINTR) {
|
|
|
|
|
// interrupted system call
|
|
|
|
|
ARCH->testCancelThread();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
|
|
|
|
n = 0;
|
|
|
|
|
for (i = 0; i < num; ++i) {
|
|
|
|
|
if (pe[i].m_socket != NULL) {
|
|
|
|
|
if (FD_ISSET(pe[i].m_socket->m_fd, &readSet)) {
|
|
|
|
|
pe[i].m_revents |= kPOLLIN;
|
|
|
|
|
}
|
|
|
|
|
if (FD_ISSET(pe[i].m_socket->m_fd, &writeSet)) {
|
|
|
|
|
pe[i].m_revents |= kPOLLOUT;
|
|
|
|
|
}
|
|
|
|
|
if (FD_ISSET(pe[i].m_socket->m_fd, &errSet)) {
|
|
|
|
|
pe[i].m_revents |= kPOLLERR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (pe[i].m_revents != 0) {
|
|
|
|
|
++n;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return n;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
void ArchNetworkBSD::unblockPollSocket(ArchThread thread) {
|
|
|
|
|
const int *unblockPipe = getUnblockPipeForThread(thread);
|
|
|
|
|
if (unblockPipe != nullptr) {
|
|
|
|
|
char dummy = 0;
|
|
|
|
|
int ignore;
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
ignore = write(unblockPipe[1], &dummy, 1);
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
size_t ArchNetworkBSD::readSocket(ArchSocket s, void *buf, size_t len) {
|
|
|
|
|
assert(s != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
ssize_t n = read(s->m_fd, buf, len);
|
|
|
|
|
if (n == -1) {
|
|
|
|
|
if (errno == EINTR || errno == EAGAIN) {
|
|
|
|
|
return 0;
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2024-07-02 19:07:06 +00:00
|
|
|
throwError(errno);
|
|
|
|
|
}
|
|
|
|
|
return n;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
size_t ArchNetworkBSD::writeSocket(ArchSocket s, const void *buf, size_t len) {
|
|
|
|
|
assert(s != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
ssize_t n = write(s->m_fd, buf, len);
|
|
|
|
|
if (n == -1) {
|
|
|
|
|
if (errno == EINTR || errno == EAGAIN) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ArchNetworkBSD::throwErrorOnSocket(ArchSocket s) {
|
|
|
|
|
assert(s != NULL);
|
|
|
|
|
|
|
|
|
|
// get the error from the socket layer
|
|
|
|
|
int err = 0;
|
|
|
|
|
auto size = static_cast<socklen_t>(sizeof(err));
|
|
|
|
|
if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR,
|
|
|
|
|
reinterpret_cast<optval_t *>(&err), &size) == -1) {
|
|
|
|
|
err = errno;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// throw if there's an error
|
|
|
|
|
if (err != 0) {
|
|
|
|
|
throwError(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ArchNetworkBSD::setBlockingOnSocket(int fd, bool blocking) {
|
|
|
|
|
assert(fd != -1);
|
|
|
|
|
|
|
|
|
|
int mode = fcntl(fd, F_GETFL, 0);
|
|
|
|
|
if (mode == -1) {
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
|
|
|
|
if (blocking) {
|
|
|
|
|
mode &= ~O_NONBLOCK;
|
|
|
|
|
} else {
|
|
|
|
|
mode |= O_NONBLOCK;
|
|
|
|
|
}
|
|
|
|
|
if (fcntl(fd, F_SETFL, mode) == -1) {
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ArchNetworkBSD::setNoDelayOnSocket(ArchSocket s, bool noDelay) {
|
|
|
|
|
assert(s != NULL);
|
|
|
|
|
|
|
|
|
|
// get old state
|
|
|
|
|
int oflag;
|
|
|
|
|
auto size = static_cast<socklen_t>(sizeof(oflag));
|
|
|
|
|
if (getsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY,
|
|
|
|
|
reinterpret_cast<optval_t *>(&oflag), &size) == -1) {
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int flag = noDelay ? 1 : 0;
|
|
|
|
|
size = static_cast<socklen_t>(sizeof(flag));
|
|
|
|
|
if (setsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY,
|
|
|
|
|
reinterpret_cast<optval_t *>(&flag), size) == -1) {
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (oflag != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ArchNetworkBSD::setReuseAddrOnSocket(ArchSocket s, bool reuse) {
|
|
|
|
|
assert(s != NULL);
|
|
|
|
|
|
|
|
|
|
// get old state
|
|
|
|
|
int oflag;
|
|
|
|
|
auto size = static_cast<socklen_t>(sizeof(oflag));
|
|
|
|
|
if (getsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR,
|
|
|
|
|
reinterpret_cast<optval_t *>(&oflag), &size) == -1) {
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int flag = reuse ? 1 : 0;
|
|
|
|
|
size = static_cast<socklen_t>(sizeof(flag));
|
|
|
|
|
if (setsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR,
|
|
|
|
|
reinterpret_cast<optval_t *>(&flag), size) == -1) {
|
|
|
|
|
throwError(errno);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (oflag != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string ArchNetworkBSD::getHostName() {
|
|
|
|
|
char name[256];
|
|
|
|
|
if (gethostname(name, sizeof(name)) == -1) {
|
|
|
|
|
name[0] = '\0';
|
|
|
|
|
} else {
|
|
|
|
|
name[sizeof(name) - 1] = '\0';
|
|
|
|
|
}
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ArchNetAddress ArchNetworkBSD::newAnyAddr(EAddressFamily family) {
|
|
|
|
|
// allocate address
|
|
|
|
|
auto *addr = new ArchNetAddressImpl;
|
|
|
|
|
|
|
|
|
|
// fill it in
|
|
|
|
|
switch (family) {
|
|
|
|
|
case kINET: {
|
|
|
|
|
auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
|
|
|
|
ipAddr->sin_family = AF_INET;
|
|
|
|
|
ipAddr->sin_port = 0;
|
|
|
|
|
ipAddr->sin_addr.s_addr = INADDR_ANY;
|
|
|
|
|
addr->m_len = static_cast<socklen_t>(sizeof(struct sockaddr_in));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case kINET6: {
|
|
|
|
|
struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
|
|
|
|
ipAddr->sin6_family = AF_INET6;
|
|
|
|
|
ipAddr->sin6_port = 0;
|
|
|
|
|
memcpy(&ipAddr->sin6_addr, &in6addr_any, sizeof(in6addr_any));
|
|
|
|
|
addr->m_len = (socklen_t)sizeof(struct sockaddr_in6);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
delete addr;
|
|
|
|
|
assert(0 && "invalid family");
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
return addr;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
ArchNetAddress ArchNetworkBSD::copyAddr(ArchNetAddress addr) {
|
|
|
|
|
assert(addr != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// allocate and copy address
|
|
|
|
|
return new ArchNetAddressImpl(*addr);
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
std::vector<ArchNetAddress>
|
|
|
|
|
ArchNetworkBSD::nameToAddr(const std::string &name) {
|
|
|
|
|
struct addrinfo hints;
|
|
|
|
|
struct in6_addr serveraddr;
|
|
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
|
hints.ai_flags = AI_NUMERICSERV;
|
|
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
|
|
|
|
|
|
if (inet_pton(AF_INET, name.c_str(), &serveraddr) == 1) {
|
|
|
|
|
hints.ai_family = AF_INET;
|
|
|
|
|
hints.ai_flags |= AI_NUMERICHOST;
|
|
|
|
|
} else if (inet_pton(AF_INET6, name.c_str(), &serveraddr) == 1) {
|
|
|
|
|
hints.ai_family = AF_INET6;
|
|
|
|
|
hints.ai_flags |= AI_NUMERICHOST;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// done with static buffer
|
|
|
|
|
ARCH->lockMutex(m_mutex);
|
|
|
|
|
struct addrinfo *pResult = nullptr;
|
|
|
|
|
int ret = getaddrinfo(name.c_str(), nullptr, &hints, &pResult);
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
ARCH->unlockMutex(m_mutex);
|
|
|
|
|
throwNameError(ret);
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// allocate address
|
|
|
|
|
std::vector<ArchNetAddressImpl *> addresses;
|
|
|
|
|
for (auto address = pResult; address != nullptr; address = address->ai_next) {
|
|
|
|
|
addresses.push_back(new ArchNetAddressImpl);
|
|
|
|
|
if (address->ai_family == AF_INET) {
|
|
|
|
|
addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in);
|
|
|
|
|
} else {
|
|
|
|
|
addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in6);
|
2016-12-28 11:50:32 +00:00
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
memcpy(&addresses.back()->m_addr, address->ai_addr,
|
|
|
|
|
addresses.back()->m_len);
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
freeaddrinfo(pResult);
|
|
|
|
|
ARCH->unlockMutex(m_mutex);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
return addresses;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
void ArchNetworkBSD::closeAddr(ArchNetAddress addr) {
|
|
|
|
|
assert(addr != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
delete addr;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
std::string ArchNetworkBSD::addrToName(ArchNetAddress addr) {
|
|
|
|
|
assert(addr != NULL);
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// mutexed name lookup (ugh)
|
|
|
|
|
ARCH->lockMutex(m_mutex);
|
|
|
|
|
char host[1024];
|
|
|
|
|
char service[20];
|
|
|
|
|
int ret = getnameinfo(TYPED_ADDR(struct sockaddr, addr), addr->m_len, host,
|
|
|
|
|
sizeof(host), service, sizeof(service), 0);
|
|
|
|
|
if (ret != 0) {
|
2018-03-20 13:53:38 +00:00
|
|
|
ARCH->unlockMutex(m_mutex);
|
2024-07-02 19:07:06 +00:00
|
|
|
throwNameError(ret);
|
|
|
|
|
}
|
2016-12-28 11:50:32 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// save (primary) name
|
|
|
|
|
std::string name = host;
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
// done with static buffer
|
|
|
|
|
ARCH->unlockMutex(m_mutex);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
return name;
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
std::string ArchNetworkBSD::addrToString(ArchNetAddress addr) {
|
|
|
|
|
assert(addr != NULL);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
switch (getAddrFamily(addr)) {
|
|
|
|
|
case kINET: {
|
|
|
|
|
auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
2016-12-28 11:50:32 +00:00
|
|
|
ARCH->lockMutex(m_mutex);
|
2024-07-02 19:07:06 +00:00
|
|
|
std::string s = inet_ntoa(ipAddr->sin_addr);
|
2016-12-28 11:50:32 +00:00
|
|
|
ARCH->unlockMutex(m_mutex);
|
2024-07-02 19:07:06 +00:00
|
|
|
return s;
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case kINET6: {
|
|
|
|
|
char strAddr[INET6_ADDRSTRLEN];
|
|
|
|
|
struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
|
|
|
|
ARCH->lockMutex(m_mutex);
|
|
|
|
|
inet_ntop(AF_INET6, &ipAddr->sin6_addr, strAddr, INET6_ADDRSTRLEN);
|
|
|
|
|
ARCH->unlockMutex(m_mutex);
|
|
|
|
|
return strAddr;
|
|
|
|
|
}
|
2018-03-20 13:53:38 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
default:
|
|
|
|
|
assert(0 && "unknown address family");
|
|
|
|
|
return "";
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IArchNetwork::EAddressFamily
|
2024-07-02 19:07:06 +00:00
|
|
|
ArchNetworkBSD::getAddrFamily(ArchNetAddress addr) {
|
|
|
|
|
assert(addr != NULL);
|
|
|
|
|
|
|
|
|
|
switch (addr->m_addr.ss_family) {
|
|
|
|
|
case AF_INET:
|
|
|
|
|
return kINET;
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
return kINET6;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return kUNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ArchNetworkBSD::setAddrPort(ArchNetAddress addr, int port) {
|
|
|
|
|
assert(addr != NULL);
|
|
|
|
|
|
|
|
|
|
switch (getAddrFamily(addr)) {
|
|
|
|
|
case kINET: {
|
|
|
|
|
auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
|
|
|
|
ipAddr->sin_port = htons(port);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case kINET6: {
|
|
|
|
|
struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
|
|
|
|
ipAddr->sin6_port = htons(port);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0 && "unknown address family");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ArchNetworkBSD::getAddrPort(ArchNetAddress addr) {
|
|
|
|
|
assert(addr != NULL);
|
|
|
|
|
|
|
|
|
|
switch (getAddrFamily(addr)) {
|
|
|
|
|
case kINET: {
|
|
|
|
|
auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
|
|
|
|
return ntohs(ipAddr->sin_port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case kINET6: {
|
|
|
|
|
struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
|
|
|
|
return ntohs(ipAddr->sin6_port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0 && "unknown address family");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ArchNetworkBSD::isAnyAddr(ArchNetAddress addr) {
|
|
|
|
|
assert(addr != NULL);
|
|
|
|
|
|
|
|
|
|
switch (getAddrFamily(addr)) {
|
|
|
|
|
case kINET: {
|
|
|
|
|
auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
|
|
|
|
return (ipAddr->sin_addr.s_addr == INADDR_ANY &&
|
|
|
|
|
addr->m_len == static_cast<socklen_t>(sizeof(struct sockaddr_in)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case kINET6: {
|
|
|
|
|
struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
|
|
|
|
return (addr->m_len == (socklen_t)sizeof(struct sockaddr_in6) &&
|
|
|
|
|
memcmp(static_cast<const void *>(&ipAddr->sin6_addr),
|
|
|
|
|
static_cast<const void *>(&in6addr_any),
|
|
|
|
|
sizeof(in6_addr)) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0 && "unknown address family");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ArchNetworkBSD::isEqualAddr(ArchNetAddress a, ArchNetAddress b) {
|
|
|
|
|
return (a->m_len == b->m_len &&
|
|
|
|
|
memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int *ArchNetworkBSD::getUnblockPipe() {
|
|
|
|
|
ArchMultithreadPosix *mt = ArchMultithreadPosix::getInstance();
|
|
|
|
|
ArchThread thread = mt->newCurrentThread();
|
|
|
|
|
const int *p = getUnblockPipeForThread(thread);
|
|
|
|
|
ARCH->closeThread(thread);
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int *ArchNetworkBSD::getUnblockPipeForThread(ArchThread thread) {
|
|
|
|
|
ArchMultithreadPosix *mt = ArchMultithreadPosix::getInstance();
|
|
|
|
|
auto *unblockPipe = static_cast<int *>(mt->getNetworkDataForThread(thread));
|
|
|
|
|
if (unblockPipe == nullptr) {
|
|
|
|
|
unblockPipe = new int[2];
|
|
|
|
|
if (pipe(unblockPipe) != -1) {
|
|
|
|
|
try {
|
|
|
|
|
setBlockingOnSocket(unblockPipe[0], false);
|
|
|
|
|
mt->setNetworkDataForCurrentThread(unblockPipe);
|
|
|
|
|
} catch (...) {
|
|
|
|
|
delete[] unblockPipe;
|
|
|
|
|
unblockPipe = nullptr;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
delete[] unblockPipe;
|
|
|
|
|
unblockPipe = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return unblockPipe;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ArchNetworkBSD::throwError(int err) {
|
|
|
|
|
switch (err) {
|
|
|
|
|
case EINTR:
|
|
|
|
|
ARCH->testCancelThread();
|
|
|
|
|
throw XArchNetworkInterrupted(new XArchEvalUnix(err));
|
|
|
|
|
|
|
|
|
|
case EACCES:
|
|
|
|
|
case EPERM:
|
|
|
|
|
throw XArchNetworkAccess(new XArchEvalUnix(err));
|
|
|
|
|
|
|
|
|
|
case ENFILE:
|
|
|
|
|
case EMFILE:
|
|
|
|
|
case ENODEV:
|
|
|
|
|
case ENOBUFS:
|
|
|
|
|
case ENOMEM:
|
|
|
|
|
case ENETDOWN:
|
2012-06-10 16:50:54 +00:00
|
|
|
#if defined(ENOSR)
|
2024-07-02 19:07:06 +00:00
|
|
|
case ENOSR:
|
2012-06-10 16:50:54 +00:00
|
|
|
#endif
|
2024-07-02 19:07:06 +00:00
|
|
|
throw XArchNetworkResource(new XArchEvalUnix(err));
|
|
|
|
|
|
|
|
|
|
case EPROTOTYPE:
|
|
|
|
|
case EPROTONOSUPPORT:
|
|
|
|
|
case EAFNOSUPPORT:
|
|
|
|
|
case EPFNOSUPPORT:
|
|
|
|
|
case ESOCKTNOSUPPORT:
|
|
|
|
|
case EINVAL:
|
|
|
|
|
case ENOPROTOOPT:
|
|
|
|
|
case EOPNOTSUPP:
|
|
|
|
|
case ESHUTDOWN:
|
2012-06-10 16:50:54 +00:00
|
|
|
#if defined(ENOPKG)
|
2024-07-02 19:07:06 +00:00
|
|
|
case ENOPKG:
|
2012-06-10 16:50:54 +00:00
|
|
|
#endif
|
2024-07-02 19:07:06 +00:00
|
|
|
throw XArchNetworkSupport(new XArchEvalUnix(err));
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case EIO:
|
|
|
|
|
throw XArchNetworkIO(new XArchEvalUnix(err));
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case EADDRNOTAVAIL:
|
|
|
|
|
throw XArchNetworkNoAddress(new XArchEvalUnix(err));
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case EADDRINUSE:
|
|
|
|
|
throw XArchNetworkAddressInUse(new XArchEvalUnix(err));
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case EHOSTUNREACH:
|
|
|
|
|
case ENETUNREACH:
|
|
|
|
|
throw XArchNetworkNoRoute(new XArchEvalUnix(err));
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case ENOTCONN:
|
|
|
|
|
throw XArchNetworkNotConnected(new XArchEvalUnix(err));
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case EPIPE:
|
|
|
|
|
throw XArchNetworkShutdown(new XArchEvalUnix(err));
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case ECONNABORTED:
|
|
|
|
|
case ECONNRESET:
|
|
|
|
|
throw XArchNetworkDisconnected(new XArchEvalUnix(err));
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case ECONNREFUSED:
|
|
|
|
|
throw XArchNetworkConnectionRefused(new XArchEvalUnix(err));
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case EHOSTDOWN:
|
|
|
|
|
case ETIMEDOUT:
|
|
|
|
|
throw XArchNetworkTimedOut(new XArchEvalUnix(err));
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
default:
|
|
|
|
|
throw XArchNetwork(new XArchEvalUnix(err));
|
|
|
|
|
}
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
void ArchNetworkBSD::throwNameError(int err) {
|
|
|
|
|
static const char *s_msg[] = {
|
|
|
|
|
"The specified host is unknown",
|
|
|
|
|
"The requested name is valid but does not have an IP address",
|
|
|
|
|
"A non-recoverable name server error occurred",
|
|
|
|
|
"A temporary error occurred on an authoritative name server",
|
|
|
|
|
"An unknown name server error occurred"};
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
switch (err) {
|
|
|
|
|
case HOST_NOT_FOUND:
|
|
|
|
|
throw XArchNetworkNameUnknown(s_msg[0]);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case NO_DATA:
|
|
|
|
|
throw XArchNetworkNameNoAddress(s_msg[1]);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case NO_RECOVERY:
|
|
|
|
|
throw XArchNetworkNameFailure(s_msg[2]);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
case TRY_AGAIN:
|
|
|
|
|
throw XArchNetworkNameUnavailable(s_msg[3]);
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
default:
|
|
|
|
|
throw XArchNetworkName(s_msg[4]);
|
|
|
|
|
}
|
2021-04-26 07:37:34 +00:00
|
|
|
}
|