initial commit of new code

This commit is contained in:
Jon Dugan 2009-02-24 06:22:58 +00:00
parent 38e1acb706
commit 0fdaab072e
10 changed files with 1145 additions and 0 deletions

17
src/Makefile Normal file
View File

@ -0,0 +1,17 @@
CFLAGS=-g -Wall
OBJS=main.o timer.o net.o tcp_window_size.o
all: iperf
iperf: $(OBJS)
$(CC) -pthread -o iperf $(OBJS)
#$(CC) -pg -pthread -o iperf-profile $(OBJS)
test: t_timer
./t_timer
t_timer: timer.o t_timer.o
$(CC) -o t_timer timer.o t_timer.o
clean:
rm -f *.o iperf iperf-profile t_timer

540
src/main.c Normal file
View File

@ -0,0 +1,540 @@
/*
* iperfjd -- greatly simplified version of iperf with the same interface
* semantics
*
* jdugan -- 24 Jan 2009
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#include <stdint.h>
#include <sys/time.h>
#include "timer.h"
#include "net.h"
#include "tcp_window_size.h"
enum {
Mundef = 0,
Mclient,
Mserver,
Ptcp = SOCK_STREAM,
Pudp = SOCK_DGRAM,
uS_TO_NS = 1000,
DEFAULT_UDP_BUFSIZE = 1470,
DEFAULT_TCP_BUFSIZE = 8192
};
#define SEC_TO_NS 1000000000 /* too big for enum on some platforms */
struct stream
{
int sock; /* local socket */
struct sockaddr_in local; /* local address */
struct sockaddr_in peer; /* peer address */
uint64_t bytes_in;
uint64_t bytes_out;
pthread_t thread;
char local_addr[512], peer_addr[512];
void *stats; /* ptr to protocol specific stats */
void *(*server)(void *sp);
void *(*client)(void *sp);
struct stream *next;
};
void *udp_client_thread(struct stream *sp);
void *udp_server_thread(struct stream *sp);
void *tcp_client_thread(struct stream *sp);
void *tcp_server_thread(struct stream *sp);
static struct option longopts[] =
{
{ "client", required_argument, NULL, 'c' },
{ "server", no_argument, NULL, 's' },
{ "time", required_argument, NULL, 't' },
{ "port", required_argument, NULL, 'p' },
{ "parallel", required_argument, NULL, 'P' },
{ "udp", no_argument, NULL, 'u' },
{ "bandwidth", required_argument, NULL, 'b' },
{ "length", required_argument, NULL, 'l' },
{ "window", required_argument, NULL, 'w' },
{ NULL, 0, NULL, 0 }
};
struct settings
{
char mode;
char proto;
char *client;
int port;
int sock;
uint64_t bw;
int duration;
int threads;
long int bufsize;
long int window;
struct sockaddr_in sa;
};
struct settings settings =
{
Mundef,
Ptcp,
NULL,
5001,
-1,
1000000,
10,
1,
DEFAULT_UDP_BUFSIZE,
1024*1024
};
struct stream *streams; /* head of list of streams */
int done = 0;
struct stream *
new_stream(int s)
{
struct stream *sp;
socklen_t len;
sp = (struct stream *) malloc(sizeof(struct stream));
if(!sp) {
perror("malloc");
return(NULL);
}
memset(sp, 0, sizeof(struct stream));
sp->sock = s;
len = sizeof sp->local;
if(getsockname(sp->sock, (struct sockaddr *) &sp->local, &len) < 0) {
perror("getsockname");
free(sp);
return(NULL);
}
if(inet_ntop(AF_INET, (void *) &sp->local.sin_addr,
(void *) &sp->local_addr, 512) == NULL) {
perror("inet_pton");
}
if(getpeername(sp->sock, (struct sockaddr *) &sp->peer, &len) < 0) {
perror("getpeername");
free(sp);
return(NULL);
}
if(inet_ntop(AF_INET, (void *) &sp->peer.sin_addr,
(void *) &sp->peer_addr, 512) == NULL) {
perror("inet_pton");
}
switch (settings.proto) {
case Ptcp:
sp->client = (void *) tcp_client_thread;
sp->server = (void *) tcp_server_thread;
break;
case Pudp:
sp->client = (void *) udp_client_thread;
sp->server = (void *) udp_server_thread;
break;
default:
assert(0);
break;
}
if(set_tcp_windowsize(sp->sock, settings.window,
settings.mode == Mserver ? SO_RCVBUF : SO_SNDBUF) < 0)
fprintf(stderr, "unable to set window size\n");
int x;
x = getsock_tcp_windowsize(sp->sock, SO_RCVBUF);
if(x < 0)
perror("SO_RCVBUF");
printf("RCV: %d\n", x);
x = getsock_tcp_windowsize(sp->sock, SO_SNDBUF);
if(x < 0)
perror("SO_SNDBUF");
printf("SND: %d\n", x);
return(sp);
}
void
add_stream(struct stream *sp)
{
struct stream *n;
if(!streams)
streams = sp;
else {
n = streams;
while(n->next)
n = n->next;
n->next = sp;
}
}
void
free_stream(struct stream *sp)
{
free(sp);
}
void connect_msg(struct stream *sp)
{
char *ipl, *ipr;
ipl = (char *) &sp->local.sin_addr;
ipr = (char *) &sp->peer.sin_addr;
printf("[%3d] local %s port %d connected with %s port %d\n",
sp->sock,
sp->local_addr, htons(sp->local.sin_port),
sp->peer_addr, htons(sp->peer.sin_port));
}
void *
udp_client_thread(struct stream *sp)
{
int i;
int64_t delayns, adjustns, dtargns;
char *buf;
struct timeval before, after;
buf = (char *) malloc(settings.bufsize);
if(!buf) {
perror("malloc: unable to allocate transmit buffer");
pthread_exit(NULL);
}
for(i=0; i < settings.bufsize; i++)
buf[i] = i % 37;
dtargns = (int64_t) settings.bufsize * SEC_TO_NS * 8;
dtargns /= settings.bw;
assert(dtargns != 0);
if(gettimeofday(&before, 0) < 0) {
perror("gettimeofday");
}
delayns = dtargns;
adjustns = 0;
printf("%lld adj %lld delay\n", adjustns, delayns);
while(!done) {
send(sp->sock, buf, settings.bufsize, 0);
sp->bytes_out += settings.bufsize;
if(delayns > 0)
delay(delayns);
if(gettimeofday(&after, 0) < 0) {
perror("gettimeofday");
}
adjustns = dtargns;
adjustns += (before.tv_sec - after.tv_sec) * SEC_TO_NS;
adjustns += (before.tv_usec - after.tv_usec) * uS_TO_NS;
if( adjustns > 0 || delayns > 0) {
//printf("%lld adj %lld delay\n", adjustns, delayns);
delayns += adjustns;
}
memcpy(&before, &after, sizeof before);
}
/* a 0 byte packet is the server's cue that we're done */
send(sp->sock, buf, 0, 0);
/* XXX: wait for response with server counts */
printf("%llu bytes sent\n", sp->bytes_out);
close(sp->sock);
pthread_exit(NULL);
}
void *
udp_server_thread(struct stream *sp)
{
char *buf;
ssize_t sz;
buf = (char *) malloc(settings.bufsize);
if(!buf) {
perror("malloc: unable to allocate receive buffer");
pthread_exit(NULL);
}
while((sz = recv(sp->sock, buf, settings.bufsize, 0)) > 0) {
sp->bytes_in += sz;
}
close(sp->sock);
printf("%llu bytes received %g\n", sp->bytes_in, (sp->bytes_in * 8.0)/(settings.duration*1000.0*1000.0));
pthread_exit(NULL);
}
void
udp_report(int final)
{
}
void
tcp_report(int final)
{
}
void *
tcp_client_thread(struct stream *sp)
{
int i;
char *buf;
buf = (char *) malloc(settings.bufsize);
if(!buf) {
perror("malloc: unable to allocate transmit buffer");
pthread_exit(NULL);
}
printf("window: %d\n", getsock_tcp_windowsize(sp->sock, SO_SNDBUF));
for(i=0; i < settings.bufsize; i++)
buf[i] = i % 37;
while(!done) {
send(sp->sock, buf, settings.bufsize, 0);
sp->bytes_out += settings.bufsize;
}
/* a 0 byte packet is the server's cue that we're done */
send(sp->sock, buf, 0, 0);
/* XXX: wait for response with server counts */
printf("%llu bytes sent\n", sp->bytes_out);
close(sp->sock);
pthread_exit(NULL);
}
void *
tcp_server_thread(struct stream *sp)
{
char *buf;
ssize_t sz;
buf = (char *) malloc(settings.bufsize);
if(!buf) {
perror("malloc: unable to allocate receive buffer");
pthread_exit(NULL);
}
printf("window: %d\n", getsock_tcp_windowsize(sp->sock, SO_RCVBUF));
while( (sz = recv(sp->sock, buf, settings.bufsize, 0)) > 0) {
sp->bytes_in += sz;
}
close(sp->sock);
printf("%llu bytes received %g\n", sp->bytes_in, (sp->bytes_in * 8.0)/(settings.duration*1000.0*1000.0));
pthread_exit(NULL);
}
int
client(void)
{
int s, i;
struct stream *sp;
struct timer *timer;
for(i = 0; i < settings.threads; i++) {
s = netdial(settings.proto, settings.client, settings.port);
if(s < 0) {
fprintf(stderr, "netdial failed\n");
return -1;
}
set_tcp_windowsize(s, settings.window, SO_SNDBUF);
if(s < 0)
return -1;
sp = new_stream(s);
add_stream(sp);
connect_msg(sp);
pthread_create(&sp->thread, NULL, sp->client, (void *) sp);
}
timer = new_timer(settings.duration, 0);
while(!timer->expired(timer))
sleep(settings.duration);
done = 1;
/* XXX: report */
sp = streams;
do {
pthread_join(sp->thread, NULL);
sp = sp->next;
} while (sp);
return 0;
}
int
server()
{
int s, cs, sz;
struct stream *sp;
struct sockaddr_in sa_peer;
socklen_t len;
char buf[settings.bufsize];
s = netannounce(settings.proto, NULL, settings.port);
if(s < 0)
return -1;
if(set_tcp_windowsize(s, settings.window, SO_RCVBUF) < 0) {
perror("unable to set window");
return -1;
}
printf("-----------------------------------------------------------\n");
printf("Server listening on %d\n", settings.port);
int x;
if((x = getsock_tcp_windowsize(s, SO_RCVBUF)) < 0)
perror("SO_RCVBUF");
printf("%s: %d\n",
settings.proto == Ptcp ? "TCP window size" : "UDP buffer size", x);
printf("-----------------------------------------------------------\n");
len = sizeof sa_peer;
while(1) {
if (Ptcp == settings.proto) {
if( (cs = accept(s, (struct sockaddr *) &sa_peer, &len)) < 0) {
perror("accept");
return -1;
}
sp = new_stream(cs);
} else if (Pudp == settings.proto) {
sz = recvfrom(s, buf, settings.bufsize, 0, (struct sockaddr *) &sa_peer, &len);
if(!sz)
break;
if(connect(s, (struct sockaddr *) &sa_peer, len) < 0) {
perror("connect");
return -1;
}
sp = new_stream(s);
sp->bytes_in += sz;
s = netannounce(settings.proto, NULL, settings.port);
if(s < 0) {
return -1;
}
}
connect_msg(sp);
pthread_create(&sp->thread, NULL, sp->server, (void *) sp);
}
return 0;
}
int
main(int argc, char **argv)
{
int rc;
char ch;
while( (ch = getopt_long(argc, argv, "c:p:st:uP:b:l:w:", longopts, NULL)) != -1 )
switch (ch) {
case 'c':
settings.mode = Mclient;
settings.client = malloc(strlen(optarg));
strcpy(settings.client, optarg);
break;
case 'p':
settings.port = atoi(optarg);
break;
case 's':
settings.mode = Mserver;
break;
case 't':
settings.duration = atoi(optarg);
break;
case 'u':
settings.proto = Pudp;
break;
case 'P':
settings.threads = atoi(optarg);
break;
case 'b':
settings.bw = atoll(optarg);
break;
case 'l':
settings.bufsize = atol(optarg);
break;
case 'w':
settings.window = atoi(optarg);
break;
}
if (settings.proto == Ptcp && settings.bufsize == DEFAULT_UDP_BUFSIZE)
settings.bufsize = DEFAULT_TCP_BUFSIZE; /* XXX: this might be evil */
switch (settings.mode) {
case Mclient:
rc = client();
break;
case Mserver:
rc = server();
break;
case Mundef:
/* FALLTHRU */
default:
printf("must specify one of -s or -c\n");
rc = -1;
break;
}
return rc;
}

