/*
This file is part of pathrate.
pathrate 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 of the License, or
(at your option) any later version.
pathrate 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 pathrate; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*-------------------------------------------------
pathrate : an end-to-end capcity estimation tool
Author : Constantinos Dovrolis ([email protected] )
Ravi S Prasad ( [email protected] )
Release : Ver 2.4.1
Support : This work was supported by the SciDAC
program of the US department
--------------------------------------------------*/
#define LOCAL
#include "pathrate.h"
#include "pathrate_rcv.h"
int main(int argc, char* argv[])
{
extern char *optarg;
struct hostent *host_snd;
struct sockaddr_in snd_tcp_addr, rcv_udp_addr;
int
opt_len,
rcv_buff_sz,
abort_phase1=0,
outlier_lim,
pack_incr_step,
tmp,
mss;
int errflg=0;
int file=0;
int append=0;
int gothostname=0;
int quick_term=0;
int
i, j, c,
sum_rtt,
ctr_code,
round,
train_len,
prev_train_len=2,
train_len_P1,
max_train_len,
no_pack_sizes=40,
no_trains,
no_trains_P1,
no_trains_per_size,
trains_msrd=0,
trains_rcvd=0,
train_no,
trains_per_size=0,
no_modes_P1=0,
no_modes_P2=0,
cap_mode_ind=0,
bad_tstamps=0,
train_spacing,
min_train_spacing,
max_train_spacing,
max_pack_sz,
min_pack_sz_P1,
pack_sz;
short
enough_data,
path_overflow,
adr_narrow,
bad_train,
bad_trains,
measurs_vld_P1[NO_TRAINS_P1],
measurs_vld_P2[NO_TRAINS_P2];
char
filename[75],
random_data[MAX_PACK_SZ],
pack_buf[MAX_PACK_SZ];
struct timeval current_time, first_time, *time_stmps=NULL;
double
bw_msr,
bin_wd,
bw_range,
avg_bw,
rtt,
adr,
std_dev,
delta,
min_possible_delta,
min_OSdelta[500],
ord_min_OSdelta[500],
mode_value,
merit,
max_merit,
measurs_P1[NO_TRAINS_P1],
measurs_P2[NO_TRAINS_P2],
ord_measurs_P1[NO_TRAINS_P1],
ord_measurs_P2[NO_TRAINS_P2];
mode_struct
curr_mode,
modes_P1[MAX_NO_MODES],
modes_P2[MAX_NO_MODES];
time_t localtm;
/* Print histogram of bandwidth measurements */
/*
Check command line arguments
*/
verbose = 1;
netlog = 0;
append = 0;
while ((c = getopt(argc, argv, "s:N:vQhHqo:O:")) != EOF){
switch (c) {
case 's':
gothostname = 1;
strcpy(hostname,optarg);
break;
case 'Q':
quick_term = 1;
break;
case 'q':
Verbose=0;
verbose=0;
break;
case 'v':
Verbose=1;
break;
case 'o':
file=1;
strcpy(filename,optarg);
break;
case 'O':
file=1;
append=1;
strcpy(filename,optarg);
break;
case 'N':
netlog=1;
strcpy(filename,optarg);
break;
case 'H':
help() ;
errflg++;
break ;
case 'h':
help() ;
errflg++;
break ;
case '?':
errflg++;
}
}
if (file){
if (append){
pathrate_fp = fopen(filename,"a");
fprintf(pathrate_fp, "\n\n");
}
else{
pathrate_fp = fopen(filename,"w");
fprintf(pathrate_fp, "\n\n");
}
}
else{
pathrate_fp = fopen("pathrate.output" , "a" ) ;
fprintf(pathrate_fp, "\n\n");
}
if (netlog) {
netlog_fp = fopen(filename,"a");
}
if (errflg || !gothostname) {
if (!gothostname) fprintf(stderr,"Need to specify sender's hostname!\n");
(void)fprintf(stderr, "usage: pathrate_rcv [-H|-h] [-Q] [-q|-v] [-o|-O <filename>]\
[-N <filename>] -s <sender>\n");
exit (-1);
}
if ((host_snd = gethostbyname(hostname)) == 0) {
/* check if the user gave ipaddr */
if ( ( snd_tcp_addr.sin_addr.s_addr = inet_addr(hostname) ) == -1 ) {
fprintf(stderr,"%s: unknown host\n", hostname);
exit(-1);
}
else
host_snd = gethostbyaddr(hostname,256,AF_INET);
}
/* Print arguments in the log file */
for (i=0; i<argc; i++)
fprintf(pathrate_fp, "%s ", argv[i]);
fprintf(pathrate_fp, "\n");
/* Print date and path info at trace file */
localtm = time(NULL);
gethostname(pack_buf, 256);
sprintf(message,"\tpathrate run from %s to %s on %s",
hostname, pack_buf, ctime(&localtm));
prntmsg(pathrate_fp);
if(verbose) prntmsg(stdout);
/*
Create data stream: UDP socket
*/
if ((sock_udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket(AF_INET,SOCK_DGRAM):");
exit(-1);
}
bzero((char*)&rcv_udp_addr, sizeof(rcv_udp_addr));
rcv_udp_addr.sin_family = AF_INET;
rcv_udp_addr.sin_addr.s_addr = htonl(INADDR_ANY);
rcv_udp_addr.sin_port = htons(UDPRCV_PORT);
if (bind(sock_udp, (struct sockaddr*)&rcv_udp_addr, sizeof(rcv_udp_addr)) < 0) {
perror("bind(sock_udp):");
exit(-1);
}
rcv_buff_sz = UDP_BUFFER_SZ;
if (setsockopt(sock_udp,SOL_SOCKET,SO_RCVBUF,(char*)&rcv_buff_sz,sizeof(rcv_buff_sz))<0){
perror("setsockopt(sock_udp,SOL_SOCKET,SO_RCVBUF):");
exit(-1);
}
/*
Create control stream: TCP connection
*/
if ((sock_tcp = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket(AF_INET, SOCK_STREAM):");
exit(-1);
}
opt_len = 1;
if (setsockopt(sock_tcp, SOL_SOCKET, SO_REUSEADDR, (char*)&opt_len, sizeof(opt_len)) < 0) {
perror("setsockopt(sock_tcp,SOL_SOCKET,SO_REUSEADDR):");
exit(-1);
}
bzero((char*)&snd_tcp_addr, sizeof(snd_tcp_addr));
snd_tcp_addr.sin_family = AF_INET;
memcpy((void*)&(snd_tcp_addr.sin_addr.s_addr), host_snd->h_addr, host_snd->h_length);
snd_tcp_addr.sin_port = htons(TCPSND_PORT);
if (connect(sock_tcp,(struct sockaddr*)&snd_tcp_addr,sizeof(snd_tcp_addr))<0) {
perror("Make sure that pathrate_snd runs at sender:");
exit(-1);
}
/*
Estimate round-trip time
*/
sum_rtt=0;
ctr_code=0;
for(i=0; i<10; i++) {
char mybuff[1024];
gettimeofday(&first_time, (struct timezone*)0);
send_ctr_msg(ctr_code);
recv_ctr_msg(sock_tcp, mybuff);
gettimeofday(¤t_time, (struct timezone*)0);
if (i>0) sum_rtt += time_to_us_delta(first_time, current_time);/* ignore first rtt */
}
rtt = (double) (sum_rtt/9000.);
sprintf(message,"\t--> Average round-trip time: %.1fms\n\n", rtt);
prntmsg(pathrate_fp);
if (verbose) prntmsg(stdout);
/*
Determine minimum train spacing based on rtt
*/
min_train_spacing = MIN_TRAIN_SPACING/1000; /* make msec */
if (min_train_spacing < rtt*1.25) {
/* if the rtt is not much smaller than the specified train spacing,
* increase minimum train spacing based on rtt */
min_train_spacing = rtt*1.25;
}
max_train_spacing = 2 * min_train_spacing;
train_spacing = min_train_spacing;
ctr_code = TRAIN_SPACING | (train_spacing<<8);
send_ctr_msg(ctr_code);
/*
Send maximum packet size to sender (based on TCP MSS)
*/
opt_len = sizeof(mss);
if (getsockopt(sock_tcp, IPPROTO_TCP, TCP_MAXSEG, (char*)&mss, &opt_len)<0){
perror("getsockopt(sock_tcp,IPPROTO_TCP,TCP_MAXSEG):");
exit(-1);
}
max_pack_sz = mss;
if (max_pack_sz == 0)
max_pack_sz = 1472; /* Make it Ethernet sized MTU */
else {
max_pac