fixed CTCPSocket::connect() to allow cancellation.
This commit is contained in:
parent
e2ee2371e0
commit
327af03d3d
|
@ -36,6 +36,7 @@ struct protoent FAR * (PASCAL FAR *CNetwork::getprotobynumber)(int proto);
|
||||||
struct protoent FAR * (PASCAL FAR *CNetwork::getprotobyname)(const char FAR * name);
|
struct protoent FAR * (PASCAL FAR *CNetwork::getprotobyname)(const char FAR * name);
|
||||||
int (PASCAL FAR *CNetwork::getsockerror)(void);
|
int (PASCAL FAR *CNetwork::getsockerror)(void);
|
||||||
int (PASCAL FAR *CNetwork::gethosterror)(void);
|
int (PASCAL FAR *CNetwork::gethosterror)(void);
|
||||||
|
int (PASCAL FAR *CNetwork::setblocking)(CNetwork::Socket s, bool blocking);
|
||||||
|
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
|
|
||||||
|
@ -210,6 +211,7 @@ CNetwork::init2(
|
||||||
poll = poll2;
|
poll = poll2;
|
||||||
read = read2;
|
read = read2;
|
||||||
write = write2;
|
write = write2;
|
||||||
|
setblocking = setblocking2;
|
||||||
|
|
||||||
s_networkModule = module;
|
s_networkModule = module;
|
||||||
}
|
}
|
||||||
|
@ -295,11 +297,19 @@ CNetwork::write2(Socket s, const void FAR* buf, size_t len)
|
||||||
return send(s, buf, len, 0);
|
return send(s, buf, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int PASCAL FAR
|
||||||
|
CNetwork::setblocking2(CNetwork::Socket s, bool blocking)
|
||||||
|
{
|
||||||
|
int flag = blocking ? 0 : 1;
|
||||||
|
return ioctlsocket(s, FIONBIO, &flag);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if UNIX_LIKE
|
#if UNIX_LIKE
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
@ -352,6 +362,26 @@ mygethostname(char* name, int namelen)
|
||||||
return gethostname(name, namelen);
|
return gethostname(name, namelen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
mysetblocking(CNetwork::Socket s, bool blocking)
|
||||||
|
{
|
||||||
|
int mode = fcntl(s, F_GETFL, 0);
|
||||||
|
if (mode == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (blocking) {
|
||||||
|
mode &= ~O_NDELAY;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mode |= O_NDELAY;
|
||||||
|
}
|
||||||
|
if (fcntl(s, F_SETFL, mode) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const int CNetwork::Error = -1;
|
const int CNetwork::Error = -1;
|
||||||
const CNetwork::Socket CNetwork::Null = -1;
|
const CNetwork::Socket CNetwork::Null = -1;
|
||||||
|
|
||||||
|
@ -388,6 +418,7 @@ CNetwork::init()
|
||||||
setfunc(getprotobyname, getprotobyname, struct protoent FAR * (PASCAL FAR *)(const char FAR * name));
|
setfunc(getprotobyname, getprotobyname, struct protoent FAR * (PASCAL FAR *)(const char FAR * name));
|
||||||
setfunc(getsockerror, myerrno, int (PASCAL FAR *)(void));
|
setfunc(getsockerror, myerrno, int (PASCAL FAR *)(void));
|
||||||
setfunc(gethosterror, myherrno, int (PASCAL FAR *)(void));
|
setfunc(gethosterror, myherrno, int (PASCAL FAR *)(void));
|
||||||
|
setfunc(setblocking, mysetblocking, int (PASCAL FAR *)(Socket, bool));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -84,8 +84,10 @@ public:
|
||||||
enum {
|
enum {
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
kEADDRINUSE = WSAEADDRINUSE,
|
kEADDRINUSE = WSAEADDRINUSE,
|
||||||
|
kECONNECTING = WSAEWOULDBLOCK,
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
kEADDRINUSE = EADDRINUSE,
|
kEADDRINUSE = EADDRINUSE,
|
||||||
|
kECONNECTING = EINPROGRESS,
|
||||||
#endif
|
#endif
|
||||||
kNone = 0
|
kNone = 0
|
||||||
};
|
};
|
||||||
|
@ -139,12 +141,17 @@ public:
|
||||||
static int (PASCAL FAR *getsockerror)(void);
|
static int (PASCAL FAR *getsockerror)(void);
|
||||||
static int (PASCAL FAR *gethosterror)(void);
|
static int (PASCAL FAR *gethosterror)(void);
|
||||||
|
|
||||||
|
// convenience functions (only available after init())
|
||||||
|
|
||||||
|
static int (PASCAL FAR *setblocking)(CNetwork::Socket s, bool blocking);
|
||||||
|
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
private:
|
private:
|
||||||
static void init2(HMODULE);
|
static void init2(HMODULE);
|
||||||
static int PASCAL FAR poll2(PollEntry[], int nfds, int timeout);
|
static int PASCAL FAR poll2(PollEntry[], int nfds, int timeout);
|
||||||
static ssize_t PASCAL FAR read2(Socket s, void FAR * buf, size_t len);
|
static ssize_t PASCAL FAR read2(Socket s, void FAR * buf, size_t len);
|
||||||
static ssize_t PASCAL FAR write2(Socket s, const void FAR * buf, size_t len);
|
static ssize_t PASCAL FAR write2(Socket s, const void FAR * buf, size_t len);
|
||||||
|
static int PASCAL FAR setblocking2(CNetwork::Socket s, bool blocking);
|
||||||
static int (PASCAL FAR *WSACleanup)(void);
|
static int (PASCAL FAR *WSACleanup)(void);
|
||||||
static int (PASCAL FAR *__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *);
|
static int (PASCAL FAR *__WSAFDIsSet)(CNetwork::Socket, fd_set FAR *);
|
||||||
static int (PASCAL FAR *select)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
|
static int (PASCAL FAR *select)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout);
|
||||||
|
|
|
@ -45,6 +45,7 @@ CTCPListenSocket::bind(const CNetworkAddress& addr)
|
||||||
IDataSocket*
|
IDataSocket*
|
||||||
CTCPListenSocket::accept()
|
CTCPListenSocket::accept()
|
||||||
{
|
{
|
||||||
|
// accept asynchronously so we can check for cancellation
|
||||||
CNetwork::PollEntry pfds[1];
|
CNetwork::PollEntry pfds[1];
|
||||||
pfds[0].fd = m_fd;
|
pfds[0].fd = m_fd;
|
||||||
pfds[0].events = CNetwork::kPOLLIN;
|
pfds[0].events = CNetwork::kPOLLIN;
|
||||||
|
|
|
@ -109,13 +109,52 @@ CTCPSocket::close()
|
||||||
void
|
void
|
||||||
CTCPSocket::connect(const CNetworkAddress& addr)
|
CTCPSocket::connect(const CNetworkAddress& addr)
|
||||||
{
|
{
|
||||||
CThread::testCancel();
|
// connect asynchronously so we can check for cancellation
|
||||||
|
CNetwork::setblocking(m_fd, false);
|
||||||
if (CNetwork::connect(m_fd, addr.getAddress(),
|
if (CNetwork::connect(m_fd, addr.getAddress(),
|
||||||
addr.getAddressLength()) == CNetwork::Error) {
|
addr.getAddressLength()) == CNetwork::Error) {
|
||||||
CThread::testCancel();
|
// check for failure
|
||||||
|
if (CNetwork::getsockerror() != CNetwork::kECONNECTING) {
|
||||||
|
CNetwork::setblocking(m_fd, true);
|
||||||
throw XSocketConnect();
|
throw XSocketConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wait for connection or failure
|
||||||
|
CNetwork::PollEntry pfds[1];
|
||||||
|
pfds[0].fd = m_fd;
|
||||||
|
pfds[0].events = CNetwork::kPOLLOUT;
|
||||||
|
for (;;) {
|
||||||
|
CThread::testCancel();
|
||||||
|
const int status = CNetwork::poll(pfds, 1, 10);
|
||||||
|
if (status > 0) {
|
||||||
|
if ((pfds[0].revents & (CNetwork::kPOLLERR |
|
||||||
|
CNetwork::kPOLLNVAL)) != 0) {
|
||||||
|
// connection failed
|
||||||
|
CNetwork::setblocking(m_fd, true);
|
||||||
|
throw XSocketConnect();
|
||||||
|
}
|
||||||
|
if ((pfds[0].revents & CNetwork::kPOLLOUT) != 0) {
|
||||||
|
int error;
|
||||||
|
CNetwork::AddressLength size = sizeof(error);
|
||||||
|
if (CNetwork::getsockopt(m_fd, SOL_SOCKET, SO_ERROR,
|
||||||
|
reinterpret_cast<char*>(&error),
|
||||||
|
&size) == CNetwork::Error ||
|
||||||
|
error != 0) {
|
||||||
|
// connection failed
|
||||||
|
CNetwork::setblocking(m_fd, true);
|
||||||
|
throw XSocketConnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// connected!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// back to blocking
|
||||||
|
CNetwork::setblocking(m_fd, true);
|
||||||
|
|
||||||
// start servicing the socket
|
// start servicing the socket
|
||||||
m_connected = kReadWrite;
|
m_connected = kReadWrite;
|
||||||
m_thread = new CThread(new TMethodJob<CTCPSocket>(
|
m_thread = new CThread(new TMethodJob<CTCPSocket>(
|
||||||
|
|
Loading…
Reference in New Issue