/*
* Copyright (c) 2006
* Ningning Hu and the Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author(s) may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <pthread.h>
#include "setsignal.h"
#include "common.h"
#define PhaseSleep (0)
#define ABS(a) (((a) < 0) ? -(a) : (a))
extern char *optarg;
extern int optind, opterr, optopt;
char version[] = "2.1";
int delay_num = 0;
int packet_size = PacketSize;
int phase_num = 3;
int probe_num = ProbeNum;
FILE * trace_fp = NULL;
int verbose = 0;
int debug = 0;
double b_bw = 0, competing_bw, PTR_bw, a_bw, c_bw[MaxRepeat];
int probing_phase_count = 0;
double probing_start_time = 0, probing_end_time = 0;
uint16 dst_port = START_PORT, src_port = 0, probing_port;
uint32 dst_ip, src_ip;
char dst_hostname[MAXHOSTNAMELEN], src_hostname[MAXHOSTNAMELEN];
char dst_ip_str[16], src_ip_str[16];
char dst[MAXHOSTNAMELEN], src[MAXHOSTNAMELEN];
int control_sock, probing_sock;
struct sockaddr_in probing_server, probing_server2 ;
RETSIGTYPE (*oldhandler)(int);
double src_gap_sum = 0; // entry value
double avg_src_gap; // entry value
struct pkt_rcd_t dst_gap[MaxProbeNum];
double dst_gap_sum;
double avg_dst_gap;
int dst_gap_count, src_gap_count;
int total_count;
double send_times[MaxProbeNum];
double tlt_src_gap, tlt_dst_gap;
/* keep the data from dst machine, 128 is for other control string */
char msg_buf[sizeof(struct pkt_rcd_t) * MaxProbeNum + 128];
int msg_len;
/* trace item: record the item used to dump out into trace file */
struct trace_item {
int probe_num, packet_size, delay_num;
double send_times[MaxProbeNum];
struct pkt_rcd_t rcv_record[MaxProbeNum];
int record_count;
double avg_src_gap;
double avg_dst_gap;
double b_bw, c_bw, a_bw, ptr;
struct trace_item * next;
};
struct trace_item * trace_list = NULL;
struct trace_item * trace_tail = NULL;
struct trace_item * cur_trace = NULL;
/* usage message */
void Usage()
{
printf("IGI/PTR-%s client usage:\n\n", version);
printf("\tptr-client [-n probe_num] [-s packet_size] [-p dst_port]\n");
printf("\t [-k repeat_num] [-f trace_file] [-vdh] dst_address\n\n");
printf("\t-n set the number of probing packets in each train [60]\n");
printf("\t-s set the length of the probing packets in byte [500B]\n");
printf("\t-p indicate the dst machine's listening port [10241]\n");
printf("\t This is optional, it can itself search for the port\n");
printf("\t that the igi_server is using.\n");
printf("\t-k the number of train probed for each source gap [3]\n");
printf("\t-f dump packet-level trace into trace_file\n");
printf("\t-v verbose mode.\n");
printf("\t-d debug mode.\n");
printf("\t-h print this message.\n");
printf("dst_address can be either an IP address or a hostname\n\n");
exit(1);
}
/* combine the sec & usec of record into a real number */
double get_rcd_time(struct pkt_rcd_t record)
{
return (record.sec + (double)record.u_sec / 1000000);
}
/* dump out all the trace packet time stamps */
void dump_trace()
{
struct trace_item * p;
int i, index;
if (trace_fp == NULL) {
printf("-w not specified, no trace to dump\n");
return;
}
/* first dump out the summary data */
p = trace_list;
index = 0;
fprintf(trace_fp, "\n%%probe_num packet_size delay_num avg_src_gap arv_dst_gap b_bw c_bw a_bw ptr\n");
fprintf(trace_fp, "summary_data = [\n");
while (p != NULL) {
index ++;
fprintf(trace_fp,"%2d %4d %5d %f %f %12.3f %12.3f %12.3f %12.3f\n",
p->probe_num,
p->packet_size,
p->delay_num,
p->avg_src_gap,
p->avg_dst_gap,
p->b_bw,
p->c_bw,
p->a_bw,
p->ptr);
p = p->next;
}
fprintf(trace_fp, "];\n");
fprintf(trace_fp, "phase_num = %d; \n\n", index);
/* then the detail packet trace */
p = trace_list;
index = 0;
while (p != NULL) {
index ++;
fprintf(trace_fp, "send_time_%d = [\n", index);
for (i=1; i<p->probe_num; i++) {
/*fprintf(trace_fp, "%f %f %f ",
p->send_times[i-1], p->send_times[i],
p->send_times[i] - p->send_times[i-1]);*/
fprintf(trace_fp, "%f ",
p->send_times[i] - p->send_times[i-1]);
}
fprintf(trace_fp, "];\n");
fprintf(trace_fp, "send_array_size(%d) = %d; \n\n",
index, p->probe_num - 1);
fprintf(trace_fp, "recv_time_%d = [\n", index);
for (i=0; i<p->record_count-1; i++) {
/*fprintf(trace_fp, "%f %f %f %d ",
get_rcd_time(p->rcv_record[i]),
get_rcd_time(p->rcv_record[i+1]),
get_rcd_time(p->rcv_record[i+1]) -
get_rcd_time(p->rcv_record[i]),
p->rcv_record[i+1].seq);*/
fprintf(trace_fp, "%f %d ",
get_rcd_time(p->rcv_record[i+1]) -
get_rcd_time(p->rcv_record[i]),
p->rcv_record[i+1].seq);
}
fprintf(trace_fp, "];\n");
fprintf(trace_fp, "recv_array_size(%d) = %d; \n\n",
index, p->record_count - 1);
p = p->next;
}
}
/* make a clean exit on interrupts */
RETSIGTYPE cleanup(int signo)
{
if (trace_fp != NULL) {
dump_trace();
fclose(trace_fp);
}
close(probing_sock);
close(control_sock);
/* free trace list */
if (trace_list != NULL) {
struct trace_item * pre, * p;
p = trace_list;
while (p != NULL) {
pre = p;
p = p->next;
free(pre);
}
}
exit(0);
}
void quit()
{
fflush(stdout);
fflush(stderr);
cleanup(1);
exit(-1);
}
/* get the current time */
double get_time()
{
struct timeval tv;
struct timezone tz;
double cur_time;
if (gettimeofday(&tv, &tz) < 0) {
perror("get_time() fails, exit\n");
quit();
}
cur_time = (double)tv.tv_sec + ((double)tv.tv_usec/(double)1000000.0);
return cur_time;
}
/* find the delay number which can set the src_gap exactly as "gap" */
int get_delay_num(double gap)
{
#define Scale (10)
int lower, upper, mid;
double s_time, e_time, tmp;
int k;
lower = 0;
upper = 16;
tmp = 133333;
/* search for upper bound */
s_time = e_time = 0;
while (e_time - s_time < gap * Scale) {
s_time = get_time();
for (k=0; k<upper * Scale; k++) {
tmp = tmp * 7;
tmp = tmp / 13;
}
e_time = get_time();
upper *= 2;
}
/* binary search for delay_num */
mid = (int)(upper + lower) / 2;
while (upper - lower > 20) {
s_time = get_time();
for (k