www.pudn.com > javasnmpv3.rar > address.cpp


/*_############################################################################
  _## 
  _##  address.cpp  
  _##
  _##  SNMP++v3.2.22
  _##  -----------------------------------------------
  _##  Copyright (c) 2001-2007 Jochen Katz, Frank Fock
  _##
  _##  This software is based on SNMP++2.6 from Hewlett Packard:
  _##  
  _##    Copyright (c) 1996
  _##    Hewlett-Packard Company
  _##  
  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
  _##  Permission to use, copy, modify, distribute and/or sell this software 
  _##  and/or its documentation is hereby granted without fee. User agrees 
  _##  to display the above copyright notice and this license notice in all 
  _##  copies of the software and any documentation of the software. User 
  _##  agrees to assume all liability for the use of the software; 
  _##  Hewlett-Packard and Jochen Katz make no representations about the 
  _##  suitability of this software for any purpose. It is provided 
  _##  "AS-IS" without warranty of any kind, either express or implied. User 
  _##  hereby grants a royalty-free license to any and all derivatives based
  _##  upon this software code base. 
  _##  
  _##  Stuttgart, Germany, Wed May  2 23:22:30 CEST 2007 
  _##  
  _##########################################################################*/
/*===================================================================

  Copyright (c) 1999
  Hewlett-Packard Company

  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
  Permission to use, copy, modify, distribute and/or sell this software
  and/or its documentation is hereby granted without fee. User agrees
  to display the above copyright notice and this license notice in all
  copies of the software and any documentation of the software. User
  agrees to assume all liability for the use of the software; Hewlett-Packard
  makes no representations about the suitability of this software for any
  purpose. It is provided "AS-IS" without warranty of any kind,either express
  or implied. User hereby grants a royalty-free license to any and all
  derivatives based upon this software code base.


  A D D R E S S. C P P

  ADDRESS CLASS IMPLEMENTATION

  DESIGN + AUTHOR:  Peter E. Mellquist

  DESCRIPTION:      Implementation file for Address classes.

  LANGUAGE:         ANSI C++

=====================================================================*/
char address_cpp_version[]="@(#) SNMP++ $Id: address.cpp 277 2007-03-22 21:17:36Z katz $";

#include 
#include 
#include 

#include "snmp_pp/address.h"
#include "snmp_pp/v3.h"

#ifdef SNMP_PP_NAMESPACE
namespace Snmp_pp {
#endif

/* Borlands isdigit has a bug */
#ifdef __BCPLUSPLUS__
#define my_isdigit(c) ((c) >= '0' && (c) <= '9')
#else
#define my_isdigit isdigit
#endif

#ifdef ADDRESS_DEBUG
#define ADDRESS_TRACE debugprintf(0, "ADDRESS %p Enter %s", this, __PRETTY_FUNCTION__)
#define ADDRESS_TRACE2 debugprintf(0, "ADDRESS op Enter %s", __PRETTY_FUNCTION__)
#else
#define ADDRESS_TRACE
#define ADDRESS_TRACE2
#endif

#if !defined HAVE_GETHOSTBYNAME_R || !defined HAVE_GETHOSTBYADDR_R || !defined HAVE_REENTRANT_GETHOSTBYNAME || !defined HAVE_REENTRANT_GETHOSTBYADDR
#ifdef _THREADS
SnmpSynchronized Address::syscall_mutex;
#endif
#endif

//=================================================================
//======== Abstract Address Class Implementation ==================
//=================================================================

Address::Address()
  : addr_changed(true), valid_flag(false)
{
  ADDRESS_TRACE;

  memset(address_buffer, 0, sizeof(unsigned char)*ADDRBUF);
}

//------------[ Address::trim_white_space( char * ptr) ]------------
// destructive trim white space
void Address::trim_white_space(char *ptr)
{
  ADDRESS_TRACE;

  char *tmp = ptr;                               // init
  while (*tmp==' ') tmp++;                       // skip leading white space
  while (*tmp && (*tmp != ' ')) *ptr++ = *tmp++; // move string to beginning
  *ptr = 0;                                      // set end of string
}

// Reset the object
void Address::clear()
{
  addr_changed = true;
  valid_flag = false;
  memset(address_buffer, 0, sizeof(unsigned char)*ADDRBUF);
}

//-----------------------------------------------------------------------
// overloaded equivlence operator, are two addresses equal?
int operator==(const Address &lhs, const Address &rhs)
{
  ADDRESS_TRACE2;

  return (strcmp((const char*)lhs, (const char*)rhs) == 0);
}

//------------------------------------------------------------------
// overloaded > operator, is a1 > a2
int operator>(const Address &lhs, const Address &rhs)
{
  ADDRESS_TRACE2;

  return (strcmp((const char*)lhs, (const char*)rhs) > 0);
}

//-----------------------------------------------------------------
// overloaded < operator, is a1 < a2
int operator<(const Address &lhs, const Address &rhs)
{
  ADDRESS_TRACE2;

  return (strcmp((const char*)lhs, (const char*)rhs) < 0);
}

//------------------------------------------------------------------
// equivlence operator overloaded, are an address and a string equal?
int operator==(const Address &lhs, const char *rhs)
{
  ADDRESS_TRACE2;

  if (!rhs && !lhs.valid())
    return TRUE;
  if (strcmp((const char *)lhs, rhs) == 0)
    return TRUE;
  return FALSE;
}

//------------------------------------------------------------------
// overloaded > , is a > inaddr
int operator>(const Address &lhs, const char *rhs)
{
  ADDRESS_TRACE2;

  if (!rhs)
    return lhs.valid();  // if lhs valid then > NULL, else invalid !> NULL
  if (strcmp((const char *)lhs, rhs) > 0)
    return TRUE;
  return FALSE;
}

//------------------------------------------------------------------
// overloaded >= , is a >= inaddr
int operator>=(const Address &lhs, const char *rhs)
{
  ADDRESS_TRACE2;

  if (!rhs)
    return TRUE; // always >= NULL
  if (strcmp((const char *)lhs, rhs) >= 0)
    return TRUE;
  return FALSE;
}

//-----------------------------------------------------------------
// overloaded < , are an address and a string equal?
int operator<(const Address &lhs, const char *rhs)
{
  ADDRESS_TRACE2;

  if (!rhs)
    return FALSE; // always >= NULL
  if (strcmp((const char *)lhs, rhs) < 0)
    return TRUE;
  return FALSE;
}

//-----------------------------------------------------------------
// overloaded <= , is a <= inaddr
int operator<=(const Address &lhs, const char *rhs)
{
  ADDRESS_TRACE2;

  if (!rhs)
    return !lhs.valid(); // invalid == NULL, else valid > NULL
  if (strcmp((const char *)lhs, rhs) <= 0)
    return TRUE;
  return FALSE;
}

//=====================================================================
//============ IPAddress Implementation ===============================
//=====================================================================

//-------[ construct an IP address with no agrs ]----------------------
IpAddress::IpAddress()
  : Address(), iv_friendly_name_status(0), ip_version(version_ipv4)
{
  ADDRESS_TRACE;

  // always initialize what type this object is
  smival.syntax = sNMP_SYNTAX_IPADDR;
  smival.value.string.len = IPLEN;
  smival.value.string.ptr = address_buffer;

  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
}

//-------[ construct an IP address with a string ]---------------------
IpAddress::IpAddress(const char *inaddr)
  : Address()
{
  ADDRESS_TRACE;

  // always initialize what type this object is
  smival.syntax = sNMP_SYNTAX_IPADDR;
  smival.value.string.len = IPLEN;
  smival.value.string.ptr = address_buffer;

  // parse_address initializes valid, address_buffer & iv_friendly_name
  valid_flag = parse_address(inaddr);
}

//-----[ IP Address copy constructor ]---------------------------------
IpAddress::IpAddress(const IpAddress &ipaddr)
  : iv_friendly_name_status(0), ip_version(ipaddr.ip_version)
{
  ADDRESS_TRACE;

  // always initialize what type this object is
  smival.syntax = sNMP_SYNTAX_IPADDR;
  smival.value.string.len = ipaddr.smival.value.string.len;
  smival.value.string.ptr = address_buffer;

  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
  valid_flag = ipaddr.valid_flag;
  if (valid_flag)
  {
    // copy the address data
    MEMCPY(address_buffer, ipaddr.address_buffer, smival.value.string.len);
    // and the friendly name
    strcpy(iv_friendly_name, ipaddr.iv_friendly_name);

    if (!ipaddr.addr_changed)
    {
      memcpy(output_buffer, ipaddr.output_buffer,
	     sizeof(unsigned char) * OUTBUFF);
      addr_changed = false;
    }
  }
}

//-----[ construct an IP address with a GenAddress ]---------------------
IpAddress::IpAddress(const GenAddress &genaddr)
  : iv_friendly_name_status(0)
{
  ADDRESS_TRACE;

  // always initialize what type this object is
  smival.syntax = sNMP_SYNTAX_IPADDR;
  smival.value.string.len = IPLEN;
  smival.value.string.ptr = address_buffer;

  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
  output_buffer[0]=0;

  // allow use of an ip or udp genaddress
  valid_flag = genaddr.valid();
  if (valid_flag)
  {
    if (genaddr.get_type() == type_ip)
    {
      // copy in the IP address data
      *this = genaddr.cast_ipaddress();
      return;
    }
    else if (genaddr.get_type() == type_udp)
    {
      // copy in the IP address data
      *this = genaddr.cast_udpaddress();
      return;
    }
  }
  valid_flag = false;
  addr_changed = true;
}

//-----[ IP Address general = operator ]-------------------------------
SnmpSyntax& IpAddress::operator=(const SnmpSyntax &val)
{
  ADDRESS_TRACE;

  if (this == &val) return *this; // protect against assignment from itself

  addr_changed = true;
  valid_flag = false;        // will get set TRUE if really valid
  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);

