blob: b6bd35b7be319bb99a585168d1eed8e8113df380 [file] [log] [blame]
robbiew723b3af2003-03-28 18:14:44 +00001/*****************************************************************************/
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
10/* */
11/* * TCP.c ---- TCP calls source */
12/* * TCP.h ---- Include file for TCP calls and data structs */
13/* 2002/03/18 --- Modified for IPv6 - Robbie Williamson (robbiew@us.ibm.com) */
14/*****************************************************************************/
15#include "netpipe.h"
16
robbiew723b3af2003-03-28 18:14:44 +000017
18int Setup(ArgStruct *p)
19{
20
21 int tr, one = 1; /* tr==1 if process is a transmitter */
vapier57c212c2006-07-04 22:29:12 +000022 int sr = 0;
robbiew723b3af2003-03-28 18:14:44 +000023 int sockfd;
24 struct sockaddr *lsin1;
25 char *host;
26 char *server_host;
27 struct addrinfo *addr;
28 struct addrinfo *server_addr;
29 struct addrinfo hints;
30 struct protoent *proto;
31
32 memset(&hints, 0, sizeof(hints));
33 hints.ai_family = AF_INET6;
34
35
vapier57c212c2006-07-04 22:29:12 +000036 host = p->host; /* copy ptr to hostname */
37 server_host = p->server_host; /* copy ptr to server */
38
robbiew723b3af2003-03-28 18:14:44 +000039 tr = p->tr; /* copy tr indicator */
40 sr = p->sr;
41
42
43 memset(&p->prot.sin1, 0, sizeof(p->prot.sin1));
44 memset(&p->prot.sin2, 0, sizeof(p->prot.sin2));
45
Garrett Cooper43088e12010-12-13 23:30:59 -080046 if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
robbiew723b3af2003-03-28 18:14:44 +000047 printf("NetPIPE: can't open stream socket! errno=%d\n", errno);
48 exit(-4);
49 }
50
Garrett Cooper43088e12010-12-13 23:30:59 -080051 if (!(proto = getprotobyname("tcp"))) {
robbiew723b3af2003-03-28 18:14:44 +000052 printf("NetPIPE: protocol 'tcp' unknown!\n");
53 exit(555);
54 }
55
56 /* Attempt to set TCP_NODELAY */
Garrett Cooper43088e12010-12-13 23:30:59 -080057 if (setsockopt(sockfd, proto->p_proto, TCP_NODELAY, &one, sizeof(one)) < 0)
robbiew723b3af2003-03-28 18:14:44 +000058 {
59 printf("NetPIPE: setsockopt: TCP_NODELAY failed! errno=%d\n", errno);
60 exit(556);
61 }
62
63 /* If requested, set the send and receive buffer sizes */
Garrett Cooper43088e12010-12-13 23:30:59 -080064 if (p->prot.sndbufsz > 0)
robbiew723b3af2003-03-28 18:14:44 +000065 {
66 printf("Send and Receive Buffers set to %d bytes\n", p->prot.sndbufsz);
Garrett Cooper43088e12010-12-13 23:30:59 -080067 if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &(p->prot.sndbufsz),
robbiew723b3af2003-03-28 18:14:44 +000068 sizeof(p->prot.sndbufsz)) < 0)
69 {
70 printf("NetPIPE: setsockopt: SO_SNDBUF failed! errno=%d\n", errno);
71 exit(556);
72 }
Garrett Cooper43088e12010-12-13 23:30:59 -080073 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &(p->prot.rcvbufsz),
robbiew723b3af2003-03-28 18:14:44 +000074 sizeof(p->prot.rcvbufsz)) < 0)
75 {
76 printf("NetPIPE: setsockopt: SO_RCVBUF failed! errno=%d\n", errno);
77 exit(556);
78 }
79 }
80
Garrett Cooper43088e12010-12-13 23:30:59 -080081 if (tr) { /* if client i.e., Sender */
robbiew723b3af2003-03-28 18:14:44 +000082
vapier57c212c2006-07-04 22:29:12 +000083 if (host) {
robbiew723b3af2003-03-28 18:14:44 +000084 getaddrinfo(host, NULL, &hints, &addr);
85 memcpy(&p->prot.sin1, addr->ai_addr, addr->ai_addrlen);
86 } else {
Garrett Cooper43088e12010-12-13 23:30:59 -080087 if ((getaddrinfo(host,NULL,&hints,&addr)) != 0) {
robbiew723b3af2003-03-28 18:14:44 +000088 printf("NetPIPE: invalid hostname '%s'\n", host);
89 exit(-5);
90 }
91 }
92 p->prot.sin1.sin6_port = htons(p->port);
vapier57c212c2006-07-04 22:29:12 +000093
robbiew723b3af2003-03-28 18:14:44 +000094} else { /* we are the receiver (server) */
95
96 memset(&p->prot.sin1, 0, sizeof(p->prot.sin1));
Garrett Cooper43088e12010-12-13 23:30:59 -080097 if (sr==0) {
robbiew723b3af2003-03-28 18:14:44 +000098 p->prot.sin1.sin6_addr = in6addr_any;
99 p->prot.sin1.sin6_port = htons(p->port);
vapier57c212c2006-07-04 22:29:12 +0000100 lsin1=(struct sockaddr*)&p->prot.sin1;
Garrett Cooper43088e12010-12-13 23:30:59 -0800101 if (bind(sockfd, (struct sockaddr*)lsin1, sizeof(p->prot.sin1)) < 0) {
robbiew723b3af2003-03-28 18:14:44 +0000102 printf("NetPIPE: server: bind on local address failed! errno=%d", errno);
103 exit(-6);
104 }
105 }
106 else{
107 getaddrinfo(server_host, NULL, NULL, &server_addr);
108 memcpy(&p->prot.sin1, server_addr->ai_addr, server_addr->ai_addrlen);
Garrett Cooper43088e12010-12-13 23:30:59 -0800109 if ((getaddrinfo(server_host, NULL, NULL, &server_addr)) != 0) {
robbiew723b3af2003-03-28 18:14:44 +0000110 printf("NetPIPE: invalid hostname '%s'\n", host);
111 exit(-5);
112 }
113 memcpy(&p->prot.sin1, server_addr->ai_addr, server_addr->ai_addrlen);
114 p->prot.sin1.sin6_port = htons(p->port);
vapier57c212c2006-07-04 22:29:12 +0000115 lsin1=(struct sockaddr*)&p->prot.sin1;
Garrett Cooper43088e12010-12-13 23:30:59 -0800116 if (bind(sockfd, (struct sockaddr*)lsin1, sizeof(p->prot.sin1)) < 0) {
robbiew723b3af2003-03-28 18:14:44 +0000117 printf("NetPIPE: server: bind on %s failed! errno=%d", server_host, errno);
118 exit(-6);
119 }
vapier57c212c2006-07-04 22:29:12 +0000120 }
robbiew723b3af2003-03-28 18:14:44 +0000121 }
122
Garrett Cooper43088e12010-12-13 23:30:59 -0800123 if (tr)
robbiew723b3af2003-03-28 18:14:44 +0000124 p->commfd = sockfd;
125 else
126 p->servicefd = sockfd;
127
128 return(0);
vapier57c212c2006-07-04 22:29:12 +0000129
130}
robbiew723b3af2003-03-28 18:14:44 +0000131
132static int
133readFully(int fd, void *obuf, int len)
134{
135 int bytesLeft = len;
136 char *buf = (char *) obuf;
137 int bytesRead = 0;
138
139 while (bytesLeft > 0 &&
140 (bytesRead = read(fd, (void *) buf, bytesLeft)) > 0)
141 {
142 bytesLeft -= bytesRead;
143 buf += bytesRead;
144 }
145 if (bytesRead <= 0)
146 return bytesRead;
147 return len;
148}
149
150void Sync(ArgStruct *p)
151{
152 char s[] = "SyncMe";
153 char response[7];
154
155 if (write(p->commfd, s, strlen(s)) < 0 ||
156 readFully(p->commfd, response, strlen(s)) < 0)
157 {
158 perror("NetPIPE: error writing or reading synchronization string");
159 exit(3);
160 }
161 if (strncmp(s, response, strlen(s)))
162 {
163 fprintf(stderr, "NetPIPE: Synchronization string incorrect!\n");
164 exit(3);
165 }
166}
167
168void PrepareToReceive(ArgStruct *p)
169{
170 /*
171 The Berkeley sockets interface doesn't have a method to pre-post
172 a buffer for reception of data.
173 */
174}
175
176void SendData(ArgStruct *p)
177{
178 int bytesWritten, bytesLeft;
179 char *q;
180
181 bytesLeft = p->bufflen;
182 bytesWritten = 0;
183 q = p->buff;
184 while (bytesLeft > 0 &&
185 (bytesWritten = write(p->commfd, q, bytesLeft)) > 0)
186 {
187 bytesLeft -= bytesWritten;
188 q += bytesWritten;
189 }
190 if (bytesWritten == -1)
191 {
192 printf("NetPIPE: write: error encountered, errno=%d\n", errno);
193 exit(401);
194 }
195}
196
197void RecvData(ArgStruct *p)
198{
199 int bytesLeft;
200 int bytesRead;
201 char *q;
202
203 bytesLeft = p->bufflen;
204 bytesRead = 0;
205 q = p->buff1;
206 while (bytesLeft > 0 &&
207 (bytesRead = read(p->commfd, q, bytesLeft)) > 0)
208 {
209 bytesLeft -= bytesRead;
210 q += bytesRead;
211 }
212 if (bytesLeft > 0 && bytesRead == 0)
213 {
214 printf("NetPIPE: \"end of file\" encountered on reading from socket\n");
215 }
216 else if (bytesRead == -1)
217 {
218 printf("NetPIPE: read: error encountered, errno=%d\n", errno);
219 exit(401);
220 }
221}
222
223void SendTime(ArgStruct *p, double *t)
224{
225 unsigned int ltime, ntime;
226
227 /*
228 Multiply the number of seconds by 1e6 to get time in microseconds
229 and convert value to an unsigned 32-bit integer.
230 */
231 ltime = (unsigned int)(*t * 1.e6);
232
233 /* Send time in network order */
234 ntime = htonl(ltime);
235 if (write(p->commfd, (char *)&ntime, sizeof(unsigned int)) < 0)
236 {
237 printf("NetPIPE: write failed in SendTime: errno=%d\n", errno);
238 exit(301);
239 }
240}
241
242void RecvTime(ArgStruct *p, double *t)
243{
244 unsigned int ltime, ntime;
245 int bytesRead;
246
247 bytesRead = readFully(p->commfd, (void *)&ntime, sizeof(unsigned int));
248 if (bytesRead < 0)
249 {
250 printf("NetPIPE: read failed in RecvTime: errno=%d\n", errno);
251 exit(302);
252 }
253 else if (bytesRead != sizeof(unsigned int))
254 {
255 fprintf(stderr, "NetPIPE: partial read in RecvTime of %d bytes\n",
256 bytesRead);
257 exit(303);
258 }
259 ltime = ntohl(ntime);
260
261 /* Result is ltime (in microseconds) divided by 1.0e6 to get seconds */
262 *t = (double)ltime / 1.0e6;
263}
264
265void SendRepeat(ArgStruct *p, int rpt)
266{
267 unsigned int lrpt, nrpt;
268
269 lrpt = rpt;
270 /* Send repeat count as an unsigned 32 bit integer in network order */
271 nrpt = htonl(lrpt);
272 if (write(p->commfd, (void *) &nrpt, sizeof(unsigned int)) < 0)
273 {
274 printf("NetPIPE: write failed in SendRepeat: errno=%d\n", errno);
275 exit(304);
276 }
277}
278
279void RecvRepeat(ArgStruct *p, int *rpt)
280{
281 unsigned int lrpt, nrpt;
282 int bytesRead;
283
284 bytesRead = readFully(p->commfd, (void *)&nrpt, sizeof(unsigned int));
285 if (bytesRead < 0)
286 {
287 printf("NetPIPE: read failed in RecvRepeat: errno=%d\n", errno);
288 exit(305);
289 }
290 else if (bytesRead != sizeof(unsigned int))
291 {
292 fprintf(stderr, "NetPIPE: partial read in RecvRepeat of %d bytes\n",
293 bytesRead);
294 exit(306);
295 }
296 lrpt = ntohl(nrpt);
297
298 *rpt = lrpt;
299}
300
301int Establish(ArgStruct *p)
302{
vapierda6657a2006-07-04 22:25:19 +0000303 socklen_t clen;
robbiew723b3af2003-03-28 18:14:44 +0000304 int one = 1;
305 struct protoent *proto;
306
307 clen = sizeof(p->prot.sin2);
Garrett Cooper43088e12010-12-13 23:30:59 -0800308 if (p->tr) {
309 if (connect(p->commfd, (struct sockaddr *) &(p->prot.sin1),
310 sizeof(p->prot.sin1)) < 0) {
robbiew723b3af2003-03-28 18:14:44 +0000311 printf("Client: Cannot Connect! errno=%d\n",errno);
312 exit(-10);
313 }
314 }
315 else {
316 /* SERVER */
317 listen(p->servicefd, 5);
318 p->commfd = accept(p->servicefd, (struct sockaddr *) &(p->prot.sin2),
319 &clen);
320
Garrett Cooper43088e12010-12-13 23:30:59 -0800321 if (p->commfd < 0) {
robbiew723b3af2003-03-28 18:14:44 +0000322 printf("Server: Accept Failed! errno=%d\n",errno);
323 exit(-12);
324 }
325
326 /*
327 Attempt to set TCP_NODELAY. TCP_NODELAY may or may not be propagated
328 to accepted sockets.
329 */
Garrett Cooper43088e12010-12-13 23:30:59 -0800330 if (!(proto = getprotobyname("tcp"))) {
robbiew723b3af2003-03-28 18:14:44 +0000331 printf("unknown protocol!\n");
332 exit(555);
333 }
334
Garrett Cooper43088e12010-12-13 23:30:59 -0800335 if (setsockopt(p->commfd, proto->p_proto, TCP_NODELAY,
robbiew723b3af2003-03-28 18:14:44 +0000336 &one, sizeof(one)) < 0)
337 {
338 printf("setsockopt: TCP_NODELAY failed! errno=%d\n", errno);
339 exit(556);
340 }
341
342 /* If requested, set the send and receive buffer sizes */
Garrett Cooper43088e12010-12-13 23:30:59 -0800343 if (p->prot.sndbufsz > 0)
robbiew723b3af2003-03-28 18:14:44 +0000344 {
345 printf("Send and Receive Buffers on accepted socket set to %d bytes\n",
346 p->prot.sndbufsz);
Garrett Cooper43088e12010-12-13 23:30:59 -0800347 if (setsockopt(p->commfd, SOL_SOCKET, SO_SNDBUF, &(p->prot.sndbufsz),
robbiew723b3af2003-03-28 18:14:44 +0000348 sizeof(p->prot.sndbufsz)) < 0)
349 {
350 printf("setsockopt: SO_SNDBUF failed! errno=%d\n", errno);
351 exit(556);
352 }
Garrett Cooper43088e12010-12-13 23:30:59 -0800353 if (setsockopt(p->commfd, SOL_SOCKET, SO_RCVBUF, &(p->prot.rcvbufsz),
robbiew723b3af2003-03-28 18:14:44 +0000354 sizeof(p->prot.rcvbufsz)) < 0)
355 {
356 printf("setsockopt: SO_RCVBUF failed! errno=%d\n", errno);
357 exit(556);
358 }
359 }
vapier57c212c2006-07-04 22:29:12 +0000360 }
robbiew723b3af2003-03-28 18:14:44 +0000361 return(0);
362}
363
vapier57c212c2006-07-04 22:29:12 +0000364int CleanUp(ArgStruct *p)
robbiew723b3af2003-03-28 18:14:44 +0000365{
366 char *quit="QUIT";
367 if (p->tr)
368 {
369 write(p->commfd,quit, 5);
370 read(p->commfd, quit, 5);
371 close(p->commfd);
372 }
373 else
374 {
375 read(p->commfd,quit, 5);
376 write(p->commfd,quit,5);
377 close(p->commfd);
378 close(p->servicefd);
379 }
380 return(0);
Chris Dearmanec6edca2012-10-17 19:54:01 -0700381}