1/*****************************************************************************/
2/* "NetPIPE" -- Network Protocol Independent Performance Evaluator.          */
3/* Copyright 1997, 1998 Iowa State University Research Foundation, Inc.      */
4/*                                                                           */
5/* This program is free software; you can redistribute it and/or modify      */
6/* it under the terms of the GNU General Public License as published by      */
7/* the Free Software Foundation.  You should have received a copy of the     */
8/* GNU General Public License along with this program; if not, write to the  */
9/* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.   */
10/*                                                                           */
11/*     * TCP.c              ---- TCP calls source                            */
12/*     * TCP.h              ---- Include file for TCP calls and data structs */
13/*****************************************************************************/
14#include    "netpipe.h"
15
16int Setup(ArgStruct * p)
17{
18	int tr, one = 1;	/* tr==1 if process is a transmitter */
19	int sockfd;
20	struct sockaddr_in *lsin1, *lsin2;	/* ptr to sockaddr_in in ArgStruct */
21	char *host;
22	struct hostent *addr;
23	struct protoent *proto;
24
25	host = p->host;		/* copy ptr to hostname */
26	tr = p->tr;		/* copy tr indicator */
27
28	lsin1 = &(p->prot.sin1);
29	lsin2 = &(p->prot.sin2);
30
31	memset((char *)lsin1, 0x00, sizeof(*lsin1));
32	memset((char *)lsin2, 0x00, sizeof(*lsin2));
33
34	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
35		printf("NetPIPE: can't open stream socket! errno=%d\n", errno);
36		exit(-4);
37	}
38
39	if (!(proto = getprotobyname("tcp"))) {
40		printf("NetPIPE: protocol 'tcp' unknown!\n");
41		exit(555);
42	}
43
44	/* Attempt to set TCP_NODELAY */
45	if (setsockopt(sockfd, proto->p_proto, TCP_NODELAY, &one, sizeof(one)) <
46	    0) {
47		printf("NetPIPE: setsockopt: TCP_NODELAY failed! errno=%d\n",
48		       errno);
49		exit(556);
50	}
51
52	/* If requested, set the send and receive buffer sizes */
53	if (p->prot.sndbufsz > 0) {
54		printf("Send and Receive Buffers set to %d bytes\n",
55		       p->prot.sndbufsz);
56		if (setsockopt
57		    (sockfd, SOL_SOCKET, SO_SNDBUF, &(p->prot.sndbufsz),
58		     sizeof(p->prot.sndbufsz)) < 0) {
59			printf
60			    ("NetPIPE: setsockopt: SO_SNDBUF failed! errno=%d\n",
61			     errno);
62			exit(556);
63		}
64		if (setsockopt
65		    (sockfd, SOL_SOCKET, SO_RCVBUF, &(p->prot.rcvbufsz),
66		     sizeof(p->prot.rcvbufsz)) < 0) {
67			printf
68			    ("NetPIPE: setsockopt: SO_RCVBUF failed! errno=%d\n",
69			     errno);
70			exit(556);
71		}
72	}
73
74	if (tr) {		/* if client i.e., Sender */
75
76		if (atoi(host) > 0) {	/* Numerical IP address */
77			lsin1->sin_family = AF_INET;
78			lsin1->sin_addr.s_addr = inet_addr(host);
79
80		} else {
81
82			if ((addr = gethostbyname(host)) == NULL) {
83				printf("NetPIPE: invalid hostname '%s'\n",
84				       host);
85				exit(-5);
86			}
87
88			lsin1->sin_family = addr->h_addrtype;
89			memcpy((char *)&(lsin1->sin_addr.s_addr), addr->h_addr,
90			       addr->h_length);
91		}
92
93		lsin1->sin_port = htons(p->port);
94
95	} else {		/* we are the receiver (server) */
96
97		memset((char *)lsin1, 0x00, sizeof(*lsin1));
98		lsin1->sin_family = AF_INET;
99		lsin1->sin_addr.s_addr = htonl(INADDR_ANY);
100		lsin1->sin_port = htons(p->port);
101
102		if (bind(sockfd, (struct sockaddr *)lsin1, sizeof(*lsin1)) < 0) {
103			printf
104			    ("NetPIPE: server: bind on local address failed! errno=%d",
105			     errno);
106			exit(-6);
107		}
108
109	}
110
111	if (tr)
112		p->commfd = sockfd;
113	else
114		p->servicefd = sockfd;
115
116	return (0);
117}
118
119static int readFully(int fd, void *obuf, int len)
120{
121	int bytesLeft = len;
122	char *buf = (char *)obuf;
123	int bytesRead = 0;
124
125	while (bytesLeft > 0 &&
126	       (bytesRead = read(fd, (void *)buf, bytesLeft)) > 0) {
127		bytesLeft -= bytesRead;
128		buf += bytesRead;
129	}
130	if (bytesRead <= 0)
131		return bytesRead;
132	return len;
133}
134
135void Sync(ArgStruct * p)
136{
137	char s[] = "SyncMe";
138	char response[7];
139
140	if (write(p->commfd, s, strlen(s)) < 0 ||
141	    readFully(p->commfd, response, strlen(s)) < 0) {
142		perror
143		    ("NetPIPE: error writing or reading synchronization string");
144		exit(3);
145	}
146	if (strncmp(s, response, strlen(s))) {
147		fprintf(stderr, "NetPIPE: Synchronization string incorrect!\n");
148		exit(3);
149	}
150}
151
152void PrepareToReceive(ArgStruct * p)
153{
154	/*
155	   The Berkeley sockets interface doesn't have a method to pre-post
156	   a buffer for reception of data.
157	 */
158}
159
160void SendData(ArgStruct * p)
161{
162	int bytesWritten, bytesLeft;
163	char *q;
164
165	bytesLeft = p->bufflen;
166	bytesWritten = 0;
167	q = p->buff;
168	while (bytesLeft > 0 &&
169	       (bytesWritten = write(p->commfd, q, bytesLeft)) > 0) {
170		bytesLeft -= bytesWritten;
171		q += bytesWritten;
172	}
173	if (bytesWritten == -1) {
174		printf("NetPIPE: write: error encountered, errno=%d\n", errno);
175		exit(401);
176	}
177}
178
179void RecvData(ArgStruct * p)
180{
181	int bytesLeft;
182	int bytesRead;
183	char *q;
184
185	bytesLeft = p->bufflen;
186	bytesRead = 0;
187	q = p->buff1;
188	while (bytesLeft > 0 && (bytesRead = read(p->commfd, q, bytesLeft)) > 0) {
189		bytesLeft -= bytesRead;
190		q += bytesRead;
191	}
192	if (bytesLeft > 0 && bytesRead == 0) {
193		printf
194		    ("NetPIPE: \"end of file\" encountered on reading from socket\n");
195	} else if (bytesRead == -1) {
196		printf("NetPIPE: read: error encountered, errno=%d\n", errno);
197		exit(401);
198	}
199}
200
201void SendTime(ArgStruct * p, double *t)
202{
203	unsigned int ltime, ntime;
204
205	/*
206	   Multiply the number of seconds by 1e6 to get time in microseconds
207	   and convert value to an unsigned 32-bit integer.
208	 */
209	ltime = (unsigned int)(*t * 1.e6);
210
211	/* Send time in network order */
212	ntime = htonl(ltime);
213	if (write(p->commfd, (char *)&ntime, sizeof(unsigned int)) < 0) {
214		printf("NetPIPE: write failed in SendTime: errno=%d\n", errno);
215		exit(301);
216	}
217}
218
219void RecvTime(ArgStruct * p, double *t)
220{
221	unsigned int ltime, ntime;
222	int bytesRead;
223
224	bytesRead = readFully(p->commfd, (void *)&ntime, sizeof(unsigned int));
225	if (bytesRead < 0) {
226		printf("NetPIPE: read failed in RecvTime: errno=%d\n", errno);
227		exit(302);
228	} else if (bytesRead != sizeof(unsigned int)) {
229		fprintf(stderr,
230			"NetPIPE: partial read in RecvTime of %d bytes\n",
231			bytesRead);
232		exit(303);
233	}
234	ltime = ntohl(ntime);
235
236	/* Result is ltime (in microseconds) divided by 1.0e6 to get seconds */
237	*t = (double)ltime / 1.0e6;
238}
239
240void SendRepeat(ArgStruct * p, int rpt)
241{
242	unsigned int lrpt, nrpt;
243
244	lrpt = rpt;
245	/* Send repeat count as an unsigned 32 bit integer in network order */
246	nrpt = htonl(lrpt);
247	if (write(p->commfd, (void *)&nrpt, sizeof(unsigned int)) < 0) {
248		printf("NetPIPE: write failed in SendRepeat: errno=%d\n",
249		       errno);
250		exit(304);
251	}
252}
253
254void RecvRepeat(ArgStruct * p, int *rpt)
255{
256	unsigned int lrpt, nrpt;
257	int bytesRead;
258
259	bytesRead = readFully(p->commfd, (void *)&nrpt, sizeof(unsigned int));
260	if (bytesRead < 0) {
261		printf("NetPIPE: read failed in RecvRepeat: errno=%d\n", errno);
262		exit(305);
263	} else if (bytesRead != sizeof(unsigned int)) {
264		fprintf(stderr,
265			"NetPIPE: partial read in RecvRepeat of %d bytes\n",
266			bytesRead);
267		exit(306);
268	}
269	lrpt = ntohl(nrpt);
270
271	*rpt = lrpt;
272}
273
274int Establish(ArgStruct * p)
275{
276	socklen_t clen;
277	int one = 1;
278	struct protoent *proto;
279
280	clen = sizeof(p->prot.sin2);
281	if (p->tr) {
282		if (connect(p->commfd, (struct sockaddr *)&(p->prot.sin1),
283			    sizeof(p->prot.sin1)) < 0) {
284			printf("Client: Cannot Connect! errno=%d\n", errno);
285			exit(-10);
286		}
287	} else {
288		/* SERVER */
289		listen(p->servicefd, 5);
290		p->commfd =
291		    accept(p->servicefd, (struct sockaddr *)&(p->prot.sin2),
292			   &clen);
293
294		if (p->commfd < 0) {
295			printf("Server: Accept Failed! errno=%d\n", errno);
296			exit(-12);
297		}
298
299		/*
300		   Attempt to set TCP_NODELAY. TCP_NODELAY may or may not be propagated
301		   to accepted sockets.
302		 */
303		if (!(proto = getprotobyname("tcp"))) {
304			printf("unknown protocol!\n");
305			exit(555);
306		}
307
308		if (setsockopt(p->commfd, proto->p_proto, TCP_NODELAY,
309			       &one, sizeof(one)) < 0) {
310			printf("setsockopt: TCP_NODELAY failed! errno=%d\n",
311			       errno);
312			exit(556);
313		}
314
315		/* If requested, set the send and receive buffer sizes */
316		if (p->prot.sndbufsz > 0) {
317			printf
318			    ("Send and Receive Buffers on accepted socket set to %d bytes\n",
319			     p->prot.sndbufsz);
320			if (setsockopt
321			    (p->commfd, SOL_SOCKET, SO_SNDBUF,
322			     &(p->prot.sndbufsz),
323			     sizeof(p->prot.sndbufsz)) < 0) {
324				printf
325				    ("setsockopt: SO_SNDBUF failed! errno=%d\n",
326				     errno);
327				exit(556);
328			}
329			if (setsockopt
330			    (p->commfd, SOL_SOCKET, SO_RCVBUF,
331			     &(p->prot.rcvbufsz),
332			     sizeof(p->prot.rcvbufsz)) < 0) {
333				printf
334				    ("setsockopt: SO_RCVBUF failed! errno=%d\n",
335				     errno);
336				exit(556);
337			}
338		}
339	}
340	return (0);
341}
342
343int CleanUp(ArgStruct * p)
344{
345	char *quit = "QUIT";
346	if (p->tr) {
347		write(p->commfd, quit, 5);
348		read(p->commfd, quit, 5);
349		close(p->commfd);
350	} else {
351		read(p->commfd, quit, 5);
352		write(p->commfd, quit, 5);
353		close(p->commfd);
354		close(p->servicefd);
355	}
356	return (0);
357}
358