  if (val.valid())
  {
    switch (val.get_syntax())
    {
      case sNMP_SYNTAX_IPADDR:
      case sNMP_SYNTAX_OCTETS:
        if ((((IpAddress &)val).smival.value.string.len == IPLEN) ||
	    (((IpAddress &)val).smival.value.string.len == UDPIPLEN))
        {
          MEMCPY(address_buffer,
                 ((IpAddress &)val).smival.value.string.ptr, IPLEN);
	  valid_flag = true;
	  ip_version = version_ipv4;
	  smival.value.string.len = IPLEN;
        }
        else if ((((IpAddress &)val).smival.value.string.len == IP6LEN) ||
		 (((IpAddress &)val).smival.value.string.len == UDPIP6LEN))
        {
	  MEMCPY(address_buffer,
		 ((IpAddress &)val).smival.value.string.ptr, IP6LEN);
	  valid_flag = true;
	  ip_version = version_ipv6;
	  smival.value.string.len = IP6LEN;
        }
        break;

        // NOTE: as a value add, other types could have "logical"
        // mappings, i.e. integer32 and unsigned32
    }
  }
  return *this;
}

//------[ assignment to another ipaddress object overloaded ]-----------------
IpAddress& IpAddress::operator=(const IpAddress &ipaddr)
{
  ADDRESS_TRACE;

  if (this == &ipaddr) return *this; // protect against assignment from itself

  valid_flag = ipaddr.valid_flag;
  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);

  if (valid_flag)
  {
    if (ipaddr.ip_version == version_ipv4)
    {
      MEMCPY(address_buffer, ipaddr.address_buffer, IPLEN);
      ip_version = version_ipv4;
      smival.value.string.len = IPLEN;
    }
    else
    {
      MEMCPY(address_buffer, ipaddr.address_buffer, IP6LEN);
      ip_version = version_ipv6;
      smival.value.string.len = IP6LEN;
    }
    strcpy(iv_friendly_name, ipaddr.iv_friendly_name);

    if (ipaddr.addr_changed)
      addr_changed = true;
    else
    {
      memcpy(output_buffer, ipaddr.output_buffer,
	     sizeof(unsigned char) * OUTBUFF);
      addr_changed = false;
    }
  }
  else
    addr_changed = true;
  return *this;
}

IpAddress& IpAddress::operator=(const char *inaddr)
{
  ADDRESS_TRACE;

  valid_flag = parse_address(inaddr);
  addr_changed = true;
  return *this;
}

//-------[ return the friendly name ]----------------------------------
char *IpAddress::friendly_name(int &status)
{
  ADDRESS_TRACE;

  if ((iv_friendly_name[0]==0) && (valid_flag))
    this->addr_to_friendly();
  status = iv_friendly_name_status;
  return iv_friendly_name;
}

// parse a dotted string
int IpAddress::parse_dotted_ipstring(const char *inaddr)
{
  ADDRESS_TRACE;

  int token_count=0;
  char temp[30];  // temp buffer for destruction

  // check len, an ip can never be bigger than 15
  // 123456789012345
  // XXX.XXX.XXX.XXX
  if (!inaddr || (strlen(inaddr) > 30)) return FALSE;

  strcpy(temp, inaddr);
  trim_white_space(temp);
  if (strlen(temp) > 15) return FALSE;

  /* Check for the following:
   * - exactly three dots
   * - no dot at begin or end
   * - at least a digit between two dots
   * - only dots and digits allowed
   */
  char *ptr = temp;
  int dot_count = 0;
  bool last_char_was_dot = true;

  while (*ptr)
  {
    if (*ptr == '.')
    {
      if (last_char_was_dot) return FALSE;
      ++dot_count;
      last_char_was_dot = true;
    }
    else if (my_isdigit(*ptr))
    {
      last_char_was_dot = false;
    }
    else
      return FALSE;
    ++ptr;
  }
  if ((dot_count != 3) || (last_char_was_dot))
    return FALSE;

  ptr = temp;
  while (*ptr)
  {
    unsigned long number = 0;

    if (*ptr == '.') ++ptr;    // skip over the dot

    // grab a digit token and convert it to a long int
    int digits = 0;
    while ((*ptr) && (*ptr != '.'))
    {
      number = (number * 10) + *(ptr++) - '0';
      ++digits;
    }
    if (digits > 3) return FALSE;
    if (number > 255) return FALSE;

    // stuff the value into the array and bump the counter
    address_buffer[token_count++]= (unsigned char) number;
  }

  ip_version = version_ipv4;
  smival.value.string.len = IPLEN;
  return TRUE;
}

#define ATOI(x)    if      ((x >= 48) && (x <= 57)) x = x-48; /* 0-9 */ \
                   else if ((x >= 97) && (x <=102)) x = x-87; /* a-f */ \
                   else if ((x >= 65) && (x <= 70)) x = x-55; /* A-F */ \
                   else x=0

