Skip to content

Instantly share code, notes, and snippets.

Created July 4, 2013 11:18
  • Star 12 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save anonymous/5926902 to your computer and use it in GitHub Desktop.
/*
** Copyright 2000
** by
** The Board of Trustees of the
** Leland Stanford Junior University.
** All rights reserved.
**
**
** Disclaimer Notice
**
** The items furnished herewith were developed under the sponsorship
** of the U.S. Government. Neither the U.S., nor the U.S. D.O.E., nor
** the Leland Stanford Junior University, nor their employees, makes any
** warranty, express or implied, or assumes any liability or
** responsibility for accuracy, completeness or usefulness of any
** information, apparatus, product or process disclosed, or represents
** that its use will not infringe privately-owned rights. Mention of any
** product, its manufacturer, or suppliers shall not, nor is it intended to,
** imply approval, disapproval, or fitness for any particular use. The U.S.
** and the University at all times retain the right to use and disseminate the
** furnished items for any purpose whatsoever.
**
** Notice 91 02 01
**
** Work supported by the U.S. Department of Energy under contract
** DE-AC03-76SF00515.
*/
/*
** SYNACK tool developed by Kishan Jayaraman
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <math.h>
#include <fcntl.h>
#include <sysexits.h>
#include <pthread.h>
#define MYPORT 5000
#define HISPORT 22
#define MYIP "doris.slac.stanford.edu"
#define HISIP "doris.slac.stanford.edu"
#define BACKLOG 1
#define MAXSECS 2146 /* 2147,483,647 usec */
#define VERY_LONG ((time_t)MAXSECS*1000000)
#define MAXLINE 1
#define TRUE 1
#define FALSE 0
#define MAX_CON 100000
struct sockaddr_in my_addr;
struct sockaddr_in his_addr;
struct hostent *myadr, *hisadr;
struct in_addr inaddr;
struct addrinfo *webadr;
time_t tvsub();
char * tvprint();
void err();
void record_stats();
void statistics();
void print_stats();
void printstats();
void callstats();
double xsqrt();
int isnumeric();
void rterror();
void err_print();
void sock_init();
void sock_close();
struct timeval* get_time();
int connect_start();
int select_start();
int select_condition();
void connection_tcp();
void *call_connection();
int max_threads();
void finish();
void exit_interrupt();
void interval_between_synacks();
int percent1 = 25; /* 1st percentile */
int percent2 = 75; /* 2nd percentile */
int hisport = 22; /* port number of server */
int counter=0;
int sockfd[MAX_CON], flags[MAX_CON];
char *ipname, *ipnum;
fd_set rset[MAX_CON], wset[MAX_CON];
struct timeval tvalfresh;
int secs = 0; /* secs for timeout */
long int millisecs=0; /* millisecondes for timeout */
int threads;
pthread_t tid[MAX_CON];
int key = 0;
/* Statistics Structure */
typedef struct _stats {
time_t rttmin; /* minimum round-trip time */
time_t rttmax; /* maximum round-trip time */
double rttsum; /* sum of recorded rtt values */
double rttssq; /* sum of squared rtt values */
time_t rttmed; /* median of rtt values*/
time_t rttiqr; /* interquartile range of rtt values */
time_t rttpct1; /* rtt value for the 1st %ile */
time_t rttpct2; /* rtt value for the 2nd %ile */
int rcvd; /* no. of successful connections */
int seq_no; /* sequence number */
time_t rttarray[1000000]; /* array of rtt values */
}stats;
stats synack = { VERY_LONG, 0 , 0, 0, 0, 0, 0, 0, 0, 0, 0};
typedef struct timer {
int sec;
int usec;
}timer;
extern char *optarg;
extern int optind;
char Usage[] = "\
Usage: synack [-options] host\n\
Common options:\n\
-p ## port number to send to (default 22)\n\
-k ## no. of connections to be made\n\
-i ## Time interval between connections in secs (default 1 sec)\n\
-u ## Time interval between connections in microsecs (minimum 20000 microsecs)\n\
-z ## Percentile 1 (default 25)\n\
-Z ## Percentile 2 (default 75)\n\
-S ## Timout in secs (default 1 Sec)\n\
-s ## Timeout in millisecs \n\
";
int
main(argc,argv)
int argc;
char **argv;
{
/* ********************************************************************** */
int sin_size,c;
int nconnect,nselect,nselectval,nread,nweb,nset;
int iscount = FALSE;
long int count = 1;
long int i,j;
int sig = 0;
int time = 0;
unsigned long gw=0;
char myip[] = MYIP;
char *hisip ;
char *wmaddr = "wmatthews=home-1.stanford.edu";
char *wmport = "80";
char line[MAXLINE +1];
struct timeval *sendtime;
struct timeval *recvtime;
struct timeval tv1;
struct timeval tv2;
struct timeval tval;
timer interval;
time_t rtt = 0;
/* Command line options */
long int length = 0; /* default value */
int interval_sec = 0; /* time interval between connections in secs */
int interval_usec = 0; /* time interval between connections in microsecs */
/* **************************************************************************** */
if (argc < 1) goto usage;
while ((c = getopt(argc, argv, "p:k:i:u:z:Z:s:S:")) != -1) {
switch (c) {
case 'p':
hisport = atoi(optarg);
break;
case 'k':
length = atoi(optarg);
break;
case 'i':
interval_sec = atoi(optarg);
break;
case 'u':
interval_usec = atoi(optarg);
break;
case 'z':
percent1 = atoi(optarg);
break;
case 'Z':
percent2 = atoi(optarg);
break;
case 'S':
secs = atoi(optarg);
break;
case 's':
millisecs = atoi(optarg);
break;
default:
goto usage;
}
}
if ( (interval_sec == 0) && (interval_usec == 0) ) {
interval.sec = 1;
interval.usec = 0;
}
else {
interval.sec = interval_sec;
interval.usec = interval_usec;
}
if ( (interval_sec == 0) && (interval_usec < 20000) )
interval.usec = 20000;
if (length > 0)
iscount = TRUE;
if (secs == 0 && millisecs == 0)
secs = 10;
tvalfresh.tv_sec = secs;
tvalfresh.tv_usec = millisecs * 1000;
if (optind == argc)
goto usage;
hisip = argv[optind];
myadr = gethostbyname(myip);
hisadr = gethostbyname(hisip);
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
myadr = gethostbyaddr((char *) &my_addr.sin_addr.s_addr, sizeof(struct in_addr*), AF_INET);
bzero(&(my_addr.sin_zero), 8);
if(!hisadr) {
rterror("Unknown host %s", hisip);
exit(EX_NOHOST);
}
his_addr.sin_family = AF_INET;
his_addr.sin_port = htons(hisport);
his_addr.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr*)hisadr->h_addr)));
if (isnumeric(hisip)) {
hisadr->h_name = NULL;
hisadr = gethostbyaddr((char *) &his_addr.sin_addr.s_addr, sizeof(struct in_addr*), AF_INET);
}
bzero(&(his_addr.sin_zero), 8);
if (isnumeric(hisip) && !hisadr) {
printf("\nAddress Information of Server not listed in Domain\n");
hisadr = gethostbyname(hisip);
}
if (!isnumeric(hisadr->h_name))
ipname = hisadr->h_name;
else
ipname = NULL;
ipnum = (char *)inet_ntoa(*((struct in_addr *)hisadr->h_addr));
if (iscount)
if (ipname != NULL)
printf("\nSYN-ACK to %s (%s), %d Packets\n\n", ipname, ipnum, length);
else
printf("\nSYN-ACK to %s , %d Packets\n\n", ipnum, length);
else
if (ipname != NULL)
printf("\nSYN-ACK to %s (%s)\n\n", ipname, ipnum);
else
printf("\nSYN-ACK to %s \n\n", ipnum);
/*
** BEGINNNING OF CONNECT LOOP
** -----------------------------
*/
while ( (!sig) && (((iscount) && (count <= length)) || (!iscount)) ) {
threads = max_threads(secs,interval);
i = pthread_create(&tid[counter], NULL, call_connection, NULL);
j = pthread_detach(tid[counter]);
if (i == EAGAIN) {
printf("\n\nOOPS....LIMIT REACHED ON MAX. NO OF THREADS :( \n\n");
goto out_of_loop;
}
if (counter == threads)
counter = 0;
else
counter++;
interval_between_synacks(interval);
count++;
synack.seq_no++;
signal(SIGINT, exit_interrupt);
if (key == 1) {
finish();
}
}
/*
** END OF CONNECT LOOP
** -------------------
*/
out_of_loop:
printf("\nWaiting for outstanding packets (if any)..........\n\n");
for (i=0; i <= threads; i++)
pthread_join(tid[i], NULL);
sleep(1);
print_stats(&synack);
exit(0);
usage:
fprintf(stderr,Usage);
exit(1);
}
/*
** END OF MAIN()
** -------------
*/
/*
** FUNCTIONS
** ---------
*/
/*
** ERR -- Prints standard error
** ----------------------------
*/
void
err(s)
char *s;
{
fprintf(stderr,"synack%: ");
perror(s);
fprintf(stderr,"errno=%d\n",errno);
exit(1);
}
/*
** TVSUB -- Subtract two timeval structs
** -------------------------------------
**
** Returns:
** Time difference in micro(!)seconds.
**
** Side effects:
** The difference of the two timeval structs
** is stored back into the first.
**
** This implementation assumes that time_t is a signed value.
** On 32-bit machines this limits the range to ~35 minutes.
** That seems sufficient for most practical purposes.
** Note that tv_sec is an *un*signed entity on some platforms.
*/
time_t
tvsub(t2, t1)
struct timeval *t2;
struct timeval *t1;
{
register time_t usec;
t2->tv_usec -= t1->tv_usec;
while (t2->tv_usec < 0)
{
t2->tv_usec += 1000000;
if (t2->tv_sec != 0)
t2->tv_sec--;
else
t2->tv_usec = 0;
}
if (t2->tv_sec < t1->tv_sec)
{
t2->tv_sec = 0;
t2->tv_usec = 0;
}
else
t2->tv_sec -= t1->tv_sec;
if (t2->tv_sec > MAXSECS)
{
t2->tv_sec = MAXSECS;
t2->tv_usec = 0;
}
usec = t2->tv_sec*1000000 + t2->tv_usec;
return(usec);
}
/*
** TVPRINT -- Convert time value to ascii string
** ---------------------------------------------
**
** Returns:
** Pointer to string in static storage.
**
** Output is in variable format, depending on the value.
** This avoids printing of non-significant digits.
*/
char *
tvprint(usec)
time_t usec; /* value to convert */
{
static char buf[30]; /* sufficient for 64-bit values */
time_t uval;
uval = usec;
(void) sprintf(buf, "%ld.%3.3ld", uval/1000, uval%1000);
return(buf);
}
/*
** RECORD_STATS -- Records RTT Statistics (Min, Mean, Max, Standard Deviation)
** ---------------------------------------------------------------------------------
*/
void
record_stats(sp, rtt)
stats *sp; /* statistics buffer */
time_t rtt; /* round-trip time */
{
if (rtt < sp->rttmin)
sp->rttmin = rtt;
if (rtt > sp->rttmax)
sp->rttmax = rtt;
sp->rttarray[sp->rcvd-1] = rtt;
sp->rttsum += (double)rtt;
sp->rttssq += (double)rtt * (double)rtt;
}
/*
** STATISTICS -- Records RTT Statistics (Median, Interquartile Range, Percentiles)
** -------------------------------------------------------------------------------
*/
void
statistics(sp,percent1,percent2)
stats *sp;
int percent1,percent2;
{
int loop1,loop2,q1,q3;
time_t temp;
for(loop1=0; loop1 <= sp->rcvd-2; loop1++)
for(loop2=loop1+1; loop2 <= sp->rcvd-1; loop2++)
{
if(sp->rttarray[loop1] > sp->rttarray[loop2])
{
temp = sp->rttarray[loop1];
sp->rttarray[loop1] = sp->rttarray[loop2];
sp->rttarray[loop2] = temp;
}
}
if((sp->rcvd%2)==0)
sp->rttmed = ((sp->rttarray[sp->rcvd/2-1])+(sp->rttarray[sp->rcvd/2]))/2;
else
sp->rttmed = sp->rttarray[sp->rcvd/2];
if((sp->rcvd%4) == 0)
{
q1 = sp->rcvd/4 - 1;
q3 = (3 * (sp->rcvd/4)) - 1 ;
}
else
{
q1 = sp->rcvd/4;
q3 = (int)(3 * ((double)sp->rcvd/4.0));
}
sp->rttiqr = sp->rttarray[q3] - sp->rttarray[q1];
if ((sp->rcvd * percent1) >= 100)
if (((sp->rcvd * percent1) % 100) == 0)
sp->rttpct1 = sp->rttarray[(sp->rcvd * percent1 / 100) - 1];
else
sp->rttpct1 = sp->rttarray[sp->rcvd * percent1 / 100];
else
sp->rttpct1 = sp->rttarray[sp->rcvd * percent1 / 100];
if ((sp->rcvd * percent2) >= 100)
if (((sp->rcvd * percent2) % 100) == 0)
sp->rttpct2 = sp->rttarray[(sp->rcvd * percent2 / 100) - 1];
else
sp->rttpct2 = sp->rttarray[sp->rcvd * percent2 / 100];
else
sp->rttpct2 = sp->rttarray[sp->rcvd * percent2 / 100];
if (sp->rcvd == 0)
sp->rttmed = 0.0;
}
/*
** PRINT_STATS -- Prints RTT Statistics
** ------------------------------------
*/
void
print_stats(sp)
stats *sp;
{
double rttavg; /* average round-trip time */
double rttstd; /* rtt standard deviation */
if (sp->rcvd == 0) {
sp->rttmin = 0.0;
sp->rttmax = 0.0;
sp->rttmed = 0.0;
rttavg = 0;
rttstd = 0;
}
if (sp->rcvd > 0)
{
rttavg = sp->rttsum / sp->rcvd;
rttstd = sp->rttssq - (rttavg * sp->rttsum);
if (sp->rcvd == 1)
rttstd = xsqrt(rttstd / sp->rcvd);
else
rttstd = xsqrt(rttstd / (sp->rcvd-1));
}
printf("\n***** Round Trip Statistics of SYN-ACK to %s (Port = %d) ******\n",hisadr->h_name, hisport);
printf("%d packets transmitted, %d packets received, %2.2f percent packet loss\n",sp->seq_no,sp->rcvd,(((float)sp->seq_no)-(float)sp->rcvd)/((float)sp->seq_no)*100.0);
printf("round-trip (ms) min/avg/max =");
printf(" %s", tvprint(sp->rttmin));
printf("/%s", tvprint((time_t)rttavg));
printf("/%s", tvprint(sp->rttmax));
printf(" (std = %s)\n", tvprint((time_t)rttstd));
statistics(sp,percent1,percent2);
printf(" (median = %s)\t", tvprint(sp->rttmed));
printf(" (interquartile range = %s)\n", tvprint(sp->rttiqr));
if(percent1 != 0)
printf(" (%d percentile = %s)\t",percent1,tvprint(sp->rttpct1));
if(percent2 != 0)
printf(" (%d percentile = %s)\n",percent2,tvprint(sp->rttpct2));
printf("\n");
}
/*
** XSQRT -- Square root
** --------------------
*/
double
xsqrt(y)
double y;
{
double t, x;
if (y <= 0)
return(0);
x = (y < 1.0) ? 1.0 : y;
do {
t = x;
x = (t + (y/t))/2.0;
} while (0 < x && x < t);
return(x);
}
/*
** PRINTSTATS -- PRINTS RTT STATISTICS
** -----------------------------------
*/
void
printstats(sp)
stats *sp; /* statistics buffer */
{
print_stats(sp);
exit(0);
}
/*
** CALLSTATS -- CALLS RTT STATISTICS
** ---------------------------------
*/
void
callstats()
{
printstats(&synack);
}
/*
** ISNUMERIC -- FINDS OUT IF AN ADDRESS IS NUMERIC
** -----------------------------------------------
*/
int
isnumeric(address)
char *address;
{
if (isdigit(*address))
return TRUE;
else
return FALSE;
}
/*
** ERROR -- Issue error message to error output
** --------------------------------------------
**
** Returns:
** None.
*/
void /*VARARGS1*/
rterror(fmt, a, b, c, d)
char *fmt; /* format of message */
char *a, *b, *c, *d; /* optional arguments */
{
(void) fprintf(stderr, "\n");
(void) fprintf(stderr, fmt, a, b, c, d);
(void) fprintf(stderr, "\n");
(void) fprintf(stderr, "\n");
}
/*
** ERR_PRINT -- PRINTS STRING IF ERROR
** -----------------------------------
*/
void
err_print(string)
char *string;
{
printf("%s\n\n", string);
exit(0);
}
/*
** SOCK_INIT -- OPENS A SOCKET & MAKES A SOCKET NON-BLOCKING
** ---------------------------------------------------------
*/
void sock_init (sock, flag)
int *sock, *flag;
{
*sock = socket(AF_INET, SOCK_STREAM, 0);
*flag = fcntl(*sock, F_GETFL, 0);
fcntl(*sock, F_SETFL, *flag | O_NONBLOCK);
}
/*
** SOCK_CLOSE -- CLOSES A CONNECTION
** ---------------------------------
*/
void sock_close (sock, flag)
int *sock, *flag;
{
close(*sock);
fcntl(*sock, F_SETFL, *flag);
}
/*
** CONNECT_START -- INITIATES A CONNECTION
** ---------------------------------------
*/
int connect_start(sock, rset, wset)
int *sock;
fd_set *rset, *wset;
{
int stat_connect;
stat_connect = connect(*sock, (struct sockaddr *)&his_addr, sizeof(struct sockaddr));
#if(!linux)
if (stat_connect == -1)
errno = EINPROGRESS;
#endif
if (errno == EINPROGRESS) {
FD_ZERO(rset);
FD_ZERO(wset);
FD_SET(*sock, rset);
FD_SET(*sock, wset);
return 1;
}
else return 0;
}
/*
** SELECT_CONDITION -- ERROR CHECKS FOR SELECT
** -------------------------------------------
*/
int select_condition(sock, rset, wset)
int *sock;
fd_set *rset, *wset;
{
int value, nset, nread;
char *line;
if ( FD_ISSET(*sock, wset) && !FD_ISSET(*sock, rset) )
value = 1;
if ( FD_ISSET(*sock, wset) && FD_ISSET(*sock, rset) )
value = 2;
if( (nset = FD_ISSET(*sock, rset) > 0) ) {
if( nread = read(*sock, line, 1) < 0) {
if (errno == 111)
value = 2;
else
value = 3;
}
}
return value;
}
/*
** SELECT_START -- CALLS THE SELECT FUNCTION
** -----------------------------------------
*/
int select_start(sock, rset, wset, tval)
int *sock;
fd_set *rset,*wset;
struct timeval *tval;
{
int nselect, nselectval;
loop:
nselect = select(*sock+1, rset, wset, NULL, tval);
if ( (nselect < 0) && (errno == EINTR) )
goto loop;
if ( (nselect < 0) && (errno == EINVAL) ) {
printf("Error in select value\n");
exit(0);
}
if (nselect == 0)
return 0;
nselectval = select_condition(sock, rset, wset);
return nselectval;
}
/*
** CONNECTION_TCP -- THE COMPLETE NON-BLOCKING CONNECTION
** ------------------------------------------------------
*/
void connection_tcp(sock, flag, tvalfresh, rset, wset,ipname, ipnum)
int *sock, *flag;
struct timeval *tvalfresh;
fd_set *rset, *wset;
char *ipname, *ipnum;
{
struct timeval *tval, *sendtime, tv1, *recvtime, tv2;
time_t rtt;
int nconnect, nselect;
float time;
int local_seq_no;
local_seq_no = synack.seq_no;
tval = (struct timeval *) malloc(sizeof(struct timeval *));
sock_init(sock, flag);
tval->tv_sec = tvalfresh->tv_sec;
tval->tv_usec = tvalfresh->tv_usec;
sendtime = &tv1;
gettimeofday(sendtime, (struct timezone *)NULL);
nconnect = connect_start(sock, rset, wset);
if (nconnect == 1) {
recvtime = &tv2;
gettimeofday(recvtime, (struct timezone *)NULL);
recvtime->tv_sec -= sendtime->tv_sec;
recvtime->tv_usec -= sendtime->tv_usec;
tval->tv_sec -= recvtime->tv_sec;
tval->tv_usec = tval->tv_usec - recvtime->tv_usec - 10000;
if (tval->tv_usec < 0) {
tval->tv_sec -= 1;
tval->tv_usec += 1000000;
}
nselect = select_start(sock, rset, wset, tval);
if (nselect == 0) {
printf("connection for seq no: %d timed out within %s Secs\n",local_seq_no,
tvprint(tvalfresh->tv_sec*1000 + tvalfresh->tv_usec/1000));
goto jump;
}
if (nselect == 1)
goto printer;
if (nselect == 2) {
printf("connection refused\n");
goto jump;
}
if (nselect ==3) {
printf("read error\n");
goto jump;
}
}
else {
printf("connect not proper\n");
exit(0);
}
if (nconnect == 0) {
/* recvtime = tv2;
gettimeofday(*recvtime, (struct timezone *)NULL); */
printf("nconnect = 0\n");
exit(0);
}
printer:
recvtime = &tv2;
gettimeofday(recvtime, (struct timezone *)NULL);
rtt = tvsub(recvtime, sendtime);
synack.rcvd++;
record_stats(&synack,rtt);
if (ipname != NULL)
printf("connected to %s : Seq = %d , RTT = %s ms \n", ipname, local_seq_no, tvprint(rtt));
else
printf("connected to %s : Seq = %d , RTT = %s ms \n", ipnum, local_seq_no, tvprint(rtt));
jump:
sock_close (sock, flag);
free(tval);
}
/*
** CALL_CONNECTION -- CALLS THE PREVIOUS FUNCTION
** ----------------------------------------------
*/
void *call_connection ()
{
connection_tcp(&sockfd[counter], &flags[counter], &tvalfresh, &rset[counter], &wset[counter], ipname, ipnum);
}
/*
** MAX_THREADS -- CALCULATES THE MAXIMUM NO. ACTIVE THREADS POSSIBLE
** -----------------------------------------------------------------
*/
int max_threads(timeout, interval)
int timeout;
timer interval;
{
int threads;
float timeout_usec;
float total_time;
timeout_usec = timeout * 1000000;
total_time = (float) ((interval.sec * 1000000) + interval.usec) ;
threads = (int) ((timeout_usec/total_time) + 3.0);
return threads;
}
/*
** FINISH -- WAIT FOR OUTSTANDING PACKETS CALLS CALLSTATS()
** --------------------------------------------------------
*/
void finish ()
{
int i;
printf("\nWaiting for outstanding packets (if any)..........\n\n");
sleep(1);
for (i=0; i <= threads; i++)
pthread_join(tid[i], NULL);
callstats();
}
/*
** EXIT_INTERRUPT -- KEY SET WHEN INTERRUPTED
** ------------------------------------------
*/
void exit_interrupt()
{
key = 1;
}
/*
** INTERVAL_BETWEEN_SYNACKS -- TIME BETWEEN SUBSEQUENT SYNs
** --------------------------------------------------------
*/
void interval_between_synacks ( timer interval)
{
int time;
time = (interval.usec + (1000000 * interval.sec) );
usleep(time);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment