#include "ip++.h"
#include "hosts.h"
#include <Security/debugging.h>
#include <arpa/inet.h>
#include <netdb.h>
namespace Security {
namespace IPPlusPlus {
typedef unsigned char Byte;
static const struct in_addr in_addr_any = { INADDR_ANY };
#if BUG_GCC
const IPAddress &IPAddress::any = *static_cast<const IPAddress *>(&in_addr_any);
#else
const IPAddress &IPAddress::any = static_cast<const IPAddress &>(in_addr_any);
#endif
IPAddress::IPAddress(const char *s)
{
if (!inet_aton(s, this))
UnixError::throwMe(EINVAL);
}
IPAddress::operator string() const
{
const Byte *p = reinterpret_cast<const Byte *>(this);
char buffer[(3+1)*4]; snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return buffer;
}
IPSockAddress::IPSockAddress()
{
sin_family = AF_INET;
}
IPSockAddress::IPSockAddress(const IPAddress &addr, IPPort port)
{
sin_family = AF_INET;
sin_addr = addr;
sin_port = htons(port);
}
IPSockAddress::operator string () const
{
char buffer[4*(3+1)+5+1]; snprintf(buffer, sizeof(buffer), "%s:%d", string(address()).c_str(), port());
return buffer;
}
IPSockAddress IPSockAddress::defaults(const IPSockAddress &defaultAddr) const
{
return defaults(defaultAddr.address(), defaultAddr.port());
}
IPSockAddress IPSockAddress::defaults(const IPAddress &defaultAddr, IPPort defaultPort) const
{
return IPSockAddress(
address() ? address() : defaultAddr,
port() ? port() : defaultPort
);
}
IPSockAddress IPSockAddress::defaults(IPPort defaultPort) const
{
return IPSockAddress(address(), port() ? port() : defaultPort);
}
Socket::Socket(int type, int protocol)
{
open(type, protocol);
}
void Socket::open(int type, int protocol)
{
checkSetFd(::socket(AF_INET, type, protocol));
mAtEnd = false;
debug("sockio", "socket(%d,%d) -> %d", type, protocol, fd());
}
void Socket::prepare(int fdFlags, int type, int protocol)
{
if (!isOpen())
open(type, protocol);
if (fdFlags)
setFlag(fdFlags);
}
void Socket::bind(const IPAddress &addr, IPPort port)
{
bind(IPSockAddress(addr, port));
}
void Socket::bind(const IPSockAddress &local)
{
checkError(::bind(fd(), local, sizeof(local)));
IFDEBUG(debug("sockio", "%d bind to %s", fd(), string(local).c_str()));
}
void Socket::listen(int backlog)
{
checkError(::listen(fd(), backlog));
}
void Socket::accept(Socket &s)
{
IPSockAddress dummy; return accept(s, dummy);
}
void Socket::accept(Socket &s, IPSockAddress &peer)
{
int length = sizeof(IPSockAddress);
s.checkSetFd(::accept(fd(), peer, &length));
assert(length == sizeof(IPSockAddress));
}
bool Socket::connect(const IPSockAddress &peer)
{
if (::connect(fd(), peer, sizeof(peer))) {
switch (errno) {
case EINPROGRESS:
IFDEBUG(debug("sockio", "%d connecting to %s", fd(), string(peer).c_str()));
return false;
case EALREADY:
if (int err = error()) UnixError::throwMe(err);
IFDEBUG(debug("sockio", "%d still trying to connect", fd()));
return false;
case EISCONN:
if (flags() & O_NONBLOCK) {
debug("sockio", "%d now connected", fd());
return true;
} else {
UnixError::throwMe();
}
default:
UnixError::throwMe();
}
} else {
IFDEBUG(debug("sockio", "%d connect to %s", fd(), string(peer).c_str()));
return true;
}
}
bool Socket::connect(const IPAddress &addr, IPPort port)
{
return connect(IPSockAddress(addr, port));
}
void Socket::shutdown(int how)
{
assert(how >= 0 && how <= 2);
checkError(::shutdown(fd(), how));
}
IPSockAddress Socket::localAddress() const
{
IPSockAddress addr;
int length = sizeof(addr);
checkError(::getsockname(fd(), addr, &length));
assert(length == sizeof(addr));
return addr;
}
IPSockAddress Socket::peerAddress() const
{
IPSockAddress addr;
int length = sizeof(addr);
checkError(::getpeername(fd(), addr, &length));
assert(length == sizeof(addr));
return addr;
}
void Socket::getOption(void *value, int &length, int name, int level = SOL_SOCKET) const
{
UnixError::check(::getsockopt(fd(), level, name, value, &length));
}
void Socket::setOption(const void *value, int length, int name, int level = SOL_SOCKET) const
{
UnixError::check(::setsockopt(fd(), level, name, value, length));
}
void Socket::connect(const Host &host, IPPort port)
{
set<IPAddress> addrs = host.addresses();
for (set<IPAddress>::const_iterator it = addrs.begin(); it != addrs.end(); it++) {
const IPSockAddress address(*it, port);
if (::connect(fd(), address, sizeof(IPSockAddress)) == 0) {
IFDEBUG(debug("sockio", "%d connect to %s", fd(), string(address).c_str()));
return;
}
}
UnixError::throwMe();
}
void TCPClientSocket::open(const IPSockAddress &peer, int fdFlags)
{
prepare(fdFlags, SOCK_STREAM);
connect(peer);
}
void TCPClientSocket::open(const IPAddress &addr, IPPort port, int fdFlags)
{
prepare(fdFlags, SOCK_STREAM);
connect(addr, port);
}
void TCPClientSocket::open(const Host &host, IPPort port, int fdFlags)
{
prepare(fdFlags, SOCK_STREAM);
connect(host, port);
}
TCPClientSocket::~TCPClientSocket()
{
close();
}
void TCPServerSocket::open(const IPSockAddress &addr, int depth)
{
prepare(0, SOCK_STREAM);
bind(addr);
listen(depth);
}
void TCPServerSocket::operator () (TCPClientSocket &newClient)
{
accept(newClient);
}
void TCPServerSocket::receive(TCPClientSocket &newClient)
{
accept(newClient);
close();
}
TCPServerSocket::~TCPServerSocket()
{
close();
}
} }