// parse a coloned string
int IpAddress::parse_coloned_ipstring(const char *inaddr)
{
  ADDRESS_TRACE;

  unsigned char tmp_address_buffer[ADDRBUF];
  char temp[60];  // temp buffer for destruction

  // check len, an ipv6 can never be bigger than 39
  // 123456789012345678901234567890123456789
  // 1BCD:2BCD:3BCD:4BCD:5BCD:6BCD:7BCD:8BCD
  if (!inaddr || (strlen(inaddr) > 60)) return FALSE;
  strcpy(temp, inaddr);
  trim_white_space(temp);
  if (strlen(temp) > 39) return FALSE;

  char *in_ptr = temp;
  char *out_ptr = (char*)tmp_address_buffer;
  char *end_first_part = NULL;
  char second[39];
  int second_used = FALSE;
  int colon_count = 0;
  int had_double_colon = FALSE;
  int last_was_colon = FALSE;
  int had_dot = FALSE;
  int dot_count = 0;
  int digit_count = 0;
  char digits[4];
  char last_deliminiter = 0;

  while (*in_ptr != 0)
  {
    if (*in_ptr == '.')
    {
      last_deliminiter = *in_ptr;
      had_dot = TRUE;
      dot_count++;
      if (dot_count > 3)
        return FALSE;
      if ((digit_count > 3) || (digit_count < 1))
        return FALSE;
      for (int i=0; i 0) && (value <= 255))
        *out_ptr++ = (unsigned char) value;
      else
      {
        if (strcmp(digits, "0") == 0)
          *out_ptr++ = (unsigned char) 0;
        else
          return FALSE;
      }
      digit_count = 0;
    }
    else if (*in_ptr == ':')
    {
      last_deliminiter = *in_ptr;

      if (had_dot)
        return FALSE; // don't allow : after a dot

      if (digit_count)
      {
        // move digits to right
	{
          for (int i=0; i= 4)
        return FALSE;
      if (!isxdigit(*in_ptr))
        return FALSE;
      digits[digit_count] = tolower(*in_ptr);

      digit_count++;
      if (digit_count > 4)
        return FALSE;
      last_was_colon = 0;
    }
    in_ptr++;
  }

  // put last bytes from digits into buffer
  if (digit_count)
  {
    if (last_deliminiter == ':')
    {
      {
	// move digits to right
	for (int i=0; i 3) || (digit_count < 1))
        return FALSE;
      for (int i=0; i 0) && (value <= 255))
        *out_ptr++ = (unsigned char) value;
      else
      {
        if (strcmp(digits, "0") == 0)
          *out_ptr++ = (unsigned char) 0;
        else
          return FALSE;
      }
      digit_count = 0;
    }
    else
      return FALSE;
  }

  // must have between two and seven colons
  if ((colon_count > 7) || (colon_count < 2))
    return FALSE;

  // if there was a dot there must be three of them
  if ((dot_count > 0) && (dot_count != 3))
    return FALSE;

  if (second_used)
  {
    int len_first  = SAFE_INT_CAST(end_first_part - (char*)tmp_address_buffer);
    int len_second = SAFE_INT_CAST(out_ptr - second);

    int i=0;
    for (i=0; ih_length == sizeof(in6_addr))
      {
        in6_addr ipAddr;
        memcpy((void *) &ipAddr, (void *) lookupResult->h_addr,
               sizeof(in6_addr));

        // now lets check out the coloned string
        if (!inet_ntop(AF_INET6, &ipAddr, ds, 48))
          return FALSE;
        debugprintf(4, "from inet_ntop: %s", ds);
        if (!parse_coloned_ipstring(ds))
          return FALSE;

        // save the friendly name
        strcpy(iv_friendly_name, inaddr);
        
        return TRUE;
      }
#endif // SNMP_PP_IPv6
      if (lookupResult->h_length == sizeof(in_addr))
      {
        in_addr ipAddr;

        memcpy((void *) &ipAddr, (void *) lookupResult->h_addr,
               sizeof(in_addr));

        // now lets check out the dotted string
        strcpy(ds,inet_ntoa(ipAddr));

        if (!parse_dotted_ipstring(ds))
          return FALSE;

        // save the friendly name
        strcpy(iv_friendly_name, inaddr);

        return TRUE;
      }
    }         // end if lookup result
    else
    {
#ifdef HAVE_GETHOSTBYNAME_R
      iv_friendly_name_status = herrno;
#else
      iv_friendly_name_status = h_errno;
#endif
      return FALSE;
    }
#endif //PPC603
  }  // end else not a dotted string
  return TRUE;
}

// using the currently defined address, do a DNS
// and try to fill up the name
int IpAddress::addr_to_friendly()
{
  ADDRESS_TRACE;

#if !defined HAVE_GETHOSTBYADDR_R && !defined HAVE_REENTRANT_GETHOSTBYADDR
#ifdef _THREADS
  SnmpSynchronize s(syscall_mutex);
#endif
#endif

#if defined (CPU) && CPU == PPC603
  int lookupResult;
	char hName[MAXHOSTNAMELEN+1];
#else
  hostent *lookupResult;
#endif
  char    ds[48];

  // can't look up an invalid address
  if (!valid_flag) return -1;

  // lets try and get the friendly name from the DNS
  strcpy(ds, this->IpAddress::get_printable());

#if !(defined (CPU) && CPU == PPC603) && defined HAVE_GETHOSTBYADDR_R
  int herrno = 0;
  hostent lookup;
  char buf[2048]; // TODO: Buf size too big?
#endif
  if (ip_version == version_ipv4)
  {
    in_addr ipAddr;

#if defined HAVE_INET_ATON
    if (inet_aton((char*)ds, &ipAddr) == 0)
      return -1;    // bad address
#elif defined HAVE_INET_PTON
    if (inet_pton(AF_INET, (char*)ds, &ipAddr) <= 0)
      return -1; // bad address
#else
    ipAddr.s_addr = inet_addr((char*)ds);
    if (ipAddr.s_addr == INADDR_NONE)
      return -1; // bad address
#endif

#if defined (CPU) && CPU == PPC603
	lookupResult = hostGetByAddr(ipAddr.s_addr, hName);
#elif defined HAVE_GETHOSTBYADDR_R
#if defined(__sun) || defined(__QNX_NEUTRINO)
    lookupResult = gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
                                   AF_INET, &lookup, buf, 2048, &herrno);
#else
    gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
                    AF_INET, &lookup, buf, 2048, &lookupResult, &herrno);
#endif
#else
    lookupResult = gethostbyaddr((char *) &ipAddr, sizeof(in_addr),
                                 AF_INET);
#endif
  }
  else
  {
#ifdef SNMP_PP_IPv6
    in6_addr ipAddr;

    if (inet_pton(AF_INET6, (char*)ds, &ipAddr) <= 0)
      return -1; // bad address

#if defined (CPU) && CPU == PPC603
	lookupResult = hostGetByAddr(ipAddr.s_addr, hName);
#elif defined HAVE_GETHOSTBYADDR_R
#if defined(__sun) || defined(__QNX_NEUTRINO)
    lookupResult = gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
                                   AF_INET6, &lookup, buf, 2048, &herrno);
#else
    gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
                    AF_INET6, &lookup, buf, 2048, &lookupResult, &herrno);
#endif
#else
    lookupResult = gethostbyaddr((char *) &ipAddr, sizeof(in6_addr),
                                 AF_INET6);
#endif // HAVE_GETHOSTBYADDR_R
#else
    return -1;
#endif // SNMP_PP_IPv6
  }
  // if we found the name, then update the iv friendly name
#if defined (CPU) && CPU == PPC603
  if (lookupResult != ERROR)
  {
    strncpy(iv_friendly_name, hName, MAX_FRIENDLY_NAME);
    return 0;
  }
  else
  {
    iv_friendly_name_status = lookupResult;
	return lookupResult;
  }

  return -1; //should not get here

#else
  if (lookupResult)
  {
    strcpy(iv_friendly_name, lookupResult->h_name);
    return 0;
  }
  else
  {
#ifdef HAVE_GETHOSTBYADDR_R
    iv_friendly_name_status = herrno;
#else
    iv_friendly_name_status = h_errno;
#endif
    return iv_friendly_name_status;
  }
#endif //PPC603
}

//----[ IP address format output ]------------------------------------
void IpAddress::format_output() const
{
  ADDRESS_TRACE;

  // if valid format else null it
  if (valid_flag)
  {
    if (ip_version == version_ipv4)
      sprintf((char *) output_buffer,"%d.%d.%d.%d",address_buffer[0],
               address_buffer[1], address_buffer[2], address_buffer[3]);
    else
      sprintf((char *) output_buffer,
               "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
               "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
               address_buffer[ 0], address_buffer[ 1], address_buffer[ 2],
               address_buffer[ 3], address_buffer[ 4], address_buffer[ 5],
               address_buffer[ 6], address_buffer[ 7], address_buffer[ 8],
               address_buffer[ 9], address_buffer[10], address_buffer[11],
               address_buffer[12], address_buffer[13], address_buffer[14],
               address_buffer[15]);
  }
  else
    *(char *)output_buffer = 0;
  IpAddress *nc_this = PP_CONST_CAST(IpAddress*, this);
  nc_this->addr_changed = false;
}

//-----------------------------------------------------------------
// logically and two IPaddresses and
// return the new one
void IpAddress::mask(const IpAddress& ipaddr)
{
  ADDRESS_TRACE;

  if (valid() && ipaddr.valid())
  {
    int count = (ip_version == version_ipv4) ? IPLEN : IP6LEN;

    for (int i = 0; i < count; i++)
      address_buffer[i] = address_buffer[i] & ipaddr.address_buffer[i];
    addr_changed = true;
  }
}


// Get the count of matching bits from the left.
int IpAddress::get_match_bits(const IpAddress match_ip) const
{
  ADDRESS_TRACE;

  int bits = 0;

  if (valid() && match_ip.valid() &&
      (ip_version == match_ip.ip_version))
  {
    int count = (ip_version == version_ipv4) ? IPLEN : IP6LEN;

    for (int i = 0; i < count; i++)
    {
	if (address_buffer[i] == match_ip.address_buffer[i])
	    bits += 8;
	else
	{
	    bits += 7;
	    unsigned char c1 = address_buffer[i] >> 1;
	    unsigned char c2 = match_ip.address_buffer[i] >> 1;
	    while (c1 != c2)
	    {
		c1 = c1 >> 1;
		c2 = c2 >> 1;
		bits--;
	    }
	    break;
	}
    }
  }

  return bits;
}

