/*-GNU-GPL-BEGIN-*
nepim - network pipemeter
Copyright (C) 2005 Everton da Silva Marques
nepim is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
nepim 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 nepim; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*-GNU-GPL-END-*/
/* $Id: win.c,v 1.9 2005/09/30 11:55:40 evertonm Exp $ */
#include <stdio.h>
#include <assert.h>
#include "win.h"
void nepim_win_init(nepim_win_t *win, uint32_t max_size)
{
assert(max_size > 0);
nepim_bit_init(&win->bit_set, max_size);
win->seq_expect = 0;
win->highest_seen_seq = 0;
win->max_size = max_size;
}
void nepim_win_del(nepim_win_t *win)
{
nepim_bit_del(&win->bit_set);
}
static int ring_interval(uint32_t begin, uint32_t past_end, uint32_t i)
{
if (begin <= past_end)
return (i >= begin) && (i < past_end);
return (i >= begin) || (i < past_end);
}
static int strict_ring_interval(uint32_t max, uint32_t begin, uint32_t past_end, uint32_t i)
{
assert(begin < max);
assert(past_end < max);
assert(i < max);
return ring_interval(begin, past_end, i);
}
static void seen_seq(nepim_win_t *win, uint32_t seq)
{
long long distance = win->highest_seen_seq;
distance -= seq;
if (distance < 0)
distance = -distance;
/* seq wrapped? */
if (distance > (1 << 31)) {
win->highest_seen_seq = seq;
return;
}
if (seq > win->highest_seen_seq)
win->highest_seen_seq = seq;
}
#define NEPIM_WIN_PAST_MARK(seq, max) (((seq) + ((max) >> 1)) % (max))
#define NEPIM_WIN_LOSS_MARK(seq, max) (((seq) + ((max) >> 2)) % (max))
void nepim_win_add(nepim_win_t *win, uint32_t seq, int *lost, int *dup)
{
int mod_seq;
int mod_expect;
int mod_past_mark;
int mod_loss_mark;
assert(lost);
assert(dup);
assert(*lost >= 0);
assert(*dup >= 0);
seen_seq(win, seq);
mod_seq = seq % win->max_size;
mod_expect = win->seq_expect % win->max_size;
mod_past_mark = NEPIM_WIN_PAST_MARK(win->seq_expect, win->max_size);
mod_loss_mark = NEPIM_WIN_LOSS_MARK(win->seq_expect, win->max_size);
assert(!nepim_bit_isset(&win->bit_set, mod_expect));
/* Expected seq ? */
if (mod_seq == mod_expect) {
for (++win->seq_expect;
nepim_bit_isset(&win->bit_set, win->seq_expect % win->max_size);
++win->seq_expect) {
nepim_bit_clear(&win->bit_set, win->seq_expect % win->max_size);
}
return;
}
/* Future seq ? -> check possible duplicate, mark as seen */
if (strict_ring_interval(win->max_size, mod_expect, mod_loss_mark, mod_seq)) {
if (nepim_bit_isset(&win->bit_set, mod_seq))
++*lost;
nepim_bit_set(&win->bit_set, mod_seq);
return;
}
/* Far future seq ? -> push "expect" mark forward while registering losses */
if (strict_ring_interval(win->max_size, mod_loss_mark, mod_past_mark, mod_seq)) {
int step = win->max_size >> 3;
int mod_seq_1 = (mod_seq + step) % win->max_size;
assert(step > 0);
nepim_bit_set(&win->bit_set, mod_seq);
for (; !strict_ring_interval(win->max_size,
win->seq_expect % win->max_size,
NEPIM_WIN_LOSS_MARK(win->seq_expect, win->max_size),
mod_seq_1);
++win->seq_expect) {
int mod_exp = win->seq_expect % win->max_size;
if (nepim_bit_isset(&win->bit_set, mod_exp))
nepim_bit_clear(&win->bit_set, mod_exp);
else
++*lost;
}
/* find first non-received position */
for (; nepim_bit_isset(&win->bit_set, win->seq_expect % win->max_size);
++win->seq_expect) {
nepim_bit_clear(&win->bit_set, win->seq_expect % win->max_size);
}
assert(!nepim_bit_isset(&win->bit_set, win->seq_expect % win->max_size));
return;
}
/* Past seq? -> register as duplicate */
assert(strict_ring_interval(win->max_size, mod_past_mark, mod_expect, mod_seq));
assert(!nepim_bit_isset(&win->bit_set, mod_seq));
++*dup;
}
int nepim_win_extract_loss(nepim_win_t *win)
{
int mod_exp = win->seq_expect % win->max_size;
int mod_seq = win->highest_seen_seq % win->max_size;
int mod_loss_mark = NEPIM_WIN_LOSS_MARK(win->highest_seen_seq, win->max_size);
int lost = 0;
assert(strict_ring_interval(win->max_size, mod_exp, mod_loss_mark, mod_seq));
for (; mod_exp != mod_seq; ++mod_exp, mod_exp %= win->max_size) {
if (!nepim_bit_isset(&win->bit_set, mod_exp)) {
++lost;
#if 0
fprintf(stderr, "LOSS: exp=%d seq=%d loss=%d\n", mod_exp, mod_seq, lost);
#endif
}
}
return lost;
}
syntax highlighted by Code2HTML, v. 0.9.1