82
src/net.c Normal file
View File

@ -0,0 +1,82 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
int
netdial(int proto, char *client, int port)
{
int s;
struct hostent *hent;
struct sockaddr_in sa;
socklen_t sn;
if((hent = gethostbyname(client)) == 0) {
perror("gethostbyname");
return(-1);
}
s = socket(AF_INET, proto, 0);
if(s < 0) {
perror("socket");
return(-1);
}
memset(&sa, 0, sizeof sa);
memmove(&sa.sin_addr, hent->h_addr, 4);
sa.sin_port = htons(port);
sa.sin_family = AF_INET;
if(connect(s, (struct sockaddr *) &sa, sizeof sa) < 0 && errno != EINPROGRESS) {
perror("connect");
return(-1);
}
/* XXX: is this necessary? */
sn = sizeof sa;
if(getpeername(s, (struct sockaddr *) &sa, &sn) >= 0) {
return(s);
}
perror("connect");
return(-1);
}
int
netannounce(int proto, char *local, int port)
{
int s;
struct sockaddr_in sa;
/* XXX: implement binding to a local address rather than * */
memset((void *) &sa, 0, sizeof sa);
s = socket(AF_INET, proto, 0);
if(s < 0) {
perror("socket");
return(-1);
}
int opt = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt));
sa.sin_port = htons(port);
sa.sin_family = AF_INET;
if(bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
close(s);
perror("bind");
return(-1);
}
if(proto == SOCK_STREAM)
listen(s, 5);
return s;
}