// Map a IPv4 Address to a IPv6 address.
int IpAddress::map_to_ipv6()
{
  ADDRESS_TRACE;

  if (!valid())
    return FALSE;

  if (ip_version != version_ipv4)
    return FALSE;

  /* just copy IPv4 address to the end of  the buffer
     zero the first 10 bytes and fill 2 Bytes with 0xff */
  memcpy(&address_buffer[12], address_buffer, 4);
  memset(address_buffer, 0, 10);
  address_buffer[10] = 0xff;
  address_buffer[11] = 0xff;

  smival.value.string.len = IP6LEN;
  ip_version = version_ipv6;

  addr_changed = true;
  return TRUE;
}

// Reset the object
void IpAddress::clear()
{
  Address::clear();
  memset(output_buffer, 0, sizeof(output_buffer));
  iv_friendly_name_status = 0;
  ip_version = version_ipv4;
  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
  smival.value.string.len = IPLEN;
}

//=======================================================================
//========== Udp Address Implementation =================================
//=======================================================================

//-------[ construct an IP address with no agrs ]----------------------
UdpAddress::UdpAddress()
  : IpAddress()
{
  ADDRESS_TRACE;

  // Inherits IP Address attributes
  // Always initialize (override) what type this object is
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = UDPIPLEN;
  smival.value.string.ptr = address_buffer;

  sep = ':';
  set_port(0);
}

//-----------------[ construct an Udp address with another Udp address ]---
UdpAddress::UdpAddress(const UdpAddress &udpaddr)
  : IpAddress(udpaddr)
{
  ADDRESS_TRACE;

  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = udpaddr.smival.value.string.len;
  smival.value.string.ptr = address_buffer;

  // Copy the port value
  sep = ':';
  set_port(udpaddr.get_port());

  if (!udpaddr.addr_changed)
  {
    memcpy(output_buffer, udpaddr.output_buffer,
	   sizeof(unsigned char) * OUTBUFF);
    addr_changed = false;
  }
}

// constructor with a dotted string
UdpAddress::UdpAddress(const char *inaddr) : IpAddress()
{
  ADDRESS_TRACE;

  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = UDPIPLEN;
  smival.value.string.ptr = address_buffer;

  valid_flag = parse_address(inaddr);
  addr_changed = true;
}

//-----------------[ construct a UdpAddress from a GenAddress ]--------------
UdpAddress::UdpAddress(const GenAddress &genaddr) : IpAddress()
{
  ADDRESS_TRACE;

  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = UDPIPLEN;
  smival.value.string.ptr = address_buffer;

  valid_flag = genaddr.valid();

  // allow use of an ip or udp genaddress
  if (valid_flag)
  {
    if (genaddr.get_type() == type_udp)
    {
      *this = genaddr.cast_udpaddress();      // copy in the IP address data
    }
    else if (genaddr.get_type() == type_ip)
    {
      *this = genaddr.cast_ipaddress();      // copy in the IP address data
    }
    else
    {
      valid_flag = false;
    }
  }
  sep = ':';
}


//--------[ construct a udp from an IpAddress ]--------------------------
UdpAddress::UdpAddress(const IpAddress &ipaddr):IpAddress(ipaddr)
{
  ADDRESS_TRACE;

  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  if (ip_version == version_ipv4)
      smival.value.string.len = UDPIPLEN;
  else
      smival.value.string.len = UDPIP6LEN;
  smival.value.string.ptr = address_buffer;

  sep = ':';
  addr_changed = true;
  set_port(0);
}

// copy an instance of this Value
SnmpSyntax& UdpAddress::operator=(const SnmpSyntax &val)
{
  ADDRESS_TRACE;

  if (this == &val) return *this;   // protect against assignment from itself

  valid_flag = false;                // will get set TRUE if really valid
  addr_changed = true;
  if (val.valid())
  {
    switch (val.get_syntax())
    {
      case sNMP_SYNTAX_IPADDR:
      {
        UdpAddress temp_udp(val.get_printable());
        *this = temp_udp;        // valid_flag is set by the udp assignment
        break;
      }
      case sNMP_SYNTAX_OCTETS:
        if (((UdpAddress &)val).smival.value.string.len == UDPIPLEN)
        {
          MEMCPY(address_buffer,((UdpAddress &)val).smival.value.string.ptr,
                 UDPIPLEN);
	  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
          valid_flag = true;
          ip_version = version_ipv4;
          smival.value.string.len = UDPIPLEN;
        }
        else if (((UdpAddress &)val).smival.value.string.len == UDPIP6LEN)
        {
          MEMCPY(address_buffer,((UdpAddress &)val).smival.value.string.ptr,
                 UDPIP6LEN);
	  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
          valid_flag = true;
          ip_version = version_ipv6;
          smival.value.string.len = UDPIP6LEN;
        }
        break;
        // NOTE: as a value add, other types could have "logical"
        // mappings, i.e. integer32 and unsigned32
    }
  }
  return *this;
}

// assignment to another UdpAddress object overloaded
UdpAddress& UdpAddress::operator=(const UdpAddress &udpaddr)
{
  ADDRESS_TRACE;

  if (this == &udpaddr) return *this; // protect against assignment from itself

  (IpAddress &)*this = udpaddr; // use ancestor assignment for ipaddr value
  if (ip_version == version_ipv4)
    smival.value.string.len = UDPIPLEN;
  else
    smival.value.string.len = UDPIP6LEN;

  set_port(udpaddr.get_port());        // copy to port value
  if (udpaddr.addr_changed)
  {
    addr_changed = true;
  }
  else
  {
    memcpy(output_buffer, udpaddr.output_buffer,
	   sizeof(unsigned char) * OUTBUFF);
    addr_changed = false;
  }

  return *this;
}

// assignment to another UdpAddress object overloaded
UdpAddress& UdpAddress::operator=(const IpAddress &ipaddr)
{
  ADDRESS_TRACE;

  if (this == &ipaddr) return *this; // protect against assignment from itself

  (IpAddress &)*this = ipaddr; // use ancestor assignment for ipaddr value
  if (ip_version == version_ipv4)
    smival.value.string.len = UDPIPLEN;
  else
    smival.value.string.len = UDPIP6LEN;

  set_port(0);        // copy to port value
  addr_changed = true;
  return *this;
}

UdpAddress& UdpAddress::operator=(const char *inaddr)
{
  ADDRESS_TRACE;

  valid_flag = parse_address(inaddr);
  addr_changed = true;
  return *this;
}

//-----[ IP Address parse Address ]---------------------------------
bool UdpAddress::parse_address(const char *inaddr)
{
  ADDRESS_TRACE;

  addr_changed = true;

  char buffer[MAX_FRIENDLY_NAME];

  unsigned short port = 0;
  if (inaddr && (strlen(inaddr)< MAX_FRIENDLY_NAME))
  {
    strcpy(buffer, inaddr);
    trim_white_space(buffer);
  }
  else
  {
    valid_flag = false;
    return FALSE;
  }
  // look for port info @ the end of the string
  // port can be delineated by a ':' or a '/'
  // if neither are present then just treat it
  // like a normal IpAddress

  int remove_brackets = FALSE;
  int found = FALSE;
  int pos = (int)strlen(buffer) - 1; // safe to cast as max is MAX_FRIENDLY_NAME
  int do_loop = TRUE;
  int another_colon_found = FALSE;

  if (pos < 0)
  {
    valid_flag = false;
    return FALSE;
  }

  // search from the end, to find the start of the port 
  // [ipv4]:port [ipv4]/port ipv4/port ipv4:port [ipv4] ipv4
  // [ipv6]:port [ipv6]/port ipv6/port           [ipv6] ipv6
  while (do_loop)
  {
    if (buffer[pos] == '/')
    {
      found = TRUE;
      sep='/';
      if (buffer[pos -1] == ']')
        remove_brackets = TRUE;
      break;
    }
    if (buffer[pos] == ':')
    {
      if ((pos > 1) && (buffer[pos -1] == ']'))
      {
        found = TRUE;
        remove_brackets = TRUE;
        sep=':';
        break;
      }

      for (int i=pos - 1; i >= 0 ; i--)
        if (buffer[i] == ':')
        {
          another_colon_found = TRUE;
        }
      if (!another_colon_found)
      {
        sep=':';
        found = TRUE;
        break;
      }
    }
    if (buffer[pos] == ']')
    {
      // we found a ] without following a port, so increase pos
      ++pos;
      remove_brackets = TRUE;
      break;
    }
    pos--;
    do_loop = ((found == FALSE) && (pos >= 0) &&
               (another_colon_found == FALSE));
  }

  if (remove_brackets)
  {
    buffer[pos-1] = 0;
    buffer[0] = ' ';
  }

  bool result;

  if (found)
  {
    buffer[pos] = 0;
    port = atoi(&buffer[pos+1]);
    result = IpAddress::parse_address(buffer);
  }
  else
  {
    port = 0;
    result = IpAddress::parse_address(buffer);
  }

  if (ip_version == version_ipv4)
    smival.value.string.len = UDPIPLEN;
  else
    smival.value.string.len = UDPIP6LEN;

  set_port(port);
  return result;
}


