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