/*
* Copyright (C) 2001-2004 Peter J Jones (pjones@pmade.org)
* All Rights Reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of the Author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/** @file
* This file contains the implementation of the Netxx::Peer class.
**/
// common header
#include "common.h"
// Netxx includes
#include <netxx/peer.h>
// standard includes
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <new>
//####################################################################
namespace
{
const unsigned int const_max_sockaddr_size = 128;
}
//###########################################################################
Netxx::Peer::Peer (void)
: okay_(false), port_(0), socketfd_(-1), sockaddr_(0), sockaddr_size_(0)
{ }
//###########################################################################
Netxx::Peer::Peer (const char *addr, port_type port, void *saddr, size_type saddr_size)
: okay_(true), addr_(addr), port_(port), socketfd_(-1), sockaddr_size_(saddr_size)
{
// TODO should this be sockaddr_ = new char[saddr_size];?
sockaddr_ = std::malloc(saddr_size);
if (!sockaddr_) throw std::bad_alloc();
std::memcpy(sockaddr_, saddr, saddr_size);
}
//###########################################################################
Netxx::Peer::Peer (socket_type socketfd, void *saddr, size_type saddr_size)
: okay_(true), port_(0), socketfd_(socketfd), sockaddr_size_(saddr_size)
{
// TODO should this be sockaddr_ = new char[saddr_size];?
sockaddr_ = std::malloc(saddr_size);
if (!sockaddr_) throw std::bad_alloc();
std::memcpy(sockaddr_, saddr, saddr_size);
sockaddr *sa = static_cast<sockaddr*>(sockaddr_);
switch (sa->sa_family) {
case AF_INET:
{
char buffer[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &(reinterpret_cast<sockaddr_in*>(sa)->sin_addr), buffer, sizeof(buffer))) {
addr_ = buffer;
port_ = ntohs(reinterpret_cast<sockaddr_in*>(sa)->sin_port);
}
}
break;
# ifndef NETXX_NO_INET6
case AF_INET6:
{
char buffer[INET6_ADDRSTRLEN];
if (inet_ntop(AF_INET6, &(reinterpret_cast<sockaddr_in6*>(sa)->sin6_addr), buffer, sizeof(buffer))) {
addr_ = buffer;
port_ = ntohs(reinterpret_cast<sockaddr_in6*>(sa)->sin6_port);
}
}
break;
# endif
# ifndef WIN32
case AF_LOCAL:
addr_ = reinterpret_cast<sockaddr_un*>(sa)->sun_path;
break;
# endif
}
}
//###########################################################################
Netxx::Peer::Peer (const Peer &other)
: okay_(other.okay_), addr_(other.addr_), port_(other.port_),
socketfd_(other.socketfd_), sockaddr_(0), sockaddr_size_(other.sockaddr_size_)
{
if (other.sockaddr_) {
sockaddr_ = std::malloc(sockaddr_size_);
if (!sockaddr_) throw std::bad_alloc();
std::memcpy(sockaddr_, other.sockaddr_, sockaddr_size_);
}
}
//###########################################################################
Netxx::Peer& Netxx::Peer::operator= (const Peer &other)
{
Peer tmp(other); swap(tmp);
return *this;
}
//###########################################################################
void Netxx::Peer::swap (Peer &other)
{
std::swap(okay_, other.okay_);
std::swap(addr_, other.addr_);
std::swap(port_, other.port_);
std::swap(socketfd_, other.socketfd_);
std::swap(sockaddr_, other.sockaddr_);
std::swap(sockaddr_size_, other.sockaddr_size_);
}
//###########################################################################
Netxx::Peer::~Peer (void)
{
if (sockaddr_) std::free(sockaddr_);
}
//###########################################################################
const char* Netxx::Peer::get_address (void) const
{
return addr_.c_str();
}
//###########################################################################
Netxx::port_type Netxx::Peer::get_port (void) const
{
return port_;
}
//###########################################################################
Netxx::port_type Netxx::Peer::get_local_port (void) const
{
os_socklen_type sa_size = const_max_sockaddr_size;
os_socklen_ptr_type sa_size_ptr = get_socklen_ptr(sa_size);
union {
sockaddr sa;
sockaddr_in sin;
# ifndef NETXX_NO_INET6
sockaddr_in6 sin6;
# endif
} sau;
int rc;
if ( (rc = getsockname(get_socketfd(), &sau.sa, sa_size_ptr))) {
throw Exception(str_error(errno));
}
switch (sau.sa.sa_family) {
case AF_INET:
return ntohs(sau.sin.sin_port);
# ifndef NETXX_NO_INET6
case AF_INET6:
return ntohs(sau.sin6.sin6_port);
# endif
default:
return 0;
}
}
//###########################################################################
Netxx::socket_type Netxx::Peer::get_socketfd (void) const
{
return socketfd_;
}
//###########################################################################
Netxx::Peer::operator bool (void) const
{
return okay_;
}
//###########################################################################
const void* Netxx::Peer::get_sa (void) const
{
return sockaddr_;
}
//###########################################################################
Netxx::size_type Netxx::Peer::get_sa_size() const
{
return sockaddr_size_;
}
//###########################################################################
namespace Netxx
{
//###########################################################################
std::ostream& operator<< (std::ostream &stream, const Peer &peer)
{
const sockaddr *sa = reinterpret_cast<const sockaddr*>(peer.get_sa());
if (peer) {
if (sa && sa->sa_family == AF_LOCAL) {
if (peer.get_address()[0] == 0) stream << "domain socket";
else stream << peer.get_address();
} else {
stream << peer.get_address() << ":" << peer.get_port();
}
}
return stream;
}
//###########################################################################
} // end Netxx namespace
syntax highlighted by Code2HTML, v. 0.9.1