//--------[ set the port number ]---------------------------------------
void UdpAddress::set_port(const unsigned short p)
{
  ADDRESS_TRACE;

  unsigned short *port_nbo;
  if (ip_version == version_ipv4)
    port_nbo = (unsigned short*)(address_buffer + IPLEN);
  else
    port_nbo = (unsigned short*)(address_buffer + IP6LEN);
  *port_nbo = htons(p);
  addr_changed = true;
}

//---------[ get the port number ]--------------------------------------
unsigned short UdpAddress::get_port() const
{
  ADDRESS_TRACE;

  if (valid_flag)
  {
    const unsigned short *port_nbo;
    if (ip_version == version_ipv4)
      port_nbo = (const unsigned short*)(address_buffer + IPLEN);
    else
      port_nbo = (const unsigned short*)(address_buffer + IP6LEN);
    return ntohs(*port_nbo);
  }
  return 0;// don't use uninitialized memory
}

//----[ UDP address format output ]------------------------------------
void UdpAddress::format_output() const
{
  ADDRESS_TRACE;

  IpAddress::format_output(); // allow ancestors to format their buffers

  // if valid format else null it
  if (valid_flag)
  {
    if (ip_version == version_ipv4)
      sprintf((char *) output_buffer,"%s%c%d",
               IpAddress::get_printable(),
               '/',//TODO:look for problems in old code and change to "sep"
               get_port() );
      else
        sprintf((char *) output_buffer,"[%s]%c%d",
                 IpAddress::get_printable(),
                 '/',//TODO:look for problems in old code and change to "sep"
                 get_port() );
  }
  else
    *(char*)output_buffer = 0;
  UdpAddress *nc_this = PP_CONST_CAST(UdpAddress*, this);
  nc_this->addr_changed = false;
}

/**
 * Map a IPv4 UDP address to a IPv6 UDP address.
 *
 * @return - TRUE if no error occured.
 */
int UdpAddress::map_to_ipv6()
{
  ADDRESS_TRACE;

  /* Save the port, as IpAddress::map_to_ipv6 destroys it */
  unsigned short old_port = get_port();

  /* Map IpAddress */
  if (!IpAddress::map_to_ipv6())
    return FALSE;

  set_port(old_port);
  smival.value.string.len = UDPIP6LEN;
  ip_version = version_ipv6;

  addr_changed = true;
  return TRUE;
}


#ifdef _IPX_ADDRESS
//=======================================================================
//=========== IPX Address Implementation ================================
//=======================================================================

//----------[ constructor no args ]--------------------------------------
IpxAddress::IpxAddress() : Address()
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = IPXLEN;
  smival.value.string.ptr = address_buffer;

  separator = 0;
  valid_flag = false;
  addr_changed = true;
}


//----------[ constructor with a string arg ]---------------------------
IpxAddress::IpxAddress(const char  *inaddr):Address()
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = IPXLEN;
  smival.value.string.ptr = address_buffer;

  separator = 0;
  valid_flag = parse_address(inaddr);
  addr_changed = true;
}


//-----[ IPX Address copy constructor ]----------------------------------
IpxAddress::IpxAddress(const IpxAddress &ipxaddr)
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = IPXLEN;
  smival.value.string.ptr = address_buffer;

  separator = 0;
  valid_flag = ipxaddr.valid_flag;
  if (valid_flag)
     MEMCPY(address_buffer, ipxaddr.address_buffer, IPXLEN);
  addr_changed = true;
}


//----[ construct an IpxAddress from a GenAddress ]---------------------------
IpxAddress::IpxAddress(const GenAddress &genaddr)
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = IPXLEN;
  smival.value.string.ptr = address_buffer;

  valid_flag = genaddr.valid();
  // allow use of an ipx or ipxsock address
  if (valid_flag)
  {
    if ((genaddr.get_type() == type_ipx) )
    {
      *this = genaddr.cast_ipxaddress();     // copy in the Ipx address data
    }
    else if ((genaddr.get_type() == type_ipxsock) )
    {
      *this = genaddr.cast_ipxsockaddress();  // copy in the Ipx address data
    }
    else
      valid_flag = false;
  }
}

//-----[ IPX Address general = operator ]-------------------------------
SnmpSyntax& IpxAddress::operator=(const SnmpSyntax &val)
{
  // protect against assignment from itself
  if (this == &val) return *this;

  valid_flag = false;              // will set to TRUE if really valid
  if (val.valid()){
    switch (val.get_syntax()){
    case sNMP_SYNTAX_OCTETS:
      if (((IpxAddress &)val).smival.value.string.len == IPXLEN){
        MEMCPY(address_buffer, ((IpxAddress &)val).smival.value.string.ptr, IPXLEN);
        valid_flag = true;
      }
    break;
    }
  }
  addr_changed = true;
  return *this;
}

//--------[ assignment to another IpAddress object overloaded ]----------
IpxAddress& IpxAddress::operator=(const IpxAddress &ipxaddress)
{
  if (this == &ipxaddress) return *this;// protect against assignment from self

  valid_flag = ipxaddress.valid_flag;
  if (valid_flag)
    MEMCPY(address_buffer, ipxaddress.address_buffer, IPXLEN);
  addr_changed = true;
  return *this;
}


//-----[ IPX Address parse Address ]-----------------------------------
// Convert a string to a ten byte ipx address
// On success sets validity  TRUE or FALSE
//
//     IPX address format
//
//  NETWORK ID| MAC ADDRESS
// 01 02 03 04|05 06 07 08 09 10
// XX XX XX XX|XX XX XX XX XX XX
//
//   Valid input format
//
//   XXXXXXXX.XXXXXXXXXXXX
//   Total length must be 21
//   Must have a separator in it
//   First string length must be 8
//   Second string length must be 12
//   Each char must take on value 0-F
//
//
// Input formats recognized
//
//  XXXXXXXX.XXXXXXXXXXXX
//  XXXXXXXX:XXXXXXXXXXXX
//  XXXXXXXX-XXXXXXXXXXXX
//  XXXXXXXX.XXXXXX-XXXXXX
//  XXXXXXXX:XXXXXX-XXXXXX
//  XXXXXXXX-XXXXXX-XXXXXX
bool IpxAddress::parse_address(const char *inaddr)
{
  char unsigned *str1,*str2;
  char temp[30];    // don't destroy original
  char unsigned *tmp;
  size_t z, tmplen;

  // save the orginal source
  if (!inaddr || (strlen(inaddr) >(sizeof(temp)-1))) return FALSE;
  strcpy(temp, inaddr);
  trim_white_space(temp);
  tmplen = strlen(temp);

  // bad total length check
  // 123456789012345678901
  // XXXXXXXX-XXXXXXXXXXXX  21 len
  //
  // XXXXXXXX-XXXXXX-XXXXXX 22 len
  // need at least 21 chars and no more than 22
  if ((tmplen <21) || (tmplen >22))
    return FALSE;

  // convert the string to all lower case
  // this allows hex values to be in upper or lower
  for (z=0;z< tmplen;z++)
    temp[z] = tolower(temp[z]);

  // check for separated nodeid
  // if found remove it
  if (temp[15] == '-')
  {
     for(z=16;z= '0') && (*tmp <= '9'))||   // good 0-9
        ((*tmp >= 'a') && (*tmp <= 'f')))    // or a-f
      tmp++;
    else
      return FALSE;

  // check out the MAC address
  tmp = str2;
  while(*tmp != 0)
    if (((*tmp >= '0') && (*tmp <= '9'))||   // good 0-9
        ((*tmp >= 'a') && (*tmp <= 'f')))    // or a-f
      tmp++;
    else
      return FALSE;

  // convert to target string
  tmp = str1;
  while (*tmp != 0)
  {
  if ((*tmp >= '0') && (*tmp <= '9'))
    *tmp = *tmp - (char unsigned )'0';
  else
    *tmp = *tmp - (char unsigned) 'a' + (char unsigned) 10;
  tmp++;
  }

  // network id portion
  address_buffer[0] = (str1[0]*16) + str1[1];
  address_buffer[1] = (str1[2]*16) + str1[3];
  address_buffer[2] = (str1[4]*16) + str1[5];
  address_buffer[3] = (str1[6]*16) + str1[7];

  tmp = str2;
  while (*tmp != 0)
  {
  if ((*tmp >= '0') && (*tmp <= '9'))
    *tmp = *tmp - (char unsigned) '0';
  else
    *tmp = *tmp - (char unsigned) 'a'+ (char unsigned) 10;
  tmp++;
  }

  address_buffer[4] = (str2[0]*16)  + str2[1];
  address_buffer[5] = (str2[2]*16)  + str2[3];
  address_buffer[6] = (str2[4]*16)  + str2[5];
  address_buffer[7] = (str2[6]*16)  + str2[7];
  address_buffer[8] = (str2[8]*16)  + str2[9];
  address_buffer[9] = (str2[10]*16) + str2[11];

  return TRUE;
}

