/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2007 INRIA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "ns3/assert.h"
#include "address.h"
#include <string.h>
#include <iostream>
#include <iomanip>
namespace ns3 {
Address::Address ()
: m_type (0),
m_len (0)
{
// Buffer left uninitialized
}
Address::Address (uint8_t type, const uint8_t *buffer, uint8_t len)
: m_type (type),
m_len (len)
{
NS_ASSERT (m_len <= MAX_SIZE);
memcpy (m_data, buffer, m_len);
}
Address::Address (const Address & address)
: m_type (address.m_type),
m_len (address.m_len)
{
NS_ASSERT (m_len <= MAX_SIZE);
memcpy (m_data, address.m_data, m_len);
}
Address &
Address::operator = (const Address &address)
{
NS_ASSERT (m_len <= MAX_SIZE);
m_type = address.m_type;
m_len = address.m_len;
NS_ASSERT (m_len <= MAX_SIZE);
memcpy (m_data, address.m_data, m_len);
return *this;
}
bool
Address::IsInvalid (void) const
{
return m_len == 0 && m_type == 0;
}
uint8_t
Address::GetLength (void) const
{
NS_ASSERT (m_len <= MAX_SIZE);
return m_len;
}
uint32_t
Address::CopyTo (uint8_t buffer[MAX_SIZE]) const
{
NS_ASSERT (m_len <= MAX_SIZE);
memcpy (buffer, m_data, m_len);
return m_len;
}
uint32_t
Address::CopyAllTo (uint8_t *buffer, uint8_t len) const
{
NS_ASSERT (len >= m_len + 2);
buffer[0] = m_type;
buffer[1] = m_len;
memcpy (buffer + 2, m_data, m_len);
return m_len + 2;
}
uint32_t
Address::CopyFrom (const uint8_t *buffer, uint8_t len)
{
NS_ASSERT (len <= MAX_SIZE);
memcpy (m_data, buffer, len);
m_len = len;
return m_len;
}
uint32_t
Address::CopyAllFrom (const uint8_t *buffer, uint8_t len)
{
NS_ASSERT (len >= 2);
m_type = buffer[0];
m_len = buffer[1];
NS_ASSERT (len >= m_len + 2);
memcpy (m_data, buffer + 2, m_len);
return m_len + 2;
}
bool
Address::CheckCompatible (uint8_t type, uint8_t len) const
{
NS_ASSERT (len <= MAX_SIZE);
return m_len == len && (m_type == type || m_type == 0);
}
bool
Address::IsMatchingType (uint8_t type) const
{
return m_type == type;
}
uint8_t
Address::Register (void)
{
static uint8_t type = 1;
type++;
return type;
}
uint32_t
Address::GetSerializedSize (void) const
{
return 1 + 1 + m_len;
}
void
Address::Serialize (TagBuffer buffer) const
{
buffer.WriteU8 (m_type);
buffer.WriteU8 (m_len);
buffer.Write (m_data, m_len);
}
void
Address::Deserialize (TagBuffer buffer)
{
m_type = buffer.ReadU8 ();
m_len = buffer.ReadU8 ();
NS_ASSERT (m_len <= MAX_SIZE);
buffer.Read (m_data, m_len);
}
ATTRIBUTE_HELPER_CPP (Address);
bool operator == (const Address &a, const Address &b)
{
/* Two addresses can be equal even if their types are
* different if one of the two types is zero. a type of
* zero identifies an Address which might contain meaningful
* payload but for which the type field could not be set because
* we did not know it. This can typically happen in the ARP
* layer where we receive an address from an ArpHeader but
* we do not know its type: we really want to be able to
* compare addresses without knowing their real type.
*/
if (a.m_type != b.m_type &&
a.m_type != 0 &&
b.m_type != 0)
{
return false;
}
if (a.m_len != b.m_len)
{
return false;
}
return memcmp (a.m_data, b.m_data, a.m_len) == 0;
}
bool operator != (const Address &a, const Address &b)
{
return !(a == b);
}
bool operator < (const Address &a, const Address &b)
{
if (a.m_type < b.m_type)
{
return true;
}
else if (a.m_type > b.m_type)
{
return false;
}
if (a.m_len < b.m_len)
{
return true;
}
else if (a.m_len > b.m_len)
{
return false;
}
NS_ASSERT (a.GetLength() == b.GetLength());
for (uint8_t i = 0; i < a.GetLength(); i++)
{
if (a.m_data[i] < b.m_data[i])
{
return true;
}
else if (a.m_data[i] > b.m_data[i])
{
return false;
}
}
return false;
}
std::ostream& operator<< (std::ostream& os, const Address & address)
{
os.setf (std::ios::hex, std::ios::basefield);
os.fill('0');
os << std::setw(2) << (uint32_t) address.m_type << "-" << std::setw(2) << (uint32_t) address.m_len << "-";
for (uint8_t i = 0; i < (address.m_len-1); ++i)
{
os << std::setw(2) << (uint32_t)address.m_data[i] << ":";
}
// Final byte not suffixed by ":"
os << std::setw(2) << (uint32_t) address.m_data[address.m_len-1];
os.setf (std::ios::dec, std::ios::basefield);
os.fill(' ');
return os;
}
static uint8_t
AsInt (std::string v)
{
std::istringstream iss;
iss.str (v);
uint32_t retval;
iss >> std::hex >> retval >> std::dec;
return retval;
}
std::istream& operator>> (std::istream& is, Address & address)
{
std::string v;
is >> v;
std::string::size_type firstDash, secondDash;
firstDash = v.find ("-");
secondDash = v.find ("-", firstDash+1);
std::string type = v.substr (0, firstDash-0);
std::string len = v.substr (firstDash+1, secondDash-(firstDash+1));
address.m_type = AsInt (type);
address.m_len = AsInt (len);
NS_ASSERT (address.m_len <= Address::MAX_SIZE);
std::string::size_type col = secondDash + 1;
for (uint8_t i = 0; i < address.m_len; ++i)
{
std::string tmp;
std::string::size_type next;
next = v.find (":", col);
if (next == std::string::npos)
{
tmp = v.substr (col, v.size ()-col);
address.m_data[i] = AsInt (tmp);
break;
}
else
{
tmp = v.substr (col, next-col);
address.m_data[i] = AsInt (tmp);
col = next + 1;
}
}
return is;
}
} // namespace ns3