initial commit of new code
This commit is contained in:
parent
38e1acb706
commit
0fdaab072e
17
src/Makefile
Normal file
17
src/Makefile
Normal 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
540
src/main.c
Normal 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
82
src/net.c
Normal 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
2
src/net.h
Normal 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
228
src/socket.c
Normal 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
27
src/t_timer.c
Normal 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
166
src/tcp_window_size.c
Normal 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
2
src/tcp_window_size.h
Normal 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
73
src/timer.c
Normal 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
8
src/timer.h
Normal 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);
|
Loading…
Reference in New Issue
Block a user