//----[ IPX address format output ]-------------------------------------
void IpxAddress::format_output() const
{
  if (valid_flag)
    sprintf((char *) output_buffer,
            "%02x%02x%02x%02x%c%02x%02x%02x%02x%02x%02x",
            address_buffer[0],address_buffer[1],
            address_buffer[2],address_buffer[3],'-',
            address_buffer[4],address_buffer[5],
            address_buffer[6],address_buffer[7],
            address_buffer[8],address_buffer[9]);
  else
    *(char*)output_buffer = 0;
  IpxAddress *nc_this = PP_CONST_CAST(IpxAddress*, this);
  nc_this->addr_changed = false;
}


#ifdef _MAC_ADDRESS
// get the host id portion of an ipx address
int IpxAddress::get_hostid(MacAddress& mac) const
{
   if (valid_flag)
   {
       char buffer[18];
       sprintf(buffer,"%02x:%02x:%02x:%02x:%02x:%02x", address_buffer[4],
                address_buffer[5], address_buffer[6], address_buffer[7],
                address_buffer[8], address_buffer[9]);
       MacAddress temp(buffer);
       mac = temp;
       if (mac.valid())
	 return TRUE;
   }
   return FALSE;
}
#endif // function that needs _MAC_ADDRESS

//========================================================================
//======== IpxSockAddress Implementation =================================
//========================================================================

//----------[ constructor no args ]--------------------------------------
IpxSockAddress::IpxSockAddress() : IpxAddress()
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = IPXSOCKLEN;
  smival.value.string.ptr = address_buffer;

  set_socket(0);
  addr_changed = true;
}

//-----------[ construct an IpxSockAddress with another IpxSockAddress]----
IpxSockAddress::IpxSockAddress(const IpxSockAddress &ipxaddr)
  : IpxAddress(ipxaddr)
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = IPXSOCKLEN;
  smival.value.string.ptr = address_buffer;

  // copy the socket value
  set_socket(ipxaddr.get_socket());
  addr_changed = true;
}


//---------------[ construct a IpxSockAddress from a string ]--------------
IpxSockAddress::IpxSockAddress(const char *inaddr):IpxAddress()
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = IPXSOCKLEN;
  smival.value.string.ptr = address_buffer;

  valid_flag = parse_address(inaddr);
  addr_changed = true;
}


//---------------[ construct a IpxSockAddress from a GenAddress ]----------
IpxSockAddress::IpxSockAddress(const GenAddress &genaddr):IpxAddress()
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = IPXSOCKLEN;
  smival.value.string.ptr = address_buffer;

  valid_flag = false;
  unsigned short socketid = 0;
  // allow use of an ipx or ipxsock address
  if ((genaddr.get_type() == type_ipx) )
  {
    valid_flag = genaddr.valid();
    if (valid_flag)
    {
      // copy in the Ipx address data
      IpxAddress temp_ipx((const char *) genaddr);
      *this = temp_ipx;
    }
  }
  else if ((genaddr.get_type() == type_ipxsock) )
  {
    valid_flag = genaddr.valid();
    if (valid_flag)
    {
      // copy in the Ipx address data
      IpxSockAddress temp_ipxsock((const char *) genaddr);
      *this = temp_ipxsock;
      //  socketid info since are making an IpxSockAddress
      socketid = temp_ipxsock.get_socket();
    }
  }
  set_socket(socketid);
  addr_changed = true;
}

//------------[ construct an IpxSockAddress from a IpxAddress ]--------------
IpxSockAddress::IpxSockAddress(const IpxAddress &ipxaddr):IpxAddress(ipxaddr)
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = IPXSOCKLEN;
  smival.value.string.ptr = address_buffer;

  set_socket(0);
  addr_changed = true;
}

// copy an instance of this Value
SnmpSyntax& IpxSockAddress::operator=(const SnmpSyntax &val)
{
  if (this == &val) return *this; // protect against assignment from itself

  valid_flag = false;              // will set to TRUE if really valid
  if (val.valid()){
    switch (val.get_syntax()){
    case sNMP_SYNTAX_OCTETS:
      {
        // See if it is of the Ipx address family
        // This handles IpxSockAddress == IpxAddress
        IpxSockAddress temp_ipx(val.get_printable());
        if (temp_ipx.valid()){
          *this = temp_ipx;                // ipxsock = ipxsock
        }
        // See if it is an OctetStr of appropriate length
        else if (((IpxSockAddress &)val).smival.value.string.len == IPXSOCKLEN){
          MEMCPY(address_buffer,
                 ((IpxSockAddress &)val).smival.value.string.ptr,
                 IPXSOCKLEN);
          valid_flag = true;
        }
      }
      break;
    }
  }
  addr_changed = true;
  return *this;
}

// assignment to another IpAddress object overloaded
IpxSockAddress& IpxSockAddress::operator=(const IpxSockAddress &ipxaddr)
{
  if (this == &ipxaddr) return *this; // protect against assignment from itself

  (IpxAddress&)*this = ipxaddr;         // use ancestor assignment for ipx addr
  set_socket(ipxaddr.get_socket());        // copy socket value
  addr_changed = true;
  return *this;
}

//----[ IPX address format output ]-------------------------------------
void IpxSockAddress::format_output() const
{
  IpxAddress::format_output(); // allow ancestors to format their buffers

  if (valid_flag)
    sprintf((char *) output_buffer,"%s/%d",
            IpxAddress::get_printable(), get_socket());
  else
    *(char*)output_buffer = 0;
  IpxSockAddress *nc_this = PP_CONST_CAST(IpxSockAddress*, this);
  nc_this->addr_changed = false;
}

//-----[ IP Address parse Address ]---------------------------------
bool IpxSockAddress::parse_address(const char *inaddr)
{
   char buffer[MAX_FRIENDLY_NAME];
   unsigned short socketid=0;

   if (inaddr && (strlen(inaddr)< MAX_FRIENDLY_NAME))
     strcpy(buffer, inaddr);
   else
   {
     valid_flag = false;
     return FALSE;
   }
   // look for port info @ the end of the string
   // port can be delineated by a ':' or a '/'
   // if neither are present then just treat it
   // like a normal IpAddress
   char *tmp;
   tmp = strstr(buffer,"/");

   if (tmp != NULL)
   {
     *tmp=0;   // new null terminator
     tmp++;
     socketid = atoi(tmp);
   }
   set_socket(socketid);
   return IpxAddress::parse_address(buffer);
}



//-------------[ set the socket number ]----------------------------------
void IpxSockAddress::set_socket(const unsigned short s)
{
  unsigned short sock_nbo = htons(s);
  MEMCPY(&address_buffer[IPXLEN], &sock_nbo, 2);
  addr_changed = true;
}

//--------------[ get the socket number ]---------------------------------
unsigned short IpxSockAddress::get_socket() const
{
  if (valid_flag)
  {
    unsigned short sock_nbo;
    MEMCPY(&sock_nbo, &address_buffer[IPXLEN], 2);
    return ntohs(sock_nbo);
  }
  return 0; // don't use uninitialized memory
}
#endif // _IPX_ADDRESS

#ifdef _MAC_ADDRESS
//========================================================================
//======== MACAddress Implementation =====================================
//========================================================================

//--------[ constructor, no arguments ]-----------------------------------
MacAddress::MacAddress() : Address()
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = MACLEN;
  smival.value.string.ptr = address_buffer;

  valid_flag = false;
  addr_changed = true;
}

