// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-

// Copyright (c) 2001-2007 International Computer Science Institute
//
// 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 XORP 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 XORP LICENSE file; the license in that file is
// legally binding.

#ident "$XORP: xorp/rip/packet_queue.cc,v 1.11 2007/02/16 22:47:14 pavlin Exp $"

#include "rip_module.h"

#include "libxorp/xorp.h"
#include "libxorp/xlog.h"
#include "libxorp/ipv4.hh"
#include "libxorp/ipv6.hh"

#include "packet_queue.hh"


template <typename A>
PacketQueue<A>::PacketQueue()
    : _buffered_bytes(0), _max_buffered_bytes(64000), _drops(0)
{
}

template <typename A>
PacketQueue<A>::~PacketQueue()
{
    flush_packets();
}

template <typename A>
void
PacketQueue<A>::enqueue_packet(const RipPacket<A>* pkt)
{
    while (_buffered_bytes + pkt->data_bytes() >= _max_buffered_bytes
	   && drop_old() == true);
    _buffered_bytes += pkt->data_bytes();
    _ready_packets.push_back(pkt);
}

template <typename A>
bool
PacketQueue<A>::empty() const
{
    return _ready_packets.empty();
}

template <typename A>
const RipPacket<A>*
PacketQueue<A>::head() const
{
    if (_ready_packets.empty())
	return 0;
    return _ready_packets.front();
}

template <typename A>
void
PacketQueue<A>::pop_head()
{
    if (_ready_packets.empty() == false) {
	_buffered_bytes -= _ready_packets.front()->data_bytes();
	delete _ready_packets.front();
	_ready_packets.pop_front();
    }
}

template <typename A>
bool
PacketQueue<A>::drop_old()
{
    if (_ready_packets.empty() == false) {
	typename QueueRep::iterator i = ++_ready_packets.begin();
	if (i != _ready_packets.end()) {
	    XLOG_INFO("Dropping outbound RIP packet");
	    delete *i;
	    _ready_packets.erase(i);
	    _drops++;
	    return true;
	}
    }
    return false;
}

template <typename A>
uint32_t
PacketQueue<A>::drop_count() const
{
    return _drops;
}

template <typename A>
void
PacketQueue<A>::reset_drop_count()
{
    _drops = 0;
}

template <typename A>
void
PacketQueue<A>::flush_packets()
{
    while (_ready_packets.empty() == false) {
	_buffered_bytes -= _ready_packets.front()->data_bytes();
	delete _ready_packets.front();
	_ready_packets.pop_front();
    }
    XLOG_ASSERT(_buffered_bytes == 0);
}

template <typename A>
void
PacketQueue<A>::set_max_buffered_bytes(uint32_t mbb)
{
    _max_buffered_bytes = mbb;
}

template <typename A>
uint32_t
PacketQueue<A>::max_buffered_bytes() const
{
    return _max_buffered_bytes;
}

template <typename A>
uint32_t
PacketQueue<A>::buffered_bytes() const
{
    return _buffered_bytes;
}


// ----------------------------------------------------------------------------
// Instantiations

#ifdef INSTANTIATE_IPV4
template class PacketQueue<IPv4>;
#endif

#ifdef INSTANTIATE_IPV6
template class PacketQueue<IPv6>;
#endif


syntax highlighted by Code2HTML, v. 0.9.1