/* 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(&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(&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()"); } }