//-----[ MAC Address copy constructor ]---------------------------------
MacAddress::MacAddress(const MacAddress &macaddr)
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = MACLEN;
  smival.value.string.ptr = address_buffer;

  valid_flag = macaddr.valid_flag;
  if (valid_flag)
    MEMCPY(address_buffer, macaddr.address_buffer, MACLEN);
  addr_changed = true;
}

//---------[ constructor with a string argument ]-------------------------
MacAddress::MacAddress(const char  *inaddr):Address()
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = MACLEN;
  smival.value.string.ptr = address_buffer;

  valid_flag = parse_address(inaddr);
  addr_changed = true;
}

//-----[ construct a MacAddress from a GenAddress ]------------------------
MacAddress::MacAddress(const GenAddress &genaddr)
{
  // always initialize SMI info
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = MACLEN;
  smival.value.string.ptr = address_buffer;

  valid_flag = false;
  // allow use of mac address
  if (genaddr.get_type() == type_mac)
  {
    valid_flag = genaddr.valid();
    if (valid_flag)
    {
      // copy in the Mac address data
      *this = genaddr.cast_macaddress();
    }
  }
  addr_changed = true;
}

//------[ assignment to another ipaddress object overloaded ]--------------
MacAddress& MacAddress::operator=(const MacAddress &macaddress)
{
  if (this == &macaddress) return *this;// protect against assignment from self

  valid_flag = macaddress.valid_flag;
  if (valid_flag)
    MEMCPY(address_buffer, macaddress.address_buffer, MACLEN);
  addr_changed = true;
  return *this;
}



//-----[ MAC Address general = operator ]---------------------------------
SnmpSyntax& MacAddress::operator=(const SnmpSyntax &val)
{
  if (this == &val) return *this;  // protect against assignment from itself

  valid_flag = false;              // will set to TRUE if really valid
  if (val.valid())
  {
    switch (val.get_syntax())
    {
      case sNMP_SYNTAX_OCTETS:
	if (((MacAddress &)val).smival.value.string.len == MACLEN)
	{
	  MEMCPY(address_buffer, ((MacAddress &)val).smival.value.string.ptr,
		 MACLEN);
	  valid_flag = true;
	}
	break;
    }
  }
  addr_changed = true;
  return *this;
}

//-----[ MAC Address parse Address ]--------------------------------------
// Convert a string to a six byte MAC address
// On success sets validity TRUE or FALSE
//
//     MAC address format
//
//   MAC ADDRESS
//   01 02 03 04 05 06
//   XX:XX:XX:XX:XX:XX
//   Valid input format
//
//   XXXXXXXXXXXX
//   Total length must be 17
//   Each char must take on value 0-F
//
//
bool MacAddress::parse_address(const char *inaddr)
{
  char temp[30];    // don't destroy original
  char unsigned *tmp;
  size_t z;


  // save the orginal source
  if (!inaddr || (strlen(inaddr) > 30)) return FALSE;
  strcpy(temp, inaddr);
  trim_white_space(temp);

  // bad total length check
  if (strlen(temp) != 17)
     return FALSE;

  // check for colons
  if ((temp[2] != ':')||(temp[5] != ':')||(temp[8]!=':')||(temp[11]!=':')||(temp[14] !=':'))
     return FALSE;

  // strip off the colons
  tmp = (unsigned char *) temp;
  int i = 0;
  while (*tmp != 0)
  {
     if (*tmp != ':')
     {
        temp[i] = *tmp;
        i++;
     }
     tmp++;
  }
  temp[i] = 0;

  // convert to lower
  for(z=0;z= '0') && (*tmp <= '9'))||   // good 0-9
        ((*tmp >= 'a') && (*tmp <= 'f')))    // or a-f
      tmp++;
    else
      return FALSE;

  // convert to target string
  tmp = (unsigned char *) temp;
  while (*tmp != 0)
  {
  if ((*tmp >= '0') && (*tmp <= '9'))
    *tmp = *tmp - (char unsigned )'0';
  else
    *tmp = *tmp - (char unsigned) 'a' + (char unsigned) 10;
  tmp++;
  }

  address_buffer[0] =  (temp[0]*16) + temp[1];
  address_buffer[1] =  (temp[2]*16) + temp[3];
  address_buffer[2] =  (temp[4]*16) + temp[5];
  address_buffer[3] =  (temp[6]*16) + temp[7];
  address_buffer[4] =  (temp[8]*16) + temp[9];
  address_buffer[5] =  (temp[10]*16) + temp[11];

  return TRUE;
}

//----[ MAC address format output ]---------------------------------
void MacAddress::format_output() const
{
  if (valid_flag)
    sprintf((char*)output_buffer,"%02x:%02x:%02x:%02x:%02x:%02x",
	    address_buffer[0], address_buffer[1], address_buffer[2],
	    address_buffer[3], address_buffer[4], address_buffer[5]);
  else
    *(char*)output_buffer = 0;
  MacAddress *nc_this = PP_CONST_CAST(MacAddress*, this);
  nc_this->addr_changed = false;
}

unsigned int MacAddress::hashFunction() const
{
  return ((((address_buffer[0] << 8) + address_buffer[1]) * HASH0)
	+ (((address_buffer[2] << 8) + address_buffer[3]) * HASH1)
        + (((address_buffer[4] << 8) + address_buffer[5]) * HASH2));
}
#endif // _MAC_ADDRESS

//========================================================================
//========== Generic Address Implementation ==============================
//========================================================================

//-----------[ constructor, no arguments ]--------------------------------
GenAddress::GenAddress() : Address()
{
  ADDRESS_TRACE;

  // initialize SMI info
  // BOK: this is generally not used for GenAddress,
  // but we need this to be a replica of the real address'
  // smival info so that operator=SnmpSyntax will work.
  smival.syntax = sNMP_SYNTAX_NULL;                // to be overridden
  smival.value.string.len = 0;                        // to be overridden
  smival.value.string.ptr = address_buffer;        // constant

  valid_flag = false;
  address = 0;
  output_buffer[0] = 0;
}

//-----------[ constructor with a string argument ]----------------------
GenAddress::GenAddress(const char  *addr,
		       const Address::addr_type use_type)
{
  ADDRESS_TRACE;

  // initialize SMI info
  // BOK: smival is generally not used for GenAddress, but
  //      we need this to be a replica of the real address'
  //      smival info so that ::operator=SnmpSyntax
  //      will work.
  smival.syntax = sNMP_SYNTAX_NULL;                // to be overridden
  smival.value.string.len = 0;                        // to be overridden
  smival.value.string.ptr = address_buffer;        // constant

  address = 0;
  parse_address(addr, use_type);

  // Copy real address smival info into GenAddr smival
  // BOK: smival is generally not used for GenAddress, but
  //      we need this to be a replica of the real address'
  //      smival info so that ::operator=SnmpSyntax
  //      will work.
  if (valid_flag ) {
      smival.syntax = ((GenAddress *)address)->smival.syntax;
      smival.value.string.len =
          ((GenAddress *)address)->smival.value.string.len;
      memcpy(smival.value.string.ptr,
          ((GenAddress *)address)->smival.value.string.ptr,
          (size_t)smival.value.string.len);
  }
  output_buffer[0] = 0;
}

//-----------[ constructor with an Address argument ]--------------------
GenAddress::GenAddress(const Address &addr)
{
  ADDRESS_TRACE;

  output_buffer[0] = 0;
  // initialize SMI info
  // BOK: this is generally not used for GenAddress,
  // but we need this to be a replica of the real address'
  // smival info so that operator=SnmpSyntax will work.
  smival.syntax = sNMP_SYNTAX_NULL;                // to be overridden
  smival.value.string.len = 0;                        // to be overridden
  smival.value.string.ptr = address_buffer;        // constant

  valid_flag = false;
  // make sure that the object is valid
  if (!addr.valid()) {
    address = 0;
    return;
  }

  // addr can be a GenAddress object and calling clone() on that is bad...
  if (addr.is_gen_address())
    address = (Address *)(((const GenAddress&)addr).address->clone());
  else
    address = (Address*)addr.clone();

  if (address)
    valid_flag = address->valid();

  // Copy real address smival info into GenAddr smival
  // BOK: smival is generally not used for GenAddress, but
  //      we need this to be a replica of the real address'
  //      smival info so that ::operator=SnmpSyntax
  //      will work.
  if (valid_flag )
  {
    smival.syntax = address->get_syntax();
    smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
    memcpy(smival.value.string.ptr,
           ((GenAddress *)address)->smival.value.string.ptr,
           (size_t)smival.value.string.len);
  }
}

