1 /* 2 * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.nio.ch; 27 28 import java.io.FileDescriptor; 29 import java.io.IOException; 30 import java.net.Inet4Address; 31 import java.net.Inet6Address; 32 import java.net.InetAddress; 33 import java.net.InetSocketAddress; 34 import java.net.NetworkInterface; 35 import java.net.ProtocolFamily; 36 import java.net.SocketAddress; 37 import java.net.SocketException; 38 import java.net.SocketOption; 39 import java.net.StandardProtocolFamily; 40 import java.net.StandardSocketOptions; 41 import java.net.UnknownHostException; 42 import java.nio.channels.AlreadyBoundException; 43 import java.nio.channels.ClosedChannelException; 44 import java.nio.channels.NotYetBoundException; 45 import java.nio.channels.NotYetConnectedException; 46 import java.nio.channels.UnresolvedAddressException; 47 import java.nio.channels.UnsupportedAddressTypeException; 48 import java.security.AccessController; 49 import java.security.PrivilegedAction; 50 import java.util.Enumeration; 51 52 import sun.net.ext.ExtendedSocketOptions; 53 import sun.net.util.IPAddressUtil; 54 import sun.security.action.GetPropertyAction; 55 56 public class Net { 57 58 private Net() { } 59 60 // unspecified protocol family 61 static final ProtocolFamily UNSPEC = new ProtocolFamily() { 62 public String name() { 63 return "UNSPEC"; 64 } 65 }; 66 67 // set to true if exclusive binding is on for Windows 68 private static final boolean exclusiveBind; 69 70 // set to true if the fast tcp loopback should be enabled on Windows 71 private static final boolean fastLoopback; 72 73 // -- Miscellaneous utilities -- 74 75 private static volatile boolean checkedIPv6; 76 private static volatile boolean isIPv6Available; 77 private static volatile boolean checkedReusePort; 78 private static volatile boolean isReusePortAvailable; 79 80 /** 81 * Tells whether dual-IPv4/IPv6 sockets should be used. 82 */ 83 static boolean isIPv6Available() { 84 if (!checkedIPv6) { 85 isIPv6Available = isIPv6Available0(); 86 checkedIPv6 = true; 87 } 88 return isIPv6Available; 89 } 90 91 /** 92 * Tells whether SO_REUSEPORT is supported. 93 */ 94 static boolean isReusePortAvailable() { 95 if (!checkedReusePort) { 96 isReusePortAvailable = isReusePortAvailable0(); 97 checkedReusePort = true; 98 } 99 return isReusePortAvailable; 100 } 101 102 /** 103 * Returns true if exclusive binding is on 104 */ 105 static boolean useExclusiveBind() { 106 return exclusiveBind; 107 } 108 109 /** 110 * Tells whether IPv6 sockets can join IPv4 multicast groups 111 */ 112 static boolean canIPv6SocketJoinIPv4Group() { 113 return canIPv6SocketJoinIPv4Group0(); 114 } 115 116 /** 117 * Tells whether {@link #join6} can be used to join an IPv4 118 * multicast group (IPv4 group as IPv4-mapped IPv6 address) 119 */ 120 static boolean canJoin6WithIPv4Group() { 121 return canJoin6WithIPv4Group0(); 122 } 123 124 public static InetSocketAddress checkAddress(SocketAddress sa) { 125 if (sa == null) 126 throw new NullPointerException(); 127 if (!(sa instanceof InetSocketAddress)) 128 throw new UnsupportedAddressTypeException(); // ## needs arg 129 InetSocketAddress isa = (InetSocketAddress)sa; 130 if (isa.isUnresolved()) 131 throw new UnresolvedAddressException(); // ## needs arg 132 InetAddress addr = isa.getAddress(); 133 if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) 134 throw new IllegalArgumentException("Invalid address type"); 135 return isa; 136 } 137 138 static InetSocketAddress checkAddress(SocketAddress sa, ProtocolFamily family) { 139 InetSocketAddress isa = checkAddress(sa); 140 if (family == StandardProtocolFamily.INET) { 141 InetAddress addr = isa.getAddress(); 142 if (!(addr instanceof Inet4Address)) 143 throw new UnsupportedAddressTypeException(); 144 } 145 return isa; 146 } 147 148 static InetSocketAddress asInetSocketAddress(SocketAddress sa) { 149 if (!(sa instanceof InetSocketAddress)) 150 throw new UnsupportedAddressTypeException(); 151 return (InetSocketAddress)sa; 152 } 153 154 static void translateToSocketException(Exception x) 155 throws SocketException 156 { 157 if (x instanceof SocketException) 158 throw (SocketException)x; 159 Exception nx = x; 160 if (x instanceof ClosedChannelException) 161 nx = new SocketException("Socket is closed"); 162 else if (x instanceof NotYetConnectedException) 163 nx = new SocketException("Socket is not connected"); 164 else if (x instanceof AlreadyBoundException) 165 nx = new SocketException("Already bound"); 166 else if (x instanceof NotYetBoundException) 167 nx = new SocketException("Socket is not bound yet"); 168 else if (x instanceof UnsupportedAddressTypeException) 169 nx = new SocketException("Unsupported address type"); 170 else if (x instanceof UnresolvedAddressException) { 171 nx = new SocketException("Unresolved address"); 172 } 173 if (nx != x) 174 nx.initCause(x); 175 176 if (nx instanceof SocketException) 177 throw (SocketException)nx; 178 else if (nx instanceof RuntimeException) 179 throw (RuntimeException)nx; 180 else 181 throw new Error("Untranslated exception", nx); 182 } 183 184 static void translateException(Exception x, 185 boolean unknownHostForUnresolved) 186 throws IOException 187 { 188 if (x instanceof IOException) 189 throw (IOException)x; 190 // Throw UnknownHostException from here since it cannot 191 // be thrown as a SocketException 192 if (unknownHostForUnresolved && 193 (x instanceof UnresolvedAddressException)) 194 { 195 throw new UnknownHostException(); 196 } 197 translateToSocketException(x); 198 } 199 200 static void translateException(Exception x) 201 throws IOException 202 { 203 translateException(x, false); 204 } 205 206 /** 207 * Returns the local address after performing a SecurityManager#checkConnect. 208 */ 209 static InetSocketAddress getRevealedLocalAddress(InetSocketAddress addr) { 210 SecurityManager sm = System.getSecurityManager(); 211 if (addr == null || sm == null) 212 return addr; 213 214 try{ 215 sm.checkConnect(addr.getAddress().getHostAddress(), -1); 216 // Security check passed 217 } catch (SecurityException e) { 218 // Return loopback address only if security check fails 219 addr = getLoopbackAddress(addr.getPort()); 220 } 221 return addr; 222 } 223 224 static String getRevealedLocalAddressAsString(InetSocketAddress addr) { 225 return System.getSecurityManager() == null ? addr.toString() : 226 getLoopbackAddress(addr.getPort()).toString(); 227 } 228 229 private static InetSocketAddress getLoopbackAddress(int port) { 230 return new InetSocketAddress(InetAddress.getLoopbackAddress(), 231 port); 232 } 233 234 /** 235 * Returns any IPv4 address of the given network interface, or 236 * null if the interface does not have any IPv4 addresses. 237 */ 238 static Inet4Address anyInet4Address(final NetworkInterface interf) { 239 return AccessController.doPrivileged(new PrivilegedAction<Inet4Address>() { 240 public Inet4Address run() { 241 Enumeration<InetAddress> addrs = interf.getInetAddresses(); 242 while (addrs.hasMoreElements()) { 243 InetAddress addr = addrs.nextElement(); 244 if (addr instanceof Inet4Address) { 245 return (Inet4Address)addr; 246 } 247 } 248 return null; 249 } 250 }); 251 } 252 253 /** 254 * Returns an IPv4 address as an int. 255 */ 256 static int inet4AsInt(InetAddress ia) { 257 if (ia instanceof Inet4Address) { 258 byte[] addr = ia.getAddress(); 259 int address = addr[3] & 0xFF; 260 address |= ((addr[2] << 8) & 0xFF00); 261 address |= ((addr[1] << 16) & 0xFF0000); 262 address |= ((addr[0] << 24) & 0xFF000000); 263 return address; 264 } 265 throw new AssertionError("Should not reach here"); 266 } 267 268 /** 269 * Returns an InetAddress from the given IPv4 address 270 * represented as an int. 271 */ 272 static InetAddress inet4FromInt(int address) { 273 byte[] addr = new byte[4]; 274 addr[0] = (byte) ((address >>> 24) & 0xFF); 275 addr[1] = (byte) ((address >>> 16) & 0xFF); 276 addr[2] = (byte) ((address >>> 8) & 0xFF); 277 addr[3] = (byte) (address & 0xFF); 278 try { 279 return InetAddress.getByAddress(addr); 280 } catch (UnknownHostException uhe) { 281 throw new AssertionError("Should not reach here"); 282 } 283 } 284 285 /** 286 * Returns an IPv6 address as a byte array 287 */ 288 static byte[] inet6AsByteArray(InetAddress ia) { 289 if (ia instanceof Inet6Address) { 290 return ia.getAddress(); 291 } 292 293 // need to construct IPv4-mapped address 294 if (ia instanceof Inet4Address) { 295 byte[] ip4address = ia.getAddress(); 296 byte[] address = new byte[16]; 297 address[10] = (byte)0xff; 298 address[11] = (byte)0xff; 299 address[12] = ip4address[0]; 300 address[13] = ip4address[1]; 301 address[14] = ip4address[2]; 302 address[15] = ip4address[3]; 303 return address; 304 } 305 306 throw new AssertionError("Should not reach here"); 307 } 308 309 // -- Socket options 310 311 static final ExtendedSocketOptions extendedOptions = 312 ExtendedSocketOptions.getInstance(); 313 314 static void setSocketOption(FileDescriptor fd, SocketOption<?> name, Object value) 315 throws IOException 316 { 317 setSocketOption(fd, Net.UNSPEC, name, value); 318 } 319 320 static void setSocketOption(FileDescriptor fd, ProtocolFamily family, 321 SocketOption<?> name, Object value) 322 throws IOException 323 { 324 if (value == null) 325 throw new IllegalArgumentException("Invalid option value"); 326 327 // only simple values supported by this method 328 Class<?> type = name.type(); 329 330 if (extendedOptions.isOptionSupported(name)) { 331 extendedOptions.setOption(fd, name, value); 332 return; 333 } 334 335 if (type != Integer.class && type != Boolean.class) 336 throw new AssertionError("Should not reach here"); 337 338 // special handling 339 if (name == StandardSocketOptions.SO_RCVBUF || 340 name == StandardSocketOptions.SO_SNDBUF) 341 { 342 int i = ((Integer)value).intValue(); 343 if (i < 0) 344 throw new IllegalArgumentException("Invalid send/receive buffer size"); 345 } 346 if (name == StandardSocketOptions.SO_LINGER) { 347 int i = ((Integer)value).intValue(); 348 if (i < 0) 349 value = Integer.valueOf(-1); 350 if (i > 65535) 351 value = Integer.valueOf(65535); 352 } 353 if (name == StandardSocketOptions.IP_TOS) { 354 int i = ((Integer)value).intValue(); 355 if (i < 0 || i > 255) 356 throw new IllegalArgumentException("Invalid IP_TOS value"); 357 } 358 if (name == StandardSocketOptions.IP_MULTICAST_TTL) { 359 int i = ((Integer)value).intValue(); 360 if (i < 0 || i > 255) 361 throw new IllegalArgumentException("Invalid TTL/hop value"); 362 } 363 364 // map option name to platform level/name 365 OptionKey key = SocketOptionRegistry.findOption(name, family); 366 if (key == null) 367 throw new AssertionError("Option not found"); 368 369 int arg; 370 if (type == Integer.class) { 371 arg = ((Integer)value).intValue(); 372 } else { 373 boolean b = ((Boolean)value).booleanValue(); 374 arg = (b) ? 1 : 0; 375 } 376 377 boolean mayNeedConversion = (family == UNSPEC); 378 boolean isIPv6 = (family == StandardProtocolFamily.INET6); 379 setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg, isIPv6); 380 } 381 382 static Object getSocketOption(FileDescriptor fd, SocketOption<?> name) 383 throws IOException 384 { 385 return getSocketOption(fd, Net.UNSPEC, name); 386 } 387 388 static Object getSocketOption(FileDescriptor fd, ProtocolFamily family, SocketOption<?> name) 389 throws IOException 390 { 391 Class<?> type = name.type(); 392 393 if (extendedOptions.isOptionSupported(name)) { 394 return extendedOptions.getOption(fd, name); 395 } 396 397 // only simple values supported by this method 398 if (type != Integer.class && type != Boolean.class) 399 throw new AssertionError("Should not reach here"); 400 401 // map option name to platform level/name 402 OptionKey key = SocketOptionRegistry.findOption(name, family); 403 if (key == null) 404 throw new AssertionError("Option not found"); 405 406 boolean mayNeedConversion = (family == UNSPEC); 407 int value = getIntOption0(fd, mayNeedConversion, key.level(), key.name()); 408 409 if (type == Integer.class) { 410 return Integer.valueOf(value); 411 } else { 412 return (value == 0) ? Boolean.FALSE : Boolean.TRUE; 413 } 414 } 415 416 public static boolean isFastTcpLoopbackRequested() { 417 String loopbackProp = GetPropertyAction 418 .privilegedGetProperty("jdk.net.useFastTcpLoopback", "false"); 419 return loopbackProp.isEmpty() ? true : Boolean.parseBoolean(loopbackProp); 420 } 421 422 // -- Socket operations -- 423 424 private static native boolean isIPv6Available0(); 425 426 private static native boolean isReusePortAvailable0(); 427 428 /* 429 * Returns 1 for Windows and -1 for Solaris/Linux/Mac OS 430 */ 431 private static native int isExclusiveBindAvailable(); 432 433 private static native boolean canIPv6SocketJoinIPv4Group0(); 434 435 private static native boolean canJoin6WithIPv4Group0(); 436 437 static FileDescriptor socket(boolean stream) throws IOException { 438 return socket(UNSPEC, stream); 439 } 440 441 static FileDescriptor socket(ProtocolFamily family, boolean stream) throws IOException { 442 boolean preferIPv6 = isIPv6Available() && 443 (family != StandardProtocolFamily.INET); 444 return IOUtil.newFD(socket0(preferIPv6, stream, false, fastLoopback)); 445 } 446 447 static FileDescriptor serverSocket(boolean stream) { 448 return IOUtil.newFD(socket0(isIPv6Available(), stream, true, fastLoopback)); 449 } 450 451 // Due to oddities SO_REUSEADDR on windows reuse is ignored 452 private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse, 453 boolean fastLoopback); 454 455 public static void bind(FileDescriptor fd, InetAddress addr, int port) 456 throws IOException 457 { 458 bind(UNSPEC, fd, addr, port); 459 } 460 461 static void bind(ProtocolFamily family, FileDescriptor fd, 462 InetAddress addr, int port) throws IOException 463 { 464 boolean preferIPv6 = isIPv6Available() && 465 (family != StandardProtocolFamily.INET); 466 if (addr.isLinkLocalAddress()) { 467 addr = IPAddressUtil.toScopedAddress(addr); 468 } 469 bind0(fd, preferIPv6, exclusiveBind, addr, port); 470 } 471 472 private static native void bind0(FileDescriptor fd, boolean preferIPv6, 473 boolean useExclBind, InetAddress addr, 474 int port) 475 throws IOException; 476 477 static native void listen(FileDescriptor fd, int backlog) throws IOException; 478 479 static int connect(FileDescriptor fd, InetAddress remote, int remotePort) 480 throws IOException 481 { 482 return connect(UNSPEC, fd, remote, remotePort); 483 } 484 485 static int connect(ProtocolFamily family, FileDescriptor fd, InetAddress remote, int remotePort) 486 throws IOException 487 { 488 if (remote.isLinkLocalAddress()) { 489 remote = IPAddressUtil.toScopedAddress(remote); 490 } 491 boolean preferIPv6 = isIPv6Available() && 492 (family != StandardProtocolFamily.INET); 493 return connect0(preferIPv6, fd, remote, remotePort); 494 } 495 496 private static native int connect0(boolean preferIPv6, 497 FileDescriptor fd, 498 InetAddress remote, 499 int remotePort) 500 throws IOException; 501 502 public static native int accept(FileDescriptor fd, 503 FileDescriptor newfd, 504 InetSocketAddress[] isaa) 505 throws IOException; 506 507 public static final int SHUT_RD = 0; 508 public static final int SHUT_WR = 1; 509 public static final int SHUT_RDWR = 2; 510 511 static native void shutdown(FileDescriptor fd, int how) throws IOException; 512 513 private static native int localPort(FileDescriptor fd) 514 throws IOException; 515 516 private static native InetAddress localInetAddress(FileDescriptor fd) 517 throws IOException; 518 519 public static InetSocketAddress localAddress(FileDescriptor fd) 520 throws IOException 521 { 522 return new InetSocketAddress(localInetAddress(fd), localPort(fd)); 523 } 524 525 private static native int remotePort(FileDescriptor fd) 526 throws IOException; 527 528 private static native InetAddress remoteInetAddress(FileDescriptor fd) 529 throws IOException; 530 531 static InetSocketAddress remoteAddress(FileDescriptor fd) 532 throws IOException 533 { 534 return new InetSocketAddress(remoteInetAddress(fd), remotePort(fd)); 535 } 536 537 private static native int getIntOption0(FileDescriptor fd, boolean mayNeedConversion, 538 int level, int opt) 539 throws IOException; 540 541 private static native void setIntOption0(FileDescriptor fd, boolean mayNeedConversion, 542 int level, int opt, int arg, boolean isIPv6) 543 throws IOException; 544 545 /** 546 * Polls a file descriptor for events. 547 * @param timeout the timeout to wait; 0 to not wait, -1 to wait indefinitely 548 * @return the polled events or 0 if no events are polled 549 */ 550 static native int poll(FileDescriptor fd, int events, long timeout) 551 throws IOException; 552 553 /** 554 * Performs a non-blocking poll of a file descriptor. 555 * @return the polled events or 0 if no events are polled 556 */ 557 static int pollNow(FileDescriptor fd, int events) throws IOException { 558 return poll(fd, events, 0); 559 } 560 561 /** 562 * Polls a connecting socket to test if the connection has been established. 563 * 564 * @apiNote This method is public to allow it be used by code in jdk.sctp. 565 * 566 * @param timeout the timeout to wait; 0 to not wait, -1 to wait indefinitely 567 * @return true if connected 568 */ 569 public static native boolean pollConnect(FileDescriptor fd, long timeout) 570 throws IOException; 571 572 /** 573 * Performs a non-blocking poll of a connecting socket to test if the 574 * connection has been established. 575 * 576 * @return true if connected 577 */ 578 static boolean pollConnectNow(FileDescriptor fd) throws IOException { 579 return pollConnect(fd, 0); 580 } 581 582 /** 583 * Return the number of bytes in the socket input buffer. 584 */ 585 static native int available(FileDescriptor fd) throws IOException; 586 587 /** 588 * Send one byte of urgent data (MSG_OOB) on the socket. 589 */ 590 static native int sendOOB(FileDescriptor fd, byte data) throws IOException; 591 592 593 // -- Multicast support -- 594 595 /** 596 * Join IPv4 multicast group 597 */ 598 static int join4(FileDescriptor fd, int group, int interf, int source) 599 throws IOException 600 { 601 return joinOrDrop4(true, fd, group, interf, source); 602 } 603 604 /** 605 * Drop membership of IPv4 multicast group 606 */ 607 static void drop4(FileDescriptor fd, int group, int interf, int source) 608 throws IOException 609 { 610 joinOrDrop4(false, fd, group, interf, source); 611 } 612 613 private static native int joinOrDrop4(boolean join, FileDescriptor fd, int group, int interf, int source) 614 throws IOException; 615 616 /** 617 * Block IPv4 source 618 */ 619 static int block4(FileDescriptor fd, int group, int interf, int source) 620 throws IOException 621 { 622 return blockOrUnblock4(true, fd, group, interf, source); 623 } 624 625 /** 626 * Unblock IPv6 source 627 */ 628 static void unblock4(FileDescriptor fd, int group, int interf, int source) 629 throws IOException 630 { 631 blockOrUnblock4(false, fd, group, interf, source); 632 } 633 634 private static native int blockOrUnblock4(boolean block, FileDescriptor fd, int group, 635 int interf, int source) 636 throws IOException; 637 638 /** 639 * Join IPv6 multicast group 640 */ 641 static int join6(FileDescriptor fd, byte[] group, int index, byte[] source) 642 throws IOException 643 { 644 return joinOrDrop6(true, fd, group, index, source); 645 } 646 647 /** 648 * Drop membership of IPv6 multicast group 649 */ 650 static void drop6(FileDescriptor fd, byte[] group, int index, byte[] source) 651 throws IOException 652 { 653 joinOrDrop6(false, fd, group, index, source); 654 } 655 656 private static native int joinOrDrop6(boolean join, FileDescriptor fd, byte[] group, int index, byte[] source) 657 throws IOException; 658 659 /** 660 * Block IPv6 source 661 */ 662 static int block6(FileDescriptor fd, byte[] group, int index, byte[] source) 663 throws IOException 664 { 665 return blockOrUnblock6(true, fd, group, index, source); 666 } 667 668 /** 669 * Unblock IPv6 source 670 */ 671 static void unblock6(FileDescriptor fd, byte[] group, int index, byte[] source) 672 throws IOException 673 { 674 blockOrUnblock6(false, fd, group, index, source); 675 } 676 677 static native int blockOrUnblock6(boolean block, FileDescriptor fd, byte[] group, int index, byte[] source) 678 throws IOException; 679 680 static native void setInterface4(FileDescriptor fd, int interf) throws IOException; 681 682 static native int getInterface4(FileDescriptor fd) throws IOException; 683 684 static native void setInterface6(FileDescriptor fd, int index) throws IOException; 685 686 static native int getInterface6(FileDescriptor fd) throws IOException; 687 688 private static native void initIDs(); 689 690 /** 691 * Event masks for the various poll system calls. 692 * They will be set platform dependent in the static initializer below. 693 */ 694 public static final short POLLIN; 695 public static final short POLLOUT; 696 public static final short POLLERR; 697 public static final short POLLHUP; 698 public static final short POLLNVAL; 699 public static final short POLLCONN; 700 701 static native short pollinValue(); 702 static native short polloutValue(); 703 static native short pollerrValue(); 704 static native short pollhupValue(); 705 static native short pollnvalValue(); 706 static native short pollconnValue(); 707 708 static { 709 IOUtil.load(); 710 initIDs(); 711 712 POLLIN = pollinValue(); 713 POLLOUT = polloutValue(); 714 POLLERR = pollerrValue(); 715 POLLHUP = pollhupValue(); 716 POLLNVAL = pollnvalValue(); 717 POLLCONN = pollconnValue(); 718 } 719 720 static { 721 int availLevel = isExclusiveBindAvailable(); 722 if (availLevel >= 0) { 723 String exclBindProp = GetPropertyAction 724 .privilegedGetProperty("sun.net.useExclusiveBind"); 725 if (exclBindProp != null) { 726 exclusiveBind = exclBindProp.isEmpty() ? 727 true : Boolean.parseBoolean(exclBindProp); 728 } else if (availLevel == 1) { 729 exclusiveBind = true; 730 } else { 731 exclusiveBind = false; 732 } 733 } else { 734 exclusiveBind = false; 735 } 736 737 fastLoopback = isFastTcpLoopbackRequested(); 738 } 739 }