/*
This file is part of pathload.
pathload 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.
pathload 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 pathload; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*-------------------------------------------------
pathload : an end-to-end available bandwidth
estimation tool
Author : Manish Jain (jain@cc.gatech.edu)
Constantinos Dovrolis (dovrolis@cc.gatech.edu)
Release : Ver 1.3.2
Support : This work was supported by the SciDAC
program of the US department
--------------------------------------------------*/
#define LOCAL
#include "pathload_gbls.h"
#include "pathload_snd.h"
int main(int argc, char* argv[])
{
struct hostent *host_rcv;
struct timeval tv1,tv2;
l_uint32 snd_time ;
l_int32 ctr_code ;
time_t localtm;
int opt_len,mss;
int ret_val ;
int iterate=0;
int done=0;
int latency[30],ord_latency[30];
int i;
int c ;
int errflg=0;
char pkt_buf[256];
char ctr_buff[8];
quiet=0;
while ((c = getopt(argc, argv, "ihHq")) != EOF)
switch (c)
{
case 'H':
case 'h':
help() ;
break ;
case 'i':
iterate=1;
break;
case 'q':
quiet=1;
break;
case '?':
errflg++;
}
if (errflg)
{
fprintf(stderr, "usage: pathload_snd [-q] [-H|-h]\n");
exit(-1);
}
num_stream = NUM_STREAM ;
min_sleeptime();
/* gettimeofday latency */
for(i=0;i<30;i++)
{
gettimeofday(&tv1,NULL);
gettimeofday(&tv2,NULL);
latency[i]=tv2.tv_sec*1000000+tv2.tv_usec-tv1.tv_sec*1000000-tv1.tv_usec;
}
order_int(latency,ord_latency,30);
gettimeofday_latency = ord_latency[15];
#ifdef DEBUG
printf("DEBUG :: gettimeofday_latency = %d\n",gettimeofday_latency);
#endif
/* Control stream: TCP connection */
if ((sock_tcp=socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket(AF_INET,SOCK_STREAM,0):");
exit(-1);
}
opt_len=1;
if (setsockopt(sock_tcp, SOL_SOCKET, SO_REUSEADDR, (char*)&opt_len,
sizeof(opt_len)) < 0)
{
perror("setsockopt(SOL_SOCKET,SO_REUSEADDR):");
exit(-1);
}
bzero((char*)&snd_tcp_addr, sizeof(snd_tcp_addr));
snd_tcp_addr.sin_family = AF_INET;
snd_tcp_addr.sin_addr.s_addr = htonl(INADDR_ANY);
snd_tcp_addr.sin_port = htons(TCPSND_PORT);
if (bind(sock_tcp, (struct sockaddr*)&snd_tcp_addr,sizeof(snd_tcp_addr)) < 0)
{
perror("bind(sock_tcp):");
exit(-1);
}
if (listen(sock_tcp,1) < 0)
{
perror("listen(sock_tcp,1):");
exit(-1);
}
/* Data stream: UDP socket */
if ((sock_udp=socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket(AF_INET,SOCK_DGRAM,0):");
exit(-1);
}
bzero((char*)&snd_udp_addr, sizeof(snd_udp_addr));
snd_udp_addr.sin_family = AF_INET;
snd_udp_addr.sin_addr.s_addr = htonl(INADDR_ANY);
snd_udp_addr.sin_port = htons(0);
if (bind(sock_udp, (struct sockaddr*)&snd_udp_addr,
sizeof(snd_udp_addr)) < 0)
{
perror("bind(sock_udp):");
exit(-1);
}
send_buff_sz = UDP_BUFFER_SZ;
if (setsockopt(sock_udp, SOL_SOCKET, SO_SNDBUF, (char*)&send_buff_sz,
sizeof(send_buff_sz)) < 0)
{
send_buff_sz/=2;
if (setsockopt(sock_udp, SOL_SOCKET, SO_SNDBUF, (char*)&send_buff_sz,
sizeof(send_buff_sz)) < 0)
{
perror("setsockopt(SOL_SOCKET,SO_SNDBUF):");
exit(-1);
}
}
do
{
if ( !quiet)
printf("\n\nWaiting for receiver to establish control stream => ");
fflush(stdout);
/*
Wait until receiver attempts to connect,
starting new measurement cycle
*/
rcv_tcp_adrlen = sizeof(rcv_tcp_addr);
ctr_strm = accept(sock_tcp, (struct sockaddr*)&rcv_tcp_addr, &rcv_tcp_adrlen);
if (ctr_strm < 0)
{
perror("accept(sock_tcp):");
exit(-1);
}
if ( !quiet)
printf("OK\n");
localtm = time(NULL);
gethostname(pkt_buf, 256);
host_rcv=gethostbyaddr((char*)&(rcv_tcp_addr.sin_addr), sizeof(rcv_tcp_addr.sin_addr), AF_INET);
if (host_rcv!=NULL)
{
if ( !quiet)
printf("Receiver %s starts measurements on %s", host_rcv->h_name, ctime(&localtm));
}
else
if ( !quiet)
printf("Unknown receiver starts measurements at %s", ctime(&localtm));
/* Form receiving UDP address */
bzero((char*)&rcv_udp_addr, sizeof(rcv_udp_addr));
rcv_udp_addr.sin_family = AF_INET;
rcv_udp_addr.sin_addr.s_addr = rcv_tcp_addr.sin_addr.s_addr;
rcv_udp_addr.sin_port = htons(UDPRCV_PORT);
/* Connect UDP socket */
connect(sock_udp , (struct sockaddr *)&rcv_udp_addr , sizeof(rcv_udp_addr));
/* Make TCP socket non-blocking */
if (fcntl(ctr_strm, F_SETFL, O_NONBLOCK)<0)
{
perror("fcntl(ctr_strm, F_SETFL, O_NONBLOCK):");
exit(-1);
}
opt_len = sizeof(mss) ;
if (getsockopt(ctr_strm, IPPROTO_TCP, TCP_MAXSEG, (char*)&mss, &opt_len)<0)
{
perror("getsockopt(sock_tcp,IPPROTO_TCP,TCP_MAXSEG):");
exit(-1);
}
snd_max_pkt_sz = mss;
if (snd_max_pkt_sz == 0 || snd_max_pkt_sz== 1448)
snd_max_pkt_sz = 1472; /* Make it Ethernet sized MTU */
else
snd_max_pkt_sz = mss+12;
/* tell receiver our max packet sz */
send_ctr_mesg(ctr_buff, snd_max_pkt_sz) ;
/* receiver's maxp packet size */
while ((rcv_max_pkt_sz = recv_ctr_mesg( ctr_buff)) == -1);
max_pkt_sz = (rcv_max_pkt_sz < snd_max_pkt_sz) ? rcv_max_pkt_sz:snd_max_pkt_sz ;
if ( !quiet )
printf("Maximum packet size :: %ld bytes\n",max_pkt_sz);
/* tell receiver our send latency */
snd_time = (l_int32) send_latency();
send_ctr_mesg(ctr_buff, snd_time) ;
/* wait for receiver to start ADR measurement */
if((ret_val=recv_ctr_mesg(ctr_buff)) == -1 )break;
if ( (((ret_val & CTR_CODE) >> 31) == 1) && ((ret_val & 0x7fffffff) == SEND_TRAIN ) )
{
if ( !quiet)
printf("Estimating ADR to initialize rate adjustment algorithm => ");
fflush(stdout);
if ( send_train() == -1 ) continue ;
if ( !quiet)
printf("Done\n");
}
fleet_id=0;
done=0;
/* Start avail-bw measurement */
while(!done)
{
if (( ret_val = recv_ctr_mesg ( ctr_buff ) ) == -1 ) break ;
if((((ret_val & CTR_CODE) >> 31) == 1) &&((ret_val&0x7fffffff) == TERMINATE))
{
if ( !quiet)
printf("Terminating current run.\n");
done=1;
}
else
{
transmission_rate = ret_val ;
if ((cur_pkt_sz = recv_ctr_mesg( ctr_buff)) <= 0 )break;
if ((stream_len = recv_ctr_mesg( ctr_buff)) <= 0 )break;
if ((time_interval = recv_ctr_mesg( ctr_buff)) <= 0 )break;
if ((ret_val = recv_ctr_mesg ( ctr_buff )) == -1 )break;
/* ret_val = SENd_FLEET */
ctr_code = RECV_FLEET | CTR_CODE ;
if ( send_ctr_mesg(ctr_buff, ctr_code ) == -1 ) break;
if(send_fleet()==-1) break ;
if ( !quiet) printf("\n");
fleet_id++ ;
}
}
close(ctr_strm);
}while (iterate);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1