J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this |
| 8 | * particular file as subject to the "Classpath" exception as provided |
| 9 | * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 23 | * have any questions. |
| 24 | */ |
| 25 | package java.net; |
| 26 | |
| 27 | import java.io.IOException; |
| 28 | import java.io.FileDescriptor; |
| 29 | |
| 30 | /* |
| 31 | * This class defines the plain SocketImpl that is used for all |
| 32 | * Windows version lower than Vista. It adds support for IPv6 on |
| 33 | * these platforms where available. |
| 34 | * |
| 35 | * For backward compatibility Windows platforms that do not have IPv6 |
| 36 | * support also use this implementation, and fd1 gets set to null |
| 37 | * during socket creation. |
| 38 | * |
| 39 | * @author Chris Hegarty |
| 40 | */ |
| 41 | |
| 42 | class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl |
| 43 | { |
| 44 | /* second fd, used for ipv6 on windows only. |
| 45 | * fd1 is used for listeners and for client sockets at initialization |
| 46 | * until the socket is connected. Up to this point fd always refers |
| 47 | * to the ipv4 socket and fd1 to the ipv6 socket. After the socket |
| 48 | * becomes connected, fd always refers to the connected socket |
| 49 | * (either v4 or v6) and fd1 is closed. |
| 50 | * |
| 51 | * For ServerSockets, fd always refers to the v4 listener and |
| 52 | * fd1 the v6 listener. |
| 53 | */ |
| 54 | private FileDescriptor fd1; |
| 55 | |
| 56 | /* |
| 57 | * Needed for ipv6 on windows because we need to know |
| 58 | * if the socket is bound to ::0 or 0.0.0.0, when a caller |
| 59 | * asks for it. Otherwise we don't know which socket to ask. |
| 60 | */ |
| 61 | private InetAddress anyLocalBoundAddr = null; |
| 62 | |
| 63 | /* to prevent starvation when listening on two sockets, this is |
| 64 | * is used to hold the id of the last socket we accepted on. |
| 65 | */ |
| 66 | private int lastfd = -1; |
| 67 | |
| 68 | static { |
| 69 | initProto(); |
| 70 | } |
| 71 | |
| 72 | public TwoStacksPlainSocketImpl() {} |
| 73 | |
| 74 | public TwoStacksPlainSocketImpl(FileDescriptor fd) { |
| 75 | this.fd = fd; |
| 76 | } |
| 77 | |
| 78 | /** |
| 79 | * Creates a socket with a boolean that specifies whether this |
| 80 | * is a stream socket (true) or an unconnected UDP socket (false). |
| 81 | */ |
| 82 | protected synchronized void create(boolean stream) throws IOException { |
| 83 | fd1 = new FileDescriptor(); |
| 84 | super.create(stream); |
| 85 | } |
| 86 | |
| 87 | /** |
| 88 | * Binds the socket to the specified address of the specified local port. |
| 89 | * @param address the address |
| 90 | * @param port the port |
| 91 | */ |
| 92 | protected synchronized void bind(InetAddress address, int lport) |
| 93 | throws IOException |
| 94 | { |
| 95 | super.bind(address, lport); |
| 96 | if (address.isAnyLocalAddress()) { |
| 97 | anyLocalBoundAddr = address; |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | public Object getOption(int opt) throws SocketException { |
| 102 | if (isClosedOrPending()) { |
| 103 | throw new SocketException("Socket Closed"); |
| 104 | } |
| 105 | if (opt == SO_BINDADDR) { |
| 106 | if (fd != null && fd1 != null ) { |
| 107 | /* must be unbound or else bound to anyLocal */ |
| 108 | return anyLocalBoundAddr; |
| 109 | } |
| 110 | InetAddressContainer in = new InetAddressContainer(); |
| 111 | socketGetOption(opt, in); |
| 112 | return in.addr; |
| 113 | } else |
| 114 | return super.getOption(opt); |
| 115 | } |
| 116 | |
| 117 | /** |
| 118 | * Closes the socket. |
| 119 | */ |
| 120 | protected void close() throws IOException { |
| 121 | synchronized(fdLock) { |
| 122 | if (fd != null || fd1 != null) { |
| 123 | if (fdUseCount == 0) { |
| 124 | if (closePending) { |
| 125 | return; |
| 126 | } |
| 127 | closePending = true; |
| 128 | socketClose(); |
| 129 | fd = null; |
| 130 | fd1 = null; |
| 131 | return; |
| 132 | } else { |
| 133 | /* |
| 134 | * If a thread has acquired the fd and a close |
| 135 | * isn't pending then use a deferred close. |
| 136 | * Also decrement fdUseCount to signal the last |
| 137 | * thread that releases the fd to close it. |
| 138 | */ |
| 139 | if (!closePending) { |
| 140 | closePending = true; |
| 141 | fdUseCount--; |
| 142 | socketClose(); |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | void reset() throws IOException { |
| 150 | if (fd != null || fd1 != null) { |
| 151 | socketClose(); |
| 152 | } |
| 153 | fd = null; |
| 154 | fd1 = null; |
| 155 | super.reset(); |
| 156 | } |
| 157 | |
| 158 | /* |
| 159 | * Return true if already closed or close is pending |
| 160 | */ |
| 161 | public boolean isClosedOrPending() { |
| 162 | /* |
| 163 | * Lock on fdLock to ensure that we wait if a |
| 164 | * close is in progress. |
| 165 | */ |
| 166 | synchronized (fdLock) { |
| 167 | if (closePending || (fd == null && fd1 == null)) { |
| 168 | return true; |
| 169 | } else { |
| 170 | return false; |
| 171 | } |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | /* Native methods */ |
| 176 | |
| 177 | static native void initProto(); |
| 178 | |
| 179 | native void socketCreate(boolean isServer) throws IOException; |
| 180 | |
| 181 | native void socketConnect(InetAddress address, int port, int timeout) |
| 182 | throws IOException; |
| 183 | |
| 184 | native void socketBind(InetAddress address, int port) |
| 185 | throws IOException; |
| 186 | |
| 187 | native void socketListen(int count) throws IOException; |
| 188 | |
| 189 | native void socketAccept(SocketImpl s) throws IOException; |
| 190 | |
| 191 | native int socketAvailable() throws IOException; |
| 192 | |
| 193 | native void socketClose0(boolean useDeferredClose) throws IOException; |
| 194 | |
| 195 | native void socketShutdown(int howto) throws IOException; |
| 196 | |
| 197 | native void socketSetOption(int cmd, boolean on, Object value) |
| 198 | throws SocketException; |
| 199 | |
| 200 | native int socketGetOption(int opt, Object iaContainerObj) throws SocketException; |
| 201 | |
| 202 | native int socketGetOption1(int opt, Object iaContainerObj, FileDescriptor fd) |
| 203 | throws SocketException; |
| 204 | |
| 205 | native void socketSendUrgentData(int data) throws IOException; |
| 206 | } |