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 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)); 121 if (domain == AF_UNSPEC || domain == AF_INET6) { 122 if (domain == AF_UNSPEC) 123 opt = 0; 124 else if (domain == AF_INET6) 125 opt = 1; 126 setsockopt(s, SOL_SOCKET, IPV6_V6ONLY, (char *) &opt, sizeof(opt)); 127 } 128 129 if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { 130 close(s); 131 freeaddrinfo(res); 132 return -1; 133 } 134 135 freeaddrinfo(res); 136 137 if (proto == SOCK_STREAM) { 138 if (listen(s, 5) < 0) { 139 close(s); 140 return -1; 141 } 142 } 143 144 return s; 145 } 146 147 148 /*******************************************************************/ 149 /* reads 'count' bytes from a socket */ 150 /********************************************************************/ 151 152 int 153 Nread(int fd, char *buf, size_t count, int prot) 154 { 155 register ssize_t r; 156 register size_t nleft = count; 157 158 while (nleft > 0) { 159 r = read(fd, buf, nleft); 160 if (r < 0) { 161 if (errno == EINTR) 162 r = 0; 163 else 164 return NET_HARDERROR; 165 } else if (r == 0) 166 break; 167 168 nleft -= r; 169 buf += r; 170 } 171 return count - nleft; 172 } 173 174 175 /* 176 * N W R I T E 177 */ 178 179 int 180 Nwrite(int fd, const char *buf, size_t count, int prot) 181 { 182 register ssize_t r; 183 register size_t nleft = count; 184 185 while (nleft > 0) { 186 r = write(fd, buf, nleft); 187 if (r < 0) { 188 switch (errno) { 189 case EINTR: 190 return count - nleft; 191 192 case EAGAIN: 193 case ENOBUFS: 194 return NET_SOFTERROR; 195 196 default: 197 return NET_HARDERROR; 198 } 199 } else if (r == 0) 200 return NET_SOFTERROR; 201 nleft -= r; 202 buf += r; 203 } 204 return count; 205 } 206 207 208 int 209 has_sendfile(void) 210 { 211 #ifdef linux 212 return 1; 213 #else 214 #ifdef __FreeBSD__ 215 return 1; 216 #else 217 #if defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6) /* OS X */ 218 return 1; 219 #else 220 return 0; 221 #endif 222 #endif 223 #endif 224 } 225 226 227 /* 228 * N S E N D F I L E 229 */ 230 231 int 232 Nsendfile(int fromfd, int tofd, const char *buf, size_t count) 233 { 234 off_t offset; 235 #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6)) 236 off_t sent; 237 #endif 238 register size_t nleft; 239 register ssize_t r; 240 241 nleft = count; 242 while (nleft > 0) { 243 offset = count - nleft; 244 #ifdef linux 245 r = sendfile(tofd, fromfd, &offset, nleft); 246 #else 247 #ifdef __FreeBSD__ 248 r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0); 249 if (r == 0) 250 r = sent; 251 #else 252 #if defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6) /* OS X */ 253 sent = nleft; 254 r = sendfile(fromfd, tofd, offset, &sent, NULL, 0); 255 if (r == 0) 256 r = sent; 257 #else 258 /* Shouldn't happen. */ 259 r = -1; 260 errno = ENOSYS; 261 #endif 262 #endif 263 #endif 264 if (r < 0) { 265 switch (errno) { 266 case EINTR: 267 return count - nleft; 268 269 case EAGAIN: 270 case ENOBUFS: 271 case ENOMEM: 272 return NET_SOFTERROR; 273 274 default: 275 return NET_HARDERROR; 276 } 277 } else if (r == 0) 278 return NET_SOFTERROR; 279 nleft -= r; 280 } 281 return count; 282 } 283 284 /*************************************************************************/ 285 286 /** 287 * getsock_tcp_mss - Returns the MSS size for TCP 288 * 289 */ 290 291 int 292 getsock_tcp_mss(int inSock) 293 { 294 int mss = 0; 295 296 int rc; 297 socklen_t len; 298 299 assert(inSock >= 0); /* print error and exit if this is not true */ 300 301 /* query for mss */ 302 len = sizeof(mss); 303 rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len); 304 305 return mss; 306 } 307 308 309 310 /*************************************************************/ 311 312 /* sets TCP_NODELAY and TCP_MAXSEG if requested */ 313 // XXX: This function is not being used. 314 315 int 316 set_tcp_options(int sock, int no_delay, int mss) 317 { 318 socklen_t len; 319 int rc; 320 int new_mss; 321 322 if (no_delay == 1) { 323 len = sizeof(no_delay); 324 rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&no_delay, len); 325 if (rc == -1) { 326 perror("TCP_NODELAY"); 327 return -1; 328 } 329 } 330 #ifdef TCP_MAXSEG 331 if (mss > 0) { 332 len = sizeof(new_mss); 333 assert(sock != -1); 334 335 /* set */ 336 new_mss = mss; 337 len = sizeof(new_mss); 338 rc = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len); 339 if (rc == -1) { 340 perror("setsockopt"); 341 return -1; 342 } 343 /* verify results */ 344 rc = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len); 345 if (new_mss != mss) { 346 perror("setsockopt value mismatch"); 347 return -1; 348 } 349 } 350 #endif 351 return 0; 352 } 353 354 /****************************************************************************/ 355 356 int 357 setnonblocking(int fd, int nonblocking) 358 { 359 int flags, newflags; 360 361 flags = fcntl(fd, F_GETFL, 0); 362 if (flags < 0) { 363 perror("fcntl(F_GETFL)"); 364 return -1; 365 } 366 if (nonblocking) 367 newflags = flags | (int) O_NONBLOCK; 368 else 369 newflags = flags & ~((int) O_NONBLOCK); 370 if (newflags != flags) 371 if (fcntl(fd, F_SETFL, newflags) < 0) { 372 perror("fcntl(F_SETFL)"); 373 return -1; 374 } 375 return 0; 376 } 377 378 /****************************************************************************/ 379 380 int 381 getsockdomain(int sock) 382 { 383 struct sockaddr sa; 384 socklen_t len = sizeof(sa); 385 386 if (getsockname(sock, &sa, &len) < 0) 387 return -1; 388 return sa.sa_family; 389 } 390