2
src/net.h Normal file
View File

@ -0,0 +1,2 @@
int netdial(int proto, char *client, int port);
int netannounce(int proto, char *local, int port);

228
src/socket.c Normal file
View File

@ -0,0 +1,228 @@
/*---------------------------------------------------------------
* Copyright (c) 1999,2000,2001,2002,2003
* The Board of Trustees of the University of Illinois
* All Rights Reserved.
*---------------------------------------------------------------
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software (Iperf) and associated
* documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and
* the following disclaimers.
*
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimers in the documentation and/or other materials
* provided with the distribution.
*
*
* Neither the names of the University of Illinois, NCSA,
* nor the names of its contributors may be used to endorse
* or promote products derived from this Software without
* specific prior written permission.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ________________________________________________________________
* National Laboratory for Applied Network Research
* National Center for Supercomputing Applications
* University of Illinois at Urbana-Champaign
* http://www.ncsa.uiuc.edu
* ________________________________________________________________
*
* socket.c
* by Mark Gates <mgates@nlanr.net>
* -------------------------------------------------------------------
* set/getsockopt
* ------------------------------------------------------------------- */
#include "headers.h"
#include "util.h"
/* -------------------------------------------------------------------
* If req_mss > 0, set the TCP maximum segment size for sock.
* Otherwise leave it as the system default.
* ------------------------------------------------------------------- */
const char warn_mss_fail[] = "\
WARNING: attempt to set TCP maxmimum segment size to %d failed.\n\
Setting the MSS may not be implemented on this OS.\n";
const char warn_mss_notset[] =
"WARNING: attempt to set TCP maximum segment size to %d, but got %d\n";
void setsock_tcp_mss( int sock, int req_mss ) {
#ifdef TCP_MAXSEG
int rc;
int new_mss;
Socklen_t len;
assert( sock != INVALID_SOCKET );
if ( req_mss > 0 ) {
/* set */
new_mss = req_mss;
len = sizeof( new_mss );
rc = setsockopt( sock, IPPROTO_TCP, TCP_MAXSEG, (char*) &new_mss, len );
if ( rc == SOCKET_ERROR ) {
fprintf( stderr, warn_mss_fail, new_mss );
return;
}
/* verify results */
rc = getsockopt( sock, IPPROTO_TCP, TCP_MAXSEG, (char*) &new_mss, &len );
WARN_errno( rc == SOCKET_ERROR, "getsockopt TCP_MAXSEG" );
if ( new_mss != req_mss ) {
fprintf( stderr, warn_mss_notset, req_mss, new_mss );
}
}
#endif
}
/* -------------------------------------------------------------------
* returns the TCP maximum segment size
* ------------------------------------------------------------------- */
int getsock_tcp_mss( int sock ) {
int mss = 0;
#ifdef TCP_MAXSEG
int rc;
Socklen_t len;
assert( sock >= 0 );
/* query for MSS */
len = sizeof( mss );
rc = getsockopt( sock, IPPROTO_TCP, TCP_MAXSEG, (char*) &mss, &len );
WARN_errno( rc == SOCKET_ERROR, "getsockopt TCP_MAXSEG" );
#endif
return mss;
}
/* -------------------------------------------------------------------
* If inTCPWin > 0, set the TCP window size (via the socket buffer
* sizes) for inSock. Otherwise leave it as the system default.
*
* This must be called prior to calling listen() or connect() on
* the socket, for TCP window sizes > 64 KB to be effective.
*
* This now works on UNICOS also, by setting TCP_WINSHIFT.
* This now works on AIX, by enabling RFC1323.
* returns -1 on error, 0 on no error.
* ------------------------------------------------------------------- */
int setsock_tcp_windowsize( int inSock, int inTCPWin, int inSend ) {
#ifdef SO_SNDBUF
int rc;
int newTCPWin;
assert( inSock >= 0 );
if ( inTCPWin > 0 ) {
#ifdef TCP_WINSHIFT
/* UNICOS requires setting the winshift explicitly */
if ( inTCPWin > 65535 ) {
int winShift = 0;
int scaledWin = inTCPWin >> 16;
while ( scaledWin > 0 ) {
scaledWin >>= 1;
winShift++;
}
/* set TCP window shift */
rc = setsockopt( inSock, IPPROTO_TCP, TCP_WINSHIFT,
(char*) &winShift, sizeof( winShift ));
if ( rc < 0 ) {
return rc;
}
/* Note: you cannot verify TCP window shift, since it returns
* a structure and not the same integer we use to set it. (ugh) */
}
#endif /* TCP_WINSHIFT */
#ifdef TCP_RFC1323
/* On AIX, RFC 1323 extensions can be set system-wide,
* using the 'no' network options command. But we can also set them
* per-socket, so let's try just in case. */
if ( inTCPWin > 65535 ) {
/* enable RFC 1323 */
int on = 1;
rc = setsockopt( inSock, IPPROTO_TCP, TCP_RFC1323,
(char*) &on, sizeof( on ));
if ( rc < 0 ) {
return rc;
}
}
#endif /* TCP_RFC1323 */
if ( !inSend ) {
/* receive buffer -- set
* note: results are verified after connect() or listen(),
* since some OS's don't show the corrected value until then. */
newTCPWin = inTCPWin;
rc = setsockopt( inSock, SOL_SOCKET, SO_RCVBUF,
(char*) &newTCPWin, sizeof( newTCPWin ));
} else {
/* send buffer -- set
* note: results are verified after connect() or listen(),
* since some OS's don't show the corrected value until then. */
newTCPWin = inTCPWin;
rc = setsockopt( inSock, SOL_SOCKET, SO_SNDBUF,
(char*) &newTCPWin, sizeof( newTCPWin ));
}
if ( rc < 0 ) {
return rc;
}
}
#endif /* SO_SNDBUF */
return 0;
}
/* -------------------------------------------------------------------
* returns the TCP window size (on the sending buffer, SO_SNDBUF),
* or -1 on error.
* ------------------------------------------------------------------- */
int getsock_tcp_windowsize( int inSock, int inSend ) {
int theTCPWin = 0;
#ifdef SO_SNDBUF
int rc;
Socklen_t len;
/* send buffer -- query for buffer size */
len = sizeof( theTCPWin );
if ( inSend ) {
rc = getsockopt( inSock, SOL_SOCKET, SO_SNDBUF,
(char*) &theTCPWin, &len );
} else {
rc = getsockopt( inSock, SOL_SOCKET, SO_RCVBUF,
(char*) &theTCPWin, &len );
}
if ( rc < 0 ) {
return rc;
}
#endif
return theTCPWin;
}

