/*****************************************************************************/
/* "NetPIPE" -- Network Protocol Independent Performance Evaluator. */
/* Copyright 1997, 1998 Iowa State University Research Foundation, Inc. */
/* */
/* This program 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. You should have received a copy of the */
/* GNU General Public License along with this program; if not, write to the */
/* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
/* */
/* * TCP.c ---- TCP calls source */
/* * TCP.h ---- Include file for TCP calls and data structs */
/* 2002/03/18 --- Modified for IPv6 - Robbie Williamson (robbiew@us.ibm.com) */
/*****************************************************************************/
#include "netpipe.h"
int Setup(ArgStruct * p)
{
int tr, one = 1; /* tr==1 if process is a transmitter */
int sr = 0;
int sockfd;
struct sockaddr *lsin1;
char *host;
char *server_host;
struct addrinfo *addr;
struct addrinfo *server_addr;
struct addrinfo hints;
struct protoent *proto;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
host = p->host; /* copy ptr to hostname */
server_host = p->server_host; /* copy ptr to server */
tr = p->tr; /* copy tr indicator */
sr = p->sr;
memset(&p->prot.sin1, 0, sizeof(p->prot.sin1));
memset(&p->prot.sin2, 0, sizeof(p->prot.sin2));
if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
printf("NetPIPE: can't open stream socket! errno=%d\n", errno);
exit(-4);
}
if (!(proto = getprotobyname("tcp"))) {
printf("NetPIPE: protocol 'tcp' unknown!\n");
exit(555);
}
/* Attempt to set TCP_NODELAY */
if (setsockopt(sockfd, proto->p_proto, TCP_NODELAY, &one, sizeof(one)) <
0) {
printf("NetPIPE: setsockopt: TCP_NODELAY failed! errno=%d\n",
errno);
exit(556);
}
/* If requested, set the send and receive buffer sizes */
if (p->prot.sndbufsz > 0) {
printf("Send and Receive Buffers set to %d bytes\n",
p->prot.sndbufsz);
if (setsockopt
(sockfd, SOL_SOCKET, SO_SNDBUF, &(p->prot.sndbufsz),
sizeof(p->prot.sndbufsz)) < 0) {
printf
("NetPIPE: setsockopt: SO_SNDBUF failed! errno=%d\n",
errno);
exit(556);
}
if (setsockopt
(sockfd, SOL_SOCKET, SO_RCVBUF, &(p->prot.rcvbufsz),
sizeof(p->prot.rcvbufsz)) < 0) {
printf
("NetPIPE: setsockopt: SO_RCVBUF failed! errno=%d\n",
errno);
exit(556);
}
}
if (tr) { /* if client i.e., Sender */
if (host) {
getaddrinfo(host, NULL, &hints, &addr);
memcpy(&p->prot.sin1, addr->ai_addr, addr->ai_addrlen);
} else {
if ((getaddrinfo(host, NULL, &hints, &addr)) != 0) {
printf("NetPIPE: invalid hostname '%s'\n",
host);
exit(-5);
}
}
p->prot.sin1.sin6_port = htons(p->port);
} else { /* we are the receiver (server) */
memset(&p->prot.sin1, 0, sizeof(p->prot.sin1));
if (sr == 0) {
p->prot.sin1.sin6_addr = in6addr_any;
p->prot.sin1.sin6_port = htons(p->port);
lsin1 = (struct sockaddr *)&p->prot.sin1;
if (bind
(sockfd, (struct sockaddr *)lsin1,
sizeof(p->prot.sin1)) < 0) {
printf
("NetPIPE: server: bind on local address failed! errno=%d",
errno);
exit(-6);
}
} else {
getaddrinfo(server_host, NULL, NULL, &server_addr);
memcpy(&p->prot.sin1, server_addr->ai_addr,
server_addr->ai_addrlen);
if ((getaddrinfo(server_host, NULL, NULL, &server_addr))
!= 0) {
printf("NetPIPE: invalid hostname '%s'\n",
host);
exit(-5);
}
memcpy(&p->prot.sin1, server_addr->ai_addr,
server_addr->ai_addrlen);
p->prot.sin1.sin6_port = htons(p->port);
lsin1 = (struct sockaddr *)&p->prot.sin1;
if (bind
(sockfd, (struct sockaddr *)lsin1,
sizeof(p->prot.sin1)) < 0) {
printf
("NetPIPE: server: bind on %s failed! errno=%d",
server_host, errno);
exit(-6);
}
}
}
if (tr)
p->commfd = sockfd;
else
p->servicefd = sockfd;
return (0);
}
static int readFully(int fd, void *obuf, int len)
{
int bytesLeft = len;
char *buf = (char *)obuf;
int bytesRead = 0;
while (bytesLeft > 0 &&
(bytesRead = read(fd, (void *)buf, bytesLeft)) > 0) {
bytesLeft -= bytesRead;
buf += bytesRead;
}
if (bytesRead <= 0)
return bytesRead;
return len;
}
void Sync(ArgStruct * p)
{
char s[] = "SyncMe";
char response[7];
if (write(p->commfd, s, strlen(s)) < 0 ||
readFully(p->commfd, response, strlen(s)) < 0) {
perror
("NetPIPE: error writing or reading synchronization string");
exit(3);
}
if (strncmp(s, response, strlen(s))) {
fprintf(stderr, "NetPIPE: Synchronization string incorrect!\n");
exit(3);
}
}
void PrepareToReceive(ArgStruct * p)
{
/*
The Berkeley sockets interface doesn't have a method to pre-post
a buffer for reception of data.
*/
}
void SendData(ArgStruct * p)
{
int bytesWritten, bytesLeft;
char *q;
bytesLeft = p->bufflen;
bytesWritten = 0;
q = p->buff;
while (bytesLeft > 0 &&
(bytesWritten = write(p->commfd, q, bytesLeft)) > 0) {
bytesLeft -= bytesWritten;
q += bytesWritten;
}
if (bytesWritten == -1) {
printf("NetPIPE: write: error encountered, errno=%d\n", errno);
exit(401);
}
}
void RecvData(ArgStruct * p)
{
int bytesLeft;
int bytesRead;
char *q;
bytesLeft = p->bufflen;
bytesRead = 0;
q = p->buff1;
while (bytesLeft > 0 && (bytesRead = read(p->commfd, q, bytesLeft)) > 0) {
bytesLeft -= bytesRead;
q += bytesRead;
}
if (bytesLeft > 0 && bytesRead == 0) {
printf
("NetPIPE: \"end of file\" encountered on reading from socket\n");
} else if (bytesRead == -1) {
printf("NetPIPE: read: error encountered, errno=%d\n", errno);
exit(401);
}
}
void SendTime(ArgStruct * p, double *t)
{
unsigned int ltime, ntime;
/*
Multiply the number of seconds by 1e6 to get time in microseconds
and convert value to an unsigned 32-bit integer.
*/
ltime = (unsigned int)(*t * 1.e6);
/* Send time in network order */
ntime = htonl(ltime);
if (write(p->commfd, (char *)&ntime, sizeof(unsigned int)) < 0) {
printf("NetPIPE: write failed in SendTime: errno=%d\n", errno);
exit(301);
}
}
void RecvTime(ArgStruct * p, double *t)
{
unsigned int ltime, ntime;
int bytesRead;
bytesRead = readFully(p->commfd, (void *)&ntime, sizeof(unsigned int));
if (bytesRead < 0) {
printf("NetPIPE: read failed in RecvTime: errno=%d\n", errno);
exit(302);
} else if (bytesRead != sizeof(unsigned int)) {
fprintf(stderr,
"NetPIPE: partial read in RecvTime of %d bytes\n",
bytesRead);
exit(303);
}
ltime = ntohl(ntime);
/* Result is ltime (in microseconds) divided by 1.0e6 to get seconds */
*t = (double)ltime / 1.0e6;
}
void SendRepeat(ArgStruct * p, int rpt)
{
unsigned int lrpt, nrpt;
lrpt = rpt;
/* Send repeat count as an unsigned 32 bit integer in network order */
nrpt = htonl(lrpt);
if (write(p->commfd, (void *)&nrpt, sizeof(unsigned int)) < 0) {
printf("NetPIPE: write failed in SendRepeat: errno=%d\n",
errno);
exit(304);
}
}
void RecvRepeat(ArgStruct * p, int *rpt)
{
unsigned int lrpt, nrpt;
int bytesRead;
bytesRead = readFully(p->commfd, (void *)&nrpt, sizeof(unsigned int));
if (bytesRead < 0) {
printf("NetPIPE: read failed in RecvRepeat: errno=%d\n", errno);
exit(305);
} else if (bytesRead != sizeof(unsigned int)) {
fprintf(stderr,
"NetPIPE: partial read in RecvRepeat of %d bytes\n",
bytesRead);
exit(306);
}
lrpt = ntohl(nrpt);
*rpt = lrpt;
}
int Establish(ArgStruct * p)
{
socklen_t clen;
int one = 1;
struct protoent *proto;
clen = sizeof(p->prot.sin2);
if (p->tr) {
if (connect(p->commfd, (struct sockaddr *)&(p->prot.sin1),
sizeof(p->prot.sin1)) < 0) {
printf("Client: Cannot Connect! errno=%d\n", errno);
exit(-10);
}
} else {
/* SERVER */
listen(p->servicefd, 5);
p->commfd =
accept(p->servicefd, (struct sockaddr *)&(p->prot.sin2),
&clen);
if (p->commfd < 0) {
printf("Server: Accept Failed! errno=%d\n", errno);
exit(-12);
}
/*
Attempt to set TCP_NODELAY. TCP_NODELAY may or may not be propagated
to accepted sockets.
*/
if (!(proto = getprotobyname("tcp"))) {
printf("unknown protocol!\n");
exit(555);
}
if (setsockopt(p->commfd, proto->p_proto, TCP_NODELAY,
&one, sizeof(one)) < 0) {
printf("setsockopt: TCP_NODELAY failed! errno=%d\n",
errno);
exit(556);
}
/* If requested, set the send and receive buffer sizes */
if (p->prot.sndbufsz > 0) {
printf
("Send and Receive Buffers on accepted socket set to %d bytes\n",
p->prot.sndbufsz);
if (setsockopt
(p->commfd, SOL_SOCKET, SO_SNDBUF,
&(p->prot.sndbufsz),
sizeof(p->prot.sndbufsz)) < 0) {
printf
("setsockopt: SO_SNDBUF failed! errno=%d\n",
errno);
exit(556);
}
if (setsockopt
(p->commfd, SOL_SOCKET, SO_RCVBUF,
&(p->prot.rcvbufsz),
sizeof(p->prot.rcvbufsz)) < 0) {
printf
("setsockopt: SO_RCVBUF failed! errno=%d\n",
errno);
exit(556);
}
}
}
return (0);
}
int CleanUp(ArgStruct * p)
{
char *quit = "QUIT";
if (p->tr) {
write(p->commfd, quit, 5);
read(p->commfd, quit, 5);
close(p->commfd);
} else {
read(p->commfd, quit, 5);
write(p->commfd, quit, 5);
close(p->commfd);
close(p->servicefd);
}
return (0);
}