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 /* 2002/03/18 --- Modified for IPv6 - Robbie Williamson (robbiew@us.ibm.com) */
14 /*****************************************************************************/
15 #include "netpipe.h"
16
Setup(ArgStruct * p)17 int Setup(ArgStruct * p)
18 {
19
20 int tr, one = 1; /* tr==1 if process is a transmitter */
21 int sr = 0;
22 int sockfd;
23 struct sockaddr *lsin1;
24 char *host;
25 char *server_host;
26 struct addrinfo *addr;
27 struct addrinfo *server_addr;
28 struct addrinfo hints;
29 struct protoent *proto;
30
31 memset(&hints, 0, sizeof(hints));
32 hints.ai_family = AF_INET6;
33
34 host = p->host; /* copy ptr to hostname */
35 server_host = p->server_host; /* copy ptr to server */
36
37 tr = p->tr; /* copy tr indicator */
38 sr = p->sr;
39
40 memset(&p->prot.sin1, 0, sizeof(p->prot.sin1));
41 memset(&p->prot.sin2, 0, sizeof(p->prot.sin2));
42
43 if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
44 printf("NetPIPE: can't open stream socket! errno=%d\n", errno);
45 exit(-4);
46 }
47
48 if (!(proto = getprotobyname("tcp"))) {
49 printf("NetPIPE: protocol 'tcp' unknown!\n");
50 exit(555);
51 }
52
53 /* Attempt to set TCP_NODELAY */
54 if (setsockopt(sockfd, proto->p_proto, TCP_NODELAY, &one, sizeof(one)) <
55 0) {
56 printf("NetPIPE: setsockopt: TCP_NODELAY failed! errno=%d\n",
57 errno);
58 exit(556);
59 }
60
61 /* If requested, set the send and receive buffer sizes */
62 if (p->prot.sndbufsz > 0) {
63 printf("Send and Receive Buffers set to %d bytes\n",
64 p->prot.sndbufsz);
65 if (setsockopt
66 (sockfd, SOL_SOCKET, SO_SNDBUF, &(p->prot.sndbufsz),
67 sizeof(p->prot.sndbufsz)) < 0) {
68 printf
69 ("NetPIPE: setsockopt: SO_SNDBUF failed! errno=%d\n",
70 errno);
71 exit(556);
72 }
73 if (setsockopt
74 (sockfd, SOL_SOCKET, SO_RCVBUF, &(p->prot.rcvbufsz),
75 sizeof(p->prot.rcvbufsz)) < 0) {
76 printf
77 ("NetPIPE: setsockopt: SO_RCVBUF failed! errno=%d\n",
78 errno);
79 exit(556);
80 }
81 }
82
83 if (tr) { /* if client i.e., Sender */
84
85 if (host) {
86 getaddrinfo(host, NULL, &hints, &addr);
87 memcpy(&p->prot.sin1, addr->ai_addr, addr->ai_addrlen);
88 } else {
89 if ((getaddrinfo(host, NULL, &hints, &addr)) != 0) {
90 printf("NetPIPE: invalid hostname '%s'\n",
91 host);
92 exit(-5);
93 }
94 }
95 p->prot.sin1.sin6_port = htons(p->port);
96
97 } else { /* we are the receiver (server) */
98
99 memset(&p->prot.sin1, 0, sizeof(p->prot.sin1));
100 if (sr == 0) {
101 p->prot.sin1.sin6_addr = in6addr_any;
102 p->prot.sin1.sin6_port = htons(p->port);
103 lsin1 = (struct sockaddr *)&p->prot.sin1;
104 if (bind
105 (sockfd, (struct sockaddr *)lsin1,
106 sizeof(p->prot.sin1)) < 0) {
107 printf
108 ("NetPIPE: server: bind on local address failed! errno=%d",
109 errno);
110 exit(-6);
111 }
112 } else {
113 getaddrinfo(server_host, NULL, NULL, &server_addr);
114 memcpy(&p->prot.sin1, server_addr->ai_addr,
115 server_addr->ai_addrlen);
116 if ((getaddrinfo(server_host, NULL, NULL, &server_addr))
117 != 0) {
118 printf("NetPIPE: invalid hostname '%s'\n",
119 host);
120 exit(-5);
121 }
122 memcpy(&p->prot.sin1, server_addr->ai_addr,
123 server_addr->ai_addrlen);
124 p->prot.sin1.sin6_port = htons(p->port);
125 lsin1 = (struct sockaddr *)&p->prot.sin1;
126 if (bind
127 (sockfd, (struct sockaddr *)lsin1,
128 sizeof(p->prot.sin1)) < 0) {
129 printf
130 ("NetPIPE: server: bind on %s failed! errno=%d",
131 server_host, errno);
132 exit(-6);
133 }
134 }
135 }
136
137 if (tr)
138 p->commfd = sockfd;
139 else
140 p->servicefd = sockfd;
141
142 return (0);
143
144 }
145
readFully(int fd,void * obuf,int len)146 static int readFully(int fd, void *obuf, int len)
147 {
148 int bytesLeft = len;
149 char *buf = (char *)obuf;
150 int bytesRead = 0;
151
152 while (bytesLeft > 0 &&
153 (bytesRead = read(fd, (void *)buf, bytesLeft)) > 0) {
154 bytesLeft -= bytesRead;
155 buf += bytesRead;
156 }
157 if (bytesRead <= 0)
158 return bytesRead;
159 return len;
160 }
161
Sync(ArgStruct * p)162 void Sync(ArgStruct * p)
163 {
164 char s[] = "SyncMe";
165 char response[7];
166
167 if (write(p->commfd, s, strlen(s)) < 0 ||
168 readFully(p->commfd, response, strlen(s)) < 0) {
169 perror
170 ("NetPIPE: error writing or reading synchronization string");
171 exit(3);
172 }
173 if (strncmp(s, response, strlen(s))) {
174 fprintf(stderr, "NetPIPE: Synchronization string incorrect!\n");
175 exit(3);
176 }
177 }
178
PrepareToReceive(ArgStruct * p)179 void PrepareToReceive(ArgStruct * p)
180 {
181 /*
182 The Berkeley sockets interface doesn't have a method to pre-post
183 a buffer for reception of data.
184 */
185 }
186
SendData(ArgStruct * p)187 void SendData(ArgStruct * p)
188 {
189 int bytesWritten, bytesLeft;
190 char *q;
191
192 bytesLeft = p->bufflen;
193 bytesWritten = 0;
194 q = p->buff;
195 while (bytesLeft > 0 &&
196 (bytesWritten = write(p->commfd, q, bytesLeft)) > 0) {
197 bytesLeft -= bytesWritten;
198 q += bytesWritten;
199 }
200 if (bytesWritten == -1) {
201 printf("NetPIPE: write: error encountered, errno=%d\n", errno);
202 exit(401);
203 }
204 }
205
RecvData(ArgStruct * p)206 void RecvData(ArgStruct * p)
207 {
208 int bytesLeft;
209 int bytesRead;
210 char *q;
211
212 bytesLeft = p->bufflen;
213 bytesRead = 0;
214 q = p->buff1;
215 while (bytesLeft > 0 && (bytesRead = read(p->commfd, q, bytesLeft)) > 0) {
216 bytesLeft -= bytesRead;
217 q += bytesRead;
218 }
219 if (bytesLeft > 0 && bytesRead == 0) {
220 printf
221 ("NetPIPE: \"end of file\" encountered on reading from socket\n");
222 } else if (bytesRead == -1) {
223 printf("NetPIPE: read: error encountered, errno=%d\n", errno);
224 exit(401);
225 }
226 }
227
SendTime(ArgStruct * p,double * t)228 void SendTime(ArgStruct * p, double *t)
229 {
230 unsigned int ltime, ntime;
231
232 /*
233 Multiply the number of seconds by 1e6 to get time in microseconds
234 and convert value to an unsigned 32-bit integer.
235 */
236 ltime = (unsigned int)(*t * 1.e6);
237
238 /* Send time in network order */
239 ntime = htonl(ltime);
240 if (write(p->commfd, (char *)&ntime, sizeof(unsigned int)) < 0) {
241 printf("NetPIPE: write failed in SendTime: errno=%d\n", errno);
242 exit(301);
243 }
244 }
245
RecvTime(ArgStruct * p,double * t)246 void RecvTime(ArgStruct * p, double *t)
247 {
248 unsigned int ltime, ntime;
249 int bytesRead;
250
251 bytesRead = readFully(p->commfd, (void *)&ntime, sizeof(unsigned int));
252 if (bytesRead < 0) {
253 printf("NetPIPE: read failed in RecvTime: errno=%d\n", errno);
254 exit(302);
255 } else if (bytesRead != sizeof(unsigned int)) {
256 fprintf(stderr,
257 "NetPIPE: partial read in RecvTime of %d bytes\n",
258 bytesRead);
259 exit(303);
260 }
261 ltime = ntohl(ntime);
262
263 /* Result is ltime (in microseconds) divided by 1.0e6 to get seconds */
264 *t = (double)ltime / 1.0e6;
265 }
266
SendRepeat(ArgStruct * p,int rpt)267 void SendRepeat(ArgStruct * p, int rpt)
268 {
269 unsigned int lrpt, nrpt;
270
271 lrpt = rpt;
272 /* Send repeat count as an unsigned 32 bit integer in network order */
273 nrpt = htonl(lrpt);
274 if (write(p->commfd, (void *)&nrpt, sizeof(unsigned int)) < 0) {
275 printf("NetPIPE: write failed in SendRepeat: errno=%d\n",
276 errno);
277 exit(304);
278 }
279 }
280
RecvRepeat(ArgStruct * p,int * rpt)281 void RecvRepeat(ArgStruct * p, int *rpt)
282 {
283 unsigned int lrpt, nrpt;
284 int bytesRead;
285
286 bytesRead = readFully(p->commfd, (void *)&nrpt, sizeof(unsigned int));
287 if (bytesRead < 0) {
288 printf("NetPIPE: read failed in RecvRepeat: errno=%d\n", errno);
289 exit(305);
290 } else if (bytesRead != sizeof(unsigned int)) {
291 fprintf(stderr,
292 "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
Establish(ArgStruct * p)301 int Establish(ArgStruct * p)
302 {
303 socklen_t clen;
304 int one = 1;
305 struct protoent *proto;
306
307 clen = sizeof(p->prot.sin2);
308 if (p->tr) {
309 if (connect(p->commfd, (struct sockaddr *)&(p->prot.sin1),
310 sizeof(p->prot.sin1)) < 0) {
311 printf("Client: Cannot Connect! errno=%d\n", errno);
312 exit(-10);
313 }
314 } else {
315 /* SERVER */
316 listen(p->servicefd, 5);
317 p->commfd =
318 accept(p->servicefd, (struct sockaddr *)&(p->prot.sin2),
319 &clen);
320
321 if (p->commfd < 0) {
322 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 */
330 if (!(proto = getprotobyname("tcp"))) {
331 printf("unknown protocol!\n");
332 exit(555);
333 }
334
335 if (setsockopt(p->commfd, proto->p_proto, TCP_NODELAY,
336 &one, sizeof(one)) < 0) {
337 printf("setsockopt: TCP_NODELAY failed! errno=%d\n",
338 errno);
339 exit(556);
340 }
341
342 /* If requested, set the send and receive buffer sizes */
343 if (p->prot.sndbufsz > 0) {
344 printf
345 ("Send and Receive Buffers on accepted socket set to %d bytes\n",
346 p->prot.sndbufsz);
347 if (setsockopt
348 (p->commfd, SOL_SOCKET, SO_SNDBUF,
349 &(p->prot.sndbufsz),
350 sizeof(p->prot.sndbufsz)) < 0) {
351 printf
352 ("setsockopt: SO_SNDBUF failed! errno=%d\n",
353 errno);
354 exit(556);
355 }
356 if (setsockopt
357 (p->commfd, SOL_SOCKET, SO_RCVBUF,
358 &(p->prot.rcvbufsz),
359 sizeof(p->prot.rcvbufsz)) < 0) {
360 printf
361 ("setsockopt: SO_RCVBUF failed! errno=%d\n",
362 errno);
363 exit(556);
364 }
365 }
366 }
367 return (0);
368 }
369
CleanUp(ArgStruct * p)370 int CleanUp(ArgStruct * p)
371 {
372 char *quit = "QUIT";
373 if (p->tr) {
374 write(p->commfd, quit, 5);
375 read(p->commfd, quit, 5);
376 close(p->commfd);
377 } else {
378 read(p->commfd, quit, 5);
379 write(p->commfd, quit, 5);
380 close(p->commfd);
381 close(p->servicefd);
382 }
383 return (0);
384 }
385