// -*- c-basic-offset: 4; related-file-name: "../include/click/ipaddress.hh" -*-
/*
 * ipaddress.{cc,hh} -- an IP address class. Useful for its hashcode()
 * method
 * Robert Morris / John Jannotti / Eddie Kohler
 *
 * Copyright (c) 1999-2000 Massachusetts Institute of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, subject to the conditions
 * listed in the Click LICENSE file. These conditions include: you must
 * preserve this copyright notice, and you cannot mention the copyright
 * holders in advertising related to the Software without their permission.
 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
 * notice is a summary of the Click LICENSE file; the license in that file is
 * legally binding.
 */

#include <click/config.h>
#include <click/glue.hh>
#include <click/ipaddress.hh>
#include <click/confparse.hh>
#include <click/straccum.hh>
#include <click/integers.hh>
CLICK_DECLS

/** @class IPAddress
    @brief An IPv4 address.

    The IPAddress type represents an IPv4 address. It supports bitwise
    operations like & and | and provides methods for unparsing IP addresses
    into ASCII dotted-quad form. */

/** @brief Constructs an IPAddress from data.
    @param data the address data, in network byte order

    The bytes data[0]...data[3] are used to construct the address. */
IPAddress::IPAddress(const unsigned char *data)
{
#ifdef HAVE_INDIFFERENT_ALIGNMENT
    _addr = *(reinterpret_cast<const unsigned *>(data));
#else
    memcpy(&_addr, data, 4);
#endif
}

/** @brief Constructs an IPAddress from a human-readable dotted-quad
    representation.
    @param str the unparsed address

    If @a str is not a valid dotted-quad address, then the IPAddress is
    initialized to 0.0.0.0. */
IPAddress::IPAddress(const String &str)
{
    if (!cp_ip_address(str, this))
	_addr = 0;
}

/** @brief Returns an IPAddress equal to the prefix mask of length @a prefix.
    @param prefix_len prefix length; 0 <= @a prefix_len <= 32

    For example, make_prefix(0) is 0.0.0.0, make_prefix(8) is 255.0.0.0, and
    make_prefix(32) is 255.255.255.255.  Causes an assertion failure if @a
    prefix_len is out of range.
    @sa mask_to_prefix_len */
IPAddress
IPAddress::make_prefix(int prefix_len)
{
    assert(prefix_len >= 0 && prefix_len <= 32);
    uint32_t umask = 0;
    if (prefix_len > 0)
	umask = 0xFFFFFFFFU << (32 - prefix_len);
    return IPAddress(htonl(umask));
}

/** @brief Returns the prefix length equivalent to this prefix mask, or -1 if
    this is not a prefix mask.

    Maintains the invariant that make_prefix(@a
    prefix_len).mask_to_prefix_len() == @a prefix_len.
    @sa make_prefix */
int
IPAddress::mask_to_prefix_len() const
{
    uint32_t host_addr = ntohl(_addr);
    int prefix = ffs_lsb(host_addr);
    if (prefix == 0)
	return 0;
    else if (host_addr == (0xFFFFFFFFU << (prefix - 1)))
	return 33 - prefix;
    else
	return -1;
}

/** @brief Unparses this address into a dotted-quad format String.

    Examples include "0.0.0.0" and "18.26.4.9".  Maintains the invariant that,
    for an IPAddress @a a, IPAddress(@a a.unparse()) == @a a. */
String
IPAddress::unparse() const
{
    const unsigned char *p = data();
    char buf[20];
    sprintf(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
    return String(buf);
}

/** @brief Unparses this address into IP address mask format: either a prefix
    length or unparse().

    If mask_to_prefix_len() >= 0, then returns that value as a base-10 String;
    otherwise, returns unparse().  Example results include "8" (for 255.0.0.0)
    and "18.26.4.9". */
String
IPAddress::unparse_mask() const
{
    int prefix_len = mask_to_prefix_len();
    if (prefix_len >= 0)
	return String(prefix_len);
    else
	return unparse();
}

/** @brief Unparses an address prefix, specified by address and mask, into
    "address/mask" format.
    @param mask the address mask

    Equivalent to unparse() + "/" + @a mask.unparse_mask(). */
String
IPAddress::unparse_with_mask(IPAddress mask) const
{
    return unparse() + "/" + mask.unparse_mask();
}

StringAccum &
operator<<(StringAccum &sa, IPAddress ipa)
{
    const unsigned char *p = ipa.data();
    char buf[20];
    int amt;
    amt = sprintf(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
    sa.append(buf, amt);
    return sa;
}

CLICK_ENDDECLS


syntax highlighted by Code2HTML, v. 0.9.1