202 lines
4.4 KiB
C++
202 lines
4.4 KiB
C++
/* lw-support/src/lib/Net/TCP/Client.cpp
|
|
*
|
|
* (c)2005, Laurence Withers. Released under the GNU GPL. See file
|
|
* COPYING for more information / terms of license.
|
|
*/
|
|
|
|
namespace lw {
|
|
|
|
|
|
|
|
NetClientTCP::NetClientTCP()
|
|
: sockAddr(0), peerAddr(0)
|
|
{
|
|
}
|
|
|
|
|
|
|
|
void NetClientTCP::clearAddr()
|
|
{
|
|
delete sockAddr;
|
|
sockAddr = 0;
|
|
delete peerAddr;
|
|
peerAddr = 0;
|
|
}
|
|
|
|
|
|
|
|
NetClientTCP::~NetClientTCP()
|
|
{
|
|
clearAddr();
|
|
}
|
|
|
|
|
|
|
|
NetClientTCP::NetClientTCP(int fd, NetAddress* sockAddr, uint16_t sockPort,
|
|
NetAddress* peerAddr, uint16_t peerPort)
|
|
: sockAddr(sockAddr), peerAddr(peerAddr),
|
|
sockPort(sockPort), peerPort(peerPort)
|
|
{
|
|
this->fd = fd;
|
|
ioMode = IOReadWrite;
|
|
setNonBlocking();
|
|
}
|
|
|
|
|
|
|
|
void NetClientTCP::connect(const NetAddress& addr, uint16_t port, bool block)
|
|
{
|
|
try {
|
|
// clear old connection
|
|
clearAddr();
|
|
close();
|
|
|
|
// create a socket
|
|
fd = TEMP_FAILURE_RETRY(socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
|
|
if(fd == -1)
|
|
throw SystemError().chain(L"socket()");
|
|
ioMode = IOReadWrite;
|
|
|
|
// set non-blocking mode
|
|
if(!block) setNonBlocking();
|
|
|
|
// fill out addresses and connect
|
|
peerAddr = addr.clone();
|
|
peerPort = port;
|
|
|
|
// IPv4
|
|
if(!sockAddr) {
|
|
const NetAddressIPv4* a = dynamic_cast<const NetAddressIPv4*>(&addr);
|
|
if(a) {
|
|
struct sockaddr_in sa;
|
|
socklen_t sa_len = sizeof(sa);
|
|
|
|
// get address
|
|
if(TEMP_FAILURE_RETRY(getsockname(
|
|
fd, (struct sockaddr*)&sa, &sa_len)))
|
|
throw SystemError().chain(L"getsockname()");
|
|
sockAddr = new NetAddressIPv4((char*)&(sa.sin_addr.s_addr));
|
|
sockPort = sa.sin_port;
|
|
|
|
// connect
|
|
int ret = TEMP_FAILURE_RETRY(::connect(
|
|
fd, a->copy(&sa, port), sa_len));
|
|
|
|
if(ret == -1 && (block || errno != EINPROGRESS))
|
|
throw SystemError().chain(L"connect()");
|
|
}
|
|
}
|
|
|
|
// IPv6
|
|
if(!sockAddr) {
|
|
const NetAddressIPv6* a = dynamic_cast<const NetAddressIPv6*>(&addr);
|
|
if(a) {
|
|
struct sockaddr_in6 sa;
|
|
socklen_t sa_len = sizeof(sa);
|
|
|
|
// get address
|
|
if(TEMP_FAILURE_RETRY(getsockname(
|
|
fd, (struct sockaddr*)&sa, &sa_len)))
|
|
throw SystemError().chain(L"getsockname()");
|
|
sockAddr = new NetAddressIPv6(sa.sin6_addr.s6_addr);
|
|
sockPort = sa.sin6_port;
|
|
|
|
// connect
|
|
int ret = TEMP_FAILURE_RETRY(::connect(
|
|
fd, a->copy(&sa, port), sa_len));
|
|
|
|
if(ret == -1 && (block || errno != EINPROGRESS))
|
|
throw SystemError().chain(L"connect()");
|
|
}
|
|
}
|
|
|
|
// unknown
|
|
if(!sockAddr) {
|
|
throw NetServer::UnknownProtocol();
|
|
}
|
|
|
|
// if we were doing blocking I/O, set non-blocking mode now
|
|
setNonBlocking();
|
|
|
|
}
|
|
|
|
// deal with errors gracefully
|
|
catch(Exception& e) {
|
|
try {
|
|
close();
|
|
}
|
|
catch(...) { }
|
|
e.chain(L"NetClientTCP::connect()");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void NetClientTCP::connect(const NetAddress& addr, uint16_t port)
|
|
{
|
|
connect(addr, port, false);
|
|
}
|
|
|
|
|
|
|
|
void NetClientTCP::connectBlocking(const NetAddress& addr, uint16_t port)
|
|
{
|
|
connect(addr, port, true);
|
|
}
|
|
|
|
|
|
|
|
NetClientTCP::NetClientTCP(const NetAddress& addr, uint16_t port)
|
|
: sockAddr(0), peerAddr(0)
|
|
{
|
|
connect(addr, port, true);
|
|
}
|
|
|
|
|
|
|
|
uint16_t NetClientTCP::localPort() const
|
|
{
|
|
checkOpen(L"NetClientTCP::localPort()");
|
|
return sockPort;
|
|
}
|
|
|
|
|
|
|
|
uint16_t NetClientTCP::remotePort() const
|
|
{
|
|
checkOpen(L"NetClientTCP::remotePort()");
|
|
return peerPort;
|
|
}
|
|
|
|
|
|
|
|
const NetAddress& NetClientTCP::localAddr() const
|
|
{
|
|
checkOpen(L"NetClientTCP::localPort()");
|
|
return *sockAddr;
|
|
}
|
|
|
|
|
|
|
|
const NetAddress& NetClientTCP::remoteAddr() const
|
|
{
|
|
checkOpen(L"NetClientTCP::remotePort()");
|
|
return *peerAddr;
|
|
}
|
|
|
|
|
|
|
|
void NetClientTCP::setNoDelay(bool noDelay)
|
|
{
|
|
int n = noDelay;
|
|
if(setsockopt(fd, SOL_TCP, TCP_NODELAY, &n, sizeof(n)))
|
|
throw SystemError()
|
|
.chain(L"setsockopt(..., SOL_TCP, TCP_NODELAY, ...)")
|
|
.chain(L"NetClientTCP::setNoDelay()");
|
|
}
|
|
|
|
|
|
|
|
}
|