27
src/t_timer.c Normal file
View File

@ -0,0 +1,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include "timer.h"
int main(int argc, char **argv)
{
struct timer *tp;
tp = new_timer(10);
sleep(5);
if(tp->expired(tp)) {
printf("timer should not have expired\n");
exit(-1);
}
sleep(5);
if(!tp->expired(tp)) {
printf("timer should have expired\n");
exit(-2);
}
exit(0);
}

166
src/tcp_window_size.c Normal file
View File

@ -0,0 +1,166 @@
/*---------------------------------------------------------------
* Copyright (c) 1999,2000,2001,2002,2003
* The Board of Trustees of the University of Illinois
* All Rights Reserved.
*---------------------------------------------------------------
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software (Iperf) and associated
* documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and
* the following disclaimers.
*
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimers in the documentation and/or other materials
* provided with the distribution.
*
*
* Neither the names of the University of Illinois, NCSA,
* nor the names of its contributors may be used to endorse
* or promote products derived from this Software without
* specific prior written permission.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ________________________________________________________________
* National Laboratory for Applied Network Research
* National Center for Supercomputing Applications
* University of Illinois at Urbana-Champaign
* http://www.ncsa.uiuc.edu
* ________________________________________________________________
*
* tcp_window_size.c
* by Mark Gates <mgates@nlanr.net>
* -------------------------------------------------------------------
* set/getsockopt
* ------------------------------------------------------------------- */
/*
* imported into iperfjd branch: 3 Feb 2009 jdugan
*
* made variable names more sane
* removed some cruft
*/
#include <sys/socket.h>
#include <assert.h>
#ifdef __cplusplus
extern "C" {
#endif
/* -------------------------------------------------------------------
* If bufsize > 0, set the TCP window size (via the socket buffer
* sizes) for sock. Otherwise leave it as the system default.
*
* This must be called prior to calling listen() or connect() on
* the socket, for TCP window sizes > 64 KB to be effective.
*
* This now works on UNICOS also, by setting TCP_WINSHIFT.
* This now works on AIX, by enabling RFC1323.
* returns -1 on error, 0 on no error.
* ------------------------------------------------------------------- */
int
set_tcp_windowsize(int sock, int bufsize, int dir)
{
#ifdef SO_SNDBUF
int rc;
int newbufsize;
assert( sock >= 0 );
if ( bufsize > 0 ) {
#ifdef TCP_WINSHIFT
/* XXX: audit -- do we care about UNICOS? */
/* UNICOS requires setting the winshift explicitly */
if (bufsize > 65535) {
int winshift = 0;
int scaledwin = bufsize >> 16;
while ( scaledwin > 0 ) {
scaledwin >>= 1;
winshift++;
}
/* set TCP window shift */
rc = setsockopt(sock, IPPROTO_TCP, TCP_WINSHIFT,
(char*) &winshift, sizeof( winshift ));
if ( rc < 0 )
return rc;
/* Note: you cannot verify TCP window shift, since it returns
* a structure and not the same integer we use to set it. (ugh) */
}
#endif /* TCP_WINSHIFT */
#ifdef TCP_RFC1323
/* On AIX, RFC 1323 extensions can be set system-wide,
* using the 'no' network options command. But we can also set them
* per-socket, so let's try just in case. */
if ( bufsize > 65535 ) {
/* enable RFC 1323 */
int on = 1;
rc = setsockopt(sock, IPPROTO_TCP, TCP_RFC1323,
(char*) &on, sizeof( on ));
if ( rc < 0 )
return rc;
}
#endif /* TCP_RFC1323 */
/* note: results are verified after connect() or listen(),
* since some OS's don't show the corrected value until then. */
newbufsize = bufsize;
rc = setsockopt(sock, SOL_SOCKET, dir, (char*) &newbufsize, sizeof newbufsize);
if (rc < 0)
return rc;
}
#endif /* SO_SNDBUF */
return 0;
}
/* -------------------------------------------------------------------
* returns the TCP window size (on the sending buffer, SO_SNDBUF),
* or -1 on error.
* ------------------------------------------------------------------- */
int
getsock_tcp_windowsize(int sock, int dir)
{
int bufsize = 0;
#ifdef SO_SNDBUF
int rc;
socklen_t len;
/* send buffer -- query for buffer size */
len = sizeof bufsize;
rc = getsockopt(sock, SOL_SOCKET, dir, (char*) &bufsize, &len);
if (rc < 0)
return rc;
#endif
return bufsize;
}
#ifdef __cplusplus
} /* end extern "C" */
#endif

