/*****************************************************************************/ /* "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); }