1 /* 2 * Copyright (c) 2009-2011, The Regents of the University of California, 3 * through Lawrence Berkeley National Laboratory (subject to receipt of any 4 * required approvals from the U.S. Dept. of Energy). All rights reserved. 5 * 6 * This code is distributed under a BSD style license, see the LICENSE file 7 * for complete information. 8 */ 9 10 #include <stdio.h> 11 #include <unistd.h> 12 #include <errno.h> 13 #include <sys/socket.h> 14 #include <sys/types.h> 15 #include <sys/errno.h> 16 #include <netinet/in.h> 17 #include <netinet/tcp.h> 18 #include <assert.h> 19 #include <netdb.h> 20 #include <string.h> 21 #include <sys/fcntl.h> 22 23 #ifdef linux 24 #include <sys/sendfile.h> 25 #else 26 #ifdef __FreeBSD__ 27 #include <sys/uio.h> 28 #else 29 #if defined(__APPLE__) && defined(__MACH__) /* OS X */ 30 #include <AvailabilityMacros.h> 31 #if defined(MAC_OS_X_VERSION_10_6) 32 #include <sys/uio.h> 33 #endif 34 #endif 35 #endif 36 #endif 37 38 #include "iperf_util.h" 39 #include "net.h" 40 #include "timer.h" 41 42 /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/ 43 * Copyright: http://swtch.com/libtask/COPYRIGHT 44 */ 45 46 /* make connection to server */ 47 int 48 netdial(int domain, int proto, char *local, char *server, int port) 49 { 50 struct addrinfo hints, *local_res, *server_res; 51 int s; 52 53 if (local) { 54 memset(&hints, 0, sizeof(hints)); 55 hints.ai_family = domain; 56 hints.ai_socktype = proto; 57 if (getaddrinfo(local, NULL, &hints, &local_res) != 0) 58 return -1; 59 } 60 61 memset(&hints, 0, sizeof(hints)); 62 hints.ai_family = domain; 63 hints.ai_socktype = proto; 64 if (getaddrinfo(server, NULL, &hints, &server_res) != 0) 65 return -1; 66 67 s = socket(server_res->ai_family, proto, 0); 68 if (s < 0) { 69 if (local) 70 freeaddrinfo(local_res); 71 freeaddrinfo(server_res); 72 return -1; 73 } 74 75 if (local) { 76 if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { 77 close(s); 78 freeaddrinfo(local_res); 79 freeaddrinfo(server_res); 80 return -1; 81 } 82 freeaddrinfo(local_res); 83 } 84 85 ((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port); 86 if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) { 87 close(s); 88 freeaddrinfo(server_res); 89 return -1; 90 } 91 92 freeaddrinfo(server_res); 93 return s; 94 } 95 96 /***************************************************************/ 97 98 int 99 netannounce(int domain, int proto, char *local, int port) 100 { 101 struct addrinfo hints, *res; 102 char portstr[6]; 103 int s, opt; 104 105 snprintf(portstr, 6, "%d", port); 106 memset(&hints, 0, sizeof(hints)); 107 hints.ai_family = (domain == AF_UNSPEC ? AF_INET6 : domain); 108 hints.ai_socktype = proto; 109 hints.ai_flags = AI_PASSIVE; 110 if (getaddrinfo(local, portstr, &hints, &res) != 0) 111 return -1; 112 113 s = socket(res->ai_family, proto, 0); 114 if (s < 0) { 115 freeaddrinfo(res); 116 return -1; 117 } 118 119 opt = 1; 120 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 121 (char *) &opt, sizeof(opt)) < 0) { 122 close(s); 123 freeaddrinfo(res); 124 return -1; 125 } 126 if (domain == AF_UNSPEC || domain == AF_INET6) { 127 if (domain == AF_UNSPEC) 128 opt = 0; 129 else if (domain == AF_INET6) 130 opt = 1; 131 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 132 (char *) &opt, sizeof(opt)) < 0) { 133 close(s); 134 freeaddrinfo(res); 135 return -1; 136 } 137 } 138 139 if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { 140 close(s); 141 freeaddrinfo(res); 142 return -1; 143 } 144 145 freeaddrinfo(res); 146 147 if (proto == SOCK_STREAM) { 148 if (listen(s, 5) < 0) { 149 close(s); 150 return -1; 151 } 152 } 153 154 return s; 155 } 156 157 158 /*******************************************************************/ 159 /* reads 'count' bytes from a socket */ 160 /********************************************************************/ 161 162 int 163 Nread(int fd, char *buf, size_t count, int prot) 164 { 165 register ssize_t r; 166 register size_t nleft = count; 167 168 while (nleft > 0) { 169 r = read(fd, buf, nleft); 170 if (r < 0) { 171 if (errno == EINTR) 172 r = 0; 173 else 174 return NET_HARDERROR; 175 } else if (r == 0) 176 break; 177 178 nleft -= r; 179 buf += r; 180 } 181 return count - nleft; 182 } 183 184 185 /* 186 * N W R I T E 187 */ 188 189 int 190 Nwrite(int fd, const char *buf, size_t count, int prot) 191 { 192 register ssize_t r; 193 register size_t nleft = count; 194 195 while (nleft > 0) { 196 r = write(fd, buf, nleft); 197 if (r < 0) { 198 switch (errno) { 199 case EINTR: 200 return count - nleft; 201 202 case EAGAIN: 203 case ENOBUFS: 204 return NET_SOFTERROR; 205 206 default: 207 return NET_HARDERROR; 208 } 209 } else if (r == 0) 210 return NET_SOFTERROR; 211 nleft -= r; 212 buf += r; 213 } 214 return count; 215 } 216 217 218 int 219 has_sendfile(void) 220 { 221 #ifdef linux 222 return 1; 223 #else 224 #ifdef __FreeBSD__ 225 return 1; 226 #else 227 #if defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6) /* OS X */ 228 return 1; 229 #else 230 return 0; 231 #endif 232 #endif 233 #endif 234 } 235 236 237 /* 238 * N S E N D F I L E 239 */ 240 241 int 242 Nsendfile(int fromfd, int tofd, const char *buf, size_t count) 243 { 244 off_t offset; 245 #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6)) 246 off_t sent; 247 #endif 248 register size_t nleft; 249 register ssize_t r; 250 251 nleft = count; 252 while (nleft > 0) { 253 offset = count - nleft; 254 #ifdef linux 255 r = sendfile(tofd, fromfd, &offset, nleft); 256 #else 257 #ifdef __FreeBSD__ 258 r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0); 259 if (r == 0) 260 r = sent; 261 #else 262 #if defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6) /* OS X */ 263 sent = nleft; 264 r = sendfile(fromfd, tofd, offset, &sent, NULL, 0); 265 if (r == 0) 266 r = sent; 267 #else 268 /* Shouldn't happen. */ 269 r = -1; 270 errno = ENOSYS; 271 #endif 272 #endif 273 #endif 274 if (r < 0) { 275 switch (errno) { 276 case EINTR: 277 return count - nleft; 278 279 case EAGAIN: 280 case ENOBUFS: 281 case ENOMEM: 282 return NET_SOFTERROR; 283 284 default: 285 return NET_HARDERROR; 286 } 287 } else if (r == 0) 288 return NET_SOFTERROR; 289 nleft -= r; 290 } 291 return count; 292 } 293 294 /*************************************************************************/ 295 296 /** 297 * getsock_tcp_mss - Returns the MSS size for TCP 298 * 299 */ 300 301 int 302 getsock_tcp_mss(int inSock) 303 { 304 int mss = 0; 305 306 int rc; 307 socklen_t len; 308 309 assert(inSock >= 0); /* print error and exit if this is not true */ 310 311 /* query for mss */ 312 len = sizeof(mss); 313 rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len); 314 if (rc == -1) { 315 perror("getsockopt TCP_MAXSEG"); 316 return -1; 317 } 318 319 return mss; 320 } 321 322 323 324 /*************************************************************/ 325 326 /* sets TCP_NODELAY and TCP_MAXSEG if requested */ 327 // XXX: This function is not being used. 328 329 int 330 set_tcp_options(int sock, int no_delay, int mss) 331 { 332 socklen_t len; 333 int rc; 334 int new_mss; 335 336 if (no_delay == 1) { 337 len = sizeof(no_delay); 338 rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&no_delay, len); 339 if (rc == -1) { 340 perror("setsockopt TCP_NODELAY"); 341 return -1; 342 } 343 } 344 #ifdef TCP_MAXSEG 345 if (mss > 0) { 346 len = sizeof(new_mss); 347 assert(sock != -1); 348 349 /* set */ 350 new_mss = mss; 351 len = sizeof(new_mss); 352 rc = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len); 353 if (rc == -1) { 354 perror("setsockopt TCP_MAXSEG"); 355 return -1; 356 } 357 /* verify results */ 358 rc = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len); 359 if (rc == -1) { 360 perror("getsockopt TCP_MAXSEG"); 361 return -1; 362 } 363 if (new_mss != mss) { 364 perror("setsockopt value mismatch"); 365 return -1; 366 } 367 } 368 #endif 369 return 0; 370 } 371 372 /****************************************************************************/ 373 374 int 375 setnonblocking(int fd, int nonblocking) 376 { 377 int flags, newflags; 378 379 flags = fcntl(fd, F_GETFL, 0); 380 if (flags < 0) { 381 perror("fcntl(F_GETFL)"); 382 return -1; 383 } 384 if (nonblocking) 385 newflags = flags | (int) O_NONBLOCK; 386 else 387 newflags = flags & ~((int) O_NONBLOCK); 388 if (newflags != flags) 389 if (fcntl(fd, F_SETFL, newflags) < 0) { 390 perror("fcntl(F_SETFL)"); 391 return -1; 392 } 393 return 0; 394 } 395 396 /****************************************************************************/ 397 398 int 399 getsockdomain(int sock) 400 { 401 struct sockaddr sa; 402 socklen_t len = sizeof(sa); 403 404 if (getsockname(sock, &sa, &len) < 0) 405 return -1; 406 return sa.sa_family; 407 } 408