2
src/tcp_window_size.h Normal file
View File

@ -0,0 +1,2 @@
int set_tcp_windowsize(int sock, int bufsize, int dir);
int getsock_tcp_windowsize(int sock, int dir);

73
src/timer.c Normal file
View File

@ -0,0 +1,73 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <stdint.h>
#include <time.h>
#include "timer.h"
int
timer_expired(struct timer *tp)
{
struct timeval now;
if(gettimeofday(&now, NULL) < 0) {
perror("gettimeofday");
return -1;
}
return tp->end.tv_sec <= now.tv_sec;
}
struct timer *
new_timer(time_t sec, suseconds_t usec)
{
struct timer *tp;
tp = (struct timer *) malloc(sizeof(struct timer));
if(gettimeofday(&tp->begin, NULL) < 0) {
perror("gettimeofday");
return NULL;
}
memcpy(&tp->end, &tp->begin, sizeof(struct timer));
tp->end.tv_sec = tp->begin.tv_sec + (time_t) sec;
tp->end.tv_usec = tp->begin.tv_usec + (time_t) usec;
tp->expired = timer_expired;
return tp;
}
void
free_timer(struct timer *tp)
{
free(tp);
}
int
delay(int64_t ns)
{
struct timespec req, rem;
req.tv_sec = 0;
while(ns >= 1000000000L)
{
ns -= 1000000000L;
req.tv_sec += 1;
}
req.tv_nsec = ns;
while(nanosleep(&req, &rem) == -1 )
if (EINTR == errno)
memcpy(&req, &rem, sizeof rem);
else
return -1;
return 0;
}

8
src/timer.h Normal file
View File

@ -0,0 +1,8 @@
struct timer {
struct timeval begin;
struct timeval end;
int (*expired)(struct timer *timer);
};
struct timer *new_timer(time_t sec, suseconds_t usec);
int delay(int64_t ns);