/*-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: common.c,v 1.42 2005/10/13 19:57:39 evertonm Exp $ */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <assert.h>

#include "common.h"
#include "sock.h"
#include "conf.h"


const char * const NEPIM_LABEL_PARTIAL      = "part";
const char * const NEPIM_LABEL_TOTAL        = "avg";
const char * const NEPIM_LABEL_TOTAL_BROKEN = "avg(broken)";


const char *nepim_version()
{
  return "0.15";
}

static void nepim_dump_stat(FILE *out, const char *label,
			    long long bytes_recv, long long bytes_sent, 
			    float interval, long sec_start, 
			    long sec_duration, int reads, int writes)
{
  float kbps_recv = bytes_recv / (interval * 125); /* 8/1000 = 1/125 */
  float kbps_sent = bytes_sent / (interval * 125); /* 8/1000 = 1/125 */
  float read_rate = reads / interval;
  float write_rate = writes / interval;
  struct timeval now;
  int result;
      
  result = gettimeofday(&now, 0);
  assert(!result);

  fprintf(out,
	  ": %s %ld/%ld kbps_in=%.2f kbps_out=%.2f rcv/s=%.2f snd/s=%.2f", 
	  label,
	  now.tv_sec - sec_start,
	  sec_duration,
	  kbps_recv,
	  kbps_sent,
	  read_rate,
	  write_rate);
}

void nepim_pipe_stat(FILE *out, const char *label, int sd,
		     long long bytes_recv, long long bytes_sent, 
		     float interval, long sec_start, 
		     long sec_duration, int reads, int writes)
{
  fprintf(out, "%d", sd);

  nepim_dump_stat(out, label, bytes_recv, bytes_sent, 
		  interval, sec_start, sec_duration,
		  reads, writes);

  fprintf(out, "\n");
}

void nepim_slot_stat(FILE *out, const char *label, int sd,
		     int local_slot, int remote_slot,
		     long long bytes_recv, long long bytes_sent, 
		     float interval, long sec_start, 
		     long sec_duration, int reads, int writes,
		     int pkt_lost, int pkt_dup)
{
  fprintf(out, "%d %d-%d", sd, local_slot, remote_slot);

  nepim_dump_stat(out, label, bytes_recv, bytes_sent, 
		  interval, sec_start, sec_duration,
		  reads, writes);

  if (nepim_global.udp_exp_stats) {
    float loss_ratio = 100 * pkt_lost;
    float dup_ratio = 100 * pkt_dup;
    
    loss_ratio /= reads;
    dup_ratio /= reads;
    
    fprintf(out,
	    " lost=%d/%.2f%% dup=%d/%.2f%%",
	    pkt_lost, loss_ratio, pkt_dup, dup_ratio);
  }

  fprintf(out, "\n");
}

void report_broken_pipe_stat(FILE *out, const nepim_pipe_t *pipe)
{
  struct timeval now;
  int result;
  float elapsed_sec;
  float elapsed_usec;
  float elapsed;
  const nepim_session_t *session = &pipe->session;
      
  result = gettimeofday(&now, 0);
  assert(!result);

  elapsed_sec = now.tv_sec - session->tv_start.tv_sec;
  elapsed_usec = now.tv_usec - session->tv_start.tv_usec;

  elapsed = elapsed_sec + elapsed_usec / 1000000;

  nepim_pipe_stat(out, 
		  NEPIM_LABEL_TOTAL_BROKEN,
		  pipe->sd, 
		  session->byte_total_recv,
		  session->byte_total_sent,
		  elapsed, 
		  session->tv_start.tv_sec,
		  session->test_duration,
		  session->total_reads,
		  session->total_writes);
}

void report_broken_slot_stat(FILE *out, const nepim_slot_t *slot)
{
  struct timeval now;
  int result;
  float elapsed_sec;
  float elapsed_usec;
  float elapsed;
  const nepim_session_t *session = &slot->session;
      
  result = gettimeofday(&now, 0);
  assert(!result);

  elapsed_sec = now.tv_sec - session->tv_start.tv_sec;
  elapsed_usec = now.tv_usec - session->tv_start.tv_usec;

  elapsed = elapsed_sec + elapsed_usec / 1000000;

  nepim_slot_stat(out, 
		  NEPIM_LABEL_TOTAL_BROKEN,
		  slot->udp_sd,
		  slot->index, 
		  slot->index_remote,
		  session->byte_total_recv,
		  session->byte_total_sent,
		  elapsed, 
		  session->tv_start.tv_sec,
		  session->test_duration,
		  session->total_reads,
		  session->total_writes,
		  slot->total_pkt_lost,
		  slot->total_pkt_dup);
}

#define NEPIM_MEGA (1000000)
#define NEPIM_8MEGA (8000000)

void nepim_timer_usec_add(struct timeval *tv, susec_t usec)
{
  tv->tv_usec += usec;

  /* overflow? */
  if (tv->tv_usec >= NEPIM_MEGA) {
    int sec = tv->tv_usec / NEPIM_MEGA;
    tv->tv_usec %= NEPIM_MEGA;
    tv->tv_sec += sec;
  }

  assert(tv->tv_usec < NEPIM_MEGA);
}

long long nepim_bps2bytes(long long bps_bit_rate, susec_t usec_delay)
{
  long long bytes;

  bytes = bps_bit_rate;
  bytes *= usec_delay;
  bytes /= NEPIM_8MEGA;

  return bytes;
}

long long nepim_min_bps(susec_t usec_delay)
{
  long long rate;

  rate = NEPIM_8MEGA;
  rate /= usec_delay;

  return rate;
}

int nepim_pps2packets(int pps_pkt_rate, susec_t usec_delay)
{
  long long pkts;

  pkts = pps_pkt_rate;
  pkts *= usec_delay;
  pkts /= NEPIM_MEGA;

  assert(pkts > -2000000000);
  assert(pkts < 2000000000);

  return pkts;
}

int nepim_min_pps(susec_t usec_delay)
{
  int pps;

  pps = NEPIM_MEGA;
  pps /= usec_delay;

  return pps;
}


syntax highlighted by Code2HTML, v. 0.9.1