//-----------------[ constructor with another GenAddress object ]-------------
GenAddress::GenAddress(const GenAddress &addr)
{
  ADDRESS_TRACE;

  output_buffer[0] = 0;
  // initialize SMI info
  // BOK: this is generally not used for GenAddress,
  // but we need this to be a replica of the real address'
  // smival info so that operator=SnmpSyntax will work.
  smival.syntax = sNMP_SYNTAX_OCTETS;
  smival.value.string.len = 0;
  smival.value.string.ptr = address_buffer;

  valid_flag = false;
  // make sure that the object is valid
  if (!addr.valid_flag)
  {
    address = 0;
    return;
  }

  address = (Address *)addr.address->clone();
  if (address)
    valid_flag = address->valid();

  // Copy real address smival info into GenAddr smival
  // BOK: smival is generally not used for GenAddress, but
  //      we need this to be a replica of the real address'
  //      smival info so that ::operator=SnmpSyntax
  //      will work.
  if (valid_flag )
  {
    smival.syntax = ((GenAddress *)address)->smival.syntax;
    smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
    memcpy(smival.value.string.ptr,
           ((GenAddress *)address)->smival.value.string.ptr,
           (size_t)smival.value.string.len);
  }
}

//------[ assignment GenAddress = GenAddress ]-----------------------------
GenAddress& GenAddress::operator=(const GenAddress &addr)
{
  ADDRESS_TRACE;

  if (this == &addr) return *this;  // protect against assignment from itself

  valid_flag = false;
  if (address)
  {
    delete address;
    address = 0;
  }
  if (addr.address)
    address = (Address *)(addr.address->clone());
  if (address)
    valid_flag = address->valid();

  // Copy real address smival info into GenAddr smival
  // BOK: smival is generally not used for GenAddress, but
  //      we need this to be a replica of the real address'
  //      smival info so that ::operator=SnmpSyntax
  //      will work.
  if (valid_flag )
  {
    smival.syntax = ((GenAddress *)address)->smival.syntax;
    smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
    memcpy(smival.value.string.ptr,
           ((GenAddress *)address)->smival.value.string.ptr,
           (size_t)smival.value.string.len);
  }

  return *this;
}

//------[ assignment GenAddress = Address ]--------------------------------
GenAddress& GenAddress::operator=(const Address &addr)
{
  ADDRESS_TRACE;

  if (this == &addr) return *this;  // protect against assignment from itself

  valid_flag = false;
  if (address)
  {
    delete address;
    address = 0;
  }

  // addr can be a GenAddress object and calling clone() on that is bad...
  if (addr.is_gen_address())
    address = (Address *)(((const GenAddress&)addr).address->clone());
  else
    address = (Address*)addr.clone();

  if (address)
    valid_flag = address->valid();

  // Copy real address smival info into GenAddr smival
  // BOK: smival is generally not used for GenAddress, but
  //      we need this to be a replica of the real address'
  //      smival info so that ::operator=SnmpSyntax
  //      will work.
  if (valid_flag )
  {
    smival.syntax = ((GenAddress *)address)->smival.syntax;
    smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
    memcpy(smival.value.string.ptr,
           ((GenAddress *)address)->smival.value.string.ptr,
           (size_t)smival.value.string.len);
  }

  return *this;
}


//------[ assignment GenAddress = any SnmpSyntax ]-----------------------
SnmpSyntax& GenAddress::operator=(const SnmpSyntax &val)
{
  ADDRESS_TRACE;

  if (this == &val) return *this; // protect against assignment from itself

  valid_flag = false;             // will get set to TRUE if really valid
  if (address)
  {
    delete address;
    address = 0;
  }

  if (val.valid())
  {
    switch (val.get_syntax() )
    {
      //-----[ ip address case ]-------------
      // BOK: this case shouldn't be needed since there is an explicit
      // GenAddr=Address assignment that will override this assignment.
      // Left here for posterity.
      case sNMP_SYNTAX_IPADDR:
      {
        address = new IpAddress(val.get_printable());
        if (address)
          valid_flag = address->valid();
      }
      break;

      //-----[ udp address case ]------------
      //-----[ ipx address case ]------------
      //-----[ mac address case ]------------
      // BOK:  This is here only to support GenAddr = primitive OctetStr.
      // The explicit GenAddr=Address assignment will handle the cases
      // GenAddr = [UdpAdd|IpxAddr|IpxSock|MacAddr].
      // Note, using the heuristic of octet str len to determine type of
      // address to create is not accurate when address lengths are equal
      // (e.g., UDPIPLEN == MACLEN).  It gets worse if we add AppleTalk or
      // OSI which use variable length addresses!
      case sNMP_SYNTAX_OCTETS:
      {
        unsigned long val_len;
        val_len = ((GenAddress &)val).smival.value.string.len;

        if ((val_len == UDPIPLEN) || (val_len == UDPIP6LEN))
          address = new UdpAddress;
        else if ((val_len == IPLEN) || (val_len == IPLEN))
          address = new IpAddress;
#ifdef _IPX_ADDRESS
        else if (val_len == IPXLEN)
          address = new IpxAddress;
        else if (val_len == IPXSOCKLEN)
          address = new IpxSockAddress;
#endif
#ifdef _MAC_ADDRESS
        else  if (val_len == MACLEN)
          address = new MacAddress;
#endif

        if (address)
        {
          *address = val;
          valid_flag = address->valid();
        }
      }
      break;
    }   // end switch
  }

  // Copy real address smival info into GenAddr smival
  // BOK: smival is generally not used for GenAddress, but
  //      we need this to be a replica of the real address'
  //      smival info so that ::operator=SnmpSyntax
  //      will work.
  if (valid_flag )
  {
    smival.syntax = ((GenAddress *)address)->smival.syntax;
    smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
    memcpy(smival.value.string.ptr,
           ((GenAddress *)address)->smival.value.string.ptr,
           (size_t)smival.value.string.len);
  }

  return *this;
}


// redefined parse address for macs
bool GenAddress::parse_address(const char *addr,
			       const Address::addr_type use_type)
{
  ADDRESS_TRACE;

  if (address) delete address;

  // try to create each of the addresses until the correct one
  // is found

  //BOK: Need to try IPX Sock and IPX before UDP since on Win32,
  //     gethostbyname() seems to think the ipx network number
  //     portion is a valid ipaddress string... stupid WinSOCK!

#ifdef _IPX_ADDRESS
  if ((use_type == Address::type_invalid) ||
      (use_type == Address::type_ipxsock))
  {
    // ipxsock address
    address = new IpxSockAddress(addr);
    valid_flag = address->valid();
    if (valid_flag && ((IpxSockAddress*)address)->get_socket())
      return TRUE;   // ok its an ipxsock address

    delete address;  // otherwise delete it and try another
  }

  if ((use_type == Address::type_invalid) ||
      (use_type == Address::type_ipx))
  {
    // ipx address
    address = new IpxAddress(addr);
    valid_flag = address->valid();
    if (valid_flag)
      return TRUE;   // ok its an ipx address

    delete address;  // otherwise delete it and try another
  }
#endif // _IPX_ADDRESS

  //TM: Must try the derived classes first...one pitfall of the
  //following solution is if someone creates with a port/socket of 0 the
  //class will get demoted to ip/ipx.  The only proper way to do this is
  //to parse the strings ourselves.

  if ((use_type == Address::type_invalid) ||
      (use_type == Address::type_udp))
  {
    // udp address
    address = new UdpAddress(addr);
    valid_flag = address->valid();
    if (valid_flag && ((UdpAddress*)address)->get_port())
      return TRUE;       // ok its a udp address

    delete address;  // otherwise delete it and try another
  }

  if ((use_type == Address::type_invalid) ||
      (use_type == Address::type_ip))
  {
    // ip address
    address = new IpAddress(addr);
    valid_flag = address->valid();
    if (valid_flag)
      return TRUE;       // ok its an ip address

    delete address;   // otherwise delete it and try another
  }

#ifdef _MAC_ADDRESS
  if ((use_type == Address::type_invalid) ||
      (use_type == Address::type_mac))
  {
    // mac address
    address = new MacAddress(addr);
    valid_flag = address->valid();
    if (valid_flag)
      return TRUE;    // ok, its a mac

    delete address;  // otherwise its invalid
  }
#endif // _MAC_ADDRESS

  address = 0;
  return FALSE;
}

#ifdef SNMP_PP_NAMESPACE
}; // end of namespace Snmp_pp
#endif