/*****************************************************************************/ /* "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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* */ /* * tcp.c ---- TCP calls source */ /* * tcp.h ---- Include file for TCP calls and data structs */ /*****************************************************************************/ #include "netpipe.h" #if defined (MPLITE) #include "mplite.h" #endif int doing_reset = 0; void Init(ArgStruct *p, int* pargc, char*** pargv) { p->reset_conn = 0; /* Default to not resetting connection */ p->prot.sndbufsz = p->prot.rcvbufsz = 0; p->tr = 0; /* The transmitter will be set using the -h host flag. */ p->rcv = 1; } void Setup(ArgStruct *p) { int one = 1; int sockfd; struct sockaddr_in *lsin1, *lsin2; /* ptr to sockaddr_in in ArgStruct */ char *host; struct hostent *addr; struct protoent *proto; int send_size, recv_size, sizeofint = sizeof(int); host = p->host; /* copy ptr to hostname */ lsin1 = &(p->prot.sin1); lsin2 = &(p->prot.sin2); bzero((char *) lsin1, sizeof(*lsin1)); bzero((char *) lsin2, sizeof(*lsin2)); if ( (sockfd = socket(AF_INET, 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) { 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); printf("You may have asked for a buffer larger than the system can handle\n"); 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); printf("You may have asked for a buffer larger than the system can handle\n"); exit(556); } } getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *) &send_size, (void *) &sizeofint); getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *) &recv_size, (void *) &sizeofint); if(!doing_reset) { fprintf(stderr,"Send and receive buffers are %d and %d bytes\n", send_size, recv_size); fprintf(stderr, "(A bug in Linux doubles the requested buffer sizes)\n"); } if( p->tr ) { /* Primary transmitter */ if (atoi(host) > 0) { /* Numerical IP address */ lsin1->sin_family = AF_INET; lsin1->sin_addr.s_addr = inet_addr(host); } else { if ((addr = gethostbyname(host)) == NULL){ printf("NetPIPE: invalid hostname '%s'\n", host); exit(-5); } lsin1->sin_family = addr->h_addrtype; bcopy(addr->h_addr, (char*) &(lsin1->sin_addr.s_addr), addr->h_length); } lsin1->sin_port = htons(p->port); p->commfd = sockfd; } else if( p->rcv ) { /* we are the receiver */ bzero((char *) lsin1, sizeof(*lsin1)); lsin1->sin_family = AF_INET; lsin1->sin_addr.s_addr = htonl(INADDR_ANY); lsin1->sin_port = htons(p->port); if (bind(sockfd, (struct sockaddr *) lsin1, sizeof(*lsin1)) < 0){ printf("NetPIPE: server: bind on local address failed! errno=%d", errno); exit(-6); } p->servicefd = sockfd; } p->upper = send_size + recv_size; establish(p); /* Establish connections */ } 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", response[] = " "; if (write(p->commfd, s, strlen(s)) < 0 || /* Write to nbor */ readFully(p->commfd, response, strlen(s)) < 0) /* Read from nbor */ { perror("NetPIPE: error writing or reading synchronization string"); exit(3); } if (strncmp(s, response, strlen(s))) { fprintf(stderr, "NetPIPE: Synchronization string incorrect! |%s|\n", response); 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->s_ptr; 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->r_ptr; 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); } } /* uint32_t is used to insure that the integer size is the same even in tests * between 64-bit and 32-bit architectures. */ void SendTime(ArgStruct *p, double *t) { uint32_t ltime, ntime; /* Multiply the number of seconds by 1e8 to get time in 0.01 microseconds and convert value to an unsigned 32-bit integer. */ ltime = (uint32_t)(*t * 1.e8); /* Send time in network order */ ntime = htonl(ltime); if (write(p->commfd, (char *)&ntime, sizeof(uint32_t)) < 0) { printf("NetPIPE: write failed in SendTime: errno=%d\n", errno); exit(301); } } void RecvTime(ArgStruct *p, double *t) { uint32_t ltime, ntime; int bytesRead; bytesRead = readFully(p->commfd, (void *)&ntime, sizeof(uint32_t)); if (bytesRead < 0) { printf("NetPIPE: read failed in RecvTime: errno=%d\n", errno); exit(302); } else if (bytesRead != sizeof(uint32_t)) { 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.0e8 to get seconds */ *t = (double)ltime / 1.0e8; } void SendRepeat(ArgStruct *p, int rpt) { uint32_t lrpt, nrpt; lrpt = rpt; /* Send repeat count as a long in network order */ nrpt = htonl(lrpt); if (write(p->commfd, (void *) &nrpt, sizeof(uint32_t)) < 0) { printf("NetPIPE: write failed in SendRepeat: errno=%d\n", errno); exit(304); } } void RecvRepeat(ArgStruct *p, int *rpt) { uint32_t lrpt, nrpt; int bytesRead; bytesRead = readFully(p->commfd, (void *)&nrpt, sizeof(uint32_t)); if (bytesRead < 0) { printf("NetPIPE: read failed in RecvRepeat: errno=%d\n", errno); exit(305); } else if (bytesRead != sizeof(uint32_t)) { fprintf(stderr, "NetPIPE: partial read in RecvRepeat of %d bytes\n", bytesRead); exit(306); } lrpt = ntohl(nrpt); *rpt = lrpt; } void establish(ArgStruct *p) { int one = 1; socklen_t clen; struct protoent *proto; clen = (socklen_t) sizeof(p->prot.sin2); if( p->tr ){ while( connect(p->commfd, (struct sockaddr *) &(p->prot.sin1), sizeof(p->prot.sin1)) < 0 ) { /* If we are doing a reset and we get a connection refused from * the connect() call, assume that the other node has not yet * gotten to its corresponding accept() call and keep trying until * we have success. */ if(!doing_reset || errno != ECONNREFUSED) { printf("Client: Cannot Connect! errno=%d\n",errno); exit(-10); } } } else if( p->rcv ) { /* 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); } } } } void CleanUp(ArgStruct *p) { char *quit="QUIT"; if (p->tr) { write(p->commfd,quit, 5); read(p->commfd, quit, 5); close(p->commfd); } else if( p->rcv ) { read(p->commfd,quit, 5); write(p->commfd,quit,5); close(p->commfd); close(p->servicefd); } } void Reset(ArgStruct *p) { /* Reset sockets */ if(p->reset_conn) { doing_reset = 1; /* Close the sockets */ CleanUp(p); /* Now open and connect new sockets */ Setup(p); } } void AfterAlignmentInit(ArgStruct *p) { }