Showing the changes to java/pkg/java/net (205 of 18352 files). Show all
Unified · Split
Binary file not shown.
| @@ -0,0 +1,352 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2011, 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 | +package java.net; | |
| 26 | + | |
| 27 | +import java.io.FileDescriptor; | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.io.InterruptedIOException; | |
| 30 | +import java.util.Enumeration; | |
| 31 | +import sun.net.ResourceManager; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * Abstract datagram and multicast socket implementation base class. | |
| 35 | + * Note: This is not a public class, so that applets cannot call | |
| 36 | + * into the implementation directly and hence cannot bypass the | |
| 37 | + * security checks present in the DatagramSocket and MulticastSocket | |
| 38 | + * classes. | |
| 39 | + * | |
| 40 | + * @author Pavani Diwanji | |
| 41 | + */ | |
| 42 | + | |
| 43 | +abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl | |
| 44 | +{ | |
| 45 | + /* timeout value for receive() */ | |
| 46 | + int timeout = 0; | |
| 47 | + boolean connected = false; | |
| 48 | + private int trafficClass = 0; | |
| 49 | + private InetAddress connectedAddress = null; | |
| 50 | + private int connectedPort = -1; | |
| 51 | + | |
| 52 | + /* cached socket options */ | |
| 53 | + private int multicastInterface = 0; | |
| 54 | + private boolean loopbackMode = true; | |
| 55 | + private int ttl = -1; | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * Load net library into runtime. | |
| 59 | + */ | |
| 60 | + static { | |
| 61 | + java.security.AccessController.doPrivileged( | |
| 62 | + new sun.security.action.LoadLibraryAction("net")); | |
| 63 | + } | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * Creates a datagram socket | |
| 67 | + */ | |
| 68 | + protected synchronized void create() throws SocketException { | |
| 69 | + fd = new FileDescriptor(); | |
| 70 | + ResourceManager.beforeUdpCreate(); | |
| 71 | + try { | |
| 72 | + datagramSocketCreate(); | |
| 73 | + } catch (SocketException ioe) { | |
| 74 | + ResourceManager.afterUdpClose(); | |
| 75 | + fd = null; | |
| 76 | + throw ioe; | |
| 77 | + } | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * Binds a datagram socket to a local port. | |
| 82 | + */ | |
| 83 | + protected synchronized void bind(int lport, InetAddress laddr) | |
| 84 | + throws SocketException { | |
| 85 | + bind0(lport, laddr); | |
| 86 | + } | |
| 87 | + | |
| 88 | + protected abstract void bind0(int lport, InetAddress laddr) | |
| 89 | + throws SocketException; | |
| 90 | + | |
| 91 | + /** | |
| 92 | + * Sends a datagram packet. The packet contains the data and the | |
| 93 | + * destination address to send the packet to. | |
| 94 | + * @param packet to be sent. | |
| 95 | + */ | |
| 96 | + protected abstract void send(DatagramPacket p) throws IOException; | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * Connects a datagram socket to a remote destination. This associates the remote | |
| 100 | + * address with the local socket so that datagrams may only be sent to this destination | |
| 101 | + * and received from this destination. | |
| 102 | + * @param address the remote InetAddress to connect to | |
| 103 | + * @param port the remote port number | |
| 104 | + */ | |
| 105 | + protected void connect(InetAddress address, int port) throws SocketException { | |
| 106 | + connect0(address, port); | |
| 107 | + connectedAddress = address; | |
| 108 | + connectedPort = port; | |
| 109 | + connected = true; | |
| 110 | + } | |
| 111 | + | |
| 112 | + /** | |
| 113 | + * Disconnects a previously connected socket. Does nothing if the socket was | |
| 114 | + * not connected already. | |
| 115 | + */ | |
| 116 | + protected void disconnect() { | |
| 117 | + disconnect0(connectedAddress.family); | |
| 118 | + connected = false; | |
| 119 | + connectedAddress = null; | |
| 120 | + connectedPort = -1; | |
| 121 | + } | |
| 122 | + | |
| 123 | + /** | |
| 124 | + * Peek at the packet to see who it is from. | |
| 125 | + * @param return the address which the packet came from. | |
| 126 | + */ | |
| 127 | + protected abstract int peek(InetAddress i) throws IOException; | |
| 128 | + protected abstract int peekData(DatagramPacket p) throws IOException; | |
| 129 | + /** | |
| 130 | + * Receive the datagram packet. | |
| 131 | + * @param Packet Received. | |
| 132 | + */ | |
| 133 | + protected synchronized void receive(DatagramPacket p) | |
| 134 | + throws IOException { | |
| 135 | + receive0(p); | |
| 136 | + } | |
| 137 | + | |
| 138 | + protected abstract void receive0(DatagramPacket p) | |
| 139 | + throws IOException; | |
| 140 | + | |
| 141 | + /** | |
| 142 | + * Set the TTL (time-to-live) option. | |
| 143 | + * @param TTL to be set. | |
| 144 | + */ | |
| 145 | + protected abstract void setTimeToLive(int ttl) throws IOException; | |
| 146 | + | |
| 147 | + /** | |
| 148 | + * Get the TTL (time-to-live) option. | |
| 149 | + */ | |
| 150 | + protected abstract int getTimeToLive() throws IOException; | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * Set the TTL (time-to-live) option. | |
| 154 | + * @param TTL to be set. | |
| 155 | + */ | |
| 156 | + protected abstract void setTTL(byte ttl) throws IOException; | |
| 157 | + | |
| 158 | + /** | |
| 159 | + * Get the TTL (time-to-live) option. | |
| 160 | + */ | |
| 161 | + protected abstract byte getTTL() throws IOException; | |
| 162 | + | |
| 163 | + /** | |
| 164 | + * Join the multicast group. | |
| 165 | + * @param multicast address to join. | |
| 166 | + */ | |
| 167 | + protected void join(InetAddress inetaddr) throws IOException { | |
| 168 | + join(inetaddr, null); | |
| 169 | + } | |
| 170 | + | |
| 171 | + /** | |
| 172 | + * Leave the multicast group. | |
| 173 | + * @param multicast address to leave. | |
| 174 | + */ | |
| 175 | + protected void leave(InetAddress inetaddr) throws IOException { | |
| 176 | + leave(inetaddr, null); | |
| 177 | + } | |
| 178 | + /** | |
| 179 | + * Join the multicast group. | |
| 180 | + * @param multicast address to join. | |
| 181 | + * @param netIf specifies the local interface to receive multicast | |
| 182 | + * datagram packets | |
| 183 | + * @throws IllegalArgumentException if mcastaddr is null or is a | |
| 184 | + * SocketAddress subclass not supported by this socket | |
| 185 | + * @since 1.4 | |
| 186 | + */ | |
| 187 | + | |
| 188 | + protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) | |
| 189 | + throws IOException { | |
| 190 | + if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) | |
| 191 | + throw new IllegalArgumentException("Unsupported address type"); | |
| 192 | + join(((InetSocketAddress)mcastaddr).getAddress(), netIf); | |
| 193 | + } | |
| 194 | + | |
| 195 | + protected abstract void join(InetAddress inetaddr, NetworkInterface netIf) | |
| 196 | + throws IOException; | |
| 197 | + | |
| 198 | + /** | |
| 199 | + * Leave the multicast group. | |
| 200 | + * @param multicast address to leave. | |
| 201 | + * @param netIf specified the local interface to leave the group at | |
| 202 | + * @throws IllegalArgumentException if mcastaddr is null or is a | |
| 203 | + * SocketAddress subclass not supported by this socket | |
| 204 | + * @since 1.4 | |
| 205 | + */ | |
| 206 | + protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) | |
| 207 | + throws IOException { | |
| 208 | + if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) | |
| 209 | + throw new IllegalArgumentException("Unsupported address type"); | |
| 210 | + leave(((InetSocketAddress)mcastaddr).getAddress(), netIf); | |
| 211 | + } | |
| 212 | + | |
| 213 | + protected abstract void leave(InetAddress inetaddr, NetworkInterface netIf) | |
| 214 | + throws IOException; | |
| 215 | + | |
| 216 | + /** | |
| 217 | + * Close the socket. | |
| 218 | + */ | |
| 219 | + protected void close() { | |
| 220 | + if (fd != null) { | |
| 221 | + datagramSocketClose(); | |
| 222 | + ResourceManager.afterUdpClose(); | |
| 223 | + fd = null; | |
| 224 | + } | |
| 225 | + } | |
| 226 | + | |
| 227 | + protected boolean isClosed() { | |
| 228 | + return (fd == null) ? true : false; | |
| 229 | + } | |
| 230 | + | |
| 231 | + protected void finalize() { | |
| 232 | + close(); | |
| 233 | + } | |
| 234 | + | |
| 235 | + /** | |
| 236 | + * set a value - since we only support (setting) binary options | |
| 237 | + * here, o must be a Boolean | |
| 238 | + */ | |
| 239 | + | |
| 240 | + public void setOption(int optID, Object o) throws SocketException { | |
| 241 | + if (isClosed()) { | |
| 242 | + throw new SocketException("Socket Closed"); | |
| 243 | + } | |
| 244 | + switch (optID) { | |
| 245 | + /* check type safety b4 going native. These should never | |
| 246 | + * fail, since only java.Socket* has access to | |
| 247 | + * PlainSocketImpl.setOption(). | |
| 248 | + */ | |
| 249 | + case SO_TIMEOUT: | |
| 250 | + if (o == null || !(o instanceof Integer)) { | |
| 251 | + throw new SocketException("bad argument for SO_TIMEOUT"); | |
| 252 | + } | |
| 253 | + int tmp = ((Integer) o).intValue(); | |
| 254 | + if (tmp < 0) | |
| 255 | + throw new IllegalArgumentException("timeout < 0"); | |
| 256 | + timeout = tmp; | |
| 257 | + return; | |
| 258 | + case IP_TOS: | |
| 259 | + if (o == null || !(o instanceof Integer)) { | |
| 260 | + throw new SocketException("bad argument for IP_TOS"); | |
| 261 | + } | |
| 262 | + trafficClass = ((Integer)o).intValue(); | |
| 263 | + break; | |
| 264 | + case SO_REUSEADDR: | |
| 265 | + if (o == null || !(o instanceof Boolean)) { | |
| 266 | + throw new SocketException("bad argument for SO_REUSEADDR"); | |
| 267 | + } | |
| 268 | + break; | |
| 269 | + case SO_BROADCAST: | |
| 270 | + if (o == null || !(o instanceof Boolean)) { | |
| 271 | + throw new SocketException("bad argument for SO_BROADCAST"); | |
| 272 | + } | |
| 273 | + break; | |
| 274 | + case SO_BINDADDR: | |
| 275 | + throw new SocketException("Cannot re-bind Socket"); | |
| 276 | + case SO_RCVBUF: | |
| 277 | + case SO_SNDBUF: | |
| 278 | + if (o == null || !(o instanceof Integer) || | |
| 279 | + ((Integer)o).intValue() < 0) { | |
| 280 | + throw new SocketException("bad argument for SO_SNDBUF or " + | |
| 281 | + "SO_RCVBUF"); | |
| 282 | + } | |
| 283 | + break; | |
| 284 | + case IP_MULTICAST_IF: | |
| 285 | + if (o == null || !(o instanceof InetAddress)) | |
| 286 | + throw new SocketException("bad argument for IP_MULTICAST_IF"); | |
| 287 | + break; | |
| 288 | + case IP_MULTICAST_IF2: | |
| 289 | + if (o == null || !(o instanceof NetworkInterface)) | |
| 290 | + throw new SocketException("bad argument for IP_MULTICAST_IF2"); | |
| 291 | + break; | |
| 292 | + case IP_MULTICAST_LOOP: | |
| 293 | + if (o == null || !(o instanceof Boolean)) | |
| 294 | + throw new SocketException("bad argument for IP_MULTICAST_LOOP"); | |
| 295 | + break; | |
| 296 | + default: | |
| 297 | + throw new SocketException("invalid option: " + optID); | |
| 298 | + } | |
| 299 | + socketSetOption(optID, o); | |
| 300 | + } | |
| 301 | + | |
| 302 | + /* | |
| 303 | + * get option's state - set or not | |
| 304 | + */ | |
| 305 | + | |
| 306 | + public Object getOption(int optID) throws SocketException { | |
| 307 | + if (isClosed()) { | |
| 308 | + throw new SocketException("Socket Closed"); | |
| 309 | + } | |
| 310 | + | |
| 311 | + Object result; | |
| 312 | + | |
| 313 | + switch (optID) { | |
| 314 | + case SO_TIMEOUT: | |
| 315 | + result = new Integer(timeout); | |
| 316 | + break; | |
| 317 | + | |
| 318 | + case IP_TOS: | |
| 319 | + result = socketGetOption(optID); | |
| 320 | + if ( ((Integer)result).intValue() == -1) { | |
| 321 | + result = new Integer(trafficClass); | |
| 322 | + } | |
| 323 | + break; | |
| 324 | + | |
| 325 | + case SO_BINDADDR: | |
| 326 | + case IP_MULTICAST_IF: | |
| 327 | + case IP_MULTICAST_IF2: | |
| 328 | + case SO_RCVBUF: | |
| 329 | + case SO_SNDBUF: | |
| 330 | + case IP_MULTICAST_LOOP: | |
| 331 | + case SO_REUSEADDR: | |
| 332 | + case SO_BROADCAST: | |
| 333 | + result = socketGetOption(optID); | |
| 334 | + break; | |
| 335 | + | |
| 336 | + default: | |
| 337 | + throw new SocketException("invalid option: " + optID); | |
| 338 | + } | |
| 339 | + | |
| 340 | + return result; | |
| 341 | + } | |
| 342 | + | |
| 343 | + protected abstract void datagramSocketCreate() throws SocketException; | |
| 344 | + protected abstract void datagramSocketClose(); | |
| 345 | + protected abstract void socketSetOption(int opt, Object val) | |
| 346 | + throws SocketException; | |
| 347 | + protected abstract Object socketGetOption(int opt) throws SocketException; | |
| 348 | + | |
| 349 | + protected abstract void connect0(InetAddress address, int port) throws SocketException; | |
| 350 | + protected abstract void disconnect0(int family); | |
| 351 | + | |
| 352 | +} | |
Binary file not shown.
| @@ -0,0 +1,716 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2011, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.io.InputStream; | |
| 30 | +import java.io.OutputStream; | |
| 31 | +import java.io.FileDescriptor; | |
| 32 | + | |
| 33 | +import sun.net.ConnectionResetException; | |
| 34 | +import sun.net.NetHooks; | |
| 35 | +import sun.net.ResourceManager; | |
| 36 | + | |
| 37 | +/** | |
| 38 | + * Default Socket Implementation. This implementation does | |
| 39 | + * not implement any security checks. | |
| 40 | + * Note this class should <b>NOT</b> be public. | |
| 41 | + * | |
| 42 | + * @author Steven B. Byrne | |
| 43 | + */ | |
| 44 | +abstract class AbstractPlainSocketImpl extends SocketImpl | |
| 45 | +{ | |
| 46 | + /* instance variable for SO_TIMEOUT */ | |
| 47 | + int timeout; // timeout in millisec | |
| 48 | + // traffic class | |
| 49 | + private int trafficClass; | |
| 50 | + | |
| 51 | + private boolean shut_rd = false; | |
| 52 | + private boolean shut_wr = false; | |
| 53 | + | |
| 54 | + private SocketInputStream socketInputStream = null; | |
| 55 | + | |
| 56 | + /* number of threads using the FileDescriptor */ | |
| 57 | + protected int fdUseCount = 0; | |
| 58 | + | |
| 59 | + /* lock when increment/decrementing fdUseCount */ | |
| 60 | + protected final Object fdLock = new Object(); | |
| 61 | + | |
| 62 | + /* indicates a close is pending on the file descriptor */ | |
| 63 | + protected boolean closePending = false; | |
| 64 | + | |
| 65 | + /* indicates connection reset state */ | |
| 66 | + private int CONNECTION_NOT_RESET = 0; | |
| 67 | + private int CONNECTION_RESET_PENDING = 1; | |
| 68 | + private int CONNECTION_RESET = 2; | |
| 69 | + private int resetState; | |
| 70 | + private final Object resetLock = new Object(); | |
| 71 | + | |
| 72 | + /* whether this Socket is a stream (TCP) socket or not (UDP) | |
| 73 | + */ | |
| 74 | + private boolean stream; | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * Load net library into runtime. | |
| 78 | + */ | |
| 79 | + static { | |
| 80 | + java.security.AccessController.doPrivileged( | |
| 81 | + new sun.security.action.LoadLibraryAction("net")); | |
| 82 | + } | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * Creates a socket with a boolean that specifies whether this | |
| 86 | + * is a stream socket (true) or an unconnected UDP socket (false). | |
| 87 | + */ | |
| 88 | + protected synchronized void create(boolean stream) throws IOException { | |
| 89 | + fd = new FileDescriptor(); | |
| 90 | + this.stream = stream; | |
| 91 | + if (!stream) { | |
| 92 | + ResourceManager.beforeUdpCreate(); | |
| 93 | + try { | |
| 94 | + socketCreate(false); | |
| 95 | + } catch (IOException ioe) { | |
| 96 | + ResourceManager.afterUdpClose(); | |
| 97 | + fd = null; | |
| 98 | + throw ioe; | |
| 99 | + } | |
| 100 | + } else { | |
| 101 | + socketCreate(true); | |
| 102 | + } | |
| 103 | + if (socket != null) | |
| 104 | + socket.setCreated(); | |
| 105 | + if (serverSocket != null) | |
| 106 | + serverSocket.setCreated(); | |
| 107 | + } | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * Creates a socket and connects it to the specified port on | |
| 111 | + * the specified host. | |
| 112 | + * @param host the specified host | |
| 113 | + * @param port the specified port | |
| 114 | + */ | |
| 115 | + protected void connect(String host, int port) | |
| 116 | + throws UnknownHostException, IOException | |
| 117 | + { | |
| 118 | + boolean connected = false; | |
| 119 | + try { | |
| 120 | + InetAddress address = InetAddress.getByName(host); | |
| 121 | + this.port = port; | |
| 122 | + this.address = address; | |
| 123 | + | |
| 124 | + connectToAddress(address, port, timeout); | |
| 125 | + connected = true; | |
| 126 | + } finally { | |
| 127 | + if (!connected) { | |
| 128 | + try { | |
| 129 | + close(); | |
| 130 | + } catch (IOException ioe) { | |
| 131 | + /* Do nothing. If connect threw an exception then | |
| 132 | + it will be passed up the call stack */ | |
| 133 | + } | |
| 134 | + } | |
| 135 | + } | |
| 136 | + } | |
| 137 | + | |
| 138 | + /** | |
| 139 | + * Creates a socket and connects it to the specified address on | |
| 140 | + * the specified port. | |
| 141 | + * @param address the address | |
| 142 | + * @param port the specified port | |
| 143 | + */ | |
| 144 | + protected void connect(InetAddress address, int port) throws IOException { | |
| 145 | + this.port = port; | |
| 146 | + this.address = address; | |
| 147 | + | |
| 148 | + try { | |
| 149 | + connectToAddress(address, port, timeout); | |
| 150 | + return; | |
| 151 | + } catch (IOException e) { | |
| 152 | + // everything failed | |
| 153 | + close(); | |
| 154 | + throw e; | |
| 155 | + } | |
| 156 | + } | |
| 157 | + | |
| 158 | + /** | |
| 159 | + * Creates a socket and connects it to the specified address on | |
| 160 | + * the specified port. | |
| 161 | + * @param address the address | |
| 162 | + * @param timeout the timeout value in milliseconds, or zero for no timeout. | |
| 163 | + * @throws IOException if connection fails | |
| 164 | + * @throws IllegalArgumentException if address is null or is a | |
| 165 | + * SocketAddress subclass not supported by this socket | |
| 166 | + * @since 1.4 | |
| 167 | + */ | |
| 168 | + protected void connect(SocketAddress address, int timeout) | |
| 169 | + throws IOException { | |
| 170 | + boolean connected = false; | |
| 171 | + try { | |
| 172 | + if (address == null || !(address instanceof InetSocketAddress)) | |
| 173 | + throw new IllegalArgumentException("unsupported address type"); | |
| 174 | + InetSocketAddress addr = (InetSocketAddress) address; | |
| 175 | + if (addr.isUnresolved()) | |
| 176 | + throw new UnknownHostException(addr.getHostName()); | |
| 177 | + this.port = addr.getPort(); | |
| 178 | + this.address = addr.getAddress(); | |
| 179 | + | |
| 180 | + connectToAddress(this.address, port, timeout); | |
| 181 | + connected = true; | |
| 182 | + } finally { | |
| 183 | + if (!connected) { | |
| 184 | + try { | |
| 185 | + close(); | |
| 186 | + } catch (IOException ioe) { | |
| 187 | + /* Do nothing. If connect threw an exception then | |
| 188 | + it will be passed up the call stack */ | |
| 189 | + } | |
| 190 | + } | |
| 191 | + } | |
| 192 | + } | |
| 193 | + | |
| 194 | + private void connectToAddress(InetAddress address, int port, int timeout) throws IOException { | |
| 195 | + if (address.isAnyLocalAddress()) { | |
| 196 | + doConnect(InetAddress.getLocalHost(), port, timeout); | |
| 197 | + } else { | |
| 198 | + doConnect(address, port, timeout); | |
| 199 | + } | |
| 200 | + } | |
| 201 | + | |
| 202 | + public void setOption(int opt, Object val) throws SocketException { | |
| 203 | + if (isClosedOrPending()) { | |
| 204 | + throw new SocketException("Socket Closed"); | |
| 205 | + } | |
| 206 | + boolean on = true; | |
| 207 | + switch (opt) { | |
| 208 | + /* check type safety b4 going native. These should never | |
| 209 | + * fail, since only java.Socket* has access to | |
| 210 | + * PlainSocketImpl.setOption(). | |
| 211 | + */ | |
| 212 | + case SO_LINGER: | |
| 213 | + if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean))) | |
| 214 | + throw new SocketException("Bad parameter for option"); | |
| 215 | + if (val instanceof Boolean) { | |
| 216 | + /* true only if disabling - enabling should be Integer */ | |
| 217 | + on = false; | |
| 218 | + } | |
| 219 | + break; | |
| 220 | + case SO_TIMEOUT: | |
| 221 | + if (val == null || (!(val instanceof Integer))) | |
| 222 | + throw new SocketException("Bad parameter for SO_TIMEOUT"); | |
| 223 | + int tmp = ((Integer) val).intValue(); | |
| 224 | + if (tmp < 0) | |
| 225 | + throw new IllegalArgumentException("timeout < 0"); | |
| 226 | + timeout = tmp; | |
| 227 | + break; | |
| 228 | + case IP_TOS: | |
| 229 | + if (val == null || !(val instanceof Integer)) { | |
| 230 | + throw new SocketException("bad argument for IP_TOS"); | |
| 231 | + } | |
| 232 | + trafficClass = ((Integer)val).intValue(); | |
| 233 | + break; | |
| 234 | + case SO_BINDADDR: | |
| 235 | + throw new SocketException("Cannot re-bind socket"); | |
| 236 | + case TCP_NODELAY: | |
| 237 | + if (val == null || !(val instanceof Boolean)) | |
| 238 | + throw new SocketException("bad parameter for TCP_NODELAY"); | |
| 239 | + on = ((Boolean)val).booleanValue(); | |
| 240 | + break; | |
| 241 | + case SO_SNDBUF: | |
| 242 | + case SO_RCVBUF: | |
| 243 | + if (val == null || !(val instanceof Integer) || | |
| 244 | + !(((Integer)val).intValue() > 0)) { | |
| 245 | + throw new SocketException("bad parameter for SO_SNDBUF " + | |
| 246 | + "or SO_RCVBUF"); | |
| 247 | + } | |
| 248 | + break; | |
| 249 | + case SO_KEEPALIVE: | |
| 250 | + if (val == null || !(val instanceof Boolean)) | |
| 251 | + throw new SocketException("bad parameter for SO_KEEPALIVE"); | |
| 252 | + on = ((Boolean)val).booleanValue(); | |
| 253 | + break; | |
| 254 | + case SO_OOBINLINE: | |
| 255 | + if (val == null || !(val instanceof Boolean)) | |
| 256 | + throw new SocketException("bad parameter for SO_OOBINLINE"); | |
| 257 | + on = ((Boolean)val).booleanValue(); | |
| 258 | + break; | |
| 259 | + case SO_REUSEADDR: | |
| 260 | + if (val == null || !(val instanceof Boolean)) | |
| 261 | + throw new SocketException("bad parameter for SO_REUSEADDR"); | |
| 262 | + on = ((Boolean)val).booleanValue(); | |
| 263 | + break; | |
| 264 | + default: | |
| 265 | + throw new SocketException("unrecognized TCP option: " + opt); | |
| 266 | + } | |
| 267 | + socketSetOption(opt, on, val); | |
| 268 | + } | |
| 269 | + public Object getOption(int opt) throws SocketException { | |
| 270 | + if (isClosedOrPending()) { | |
| 271 | + throw new SocketException("Socket Closed"); | |
| 272 | + } | |
| 273 | + if (opt == SO_TIMEOUT) { | |
| 274 | + return new Integer(timeout); | |
| 275 | + } | |
| 276 | + int ret = 0; | |
| 277 | + /* | |
| 278 | + * The native socketGetOption() knows about 3 options. | |
| 279 | + * The 32 bit value it returns will be interpreted according | |
| 280 | + * to what we're asking. A return of -1 means it understands | |
| 281 | + * the option but its turned off. It will raise a SocketException | |
| 282 | + * if "opt" isn't one it understands. | |
| 283 | + */ | |
| 284 | + | |
| 285 | + switch (opt) { | |
| 286 | + case TCP_NODELAY: | |
| 287 | + ret = socketGetOption(opt, null); | |
| 288 | + return Boolean.valueOf(ret != -1); | |
| 289 | + case SO_OOBINLINE: | |
| 290 | + ret = socketGetOption(opt, null); | |
| 291 | + return Boolean.valueOf(ret != -1); | |
| 292 | + case SO_LINGER: | |
| 293 | + ret = socketGetOption(opt, null); | |
| 294 | + return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret)); | |
| 295 | + case SO_REUSEADDR: | |
| 296 | + ret = socketGetOption(opt, null); | |
| 297 | + return Boolean.valueOf(ret != -1); | |
| 298 | + case SO_BINDADDR: | |
| 299 | + InetAddressContainer in = new InetAddressContainer(); | |
| 300 | + ret = socketGetOption(opt, in); | |
| 301 | + return in.addr; | |
| 302 | + case SO_SNDBUF: | |
| 303 | + case SO_RCVBUF: | |
| 304 | + ret = socketGetOption(opt, null); | |
| 305 | + return new Integer(ret); | |
| 306 | + case IP_TOS: | |
| 307 | + ret = socketGetOption(opt, null); | |
| 308 | + if (ret == -1) { // ipv6 tos | |
| 309 | + return new Integer(trafficClass); | |
| 310 | + } else { | |
| 311 | + return new Integer(ret); | |
| 312 | + } | |
| 313 | + case SO_KEEPALIVE: | |
| 314 | + ret = socketGetOption(opt, null); | |
| 315 | + return Boolean.valueOf(ret != -1); | |
| 316 | + // should never get here | |
| 317 | + default: | |
| 318 | + return null; | |
| 319 | + } | |
| 320 | + } | |
| 321 | + | |
| 322 | + /** | |
| 323 | + * The workhorse of the connection operation. Tries several times to | |
| 324 | + * establish a connection to the given <host, port>. If unsuccessful, | |
| 325 | + * throws an IOException indicating what went wrong. | |
| 326 | + */ | |
| 327 | + | |
| 328 | + synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException { | |
| 329 | + synchronized (fdLock) { | |
| 330 | + if (!closePending && (socket == null || !socket.isBound())) { | |
| 331 | + NetHooks.beforeTcpConnect(fd, address, port); | |
| 332 | + } | |
| 333 | + } | |
| 334 | + try { | |
| 335 | + acquireFD(); | |
| 336 | + try { | |
| 337 | + socketConnect(address, port, timeout); | |
| 338 | + /* socket may have been closed during poll/select */ | |
| 339 | + synchronized (fdLock) { | |
| 340 | + if (closePending) { | |
| 341 | + throw new SocketException ("Socket closed"); | |
| 342 | + } | |
| 343 | + } | |
| 344 | + // If we have a ref. to the Socket, then sets the flags | |
| 345 | + // created, bound & connected to true. | |
| 346 | + // This is normally done in Socket.connect() but some | |
| 347 | + // subclasses of Socket may call impl.connect() directly! | |
| 348 | + if (socket != null) { | |
| 349 | + socket.setBound(); | |
| 350 | + socket.setConnected(); | |
| 351 | + } | |
| 352 | + } finally { | |
| 353 | + releaseFD(); | |
| 354 | + } | |
| 355 | + } catch (IOException e) { | |
| 356 | + close(); | |
| 357 | + throw e; | |
| 358 | + } | |
| 359 | + } | |
| 360 | + | |
| 361 | + /** | |
| 362 | + * Binds the socket to the specified address of the specified local port. | |
| 363 | + * @param address the address | |
| 364 | + * @param port the port | |
| 365 | + */ | |
| 366 | + protected synchronized void bind(InetAddress address, int lport) | |
| 367 | + throws IOException | |
| 368 | + { | |
| 369 | + synchronized (fdLock) { | |
| 370 | + if (!closePending && (socket == null || !socket.isBound())) { | |
| 371 | + NetHooks.beforeTcpBind(fd, address, lport); | |
| 372 | + } | |
| 373 | + } | |
| 374 | + socketBind(address, lport); | |
| 375 | + if (socket != null) | |
| 376 | + socket.setBound(); | |
| 377 | + if (serverSocket != null) | |
| 378 | + serverSocket.setBound(); | |
| 379 | + } | |
| 380 | + | |
| 381 | + /** | |
| 382 | + * Listens, for a specified amount of time, for connections. | |
| 383 | + * @param count the amount of time to listen for connections | |
| 384 | + */ | |
| 385 | + protected synchronized void listen(int count) throws IOException { | |
| 386 | + socketListen(count); | |
| 387 | + } | |
| 388 | + | |
| 389 | + /** | |
| 390 | + * Accepts connections. | |
| 391 | + * @param s the connection | |
| 392 | + */ | |
| 393 | + protected void accept(SocketImpl s) throws IOException { | |
| 394 | + acquireFD(); | |
| 395 | + try { | |
| 396 | + socketAccept(s); | |
| 397 | + } finally { | |
| 398 | + releaseFD(); | |
| 399 | + } | |
| 400 | + } | |
| 401 | + | |
| 402 | + /** | |
| 403 | + * Gets an InputStream for this socket. | |
| 404 | + */ | |
| 405 | + protected synchronized InputStream getInputStream() throws IOException { | |
| 406 | + if (isClosedOrPending()) { | |
| 407 | + throw new IOException("Socket Closed"); | |
| 408 | + } | |
| 409 | + if (shut_rd) { | |
| 410 | + throw new IOException("Socket input is shutdown"); | |
| 411 | + } | |
| 412 | + if (socketInputStream == null) { | |
| 413 | + socketInputStream = new SocketInputStream(this); | |
| 414 | + } | |
| 415 | + return socketInputStream; | |
| 416 | + } | |
| 417 | + | |
| 418 | + void setInputStream(SocketInputStream in) { | |
| 419 | + socketInputStream = in; | |
| 420 | + } | |
| 421 | + | |
| 422 | + /** | |
| 423 | + * Gets an OutputStream for this socket. | |
| 424 | + */ | |
| 425 | + protected synchronized OutputStream getOutputStream() throws IOException { | |
| 426 | + if (isClosedOrPending()) { | |
| 427 | + throw new IOException("Socket Closed"); | |
| 428 | + } | |
| 429 | + if (shut_wr) { | |
| 430 | + throw new IOException("Socket output is shutdown"); | |
| 431 | + } | |
| 432 | + return new SocketOutputStream(this); | |
| 433 | + } | |
| 434 | + | |
| 435 | + void setFileDescriptor(FileDescriptor fd) { | |
| 436 | + this.fd = fd; | |
| 437 | + } | |
| 438 | + | |
| 439 | + void setAddress(InetAddress address) { | |
| 440 | + this.address = address; | |
| 441 | + } | |
| 442 | + | |
| 443 | + void setPort(int port) { | |
| 444 | + this.port = port; | |
| 445 | + } | |
| 446 | + | |
| 447 | + void setLocalPort(int localport) { | |
| 448 | + this.localport = localport; | |
| 449 | + } | |
| 450 | + | |
| 451 | + /** | |
| 452 | + * Returns the number of bytes that can be read without blocking. | |
| 453 | + */ | |
| 454 | + protected synchronized int available() throws IOException { | |
| 455 | + if (isClosedOrPending()) { | |
| 456 | + throw new IOException("Stream closed."); | |
| 457 | + } | |
| 458 | + | |
| 459 | + /* | |
| 460 | + * If connection has been reset then return 0 to indicate | |
| 461 | + * there are no buffered bytes. | |
| 462 | + */ | |
| 463 | + if (isConnectionReset()) { | |
| 464 | + return 0; | |
| 465 | + } | |
| 466 | + | |
| 467 | + /* | |
| 468 | + * If no bytes available and we were previously notified | |
| 469 | + * of a connection reset then we move to the reset state. | |
| 470 | + * | |
| 471 | + * If are notified of a connection reset then check | |
| 472 | + * again if there are bytes buffered on the socket. | |
| 473 | + */ | |
| 474 | + int n = 0; | |
| 475 | + try { | |
| 476 | + n = socketAvailable(); | |
| 477 | + if (n == 0 && isConnectionResetPending()) { | |
| 478 | + setConnectionReset(); | |
| 479 | + } | |
| 480 | + } catch (ConnectionResetException exc1) { | |
| 481 | + setConnectionResetPending(); | |
| 482 | + try { | |
| 483 | + n = socketAvailable(); | |
| 484 | + if (n == 0) { | |
| 485 | + setConnectionReset(); | |
| 486 | + } | |
| 487 | + } catch (ConnectionResetException exc2) { | |
| 488 | + } | |
| 489 | + } | |
| 490 | + return n; | |
| 491 | + } | |
| 492 | + | |
| 493 | + /** | |
| 494 | + * Closes the socket. | |
| 495 | + */ | |
| 496 | + protected void close() throws IOException { | |
| 497 | + synchronized(fdLock) { | |
| 498 | + if (fd != null) { | |
| 499 | + if (!stream) { | |
| 500 | + ResourceManager.afterUdpClose(); | |
| 501 | + } | |
| 502 | + if (fdUseCount == 0) { | |
| 503 | + if (closePending) { | |
| 504 | + return; | |
| 505 | + } | |
| 506 | + closePending = true; | |
| 507 | + /* | |
| 508 | + * We close the FileDescriptor in two-steps - first the | |
| 509 | + * "pre-close" which closes the socket but doesn't | |
| 510 | + * release the underlying file descriptor. This operation | |
| 511 | + * may be lengthy due to untransmitted data and a long | |
| 512 | + * linger interval. Once the pre-close is done we do the | |
| 513 | + * actual socket to release the fd. | |
| 514 | + */ | |
| 515 | + try { | |
| 516 | + socketPreClose(); | |
| 517 | + } finally { | |
| 518 | + socketClose(); | |
| 519 | + } | |
| 520 | + fd = null; | |
| 521 | + return; | |
| 522 | + } else { | |
| 523 | + /* | |
| 524 | + * If a thread has acquired the fd and a close | |
| 525 | + * isn't pending then use a deferred close. | |
| 526 | + * Also decrement fdUseCount to signal the last | |
| 527 | + * thread that releases the fd to close it. | |
| 528 | + */ | |
| 529 | + if (!closePending) { | |
| 530 | + closePending = true; | |
| 531 | + fdUseCount--; | |
| 532 | + socketPreClose(); | |
| 533 | + } | |
| 534 | + } | |
| 535 | + } | |
| 536 | + } | |
| 537 | + } | |
| 538 | + | |
| 539 | + void reset() throws IOException { | |
| 540 | + if (fd != null) { | |
| 541 | + socketClose(); | |
| 542 | + } | |
| 543 | + fd = null; | |
| 544 | + super.reset(); | |
| 545 | + } | |
| 546 | + | |
| 547 | + | |
| 548 | + /** | |
| 549 | + * Shutdown read-half of the socket connection; | |
| 550 | + */ | |
| 551 | + protected void shutdownInput() throws IOException { | |
| 552 | + if (fd != null) { | |
| 553 | + socketShutdown(SHUT_RD); | |
| 554 | + if (socketInputStream != null) { | |
| 555 | + socketInputStream.setEOF(true); | |
| 556 | + } | |
| 557 | + shut_rd = true; | |
| 558 | + } | |
| 559 | + } | |
| 560 | + | |
| 561 | + /** | |
| 562 | + * Shutdown write-half of the socket connection; | |
| 563 | + */ | |
| 564 | + protected void shutdownOutput() throws IOException { | |
| 565 | + if (fd != null) { | |
| 566 | + socketShutdown(SHUT_WR); | |
| 567 | + shut_wr = true; | |
| 568 | + } | |
| 569 | + } | |
| 570 | + | |
| 571 | + protected boolean supportsUrgentData () { | |
| 572 | + return true; | |
| 573 | + } | |
| 574 | + | |
| 575 | + protected void sendUrgentData (int data) throws IOException { | |
| 576 | + if (fd == null) { | |
| 577 | + throw new IOException("Socket Closed"); | |
| 578 | + } | |
| 579 | + socketSendUrgentData (data); | |
| 580 | + } | |
| 581 | + | |
| 582 | + /** | |
| 583 | + * Cleans up if the user forgets to close it. | |
| 584 | + */ | |
| 585 | + protected void finalize() throws IOException { | |
| 586 | + close(); | |
| 587 | + } | |
| 588 | + | |
| 589 | + /* | |
| 590 | + * "Acquires" and returns the FileDescriptor for this impl | |
| 591 | + * | |
| 592 | + * A corresponding releaseFD is required to "release" the | |
| 593 | + * FileDescriptor. | |
| 594 | + */ | |
| 595 | + FileDescriptor acquireFD() { | |
| 596 | + synchronized (fdLock) { | |
| 597 | + fdUseCount++; | |
| 598 | + return fd; | |
| 599 | + } | |
| 600 | + } | |
| 601 | + | |
| 602 | + /* | |
| 603 | + * "Release" the FileDescriptor for this impl. | |
| 604 | + * | |
| 605 | + * If the use count goes to -1 then the socket is closed. | |
| 606 | + */ | |
| 607 | + void releaseFD() { | |
| 608 | + synchronized (fdLock) { | |
| 609 | + fdUseCount--; | |
| 610 | + if (fdUseCount == -1) { | |
| 611 | + if (fd != null) { | |
| 612 | + try { | |
| 613 | + socketClose(); | |
| 614 | + } catch (IOException e) { | |
| 615 | + } finally { | |
| 616 | + fd = null; | |
| 617 | + } | |
| 618 | + } | |
| 619 | + } | |
| 620 | + } | |
| 621 | + } | |
| 622 | + | |
| 623 | + public boolean isConnectionReset() { | |
| 624 | + synchronized (resetLock) { | |
| 625 | + return (resetState == CONNECTION_RESET); | |
| 626 | + } | |
| 627 | + } | |
| 628 | + | |
| 629 | + public boolean isConnectionResetPending() { | |
| 630 | + synchronized (resetLock) { | |
| 631 | + return (resetState == CONNECTION_RESET_PENDING); | |
| 632 | + } | |
| 633 | + } | |
| 634 | + | |
| 635 | + public void setConnectionReset() { | |
| 636 | + synchronized (resetLock) { | |
| 637 | + resetState = CONNECTION_RESET; | |
| 638 | + } | |
| 639 | + } | |
| 640 | + | |
| 641 | + public void setConnectionResetPending() { | |
| 642 | + synchronized (resetLock) { | |
| 643 | + if (resetState == CONNECTION_NOT_RESET) { | |
| 644 | + resetState = CONNECTION_RESET_PENDING; | |
| 645 | + } | |
| 646 | + } | |
| 647 | + | |
| 648 | + } | |
| 649 | + | |
| 650 | + /* | |
| 651 | + * Return true if already closed or close is pending | |
| 652 | + */ | |
| 653 | + public boolean isClosedOrPending() { | |
| 654 | + /* | |
| 655 | + * Lock on fdLock to ensure that we wait if a | |
| 656 | + * close is in progress. | |
| 657 | + */ | |
| 658 | + synchronized (fdLock) { | |
| 659 | + if (closePending || (fd == null)) { | |
| 660 | + return true; | |
| 661 | + } else { | |
| 662 | + return false; | |
| 663 | + } | |
| 664 | + } | |
| 665 | + } | |
| 666 | + | |
| 667 | + /* | |
| 668 | + * Return the current value of SO_TIMEOUT | |
| 669 | + */ | |
| 670 | + public int getTimeout() { | |
| 671 | + return timeout; | |
| 672 | + } | |
| 673 | + | |
| 674 | + /* | |
| 675 | + * "Pre-close" a socket by dup'ing the file descriptor - this enables | |
| 676 | + * the socket to be closed without releasing the file descriptor. | |
| 677 | + */ | |
| 678 | + private void socketPreClose() throws IOException { | |
| 679 | + socketClose0(true); | |
| 680 | + } | |
| 681 | + | |
| 682 | + /* | |
| 683 | + * Close the socket (and release the file descriptor). | |
| 684 | + */ | |
| 685 | + protected void socketClose() throws IOException { | |
| 686 | + socketClose0(false); | |
| 687 | + } | |
| 688 | + | |
| 689 | + abstract void socketCreate(boolean isServer) throws IOException; | |
| 690 | + abstract void socketConnect(InetAddress address, int port, int timeout) | |
| 691 | + throws IOException; | |
| 692 | + abstract void socketBind(InetAddress address, int port) | |
| 693 | + throws IOException; | |
| 694 | + abstract void socketListen(int count) | |
| 695 | + throws IOException; | |
| 696 | + abstract void socketAccept(SocketImpl s) | |
| 697 | + throws IOException; | |
| 698 | + abstract int socketAvailable() | |
| 699 | + throws IOException; | |
| 700 | + abstract void socketClose0(boolean useDeferredClose) | |
| 701 | + throws IOException; | |
| 702 | + abstract void socketShutdown(int howto) | |
| 703 | + throws IOException; | |
| 704 | + abstract void socketSetOption(int cmd, boolean on, Object value) | |
| 705 | + throws SocketException; | |
| 706 | + abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException; | |
| 707 | + abstract void socketSendUrgentData(int data) | |
| 708 | + throws IOException; | |
| 709 | + | |
| 710 | + public final static int SHUT_RD = 0; | |
| 711 | + public final static int SHUT_WR = 1; | |
| 712 | +} | |
| 713 | + | |
| 714 | +class InetAddressContainer { | |
| 715 | + InetAddress addr; | |
| 716 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,425 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2004, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * The class Authenticator represents an object that knows how to obtain | |
| 30 | + * authentication for a network connection. Usually, it will do this | |
| 31 | + * by prompting the user for information. | |
| 32 | + * <p> | |
| 33 | + * Applications use this class by overriding {@link | |
| 34 | + * #getPasswordAuthentication()} in a sub-class. This method will | |
| 35 | + * typically use the various getXXX() accessor methods to get information | |
| 36 | + * about the entity requesting authentication. It must then acquire a | |
| 37 | + * username and password either by interacting with the user or through | |
| 38 | + * some other non-interactive means. The credentials are then returned | |
| 39 | + * as a {@link PasswordAuthentication} return value. | |
| 40 | + * <p> | |
| 41 | + * An instance of this concrete sub-class is then registered | |
| 42 | + * with the system by calling {@link #setDefault(Authenticator)}. | |
| 43 | + * When authentication is required, the system will invoke one of the | |
| 44 | + * requestPasswordAuthentication() methods which in turn will call the | |
| 45 | + * getPasswordAuthentication() method of the registered object. | |
| 46 | + * <p> | |
| 47 | + * All methods that request authentication have a default implementation | |
| 48 | + * that fails. | |
| 49 | + * | |
| 50 | + * @see java.net.Authenticator#setDefault(java.net.Authenticator) | |
| 51 | + * @see java.net.Authenticator#getPasswordAuthentication() | |
| 52 | + * | |
| 53 | + * @author Bill Foote | |
| 54 | + * @since 1.2 | |
| 55 | + */ | |
| 56 | + | |
| 57 | +// There are no abstract methods, but to be useful the user must | |
| 58 | +// subclass. | |
| 59 | +public abstract | |
| 60 | +class Authenticator { | |
| 61 | + | |
| 62 | + // The system-wide authenticator object. See setDefault(). | |
| 63 | + private static Authenticator theAuthenticator; | |
| 64 | + | |
| 65 | + private String requestingHost; | |
| 66 | + private InetAddress requestingSite; | |
| 67 | + private int requestingPort; | |
| 68 | + private String requestingProtocol; | |
| 69 | + private String requestingPrompt; | |
| 70 | + private String requestingScheme; | |
| 71 | + private URL requestingURL; | |
| 72 | + private RequestorType requestingAuthType; | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * The type of the entity requesting authentication. | |
| 76 | + * | |
| 77 | + * @since 1.5 | |
| 78 | + */ | |
| 79 | + public enum RequestorType { | |
| 80 | + /** | |
| 81 | + * Entity requesting authentication is a HTTP proxy server. | |
| 82 | + */ | |
| 83 | + PROXY, | |
| 84 | + /** | |
| 85 | + * Entity requesting authentication is a HTTP origin server. | |
| 86 | + */ | |
| 87 | + SERVER | |
| 88 | + } | |
| 89 | + | |
| 90 | + private void reset() { | |
| 91 | + requestingHost = null; | |
| 92 | + requestingSite = null; | |
| 93 | + requestingPort = -1; | |
| 94 | + requestingProtocol = null; | |
| 95 | + requestingPrompt = null; | |
| 96 | + requestingScheme = null; | |
| 97 | + requestingURL = null; | |
| 98 | + requestingAuthType = RequestorType.SERVER; | |
| 99 | + } | |
| 100 | + | |
| 101 | + | |
| 102 | + /** | |
| 103 | + * Sets the authenticator that will be used by the networking code | |
| 104 | + * when a proxy or an HTTP server asks for authentication. | |
| 105 | + * <p> | |
| 106 | + * First, if there is a security manager, its <code>checkPermission</code> | |
| 107 | + * method is called with a | |
| 108 | + * <code>NetPermission("setDefaultAuthenticator")</code> permission. | |
| 109 | + * This may result in a java.lang.SecurityException. | |
| 110 | + * | |
| 111 | + * @param a The authenticator to be set. If a is <code>null</code> then | |
| 112 | + * any previously set authenticator is removed. | |
| 113 | + * | |
| 114 | + * @throws SecurityException | |
| 115 | + * if a security manager exists and its | |
| 116 | + * <code>checkPermission</code> method doesn't allow | |
| 117 | + * setting the default authenticator. | |
| 118 | + * | |
| 119 | + * @see SecurityManager#checkPermission | |
| 120 | + * @see java.net.NetPermission | |
| 121 | + */ | |
| 122 | + public synchronized static void setDefault(Authenticator a) { | |
| 123 | + SecurityManager sm = System.getSecurityManager(); | |
| 124 | + if (sm != null) { | |
| 125 | + NetPermission setDefaultPermission | |
| 126 | + = new NetPermission("setDefaultAuthenticator"); | |
| 127 | + sm.checkPermission(setDefaultPermission); | |
| 128 | + } | |
| 129 | + | |
| 130 | + theAuthenticator = a; | |
| 131 | + } | |
| 132 | + | |
| 133 | + /** | |
| 134 | + * Ask the authenticator that has been registered with the system | |
| 135 | + * for a password. | |
| 136 | + * <p> | |
| 137 | + * First, if there is a security manager, its <code>checkPermission</code> | |
| 138 | + * method is called with a | |
| 139 | + * <code>NetPermission("requestPasswordAuthentication")</code> permission. | |
| 140 | + * This may result in a java.lang.SecurityException. | |
| 141 | + * | |
| 142 | + * @param addr The InetAddress of the site requesting authorization, | |
| 143 | + * or null if not known. | |
| 144 | + * @param port the port for the requested connection | |
| 145 | + * @param protocol The protocol that's requesting the connection | |
| 146 | + * ({@link java.net.Authenticator#getRequestingProtocol()}) | |
| 147 | + * @param prompt A prompt string for the user | |
| 148 | + * @param scheme The authentication scheme | |
| 149 | + * | |
| 150 | + * @return The username/password, or null if one can't be gotten. | |
| 151 | + * | |
| 152 | + * @throws SecurityException | |
| 153 | + * if a security manager exists and its | |
| 154 | + * <code>checkPermission</code> method doesn't allow | |
| 155 | + * the password authentication request. | |
| 156 | + * | |
| 157 | + * @see SecurityManager#checkPermission | |
| 158 | + * @see java.net.NetPermission | |
| 159 | + */ | |
| 160 | + public static PasswordAuthentication requestPasswordAuthentication( | |
| 161 | + InetAddress addr, | |
| 162 | + int port, | |
| 163 | + String protocol, | |
| 164 | + String prompt, | |
| 165 | + String scheme) { | |
| 166 | + | |
| 167 | + SecurityManager sm = System.getSecurityManager(); | |
| 168 | + if (sm != null) { | |
| 169 | + NetPermission requestPermission | |
| 170 | + = new NetPermission("requestPasswordAuthentication"); | |
| 171 | + sm.checkPermission(requestPermission); | |
| 172 | + } | |
| 173 | + | |
| 174 | + Authenticator a = theAuthenticator; | |
| 175 | + if (a == null) { | |
| 176 | + return null; | |
| 177 | + } else { | |
| 178 | + synchronized(a) { | |
| 179 | + a.reset(); | |
| 180 | + a.requestingSite = addr; | |
| 181 | + a.requestingPort = port; | |
| 182 | + a.requestingProtocol = protocol; | |
| 183 | + a.requestingPrompt = prompt; | |
| 184 | + a.requestingScheme = scheme; | |
| 185 | + return a.getPasswordAuthentication(); | |
| 186 | + } | |
| 187 | + } | |
| 188 | + } | |
| 189 | + | |
| 190 | + /** | |
| 191 | + * Ask the authenticator that has been registered with the system | |
| 192 | + * for a password. This is the preferred method for requesting a password | |
| 193 | + * because the hostname can be provided in cases where the InetAddress | |
| 194 | + * is not available. | |
| 195 | + * <p> | |
| 196 | + * First, if there is a security manager, its <code>checkPermission</code> | |
| 197 | + * method is called with a | |
| 198 | + * <code>NetPermission("requestPasswordAuthentication")</code> permission. | |
| 199 | + * This may result in a java.lang.SecurityException. | |
| 200 | + * | |
| 201 | + * @param host The hostname of the site requesting authentication. | |
| 202 | + * @param addr The InetAddress of the site requesting authentication, | |
| 203 | + * or null if not known. | |
| 204 | + * @param port the port for the requested connection. | |
| 205 | + * @param protocol The protocol that's requesting the connection | |
| 206 | + * ({@link java.net.Authenticator#getRequestingProtocol()}) | |
| 207 | + * @param prompt A prompt string for the user which identifies the authentication realm. | |
| 208 | + * @param scheme The authentication scheme | |
| 209 | + * | |
| 210 | + * @return The username/password, or null if one can't be gotten. | |
| 211 | + * | |
| 212 | + * @throws SecurityException | |
| 213 | + * if a security manager exists and its | |
| 214 | + * <code>checkPermission</code> method doesn't allow | |
| 215 | + * the password authentication request. | |
| 216 | + * | |
| 217 | + * @see SecurityManager#checkPermission | |
| 218 | + * @see java.net.NetPermission | |
| 219 | + * @since 1.4 | |
| 220 | + */ | |
| 221 | + public static PasswordAuthentication requestPasswordAuthentication( | |
| 222 | + String host, | |
| 223 | + InetAddress addr, | |
| 224 | + int port, | |
| 225 | + String protocol, | |
| 226 | + String prompt, | |
| 227 | + String scheme) { | |
| 228 | + | |
| 229 | + SecurityManager sm = System.getSecurityManager(); | |
| 230 | + if (sm != null) { | |
| 231 | + NetPermission requestPermission | |
| 232 | + = new NetPermission("requestPasswordAuthentication"); | |
| 233 | + sm.checkPermission(requestPermission); | |
| 234 | + } | |
| 235 | + | |
| 236 | + Authenticator a = theAuthenticator; | |
| 237 | + if (a == null) { | |
| 238 | + return null; | |
| 239 | + } else { | |
| 240 | + synchronized(a) { | |
| 241 | + a.reset(); | |
| 242 | + a.requestingHost = host; | |
| 243 | + a.requestingSite = addr; | |
| 244 | + a.requestingPort = port; | |
| 245 | + a.requestingProtocol = protocol; | |
| 246 | + a.requestingPrompt = prompt; | |
| 247 | + a.requestingScheme = scheme; | |
| 248 | + return a.getPasswordAuthentication(); | |
| 249 | + } | |
| 250 | + } | |
| 251 | + } | |
| 252 | + | |
| 253 | + /** | |
| 254 | + * Ask the authenticator that has been registered with the system | |
| 255 | + * for a password. | |
| 256 | + * <p> | |
| 257 | + * First, if there is a security manager, its <code>checkPermission</code> | |
| 258 | + * method is called with a | |
| 259 | + * <code>NetPermission("requestPasswordAuthentication")</code> permission. | |
| 260 | + * This may result in a java.lang.SecurityException. | |
| 261 | + * | |
| 262 | + * @param host The hostname of the site requesting authentication. | |
| 263 | + * @param addr The InetAddress of the site requesting authorization, | |
| 264 | + * or null if not known. | |
| 265 | + * @param port the port for the requested connection | |
| 266 | + * @param protocol The protocol that's requesting the connection | |
| 267 | + * ({@link java.net.Authenticator#getRequestingProtocol()}) | |
| 268 | + * @param prompt A prompt string for the user | |
| 269 | + * @param scheme The authentication scheme | |
| 270 | + * @param url The requesting URL that caused the authentication | |
| 271 | + * @param reqType The type (server or proxy) of the entity requesting | |
| 272 | + * authentication. | |
| 273 | + * | |
| 274 | + * @return The username/password, or null if one can't be gotten. | |
| 275 | + * | |
| 276 | + * @throws SecurityException | |
| 277 | + * if a security manager exists and its | |
| 278 | + * <code>checkPermission</code> method doesn't allow | |
| 279 | + * the password authentication request. | |
| 280 | + * | |
| 281 | + * @see SecurityManager#checkPermission | |
| 282 | + * @see java.net.NetPermission | |
| 283 | + * | |
| 284 | + * @since 1.5 | |
| 285 | + */ | |
| 286 | + public static PasswordAuthentication requestPasswordAuthentication( | |
| 287 | + String host, | |
| 288 | + InetAddress addr, | |
| 289 | + int port, | |
| 290 | + String protocol, | |
| 291 | + String prompt, | |
| 292 | + String scheme, | |
| 293 | + URL url, | |
| 294 | + RequestorType reqType) { | |
| 295 | + | |
| 296 | + SecurityManager sm = System.getSecurityManager(); | |
| 297 | + if (sm != null) { | |
| 298 | + NetPermission requestPermission | |
| 299 | + = new NetPermission("requestPasswordAuthentication"); | |
| 300 | + sm.checkPermission(requestPermission); | |
| 301 | + } | |
| 302 | + | |
| 303 | + Authenticator a = theAuthenticator; | |
| 304 | + if (a == null) { | |
| 305 | + return null; | |
| 306 | + } else { | |
| 307 | + synchronized(a) { | |
| 308 | + a.reset(); | |
| 309 | + a.requestingHost = host; | |
| 310 | + a.requestingSite = addr; | |
| 311 | + a.requestingPort = port; | |
| 312 | + a.requestingProtocol = protocol; | |
| 313 | + a.requestingPrompt = prompt; | |
| 314 | + a.requestingScheme = scheme; | |
| 315 | + a.requestingURL = url; | |
| 316 | + a.requestingAuthType = reqType; | |
| 317 | + return a.getPasswordAuthentication(); | |
| 318 | + } | |
| 319 | + } | |
| 320 | + } | |
| 321 | + | |
| 322 | + /** | |
| 323 | + * Gets the <code>hostname</code> of the | |
| 324 | + * site or proxy requesting authentication, or <code>null</code> | |
| 325 | + * if not available. | |
| 326 | + * | |
| 327 | + * @return the hostname of the connection requiring authentication, or null | |
| 328 | + * if it's not available. | |
| 329 | + * @since 1.4 | |
| 330 | + */ | |
| 331 | + protected final String getRequestingHost() { | |
| 332 | + return requestingHost; | |
| 333 | + } | |
| 334 | + | |
| 335 | + /** | |
| 336 | + * Gets the <code>InetAddress</code> of the | |
| 337 | + * site requesting authorization, or <code>null</code> | |
| 338 | + * if not available. | |
| 339 | + * | |
| 340 | + * @return the InetAddress of the site requesting authorization, or null | |
| 341 | + * if it's not available. | |
| 342 | + */ | |
| 343 | + protected final InetAddress getRequestingSite() { | |
| 344 | + return requestingSite; | |
| 345 | + } | |
| 346 | + | |
| 347 | + /** | |
| 348 | + * Gets the port number for the requested connection. | |
| 349 | + * @return an <code>int</code> indicating the | |
| 350 | + * port for the requested connection. | |
| 351 | + */ | |
| 352 | + protected final int getRequestingPort() { | |
| 353 | + return requestingPort; | |
| 354 | + } | |
| 355 | + | |
| 356 | + /** | |
| 357 | + * Give the protocol that's requesting the connection. Often this | |
| 358 | + * will be based on a URL, but in a future JDK it could be, for | |
| 359 | + * example, "SOCKS" for a password-protected SOCKS5 firewall. | |
| 360 | + * | |
| 361 | + * @return the protcol, optionally followed by "/version", where | |
| 362 | + * version is a version number. | |
| 363 | + * | |
| 364 | + * @see java.net.URL#getProtocol() | |
| 365 | + */ | |
| 366 | + protected final String getRequestingProtocol() { | |
| 367 | + return requestingProtocol; | |
| 368 | + } | |
| 369 | + | |
| 370 | + /** | |
| 371 | + * Gets the prompt string given by the requestor. | |
| 372 | + * | |
| 373 | + * @return the prompt string given by the requestor (realm for | |
| 374 | + * http requests) | |
| 375 | + */ | |
| 376 | + protected final String getRequestingPrompt() { | |
| 377 | + return requestingPrompt; | |
| 378 | + } | |
| 379 | + | |
| 380 | + /** | |
| 381 | + * Gets the scheme of the requestor (the HTTP scheme | |
| 382 | + * for an HTTP firewall, for example). | |
| 383 | + * | |
| 384 | + * @return the scheme of the requestor | |
| 385 | + * | |
| 386 | + */ | |
| 387 | + protected final String getRequestingScheme() { | |
| 388 | + return requestingScheme; | |
| 389 | + } | |
| 390 | + | |
| 391 | + /** | |
| 392 | + * Called when password authorization is needed. Subclasses should | |
| 393 | + * override the default implementation, which returns null. | |
| 394 | + * @return The PasswordAuthentication collected from the | |
| 395 | + * user, or null if none is provided. | |
| 396 | + */ | |
| 397 | + protected PasswordAuthentication getPasswordAuthentication() { | |
| 398 | + return null; | |
| 399 | + } | |
| 400 | + | |
| 401 | + /** | |
| 402 | + * Returns the URL that resulted in this | |
| 403 | + * request for authentication. | |
| 404 | + * | |
| 405 | + * @since 1.5 | |
| 406 | + * | |
| 407 | + * @return the requesting URL | |
| 408 | + * | |
| 409 | + */ | |
| 410 | + protected URL getRequestingURL () { | |
| 411 | + return requestingURL; | |
| 412 | + } | |
| 413 | + | |
| 414 | + /** | |
| 415 | + * Returns whether the requestor is a Proxy or a Server. | |
| 416 | + * | |
| 417 | + * @since 1.5 | |
| 418 | + * | |
| 419 | + * @return the authentication type of the requestor | |
| 420 | + * | |
| 421 | + */ | |
| 422 | + protected RequestorType getRequestorType () { | |
| 423 | + return requestingAuthType; | |
| 424 | + } | |
| 425 | +} | |
Binary file not shown.
| @@ -0,0 +1,54 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Signals that an error occurred while attempting to bind a | |
| 30 | + * socket to a local address and port. Typically, the port is | |
| 31 | + * in use, or the requested local address could not be assigned. | |
| 32 | + * | |
| 33 | + * @since JDK1.1 | |
| 34 | + */ | |
| 35 | + | |
| 36 | +public class BindException extends SocketException { | |
| 37 | + private static final long serialVersionUID = -5945005768251722951L; | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * Constructs a new BindException with the specified detail | |
| 41 | + * message as to why the bind error occurred. | |
| 42 | + * A detail message is a String that gives a specific | |
| 43 | + * description of this error. | |
| 44 | + * @param msg the detail message | |
| 45 | + */ | |
| 46 | + public BindException(String msg) { | |
| 47 | + super(msg); | |
| 48 | + } | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Construct a new BindException with no detailed message. | |
| 52 | + */ | |
| 53 | + public BindException() {} | |
| 54 | +} | |
Binary file not shown.
| @@ -0,0 +1,63 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2004, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.OutputStream; | |
| 29 | +import java.io.IOException; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * Represents channels for storing resources in the | |
| 33 | + * ResponseCache. Instances of such a class provide an | |
| 34 | + * OutputStream object which is called by protocol handlers to | |
| 35 | + * store the resource data into the cache, and also an abort() method | |
| 36 | + * which allows a cache store operation to be interrupted and | |
| 37 | + * abandoned. If an IOException is encountered while reading the | |
| 38 | + * response or writing to the cache, the current cache store operation | |
| 39 | + * will be aborted. | |
| 40 | + * | |
| 41 | + * @author Yingxian Wang | |
| 42 | + * @since 1.5 | |
| 43 | + */ | |
| 44 | +public abstract class CacheRequest { | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * Returns an OutputStream to which the response body can be | |
| 48 | + * written. | |
| 49 | + * | |
| 50 | + * @return an OutputStream to which the response body can | |
| 51 | + * be written | |
| 52 | + * @throws IOException if an I/O error occurs while | |
| 53 | + * writing the response body | |
| 54 | + */ | |
| 55 | + public abstract OutputStream getBody() throws IOException; | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * Aborts the attempt to cache the response. If an IOException is | |
| 59 | + * encountered while reading the response or writing to the cache, | |
| 60 | + * the current cache store operation will be abandoned. | |
| 61 | + */ | |
| 62 | + public abstract void abort(); | |
| 63 | +} | |
Binary file not shown.
| @@ -0,0 +1,64 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2004, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.InputStream; | |
| 29 | +import java.util.Map; | |
| 30 | +import java.util.List; | |
| 31 | +import java.io.IOException; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * Represent channels for retrieving resources from the | |
| 35 | + * ResponseCache. Instances of such a class provide an | |
| 36 | + * InputStream that returns the entity body, and also a | |
| 37 | + * getHeaders() method which returns the associated response headers. | |
| 38 | + * | |
| 39 | + * @author Yingxian Wang | |
| 40 | + * @since 1.5 | |
| 41 | + */ | |
| 42 | +public abstract class CacheResponse { | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * Returns the response headers as a Map. | |
| 46 | + * | |
| 47 | + * @return An immutable Map from response header field names to | |
| 48 | + * lists of field values. The status line has null as its | |
| 49 | + * field name. | |
| 50 | + * @throws IOException if an I/O error occurs | |
| 51 | + * while getting the response headers | |
| 52 | + */ | |
| 53 | + public abstract Map<String, List<String>> getHeaders() throws IOException; | |
| 54 | + | |
| 55 | + /** | |
| 56 | + * Returns the response body as an InputStream. | |
| 57 | + * | |
| 58 | + * @return an InputStream from which the response body can | |
| 59 | + * be accessed | |
| 60 | + * @throws IOException if an I/O error occurs while | |
| 61 | + * getting the response body | |
| 62 | + */ | |
| 63 | + public abstract InputStream getBody() throws IOException; | |
| 64 | +} | |
Binary file not shown.
| @@ -0,0 +1,54 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Signals that an error occurred while attempting to connect a | |
| 30 | + * socket to a remote address and port. Typically, the connection | |
| 31 | + * was refused remotely (e.g., no process is listening on the | |
| 32 | + * remote address/port). | |
| 33 | + * | |
| 34 | + * @since JDK1.1 | |
| 35 | + */ | |
| 36 | +public class ConnectException extends SocketException { | |
| 37 | + private static final long serialVersionUID = 3831404271622369215L; | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * Constructs a new ConnectException with the specified detail | |
| 41 | + * message as to why the connect error occurred. | |
| 42 | + * A detail message is a String that gives a specific | |
| 43 | + * description of this error. | |
| 44 | + * @param msg the detail message | |
| 45 | + */ | |
| 46 | + public ConnectException(String msg) { | |
| 47 | + super(msg); | |
| 48 | + } | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Construct a new ConnectException with no detailed message. | |
| 52 | + */ | |
| 53 | + public ConnectException() {} | |
| 54 | +} | |
Binary file not shown.
| @@ -0,0 +1,110 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2006, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * The abstract class <code>ContentHandler</code> is the superclass | |
| 32 | + * of all classes that read an <code>Object</code> from a | |
| 33 | + * <code>URLConnection</code>. | |
| 34 | + * <p> | |
| 35 | + * An application does not generally call the | |
| 36 | + * <code>getContent</code> method in this class directly. Instead, an | |
| 37 | + * application calls the <code>getContent</code> method in class | |
| 38 | + * <code>URL</code> or in <code>URLConnection</code>. | |
| 39 | + * The application's content handler factory (an instance of a class that | |
| 40 | + * implements the interface <code>ContentHandlerFactory</code> set | |
| 41 | + * up by a call to <code>setContentHandler</code>) is | |
| 42 | + * called with a <code>String</code> giving the MIME type of the | |
| 43 | + * object being received on the socket. The factory returns an | |
| 44 | + * instance of a subclass of <code>ContentHandler</code>, and its | |
| 45 | + * <code>getContent</code> method is called to create the object. | |
| 46 | + * <p> | |
| 47 | + * If no content handler could be found, URLConnection will | |
| 48 | + * look for a content handler in a user-defineable set of places. | |
| 49 | + * By default it looks in sun.net.www.content, but users can define a | |
| 50 | + * vertical-bar delimited set of class prefixes to search through in | |
| 51 | + * addition by defining the java.content.handler.pkgs property. | |
| 52 | + * The class name must be of the form: | |
| 53 | + * <pre> | |
| 54 | + * {package-prefix}.{major}.{minor} | |
| 55 | + * e.g. | |
| 56 | + * YoyoDyne.experimental.text.plain | |
| 57 | + * </pre> | |
| 58 | + * If the loading of the content handler class would be performed by | |
| 59 | + * a classloader that is outside of the delegation chain of the caller, | |
| 60 | + * the JVM will need the RuntimePermission "getClassLoader". | |
| 61 | + * | |
| 62 | + * @author James Gosling | |
| 63 | + * @see java.net.ContentHandler#getContent(java.net.URLConnection) | |
| 64 | + * @see java.net.ContentHandlerFactory | |
| 65 | + * @see java.net.URL#getContent() | |
| 66 | + * @see java.net.URLConnection | |
| 67 | + * @see java.net.URLConnection#getContent() | |
| 68 | + * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory) | |
| 69 | + * @since JDK1.0 | |
| 70 | + */ | |
| 71 | +abstract public class ContentHandler { | |
| 72 | + /** | |
| 73 | + * Given a URL connect stream positioned at the beginning of the | |
| 74 | + * representation of an object, this method reads that stream and | |
| 75 | + * creates an object from it. | |
| 76 | + * | |
| 77 | + * @param urlc a URL connection. | |
| 78 | + * @return the object read by the <code>ContentHandler</code>. | |
| 79 | + * @exception IOException if an I/O error occurs while reading the object. | |
| 80 | + */ | |
| 81 | + abstract public Object getContent(URLConnection urlc) throws IOException; | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * Given a URL connect stream positioned at the beginning of the | |
| 85 | + * representation of an object, this method reads that stream and | |
| 86 | + * creates an object that matches one of the types specified. | |
| 87 | + * | |
| 88 | + * The default implementation of this method should call getContent() | |
| 89 | + * and screen the return type for a match of the suggested types. | |
| 90 | + * | |
| 91 | + * @param urlc a URL connection. | |
| 92 | + * @param classes an array of types requested | |
| 93 | + * @return the object read by the <code>ContentHandler</code> that is | |
| 94 | + * the first match of the suggested types. | |
| 95 | + * null if none of the requested are supported. | |
| 96 | + * @exception IOException if an I/O error occurs while reading the object. | |
| 97 | + * @since 1.3 | |
| 98 | + */ | |
| 99 | + public Object getContent(URLConnection urlc, Class[] classes) throws IOException { | |
| 100 | + Object obj = getContent(urlc); | |
| 101 | + | |
| 102 | + for (int i = 0; i < classes.length; i++) { | |
| 103 | + if (classes[i].isInstance(obj)) { | |
| 104 | + return obj; | |
| 105 | + } | |
| 106 | + } | |
| 107 | + return null; | |
| 108 | + } | |
| 109 | + | |
| 110 | +} | |
Binary file not shown.
| @@ -0,0 +1,54 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 1997, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This interface defines a factory for content handlers. An | |
| 30 | + * implementation of this interface should map a MIME type into an | |
| 31 | + * instance of <code>ContentHandler</code>. | |
| 32 | + * <p> | |
| 33 | + * This interface is used by the <code>URLStreamHandler</code> class | |
| 34 | + * to create a <code>ContentHandler</code> for a MIME type. | |
| 35 | + * | |
| 36 | + * @author James Gosling | |
| 37 | + * @see java.net.ContentHandler | |
| 38 | + * @see java.net.URLStreamHandler | |
| 39 | + * @since JDK1.0 | |
| 40 | + */ | |
| 41 | +public interface ContentHandlerFactory { | |
| 42 | + /** | |
| 43 | + * Creates a new <code>ContentHandler</code> to read an object from | |
| 44 | + * a <code>URLStreamHandler</code>. | |
| 45 | + * | |
| 46 | + * @param mimetype the MIME type for which a content handler is desired. | |
| 47 | + | |
| 48 | + * @return a new <code>ContentHandler</code> to read an object from a | |
| 49 | + * <code>URLStreamHandler</code>. | |
| 50 | + * @see java.net.ContentHandler | |
| 51 | + * @see java.net.URLStreamHandler | |
| 52 | + */ | |
| 53 | + ContentHandler createContentHandler(String mimetype); | |
| 54 | +} | |
Binary file not shown.
| @@ -0,0 +1,150 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +import java.util.Map; | |
| 29 | +import java.util.List; | |
| 30 | +import java.io.IOException; | |
| 31 | +import sun.security.util.SecurityConstants; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * A CookieHandler object provides a callback mechanism to hook up a | |
| 35 | + * HTTP state management policy implementation into the HTTP protocol | |
| 36 | + * handler. The HTTP state management mechanism specifies a way to | |
| 37 | + * create a stateful session with HTTP requests and responses. | |
| 38 | + * | |
| 39 | + * <p>A system-wide CookieHandler that to used by the HTTP protocol | |
| 40 | + * handler can be registered by doing a | |
| 41 | + * CookieHandler.setDefault(CookieHandler). The currently registered | |
| 42 | + * CookieHandler can be retrieved by calling | |
| 43 | + * CookieHandler.getDefault(). | |
| 44 | + * | |
| 45 | + * For more information on HTTP state management, see <a | |
| 46 | + * href="http://www.ietf.org/rfc/rfc2965.txt"><i>RFC 2965: HTTP | |
| 47 | + * State Management Mechanism</i></a> | |
| 48 | + * | |
| 49 | + * @author Yingxian Wang | |
| 50 | + * @since 1.5 | |
| 51 | + */ | |
| 52 | +public abstract class CookieHandler { | |
| 53 | + /** | |
| 54 | + * The system-wide cookie handler that will apply cookies to the | |
| 55 | + * request headers and manage cookies from the response headers. | |
| 56 | + * | |
| 57 | + * @see setDefault(CookieHandler) | |
| 58 | + * @see getDefault() | |
| 59 | + */ | |
| 60 | + private static CookieHandler cookieHandler; | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * Gets the system-wide cookie handler. | |
| 64 | + * | |
| 65 | + * @return the system-wide cookie handler; A null return means | |
| 66 | + * there is no system-wide cookie handler currently set. | |
| 67 | + * @throws SecurityException | |
| 68 | + * If a security manager has been installed and it denies | |
| 69 | + * {@link NetPermission}<tt>("getCookieHandler")</tt> | |
| 70 | + * @see #setDefault(CookieHandler) | |
| 71 | + */ | |
| 72 | + public synchronized static CookieHandler getDefault() { | |
| 73 | + SecurityManager sm = System.getSecurityManager(); | |
| 74 | + if (sm != null) { | |
| 75 | + sm.checkPermission(SecurityConstants.GET_COOKIEHANDLER_PERMISSION); | |
| 76 | + } | |
| 77 | + return cookieHandler; | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * Sets (or unsets) the system-wide cookie handler. | |
| 82 | + * | |
| 83 | + * Note: non-standard http protocol handlers may ignore this setting. | |
| 84 | + * | |
| 85 | + * @param cHandler The HTTP cookie handler, or | |
| 86 | + * <code>null</code> to unset. | |
| 87 | + * @throws SecurityException | |
| 88 | + * If a security manager has been installed and it denies | |
| 89 | + * {@link NetPermission}<tt>("setCookieHandler")</tt> | |
| 90 | + * @see #getDefault() | |
| 91 | + */ | |
| 92 | + public synchronized static void setDefault(CookieHandler cHandler) { | |
| 93 | + SecurityManager sm = System.getSecurityManager(); | |
| 94 | + if (sm != null) { | |
| 95 | + sm.checkPermission(SecurityConstants.SET_COOKIEHANDLER_PERMISSION); | |
| 96 | + } | |
| 97 | + cookieHandler = cHandler; | |
| 98 | + } | |
| 99 | + | |
| 100 | + /** | |
| 101 | + * Gets all the applicable cookies from a cookie cache for the | |
| 102 | + * specified uri in the request header. | |
| 103 | + * | |
| 104 | + * <P>The {@code URI} passed as an argument specifies the intended use for | |
| 105 | + * the cookies. In particular the scheme should reflect whether the cookies | |
| 106 | + * will be sent over http, https or used in another context like javascript. | |
| 107 | + * The host part should reflect either the destination of the cookies or | |
| 108 | + * their origin in the case of javascript.</P> | |
| 109 | + * <P>It is up to the implementation to take into account the {@code URI} and | |
| 110 | + * the cookies attributes and security settings to determine which ones | |
| 111 | + * should be returned.</P> | |
| 112 | + * | |
| 113 | + * <P>HTTP protocol implementers should make sure that this method is | |
| 114 | + * called after all request headers related to choosing cookies | |
| 115 | + * are added, and before the request is sent.</P> | |
| 116 | + * | |
| 117 | + * @param uri a <code>URI</code> representing the intended use for the | |
| 118 | + * cookies | |
| 119 | + * @param requestHeaders - a Map from request header | |
| 120 | + * field names to lists of field values representing | |
| 121 | + * the current request headers | |
| 122 | + * @return an immutable map from state management headers, with | |
| 123 | + * field names "Cookie" or "Cookie2" to a list of | |
| 124 | + * cookies containing state information | |
| 125 | + * | |
| 126 | + * @throws IOException if an I/O error occurs | |
| 127 | + * @throws IllegalArgumentException if either argument is null | |
| 128 | + * @see #put(URI, Map) | |
| 129 | + */ | |
| 130 | + public abstract Map<String, List<String>> | |
| 131 | + get(URI uri, Map<String, List<String>> requestHeaders) | |
| 132 | + throws IOException; | |
| 133 | + | |
| 134 | + /** | |
| 135 | + * Sets all the applicable cookies, examples are response header | |
| 136 | + * fields that are named Set-Cookie2, present in the response | |
| 137 | + * headers into a cookie cache. | |
| 138 | + * | |
| 139 | + * @param uri a <code>URI</code> where the cookies come from | |
| 140 | + * @param responseHeaders an immutable map from field names to | |
| 141 | + * lists of field values representing the response | |
| 142 | + * header fields returned | |
| 143 | + * @throws IOException if an I/O error occurs | |
| 144 | + * @throws IllegalArgumentException if either argument is null | |
| 145 | + * @see #get(URI, Map) | |
| 146 | + */ | |
| 147 | + public abstract void | |
| 148 | + put(URI uri, Map<String, List<String>> responseHeaders) | |
| 149 | + throws IOException; | |
| 150 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,446 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +import java.util.Map; | |
| 29 | +import java.util.List; | |
| 30 | +import java.util.Collections; | |
| 31 | +import java.util.Comparator; | |
| 32 | +import java.io.IOException; | |
| 33 | +import sun.util.logging.PlatformLogger; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * CookieManager provides a concrete implementation of {@link CookieHandler}, | |
| 37 | + * which separates the storage of cookies from the policy surrounding accepting | |
| 38 | + * and rejecting cookies. A CookieManager is initialized with a {@link CookieStore} | |
| 39 | + * which manages storage, and a {@link CookiePolicy} object, which makes | |
| 40 | + * policy decisions on cookie acceptance/rejection. | |
| 41 | + * | |
| 42 | + * <p> The HTTP cookie management in java.net package looks like: | |
| 43 | + * <blockquote> | |
| 44 | + * <pre> | |
| 45 | + * use | |
| 46 | + * CookieHandler <------- HttpURLConnection | |
| 47 | + * ^ | |
| 48 | + * | impl | |
| 49 | + * | use | |
| 50 | + * CookieManager -------> CookiePolicy | |
| 51 | + * | use | |
| 52 | + * |--------> HttpCookie | |
| 53 | + * | ^ | |
| 54 | + * | | use | |
| 55 | + * | use | | |
| 56 | + * |--------> CookieStore | |
| 57 | + * ^ | |
| 58 | + * | impl | |
| 59 | + * | | |
| 60 | + * Internal in-memory implementation | |
| 61 | + * </pre> | |
| 62 | + * <ul> | |
| 63 | + * <li> | |
| 64 | + * CookieHandler is at the core of cookie management. User can call | |
| 65 | + * CookieHandler.setDefault to set a concrete CookieHanlder implementation | |
| 66 | + * to be used. | |
| 67 | + * </li> | |
| 68 | + * <li> | |
| 69 | + * CookiePolicy.shouldAccept will be called by CookieManager.put to see whether | |
| 70 | + * or not one cookie should be accepted and put into cookie store. User can use | |
| 71 | + * any of three pre-defined CookiePolicy, namely ACCEPT_ALL, ACCEPT_NONE and | |
| 72 | + * ACCEPT_ORIGINAL_SERVER, or user can define his own CookiePolicy implementation | |
| 73 | + * and tell CookieManager to use it. | |
| 74 | + * </li> | |
| 75 | + * <li> | |
| 76 | + * CookieStore is the place where any accepted HTTP cookie is stored in. | |
| 77 | + * If not specified when created, a CookieManager instance will use an internal | |
| 78 | + * in-memory implementation. Or user can implements one and tell CookieManager | |
| 79 | + * to use it. | |
| 80 | + * </li> | |
| 81 | + * <li> | |
| 82 | + * Currently, only CookieStore.add(URI, HttpCookie) and CookieStore.get(URI) | |
| 83 | + * are used by CookieManager. Others are for completeness and might be needed | |
| 84 | + * by a more sophisticated CookieStore implementation, e.g. a NetscapeCookieSotre. | |
| 85 | + * </li> | |
| 86 | + * </ul> | |
| 87 | + * </blockquote> | |
| 88 | + * | |
| 89 | + * <p>There're various ways user can hook up his own HTTP cookie management behavior, e.g. | |
| 90 | + * <blockquote> | |
| 91 | + * <ul> | |
| 92 | + * <li>Use CookieHandler.setDefault to set a brand new {@link CookieHandler} implementation | |
| 93 | + * <li>Let CookieManager be the default {@link CookieHandler} implementation, | |
| 94 | + * but implement user's own {@link CookieStore} and {@link CookiePolicy} | |
| 95 | + * and tell default CookieManager to use them: | |
| 96 | + * <blockquote><pre> | |
| 97 | + * // this should be done at the beginning of an HTTP session | |
| 98 | + * CookieHandler.setDefault(new CookieManager(new MyCookieStore(), new MyCookiePolicy())); | |
| 99 | + * </pre></blockquote> | |
| 100 | + * <li>Let CookieManager be the default {@link CookieHandler} implementation, but | |
| 101 | + * use customized {@link CookiePolicy}: | |
| 102 | + * <blockquote><pre> | |
| 103 | + * // this should be done at the beginning of an HTTP session | |
| 104 | + * CookieHandler.setDefault(new CookieManager()); | |
| 105 | + * // this can be done at any point of an HTTP session | |
| 106 | + * ((CookieManager)CookieHandler.getDefault()).setCookiePolicy(new MyCookiePolicy()); | |
| 107 | + * </pre></blockquote> | |
| 108 | + * </ul> | |
| 109 | + * </blockquote> | |
| 110 | + * | |
| 111 | + * <p>The implementation conforms to <a href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a>, section 3.3. | |
| 112 | + * | |
| 113 | + * @see CookiePolicy | |
| 114 | + * @author Edward Wang | |
| 115 | + * @since 1.6 | |
| 116 | + */ | |
| 117 | +public class CookieManager extends CookieHandler | |
| 118 | +{ | |
| 119 | + /* ---------------- Fields -------------- */ | |
| 120 | + | |
| 121 | + private CookiePolicy policyCallback; | |
| 122 | + | |
| 123 | + | |
| 124 | + private CookieStore cookieJar = null; | |
| 125 | + | |
| 126 | + | |
| 127 | + /* ---------------- Ctors -------------- */ | |
| 128 | + | |
| 129 | + /** | |
| 130 | + * Create a new cookie manager. | |
| 131 | + * | |
| 132 | + * <p>This constructor will create new cookie manager with default | |
| 133 | + * cookie store and accept policy. The effect is same as | |
| 134 | + * <tt>CookieManager(null, null)</tt>. | |
| 135 | + */ | |
| 136 | + public CookieManager() { | |
| 137 | + this(null, null); | |
| 138 | + } | |
| 139 | + | |
| 140 | + | |
| 141 | + /** | |
| 142 | + * Create a new cookie manager with specified cookie store and cookie policy. | |
| 143 | + * | |
| 144 | + * @param store a <tt>CookieStore</tt> to be used by cookie manager. | |
| 145 | + * if <tt>null</tt>, cookie manager will use a default one, | |
| 146 | + * which is an in-memory CookieStore implmentation. | |
| 147 | + * @param cookiePolicy a <tt>CookiePolicy</tt> instance | |
| 148 | + * to be used by cookie manager as policy callback. | |
| 149 | + * if <tt>null</tt>, ACCEPT_ORIGINAL_SERVER will | |
| 150 | + * be used. | |
| 151 | + */ | |
| 152 | + public CookieManager(CookieStore store, | |
| 153 | + CookiePolicy cookiePolicy) | |
| 154 | + { | |
| 155 | + // use default cookie policy if not specify one | |
| 156 | + policyCallback = (cookiePolicy == null) ? CookiePolicy.ACCEPT_ORIGINAL_SERVER | |
| 157 | + : cookiePolicy; | |
| 158 | + | |
| 159 | + // if not specify CookieStore to use, use default one | |
| 160 | + if (store == null) { | |
| 161 | + cookieJar = new InMemoryCookieStore(); | |
| 162 | + } else { | |
| 163 | + cookieJar = store; | |
| 164 | + } | |
| 165 | + } | |
| 166 | + | |
| 167 | + | |
| 168 | + /* ---------------- Public operations -------------- */ | |
| 169 | + | |
| 170 | + /** | |
| 171 | + * To set the cookie policy of this cookie manager. | |
| 172 | + * | |
| 173 | + * <p> A instance of <tt>CookieManager</tt> will have | |
| 174 | + * cookie policy ACCEPT_ORIGINAL_SERVER by default. Users always | |
| 175 | + * can call this method to set another cookie policy. | |
| 176 | + * | |
| 177 | + * @param cookiePolicy the cookie policy. Can be <tt>null</tt>, which | |
| 178 | + * has no effects on current cookie policy. | |
| 179 | + */ | |
| 180 | + public void setCookiePolicy(CookiePolicy cookiePolicy) { | |
| 181 | + if (cookiePolicy != null) policyCallback = cookiePolicy; | |
| 182 | + } | |
| 183 | + | |
| 184 | + | |
| 185 | + /** | |
| 186 | + * To retrieve current cookie store. | |
| 187 | + * | |
| 188 | + * @return the cookie store currently used by cookie manager. | |
| 189 | + */ | |
| 190 | + public CookieStore getCookieStore() { | |
| 191 | + return cookieJar; | |
| 192 | + } | |
| 193 | + | |
| 194 | + | |
| 195 | + public Map<String, List<String>> | |
| 196 | + get(URI uri, Map<String, List<String>> requestHeaders) | |
| 197 | + throws IOException | |
| 198 | + { | |
| 199 | + // pre-condition check | |
| 200 | + if (uri == null || requestHeaders == null) { | |
| 201 | + throw new IllegalArgumentException("Argument is null"); | |
| 202 | + } | |
| 203 | + | |
| 204 | + Map<String, List<String>> cookieMap = | |
| 205 | + new java.util.HashMap<String, List<String>>(); | |
| 206 | + // if there's no default CookieStore, no way for us to get any cookie | |
| 207 | + if (cookieJar == null) | |
| 208 | + return Collections.unmodifiableMap(cookieMap); | |
| 209 | + | |
| 210 | + boolean secureLink = "https".equalsIgnoreCase(uri.getScheme()); | |
| 211 | + List<HttpCookie> cookies = new java.util.ArrayList<HttpCookie>(); | |
| 212 | + String path = uri.getPath(); | |
| 213 | + if (path == null || path.isEmpty()) { | |
| 214 | + path = "/"; | |
| 215 | + } | |
| 216 | + for (HttpCookie cookie : cookieJar.get(uri)) { | |
| 217 | + // apply path-matches rule (RFC 2965 sec. 3.3.4) | |
| 218 | + // and check for the possible "secure" tag (i.e. don't send | |
| 219 | + // 'secure' cookies over unsecure links) | |
| 220 | + if (pathMatches(path, cookie.getPath()) && | |
| 221 | + (secureLink || !cookie.getSecure())) { | |
| 222 | + // Enforce httponly attribute | |
| 223 | + if (cookie.isHttpOnly()) { | |
| 224 | + String s = uri.getScheme(); | |
| 225 | + if (!"http".equalsIgnoreCase(s) && !"https".equalsIgnoreCase(s)) { | |
| 226 | + continue; | |
| 227 | + } | |
| 228 | + } | |
| 229 | + // Let's check the authorize port list if it exists | |
| 230 | + String ports = cookie.getPortlist(); | |
| 231 | + if (ports != null && !ports.isEmpty()) { | |
| 232 | + int port = uri.getPort(); | |
| 233 | + if (port == -1) { | |
| 234 | + port = "https".equals(uri.getScheme()) ? 443 : 80; | |
| 235 | + } | |
| 236 | + if (isInPortList(ports, port)) { | |
| 237 | + cookies.add(cookie); | |
| 238 | + } | |
| 239 | + } else { | |
| 240 | + cookies.add(cookie); | |
| 241 | + } | |
| 242 | + } | |
| 243 | + } | |
| 244 | + | |
| 245 | + // apply sort rule (RFC 2965 sec. 3.3.4) | |
| 246 | + List<String> cookieHeader = sortByPath(cookies); | |
| 247 | + | |
| 248 | + cookieMap.put("Cookie", cookieHeader); | |
| 249 | + return Collections.unmodifiableMap(cookieMap); | |
| 250 | + } | |
| 251 | + | |
| 252 | + | |
| 253 | + public void | |
| 254 | + put(URI uri, Map<String, List<String>> responseHeaders) | |
| 255 | + throws IOException | |
| 256 | + { | |
| 257 | + // pre-condition check | |
| 258 | + if (uri == null || responseHeaders == null) { | |
| 259 | + throw new IllegalArgumentException("Argument is null"); | |
| 260 | + } | |
| 261 | + | |
| 262 | + | |
| 263 | + // if there's no default CookieStore, no need to remember any cookie | |
| 264 | + if (cookieJar == null) | |
| 265 | + return; | |
| 266 | + | |
| 267 | + PlatformLogger logger = PlatformLogger.getLogger("java.net.CookieManager"); | |
| 268 | + for (String headerKey : responseHeaders.keySet()) { | |
| 269 | + // RFC 2965 3.2.2, key must be 'Set-Cookie2' | |
| 270 | + // we also accept 'Set-Cookie' here for backward compatibility | |
| 271 | + if (headerKey == null | |
| 272 | + || !(headerKey.equalsIgnoreCase("Set-Cookie2") | |
| 273 | + || headerKey.equalsIgnoreCase("Set-Cookie") | |
| 274 | + ) | |
| 275 | + ) | |
| 276 | + { | |
| 277 | + continue; | |
| 278 | + } | |
| 279 | + | |
| 280 | + for (String headerValue : responseHeaders.get(headerKey)) { | |
| 281 | + try { | |
| 282 | + List<HttpCookie> cookies; | |
| 283 | + try { | |
| 284 | + cookies = HttpCookie.parse(headerValue); | |
| 285 | + } catch (IllegalArgumentException e) { | |
| 286 | + // Bogus header, make an empty list and log the error | |
| 287 | + cookies = java.util.Collections.EMPTY_LIST; | |
| 288 | + if (logger.isLoggable(PlatformLogger.SEVERE)) { | |
| 289 | + logger.severe("Invalid cookie for " + uri + ": " + headerValue); | |
| 290 | + } | |
| 291 | + } | |
| 292 | + for (HttpCookie cookie : cookies) { | |
| 293 | + if (cookie.getPath() == null) { | |
| 294 | + // If no path is specified, then by default | |
| 295 | + // the path is the directory of the page/doc | |
| 296 | + String path = uri.getPath(); | |
| 297 | + if (!path.endsWith("/")) { | |
| 298 | + int i = path.lastIndexOf("/"); | |
| 299 | + if (i > 0) { | |
| 300 | + path = path.substring(0, i + 1); | |
| 301 | + } else { | |
| 302 | + path = "/"; | |
| 303 | + } | |
| 304 | + } | |
| 305 | + cookie.setPath(path); | |
| 306 | + } | |
| 307 | + | |
| 308 | + // As per RFC 2965, section 3.3.1: | |
| 309 | + // Domain Defaults to the effective request-host. (Note that because | |
| 310 | + // there is no dot at the beginning of effective request-host, | |
| 311 | + // the default Domain can only domain-match itself.) | |
| 312 | + if (cookie.getDomain() == null) { | |
| 313 | + cookie.setDomain(uri.getHost()); | |
| 314 | + } | |
| 315 | + String ports = cookie.getPortlist(); | |
| 316 | + if (ports != null) { | |
| 317 | + int port = uri.getPort(); | |
| 318 | + if (port == -1) { | |
| 319 | + port = "https".equals(uri.getScheme()) ? 443 : 80; | |
| 320 | + } | |
| 321 | + if (ports.isEmpty()) { | |
| 322 | + // Empty port list means this should be restricted | |
| 323 | + // to the incoming URI port | |
| 324 | + cookie.setPortlist("" + port ); | |
| 325 | + if (shouldAcceptInternal(uri, cookie)) { | |
| 326 | + cookieJar.add(uri, cookie); | |
| 327 | + } | |
| 328 | + } else { | |
| 329 | + // Only store cookies with a port list | |
| 330 | + // IF the URI port is in that list, as per | |
| 331 | + // RFC 2965 section 3.3.2 | |
| 332 | + if (isInPortList(ports, port) && | |
| 333 | + shouldAcceptInternal(uri, cookie)) { | |
| 334 | + cookieJar.add(uri, cookie); | |
| 335 | + } | |
| 336 | + } | |
| 337 | + } else { | |
| 338 | + if (shouldAcceptInternal(uri, cookie)) { | |
| 339 | + cookieJar.add(uri, cookie); | |
| 340 | + } | |
| 341 | + } | |
| 342 | + } | |
| 343 | + } catch (IllegalArgumentException e) { | |
| 344 | + // invalid set-cookie header string | |
| 345 | + // no-op | |
| 346 | + } | |
| 347 | + } | |
| 348 | + } | |
| 349 | + } | |
| 350 | + | |
| 351 | + | |
| 352 | + /* ---------------- Private operations -------------- */ | |
| 353 | + | |
| 354 | + // to determine whether or not accept this cookie | |
| 355 | + private boolean shouldAcceptInternal(URI uri, HttpCookie cookie) { | |
| 356 | + try { | |
| 357 | + return policyCallback.shouldAccept(uri, cookie); | |
| 358 | + } catch (Exception ignored) { // pretect against malicious callback | |
| 359 | + return false; | |
| 360 | + } | |
| 361 | + } | |
| 362 | + | |
| 363 | + | |
| 364 | + static private boolean isInPortList(String lst, int port) { | |
| 365 | + int i = lst.indexOf(","); | |
| 366 | + int val = -1; | |
| 367 | + while (i > 0) { | |
| 368 | + try { | |
| 369 | + val = Integer.parseInt(lst.substring(0, i)); | |
| 370 | + if (val == port) { | |
| 371 | + return true; | |
| 372 | + } | |
| 373 | + } catch (NumberFormatException numberFormatException) { | |
| 374 | + } | |
| 375 | + lst = lst.substring(i+1); | |
| 376 | + i = lst.indexOf(","); | |
| 377 | + } | |
| 378 | + if (!lst.isEmpty()) { | |
| 379 | + try { | |
| 380 | + val = Integer.parseInt(lst); | |
| 381 | + if (val == port) { | |
| 382 | + return true; | |
| 383 | + } | |
| 384 | + } catch (NumberFormatException numberFormatException) { | |
| 385 | + } | |
| 386 | + } | |
| 387 | + return false; | |
| 388 | + } | |
| 389 | + | |
| 390 | + /* | |
| 391 | + * path-matches algorithm, as defined by RFC 2965 | |
| 392 | + */ | |
| 393 | + private boolean pathMatches(String path, String pathToMatchWith) { | |
| 394 | + if (path == pathToMatchWith) | |
| 395 | + return true; | |
| 396 | + if (path == null || pathToMatchWith == null) | |
| 397 | + return false; | |
| 398 | + if (path.startsWith(pathToMatchWith)) | |
| 399 | + return true; | |
| 400 | + | |
| 401 | + return false; | |
| 402 | + } | |
| 403 | + | |
| 404 | + | |
| 405 | + /* | |
| 406 | + * sort cookies with respect to their path: those with more specific Path attributes | |
| 407 | + * precede those with less specific, as defined in RFC 2965 sec. 3.3.4 | |
| 408 | + */ | |
| 409 | + private List<String> sortByPath(List<HttpCookie> cookies) { | |
| 410 | + Collections.sort(cookies, new CookiePathComparator()); | |
| 411 | + | |
| 412 | + List<String> cookieHeader = new java.util.ArrayList<String>(); | |
| 413 | + for (HttpCookie cookie : cookies) { | |
| 414 | + // Netscape cookie spec and RFC 2965 have different format of Cookie | |
| 415 | + // header; RFC 2965 requires a leading $Version="1" string while Netscape | |
| 416 | + // does not. | |
| 417 | + // The workaround here is to add a $Version="1" string in advance | |
| 418 | + if (cookies.indexOf(cookie) == 0 && cookie.getVersion() > 0) { | |
| 419 | + cookieHeader.add("$Version=\"1\""); | |
| 420 | + } | |
| 421 | + | |
| 422 | + cookieHeader.add(cookie.toString()); | |
| 423 | + } | |
| 424 | + return cookieHeader; | |
| 425 | + } | |
| 426 | + | |
| 427 | + | |
| 428 | + static class CookiePathComparator implements Comparator<HttpCookie> { | |
| 429 | + public int compare(HttpCookie c1, HttpCookie c2) { | |
| 430 | + if (c1 == c2) return 0; | |
| 431 | + if (c1 == null) return -1; | |
| 432 | + if (c2 == null) return 1; | |
| 433 | + | |
| 434 | + // path rule only applies to the cookies with same name | |
| 435 | + if (!c1.getName().equals(c2.getName())) return 0; | |
| 436 | + | |
| 437 | + // those with more specific Path attributes precede those with less specific | |
| 438 | + if (c1.getPath().startsWith(c2.getPath())) | |
| 439 | + return -1; | |
| 440 | + else if (c2.getPath().startsWith(c1.getPath())) | |
| 441 | + return 1; | |
| 442 | + else | |
| 443 | + return 0; | |
| 444 | + } | |
| 445 | + } | |
| 446 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,76 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * CookiePolicy implementations decide which cookies should be accepted | |
| 30 | + * and which should be rejected. Three pre-defined policy implementations | |
| 31 | + * are provided, namely ACCEPT_ALL, ACCEPT_NONE and ACCEPT_ORIGINAL_SERVER. | |
| 32 | + * | |
| 33 | + * <p>See RFC 2965 sec. 3.3 & 7 for more detail. | |
| 34 | + * | |
| 35 | + * @author Edward Wang | |
| 36 | + * @since 1.6 | |
| 37 | + */ | |
| 38 | +public interface CookiePolicy { | |
| 39 | + /** | |
| 40 | + * One pre-defined policy which accepts all cookies. | |
| 41 | + */ | |
| 42 | + public static final CookiePolicy ACCEPT_ALL = new CookiePolicy(){ | |
| 43 | + public boolean shouldAccept(URI uri, HttpCookie cookie) { | |
| 44 | + return true; | |
| 45 | + } | |
| 46 | + }; | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * One pre-defined policy which accepts no cookies. | |
| 50 | + */ | |
| 51 | + public static final CookiePolicy ACCEPT_NONE = new CookiePolicy(){ | |
| 52 | + public boolean shouldAccept(URI uri, HttpCookie cookie) { | |
| 53 | + return false; | |
| 54 | + } | |
| 55 | + }; | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * One pre-defined policy which only accepts cookies from original server. | |
| 59 | + */ | |
| 60 | + public static final CookiePolicy ACCEPT_ORIGINAL_SERVER = new CookiePolicy(){ | |
| 61 | + public boolean shouldAccept(URI uri, HttpCookie cookie) { | |
| 62 | + return HttpCookie.domainMatches(cookie.getDomain(), uri.getHost()); | |
| 63 | + } | |
| 64 | + }; | |
| 65 | + | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * Will be called to see whether or not this cookie should be accepted. | |
| 69 | + * | |
| 70 | + * @param uri the URI to consult accept policy with | |
| 71 | + * @param cookie the HttpCookie object in question | |
| 72 | + * @return <tt>true</tt> if this cookie should be accepted; | |
| 73 | + * otherwise, <tt>false</tt> | |
| 74 | + */ | |
| 75 | + public boolean shouldAccept(URI uri, HttpCookie cookie); | |
| 76 | +} | |
Binary file not shown.
| @@ -0,0 +1,127 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 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 java.net; | |
| 27 | + | |
| 28 | +import java.util.List; | |
| 29 | +import java.util.Map; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * A CookieStore object represents a storage for cookie. Can store and retrieve | |
| 33 | + * cookies. | |
| 34 | + * | |
| 35 | + * <p>{@link CookieManager} will call <tt>CookieStore.add</tt> to save cookies | |
| 36 | + * for every incoming HTTP response, and call <tt>CookieStore.get</tt> to | |
| 37 | + * retrieve cookie for every outgoing HTTP request. A CookieStore | |
| 38 | + * is responsible for removing HttpCookie instances which have expired. | |
| 39 | + * | |
| 40 | + * @author Edward Wang | |
| 41 | + * @since 1.6 | |
| 42 | + */ | |
| 43 | +public interface CookieStore { | |
| 44 | + /** | |
| 45 | + * Adds one HTTP cookie to the store. This is called for every | |
| 46 | + * incoming HTTP response. | |
| 47 | + * | |
| 48 | + * <p>A cookie to store may or may not be associated with an URI. If it | |
| 49 | + * is not associated with an URI, the cookie's domain and path attribute | |
| 50 | + * will indicate where it comes from. If it is associated with an URI and | |
| 51 | + * its domain and path attribute are not speicifed, given URI will indicate | |
| 52 | + * where this cookie comes from. | |
| 53 | + * | |
| 54 | + * <p>If a cookie corresponding to the given URI already exists, | |
| 55 | + * then it is replaced with the new one. | |
| 56 | + * | |
| 57 | + * @param uri the uri this cookie associated with. | |
| 58 | + * if <tt>null</tt>, this cookie will not be associated | |
| 59 | + * with an URI | |
| 60 | + * @param cookie the cookie to store | |
| 61 | + * | |
| 62 | + * @throws NullPointerException if <tt>cookie</tt> is <tt>null</tt> | |
| 63 | + * | |
| 64 | + * @see #get | |
| 65 | + * | |
| 66 | + */ | |
| 67 | + public void add(URI uri, HttpCookie cookie); | |
| 68 | + | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * Retrieve cookies associated with given URI, or whose domain matches the | |
| 72 | + * given URI. Only cookies that have not expired are returned. | |
| 73 | + * This is called for every outgoing HTTP request. | |
| 74 | + * | |
| 75 | + * @return an immutable list of HttpCookie, | |
| 76 | + * return empty list if no cookies match the given URI | |
| 77 | + * | |
| 78 | + * @throws NullPointerException if <tt>uri</tt> is <tt>null</tt> | |
| 79 | + * | |
| 80 | + * @see #add | |
| 81 | + * | |
| 82 | + */ | |
| 83 | + public List<HttpCookie> get(URI uri); | |
| 84 | + | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * Get all not-expired cookies in cookie store. | |
| 88 | + * | |
| 89 | + * @return an immutable list of http cookies; | |
| 90 | + * return empty list if there's no http cookie in store | |
| 91 | + */ | |
| 92 | + public List<HttpCookie> getCookies(); | |
| 93 | + | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * Get all URIs which identify the cookies in this cookie store. | |
| 97 | + * | |
| 98 | + * @return an immutable list of URIs; | |
| 99 | + * return empty list if no cookie in this cookie store | |
| 100 | + * is associated with an URI | |
| 101 | + */ | |
| 102 | + public List<URI> getURIs(); | |
| 103 | + | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * Remove a cookie from store. | |
| 107 | + * | |
| 108 | + * @param uri the uri this cookie associated with. | |
| 109 | + * if <tt>null</tt>, the cookie to be removed is not associated | |
| 110 | + * with an URI when added; if not <tt>null</tt>, the cookie | |
| 111 | + * to be removed is associated with the given URI when added. | |
| 112 | + * @param cookie the cookie to remove | |
| 113 | + * | |
| 114 | + * @return <tt>true</tt> if this store contained the specified cookie | |
| 115 | + * | |
| 116 | + * @throws NullPointerException if <tt>cookie</tt> is <tt>null</tt> | |
| 117 | + */ | |
| 118 | + public boolean remove(URI uri, HttpCookie cookie); | |
| 119 | + | |
| 120 | + | |
| 121 | + /** | |
| 122 | + * Remove all cookies in this cookie store. | |
| 123 | + * | |
| 124 | + * @return <tt>true</tt> if this store changed as a result of the call | |
| 125 | + */ | |
| 126 | + public boolean removeAll(); | |
| 127 | +} | |
Binary file not shown.
| @@ -0,0 +1,385 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2006, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class represents a datagram packet. | |
| 30 | + * <p> | |
| 31 | + * Datagram packets are used to implement a connectionless packet | |
| 32 | + * delivery service. Each message is routed from one machine to | |
| 33 | + * another based solely on information contained within that packet. | |
| 34 | + * Multiple packets sent from one machine to another might be routed | |
| 35 | + * differently, and might arrive in any order. Packet delivery is | |
| 36 | + * not guaranteed. | |
| 37 | + * | |
| 38 | + * @author Pavani Diwanji | |
| 39 | + * @author Benjamin Renaud | |
| 40 | + * @since JDK1.0 | |
| 41 | + */ | |
| 42 | +public final | |
| 43 | +class DatagramPacket { | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * Perform class initialization | |
| 47 | + */ | |
| 48 | + static { | |
| 49 | + java.security.AccessController.doPrivileged( | |
| 50 | + new sun.security.action.LoadLibraryAction("net")); | |
| 51 | + init(); | |
| 52 | + } | |
| 53 | + | |
| 54 | + /* | |
| 55 | + * The fields of this class are package-private since DatagramSocketImpl | |
| 56 | + * classes needs to access them. | |
| 57 | + */ | |
| 58 | + byte[] buf; | |
| 59 | + int offset; | |
| 60 | + int length; | |
| 61 | + int bufLength; | |
| 62 | + InetAddress address; | |
| 63 | + int port; | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * Constructs a <code>DatagramPacket</code> for receiving packets of | |
| 67 | + * length <code>length</code>, specifying an offset into the buffer. | |
| 68 | + * <p> | |
| 69 | + * The <code>length</code> argument must be less than or equal to | |
| 70 | + * <code>buf.length</code>. | |
| 71 | + * | |
| 72 | + * @param buf buffer for holding the incoming datagram. | |
| 73 | + * @param offset the offset for the buffer | |
| 74 | + * @param length the number of bytes to read. | |
| 75 | + * | |
| 76 | + * @since 1.2 | |
| 77 | + */ | |
| 78 | + public DatagramPacket(byte buf[], int offset, int length) { | |
| 79 | + setData(buf, offset, length); | |
| 80 | + this.address = null; | |
| 81 | + this.port = -1; | |
| 82 | + } | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * Constructs a <code>DatagramPacket</code> for receiving packets of | |
| 86 | + * length <code>length</code>. | |
| 87 | + * <p> | |
| 88 | + * The <code>length</code> argument must be less than or equal to | |
| 89 | + * <code>buf.length</code>. | |
| 90 | + * | |
| 91 | + * @param buf buffer for holding the incoming datagram. | |
| 92 | + * @param length the number of bytes to read. | |
| 93 | + */ | |
| 94 | + public DatagramPacket(byte buf[], int length) { | |
| 95 | + this (buf, 0, length); | |
| 96 | + } | |
| 97 | + | |
| 98 | + /** | |
| 99 | + * Constructs a datagram packet for sending packets of length | |
| 100 | + * <code>length</code> with offset <code>ioffset</code>to the | |
| 101 | + * specified port number on the specified host. The | |
| 102 | + * <code>length</code> argument must be less than or equal to | |
| 103 | + * <code>buf.length</code>. | |
| 104 | + * | |
| 105 | + * @param buf the packet data. | |
| 106 | + * @param offset the packet data offset. | |
| 107 | + * @param length the packet data length. | |
| 108 | + * @param address the destination address. | |
| 109 | + * @param port the destination port number. | |
| 110 | + * @see java.net.InetAddress | |
| 111 | + * | |
| 112 | + * @since 1.2 | |
| 113 | + */ | |
| 114 | + public DatagramPacket(byte buf[], int offset, int length, | |
| 115 | + InetAddress address, int port) { | |
| 116 | + setData(buf, offset, length); | |
| 117 | + setAddress(address); | |
| 118 | + setPort(port); | |
| 119 | + } | |
| 120 | + | |
| 121 | + /** | |
| 122 | + * Constructs a datagram packet for sending packets of length | |
| 123 | + * <code>length</code> with offset <code>ioffset</code>to the | |
| 124 | + * specified port number on the specified host. The | |
| 125 | + * <code>length</code> argument must be less than or equal to | |
| 126 | + * <code>buf.length</code>. | |
| 127 | + * | |
| 128 | + * @param buf the packet data. | |
| 129 | + * @param offset the packet data offset. | |
| 130 | + * @param length the packet data length. | |
| 131 | + * @param address the destination socket address. | |
| 132 | + * @throws IllegalArgumentException if address type is not supported | |
| 133 | + * @see java.net.InetAddress | |
| 134 | + * | |
| 135 | + * @since 1.4 | |
| 136 | + */ | |
| 137 | + public DatagramPacket(byte buf[], int offset, int length, | |
| 138 | + SocketAddress address) throws SocketException { | |
| 139 | + setData(buf, offset, length); | |
| 140 | + setSocketAddress(address); | |
| 141 | + } | |
| 142 | + | |
| 143 | + /** | |
| 144 | + * Constructs a datagram packet for sending packets of length | |
| 145 | + * <code>length</code> to the specified port number on the specified | |
| 146 | + * host. The <code>length</code> argument must be less than or equal | |
| 147 | + * to <code>buf.length</code>. | |
| 148 | + * | |
| 149 | + * @param buf the packet data. | |
| 150 | + * @param length the packet length. | |
| 151 | + * @param address the destination address. | |
| 152 | + * @param port the destination port number. | |
| 153 | + * @see java.net.InetAddress | |
| 154 | + */ | |
| 155 | + public DatagramPacket(byte buf[], int length, | |
| 156 | + InetAddress address, int port) { | |
| 157 | + this(buf, 0, length, address, port); | |
| 158 | + } | |
| 159 | + | |
| 160 | + /** | |
| 161 | + * Constructs a datagram packet for sending packets of length | |
| 162 | + * <code>length</code> to the specified port number on the specified | |
| 163 | + * host. The <code>length</code> argument must be less than or equal | |
| 164 | + * to <code>buf.length</code>. | |
| 165 | + * | |
| 166 | + * @param buf the packet data. | |
| 167 | + * @param length the packet length. | |
| 168 | + * @param address the destination address. | |
| 169 | + * @throws IllegalArgumentException if address type is not supported | |
| 170 | + * @since 1.4 | |
| 171 | + * @see java.net.InetAddress | |
| 172 | + */ | |
| 173 | + public DatagramPacket(byte buf[], int length, | |
| 174 | + SocketAddress address) throws SocketException { | |
| 175 | + this(buf, 0, length, address); | |
| 176 | + } | |
| 177 | + | |
| 178 | + /** | |
| 179 | + * Returns the IP address of the machine to which this datagram is being | |
| 180 | + * sent or from which the datagram was received. | |
| 181 | + * | |
| 182 | + * @return the IP address of the machine to which this datagram is being | |
| 183 | + * sent or from which the datagram was received. | |
| 184 | + * @see java.net.InetAddress | |
| 185 | + * @see #setAddress(java.net.InetAddress) | |
| 186 | + */ | |
| 187 | + public synchronized InetAddress getAddress() { | |
| 188 | + return address; | |
| 189 | + } | |
| 190 | + | |
| 191 | + /** | |
| 192 | + * Returns the port number on the remote host to which this datagram is | |
| 193 | + * being sent or from which the datagram was received. | |
| 194 | + * | |
| 195 | + * @return the port number on the remote host to which this datagram is | |
| 196 | + * being sent or from which the datagram was received. | |
| 197 | + * @see #setPort(int) | |
| 198 | + */ | |
| 199 | + public synchronized int getPort() { | |
| 200 | + return port; | |
| 201 | + } | |
| 202 | + | |
| 203 | + /** | |
| 204 | + * Returns the data buffer. The data received or the data to be sent | |
| 205 | + * starts from the <code>offset</code> in the buffer, | |
| 206 | + * and runs for <code>length</code> long. | |
| 207 | + * | |
| 208 | + * @return the buffer used to receive or send data | |
| 209 | + * @see #setData(byte[], int, int) | |
| 210 | + */ | |
| 211 | + public synchronized byte[] getData() { | |
| 212 | + return buf; | |
| 213 | + } | |
| 214 | + | |
| 215 | + /** | |
| 216 | + * Returns the offset of the data to be sent or the offset of the | |
| 217 | + * data received. | |
| 218 | + * | |
| 219 | + * @return the offset of the data to be sent or the offset of the | |
| 220 | + * data received. | |
| 221 | + * | |
| 222 | + * @since 1.2 | |
| 223 | + */ | |
| 224 | + public synchronized int getOffset() { | |
| 225 | + return offset; | |
| 226 | + } | |
| 227 | + | |
| 228 | + /** | |
| 229 | + * Returns the length of the data to be sent or the length of the | |
| 230 | + * data received. | |
| 231 | + * | |
| 232 | + * @return the length of the data to be sent or the length of the | |
| 233 | + * data received. | |
| 234 | + * @see #setLength(int) | |
| 235 | + */ | |
| 236 | + public synchronized int getLength() { | |
| 237 | + return length; | |
| 238 | + } | |
| 239 | + | |
| 240 | + /** | |
| 241 | + * Set the data buffer for this packet. This sets the | |
| 242 | + * data, length and offset of the packet. | |
| 243 | + * | |
| 244 | + * @param buf the buffer to set for this packet | |
| 245 | + * | |
| 246 | + * @param offset the offset into the data | |
| 247 | + * | |
| 248 | + * @param length the length of the data | |
| 249 | + * and/or the length of the buffer used to receive data | |
| 250 | + * | |
| 251 | + * @exception NullPointerException if the argument is null | |
| 252 | + * | |
| 253 | + * @see #getData | |
| 254 | + * @see #getOffset | |
| 255 | + * @see #getLength | |
| 256 | + * | |
| 257 | + * @since 1.2 | |
| 258 | + */ | |
| 259 | + public synchronized void setData(byte[] buf, int offset, int length) { | |
| 260 | + /* this will check to see if buf is null */ | |
| 261 | + if (length < 0 || offset < 0 || | |
| 262 | + (length + offset) < 0 || | |
| 263 | + ((length + offset) > buf.length)) { | |
| 264 | + throw new IllegalArgumentException("illegal length or offset"); | |
| 265 | + } | |
| 266 | + this.buf = buf; | |
| 267 | + this.length = length; | |
| 268 | + this.bufLength = length; | |
| 269 | + this.offset = offset; | |
| 270 | + } | |
| 271 | + | |
| 272 | + /** | |
| 273 | + * Sets the IP address of the machine to which this datagram | |
| 274 | + * is being sent. | |
| 275 | + * @param iaddr the <code>InetAddress</code> | |
| 276 | + * @since JDK1.1 | |
| 277 | + * @see #getAddress() | |
| 278 | + */ | |
| 279 | + public synchronized void setAddress(InetAddress iaddr) { | |
| 280 | + address = iaddr; | |
| 281 | + } | |
| 282 | + | |
| 283 | + /** | |
| 284 | + * Sets the port number on the remote host to which this datagram | |
| 285 | + * is being sent. | |
| 286 | + * @param iport the port number | |
| 287 | + * @since JDK1.1 | |
| 288 | + * @see #getPort() | |
| 289 | + */ | |
| 290 | + public synchronized void setPort(int iport) { | |
| 291 | + if (iport < 0 || iport > 0xFFFF) { | |
| 292 | + throw new IllegalArgumentException("Port out of range:"+ iport); | |
| 293 | + } | |
| 294 | + port = iport; | |
| 295 | + } | |
| 296 | + | |
| 297 | + /** | |
| 298 | + * Sets the SocketAddress (usually IP address + port number) of the remote | |
| 299 | + * host to which this datagram is being sent. | |
| 300 | + * | |
| 301 | + * @param address the <code>SocketAddress</code> | |
| 302 | + * @throws IllegalArgumentException if address is null or is a | |
| 303 | + * SocketAddress subclass not supported by this socket | |
| 304 | + * | |
| 305 | + * @since 1.4 | |
| 306 | + * @see #getSocketAddress | |
| 307 | + */ | |
| 308 | + public synchronized void setSocketAddress(SocketAddress address) { | |
| 309 | + if (address == null || !(address instanceof InetSocketAddress)) | |
| 310 | + throw new IllegalArgumentException("unsupported address type"); | |
| 311 | + InetSocketAddress addr = (InetSocketAddress) address; | |
| 312 | + if (addr.isUnresolved()) | |
| 313 | + throw new IllegalArgumentException("unresolved address"); | |
| 314 | + setAddress(addr.getAddress()); | |
| 315 | + setPort(addr.getPort()); | |
| 316 | + } | |
| 317 | + | |
| 318 | + /** | |
| 319 | + * Gets the SocketAddress (usually IP address + port number) of the remote | |
| 320 | + * host that this packet is being sent to or is coming from. | |
| 321 | + * | |
| 322 | + * @return the <code>SocketAddress</code> | |
| 323 | + * @since 1.4 | |
| 324 | + * @see #setSocketAddress | |
| 325 | + */ | |
| 326 | + public synchronized SocketAddress getSocketAddress() { | |
| 327 | + return new InetSocketAddress(getAddress(), getPort()); | |
| 328 | + } | |
| 329 | + | |
| 330 | + /** | |
| 331 | + * Set the data buffer for this packet. With the offset of | |
| 332 | + * this DatagramPacket set to 0, and the length set to | |
| 333 | + * the length of <code>buf</code>. | |
| 334 | + * | |
| 335 | + * @param buf the buffer to set for this packet. | |
| 336 | + * | |
| 337 | + * @exception NullPointerException if the argument is null. | |
| 338 | + * | |
| 339 | + * @see #getLength | |
| 340 | + * @see #getData | |
| 341 | + * | |
| 342 | + * @since JDK1.1 | |
| 343 | + */ | |
| 344 | + public synchronized void setData(byte[] buf) { | |
| 345 | + if (buf == null) { | |
| 346 | + throw new NullPointerException("null packet buffer"); | |
| 347 | + } | |
| 348 | + this.buf = buf; | |
| 349 | + this.offset = 0; | |
| 350 | + this.length = buf.length; | |
| 351 | + this.bufLength = buf.length; | |
| 352 | + } | |
| 353 | + | |
| 354 | + /** | |
| 355 | + * Set the length for this packet. The length of the packet is | |
| 356 | + * the number of bytes from the packet's data buffer that will be | |
| 357 | + * sent, or the number of bytes of the packet's data buffer that | |
| 358 | + * will be used for receiving data. The length must be lesser or | |
| 359 | + * equal to the offset plus the length of the packet's buffer. | |
| 360 | + * | |
| 361 | + * @param length the length to set for this packet. | |
| 362 | + * | |
| 363 | + * @exception IllegalArgumentException if the length is negative | |
| 364 | + * of if the length is greater than the packet's data buffer | |
| 365 | + * length. | |
| 366 | + * | |
| 367 | + * @see #getLength | |
| 368 | + * @see #setData | |
| 369 | + * | |
| 370 | + * @since JDK1.1 | |
| 371 | + */ | |
| 372 | + public synchronized void setLength(int length) { | |
| 373 | + if ((length + offset) > buf.length || length < 0 || | |
| 374 | + (length + offset) < 0) { | |
| 375 | + throw new IllegalArgumentException("illegal length"); | |
| 376 | + } | |
| 377 | + this.length = length; | |
| 378 | + this.bufLength = this.length; | |
| 379 | + } | |
| 380 | + | |
| 381 | + /** | |
| 382 | + * Perform class load-time initializations. | |
| 383 | + */ | |
| 384 | + private native static void init(); | |
| 385 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,1257 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2010, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.FileDescriptor; | |
| 29 | +import java.io.IOException; | |
| 30 | +import java.io.InterruptedIOException; | |
| 31 | +import java.nio.channels.DatagramChannel; | |
| 32 | +import java.security.AccessController; | |
| 33 | +import java.security.PrivilegedExceptionAction; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * This class represents a socket for sending and receiving datagram packets. | |
| 37 | + * | |
| 38 | + * <p>A datagram socket is the sending or receiving point for a packet | |
| 39 | + * delivery service. Each packet sent or received on a datagram socket | |
| 40 | + * is individually addressed and routed. Multiple packets sent from | |
| 41 | + * one machine to another may be routed differently, and may arrive in | |
| 42 | + * any order. | |
| 43 | + * | |
| 44 | + * <p> Where possible, a newly constructed {@code DatagramSocket} has the | |
| 45 | + * {@link SocketOptions#SO_BROADCAST SO_BROADCAST} socket option enabled so as | |
| 46 | + * to allow the transmission of broadcast datagrams. In order to receive | |
| 47 | + * broadcast packets a DatagramSocket should be bound to the wildcard address. | |
| 48 | + * In some implementations, broadcast packets may also be received when | |
| 49 | + * a DatagramSocket is bound to a more specific address. | |
| 50 | + * <p> | |
| 51 | + * Example: | |
| 52 | + * <code> | |
| 53 | + * DatagramSocket s = new DatagramSocket(null); | |
| 54 | + * s.bind(new InetSocketAddress(8888)); | |
| 55 | + * </code> | |
| 56 | + * Which is equivalent to: | |
| 57 | + * <code> | |
| 58 | + * DatagramSocket s = new DatagramSocket(8888); | |
| 59 | + * </code> | |
| 60 | + * Both cases will create a DatagramSocket able to receive broadcasts on | |
| 61 | + * UDP port 8888. | |
| 62 | + * | |
| 63 | + * @author Pavani Diwanji | |
| 64 | + * @see java.net.DatagramPacket | |
| 65 | + * @see java.nio.channels.DatagramChannel | |
| 66 | + * @since JDK1.0 | |
| 67 | + */ | |
| 68 | +public | |
| 69 | +class DatagramSocket implements java.io.Closeable { | |
| 70 | + /** | |
| 71 | + * Various states of this socket. | |
| 72 | + */ | |
| 73 | + private boolean created = false; | |
| 74 | + private boolean bound = false; | |
| 75 | + private boolean closed = false; | |
| 76 | + private Object closeLock = new Object(); | |
| 77 | + | |
| 78 | + /* | |
| 79 | + * The implementation of this DatagramSocket. | |
| 80 | + */ | |
| 81 | + DatagramSocketImpl impl; | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * Are we using an older DatagramSocketImpl? | |
| 85 | + */ | |
| 86 | + boolean oldImpl = false; | |
| 87 | + | |
| 88 | + /* | |
| 89 | + * Connection state: | |
| 90 | + * ST_NOT_CONNECTED = socket not connected | |
| 91 | + * ST_CONNECTED = socket connected | |
| 92 | + * ST_CONNECTED_NO_IMPL = socket connected but not at impl level | |
| 93 | + */ | |
| 94 | + static final int ST_NOT_CONNECTED = 0; | |
| 95 | + static final int ST_CONNECTED = 1; | |
| 96 | + static final int ST_CONNECTED_NO_IMPL = 2; | |
| 97 | + | |
| 98 | + int connectState = ST_NOT_CONNECTED; | |
| 99 | + | |
| 100 | + /* | |
| 101 | + * Connected address & port | |
| 102 | + */ | |
| 103 | + InetAddress connectedAddress = null; | |
| 104 | + int connectedPort = -1; | |
| 105 | + | |
| 106 | + /** | |
| 107 | + * Connects this socket to a remote socket address (IP address + port number). | |
| 108 | + * Binds socket if not already bound. | |
| 109 | + * <p> | |
| 110 | + * @param addr The remote address. | |
| 111 | + * @param port The remote port | |
| 112 | + * @throws SocketException if binding the socket fails. | |
| 113 | + */ | |
| 114 | + private synchronized void connectInternal(InetAddress address, int port) throws SocketException { | |
| 115 | + if (port < 0 || port > 0xFFFF) { | |
| 116 | + throw new IllegalArgumentException("connect: " + port); | |
| 117 | + } | |
| 118 | + if (address == null) { | |
| 119 | + throw new IllegalArgumentException("connect: null address"); | |
| 120 | + } | |
| 121 | + checkAddress (address, "connect"); | |
| 122 | + if (isClosed()) | |
| 123 | + return; | |
| 124 | + SecurityManager security = System.getSecurityManager(); | |
| 125 | + if (security != null) { | |
| 126 | + if (address.isMulticastAddress()) { | |
| 127 | + security.checkMulticast(address); | |
| 128 | + } else { | |
| 129 | + security.checkConnect(address.getHostAddress(), port); | |
| 130 | + security.checkAccept(address.getHostAddress(), port); | |
| 131 | + } | |
| 132 | + } | |
| 133 | + | |
| 134 | + if (!isBound()) | |
| 135 | + bind(new InetSocketAddress(0)); | |
| 136 | + | |
| 137 | + // old impls do not support connect/disconnect | |
| 138 | + if (oldImpl) { | |
| 139 | + connectState = ST_CONNECTED_NO_IMPL; | |
| 140 | + } else { | |
| 141 | + try { | |
| 142 | + getImpl().connect(address, port); | |
| 143 | + | |
| 144 | + // socket is now connected by the impl | |
| 145 | + connectState = ST_CONNECTED; | |
| 146 | + } catch (SocketException se) { | |
| 147 | + | |
| 148 | + // connection will be emulated by DatagramSocket | |
| 149 | + connectState = ST_CONNECTED_NO_IMPL; | |
| 150 | + } | |
| 151 | + } | |
| 152 | + | |
| 153 | + connectedAddress = address; | |
| 154 | + connectedPort = port; | |
| 155 | + } | |
| 156 | + | |
| 157 | + | |
| 158 | + /** | |
| 159 | + * Constructs a datagram socket and binds it to any available port | |
| 160 | + * on the local host machine. The socket will be bound to the | |
| 161 | + * {@link InetAddress#isAnyLocalAddress wildcard} address, | |
| 162 | + * an IP address chosen by the kernel. | |
| 163 | + * | |
| 164 | + * <p>If there is a security manager, | |
| 165 | + * its <code>checkListen</code> method is first called | |
| 166 | + * with 0 as its argument to ensure the operation is allowed. | |
| 167 | + * This could result in a SecurityException. | |
| 168 | + * | |
| 169 | + * @exception SocketException if the socket could not be opened, | |
| 170 | + * or the socket could not bind to the specified local port. | |
| 171 | + * @exception SecurityException if a security manager exists and its | |
| 172 | + * <code>checkListen</code> method doesn't allow the operation. | |
| 173 | + * | |
| 174 | + * @see SecurityManager#checkListen | |
| 175 | + */ | |
| 176 | + public DatagramSocket() throws SocketException { | |
| 177 | + // create a datagram socket. | |
| 178 | + createImpl(); | |
| 179 | + try { | |
| 180 | + bind(new InetSocketAddress(0)); | |
| 181 | + } catch (SocketException se) { | |
| 182 | + throw se; | |
| 183 | + } catch(IOException e) { | |
| 184 | + throw new SocketException(e.getMessage()); | |
| 185 | + } | |
| 186 | + } | |
| 187 | + | |
| 188 | + /** | |
| 189 | + * Creates an unbound datagram socket with the specified | |
| 190 | + * DatagramSocketImpl. | |
| 191 | + * | |
| 192 | + * @param impl an instance of a <B>DatagramSocketImpl</B> | |
| 193 | + * the subclass wishes to use on the DatagramSocket. | |
| 194 | + * @since 1.4 | |
| 195 | + */ | |
| 196 | + protected DatagramSocket(DatagramSocketImpl impl) { | |
| 197 | + if (impl == null) | |
| 198 | + throw new NullPointerException(); | |
| 199 | + this.impl = impl; | |
| 200 | + checkOldImpl(); | |
| 201 | + } | |
| 202 | + | |
| 203 | + /** | |
| 204 | + * Creates a datagram socket, bound to the specified local | |
| 205 | + * socket address. | |
| 206 | + * <p> | |
| 207 | + * If, if the address is <code>null</code>, creates an unbound socket. | |
| 208 | + * <p> | |
| 209 | + * <p>If there is a security manager, | |
| 210 | + * its <code>checkListen</code> method is first called | |
| 211 | + * with the port from the socket address | |
| 212 | + * as its argument to ensure the operation is allowed. | |
| 213 | + * This could result in a SecurityException. | |
| 214 | + * | |
| 215 | + * @param bindaddr local socket address to bind, or <code>null</code> | |
| 216 | + * for an unbound socket. | |
| 217 | + * | |
| 218 | + * @exception SocketException if the socket could not be opened, | |
| 219 | + * or the socket could not bind to the specified local port. | |
| 220 | + * @exception SecurityException if a security manager exists and its | |
| 221 | + * <code>checkListen</code> method doesn't allow the operation. | |
| 222 | + * | |
| 223 | + * @see SecurityManager#checkListen | |
| 224 | + * @since 1.4 | |
| 225 | + */ | |
| 226 | + public DatagramSocket(SocketAddress bindaddr) throws SocketException { | |
| 227 | + // create a datagram socket. | |
| 228 | + createImpl(); | |
| 229 | + if (bindaddr != null) { | |
| 230 | + bind(bindaddr); | |
| 231 | + } | |
| 232 | + } | |
| 233 | + | |
| 234 | + /** | |
| 235 | + * Constructs a datagram socket and binds it to the specified port | |
| 236 | + * on the local host machine. The socket will be bound to the | |
| 237 | + * {@link InetAddress#isAnyLocalAddress wildcard} address, | |
| 238 | + * an IP address chosen by the kernel. | |
| 239 | + * | |
| 240 | + * <p>If there is a security manager, | |
| 241 | + * its <code>checkListen</code> method is first called | |
| 242 | + * with the <code>port</code> argument | |
| 243 | + * as its argument to ensure the operation is allowed. | |
| 244 | + * This could result in a SecurityException. | |
| 245 | + * | |
| 246 | + * @param port port to use. | |
| 247 | + * @exception SocketException if the socket could not be opened, | |
| 248 | + * or the socket could not bind to the specified local port. | |
| 249 | + * @exception SecurityException if a security manager exists and its | |
| 250 | + * <code>checkListen</code> method doesn't allow the operation. | |
| 251 | + * | |
| 252 | + * @see SecurityManager#checkListen | |
| 253 | + */ | |
| 254 | + public DatagramSocket(int port) throws SocketException { | |
| 255 | + this(port, null); | |
| 256 | + } | |
| 257 | + | |
| 258 | + /** | |
| 259 | + * Creates a datagram socket, bound to the specified local | |
| 260 | + * address. The local port must be between 0 and 65535 inclusive. | |
| 261 | + * If the IP address is 0.0.0.0, the socket will be bound to the | |
| 262 | + * {@link InetAddress#isAnyLocalAddress wildcard} address, | |
| 263 | + * an IP address chosen by the kernel. | |
| 264 | + * | |
| 265 | + * <p>If there is a security manager, | |
| 266 | + * its <code>checkListen</code> method is first called | |
| 267 | + * with the <code>port</code> argument | |
| 268 | + * as its argument to ensure the operation is allowed. | |
| 269 | + * This could result in a SecurityException. | |
| 270 | + * | |
| 271 | + * @param port local port to use | |
| 272 | + * @param laddr local address to bind | |
| 273 | + * | |
| 274 | + * @exception SocketException if the socket could not be opened, | |
| 275 | + * or the socket could not bind to the specified local port. | |
| 276 | + * @exception SecurityException if a security manager exists and its | |
| 277 | + * <code>checkListen</code> method doesn't allow the operation. | |
| 278 | + * | |
| 279 | + * @see SecurityManager#checkListen | |
| 280 | + * @since JDK1.1 | |
| 281 | + */ | |
| 282 | + public DatagramSocket(int port, InetAddress laddr) throws SocketException { | |
| 283 | + this(new InetSocketAddress(laddr, port)); | |
| 284 | + } | |
| 285 | + | |
| 286 | + private void checkOldImpl() { | |
| 287 | + if (impl == null) | |
| 288 | + return; | |
| 289 | + // DatagramSocketImpl.peekdata() is a protected method, therefore we need to use | |
| 290 | + // getDeclaredMethod, therefore we need permission to access the member | |
| 291 | + try { | |
| 292 | + AccessController.doPrivileged( | |
| 293 | + new PrivilegedExceptionAction<Void>() { | |
| 294 | + public Void run() throws NoSuchMethodException { | |
| 295 | + Class[] cl = new Class[1]; | |
| 296 | + cl[0] = DatagramPacket.class; | |
| 297 | + impl.getClass().getDeclaredMethod("peekData", cl); | |
| 298 | + return null; | |
| 299 | + } | |
| 300 | + }); | |
| 301 | + } catch (java.security.PrivilegedActionException e) { | |
| 302 | + oldImpl = true; | |
| 303 | + } | |
| 304 | + } | |
| 305 | + | |
| 306 | + static Class implClass = null; | |
| 307 | + | |
| 308 | + void createImpl() throws SocketException { | |
| 309 | + if (impl == null) { | |
| 310 | + if (factory != null) { | |
| 311 | + impl = factory.createDatagramSocketImpl(); | |
| 312 | + checkOldImpl(); | |
| 313 | + } else { | |
| 314 | + boolean isMulticast = (this instanceof MulticastSocket) ? true : false; | |
| 315 | + impl = DefaultDatagramSocketImplFactory.createDatagramSocketImpl(isMulticast); | |
| 316 | + | |
| 317 | + checkOldImpl(); | |
| 318 | + } | |
| 319 | + } | |
| 320 | + // creates a udp socket | |
| 321 | + impl.create(); | |
| 322 | + created = true; | |
| 323 | + } | |
| 324 | + | |
| 325 | + /** | |
| 326 | + * Get the <code>DatagramSocketImpl</code> attached to this socket, | |
| 327 | + * creating it if necessary. | |
| 328 | + * | |
| 329 | + * @return the <code>DatagramSocketImpl</code> attached to that | |
| 330 | + * DatagramSocket | |
| 331 | + * @throws SocketException if creation fails. | |
| 332 | + * @since 1.4 | |
| 333 | + */ | |
| 334 | + DatagramSocketImpl getImpl() throws SocketException { | |
| 335 | + if (!created) | |
| 336 | + createImpl(); | |
| 337 | + return impl; | |
| 338 | + } | |
| 339 | + | |
| 340 | + /** | |
| 341 | + * Binds this DatagramSocket to a specific address & port. | |
| 342 | + * <p> | |
| 343 | + * If the address is <code>null</code>, then the system will pick up | |
| 344 | + * an ephemeral port and a valid local address to bind the socket. | |
| 345 | + *<p> | |
| 346 | + * @param addr The address & port to bind to. | |
| 347 | + * @throws SocketException if any error happens during the bind, or if the | |
| 348 | + * socket is already bound. | |
| 349 | + * @throws SecurityException if a security manager exists and its | |
| 350 | + * <code>checkListen</code> method doesn't allow the operation. | |
| 351 | + * @throws IllegalArgumentException if addr is a SocketAddress subclass | |
| 352 | + * not supported by this socket. | |
| 353 | + * @since 1.4 | |
| 354 | + */ | |
| 355 | + public synchronized void bind(SocketAddress addr) throws SocketException { | |
| 356 | + if (isClosed()) | |
| 357 | + throw new SocketException("Socket is closed"); | |
| 358 | + if (isBound()) | |
| 359 | + throw new SocketException("already bound"); | |
| 360 | + if (addr == null) | |
| 361 | + addr = new InetSocketAddress(0); | |
| 362 | + if (!(addr instanceof InetSocketAddress)) | |
| 363 | + throw new IllegalArgumentException("Unsupported address type!"); | |
| 364 | + InetSocketAddress epoint = (InetSocketAddress) addr; | |
| 365 | + if (epoint.isUnresolved()) | |
| 366 | + throw new SocketException("Unresolved address"); | |
| 367 | + InetAddress iaddr = epoint.getAddress(); | |
| 368 | + int port = epoint.getPort(); | |
| 369 | + checkAddress(iaddr, "bind"); | |
| 370 | + SecurityManager sec = System.getSecurityManager(); | |
| 371 | + if (sec != null) { | |
| 372 | + sec.checkListen(port); | |
| 373 | + } | |
| 374 | + try { | |
| 375 | + getImpl().bind(port, iaddr); | |
| 376 | + } catch (SocketException e) { | |
| 377 | + getImpl().close(); | |
| 378 | + throw e; | |
| 379 | + } | |
| 380 | + bound = true; | |
| 381 | + } | |
| 382 | + | |
| 383 | + void checkAddress (InetAddress addr, String op) { | |
| 384 | + if (addr == null) { | |
| 385 | + return; | |
| 386 | + } | |
| 387 | + if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) { | |
| 388 | + throw new IllegalArgumentException(op + ": invalid address type"); | |
| 389 | + } | |
| 390 | + } | |
| 391 | + | |
| 392 | + /** | |
| 393 | + * Connects the socket to a remote address for this socket. When a | |
| 394 | + * socket is connected to a remote address, packets may only be | |
| 395 | + * sent to or received from that address. By default a datagram | |
| 396 | + * socket is not connected. | |
| 397 | + * | |
| 398 | + * <p>If the remote destination to which the socket is connected does not | |
| 399 | + * exist, or is otherwise unreachable, and if an ICMP destination unreachable | |
| 400 | + * packet has been received for that address, then a subsequent call to | |
| 401 | + * send or receive may throw a PortUnreachableException. Note, there is no | |
| 402 | + * guarantee that the exception will be thrown. | |
| 403 | + * | |
| 404 | + * <p> If a security manager has been installed then it is invoked to check | |
| 405 | + * access to the remote address. Specifically, if the given {@code address} | |
| 406 | + * is a {@link InetAddress#isMulticastAddress multicast address}, | |
| 407 | + * the security manager's {@link | |
| 408 | + * java.lang.SecurityManager#checkMulticast(InetAddress) | |
| 409 | + * checkMulticast} method is invoked with the given {@code address}. | |
| 410 | + * Otherwise, the security manager's {@link | |
| 411 | + * java.lang.SecurityManager#checkConnect(String,int) checkConnect} | |
| 412 | + * and {@link java.lang.SecurityManager#checkAccept checkAccept} methods | |
| 413 | + * are invoked, with the given {@code address} and {@code port}, to | |
| 414 | + * verify that datagrams are permitted to be sent and received | |
| 415 | + * respectively. | |
| 416 | + * | |
| 417 | + * <p> When a socket is connected, {@link #receive receive} and | |
| 418 | + * {@link #send send} <b>will not perform any security checks</b> | |
| 419 | + * on incoming and outgoing packets, other than matching the packet's | |
| 420 | + * and the socket's address and port. On a send operation, if the | |
| 421 | + * packet's address is set and the packet's address and the socket's | |
| 422 | + * address do not match, an {@code IllegalArgumentException} will be | |
| 423 | + * thrown. A socket connected to a multicast address may only be used | |
| 424 | + * to send packets. | |
| 425 | + * | |
| 426 | + * @param address the remote address for the socket | |
| 427 | + * | |
| 428 | + * @param port the remote port for the socket. | |
| 429 | + * | |
| 430 | + * @throws IllegalArgumentException | |
| 431 | + * if the address is null, or the port is out of range. | |
| 432 | + * | |
| 433 | + * @throws SecurityException | |
| 434 | + * if a security manager has been installed and it does | |
| 435 | + * not permit access to the given remote address | |
| 436 | + * | |
| 437 | + * @see #disconnect | |
| 438 | + */ | |
| 439 | + public void connect(InetAddress address, int port) { | |
| 440 | + try { | |
| 441 | + connectInternal(address, port); | |
| 442 | + } catch (SocketException se) { | |
| 443 | + throw new Error("connect failed", se); | |
| 444 | + } | |
| 445 | + } | |
| 446 | + | |
| 447 | + /** | |
| 448 | + * Connects this socket to a remote socket address (IP address + port number). | |
| 449 | + * | |
| 450 | + * <p> If given an {@link InetSocketAddress InetSocketAddress}, this method | |
| 451 | + * behaves as if invoking {@link #connect(InetAddress,int) connect(InetAddress,int)} | |
| 452 | + * with the the given socket addresses IP address and port number. | |
| 453 | + * | |
| 454 | + * @param addr The remote address. | |
| 455 | + * | |
| 456 | + * @throws SocketException | |
| 457 | + * if the connect fails | |
| 458 | + * | |
| 459 | + * @throws IllegalArgumentException | |
| 460 | + * if {@code addr} is {@code null}, or {@code addr} is a SocketAddress | |
| 461 | + * subclass not supported by this socket | |
| 462 | + * | |
| 463 | + * @throws SecurityException | |
| 464 | + * if a security manager has been installed and it does | |
| 465 | + * not permit access to the given remote address | |
| 466 | + * | |
| 467 | + * @since 1.4 | |
| 468 | + */ | |
| 469 | + public void connect(SocketAddress addr) throws SocketException { | |
| 470 | + if (addr == null) | |
| 471 | + throw new IllegalArgumentException("Address can't be null"); | |
| 472 | + if (!(addr instanceof InetSocketAddress)) | |
| 473 | + throw new IllegalArgumentException("Unsupported address type"); | |
| 474 | + InetSocketAddress epoint = (InetSocketAddress) addr; | |
| 475 | + if (epoint.isUnresolved()) | |
| 476 | + throw new SocketException("Unresolved address"); | |
| 477 | + connectInternal(epoint.getAddress(), epoint.getPort()); | |
| 478 | + } | |
| 479 | + | |
| 480 | + /** | |
| 481 | + * Disconnects the socket. If the socket is closed or not connected, | |
| 482 | + * then this method has no effect. | |
| 483 | + * | |
| 484 | + * @see #connect | |
| 485 | + */ | |
| 486 | + public void disconnect() { | |
| 487 | + synchronized (this) { | |
| 488 | + if (isClosed()) | |
| 489 | + return; | |
| 490 | + if (connectState == ST_CONNECTED) { | |
| 491 | + impl.disconnect (); | |
| 492 | + } | |
| 493 | + connectedAddress = null; | |
| 494 | + connectedPort = -1; | |
| 495 | + connectState = ST_NOT_CONNECTED; | |
| 496 | + } | |
| 497 | + } | |
| 498 | + | |
| 499 | + /** | |
| 500 | + * Returns the binding state of the socket. | |
| 501 | + * <p> | |
| 502 | + * If the socket was bound prior to being {@link #close closed}, | |
| 503 | + * then this method will continue to return <code>true</code> | |
| 504 | + * after the socket is closed. | |
| 505 | + * | |
| 506 | + * @return true if the socket successfully bound to an address | |
| 507 | + * @since 1.4 | |
| 508 | + */ | |
| 509 | + public boolean isBound() { | |
| 510 | + return bound; | |
| 511 | + } | |
| 512 | + | |
| 513 | + /** | |
| 514 | + * Returns the connection state of the socket. | |
| 515 | + * <p> | |
| 516 | + * If the socket was connected prior to being {@link #close closed}, | |
| 517 | + * then this method will continue to return <code>true</code> | |
| 518 | + * after the socket is closed. | |
| 519 | + * | |
| 520 | + * @return true if the socket successfully connected to a server | |
| 521 | + * @since 1.4 | |
| 522 | + */ | |
| 523 | + public boolean isConnected() { | |
| 524 | + return connectState != ST_NOT_CONNECTED; | |
| 525 | + } | |
| 526 | + | |
| 527 | + /** | |
| 528 | + * Returns the address to which this socket is connected. Returns | |
| 529 | + * <code>null</code> if the socket is not connected. | |
| 530 | + * <p> | |
| 531 | + * If the socket was connected prior to being {@link #close closed}, | |
| 532 | + * then this method will continue to return the connected address | |
| 533 | + * after the socket is closed. | |
| 534 | + * | |
| 535 | + * @return the address to which this socket is connected. | |
| 536 | + */ | |
| 537 | + public InetAddress getInetAddress() { | |
| 538 | + return connectedAddress; | |
| 539 | + } | |
| 540 | + | |
| 541 | + /** | |
| 542 | + * Returns the port number to which this socket is connected. | |
| 543 | + * Returns <code>-1</code> if the socket is not connected. | |
| 544 | + * <p> | |
| 545 | + * If the socket was connected prior to being {@link #close closed}, | |
| 546 | + * then this method will continue to return the connected port number | |
| 547 | + * after the socket is closed. | |
| 548 | + * | |
| 549 | + * @return the port number to which this socket is connected. | |
| 550 | + */ | |
| 551 | + public int getPort() { | |
| 552 | + return connectedPort; | |
| 553 | + } | |
| 554 | + | |
| 555 | + /** | |
| 556 | + * Returns the address of the endpoint this socket is connected to, or | |
| 557 | + * <code>null</code> if it is unconnected. | |
| 558 | + * <p> | |
| 559 | + * If the socket was connected prior to being {@link #close closed}, | |
| 560 | + * then this method will continue to return the connected address | |
| 561 | + * after the socket is closed. | |
| 562 | + * | |
| 563 | + * @return a <code>SocketAddress</code> representing the remote | |
| 564 | + * endpoint of this socket, or <code>null</code> if it is | |
| 565 | + * not connected yet. | |
| 566 | + * @see #getInetAddress() | |
| 567 | + * @see #getPort() | |
| 568 | + * @see #connect(SocketAddress) | |
| 569 | + * @since 1.4 | |
| 570 | + */ | |
| 571 | + public SocketAddress getRemoteSocketAddress() { | |
| 572 | + if (!isConnected()) | |
| 573 | + return null; | |
| 574 | + return new InetSocketAddress(getInetAddress(), getPort()); | |
| 575 | + } | |
| 576 | + | |
| 577 | + /** | |
| 578 | + * Returns the address of the endpoint this socket is bound to. | |
| 579 | + * | |
| 580 | + * @return a <code>SocketAddress</code> representing the local endpoint of this | |
| 581 | + * socket, or <code>null</code> if it is closed or not bound yet. | |
| 582 | + * @see #getLocalAddress() | |
| 583 | + * @see #getLocalPort() | |
| 584 | + * @see #bind(SocketAddress) | |
| 585 | + * @since 1.4 | |
| 586 | + */ | |
| 587 | + | |
| 588 | + public SocketAddress getLocalSocketAddress() { | |
| 589 | + if (isClosed()) | |
| 590 | + return null; | |
| 591 | + if (!isBound()) | |
| 592 | + return null; | |
| 593 | + return new InetSocketAddress(getLocalAddress(), getLocalPort()); | |
| 594 | + } | |
| 595 | + | |
| 596 | + /** | |
| 597 | + * Sends a datagram packet from this socket. The | |
| 598 | + * <code>DatagramPacket</code> includes information indicating the | |
| 599 | + * data to be sent, its length, the IP address of the remote host, | |
| 600 | + * and the port number on the remote host. | |
| 601 | + * | |
| 602 | + * <p>If there is a security manager, and the socket is not currently | |
| 603 | + * connected to a remote address, this method first performs some | |
| 604 | + * security checks. First, if <code>p.getAddress().isMulticastAddress()</code> | |
| 605 | + * is true, this method calls the | |
| 606 | + * security manager's <code>checkMulticast</code> method | |
| 607 | + * with <code>p.getAddress()</code> as its argument. | |
| 608 | + * If the evaluation of that expression is false, | |
| 609 | + * this method instead calls the security manager's | |
| 610 | + * <code>checkConnect</code> method with arguments | |
| 611 | + * <code>p.getAddress().getHostAddress()</code> and | |
| 612 | + * <code>p.getPort()</code>. Each call to a security manager method | |
| 613 | + * could result in a SecurityException if the operation is not allowed. | |
| 614 | + * | |
| 615 | + * @param p the <code>DatagramPacket</code> to be sent. | |
| 616 | + * | |
| 617 | + * @exception IOException if an I/O error occurs. | |
| 618 | + * @exception SecurityException if a security manager exists and its | |
| 619 | + * <code>checkMulticast</code> or <code>checkConnect</code> | |
| 620 | + * method doesn't allow the send. | |
| 621 | + * @exception PortUnreachableException may be thrown if the socket is connected | |
| 622 | + * to a currently unreachable destination. Note, there is no | |
| 623 | + * guarantee that the exception will be thrown. | |
| 624 | + * @exception java.nio.channels.IllegalBlockingModeException | |
| 625 | + * if this socket has an associated channel, | |
| 626 | + * and the channel is in non-blocking mode. | |
| 627 | + * @exception IllegalArgumentException if the socket is connected, | |
| 628 | + * and connected address and packet address differ. | |
| 629 | + * | |
| 630 | + * @see java.net.DatagramPacket | |
| 631 | + * @see SecurityManager#checkMulticast(InetAddress) | |
| 632 | + * @see SecurityManager#checkConnect | |
| 633 | + * @revised 1.4 | |
| 634 | + * @spec JSR-51 | |
| 635 | + */ | |
| 636 | + public void send(DatagramPacket p) throws IOException { | |
| 637 | + InetAddress packetAddress = null; | |
| 638 | + synchronized (p) { | |
| 639 | + if (isClosed()) | |
| 640 | + throw new SocketException("Socket is closed"); | |
| 641 | + checkAddress (p.getAddress(), "send"); | |
| 642 | + if (connectState == ST_NOT_CONNECTED) { | |
| 643 | + // check the address is ok wiht the security manager on every send. | |
| 644 | + SecurityManager security = System.getSecurityManager(); | |
| 645 | + | |
| 646 | + // The reason you want to synchronize on datagram packet | |
| 647 | + // is because you dont want an applet to change the address | |
| 648 | + // while you are trying to send the packet for example | |
| 649 | + // after the security check but before the send. | |
| 650 | + if (security != null) { | |
| 651 | + if (p.getAddress().isMulticastAddress()) { | |
| 652 | + security.checkMulticast(p.getAddress()); | |
| 653 | + } else { | |
| 654 | + security.checkConnect(p.getAddress().getHostAddress(), | |
| 655 | + p.getPort()); | |
| 656 | + } | |
| 657 | + } | |
| 658 | + } else { | |
| 659 | + // we're connected | |
| 660 | + packetAddress = p.getAddress(); | |
| 661 | + if (packetAddress == null) { | |
| 662 | + p.setAddress(connectedAddress); | |
| 663 | + p.setPort(connectedPort); | |
| 664 | + } else if ((!packetAddress.equals(connectedAddress)) || | |
| 665 | + p.getPort() != connectedPort) { | |
| 666 | + throw new IllegalArgumentException("connected address " + | |
| 667 | + "and packet address" + | |
| 668 | + " differ"); | |
| 669 | + } | |
| 670 | + } | |
| 671 | + // Check whether the socket is bound | |
| 672 | + if (!isBound()) | |
| 673 | + bind(new InetSocketAddress(0)); | |
| 674 | + // call the method to send | |
| 675 | + getImpl().send(p); | |
| 676 | + } | |
| 677 | + } | |
| 678 | + | |
| 679 | + /** | |
| 680 | + * Receives a datagram packet from this socket. When this method | |
| 681 | + * returns, the <code>DatagramPacket</code>'s buffer is filled with | |
| 682 | + * the data received. The datagram packet also contains the sender's | |
| 683 | + * IP address, and the port number on the sender's machine. | |
| 684 | + * <p> | |
| 685 | + * This method blocks until a datagram is received. The | |
| 686 | + * <code>length</code> field of the datagram packet object contains | |
| 687 | + * the length of the received message. If the message is longer than | |
| 688 | + * the packet's length, the message is truncated. | |
| 689 | + * <p> | |
| 690 | + * If there is a security manager, a packet cannot be received if the | |
| 691 | + * security manager's <code>checkAccept</code> method | |
| 692 | + * does not allow it. | |
| 693 | + * | |
| 694 | + * @param p the <code>DatagramPacket</code> into which to place | |
| 695 | + * the incoming data. | |
| 696 | + * @exception IOException if an I/O error occurs. | |
| 697 | + * @exception SocketTimeoutException if setSoTimeout was previously called | |
| 698 | + * and the timeout has expired. | |
| 699 | + * @exception PortUnreachableException may be thrown if the socket is connected | |
| 700 | + * to a currently unreachable destination. Note, there is no guarantee that the | |
| 701 | + * exception will be thrown. | |
| 702 | + * @exception java.nio.channels.IllegalBlockingModeException | |
| 703 | + * if this socket has an associated channel, | |
| 704 | + * and the channel is in non-blocking mode. | |
| 705 | + * @see java.net.DatagramPacket | |
| 706 | + * @see java.net.DatagramSocket | |
| 707 | + * @revised 1.4 | |
| 708 | + * @spec JSR-51 | |
| 709 | + */ | |
| 710 | + public synchronized void receive(DatagramPacket p) throws IOException { | |
| 711 | + synchronized (p) { | |
| 712 | + if (!isBound()) | |
| 713 | + bind(new InetSocketAddress(0)); | |
| 714 | + if (connectState == ST_NOT_CONNECTED) { | |
| 715 | + // check the address is ok with the security manager before every recv. | |
| 716 | + SecurityManager security = System.getSecurityManager(); | |
| 717 | + if (security != null) { | |
| 718 | + while(true) { | |
| 719 | + String peekAd = null; | |
| 720 | + int peekPort = 0; | |
| 721 | + // peek at the packet to see who it is from. | |
| 722 | + if (!oldImpl) { | |
| 723 | + // We can use the new peekData() API | |
| 724 | + DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1); | |
| 725 | + peekPort = getImpl().peekData(peekPacket); | |
| 726 | + peekAd = peekPacket.getAddress().getHostAddress(); | |
| 727 | + } else { | |
| 728 | + InetAddress adr = new InetAddress(); | |
| 729 | + peekPort = getImpl().peek(adr); | |
| 730 | + peekAd = adr.getHostAddress(); | |
| 731 | + } | |
| 732 | + try { | |
| 733 | + security.checkAccept(peekAd, peekPort); | |
| 734 | + // security check succeeded - so now break | |
| 735 | + // and recv the packet. | |
| 736 | + break; | |
| 737 | + } catch (SecurityException se) { | |
| 738 | + // Throw away the offending packet by consuming | |
| 739 | + // it in a tmp buffer. | |
| 740 | + DatagramPacket tmp = new DatagramPacket(new byte[1], 1); | |
| 741 | + getImpl().receive(tmp); | |
| 742 | + | |
| 743 | + // silently discard the offending packet | |
| 744 | + // and continue: unknown/malicious | |
| 745 | + // entities on nets should not make | |
| 746 | + // runtime throw security exception and | |
| 747 | + // disrupt the applet by sending random | |
| 748 | + // datagram packets. | |
| 749 | + continue; | |
| 750 | + } | |
| 751 | + } // end of while | |
| 752 | + } | |
| 753 | + } | |
| 754 | + if (connectState == ST_CONNECTED_NO_IMPL) { | |
| 755 | + // We have to do the filtering the old fashioned way since | |
| 756 | + // the native impl doesn't support connect or the connect | |
| 757 | + // via the impl failed. | |
| 758 | + boolean stop = false; | |
| 759 | + while (!stop) { | |
| 760 | + // peek at the packet to see who it is from. | |
| 761 | + InetAddress peekAddress = new InetAddress(); | |
| 762 | + int peekPort = getImpl().peek(peekAddress); | |
| 763 | + if ((!connectedAddress.equals(peekAddress)) || | |
| 764 | + (connectedPort != peekPort)) { | |
| 765 | + // throw the packet away and silently continue | |
| 766 | + DatagramPacket tmp = new DatagramPacket(new byte[1], 1); | |
| 767 | + getImpl().receive(tmp); | |
| 768 | + } else { | |
| 769 | + stop = true; | |
| 770 | + } | |
| 771 | + } | |
| 772 | + } | |
| 773 | + // If the security check succeeds, or the datagram is | |
| 774 | + // connected then receive the packet | |
| 775 | + getImpl().receive(p); | |
| 776 | + } | |
| 777 | + } | |
| 778 | + | |
| 779 | + /** | |
| 780 | + * Gets the local address to which the socket is bound. | |
| 781 | + * | |
| 782 | + * <p>If there is a security manager, its | |
| 783 | + * <code>checkConnect</code> method is first called | |
| 784 | + * with the host address and <code>-1</code> | |
| 785 | + * as its arguments to see if the operation is allowed. | |
| 786 | + * | |
| 787 | + * @see SecurityManager#checkConnect | |
| 788 | + * @return the local address to which the socket is bound, | |
| 789 | + * <code>null</code> if the socket is closed, or | |
| 790 | + * an <code>InetAddress</code> representing | |
| 791 | + * {@link InetAddress#isAnyLocalAddress wildcard} | |
| 792 | + * address if either the socket is not bound, or | |
| 793 | + * the security manager <code>checkConnect</code> | |
| 794 | + * method does not allow the operation | |
| 795 | + * @since 1.1 | |
| 796 | + */ | |
| 797 | + public InetAddress getLocalAddress() { | |
| 798 | + if (isClosed()) | |
| 799 | + return null; | |
| 800 | + InetAddress in = null; | |
| 801 | + try { | |
| 802 | + in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR); | |
| 803 | + if (in.isAnyLocalAddress()) { | |
| 804 | + in = InetAddress.anyLocalAddress(); | |
| 805 | + } | |
| 806 | + SecurityManager s = System.getSecurityManager(); | |
| 807 | + if (s != null) { | |
| 808 | + s.checkConnect(in.getHostAddress(), -1); | |
| 809 | + } | |
| 810 | + } catch (Exception e) { | |
| 811 | + in = InetAddress.anyLocalAddress(); // "0.0.0.0" | |
| 812 | + } | |
| 813 | + return in; | |
| 814 | + } | |
| 815 | + | |
| 816 | + /** | |
| 817 | + * Returns the port number on the local host to which this socket | |
| 818 | + * is bound. | |
| 819 | + * | |
| 820 | + * @return the port number on the local host to which this socket is bound, | |
| 821 | + <code>-1</code> if the socket is closed, or | |
| 822 | + <code>0</code> if it is not bound yet. | |
| 823 | + */ | |
| 824 | + public int getLocalPort() { | |
| 825 | + if (isClosed()) | |
| 826 | + return -1; | |
| 827 | + try { | |
| 828 | + return getImpl().getLocalPort(); | |
| 829 | + } catch (Exception e) { | |
| 830 | + return 0; | |
| 831 | + } | |
| 832 | + } | |
| 833 | + | |
| 834 | + /** Enable/disable SO_TIMEOUT with the specified timeout, in | |
| 835 | + * milliseconds. With this option set to a non-zero timeout, | |
| 836 | + * a call to receive() for this DatagramSocket | |
| 837 | + * will block for only this amount of time. If the timeout expires, | |
| 838 | + * a <B>java.net.SocketTimeoutException</B> is raised, though the | |
| 839 | + * DatagramSocket is still valid. The option <B>must</B> be enabled | |
| 840 | + * prior to entering the blocking operation to have effect. The | |
| 841 | + * timeout must be > 0. | |
| 842 | + * A timeout of zero is interpreted as an infinite timeout. | |
| 843 | + * | |
| 844 | + * @param timeout the specified timeout in milliseconds. | |
| 845 | + * @throws SocketException if there is an error in the underlying protocol, such as an UDP error. | |
| 846 | + * @since JDK1.1 | |
| 847 | + * @see #getSoTimeout() | |
| 848 | + */ | |
| 849 | + public synchronized void setSoTimeout(int timeout) throws SocketException { | |
| 850 | + if (isClosed()) | |
| 851 | + throw new SocketException("Socket is closed"); | |
| 852 | + getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); | |
| 853 | + } | |
| 854 | + | |
| 855 | + /** | |
| 856 | + * Retrieve setting for SO_TIMEOUT. 0 returns implies that the | |
| 857 | + * option is disabled (i.e., timeout of infinity). | |
| 858 | + * | |
| 859 | + * @return the setting for SO_TIMEOUT | |
| 860 | + * @throws SocketException if there is an error in the underlying protocol, such as an UDP error. | |
| 861 | + * @since JDK1.1 | |
| 862 | + * @see #setSoTimeout(int) | |
| 863 | + */ | |
| 864 | + public synchronized int getSoTimeout() throws SocketException { | |
| 865 | + if (isClosed()) | |
| 866 | + throw new SocketException("Socket is closed"); | |
| 867 | + if (getImpl() == null) | |
| 868 | + return 0; | |
| 869 | + Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT); | |
| 870 | + /* extra type safety */ | |
| 871 | + if (o instanceof Integer) { | |
| 872 | + return ((Integer) o).intValue(); | |
| 873 | + } else { | |
| 874 | + return 0; | |
| 875 | + } | |
| 876 | + } | |
| 877 | + | |
| 878 | + /** | |
| 879 | + * Sets the SO_SNDBUF option to the specified value for this | |
| 880 | + * <tt>DatagramSocket</tt>. The SO_SNDBUF option is used by the | |
| 881 | + * network implementation as a hint to size the underlying | |
| 882 | + * network I/O buffers. The SO_SNDBUF setting may also be used | |
| 883 | + * by the network implementation to determine the maximum size | |
| 884 | + * of the packet that can be sent on this socket. | |
| 885 | + * <p> | |
| 886 | + * As SO_SNDBUF is a hint, applications that want to verify | |
| 887 | + * what size the buffer is should call {@link #getSendBufferSize()}. | |
| 888 | + * <p> | |
| 889 | + * Increasing the buffer size may allow multiple outgoing packets | |
| 890 | + * to be queued by the network implementation when the send rate | |
| 891 | + * is high. | |
| 892 | + * <p> | |
| 893 | + * Note: If {@link #send(DatagramPacket)} is used to send a | |
| 894 | + * <code>DatagramPacket</code> that is larger than the setting | |
| 895 | + * of SO_SNDBUF then it is implementation specific if the | |
| 896 | + * packet is sent or discarded. | |
| 897 | + * | |
| 898 | + * @param size the size to which to set the send buffer | |
| 899 | + * size. This value must be greater than 0. | |
| 900 | + * | |
| 901 | + * @exception SocketException if there is an error | |
| 902 | + * in the underlying protocol, such as an UDP error. | |
| 903 | + * @exception IllegalArgumentException if the value is 0 or is | |
| 904 | + * negative. | |
| 905 | + * @see #getSendBufferSize() | |
| 906 | + */ | |
| 907 | + public synchronized void setSendBufferSize(int size) | |
| 908 | + throws SocketException{ | |
| 909 | + if (!(size > 0)) { | |
| 910 | + throw new IllegalArgumentException("negative send size"); | |
| 911 | + } | |
| 912 | + if (isClosed()) | |
| 913 | + throw new SocketException("Socket is closed"); | |
| 914 | + getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size)); | |
| 915 | + } | |
| 916 | + | |
| 917 | + /** | |
| 918 | + * Get value of the SO_SNDBUF option for this <tt>DatagramSocket</tt>, that is the | |
| 919 | + * buffer size used by the platform for output on this <tt>DatagramSocket</tt>. | |
| 920 | + * | |
| 921 | + * @return the value of the SO_SNDBUF option for this <tt>DatagramSocket</tt> | |
| 922 | + * @exception SocketException if there is an error in | |
| 923 | + * the underlying protocol, such as an UDP error. | |
| 924 | + * @see #setSendBufferSize | |
| 925 | + */ | |
| 926 | + public synchronized int getSendBufferSize() throws SocketException { | |
| 927 | + if (isClosed()) | |
| 928 | + throw new SocketException("Socket is closed"); | |
| 929 | + int result = 0; | |
| 930 | + Object o = getImpl().getOption(SocketOptions.SO_SNDBUF); | |
| 931 | + if (o instanceof Integer) { | |
| 932 | + result = ((Integer)o).intValue(); | |
| 933 | + } | |
| 934 | + return result; | |
| 935 | + } | |
| 936 | + | |
| 937 | + /** | |
| 938 | + * Sets the SO_RCVBUF option to the specified value for this | |
| 939 | + * <tt>DatagramSocket</tt>. The SO_RCVBUF option is used by the | |
| 940 | + * the network implementation as a hint to size the underlying | |
| 941 | + * network I/O buffers. The SO_RCVBUF setting may also be used | |
| 942 | + * by the network implementation to determine the maximum size | |
| 943 | + * of the packet that can be received on this socket. | |
| 944 | + * <p> | |
| 945 | + * Because SO_RCVBUF is a hint, applications that want to | |
| 946 | + * verify what size the buffers were set to should call | |
| 947 | + * {@link #getReceiveBufferSize()}. | |
| 948 | + * <p> | |
| 949 | + * Increasing SO_RCVBUF may allow the network implementation | |
| 950 | + * to buffer multiple packets when packets arrive faster than | |
| 951 | + * are being received using {@link #receive(DatagramPacket)}. | |
| 952 | + * <p> | |
| 953 | + * Note: It is implementation specific if a packet larger | |
| 954 | + * than SO_RCVBUF can be received. | |
| 955 | + * | |
| 956 | + * @param size the size to which to set the receive buffer | |
| 957 | + * size. This value must be greater than 0. | |
| 958 | + * | |
| 959 | + * @exception SocketException if there is an error in | |
| 960 | + * the underlying protocol, such as an UDP error. | |
| 961 | + * @exception IllegalArgumentException if the value is 0 or is | |
| 962 | + * negative. | |
| 963 | + * @see #getReceiveBufferSize() | |
| 964 | + */ | |
| 965 | + public synchronized void setReceiveBufferSize(int size) | |
| 966 | + throws SocketException{ | |
| 967 | + if (size <= 0) { | |
| 968 | + throw new IllegalArgumentException("invalid receive size"); | |
| 969 | + } | |
| 970 | + if (isClosed()) | |
| 971 | + throw new SocketException("Socket is closed"); | |
| 972 | + getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size)); | |
| 973 | + } | |
| 974 | + | |
| 975 | + /** | |
| 976 | + * Get value of the SO_RCVBUF option for this <tt>DatagramSocket</tt>, that is the | |
| 977 | + * buffer size used by the platform for input on this <tt>DatagramSocket</tt>. | |
| 978 | + * | |
| 979 | + * @return the value of the SO_RCVBUF option for this <tt>DatagramSocket</tt> | |
| 980 | + * @exception SocketException if there is an error in the underlying protocol, such as an UDP error. | |
| 981 | + * @see #setReceiveBufferSize(int) | |
| 982 | + */ | |
| 983 | + public synchronized int getReceiveBufferSize() | |
| 984 | + throws SocketException{ | |
| 985 | + if (isClosed()) | |
| 986 | + throw new SocketException("Socket is closed"); | |
| 987 | + int result = 0; | |
| 988 | + Object o = getImpl().getOption(SocketOptions.SO_RCVBUF); | |
| 989 | + if (o instanceof Integer) { | |
| 990 | + result = ((Integer)o).intValue(); | |
| 991 | + } | |
| 992 | + return result; | |
| 993 | + } | |
| 994 | + | |
| 995 | + /** | |
| 996 | + * Enable/disable the SO_REUSEADDR socket option. | |
| 997 | + * <p> | |
| 998 | + * For UDP sockets it may be necessary to bind more than one | |
| 999 | + * socket to the same socket address. This is typically for the | |
| 1000 | + * purpose of receiving multicast packets | |
| 1001 | + * (See {@link java.net.MulticastSocket}). The | |
| 1002 | + * <tt>SO_REUSEADDR</tt> socket option allows multiple | |
| 1003 | + * sockets to be bound to the same socket address if the | |
| 1004 | + * <tt>SO_REUSEADDR</tt> socket option is enabled prior | |
| 1005 | + * to binding the socket using {@link #bind(SocketAddress)}. | |
| 1006 | + * <p> | |
| 1007 | + * Note: This functionality is not supported by all existing platforms, | |
| 1008 | + * so it is implementation specific whether this option will be ignored | |
| 1009 | + * or not. However, if it is not supported then | |
| 1010 | + * {@link #getReuseAddress()} will always return <code>false</code>. | |
| 1011 | + * <p> | |
| 1012 | + * When a <tt>DatagramSocket</tt> is created the initial setting | |
| 1013 | + * of <tt>SO_REUSEADDR</tt> is disabled. | |
| 1014 | + * <p> | |
| 1015 | + * The behaviour when <tt>SO_REUSEADDR</tt> is enabled or | |
| 1016 | + * disabled after a socket is bound (See {@link #isBound()}) | |
| 1017 | + * is not defined. | |
| 1018 | + * | |
| 1019 | + * @param on whether to enable or disable the | |
| 1020 | + * @exception SocketException if an error occurs enabling or | |
| 1021 | + * disabling the <tt>SO_RESUEADDR</tt> socket option, | |
| 1022 | + * or the socket is closed. | |
| 1023 | + * @since 1.4 | |
| 1024 | + * @see #getReuseAddress() | |
| 1025 | + * @see #bind(SocketAddress) | |
| 1026 | + * @see #isBound() | |
| 1027 | + * @see #isClosed() | |
| 1028 | + */ | |
| 1029 | + public synchronized void setReuseAddress(boolean on) throws SocketException { | |
| 1030 | + if (isClosed()) | |
| 1031 | + throw new SocketException("Socket is closed"); | |
| 1032 | + // Integer instead of Boolean for compatibility with older DatagramSocketImpl | |
| 1033 | + if (oldImpl) | |
| 1034 | + getImpl().setOption(SocketOptions.SO_REUSEADDR, new Integer(on?-1:0)); | |
| 1035 | + else | |
| 1036 | + getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); | |
| 1037 | + } | |
| 1038 | + | |
| 1039 | + /** | |
| 1040 | + * Tests if SO_REUSEADDR is enabled. | |
| 1041 | + * | |
| 1042 | + * @return a <code>boolean</code> indicating whether or not SO_REUSEADDR is enabled. | |
| 1043 | + * @exception SocketException if there is an error | |
| 1044 | + * in the underlying protocol, such as an UDP error. | |
| 1045 | + * @since 1.4 | |
| 1046 | + * @see #setReuseAddress(boolean) | |
| 1047 | + */ | |
| 1048 | + public synchronized boolean getReuseAddress() throws SocketException { | |
| 1049 | + if (isClosed()) | |
| 1050 | + throw new SocketException("Socket is closed"); | |
| 1051 | + Object o = getImpl().getOption(SocketOptions.SO_REUSEADDR); | |
| 1052 | + return ((Boolean)o).booleanValue(); | |
| 1053 | + } | |
| 1054 | + | |
| 1055 | + /** | |
| 1056 | + * Enable/disable SO_BROADCAST. | |
| 1057 | + * | |
| 1058 | + * <p> Some operating systems may require that the Java virtual machine be | |
| 1059 | + * started with implementation specific privileges to enable this option or | |
| 1060 | + * send broadcast datagrams. | |
| 1061 | + * | |
| 1062 | + * @param on | |
| 1063 | + * whether or not to have broadcast turned on. | |
| 1064 | + * | |
| 1065 | + * @throws SocketException | |
| 1066 | + * if there is an error in the underlying protocol, such as an UDP | |
| 1067 | + * error. | |
| 1068 | + * | |
| 1069 | + * @since 1.4 | |
| 1070 | + * @see #getBroadcast() | |
| 1071 | + */ | |
| 1072 | + public synchronized void setBroadcast(boolean on) throws SocketException { | |
| 1073 | + if (isClosed()) | |
| 1074 | + throw new SocketException("Socket is closed"); | |
| 1075 | + getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(on)); | |
| 1076 | + } | |
| 1077 | + | |
| 1078 | + /** | |
| 1079 | + * Tests if SO_BROADCAST is enabled. | |
| 1080 | + * @return a <code>boolean</code> indicating whether or not SO_BROADCAST is enabled. | |
| 1081 | + * @exception SocketException if there is an error | |
| 1082 | + * in the underlying protocol, such as an UDP error. | |
| 1083 | + * @since 1.4 | |
| 1084 | + * @see #setBroadcast(boolean) | |
| 1085 | + */ | |
| 1086 | + public synchronized boolean getBroadcast() throws SocketException { | |
| 1087 | + if (isClosed()) | |
| 1088 | + throw new SocketException("Socket is closed"); | |
| 1089 | + return ((Boolean)(getImpl().getOption(SocketOptions.SO_BROADCAST))).booleanValue(); | |
| 1090 | + } | |
| 1091 | + | |
| 1092 | + /** | |
| 1093 | + * Sets traffic class or type-of-service octet in the IP | |
| 1094 | + * datagram header for datagrams sent from this DatagramSocket. | |
| 1095 | + * As the underlying network implementation may ignore this | |
| 1096 | + * value applications should consider it a hint. | |
| 1097 | + * | |
| 1098 | + * <P> The tc <B>must</B> be in the range <code> 0 <= tc <= | |
| 1099 | + * 255</code> or an IllegalArgumentException will be thrown. | |
| 1100 | + * <p>Notes: | |
| 1101 | + * <p>For Internet Protocol v4 the value consists of an | |
| 1102 | + * <code>integer</code>, the least significant 8 bits of which | |
| 1103 | + * represent the value of the TOS octet in IP packets sent by | |
| 1104 | + * the socket. | |
| 1105 | + * RFC 1349 defines the TOS values as follows: | |
| 1106 | + * <p> | |
| 1107 | + * <UL> | |
| 1108 | + * <LI><CODE>IPTOS_LOWCOST (0x02)</CODE></LI> | |
| 1109 | + * <LI><CODE>IPTOS_RELIABILITY (0x04)</CODE></LI> | |
| 1110 | + * <LI><CODE>IPTOS_THROUGHPUT (0x08)</CODE></LI> | |
| 1111 | + * <LI><CODE>IPTOS_LOWDELAY (0x10)</CODE></LI> | |
| 1112 | + * </UL> | |
| 1113 | + * The last low order bit is always ignored as this | |
| 1114 | + * corresponds to the MBZ (must be zero) bit. | |
| 1115 | + * <p> | |
| 1116 | + * Setting bits in the precedence field may result in a | |
| 1117 | + * SocketException indicating that the operation is not | |
| 1118 | + * permitted. | |
| 1119 | + * <p> | |
| 1120 | + * for Internet Protocol v6 <code>tc</code> is the value that | |
| 1121 | + * would be placed into the sin6_flowinfo field of the IP header. | |
| 1122 | + * | |
| 1123 | + * @param tc an <code>int</code> value for the bitset. | |
| 1124 | + * @throws SocketException if there is an error setting the | |
| 1125 | + * traffic class or type-of-service | |
| 1126 | + * @since 1.4 | |
| 1127 | + * @see #getTrafficClass | |
| 1128 | + */ | |
| 1129 | + public synchronized void setTrafficClass(int tc) throws SocketException { | |
| 1130 | + if (tc < 0 || tc > 255) | |
| 1131 | + throw new IllegalArgumentException("tc is not in range 0 -- 255"); | |
| 1132 | + | |
| 1133 | + if (isClosed()) | |
| 1134 | + throw new SocketException("Socket is closed"); | |
| 1135 | + getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc)); | |
| 1136 | + } | |
| 1137 | + | |
| 1138 | + /** | |
| 1139 | + * Gets traffic class or type-of-service in the IP datagram | |
| 1140 | + * header for packets sent from this DatagramSocket. | |
| 1141 | + * <p> | |
| 1142 | + * As the underlying network implementation may ignore the | |
| 1143 | + * traffic class or type-of-service set using {@link #setTrafficClass(int)} | |
| 1144 | + * this method may return a different value than was previously | |
| 1145 | + * set using the {@link #setTrafficClass(int)} method on this | |
| 1146 | + * DatagramSocket. | |
| 1147 | + * | |
| 1148 | + * @return the traffic class or type-of-service already set | |
| 1149 | + * @throws SocketException if there is an error obtaining the | |
| 1150 | + * traffic class or type-of-service value. | |
| 1151 | + * @since 1.4 | |
| 1152 | + * @see #setTrafficClass(int) | |
| 1153 | + */ | |
| 1154 | + public synchronized int getTrafficClass() throws SocketException { | |
| 1155 | + if (isClosed()) | |
| 1156 | + throw new SocketException("Socket is closed"); | |
| 1157 | + return ((Integer)(getImpl().getOption(SocketOptions.IP_TOS))).intValue(); | |
| 1158 | + } | |
| 1159 | + | |
| 1160 | + /** | |
| 1161 | + * Closes this datagram socket. | |
| 1162 | + * <p> | |
| 1163 | + * Any thread currently blocked in {@link #receive} upon this socket | |
| 1164 | + * will throw a {@link SocketException}. | |
| 1165 | + * | |
| 1166 | + * <p> If this socket has an associated channel then the channel is closed | |
| 1167 | + * as well. | |
| 1168 | + * | |
| 1169 | + * @revised 1.4 | |
| 1170 | + * @spec JSR-51 | |
| 1171 | + */ | |
| 1172 | + public void close() { | |
| 1173 | + synchronized(closeLock) { | |
| 1174 | + if (isClosed()) | |
| 1175 | + return; | |
| 1176 | + impl.close(); | |
| 1177 | + closed = true; | |
| 1178 | + } | |
| 1179 | + } | |
| 1180 | + | |
| 1181 | + /** | |
| 1182 | + * Returns whether the socket is closed or not. | |
| 1183 | + * | |
| 1184 | + * @return true if the socket has been closed | |
| 1185 | + * @since 1.4 | |
| 1186 | + */ | |
| 1187 | + public boolean isClosed() { | |
| 1188 | + synchronized(closeLock) { | |
| 1189 | + return closed; | |
| 1190 | + } | |
| 1191 | + } | |
| 1192 | + | |
| 1193 | + /** | |
| 1194 | + * Returns the unique {@link java.nio.channels.DatagramChannel} object | |
| 1195 | + * associated with this datagram socket, if any. | |
| 1196 | + * | |
| 1197 | + * <p> A datagram socket will have a channel if, and only if, the channel | |
| 1198 | + * itself was created via the {@link java.nio.channels.DatagramChannel#open | |
| 1199 | + * DatagramChannel.open} method. | |
| 1200 | + * | |
| 1201 | + * @return the datagram channel associated with this datagram socket, | |
| 1202 | + * or <tt>null</tt> if this socket was not created for a channel | |
| 1203 | + * | |
| 1204 | + * @since 1.4 | |
| 1205 | + * @spec JSR-51 | |
| 1206 | + */ | |
| 1207 | + public DatagramChannel getChannel() { | |
| 1208 | + return null; | |
| 1209 | + } | |
| 1210 | + | |
| 1211 | + /** | |
| 1212 | + * User defined factory for all datagram sockets. | |
| 1213 | + */ | |
| 1214 | + static DatagramSocketImplFactory factory; | |
| 1215 | + | |
| 1216 | + /** | |
| 1217 | + * Sets the datagram socket implementation factory for the | |
| 1218 | + * application. The factory can be specified only once. | |
| 1219 | + * <p> | |
| 1220 | + * When an application creates a new datagram socket, the socket | |
| 1221 | + * implementation factory's <code>createDatagramSocketImpl</code> method is | |
| 1222 | + * called to create the actual datagram socket implementation. | |
| 1223 | + * <p> | |
| 1224 | + * Passing <code>null</code> to the method is a no-op unless the factory | |
| 1225 | + * was already set. | |
| 1226 | + * | |
| 1227 | + * <p>If there is a security manager, this method first calls | |
| 1228 | + * the security manager's <code>checkSetFactory</code> method | |
| 1229 | + * to ensure the operation is allowed. | |
| 1230 | + * This could result in a SecurityException. | |
| 1231 | + * | |
| 1232 | + * @param fac the desired factory. | |
| 1233 | + * @exception IOException if an I/O error occurs when setting the | |
| 1234 | + * datagram socket factory. | |
| 1235 | + * @exception SocketException if the factory is already defined. | |
| 1236 | + * @exception SecurityException if a security manager exists and its | |
| 1237 | + * <code>checkSetFactory</code> method doesn't allow the | |
| 1238 | + operation. | |
| 1239 | + * @see | |
| 1240 | + java.net.DatagramSocketImplFactory#createDatagramSocketImpl() | |
| 1241 | + * @see SecurityManager#checkSetFactory | |
| 1242 | + * @since 1.3 | |
| 1243 | + */ | |
| 1244 | + public static synchronized void | |
| 1245 | + setDatagramSocketImplFactory(DatagramSocketImplFactory fac) | |
| 1246 | + throws IOException | |
| 1247 | + { | |
| 1248 | + if (factory != null) { | |
| 1249 | + throw new SocketException("factory already defined"); | |
| 1250 | + } | |
| 1251 | + SecurityManager security = System.getSecurityManager(); | |
| 1252 | + if (security != null) { | |
| 1253 | + security.checkSetFactory(); | |
| 1254 | + } | |
| 1255 | + factory = fac; | |
| 1256 | + } | |
| 1257 | +} | |
Binary file not shown.
| @@ -0,0 +1,244 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2006, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.FileDescriptor; | |
| 29 | +import java.io.IOException; | |
| 30 | +import java.io.InterruptedIOException; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * Abstract datagram and multicast socket implementation base class. | |
| 34 | + * @author Pavani Diwanji | |
| 35 | + * @since JDK1.1 | |
| 36 | + */ | |
| 37 | + | |
| 38 | +public abstract class DatagramSocketImpl implements SocketOptions { | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * The local port number. | |
| 42 | + */ | |
| 43 | + protected int localPort; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * The file descriptor object. | |
| 47 | + */ | |
| 48 | + protected FileDescriptor fd; | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Creates a datagram socket. | |
| 52 | + * @exception SocketException if there is an error in the | |
| 53 | + * underlying protocol, such as a TCP error. | |
| 54 | + */ | |
| 55 | + protected abstract void create() throws SocketException; | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * Binds a datagram socket to a local port and address. | |
| 59 | + * @param lport the local port | |
| 60 | + * @param laddr the local address | |
| 61 | + * @exception SocketException if there is an error in the | |
| 62 | + * underlying protocol, such as a TCP error. | |
| 63 | + */ | |
| 64 | + protected abstract void bind(int lport, InetAddress laddr) throws SocketException; | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Sends a datagram packet. The packet contains the data and the | |
| 68 | + * destination address to send the packet to. | |
| 69 | + * @param p the packet to be sent. | |
| 70 | + * @exception IOException if an I/O exception occurs while sending the | |
| 71 | + * datagram packet. | |
| 72 | + * @exception PortUnreachableException may be thrown if the socket is connected | |
| 73 | + * to a currently unreachable destination. Note, there is no guarantee that | |
| 74 | + * the exception will be thrown. | |
| 75 | + */ | |
| 76 | + protected abstract void send(DatagramPacket p) throws IOException; | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * Connects a datagram socket to a remote destination. This associates the remote | |
| 80 | + * address with the local socket so that datagrams may only be sent to this destination | |
| 81 | + * and received from this destination. This may be overridden to call a native | |
| 82 | + * system connect. | |
| 83 | + * | |
| 84 | + * <p>If the remote destination to which the socket is connected does not | |
| 85 | + * exist, or is otherwise unreachable, and if an ICMP destination unreachable | |
| 86 | + * packet has been received for that address, then a subsequent call to | |
| 87 | + * send or receive may throw a PortUnreachableException. | |
| 88 | + * Note, there is no guarantee that the exception will be thrown. | |
| 89 | + * @param address the remote InetAddress to connect to | |
| 90 | + * @param port the remote port number | |
| 91 | + * @exception SocketException may be thrown if the socket cannot be | |
| 92 | + * connected to the remote destination | |
| 93 | + * @since 1.4 | |
| 94 | + */ | |
| 95 | + protected void connect(InetAddress address, int port) throws SocketException {} | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * Disconnects a datagram socket from its remote destination. | |
| 99 | + * @since 1.4 | |
| 100 | + */ | |
| 101 | + protected void disconnect() {} | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * Peek at the packet to see who it is from. Updates the specified <code>InetAddress</code> | |
| 105 | + * to the address which the packet came from. | |
| 106 | + * @param i an InetAddress object | |
| 107 | + * @return the port number which the packet came from. | |
| 108 | + * @exception IOException if an I/O exception occurs | |
| 109 | + * @exception PortUnreachableException may be thrown if the socket is connected | |
| 110 | + * to a currently unreachable destination. Note, there is no guarantee that the | |
| 111 | + * exception will be thrown. | |
| 112 | + */ | |
| 113 | + protected abstract int peek(InetAddress i) throws IOException; | |
| 114 | + | |
| 115 | + /** | |
| 116 | + * Peek at the packet to see who it is from. The data is copied into the specified | |
| 117 | + * <code>DatagramPacket</code>. The data is returned, | |
| 118 | + * but not consumed, so that a subsequent peekData/receive operation | |
| 119 | + * will see the same data. | |
| 120 | + * @param p the Packet Received. | |
| 121 | + * @return the port number which the packet came from. | |
| 122 | + * @exception IOException if an I/O exception occurs | |
| 123 | + * @exception PortUnreachableException may be thrown if the socket is connected | |
| 124 | + * to a currently unreachable destination. Note, there is no guarantee that the | |
| 125 | + * exception will be thrown. | |
| 126 | + * @since 1.4 | |
| 127 | + */ | |
| 128 | + protected abstract int peekData(DatagramPacket p) throws IOException; | |
| 129 | + /** | |
| 130 | + * Receive the datagram packet. | |
| 131 | + * @param p the Packet Received. | |
| 132 | + * @exception IOException if an I/O exception occurs | |
| 133 | + * while receiving the datagram packet. | |
| 134 | + * @exception PortUnreachableException may be thrown if the socket is connected | |
| 135 | + * to a currently unreachable destination. Note, there is no guarantee that the | |
| 136 | + * exception will be thrown. | |
| 137 | + */ | |
| 138 | + protected abstract void receive(DatagramPacket p) throws IOException; | |
| 139 | + | |
| 140 | + /** | |
| 141 | + * Set the TTL (time-to-live) option. | |
| 142 | + * @param ttl a byte specifying the TTL value | |
| 143 | + * | |
| 144 | + * @deprecated use setTimeToLive instead. | |
| 145 | + * @exception IOException if an I/O exception occurs while setting | |
| 146 | + * the time-to-live option. | |
| 147 | + * @see #getTTL() | |
| 148 | + */ | |
| 149 | + @Deprecated | |
| 150 | + protected abstract void setTTL(byte ttl) throws IOException; | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * Retrieve the TTL (time-to-live) option. | |
| 154 | + * | |
| 155 | + * @exception IOException if an I/O exception occurs | |
| 156 | + * while retrieving the time-to-live option | |
| 157 | + * @deprecated use getTimeToLive instead. | |
| 158 | + * @return a byte representing the TTL value | |
| 159 | + * @see #setTTL(byte) | |
| 160 | + */ | |
| 161 | + @Deprecated | |
| 162 | + protected abstract byte getTTL() throws IOException; | |
| 163 | + | |
| 164 | + /** | |
| 165 | + * Set the TTL (time-to-live) option. | |
| 166 | + * @param ttl an <tt>int</tt> specifying the time-to-live value | |
| 167 | + * @exception IOException if an I/O exception occurs | |
| 168 | + * while setting the time-to-live option. | |
| 169 | + * @see #getTimeToLive() | |
| 170 | + */ | |
| 171 | + protected abstract void setTimeToLive(int ttl) throws IOException; | |
| 172 | + | |
| 173 | + /** | |
| 174 | + * Retrieve the TTL (time-to-live) option. | |
| 175 | + * @exception IOException if an I/O exception occurs | |
| 176 | + * while retrieving the time-to-live option | |
| 177 | + * @return an <tt>int</tt> representing the time-to-live value | |
| 178 | + * @see #setTimeToLive(int) | |
| 179 | + */ | |
| 180 | + protected abstract int getTimeToLive() throws IOException; | |
| 181 | + | |
| 182 | + /** | |
| 183 | + * Join the multicast group. | |
| 184 | + * @param inetaddr multicast address to join. | |
| 185 | + * @exception IOException if an I/O exception occurs | |
| 186 | + * while joining the multicast group. | |
| 187 | + */ | |
| 188 | + protected abstract void join(InetAddress inetaddr) throws IOException; | |
| 189 | + | |
| 190 | + /** | |
| 191 | + * Leave the multicast group. | |
| 192 | + * @param inetaddr multicast address to leave. | |
| 193 | + * @exception IOException if an I/O exception occurs | |
| 194 | + * while leaving the multicast group. | |
| 195 | + */ | |
| 196 | + protected abstract void leave(InetAddress inetaddr) throws IOException; | |
| 197 | + | |
| 198 | + /** | |
| 199 | + * Join the multicast group. | |
| 200 | + * @param mcastaddr address to join. | |
| 201 | + * @param netIf specifies the local interface to receive multicast | |
| 202 | + * datagram packets | |
| 203 | + * @throws IOException if an I/O exception occurs while joining | |
| 204 | + * the multicast group | |
| 205 | + * @since 1.4 | |
| 206 | + */ | |
| 207 | + protected abstract void joinGroup(SocketAddress mcastaddr, | |
| 208 | + NetworkInterface netIf) | |
| 209 | + throws IOException; | |
| 210 | + | |
| 211 | + /** | |
| 212 | + * Leave the multicast group. | |
| 213 | + * @param mcastaddr address to leave. | |
| 214 | + * @param netIf specified the local interface to leave the group at | |
| 215 | + * @throws IOException if an I/O exception occurs while leaving | |
| 216 | + * the multicast group | |
| 217 | + * @since 1.4 | |
| 218 | + */ | |
| 219 | + protected abstract void leaveGroup(SocketAddress mcastaddr, | |
| 220 | + NetworkInterface netIf) | |
| 221 | + throws IOException; | |
| 222 | + | |
| 223 | + /** | |
| 224 | + * Close the socket. | |
| 225 | + */ | |
| 226 | + protected abstract void close(); | |
| 227 | + | |
| 228 | + /** | |
| 229 | + * Gets the local port. | |
| 230 | + * @return an <tt>int</tt> representing the local port value | |
| 231 | + */ | |
| 232 | + protected int getLocalPort() { | |
| 233 | + return localPort; | |
| 234 | + } | |
| 235 | + | |
| 236 | + /** | |
| 237 | + * Gets the datagram socket file descriptor. | |
| 238 | + * @return a <tt>FileDescriptor</tt> object representing the datagram socket | |
| 239 | + * file descriptor | |
| 240 | + */ | |
| 241 | + protected FileDescriptor getFileDescriptor() { | |
| 242 | + return fd; | |
| 243 | + } | |
| 244 | +} | |
Binary file not shown.
| @@ -0,0 +1,46 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1999, 2002, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This interface defines a factory for datagram socket implementations. It | |
| 30 | + * is used by the classes <code>DatagramSocket</code> to create actual socket | |
| 31 | + * implementations. | |
| 32 | + * | |
| 33 | + * @author Yingxian Wang | |
| 34 | + * @see java.net.DatagramSocket | |
| 35 | + * @since 1.3 | |
| 36 | + */ | |
| 37 | +public | |
| 38 | +interface DatagramSocketImplFactory { | |
| 39 | + /** | |
| 40 | + * Creates a new <code>DatagramSocketImpl</code> instance. | |
| 41 | + * | |
| 42 | + * @return a new instance of <code>DatagramSocketImpl</code>. | |
| 43 | + * @see java.net.DatagramSocketImpl | |
| 44 | + */ | |
| 45 | + DatagramSocketImpl createDatagramSocketImpl(); | |
| 46 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,44 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 1999, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * A simple interface which provides a mechanism to map | |
| 30 | + * between a file name and a MIME type string. | |
| 31 | + * | |
| 32 | + * @author Steven B. Byrne | |
| 33 | + * @since JDK1.1 | |
| 34 | + */ | |
| 35 | +public interface FileNameMap { | |
| 36 | + | |
| 37 | + /** | |
| 38 | + * Gets the MIME type for the specified file name. | |
| 39 | + * @param fileName the specified file name | |
| 40 | + * @return a <code>String</code> indicating the MIME | |
| 41 | + * type for the specified file name. | |
| 42 | + */ | |
| 43 | + public String getContentTypeFor(String fileName); | |
| 44 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,1206 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2010, 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 java.net; | |
| 27 | + | |
| 28 | +import java.util.List; | |
| 29 | +import java.util.StringTokenizer; | |
| 30 | +import java.util.NoSuchElementException; | |
| 31 | +import java.text.SimpleDateFormat; | |
| 32 | +import java.util.TimeZone; | |
| 33 | +import java.util.Date; | |
| 34 | + | |
| 35 | +import java.lang.NullPointerException; // for javadoc | |
| 36 | +import java.util.Locale; | |
| 37 | +import java.util.Objects; | |
| 38 | + | |
| 39 | +/** | |
| 40 | + * An HttpCookie object represents an http cookie, which carries state | |
| 41 | + * information between server and user agent. Cookie is widely adopted | |
| 42 | + * to create stateful sessions. | |
| 43 | + * | |
| 44 | + * <p>There are 3 http cookie specifications: | |
| 45 | + * <blockquote> | |
| 46 | + * Netscape draft<br> | |
| 47 | + * RFC 2109 - <a href="http://www.ietf.org/rfc/rfc2109.txt"> | |
| 48 | + * <i>http://www.ietf.org/rfc/rfc2109.txt</i></a><br> | |
| 49 | + * RFC 2965 - <a href="http://www.ietf.org/rfc/rfc2965.txt"> | |
| 50 | + * <i>http://www.ietf.org/rfc/rfc2965.txt</i></a> | |
| 51 | + * </blockquote> | |
| 52 | + * | |
| 53 | + * <p>HttpCookie class can accept all these 3 forms of syntax. | |
| 54 | + * | |
| 55 | + * @author Edward Wang | |
| 56 | + * @since 1.6 | |
| 57 | + */ | |
| 58 | +public final class HttpCookie implements Cloneable { | |
| 59 | + /* ---------------- Fields -------------- */ | |
| 60 | + | |
| 61 | + // | |
| 62 | + // The value of the cookie itself. | |
| 63 | + // | |
| 64 | + | |
| 65 | + private String name; // NAME= ... "$Name" style is reserved | |
| 66 | + private String value; // value of NAME | |
| 67 | + | |
| 68 | + // | |
| 69 | + // Attributes encoded in the header's cookie fields. | |
| 70 | + // | |
| 71 | + | |
| 72 | + private String comment; // Comment=VALUE ... describes cookie's use | |
| 73 | + private String commentURL; // CommentURL="http URL" ... describes cookie's use | |
| 74 | + private boolean toDiscard; // Discard ... discard cookie unconditionally | |
| 75 | + private String domain; // Domain=VALUE ... domain that sees cookie | |
| 76 | + private long maxAge = MAX_AGE_UNSPECIFIED; // Max-Age=VALUE ... cookies auto-expire | |
| 77 | + private String path; // Path=VALUE ... URLs that see the cookie | |
| 78 | + private String portlist; // Port[="portlist"] ... the port cookie may be returned to | |
| 79 | + private boolean secure; // Secure ... e.g. use SSL | |
| 80 | + private boolean httpOnly; // HttpOnly ... i.e. not accessible to scripts | |
| 81 | + private int version = 1; // Version=1 ... RFC 2965 style | |
| 82 | + | |
| 83 | + // | |
| 84 | + // Hold the creation time (in seconds) of the http cookie for later | |
| 85 | + // expiration calculation | |
| 86 | + // | |
| 87 | + private long whenCreated = 0; | |
| 88 | + | |
| 89 | + | |
| 90 | + // | |
| 91 | + // Since the positive and zero max-age have their meanings, | |
| 92 | + // this value serves as a hint as 'not specify max-age' | |
| 93 | + // | |
| 94 | + private final static long MAX_AGE_UNSPECIFIED = -1; | |
| 95 | + | |
| 96 | + | |
| 97 | + // | |
| 98 | + // date formats used by Netscape's cookie draft | |
| 99 | + // as well as formats seen on various sites | |
| 100 | + // | |
| 101 | + private final static String[] COOKIE_DATE_FORMATS = { | |
| 102 | + "EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'", | |
| 103 | + "EEE',' dd MMM yyyy HH:mm:ss 'GMT'", | |
| 104 | + "EEE MMM dd yyyy HH:mm:ss 'GMT'Z" | |
| 105 | + }; | |
| 106 | + | |
| 107 | + // | |
| 108 | + // constant strings represent set-cookie header token | |
| 109 | + // | |
| 110 | + private final static String SET_COOKIE = "set-cookie:"; | |
| 111 | + private final static String SET_COOKIE2 = "set-cookie2:"; | |
| 112 | + | |
| 113 | + | |
| 114 | + /* ---------------- Ctors -------------- */ | |
| 115 | + | |
| 116 | + /** | |
| 117 | + * Constructs a cookie with a specified name and value. | |
| 118 | + * | |
| 119 | + * <p>The name must conform to RFC 2965. That means it can contain | |
| 120 | + * only ASCII alphanumeric characters and cannot contain commas, | |
| 121 | + * semicolons, or white space or begin with a $ character. The cookie's | |
| 122 | + * name cannot be changed after creation. | |
| 123 | + * | |
| 124 | + * <p>The value can be anything the server chooses to send. Its | |
| 125 | + * value is probably of interest only to the server. The cookie's | |
| 126 | + * value can be changed after creation with the | |
| 127 | + * <code>setValue</code> method. | |
| 128 | + * | |
| 129 | + * <p>By default, cookies are created according to the RFC 2965 | |
| 130 | + * cookie specification. The version can be changed with the | |
| 131 | + * <code>setVersion</code> method. | |
| 132 | + * | |
| 133 | + * | |
| 134 | + * @param name a <code>String</code> specifying the name of the cookie | |
| 135 | + * | |
| 136 | + * @param value a <code>String</code> specifying the value of the cookie | |
| 137 | + * | |
| 138 | + * @throws IllegalArgumentException if the cookie name contains illegal characters | |
| 139 | + * or it is one of the tokens reserved for use | |
| 140 | + * by the cookie protocol | |
| 141 | + * @throws NullPointerException if <tt>name</tt> is <tt>null</tt> | |
| 142 | + * @see #setValue | |
| 143 | + * @see #setVersion | |
| 144 | + * | |
| 145 | + */ | |
| 146 | + | |
| 147 | + public HttpCookie(String name, String value) { | |
| 148 | + name = name.trim(); | |
| 149 | + if (name.length() == 0 || !isToken(name) || isReserved(name)) { | |
| 150 | + throw new IllegalArgumentException("Illegal cookie name"); | |
| 151 | + } | |
| 152 | + | |
| 153 | + this.name = name; | |
| 154 | + this.value = value; | |
| 155 | + toDiscard = false; | |
| 156 | + secure = false; | |
| 157 | + | |
| 158 | + whenCreated = System.currentTimeMillis(); | |
| 159 | + portlist = null; | |
| 160 | + } | |
| 161 | + | |
| 162 | + | |
| 163 | + /** | |
| 164 | + * Constructs cookies from set-cookie or set-cookie2 header string. | |
| 165 | + * RFC 2965 section 3.2.2 set-cookie2 syntax indicates that one header line | |
| 166 | + * may contain more than one cookie definitions, so this is a static | |
| 167 | + * utility method instead of another constructor. | |
| 168 | + * | |
| 169 | + * @param header a <tt>String</tt> specifying the set-cookie header. | |
| 170 | + * The header should start with "set-cookie", or "set-cookie2" | |
| 171 | + * token; or it should have no leading token at all. | |
| 172 | + * @return a List of cookie parsed from header line string | |
| 173 | + * @throws IllegalArgumentException if header string violates the cookie | |
| 174 | + * specification's syntax, or the cookie | |
| 175 | + * name contains llegal characters, or | |
| 176 | + * the cookie name is one of the tokens | |
| 177 | + * reserved for use by the cookie protocol | |
| 178 | + * @throws NullPointerException if the header string is <tt>null</tt> | |
| 179 | + */ | |
| 180 | + public static List<HttpCookie> parse(String header) { | |
| 181 | + int version = guessCookieVersion(header); | |
| 182 | + | |
| 183 | + // if header start with set-cookie or set-cookie2, strip it off | |
| 184 | + if (startsWithIgnoreCase(header, SET_COOKIE2)) { | |
| 185 | + header = header.substring(SET_COOKIE2.length()); | |
| 186 | + } else if (startsWithIgnoreCase(header, SET_COOKIE)) { | |
| 187 | + header = header.substring(SET_COOKIE.length()); | |
| 188 | + } | |
| 189 | + | |
| 190 | + | |
| 191 | + List<HttpCookie> cookies = new java.util.ArrayList<HttpCookie>(); | |
| 192 | + // The Netscape cookie may have a comma in its expires attribute, | |
| 193 | + // while the comma is the delimiter in rfc 2965/2109 cookie header string. | |
| 194 | + // so the parse logic is slightly different | |
| 195 | + if (version == 0) { | |
| 196 | + // Netscape draft cookie | |
| 197 | + HttpCookie cookie = parseInternal(header); | |
| 198 | + cookie.setVersion(0); | |
| 199 | + cookies.add(cookie); | |
| 200 | + } else { | |
| 201 | + // rfc2965/2109 cookie | |
| 202 | + // if header string contains more than one cookie, | |
| 203 | + // it'll separate them with comma | |
| 204 | + List<String> cookieStrings = splitMultiCookies(header); | |
| 205 | + for (String cookieStr : cookieStrings) { | |
| 206 | + HttpCookie cookie = parseInternal(cookieStr); | |
| 207 | + cookie.setVersion(1); | |
| 208 | + cookies.add(cookie); | |
| 209 | + } | |
| 210 | + } | |
| 211 | + | |
| 212 | + return cookies; | |
| 213 | + } | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + /* ---------------- Public operations -------------- */ | |
| 219 | + | |
| 220 | + | |
| 221 | + /** | |
| 222 | + * Reports whether this http cookie has expired or not. | |
| 223 | + * | |
| 224 | + * @return <tt>true</tt> to indicate this http cookie has expired; | |
| 225 | + * otherwise, <tt>false</tt> | |
| 226 | + */ | |
| 227 | + public boolean hasExpired() { | |
| 228 | + if (maxAge == 0) return true; | |
| 229 | + | |
| 230 | + // if not specify max-age, this cookie should be | |
| 231 | + // discarded when user agent is to be closed, but | |
| 232 | + // it is not expired. | |
| 233 | + if (maxAge == MAX_AGE_UNSPECIFIED) return false; | |
| 234 | + | |
| 235 | + long deltaSecond = (System.currentTimeMillis() - whenCreated) / 1000; | |
| 236 | + if (deltaSecond > maxAge) | |
| 237 | + return true; | |
| 238 | + else | |
| 239 | + return false; | |
| 240 | + } | |
| 241 | + | |
| 242 | + /** | |
| 243 | + * | |
| 244 | + * Specifies a comment that describes a cookie's purpose. | |
| 245 | + * The comment is useful if the browser presents the cookie | |
| 246 | + * to the user. Comments | |
| 247 | + * are not supported by Netscape Version 0 cookies. | |
| 248 | + * | |
| 249 | + * @param purpose a <code>String</code> specifying the comment | |
| 250 | + * to display to the user | |
| 251 | + * | |
| 252 | + * @see #getComment | |
| 253 | + * | |
| 254 | + */ | |
| 255 | + | |
| 256 | + public void setComment(String purpose) { | |
| 257 | + comment = purpose; | |
| 258 | + } | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + /** | |
| 264 | + * Returns the comment describing the purpose of this cookie, or | |
| 265 | + * <code>null</code> if the cookie has no comment. | |
| 266 | + * | |
| 267 | + * @return a <code>String</code> containing the comment, | |
| 268 | + * or <code>null</code> if none | |
| 269 | + * | |
| 270 | + * @see #setComment | |
| 271 | + * | |
| 272 | + */ | |
| 273 | + | |
| 274 | + public String getComment() { | |
| 275 | + return comment; | |
| 276 | + } | |
| 277 | + | |
| 278 | + | |
| 279 | + /** | |
| 280 | + * | |
| 281 | + * Specifies a comment url that describes a cookie's purpose. | |
| 282 | + * The comment url is useful if the browser presents the cookie | |
| 283 | + * to the user. Comment url is RFC 2965 only. | |
| 284 | + * | |
| 285 | + * @param purpose a <code>String</code> specifying the comment url | |
| 286 | + * to display to the user | |
| 287 | + * | |
| 288 | + * @see #getCommentURL | |
| 289 | + * | |
| 290 | + */ | |
| 291 | + | |
| 292 | + public void setCommentURL(String purpose) { | |
| 293 | + commentURL = purpose; | |
| 294 | + } | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + /** | |
| 300 | + * Returns the comment url describing the purpose of this cookie, or | |
| 301 | + * <code>null</code> if the cookie has no comment url. | |
| 302 | + * | |
| 303 | + * @return a <code>String</code> containing the comment url, | |
| 304 | + * or <code>null</code> if none | |
| 305 | + * | |
| 306 | + * @see #setCommentURL | |
| 307 | + * | |
| 308 | + */ | |
| 309 | + | |
| 310 | + public String getCommentURL() { | |
| 311 | + return commentURL; | |
| 312 | + } | |
| 313 | + | |
| 314 | + | |
| 315 | + /** | |
| 316 | + * Specify whether user agent should discard the cookie unconditionally. | |
| 317 | + * This is RFC 2965 only attribute. | |
| 318 | + * | |
| 319 | + * @param discard <tt>true</tt> indicates to discard cookie unconditionally | |
| 320 | + * | |
| 321 | + * @see #getDiscard | |
| 322 | + */ | |
| 323 | + | |
| 324 | + public void setDiscard(boolean discard) { | |
| 325 | + toDiscard = discard; | |
| 326 | + } | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + /** | |
| 332 | + * Return the discard attribute of the cookie | |
| 333 | + * | |
| 334 | + * @return a <tt>boolean</tt> to represent this cookie's discard attribute | |
| 335 | + * | |
| 336 | + * @see #setDiscard | |
| 337 | + */ | |
| 338 | + | |
| 339 | + public boolean getDiscard() { | |
| 340 | + return toDiscard; | |
| 341 | + } | |
| 342 | + | |
| 343 | + | |
| 344 | + /** | |
| 345 | + * Specify the portlist of the cookie, which restricts the port(s) | |
| 346 | + * to which a cookie may be sent back in a Cookie header. | |
| 347 | + * | |
| 348 | + * @param ports a <tt>String</tt> specify the port list, which is | |
| 349 | + * comma seperated series of digits | |
| 350 | + * @see #getPortlist | |
| 351 | + */ | |
| 352 | + | |
| 353 | + public void setPortlist(String ports) { | |
| 354 | + portlist = ports; | |
| 355 | + } | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + /** | |
| 361 | + * Return the port list attribute of the cookie | |
| 362 | + * | |
| 363 | + * @return a <tt>String</tt> contains the port list | |
| 364 | + * or <tt>null</tt> if none | |
| 365 | + * @see #setPortlist | |
| 366 | + */ | |
| 367 | + | |
| 368 | + public String getPortlist() { | |
| 369 | + return portlist; | |
| 370 | + } | |
| 371 | + | |
| 372 | + /** | |
| 373 | + * | |
| 374 | + * Specifies the domain within which this cookie should be presented. | |
| 375 | + * | |
| 376 | + * <p>The form of the domain name is specified by RFC 2965. A domain | |
| 377 | + * name begins with a dot (<code>.foo.com</code>) and means that | |
| 378 | + * the cookie is visible to servers in a specified Domain Name System | |
| 379 | + * (DNS) zone (for example, <code>www.foo.com</code>, but not | |
| 380 | + * <code>a.b.foo.com</code>). By default, cookies are only returned | |
| 381 | + * to the server that sent them. | |
| 382 | + * | |
| 383 | + * | |
| 384 | + * @param pattern a <code>String</code> containing the domain name | |
| 385 | + * within which this cookie is visible; | |
| 386 | + * form is according to RFC 2965 | |
| 387 | + * | |
| 388 | + * @see #getDomain | |
| 389 | + * | |
| 390 | + */ | |
| 391 | + | |
| 392 | + public void setDomain(String pattern) { | |
| 393 | + if (pattern != null) | |
| 394 | + domain = pattern.toLowerCase(); | |
| 395 | + else | |
| 396 | + domain = pattern; | |
| 397 | + } | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + /** | |
| 404 | + * Returns the domain name set for this cookie. The form of | |
| 405 | + * the domain name is set by RFC 2965. | |
| 406 | + * | |
| 407 | + * @return a <code>String</code> containing the domain name | |
| 408 | + * | |
| 409 | + * @see #setDomain | |
| 410 | + * | |
| 411 | + */ | |
| 412 | + | |
| 413 | + public String getDomain() { | |
| 414 | + return domain; | |
| 415 | + } | |
| 416 | + | |
| 417 | + | |
| 418 | + /** | |
| 419 | + * Sets the maximum age of the cookie in seconds. | |
| 420 | + * | |
| 421 | + * <p>A positive value indicates that the cookie will expire | |
| 422 | + * after that many seconds have passed. Note that the value is | |
| 423 | + * the <i>maximum</i> age when the cookie will expire, not the cookie's | |
| 424 | + * current age. | |
| 425 | + * | |
| 426 | + * <p>A negative value means | |
| 427 | + * that the cookie is not stored persistently and will be deleted | |
| 428 | + * when the Web browser exits. A zero value causes the cookie | |
| 429 | + * to be deleted. | |
| 430 | + * | |
| 431 | + * @param expiry an integer specifying the maximum age of the | |
| 432 | + * cookie in seconds; if zero, the cookie | |
| 433 | + * should be discarded immediately; | |
| 434 | + * otherwise, the cookie's max age is unspecified. | |
| 435 | + * | |
| 436 | + * @see #getMaxAge | |
| 437 | + * | |
| 438 | + */ | |
| 439 | + public void setMaxAge(long expiry) { | |
| 440 | + maxAge = expiry; | |
| 441 | + } | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + /** | |
| 447 | + * Returns the maximum age of the cookie, specified in seconds. | |
| 448 | + * By default, <code>-1</code> indicating the cookie will persist | |
| 449 | + * until browser shutdown. | |
| 450 | + * | |
| 451 | + * | |
| 452 | + * @return an integer specifying the maximum age of the | |
| 453 | + * cookie in seconds | |
| 454 | + * | |
| 455 | + * | |
| 456 | + * @see #setMaxAge | |
| 457 | + * | |
| 458 | + */ | |
| 459 | + | |
| 460 | + public long getMaxAge() { | |
| 461 | + return maxAge; | |
| 462 | + } | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + /** | |
| 468 | + * Specifies a path for the cookie | |
| 469 | + * to which the client should return the cookie. | |
| 470 | + * | |
| 471 | + * <p>The cookie is visible to all the pages in the directory | |
| 472 | + * you specify, and all the pages in that directory's subdirectories. | |
| 473 | + * A cookie's path must include the servlet that set the cookie, | |
| 474 | + * for example, <i>/catalog</i>, which makes the cookie | |
| 475 | + * visible to all directories on the server under <i>/catalog</i>. | |
| 476 | + * | |
| 477 | + * <p>Consult RFC 2965 (available on the Internet) for more | |
| 478 | + * information on setting path names for cookies. | |
| 479 | + * | |
| 480 | + * | |
| 481 | + * @param uri a <code>String</code> specifying a path | |
| 482 | + * | |
| 483 | + * | |
| 484 | + * @see #getPath | |
| 485 | + * | |
| 486 | + */ | |
| 487 | + | |
| 488 | + public void setPath(String uri) { | |
| 489 | + path = uri; | |
| 490 | + } | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + /** | |
| 496 | + * Returns the path on the server | |
| 497 | + * to which the browser returns this cookie. The | |
| 498 | + * cookie is visible to all subpaths on the server. | |
| 499 | + * | |
| 500 | + * | |
| 501 | + * @return a <code>String</code> specifying a path that contains | |
| 502 | + * a servlet name, for example, <i>/catalog</i> | |
| 503 | + * | |
| 504 | + * @see #setPath | |
| 505 | + * | |
| 506 | + */ | |
| 507 | + | |
| 508 | + public String getPath() { | |
| 509 | + return path; | |
| 510 | + } | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + /** | |
| 517 | + * Indicates whether the cookie should only be sent using a secure protocol, | |
| 518 | + * such as HTTPS or SSL. | |
| 519 | + * | |
| 520 | + * <p>The default value is <code>false</code>. | |
| 521 | + * | |
| 522 | + * @param flag If <code>true</code>, the cookie can only be sent over | |
| 523 | + * a secure protocol like https. | |
| 524 | + * If <code>false</code>, it can be sent over any protocol. | |
| 525 | + * | |
| 526 | + * @see #getSecure | |
| 527 | + * | |
| 528 | + */ | |
| 529 | + | |
| 530 | + public void setSecure(boolean flag) { | |
| 531 | + secure = flag; | |
| 532 | + } | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + /** | |
| 538 | + * Returns <code>true</code> if sending this cookie should be | |
| 539 | + * restricted to a secure protocol, or <code>false</code> if the | |
| 540 | + * it can be sent using any protocol. | |
| 541 | + * | |
| 542 | + * @return <code>false</code> if the cookie can be sent over | |
| 543 | + * any standard protocol; otherwise, <code>true</code> | |
| 544 | + * | |
| 545 | + * @see #setSecure | |
| 546 | + * | |
| 547 | + */ | |
| 548 | + | |
| 549 | + public boolean getSecure() { | |
| 550 | + return secure; | |
| 551 | + } | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + /** | |
| 558 | + * Returns the name of the cookie. The name cannot be changed after | |
| 559 | + * creation. | |
| 560 | + * | |
| 561 | + * @return a <code>String</code> specifying the cookie's name | |
| 562 | + * | |
| 563 | + */ | |
| 564 | + | |
| 565 | + public String getName() { | |
| 566 | + return name; | |
| 567 | + } | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + /** | |
| 574 | + * | |
| 575 | + * Assigns a new value to a cookie after the cookie is created. | |
| 576 | + * If you use a binary value, you may want to use BASE64 encoding. | |
| 577 | + * | |
| 578 | + * <p>With Version 0 cookies, values should not contain white | |
| 579 | + * space, brackets, parentheses, equals signs, commas, | |
| 580 | + * double quotes, slashes, question marks, at signs, colons, | |
| 581 | + * and semicolons. Empty values may not behave the same way | |
| 582 | + * on all browsers. | |
| 583 | + * | |
| 584 | + * @param newValue a <code>String</code> specifying the new value | |
| 585 | + * | |
| 586 | + * | |
| 587 | + * @see #getValue | |
| 588 | + * | |
| 589 | + */ | |
| 590 | + | |
| 591 | + public void setValue(String newValue) { | |
| 592 | + value = newValue; | |
| 593 | + } | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + /** | |
| 599 | + * Returns the value of the cookie. | |
| 600 | + * | |
| 601 | + * @return a <code>String</code> containing the cookie's | |
| 602 | + * present value | |
| 603 | + * | |
| 604 | + * @see #setValue | |
| 605 | + * | |
| 606 | + */ | |
| 607 | + | |
| 608 | + public String getValue() { | |
| 609 | + return value; | |
| 610 | + } | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + /** | |
| 616 | + * Returns the version of the protocol this cookie complies | |
| 617 | + * with. Version 1 complies with RFC 2965/2109, | |
| 618 | + * and version 0 complies with the original | |
| 619 | + * cookie specification drafted by Netscape. Cookies provided | |
| 620 | + * by a browser use and identify the browser's cookie version. | |
| 621 | + * | |
| 622 | + * | |
| 623 | + * @return 0 if the cookie complies with the | |
| 624 | + * original Netscape specification; 1 | |
| 625 | + * if the cookie complies with RFC 2965/2109 | |
| 626 | + * | |
| 627 | + * @see #setVersion | |
| 628 | + * | |
| 629 | + */ | |
| 630 | + | |
| 631 | + public int getVersion() { | |
| 632 | + return version; | |
| 633 | + } | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + /** | |
| 639 | + * Sets the version of the cookie protocol this cookie complies | |
| 640 | + * with. Version 0 complies with the original Netscape cookie | |
| 641 | + * specification. Version 1 complies with RFC 2965/2109. | |
| 642 | + * | |
| 643 | + * | |
| 644 | + * @param v 0 if the cookie should comply with | |
| 645 | + * the original Netscape specification; | |
| 646 | + * 1 if the cookie should comply with RFC 2965/2109 | |
| 647 | + * | |
| 648 | + * @throws IllegalArgumentException if <tt>v</tt> is neither 0 nor 1 | |
| 649 | + * | |
| 650 | + * @see #getVersion | |
| 651 | + * | |
| 652 | + */ | |
| 653 | + | |
| 654 | + public void setVersion(int v) { | |
| 655 | + if (v != 0 && v != 1) { | |
| 656 | + throw new IllegalArgumentException("cookie version should be 0 or 1"); | |
| 657 | + } | |
| 658 | + | |
| 659 | + version = v; | |
| 660 | + } | |
| 661 | + | |
| 662 | + /** | |
| 663 | + * Returns {@code true} if this cookie contains the <i>HttpOnly</i> | |
| 664 | + * attribute. This means that the cookie should not be accessible to | |
| 665 | + * scripting engines, like javascript. | |
| 666 | + * | |
| 667 | + * @return {@code true} if this cookie should be considered http only. | |
| 668 | + * @see #setHttpOnly(boolean) | |
| 669 | + */ | |
| 670 | + public boolean isHttpOnly() | |
| 671 | + { | |
| 672 | + return httpOnly; | |
| 673 | + } | |
| 674 | + | |
| 675 | + /** | |
| 676 | + * Indicates whether the cookie should be considered HTTP Only. If set to | |
| 677 | + * {@code true} it means the cookie should not be accessible to scripting | |
| 678 | + * engines like javascript. | |
| 679 | + * | |
| 680 | + * @param httpOnly if {@code true} make the cookie HTTP only, i.e. | |
| 681 | + * only visible as part of an HTTP request. | |
| 682 | + * @see #isHttpOnly() | |
| 683 | + */ | |
| 684 | + public void setHttpOnly(boolean httpOnly) | |
| 685 | + { | |
| 686 | + this.httpOnly = httpOnly; | |
| 687 | + } | |
| 688 | + | |
| 689 | + /** | |
| 690 | + * The utility method to check whether a host name is in a domain | |
| 691 | + * or not. | |
| 692 | + * | |
| 693 | + * <p>This concept is described in the cookie specification. | |
| 694 | + * To understand the concept, some terminologies need to be defined first: | |
| 695 | + * <blockquote> | |
| 696 | + * effective host name = hostname if host name contains dot<br> | |
| 697 | + * or = hostname.local if not | |
| 698 | + * </blockquote> | |
| 699 | + * <p>Host A's name domain-matches host B's if: | |
| 700 | + * <blockquote><ul> | |
| 701 | + * <li>their host name strings string-compare equal; or</li> | |
| 702 | + * <li>A is a HDN string and has the form NB, where N is a non-empty | |
| 703 | + * name string, B has the form .B', and B' is a HDN string. (So, | |
| 704 | + * x.y.com domain-matches .Y.com but not Y.com.)</li> | |
| 705 | + * </ul></blockquote> | |
| 706 | + * | |
| 707 | + * <p>A host isn't in a domain (RFC 2965 sec. 3.3.2) if: | |
| 708 | + * <blockquote><ul> | |
| 709 | + * <li>The value for the Domain attribute contains no embedded dots, | |
| 710 | + * and the value is not .local.</li> | |
| 711 | + * <li>The effective host name that derives from the request-host does | |
| 712 | + * not domain-match the Domain attribute.</li> | |
| 713 | + * <li>The request-host is a HDN (not IP address) and has the form HD, | |
| 714 | + * where D is the value of the Domain attribute, and H is a string | |
| 715 | + * that contains one or more dots.</li> | |
| 716 | + * </ul></blockquote> | |
| 717 | + * | |
| 718 | + * <p>Examples: | |
| 719 | + * <blockquote><ul> | |
| 720 | + * <li>A Set-Cookie2 from request-host y.x.foo.com for Domain=.foo.com | |
| 721 | + * would be rejected, because H is y.x and contains a dot.</li> | |
| 722 | + * <li>A Set-Cookie2 from request-host x.foo.com for Domain=.foo.com | |
| 723 | + * would be accepted.</li> | |
| 724 | + * <li>A Set-Cookie2 with Domain=.com or Domain=.com., will always be | |
| 725 | + * rejected, because there is no embedded dot.</li> | |
| 726 | + * <li>A Set-Cookie2 with Domain=ajax.com will be accepted, and the | |
| 727 | + * value for Domain will be taken to be .ajax.com, because a dot | |
| 728 | + * gets prepended to the value.</li> | |
| 729 | + * <li>A Set-Cookie2 from request-host example for Domain=.local will | |
| 730 | + * be accepted, because the effective host name for the request- | |
| 731 | + * host is example.local, and example.local domain-matches .local.</li> | |
| 732 | + * </ul></blockquote> | |
| 733 | + * | |
| 734 | + * @param domain the domain name to check host name with | |
| 735 | + * @param host the host name in question | |
| 736 | + * @return <tt>true</tt> if they domain-matches; <tt>false</tt> if not | |
| 737 | + */ | |
| 738 | + public static boolean domainMatches(String domain, String host) { | |
| 739 | + if (domain == null || host == null) | |
| 740 | + return false; | |
| 741 | + | |
| 742 | + // if there's no embedded dot in domain and domain is not .local | |
| 743 | + boolean isLocalDomain = ".local".equalsIgnoreCase(domain); | |
| 744 | + int embeddedDotInDomain = domain.indexOf('.'); | |
| 745 | + if (embeddedDotInDomain == 0) | |
| 746 | + embeddedDotInDomain = domain.indexOf('.', 1); | |
| 747 | + if (!isLocalDomain | |
| 748 | + && (embeddedDotInDomain == -1 || embeddedDotInDomain == domain.length() - 1)) | |
| 749 | + return false; | |
| 750 | + | |
| 751 | + // if the host name contains no dot and the domain name is .local | |
| 752 | + int firstDotInHost = host.indexOf('.'); | |
| 753 | + if (firstDotInHost == -1 && isLocalDomain) | |
| 754 | + return true; | |
| 755 | + | |
| 756 | + int domainLength = domain.length(); | |
| 757 | + int lengthDiff = host.length() - domainLength; | |
| 758 | + if (lengthDiff == 0) { | |
| 759 | + // if the host name and the domain name are just string-compare euqal | |
| 760 | + return host.equalsIgnoreCase(domain); | |
| 761 | + } | |
| 762 | + else if (lengthDiff > 0) { | |
| 763 | + // need to check H & D component | |
| 764 | + String H = host.substring(0, lengthDiff); | |
| 765 | + String D = host.substring(lengthDiff); | |
| 766 | + | |
| 767 | + return (H.indexOf('.') == -1 && D.equalsIgnoreCase(domain)); | |
| 768 | + } | |
| 769 | + else if (lengthDiff == -1) { | |
| 770 | + // if domain is actually .host | |
| 771 | + return (domain.charAt(0) == '.' && | |
| 772 | + host.equalsIgnoreCase(domain.substring(1))); | |
| 773 | + } | |
| 774 | + | |
| 775 | + return false; | |
| 776 | + } | |
| 777 | + | |
| 778 | + | |
| 779 | + /** | |
| 780 | + * Constructs a cookie header string representation of this cookie, | |
| 781 | + * which is in the format defined by corresponding cookie specification, | |
| 782 | + * but without the leading "Cookie:" token. | |
| 783 | + * | |
| 784 | + * @return a string form of the cookie. The string has the defined format | |
| 785 | + */ | |
| 786 | + @Override | |
| 787 | + public String toString() { | |
| 788 | + if (getVersion() > 0) { | |
| 789 | + return toRFC2965HeaderString(); | |
| 790 | + } else { | |
| 791 | + return toNetscapeHeaderString(); | |
| 792 | + } | |
| 793 | + } | |
| 794 | + | |
| 795 | + | |
| 796 | + /** | |
| 797 | + * Test the equality of two http cookies. | |
| 798 | + * | |
| 799 | + * <p> The result is <tt>true</tt> only if two cookies | |
| 800 | + * come from same domain (case-insensitive), | |
| 801 | + * have same name (case-insensitive), | |
| 802 | + * and have same path (case-sensitive). | |
| 803 | + * | |
| 804 | + * @return <tt>true</tt> if 2 http cookies equal to each other; | |
| 805 | + * otherwise, <tt>false</tt> | |
| 806 | + */ | |
| 807 | + @Override | |
| 808 | + public boolean equals(Object obj) { | |
| 809 | + if (obj == this) | |
| 810 | + return true; | |
| 811 | + if (!(obj instanceof HttpCookie)) | |
| 812 | + return false; | |
| 813 | + HttpCookie other = (HttpCookie)obj; | |
| 814 | + | |
| 815 | + // One http cookie equals to another cookie (RFC 2965 sec. 3.3.3) if: | |
| 816 | + // 1. they come from same domain (case-insensitive), | |
| 817 | + // 2. have same name (case-insensitive), | |
| 818 | + // 3. and have same path (case-sensitive). | |
| 819 | + return equalsIgnoreCase(getName(), other.getName()) && | |
| 820 | + equalsIgnoreCase(getDomain(), other.getDomain()) && | |
| 821 | + Objects.equals(getPath(), other.getPath()); | |
| 822 | + } | |
| 823 | + | |
| 824 | + | |
| 825 | + /** | |
| 826 | + * Return hash code of this http cookie. The result is the sum of | |
| 827 | + * hash code value of three significant components of this cookie: | |
| 828 | + * name, domain, and path. | |
| 829 | + * That is, the hash code is the value of the expression: | |
| 830 | + * <blockquote> | |
| 831 | + * getName().toLowerCase().hashCode()<br> | |
| 832 | + * + getDomain().toLowerCase().hashCode()<br> | |
| 833 | + * + getPath().hashCode() | |
| 834 | + * </blockquote> | |
| 835 | + * | |
| 836 | + * @return this http cookie's hash code | |
| 837 | + */ | |
| 838 | + @Override | |
| 839 | + public int hashCode() { | |
| 840 | + int h1 = name.toLowerCase().hashCode(); | |
| 841 | + int h2 = (domain!=null) ? domain.toLowerCase().hashCode() : 0; | |
| 842 | + int h3 = (path!=null) ? path.hashCode() : 0; | |
| 843 | + | |
| 844 | + return h1 + h2 + h3; | |
| 845 | + } | |
| 846 | + | |
| 847 | + /** | |
| 848 | + * Create and return a copy of this object. | |
| 849 | + * | |
| 850 | + * @return a clone of this http cookie | |
| 851 | + */ | |
| 852 | + @Override | |
| 853 | + public Object clone() { | |
| 854 | + try { | |
| 855 | + return super.clone(); | |
| 856 | + } catch (CloneNotSupportedException e) { | |
| 857 | + throw new RuntimeException(e.getMessage()); | |
| 858 | + } | |
| 859 | + } | |
| 860 | + | |
| 861 | + | |
| 862 | + /* ---------------- Private operations -------------- */ | |
| 863 | + | |
| 864 | + // Note -- disabled for now to allow full Netscape compatibility | |
| 865 | + // from RFC 2068, token special case characters | |
| 866 | + // | |
| 867 | + // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t"; | |
| 868 | + private static final String tspecials = ",;"; | |
| 869 | + | |
| 870 | + /* | |
| 871 | + * Tests a string and returns true if the string counts as a | |
| 872 | + * token. | |
| 873 | + * | |
| 874 | + * @param value the <code>String</code> to be tested | |
| 875 | + * | |
| 876 | + * @return <code>true</code> if the <code>String</code> is | |
| 877 | + * a token; <code>false</code> if it is not | |
| 878 | + */ | |
| 879 | + | |
| 880 | + private static boolean isToken(String value) { | |
| 881 | + int len = value.length(); | |
| 882 | + | |
| 883 | + for (int i = 0; i < len; i++) { | |
| 884 | + char c = value.charAt(i); | |
| 885 | + | |
| 886 | + if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1) | |
| 887 | + return false; | |
| 888 | + } | |
| 889 | + return true; | |
| 890 | + } | |
| 891 | + | |
| 892 | + | |
| 893 | + /* | |
| 894 | + * @param name the name to be tested | |
| 895 | + * @return <tt>true</tt> if the name is reserved by cookie | |
| 896 | + * specification, <tt>false</tt> if it is not | |
| 897 | + */ | |
| 898 | + private static boolean isReserved(String name) { | |
| 899 | + if (name.equalsIgnoreCase("Comment") | |
| 900 | + || name.equalsIgnoreCase("CommentURL") // rfc2965 only | |
| 901 | + || name.equalsIgnoreCase("Discard") // rfc2965 only | |
| 902 | + || name.equalsIgnoreCase("Domain") | |
| 903 | + || name.equalsIgnoreCase("Expires") // netscape draft only | |
| 904 | + || name.equalsIgnoreCase("Max-Age") | |
| 905 | + || name.equalsIgnoreCase("Path") | |
| 906 | + || name.equalsIgnoreCase("Port") // rfc2965 only | |
| 907 | + || name.equalsIgnoreCase("Secure") | |
| 908 | + || name.equalsIgnoreCase("Version") | |
| 909 | + || name.equalsIgnoreCase("HttpOnly") | |
| 910 | + || name.charAt(0) == '$') | |
| 911 | + { | |
| 912 | + return true; | |
| 913 | + } | |
| 914 | + | |
| 915 | + return false; | |
| 916 | + } | |
| 917 | + | |
| 918 | + | |
| 919 | + /* | |
| 920 | + * Parse header string to cookie object. | |
| 921 | + * | |
| 922 | + * @param header header string; should contain only one NAME=VALUE pair | |
| 923 | + * | |
| 924 | + * @return an HttpCookie being extracted | |
| 925 | + * | |
| 926 | + * @throws IllegalArgumentException if header string violates the cookie | |
| 927 | + * specification | |
| 928 | + */ | |
| 929 | + private static HttpCookie parseInternal(String header) | |
| 930 | + { | |
| 931 | + HttpCookie cookie = null; | |
| 932 | + String namevaluePair = null; | |
| 933 | + | |
| 934 | + StringTokenizer tokenizer = new StringTokenizer(header, ";"); | |
| 935 | + | |
| 936 | + // there should always have at least on name-value pair; | |
| 937 | + // it's cookie's name | |
| 938 | + try { | |
| 939 | + namevaluePair = tokenizer.nextToken(); | |
| 940 | + int index = namevaluePair.indexOf('='); | |
| 941 | + if (index != -1) { | |
| 942 | + String name = namevaluePair.substring(0, index).trim(); | |
| 943 | + String value = namevaluePair.substring(index + 1).trim(); | |
| 944 | + cookie = new HttpCookie(name, stripOffSurroundingQuote(value)); | |
| 945 | + } else { | |
| 946 | + // no "=" in name-value pair; it's an error | |
| 947 | + throw new IllegalArgumentException("Invalid cookie name-value pair"); | |
| 948 | + } | |
| 949 | + } catch (NoSuchElementException ignored) { | |
| 950 | + throw new IllegalArgumentException("Empty cookie header string"); | |
| 951 | + } | |
| 952 | + | |
| 953 | + // remaining name-value pairs are cookie's attributes | |
| 954 | + while (tokenizer.hasMoreTokens()) { | |
| 955 | + namevaluePair = tokenizer.nextToken(); | |
| 956 | + int index = namevaluePair.indexOf('='); | |
| 957 | + String name, value; | |
| 958 | + if (index != -1) { | |
| 959 | + name = namevaluePair.substring(0, index).trim(); | |
| 960 | + value = namevaluePair.substring(index + 1).trim(); | |
| 961 | + } else { | |
| 962 | + name = namevaluePair.trim(); | |
| 963 | + value = null; | |
| 964 | + } | |
| 965 | + | |
| 966 | + // assign attribute to cookie | |
| 967 | + assignAttribute(cookie, name, value); | |
| 968 | + } | |
| 969 | + | |
| 970 | + return cookie; | |
| 971 | + } | |
| 972 | + | |
| 973 | + | |
| 974 | + /* | |
| 975 | + * assign cookie attribute value to attribute name; | |
| 976 | + * use a map to simulate method dispatch | |
| 977 | + */ | |
| 978 | + static interface CookieAttributeAssignor { | |
| 979 | + public void assign(HttpCookie cookie, String attrName, String attrValue); | |
| 980 | + } | |
| 981 | + static java.util.Map<String, CookieAttributeAssignor> assignors = null; | |
| 982 | + static { | |
| 983 | + assignors = new java.util.HashMap<String, CookieAttributeAssignor>(); | |
| 984 | + assignors.put("comment", new CookieAttributeAssignor(){ | |
| 985 | + public void assign(HttpCookie cookie, String attrName, String attrValue) { | |
| 986 | + if (cookie.getComment() == null) cookie.setComment(attrValue); | |
| 987 | + } | |
| 988 | + }); | |
| 989 | + assignors.put("commenturl", new CookieAttributeAssignor(){ | |
| 990 | + public void assign(HttpCookie cookie, String attrName, String attrValue) { | |
| 991 | + if (cookie.getCommentURL() == null) cookie.setCommentURL(attrValue); | |
| 992 | + } | |
| 993 | + }); | |
| 994 | + assignors.put("discard", new CookieAttributeAssignor(){ | |
| 995 | + public void assign(HttpCookie cookie, String attrName, String attrValue) { | |
| 996 | + cookie.setDiscard(true); | |
| 997 | + } | |
| 998 | + }); | |
| 999 | + assignors.put("domain", new CookieAttributeAssignor(){ | |
| 1000 | + public void assign(HttpCookie cookie, String attrName, String attrValue) { | |
| 1001 | + if (cookie.getDomain() == null) cookie.setDomain(attrValue); | |
| 1002 | + } | |
| 1003 | + }); | |
| 1004 | + assignors.put("max-age", new CookieAttributeAssignor(){ | |
| 1005 | + public void assign(HttpCookie cookie, String attrName, String attrValue) { | |
| 1006 | + try { | |
| 1007 | + long maxage = Long.parseLong(attrValue); | |
| 1008 | + if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED) cookie.setMaxAge(maxage); | |
| 1009 | + } catch (NumberFormatException ignored) { | |
| 1010 | + throw new IllegalArgumentException("Illegal cookie max-age attribute"); | |
| 1011 | + } | |
| 1012 | + } | |
| 1013 | + }); | |
| 1014 | + assignors.put("path", new CookieAttributeAssignor(){ | |
| 1015 | + public void assign(HttpCookie cookie, String attrName, String attrValue) { | |
| 1016 | + if (cookie.getPath() == null) cookie.setPath(attrValue); | |
| 1017 | + } | |
| 1018 | + }); | |
| 1019 | + assignors.put("port", new CookieAttributeAssignor(){ | |
| 1020 | + public void assign(HttpCookie cookie, String attrName, String attrValue) { | |
| 1021 | + if (cookie.getPortlist() == null) cookie.setPortlist(attrValue == null ? "" : attrValue); | |
| 1022 | + } | |
| 1023 | + }); | |
| 1024 | + assignors.put("secure", new CookieAttributeAssignor(){ | |
| 1025 | + public void assign(HttpCookie cookie, String attrName, String attrValue) { | |
| 1026 | + cookie.setSecure(true); | |
| 1027 | + } | |
| 1028 | + }); | |
| 1029 | + assignors.put("httponly", new CookieAttributeAssignor(){ | |
| 1030 | + public void assign(HttpCookie cookie, String attrName, String attrValue) { | |
| 1031 | + cookie.setHttpOnly(true); | |
| 1032 | + } | |
| 1033 | + }); | |
| 1034 | + assignors.put("version", new CookieAttributeAssignor(){ | |
| 1035 | + public void assign(HttpCookie cookie, String attrName, String attrValue) { | |
| 1036 | + try { | |
| 1037 | + int version = Integer.parseInt(attrValue); | |
| 1038 | + cookie.setVersion(version); | |
| 1039 | + } catch (NumberFormatException ignored) { | |
| 1040 | + // Just ignore bogus version, it will default to 0 or 1 | |
| 1041 | + } | |
| 1042 | + } | |
| 1043 | + }); | |
| 1044 | + assignors.put("expires", new CookieAttributeAssignor(){ // Netscape only | |
| 1045 | + public void assign(HttpCookie cookie, String attrName, String attrValue) { | |
| 1046 | + if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED) { | |
| 1047 | + cookie.setMaxAge(cookie.expiryDate2DeltaSeconds(attrValue)); | |
| 1048 | + } | |
| 1049 | + } | |
| 1050 | + }); | |
| 1051 | + } | |
| 1052 | + private static void assignAttribute(HttpCookie cookie, | |
| 1053 | + String attrName, | |
| 1054 | + String attrValue) | |
| 1055 | + { | |
| 1056 | + // strip off the surrounding "-sign if there's any | |
| 1057 | + attrValue = stripOffSurroundingQuote(attrValue); | |
| 1058 | + | |
| 1059 | + CookieAttributeAssignor assignor = assignors.get(attrName.toLowerCase()); | |
| 1060 | + if (assignor != null) { | |
| 1061 | + assignor.assign(cookie, attrName, attrValue); | |
| 1062 | + } else { | |
| 1063 | + // Ignore the attribute as per RFC 2965 | |
| 1064 | + } | |
| 1065 | + } | |
| 1066 | + | |
| 1067 | + /* | |
| 1068 | + * Constructs a string representation of this cookie. The string format is | |
| 1069 | + * as Netscape spec, but without leading "Cookie:" token. | |
| 1070 | + */ | |
| 1071 | + private String toNetscapeHeaderString() { | |
| 1072 | + StringBuilder sb = new StringBuilder(); | |
| 1073 | + | |
| 1074 | + sb.append(getName() + "=" + getValue()); | |
| 1075 | + | |
| 1076 | + return sb.toString(); | |
| 1077 | + } | |
| 1078 | + | |
| 1079 | + /* | |
| 1080 | + * Constructs a string representation of this cookie. The string format is | |
| 1081 | + * as RFC 2965/2109, but without leading "Cookie:" token. | |
| 1082 | + */ | |
| 1083 | + private String toRFC2965HeaderString() { | |
| 1084 | + StringBuilder sb = new StringBuilder(); | |
| 1085 | + | |
| 1086 | + sb.append(getName()).append("=\"").append(getValue()).append('"'); | |
| 1087 | + if (getPath() != null) | |
| 1088 | + sb.append(";$Path=\"").append(getPath()).append('"'); | |
| 1089 | + if (getDomain() != null) | |
| 1090 | + sb.append(";$Domain=\"").append(getDomain()).append('"'); | |
| 1091 | + if (getPortlist() != null) | |
| 1092 | + sb.append(";$Port=\"").append(getPortlist()).append('"'); | |
| 1093 | + | |
| 1094 | + return sb.toString(); | |
| 1095 | + } | |
| 1096 | + | |
| 1097 | + static final TimeZone GMT = TimeZone.getTimeZone("GMT"); | |
| 1098 | + | |
| 1099 | + /* | |
| 1100 | + * @param dateString a date string in one of the formats | |
| 1101 | + * defined in Netscape cookie spec | |
| 1102 | + * | |
| 1103 | + * @return delta seconds between this cookie's creation | |
| 1104 | + * time and the time specified by dateString | |
| 1105 | + */ | |
| 1106 | + private long expiryDate2DeltaSeconds(String dateString) { | |
| 1107 | + for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) { | |
| 1108 | + SimpleDateFormat df = new SimpleDateFormat(COOKIE_DATE_FORMATS[i], Locale.US); | |
| 1109 | + df.setTimeZone(GMT); | |
| 1110 | + try { | |
| 1111 | + Date date = df.parse(dateString); | |
| 1112 | + return (date.getTime() - whenCreated) / 1000; | |
| 1113 | + } catch (Exception e) { | |
| 1114 | + // Ignore, try the next date format | |
| 1115 | + } | |
| 1116 | + } | |
| 1117 | + return 0; | |
| 1118 | + } | |
| 1119 | + | |
| 1120 | + | |
| 1121 | + | |
| 1122 | + /* | |
| 1123 | + * try to guess the cookie version through set-cookie header string | |
| 1124 | + */ | |
| 1125 | + private static int guessCookieVersion(String header) { | |
| 1126 | + int version = 0; | |
| 1127 | + | |
| 1128 | + header = header.toLowerCase(); | |
| 1129 | + if (header.indexOf("expires=") != -1) { | |
| 1130 | + // only netscape cookie using 'expires' | |
| 1131 | + version = 0; | |
| 1132 | + } else if (header.indexOf("version=") != -1) { | |
| 1133 | + // version is mandatory for rfc 2965/2109 cookie | |
| 1134 | + version = 1; | |
| 1135 | + } else if (header.indexOf("max-age") != -1) { | |
| 1136 | + // rfc 2965/2109 use 'max-age' | |
| 1137 | + version = 1; | |
| 1138 | + } else if (startsWithIgnoreCase(header, SET_COOKIE2)) { | |
| 1139 | + // only rfc 2965 cookie starts with 'set-cookie2' | |
| 1140 | + version = 1; | |
| 1141 | + } | |
| 1142 | + | |
| 1143 | + return version; | |
| 1144 | + } | |
| 1145 | + | |
| 1146 | + private static String stripOffSurroundingQuote(String str) { | |
| 1147 | + if (str != null && str.length() > 2 && | |
| 1148 | + str.charAt(0) == '"' && str.charAt(str.length() - 1) == '"') { | |
| 1149 | + return str.substring(1, str.length() - 1); | |
| 1150 | + } | |
| 1151 | + if (str != null && str.length() > 2 && | |
| 1152 | + str.charAt(0) == '\'' && str.charAt(str.length() - 1) == '\'') { | |
| 1153 | + return str.substring(1, str.length() - 1); | |
| 1154 | + } | |
| 1155 | + return str; | |
| 1156 | + } | |
| 1157 | + | |
| 1158 | + private static boolean equalsIgnoreCase(String s, String t) { | |
| 1159 | + if (s == t) return true; | |
| 1160 | + if ((s != null) && (t != null)) { | |
| 1161 | + return s.equalsIgnoreCase(t); | |
| 1162 | + } | |
| 1163 | + return false; | |
| 1164 | + } | |
| 1165 | + | |
| 1166 | + private static boolean startsWithIgnoreCase(String s, String start) { | |
| 1167 | + if (s == null || start == null) return false; | |
| 1168 | + | |
| 1169 | + if (s.length() >= start.length() && | |
| 1170 | + start.equalsIgnoreCase(s.substring(0, start.length()))) { | |
| 1171 | + return true; | |
| 1172 | + } | |
| 1173 | + | |
| 1174 | + return false; | |
| 1175 | + } | |
| 1176 | + | |
| 1177 | + /* | |
| 1178 | + * Split cookie header string according to rfc 2965: | |
| 1179 | + * 1) split where it is a comma; | |
| 1180 | + * 2) but not the comma surrounding by double-quotes, which is the comma | |
| 1181 | + * inside port list or embeded URIs. | |
| 1182 | + * | |
| 1183 | + * @param header the cookie header string to split | |
| 1184 | + * | |
| 1185 | + * @return list of strings; never null | |
| 1186 | + * | |
| 1187 | + */ | |
| 1188 | + private static List<String> splitMultiCookies(String header) { | |
| 1189 | + List<String> cookies = new java.util.ArrayList<String>(); | |
| 1190 | + int quoteCount = 0; | |
| 1191 | + int p, q; | |
| 1192 | + | |
| 1193 | + for (p = 0, q = 0; p < header.length(); p++) { | |
| 1194 | + char c = header.charAt(p); | |
| 1195 | + if (c == '"') quoteCount++; | |
| 1196 | + if (c == ',' && (quoteCount % 2 == 0)) { // it is comma and not surrounding by double-quotes | |
| 1197 | + cookies.add(header.substring(q, p)); | |
| 1198 | + q = p + 1; | |
| 1199 | + } | |
| 1200 | + } | |
| 1201 | + | |
| 1202 | + cookies.add(header.substring(q)); | |
| 1203 | + | |
| 1204 | + return cookies; | |
| 1205 | + } | |
| 1206 | +} | |
Binary file not shown.
| @@ -0,0 +1,99 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2004, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * Thrown to indicate that a HTTP request needs to be retried | |
| 32 | + * but cannot be retried automatically, due to streaming mode | |
| 33 | + * being enabled. | |
| 34 | + * | |
| 35 | + * @author Michael McMahon | |
| 36 | + * @since 1.5 | |
| 37 | + */ | |
| 38 | +public | |
| 39 | +class HttpRetryException extends IOException { | |
| 40 | + private static final long serialVersionUID = -9186022286469111381L; | |
| 41 | + | |
| 42 | + private int responseCode; | |
| 43 | + private String location; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * Constructs a new <code>HttpRetryException</code> from the | |
| 47 | + * specified response code and exception detail message | |
| 48 | + * | |
| 49 | + * @param detail the detail message. | |
| 50 | + * @param code the HTTP response code from server. | |
| 51 | + */ | |
| 52 | + public HttpRetryException(String detail, int code) { | |
| 53 | + super(detail); | |
| 54 | + responseCode = code; | |
| 55 | + } | |
| 56 | + | |
| 57 | + /** | |
| 58 | + * Constructs a new <code>HttpRetryException</code> with detail message | |
| 59 | + * responseCode and the contents of the Location response header field. | |
| 60 | + * | |
| 61 | + * @param detail the detail message. | |
| 62 | + * @param code the HTTP response code from server. | |
| 63 | + * @param location the URL to be redirected to | |
| 64 | + */ | |
| 65 | + public HttpRetryException(String detail, int code, String location) { | |
| 66 | + super (detail); | |
| 67 | + responseCode = code; | |
| 68 | + this.location = location; | |
| 69 | + } | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * Returns the http response code | |
| 73 | + * | |
| 74 | + * @return The http response code. | |
| 75 | + */ | |
| 76 | + public int responseCode() { | |
| 77 | + return responseCode; | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * Returns a string explaining why the http request could | |
| 82 | + * not be retried. | |
| 83 | + * | |
| 84 | + * @return The reason string | |
| 85 | + */ | |
| 86 | + public String getReason() { | |
| 87 | + return super.getMessage(); | |
| 88 | + } | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * Returns the value of the Location header field if the | |
| 92 | + * error resulted from redirection. | |
| 93 | + * | |
| 94 | + * @return The location string | |
| 95 | + */ | |
| 96 | + public String getLocation() { | |
| 97 | + return location; | |
| 98 | + } | |
| 99 | +} | |
Binary file not shown.
| @@ -0,0 +1,804 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2011, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.InputStream; | |
| 29 | +import java.io.IOException; | |
| 30 | +import java.security.Permission; | |
| 31 | +import java.util.Date; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * A URLConnection with support for HTTP-specific features. See | |
| 35 | + * <A HREF="http://www.w3.org/pub/WWW/Protocols/"> the spec </A> for | |
| 36 | + * details. | |
| 37 | + * <p> | |
| 38 | + * | |
| 39 | + * Each HttpURLConnection instance is used to make a single request | |
| 40 | + * but the underlying network connection to the HTTP server may be | |
| 41 | + * transparently shared by other instances. Calling the close() methods | |
| 42 | + * on the InputStream or OutputStream of an HttpURLConnection | |
| 43 | + * after a request may free network resources associated with this | |
| 44 | + * instance but has no effect on any shared persistent connection. | |
| 45 | + * Calling the disconnect() method may close the underlying socket | |
| 46 | + * if a persistent connection is otherwise idle at that time. | |
| 47 | + * | |
| 48 | + * <P>The HTTP protocol handler has a few settings that can be accessed through | |
| 49 | + * System Properties. This covers | |
| 50 | + * <a href="doc-files/net-properties.html#Proxies">Proxy settings</a> as well as | |
| 51 | + * <a href="doc-files/net-properties.html#MiscHTTP"> various other settings</a>. | |
| 52 | + * </P> | |
| 53 | + * | |
| 54 | + * @see java.net.HttpURLConnection#disconnect() | |
| 55 | + * @since JDK1.1 | |
| 56 | + */ | |
| 57 | +abstract public class HttpURLConnection extends URLConnection { | |
| 58 | + /* instance variables */ | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * The HTTP method (GET,POST,PUT,etc.). | |
| 62 | + */ | |
| 63 | + protected String method = "GET"; | |
| 64 | + | |
| 65 | + /** | |
| 66 | + * The chunk-length when using chunked encoding streaming mode for output. | |
| 67 | + * A value of <code>-1</code> means chunked encoding is disabled for output. | |
| 68 | + * @since 1.5 | |
| 69 | + */ | |
| 70 | + protected int chunkLength = -1; | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * The fixed content-length when using fixed-length streaming mode. | |
| 74 | + * A value of <code>-1</code> means fixed-length streaming mode is disabled | |
| 75 | + * for output. | |
| 76 | + * | |
| 77 | + * <P> <B>NOTE:</B> {@link #fixedContentLengthLong} is recommended instead | |
| 78 | + * of this field, as it allows larger content lengths to be set. | |
| 79 | + * | |
| 80 | + * @since 1.5 | |
| 81 | + */ | |
| 82 | + protected int fixedContentLength = -1; | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * The fixed content-length when using fixed-length streaming mode. | |
| 86 | + * A value of {@code -1} means fixed-length streaming mode is disabled | |
| 87 | + * for output. | |
| 88 | + * | |
| 89 | + * @since 1.7 | |
| 90 | + */ | |
| 91 | + protected long fixedContentLengthLong = -1; | |
| 92 | + | |
| 93 | + /** | |
| 94 | + * Returns the key for the <code>n</code><sup>th</sup> header field. | |
| 95 | + * Some implementations may treat the <code>0</code><sup>th</sup> | |
| 96 | + * header field as special, i.e. as the status line returned by the HTTP | |
| 97 | + * server. In this case, {@link #getHeaderField(int) getHeaderField(0)} returns the status | |
| 98 | + * line, but <code>getHeaderFieldKey(0)</code> returns null. | |
| 99 | + * | |
| 100 | + * @param n an index, where n >=0. | |
| 101 | + * @return the key for the <code>n</code><sup>th</sup> header field, | |
| 102 | + * or <code>null</code> if the key does not exist. | |
| 103 | + */ | |
| 104 | + public String getHeaderFieldKey (int n) { | |
| 105 | + return null; | |
| 106 | + } | |
| 107 | + | |
| 108 | + /** | |
| 109 | + * This method is used to enable streaming of a HTTP request body | |
| 110 | + * without internal buffering, when the content length is known in | |
| 111 | + * advance. | |
| 112 | + * <p> | |
| 113 | + * An exception will be thrown if the application | |
| 114 | + * attempts to write more data than the indicated | |
| 115 | + * content-length, or if the application closes the OutputStream | |
| 116 | + * before writing the indicated amount. | |
| 117 | + * <p> | |
| 118 | + * When output streaming is enabled, authentication | |
| 119 | + * and redirection cannot be handled automatically. | |
| 120 | + * A HttpRetryException will be thrown when reading | |
| 121 | + * the response if authentication or redirection are required. | |
| 122 | + * This exception can be queried for the details of the error. | |
| 123 | + * <p> | |
| 124 | + * This method must be called before the URLConnection is connected. | |
| 125 | + * <p> | |
| 126 | + * <B>NOTE:</B> {@link #setFixedLengthStreamingMode(long)} is recommended | |
| 127 | + * instead of this method as it allows larger content lengths to be set. | |
| 128 | + * | |
| 129 | + * @param contentLength The number of bytes which will be written | |
| 130 | + * to the OutputStream. | |
| 131 | + * | |
| 132 | + * @throws IllegalStateException if URLConnection is already connected | |
| 133 | + * or if a different streaming mode is already enabled. | |
| 134 | + * | |
| 135 | + * @throws IllegalArgumentException if a content length less than | |
| 136 | + * zero is specified. | |
| 137 | + * | |
| 138 | + * @see #setChunkedStreamingMode(int) | |
| 139 | + * @since 1.5 | |
| 140 | + */ | |
| 141 | + public void setFixedLengthStreamingMode (int contentLength) { | |
| 142 | + if (connected) { | |
| 143 | + throw new IllegalStateException ("Already connected"); | |
| 144 | + } | |
| 145 | + if (chunkLength != -1) { | |
| 146 | + throw new IllegalStateException ("Chunked encoding streaming mode set"); | |
| 147 | + } | |
| 148 | + if (contentLength < 0) { | |
| 149 | + throw new IllegalArgumentException ("invalid content length"); | |
| 150 | + } | |
| 151 | + fixedContentLength = contentLength; | |
| 152 | + } | |
| 153 | + | |
| 154 | + /** | |
| 155 | + * This method is used to enable streaming of a HTTP request body | |
| 156 | + * without internal buffering, when the content length is known in | |
| 157 | + * advance. | |
| 158 | + * | |
| 159 | + * <P> An exception will be thrown if the application attempts to write | |
| 160 | + * more data than the indicated content-length, or if the application | |
| 161 | + * closes the OutputStream before writing the indicated amount. | |
| 162 | + * | |
| 163 | + * <P> When output streaming is enabled, authentication and redirection | |
| 164 | + * cannot be handled automatically. A {@linkplain HttpRetryException} will | |
| 165 | + * be thrown when reading the response if authentication or redirection | |
| 166 | + * are required. This exception can be queried for the details of the | |
| 167 | + * error. | |
| 168 | + * | |
| 169 | + * <P> This method must be called before the URLConnection is connected. | |
| 170 | + * | |
| 171 | + * <P> The content length set by invoking this method takes precedence | |
| 172 | + * over any value set by {@link #setFixedLengthStreamingMode(int)}. | |
| 173 | + * | |
| 174 | + * @param contentLength | |
| 175 | + * The number of bytes which will be written to the OutputStream. | |
| 176 | + * | |
| 177 | + * @throws IllegalStateException | |
| 178 | + * if URLConnection is already connected or if a different | |
| 179 | + * streaming mode is already enabled. | |
| 180 | + * | |
| 181 | + * @throws IllegalArgumentException | |
| 182 | + * if a content length less than zero is specified. | |
| 183 | + * | |
| 184 | + * @since 1.7 | |
| 185 | + */ | |
| 186 | + public void setFixedLengthStreamingMode(long contentLength) { | |
| 187 | + if (connected) { | |
| 188 | + throw new IllegalStateException("Already connected"); | |
| 189 | + } | |
| 190 | + if (chunkLength != -1) { | |
| 191 | + throw new IllegalStateException( | |
| 192 | + "Chunked encoding streaming mode set"); | |
| 193 | + } | |
| 194 | + if (contentLength < 0) { | |
| 195 | + throw new IllegalArgumentException("invalid content length"); | |
| 196 | + } | |
| 197 | + fixedContentLengthLong = contentLength; | |
| 198 | + } | |
| 199 | + | |
| 200 | + /* Default chunk size (including chunk header) if not specified; | |
| 201 | + * we want to keep this in sync with the one defined in | |
| 202 | + * sun.net.www.http.ChunkedOutputStream | |
| 203 | + */ | |
| 204 | + private static final int DEFAULT_CHUNK_SIZE = 4096; | |
| 205 | + | |
| 206 | + /** | |
| 207 | + * This method is used to enable streaming of a HTTP request body | |
| 208 | + * without internal buffering, when the content length is <b>not</b> | |
| 209 | + * known in advance. In this mode, chunked transfer encoding | |
| 210 | + * is used to send the request body. Note, not all HTTP servers | |
| 211 | + * support this mode. | |
| 212 | + * <p> | |
| 213 | + * When output streaming is enabled, authentication | |
| 214 | + * and redirection cannot be handled automatically. | |
| 215 | + * A HttpRetryException will be thrown when reading | |
| 216 | + * the response if authentication or redirection are required. | |
| 217 | + * This exception can be queried for the details of the error. | |
| 218 | + * <p> | |
| 219 | + * This method must be called before the URLConnection is connected. | |
| 220 | + * | |
| 221 | + * @param chunklen The number of bytes to write in each chunk. | |
| 222 | + * If chunklen is less than or equal to zero, a default | |
| 223 | + * value will be used. | |
| 224 | + * | |
| 225 | + * @throws IllegalStateException if URLConnection is already connected | |
| 226 | + * or if a different streaming mode is already enabled. | |
| 227 | + * | |
| 228 | + * @see #setFixedLengthStreamingMode(int) | |
| 229 | + * @since 1.5 | |
| 230 | + */ | |
| 231 | + public void setChunkedStreamingMode (int chunklen) { | |
| 232 | + if (connected) { | |
| 233 | + throw new IllegalStateException ("Can't set streaming mode: already connected"); | |
| 234 | + } | |
| 235 | + if (fixedContentLength != -1 || fixedContentLengthLong != -1) { | |
| 236 | + throw new IllegalStateException ("Fixed length streaming mode set"); | |
| 237 | + } | |
| 238 | + chunkLength = chunklen <=0? DEFAULT_CHUNK_SIZE : chunklen; | |
| 239 | + } | |
| 240 | + | |
| 241 | + /** | |
| 242 | + * Returns the value for the <code>n</code><sup>th</sup> header field. | |
| 243 | + * Some implementations may treat the <code>0</code><sup>th</sup> | |
| 244 | + * header field as special, i.e. as the status line returned by the HTTP | |
| 245 | + * server. | |
| 246 | + * <p> | |
| 247 | + * This method can be used in conjunction with the | |
| 248 | + * {@link #getHeaderFieldKey getHeaderFieldKey} method to iterate through all | |
| 249 | + * the headers in the message. | |
| 250 | + * | |
| 251 | + * @param n an index, where n>=0. | |
| 252 | + * @return the value of the <code>n</code><sup>th</sup> header field, | |
| 253 | + * or <code>null</code> if the value does not exist. | |
| 254 | + * @see java.net.HttpURLConnection#getHeaderFieldKey(int) | |
| 255 | + */ | |
| 256 | + public String getHeaderField(int n) { | |
| 257 | + return null; | |
| 258 | + } | |
| 259 | + | |
| 260 | + /** | |
| 261 | + * An <code>int</code> representing the three digit HTTP Status-Code. | |
| 262 | + * <ul> | |
| 263 | + * <li> 1xx: Informational | |
| 264 | + * <li> 2xx: Success | |
| 265 | + * <li> 3xx: Redirection | |
| 266 | + * <li> 4xx: Client Error | |
| 267 | + * <li> 5xx: Server Error | |
| 268 | + * </ul> | |
| 269 | + */ | |
| 270 | + protected int responseCode = -1; | |
| 271 | + | |
| 272 | + /** | |
| 273 | + * The HTTP response message. | |
| 274 | + */ | |
| 275 | + protected String responseMessage = null; | |
| 276 | + | |
| 277 | + /* static variables */ | |
| 278 | + | |
| 279 | + /* do we automatically follow redirects? The default is true. */ | |
| 280 | + private static boolean followRedirects = true; | |
| 281 | + | |
| 282 | + /** | |
| 283 | + * If <code>true</code>, the protocol will automatically follow redirects. | |
| 284 | + * If <code>false</code>, the protocol will not automatically follow | |
| 285 | + * redirects. | |
| 286 | + * <p> | |
| 287 | + * This field is set by the <code>setInstanceFollowRedirects</code> | |
| 288 | + * method. Its value is returned by the <code>getInstanceFollowRedirects</code> | |
| 289 | + * method. | |
| 290 | + * <p> | |
| 291 | + * Its default value is based on the value of the static followRedirects | |
| 292 | + * at HttpURLConnection construction time. | |
| 293 | + * | |
| 294 | + * @see java.net.HttpURLConnection#setInstanceFollowRedirects(boolean) | |
| 295 | + * @see java.net.HttpURLConnection#getInstanceFollowRedirects() | |
| 296 | + * @see java.net.HttpURLConnection#setFollowRedirects(boolean) | |
| 297 | + */ | |
| 298 | + protected boolean instanceFollowRedirects = followRedirects; | |
| 299 | + | |
| 300 | + /* valid HTTP methods */ | |
| 301 | + private static final String[] methods = { | |
| 302 | + "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE" | |
| 303 | + }; | |
| 304 | + | |
| 305 | + /** | |
| 306 | + * Constructor for the HttpURLConnection. | |
| 307 | + * @param u the URL | |
| 308 | + */ | |
| 309 | + protected HttpURLConnection (URL u) { | |
| 310 | + super(u); | |
| 311 | + } | |
| 312 | + | |
| 313 | + /** | |
| 314 | + * Sets whether HTTP redirects (requests with response code 3xx) should | |
| 315 | + * be automatically followed by this class. True by default. Applets | |
| 316 | + * cannot change this variable. | |
| 317 | + * <p> | |
| 318 | + * If there is a security manager, this method first calls | |
| 319 | + * the security manager's <code>checkSetFactory</code> method | |
| 320 | + * to ensure the operation is allowed. | |
| 321 | + * This could result in a SecurityException. | |
| 322 | + * | |
| 323 | + * @param set a <code>boolean</code> indicating whether or not | |
| 324 | + * to follow HTTP redirects. | |
| 325 | + * @exception SecurityException if a security manager exists and its | |
| 326 | + * <code>checkSetFactory</code> method doesn't | |
| 327 | + * allow the operation. | |
| 328 | + * @see SecurityManager#checkSetFactory | |
| 329 | + * @see #getFollowRedirects() | |
| 330 | + */ | |
| 331 | + public static void setFollowRedirects(boolean set) { | |
| 332 | + SecurityManager sec = System.getSecurityManager(); | |
| 333 | + if (sec != null) { | |
| 334 | + // seems to be the best check here... | |
| 335 | + sec.checkSetFactory(); | |
| 336 | + } | |
| 337 | + followRedirects = set; | |
| 338 | + } | |
| 339 | + | |
| 340 | + /** | |
| 341 | + * Returns a <code>boolean</code> indicating | |
| 342 | + * whether or not HTTP redirects (3xx) should | |
| 343 | + * be automatically followed. | |
| 344 | + * | |
| 345 | + * @return <code>true</code> if HTTP redirects should | |
| 346 | + * be automatically followed, <tt>false</tt> if not. | |
| 347 | + * @see #setFollowRedirects(boolean) | |
| 348 | + */ | |
| 349 | + public static boolean getFollowRedirects() { | |
| 350 | + return followRedirects; | |
| 351 | + } | |
| 352 | + | |
| 353 | + /** | |
| 354 | + * Sets whether HTTP redirects (requests with response code 3xx) should | |
| 355 | + * be automatically followed by this <code>HttpURLConnection</code> | |
| 356 | + * instance. | |
| 357 | + * <p> | |
| 358 | + * The default value comes from followRedirects, which defaults to | |
| 359 | + * true. | |
| 360 | + * | |
| 361 | + * @param followRedirects a <code>boolean</code> indicating | |
| 362 | + * whether or not to follow HTTP redirects. | |
| 363 | + * | |
| 364 | + * @see java.net.HttpURLConnection#instanceFollowRedirects | |
| 365 | + * @see #getInstanceFollowRedirects | |
| 366 | + * @since 1.3 | |
| 367 | + */ | |
| 368 | + public void setInstanceFollowRedirects(boolean followRedirects) { | |
| 369 | + instanceFollowRedirects = followRedirects; | |
| 370 | + } | |
| 371 | + | |
| 372 | + /** | |
| 373 | + * Returns the value of this <code>HttpURLConnection</code>'s | |
| 374 | + * <code>instanceFollowRedirects</code> field. | |
| 375 | + * | |
| 376 | + * @return the value of this <code>HttpURLConnection</code>'s | |
| 377 | + * <code>instanceFollowRedirects</code> field. | |
| 378 | + * @see java.net.HttpURLConnection#instanceFollowRedirects | |
| 379 | + * @see #setInstanceFollowRedirects(boolean) | |
| 380 | + * @since 1.3 | |
| 381 | + */ | |
| 382 | + public boolean getInstanceFollowRedirects() { | |
| 383 | + return instanceFollowRedirects; | |
| 384 | + } | |
| 385 | + | |
| 386 | + /** | |
| 387 | + * Set the method for the URL request, one of: | |
| 388 | + * <UL> | |
| 389 | + * <LI>GET | |
| 390 | + * <LI>POST | |
| 391 | + * <LI>HEAD | |
| 392 | + * <LI>OPTIONS | |
| 393 | + * <LI>PUT | |
| 394 | + * <LI>DELETE | |
| 395 | + * <LI>TRACE | |
| 396 | + * </UL> are legal, subject to protocol restrictions. The default | |
| 397 | + * method is GET. | |
| 398 | + * | |
| 399 | + * @param method the HTTP method | |
| 400 | + * @exception ProtocolException if the method cannot be reset or if | |
| 401 | + * the requested method isn't valid for HTTP. | |
| 402 | + * @exception SecurityException if a security manager is set and the | |
| 403 | + * method is "TRACE", but the "allowHttpTrace" | |
| 404 | + * NetPermission is not granted. | |
| 405 | + * @see #getRequestMethod() | |
| 406 | + */ | |
| 407 | + public void setRequestMethod(String method) throws ProtocolException { | |
| 408 | + if (connected) { | |
| 409 | + throw new ProtocolException("Can't reset method: already connected"); | |
| 410 | + } | |
| 411 | + // This restriction will prevent people from using this class to | |
| 412 | + // experiment w/ new HTTP methods using java. But it should | |
| 413 | + // be placed for security - the request String could be | |
| 414 | + // arbitrarily long. | |
| 415 | + | |
| 416 | + for (int i = 0; i < methods.length; i++) { | |
| 417 | + if (methods[i].equals(method)) { | |
| 418 | + if (method.equals("TRACE")) { | |
| 419 | + SecurityManager s = System.getSecurityManager(); | |
| 420 | + if (s != null) { | |
| 421 | + s.checkPermission(new NetPermission("allowHttpTrace")); | |
| 422 | + } | |
| 423 | + } | |
| 424 | + this.method = method; | |
| 425 | + return; | |
| 426 | + } | |
| 427 | + } | |
| 428 | + throw new ProtocolException("Invalid HTTP method: " + method); | |
| 429 | + } | |
| 430 | + | |
| 431 | + /** | |
| 432 | + * Get the request method. | |
| 433 | + * @return the HTTP request method | |
| 434 | + * @see #setRequestMethod(java.lang.String) | |
| 435 | + */ | |
| 436 | + public String getRequestMethod() { | |
| 437 | + return method; | |
| 438 | + } | |
| 439 | + | |
| 440 | + /** | |
| 441 | + * Gets the status code from an HTTP response message. | |
| 442 | + * For example, in the case of the following status lines: | |
| 443 | + * <PRE> | |
| 444 | + * HTTP/1.0 200 OK | |
| 445 | + * HTTP/1.0 401 Unauthorized | |
| 446 | + * </PRE> | |
| 447 | + * It will return 200 and 401 respectively. | |
| 448 | + * Returns -1 if no code can be discerned | |
| 449 | + * from the response (i.e., the response is not valid HTTP). | |
| 450 | + * @throws IOException if an error occurred connecting to the server. | |
| 451 | + * @return the HTTP Status-Code, or -1 | |
| 452 | + */ | |
| 453 | + public int getResponseCode() throws IOException { | |
| 454 | + /* | |
| 455 | + * We're got the response code already | |
| 456 | + */ | |
| 457 | + if (responseCode != -1) { | |
| 458 | + return responseCode; | |
| 459 | + } | |
| 460 | + | |
| 461 | + /* | |
| 462 | + * Ensure that we have connected to the server. Record | |
| 463 | + * exception as we need to re-throw it if there isn't | |
| 464 | + * a status line. | |
| 465 | + */ | |
| 466 | + Exception exc = null; | |
| 467 | + try { | |
| 468 | + getInputStream(); | |
| 469 | + } catch (Exception e) { | |
| 470 | + exc = e; | |
| 471 | + } | |
| 472 | + | |
| 473 | + /* | |
| 474 | + * If we can't a status-line then re-throw any exception | |
| 475 | + * that getInputStream threw. | |
| 476 | + */ | |
| 477 | + String statusLine = getHeaderField(0); | |
| 478 | + if (statusLine == null) { | |
| 479 | + if (exc != null) { | |
| 480 | + if (exc instanceof RuntimeException) | |
| 481 | + throw (RuntimeException)exc; | |
| 482 | + else | |
| 483 | + throw (IOException)exc; | |
| 484 | + } | |
| 485 | + return -1; | |
| 486 | + } | |
| 487 | + | |
| 488 | + /* | |
| 489 | + * Examine the status-line - should be formatted as per | |
| 490 | + * section 6.1 of RFC 2616 :- | |
| 491 | + * | |
| 492 | + * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase | |
| 493 | + * | |
| 494 | + * If status line can't be parsed return -1. | |
| 495 | + */ | |
| 496 | + if (statusLine.startsWith("HTTP/1.")) { | |
| 497 | + int codePos = statusLine.indexOf(' '); | |
| 498 | + if (codePos > 0) { | |
| 499 | + | |
| 500 | + int phrasePos = statusLine.indexOf(' ', codePos+1); | |
| 501 | + if (phrasePos > 0 && phrasePos < statusLine.length()) { | |
| 502 | + responseMessage = statusLine.substring(phrasePos+1); | |
| 503 | + } | |
| 504 | + | |
| 505 | + // deviation from RFC 2616 - don't reject status line | |
| 506 | + // if SP Reason-Phrase is not included. | |
| 507 | + if (phrasePos < 0) | |
| 508 | + phrasePos = statusLine.length(); | |
| 509 | + | |
| 510 | + try { | |
| 511 | + responseCode = Integer.parseInt | |
| 512 | + (statusLine.substring(codePos+1, phrasePos)); | |
| 513 | + return responseCode; | |
| 514 | + } catch (NumberFormatException e) { } | |
| 515 | + } | |
| 516 | + } | |
| 517 | + return -1; | |
| 518 | + } | |
| 519 | + | |
| 520 | + /** | |
| 521 | + * Gets the HTTP response message, if any, returned along with the | |
| 522 | + * response code from a server. From responses like: | |
| 523 | + * <PRE> | |
| 524 | + * HTTP/1.0 200 OK | |
| 525 | + * HTTP/1.0 404 Not Found | |
| 526 | + * </PRE> | |
| 527 | + * Extracts the Strings "OK" and "Not Found" respectively. | |
| 528 | + * Returns null if none could be discerned from the responses | |
| 529 | + * (the result was not valid HTTP). | |
| 530 | + * @throws IOException if an error occurred connecting to the server. | |
| 531 | + * @return the HTTP response message, or <code>null</code> | |
| 532 | + */ | |
| 533 | + public String getResponseMessage() throws IOException { | |
| 534 | + getResponseCode(); | |
| 535 | + return responseMessage; | |
| 536 | + } | |
| 537 | + | |
| 538 | + public long getHeaderFieldDate(String name, long Default) { | |
| 539 | + String dateString = getHeaderField(name); | |
| 540 | + try { | |
| 541 | + if (dateString.indexOf("GMT") == -1) { | |
| 542 | + dateString = dateString+" GMT"; | |
| 543 | + } | |
| 544 | + return Date.parse(dateString); | |
| 545 | + } catch (Exception e) { | |
| 546 | + } | |
| 547 | + return Default; | |
| 548 | + } | |
| 549 | + | |
| 550 | + | |
| 551 | + /** | |
| 552 | + * Indicates that other requests to the server | |
| 553 | + * are unlikely in the near future. Calling disconnect() | |
| 554 | + * should not imply that this HttpURLConnection | |
| 555 | + * instance can be reused for other requests. | |
| 556 | + */ | |
| 557 | + public abstract void disconnect(); | |
| 558 | + | |
| 559 | + /** | |
| 560 | + * Indicates if the connection is going through a proxy. | |
| 561 | + * @return a boolean indicating if the connection is | |
| 562 | + * using a proxy. | |
| 563 | + */ | |
| 564 | + public abstract boolean usingProxy(); | |
| 565 | + | |
| 566 | + /** | |
| 567 | + * Returns a {@link SocketPermission} object representing the | |
| 568 | + * permission necessary to connect to the destination host and port. | |
| 569 | + * | |
| 570 | + * @exception IOException if an error occurs while computing | |
| 571 | + * the permission. | |
| 572 | + * | |
| 573 | + * @return a <code>SocketPermission</code> object representing the | |
| 574 | + * permission necessary to connect to the destination | |
| 575 | + * host and port. | |
| 576 | + */ | |
| 577 | + public Permission getPermission() throws IOException { | |
| 578 | + int port = url.getPort(); | |
| 579 | + port = port < 0 ? 80 : port; | |
| 580 | + String host = url.getHost() + ":" + port; | |
| 581 | + Permission permission = new SocketPermission(host, "connect"); | |
| 582 | + return permission; | |
| 583 | + } | |
| 584 | + | |
| 585 | + /** | |
| 586 | + * Returns the error stream if the connection failed | |
| 587 | + * but the server sent useful data nonetheless. The | |
| 588 | + * typical example is when an HTTP server responds | |
| 589 | + * with a 404, which will cause a FileNotFoundException | |
| 590 | + * to be thrown in connect, but the server sent an HTML | |
| 591 | + * help page with suggestions as to what to do. | |
| 592 | + * | |
| 593 | + * <p>This method will not cause a connection to be initiated. If | |
| 594 | + * the connection was not connected, or if the server did not have | |
| 595 | + * an error while connecting or if the server had an error but | |
| 596 | + * no error data was sent, this method will return null. This is | |
| 597 | + * the default. | |
| 598 | + * | |
| 599 | + * @return an error stream if any, null if there have been no | |
| 600 | + * errors, the connection is not connected or the server sent no | |
| 601 | + * useful data. | |
| 602 | + */ | |
| 603 | + public InputStream getErrorStream() { | |
| 604 | + return null; | |
| 605 | + } | |
| 606 | + | |
| 607 | + /** | |
| 608 | + * The response codes for HTTP, as of version 1.1. | |
| 609 | + */ | |
| 610 | + | |
| 611 | + // REMIND: do we want all these?? | |
| 612 | + // Others not here that we do want?? | |
| 613 | + | |
| 614 | + /* 2XX: generally "OK" */ | |
| 615 | + | |
| 616 | + /** | |
| 617 | + * HTTP Status-Code 200: OK. | |
| 618 | + */ | |
| 619 | + public static final int HTTP_OK = 200; | |
| 620 | + | |
| 621 | + /** | |
| 622 | + * HTTP Status-Code 201: Created. | |
| 623 | + */ | |
| 624 | + public static final int HTTP_CREATED = 201; | |
| 625 | + | |
| 626 | + /** | |
| 627 | + * HTTP Status-Code 202: Accepted. | |
| 628 | + */ | |
| 629 | + public static final int HTTP_ACCEPTED = 202; | |
| 630 | + | |
| 631 | + /** | |
| 632 | + * HTTP Status-Code 203: Non-Authoritative Information. | |
| 633 | + */ | |
| 634 | + public static final int HTTP_NOT_AUTHORITATIVE = 203; | |
| 635 | + | |
| 636 | + /** | |
| 637 | + * HTTP Status-Code 204: No Content. | |
| 638 | + */ | |
| 639 | + public static final int HTTP_NO_CONTENT = 204; | |
| 640 | + | |
| 641 | + /** | |
| 642 | + * HTTP Status-Code 205: Reset Content. | |
| 643 | + */ | |
| 644 | + public static final int HTTP_RESET = 205; | |
| 645 | + | |
| 646 | + /** | |
| 647 | + * HTTP Status-Code 206: Partial Content. | |
| 648 | + */ | |
| 649 | + public static final int HTTP_PARTIAL = 206; | |
| 650 | + | |
| 651 | + /* 3XX: relocation/redirect */ | |
| 652 | + | |
| 653 | + /** | |
| 654 | + * HTTP Status-Code 300: Multiple Choices. | |
| 655 | + */ | |
| 656 | + public static final int HTTP_MULT_CHOICE = 300; | |
| 657 | + | |
| 658 | + /** | |
| 659 | + * HTTP Status-Code 301: Moved Permanently. | |
| 660 | + */ | |
| 661 | + public static final int HTTP_MOVED_PERM = 301; | |
| 662 | + | |
| 663 | + /** | |
| 664 | + * HTTP Status-Code 302: Temporary Redirect. | |
| 665 | + */ | |
| 666 | + public static final int HTTP_MOVED_TEMP = 302; | |
| 667 | + | |
| 668 | + /** | |
| 669 | + * HTTP Status-Code 303: See Other. | |
| 670 | + */ | |
| 671 | + public static final int HTTP_SEE_OTHER = 303; | |
| 672 | + | |
| 673 | + /** | |
| 674 | + * HTTP Status-Code 304: Not Modified. | |
| 675 | + */ | |
| 676 | + public static final int HTTP_NOT_MODIFIED = 304; | |
| 677 | + | |
| 678 | + /** | |
| 679 | + * HTTP Status-Code 305: Use Proxy. | |
| 680 | + */ | |
| 681 | + public static final int HTTP_USE_PROXY = 305; | |
| 682 | + | |
| 683 | + /* 4XX: client error */ | |
| 684 | + | |
| 685 | + /** | |
| 686 | + * HTTP Status-Code 400: Bad Request. | |
| 687 | + */ | |
| 688 | + public static final int HTTP_BAD_REQUEST = 400; | |
| 689 | + | |
| 690 | + /** | |
| 691 | + * HTTP Status-Code 401: Unauthorized. | |
| 692 | + */ | |
| 693 | + public static final int HTTP_UNAUTHORIZED = 401; | |
| 694 | + | |
| 695 | + /** | |
| 696 | + * HTTP Status-Code 402: Payment Required. | |
| 697 | + */ | |
| 698 | + public static final int HTTP_PAYMENT_REQUIRED = 402; | |
| 699 | + | |
| 700 | + /** | |
| 701 | + * HTTP Status-Code 403: Forbidden. | |
| 702 | + */ | |
| 703 | + public static final int HTTP_FORBIDDEN = 403; | |
| 704 | + | |
| 705 | + /** | |
| 706 | + * HTTP Status-Code 404: Not Found. | |
| 707 | + */ | |
| 708 | + public static final int HTTP_NOT_FOUND = 404; | |
| 709 | + | |
| 710 | + /** | |
| 711 | + * HTTP Status-Code 405: Method Not Allowed. | |
| 712 | + */ | |
| 713 | + public static final int HTTP_BAD_METHOD = 405; | |
| 714 | + | |
| 715 | + /** | |
| 716 | + * HTTP Status-Code 406: Not Acceptable. | |
| 717 | + */ | |
| 718 | + public static final int HTTP_NOT_ACCEPTABLE = 406; | |
| 719 | + | |
| 720 | + /** | |
| 721 | + * HTTP Status-Code 407: Proxy Authentication Required. | |
| 722 | + */ | |
| 723 | + public static final int HTTP_PROXY_AUTH = 407; | |
| 724 | + | |
| 725 | + /** | |
| 726 | + * HTTP Status-Code 408: Request Time-Out. | |
| 727 | + */ | |
| 728 | + public static final int HTTP_CLIENT_TIMEOUT = 408; | |
| 729 | + | |
| 730 | + /** | |
| 731 | + * HTTP Status-Code 409: Conflict. | |
| 732 | + */ | |
| 733 | + public static final int HTTP_CONFLICT = 409; | |
| 734 | + | |
| 735 | + /** | |
| 736 | + * HTTP Status-Code 410: Gone. | |
| 737 | + */ | |
| 738 | + public static final int HTTP_GONE = 410; | |
| 739 | + | |
| 740 | + /** | |
| 741 | + * HTTP Status-Code 411: Length Required. | |
| 742 | + */ | |
| 743 | + public static final int HTTP_LENGTH_REQUIRED = 411; | |
| 744 | + | |
| 745 | + /** | |
| 746 | + * HTTP Status-Code 412: Precondition Failed. | |
| 747 | + */ | |
| 748 | + public static final int HTTP_PRECON_FAILED = 412; | |
| 749 | + | |
| 750 | + /** | |
| 751 | + * HTTP Status-Code 413: Request Entity Too Large. | |
| 752 | + */ | |
| 753 | + public static final int HTTP_ENTITY_TOO_LARGE = 413; | |
| 754 | + | |
| 755 | + /** | |
| 756 | + * HTTP Status-Code 414: Request-URI Too Large. | |
| 757 | + */ | |
| 758 | + public static final int HTTP_REQ_TOO_LONG = 414; | |
| 759 | + | |
| 760 | + /** | |
| 761 | + * HTTP Status-Code 415: Unsupported Media Type. | |
| 762 | + */ | |
| 763 | + public static final int HTTP_UNSUPPORTED_TYPE = 415; | |
| 764 | + | |
| 765 | + /* 5XX: server error */ | |
| 766 | + | |
| 767 | + /** | |
| 768 | + * HTTP Status-Code 500: Internal Server Error. | |
| 769 | + * @deprecated it is misplaced and shouldn't have existed. | |
| 770 | + */ | |
| 771 | + @Deprecated | |
| 772 | + public static final int HTTP_SERVER_ERROR = 500; | |
| 773 | + | |
| 774 | + /** | |
| 775 | + * HTTP Status-Code 500: Internal Server Error. | |
| 776 | + */ | |
| 777 | + public static final int HTTP_INTERNAL_ERROR = 500; | |
| 778 | + | |
| 779 | + /** | |
| 780 | + * HTTP Status-Code 501: Not Implemented. | |
| 781 | + */ | |
| 782 | + public static final int HTTP_NOT_IMPLEMENTED = 501; | |
| 783 | + | |
| 784 | + /** | |
| 785 | + * HTTP Status-Code 502: Bad Gateway. | |
| 786 | + */ | |
| 787 | + public static final int HTTP_BAD_GATEWAY = 502; | |
| 788 | + | |
| 789 | + /** | |
| 790 | + * HTTP Status-Code 503: Service Unavailable. | |
| 791 | + */ | |
| 792 | + public static final int HTTP_UNAVAILABLE = 503; | |
| 793 | + | |
| 794 | + /** | |
| 795 | + * HTTP Status-Code 504: Gateway Timeout. | |
| 796 | + */ | |
| 797 | + public static final int HTTP_GATEWAY_TIMEOUT = 504; | |
| 798 | + | |
| 799 | + /** | |
| 800 | + * HTTP Status-Code 505: HTTP Version Not Supported. | |
| 801 | + */ | |
| 802 | + public static final int HTTP_VERSION = 505; | |
| 803 | + | |
| 804 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,468 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 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 | +package java.net; | |
| 26 | + | |
| 27 | +import java.io.InputStream; | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.security.AccessController; | |
| 30 | +import java.security.PrivilegedAction; | |
| 31 | + | |
| 32 | +import sun.net.idn.StringPrep; | |
| 33 | +import sun.net.idn.Punycode; | |
| 34 | +import sun.text.normalizer.UCharacterIterator; | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * Provides methods to convert internationalized domain names (IDNs) between | |
| 38 | + * a normal Unicode representation and an ASCII Compatible Encoding (ACE) representation. | |
| 39 | + * Internationalized domain names can use characters from the entire range of | |
| 40 | + * Unicode, while traditional domain names are restricted to ASCII characters. | |
| 41 | + * ACE is an encoding of Unicode strings that uses only ASCII characters and | |
| 42 | + * can be used with software (such as the Domain Name System) that only | |
| 43 | + * understands traditional domain names. | |
| 44 | + * | |
| 45 | + * <p>Internationalized domain names are defined in <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>. | |
| 46 | + * RFC 3490 defines two operations: ToASCII and ToUnicode. These 2 operations employ | |
| 47 | + * <a href="http://www.ietf.org/rfc/rfc3491.txt">Nameprep</a> algorithm, which is a | |
| 48 | + * profile of <a href="http://www.ietf.org/rfc/rfc3454.txt">Stringprep</a>, and | |
| 49 | + * <a href="http://www.ietf.org/rfc/rfc3492.txt">Punycode</a> algorithm to convert | |
| 50 | + * domain name string back and forth. | |
| 51 | + * | |
| 52 | + * <p>The behavior of aforementioned conversion process can be adjusted by various flags: | |
| 53 | + * <ul> | |
| 54 | + * <li>If the ALLOW_UNASSIGNED flag is used, the domain name string to be converted | |
| 55 | + * can contain code points that are unassigned in Unicode 3.2, which is the | |
| 56 | + * Unicode version on which IDN conversion is based. If the flag is not used, | |
| 57 | + * the presence of such unassigned code points is treated as an error. | |
| 58 | + * <li>If the USE_STD3_ASCII_RULES flag is used, ASCII strings are checked against <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC 1122</a> and <a href="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</a>. | |
| 59 | + * It is an error if they don't meet the requirements. | |
| 60 | + * </ul> | |
| 61 | + * These flags can be logically OR'ed together. | |
| 62 | + * | |
| 63 | + * <p>The security consideration is important with respect to internationalization | |
| 64 | + * domain name support. For example, English domain names may be <i>homographed</i> | |
| 65 | + * - maliciously misspelled by substitution of non-Latin letters. | |
| 66 | + * <a href="http://www.unicode.org/reports/tr36/">Unicode Technical Report #36</a> | |
| 67 | + * discusses security issues of IDN support as well as possible solutions. | |
| 68 | + * Applications are responsible for taking adequate security measures when using | |
| 69 | + * international domain names. | |
| 70 | + * | |
| 71 | + * @author Edward Wang | |
| 72 | + * @since 1.6 | |
| 73 | + * | |
| 74 | + */ | |
| 75 | +public final class IDN { | |
| 76 | + /** | |
| 77 | + * Flag to allow processing of unassigned code points | |
| 78 | + */ | |
| 79 | + public static final int ALLOW_UNASSIGNED = 0x01; | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * Flag to turn on the check against STD-3 ASCII rules | |
| 83 | + */ | |
| 84 | + public static final int USE_STD3_ASCII_RULES = 0x02; | |
| 85 | + | |
| 86 | + | |
| 87 | + /** | |
| 88 | + * Translates a string from Unicode to ASCII Compatible Encoding (ACE), | |
| 89 | + * as defined by the ToASCII operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>. | |
| 90 | + * | |
| 91 | + * <p>ToASCII operation can fail. ToASCII fails if any step of it fails. | |
| 92 | + * If ToASCII operation fails, an IllegalArgumentException will be thrown. | |
| 93 | + * In this case, the input string should not be used in an internationalized domain name. | |
| 94 | + * | |
| 95 | + * <p> A label is an individual part of a domain name. The original ToASCII operation, | |
| 96 | + * as defined in RFC 3490, only operates on a single label. This method can handle | |
| 97 | + * both label and entire domain name, by assuming that labels in a domain name are | |
| 98 | + * always separated by dots. The following characters are recognized as dots: | |
| 99 | + * \u002E (full stop), \u3002 (ideographic full stop), \uFF0E (fullwidth full stop), | |
| 100 | + * and \uFF61 (halfwidth ideographic full stop). if dots are | |
| 101 | + * used as label separators, this method also changes all of them to \u002E (full stop) | |
| 102 | + * in output translated string. | |
| 103 | + * | |
| 104 | + * @param input the string to be processed | |
| 105 | + * @param flag process flag; can be 0 or any logical OR of possible flags | |
| 106 | + * | |
| 107 | + * @return the translated <tt>String</tt> | |
| 108 | + * | |
| 109 | + * @throws IllegalArgumentException if the input string doesn't conform to RFC 3490 specification | |
| 110 | + */ | |
| 111 | + public static String toASCII(String input, int flag) | |
| 112 | + { | |
| 113 | + int p = 0, q = 0; | |
| 114 | + StringBuffer out = new StringBuffer(); | |
| 115 | + | |
| 116 | + while (p < input.length()) { | |
| 117 | + q = searchDots(input, p); | |
| 118 | + out.append(toASCIIInternal(input.substring(p, q), flag)); | |
| 119 | + p = q + 1; | |
| 120 | + if (p < input.length()) out.append('.'); | |
| 121 | + } | |
| 122 | + | |
| 123 | + return out.toString(); | |
| 124 | + } | |
| 125 | + | |
| 126 | + | |
| 127 | + /** | |
| 128 | + * Translates a string from Unicode to ASCII Compatible Encoding (ACE), | |
| 129 | + * as defined by the ToASCII operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>. | |
| 130 | + * | |
| 131 | + * <p> This convenience method works as if by invoking the | |
| 132 | + * two-argument counterpart as follows: | |
| 133 | + * <blockquote><tt> | |
| 134 | + * {@link #toASCII(String, int) toASCII}(input, 0); | |
| 135 | + * </tt></blockquote> | |
| 136 | + * | |
| 137 | + * @param input the string to be processed | |
| 138 | + * | |
| 139 | + * @return the translated <tt>String</tt> | |
| 140 | + * | |
| 141 | + * @throws IllegalArgumentException if the input string doesn't conform to RFC 3490 specification | |
| 142 | + */ | |
| 143 | + public static String toASCII(String input) { | |
| 144 | + return toASCII(input, 0); | |
| 145 | + } | |
| 146 | + | |
| 147 | + | |
| 148 | + /** | |
| 149 | + * Translates a string from ASCII Compatible Encoding (ACE) to Unicode, | |
| 150 | + * as defined by the ToUnicode operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>. | |
| 151 | + * | |
| 152 | + * <p>ToUnicode never fails. In case of any error, the input string is returned unmodified. | |
| 153 | + * | |
| 154 | + * <p> A label is an individual part of a domain name. The original ToUnicode operation, | |
| 155 | + * as defined in RFC 3490, only operates on a single label. This method can handle | |
| 156 | + * both label and entire domain name, by assuming that labels in a domain name are | |
| 157 | + * always separated by dots. The following characters are recognized as dots: | |
| 158 | + * \u002E (full stop), \u3002 (ideographic full stop), \uFF0E (fullwidth full stop), | |
| 159 | + * and \uFF61 (halfwidth ideographic full stop). | |
| 160 | + * | |
| 161 | + * @param input the string to be processed | |
| 162 | + * @param flag process flag; can be 0 or any logical OR of possible flags | |
| 163 | + * | |
| 164 | + * @return the translated <tt>String</tt> | |
| 165 | + */ | |
| 166 | + public static String toUnicode(String input, int flag) { | |
| 167 | + int p = 0, q = 0; | |
| 168 | + StringBuffer out = new StringBuffer(); | |
| 169 | + | |
| 170 | + while (p < input.length()) { | |
| 171 | + q = searchDots(input, p); | |
| 172 | + out.append(toUnicodeInternal(input.substring(p, q), flag)); | |
| 173 | + p = q + 1; | |
| 174 | + if (p < input.length()) out.append('.'); | |
| 175 | + } | |
| 176 | + | |
| 177 | + return out.toString(); | |
| 178 | + } | |
| 179 | + | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * Translates a string from ASCII Compatible Encoding (ACE) to Unicode, | |
| 183 | + * as defined by the ToUnicode operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>. | |
| 184 | + * | |
| 185 | + * <p> This convenience method works as if by invoking the | |
| 186 | + * two-argument counterpart as follows: | |
| 187 | + * <blockquote><tt> | |
| 188 | + * {@link #toUnicode(String, int) toUnicode}(input, 0); | |
| 189 | + * </tt></blockquote> | |
| 190 | + * | |
| 191 | + * @param input the string to be processed | |
| 192 | + * | |
| 193 | + * @return the translated <tt>String</tt> | |
| 194 | + */ | |
| 195 | + public static String toUnicode(String input) { | |
| 196 | + return toUnicode(input, 0); | |
| 197 | + } | |
| 198 | + | |
| 199 | + | |
| 200 | + /* ---------------- Private members -------------- */ | |
| 201 | + | |
| 202 | + // ACE Prefix is "xn--" | |
| 203 | + private static final String ACE_PREFIX = "xn--"; | |
| 204 | + private static final int ACE_PREFIX_LENGTH = ACE_PREFIX.length(); | |
| 205 | + | |
| 206 | + private static final int MAX_LABEL_LENGTH = 63; | |
| 207 | + | |
| 208 | + // single instance of nameprep | |
| 209 | + private static StringPrep namePrep = null; | |
| 210 | + | |
| 211 | + static { | |
| 212 | + InputStream stream = null; | |
| 213 | + | |
| 214 | + try { | |
| 215 | + final String IDN_PROFILE = "uidna.spp"; | |
| 216 | + if (System.getSecurityManager() != null) { | |
| 217 | + stream = AccessController.doPrivileged(new PrivilegedAction<InputStream>() { | |
| 218 | + public InputStream run() { | |
| 219 | + return StringPrep.class.getResourceAsStream(IDN_PROFILE); | |
| 220 | + } | |
| 221 | + }); | |
| 222 | + } else { | |
| 223 | + stream = StringPrep.class.getResourceAsStream(IDN_PROFILE); | |
| 224 | + } | |
| 225 | + | |
| 226 | + namePrep = new StringPrep(stream); | |
| 227 | + stream.close(); | |
| 228 | + } catch (IOException e) { | |
| 229 | + // should never reach here | |
| 230 | + assert false; | |
| 231 | + } | |
| 232 | + } | |
| 233 | + | |
| 234 | + | |
| 235 | + /* ---------------- Private operations -------------- */ | |
| 236 | + | |
| 237 | + | |
| 238 | + // | |
| 239 | + // to suppress the default zero-argument constructor | |
| 240 | + // | |
| 241 | + private IDN() {} | |
| 242 | + | |
| 243 | + // | |
| 244 | + // toASCII operation; should only apply to a single label | |
| 245 | + // | |
| 246 | + private static String toASCIIInternal(String label, int flag) | |
| 247 | + { | |
| 248 | + // step 1 | |
| 249 | + // Check if the string contains code points outside the ASCII range 0..0x7c. | |
| 250 | + boolean isASCII = isAllASCII(label); | |
| 251 | + StringBuffer dest; | |
| 252 | + | |
| 253 | + // step 2 | |
| 254 | + // perform the nameprep operation; flag ALLOW_UNASSIGNED is used here | |
| 255 | + if (!isASCII) { | |
| 256 | + UCharacterIterator iter = UCharacterIterator.getInstance(label); | |
| 257 | + try { | |
| 258 | + dest = namePrep.prepare(iter, flag); | |
| 259 | + } catch (java.text.ParseException e) { | |
| 260 | + throw new IllegalArgumentException(e); | |
| 261 | + } | |
| 262 | + } else { | |
| 263 | + dest = new StringBuffer(label); | |
| 264 | + } | |
| 265 | + | |
| 266 | + // step 3 | |
| 267 | + // Verify the absence of non-LDH ASCII code points | |
| 268 | + // 0..0x2c, 0x2e..0x2f, 0x3a..0x40, 0x5b..0x60, 0x7b..0x7f | |
| 269 | + // Verify the absence of leading and trailing hyphen | |
| 270 | + boolean useSTD3ASCIIRules = ((flag & USE_STD3_ASCII_RULES) != 0); | |
| 271 | + if (useSTD3ASCIIRules) { | |
| 272 | + for (int i = 0; i < dest.length(); i++) { | |
| 273 | + int c = dest.charAt(i); | |
| 274 | + if (!isLDHChar(c)) { | |
| 275 | + throw new IllegalArgumentException("Contains non-LDH characters"); | |
| 276 | + } | |
| 277 | + } | |
| 278 | + | |
| 279 | + if (dest.charAt(0) == '-' || dest.charAt(dest.length() - 1) == '-') { | |
| 280 | + throw new IllegalArgumentException("Has leading or trailing hyphen"); | |
| 281 | + } | |
| 282 | + } | |
| 283 | + | |
| 284 | + if (!isASCII) { | |
| 285 | + // step 4 | |
| 286 | + // If all code points are inside 0..0x7f, skip to step 8 | |
| 287 | + if (!isAllASCII(dest.toString())) { | |
| 288 | + // step 5 | |
| 289 | + // verify the sequence does not begin with ACE prefix | |
| 290 | + if(!startsWithACEPrefix(dest)){ | |
| 291 | + | |
| 292 | + // step 6 | |
| 293 | + // encode the sequence with punycode | |
| 294 | + try { | |
| 295 | + dest = Punycode.encode(dest, null); | |
| 296 | + } catch (java.text.ParseException e) { | |
| 297 | + throw new IllegalArgumentException(e); | |
| 298 | + } | |
| 299 | + | |
| 300 | + dest = toASCIILower(dest); | |
| 301 | + | |
| 302 | + // step 7 | |
| 303 | + // prepend the ACE prefix | |
| 304 | + dest.insert(0, ACE_PREFIX); | |
| 305 | + } else { | |
| 306 | + throw new IllegalArgumentException("The input starts with the ACE Prefix"); | |
| 307 | + } | |
| 308 | + | |
| 309 | + } | |
| 310 | + } | |
| 311 | + | |
| 312 | + // step 8 | |
| 313 | + // the length must be inside 1..63 | |
| 314 | + if(dest.length() > MAX_LABEL_LENGTH){ | |
| 315 | + throw new IllegalArgumentException("The label in the input is too long"); | |
| 316 | + } | |
| 317 | + | |
| 318 | + return dest.toString(); | |
| 319 | + } | |
| 320 | + | |
| 321 | + // | |
| 322 | + // toUnicode operation; should only apply to a single label | |
| 323 | + // | |
| 324 | + private static String toUnicodeInternal(String label, int flag) { | |
| 325 | + boolean[] caseFlags = null; | |
| 326 | + StringBuffer dest; | |
| 327 | + | |
| 328 | + // step 1 | |
| 329 | + // find out if all the codepoints in input are ASCII | |
| 330 | + boolean isASCII = isAllASCII(label); | |
| 331 | + | |
| 332 | + if(!isASCII){ | |
| 333 | + // step 2 | |
| 334 | + // perform the nameprep operation; flag ALLOW_UNASSIGNED is used here | |
| 335 | + try { | |
| 336 | + UCharacterIterator iter = UCharacterIterator.getInstance(label); | |
| 337 | + dest = namePrep.prepare(iter, flag); | |
| 338 | + } catch (Exception e) { | |
| 339 | + // toUnicode never fails; if any step fails, return the input string | |
| 340 | + return label; | |
| 341 | + } | |
| 342 | + } else { | |
| 343 | + dest = new StringBuffer(label); | |
| 344 | + } | |
| 345 | + | |
| 346 | + // step 3 | |
| 347 | + // verify ACE Prefix | |
| 348 | + if(startsWithACEPrefix(dest)) { | |
| 349 | + | |
| 350 | + // step 4 | |
| 351 | + // Remove the ACE Prefix | |
| 352 | + String temp = dest.substring(ACE_PREFIX_LENGTH, dest.length()); | |
| 353 | + | |
| 354 | + try { | |
| 355 | + // step 5 | |
| 356 | + // Decode using punycode | |
| 357 | + StringBuffer decodeOut = Punycode.decode(new StringBuffer(temp), null); | |
| 358 | + | |
| 359 | + // step 6 | |
| 360 | + // Apply toASCII | |
| 361 | + String toASCIIOut = toASCII(decodeOut.toString(), flag); | |
| 362 | + | |
| 363 | + // step 7 | |
| 364 | + // verify | |
| 365 | + if (toASCIIOut.equalsIgnoreCase(dest.toString())) { | |
| 366 | + // step 8 | |
| 367 | + // return output of step 5 | |
| 368 | + return decodeOut.toString(); | |
| 369 | + } | |
| 370 | + } catch (Exception ignored) { | |
| 371 | + // no-op | |
| 372 | + } | |
| 373 | + } | |
| 374 | + | |
| 375 | + // just return the input | |
| 376 | + return label; | |
| 377 | + } | |
| 378 | + | |
| 379 | + | |
| 380 | + // | |
| 381 | + // LDH stands for "letter/digit/hyphen", with characters restricted to the | |
| 382 | + // 26-letter Latin alphabet <A-Z a-z>, the digits <0-9>, and the hyphen | |
| 383 | + // <-> | |
| 384 | + // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x56..0x60, 0x7B..0x7F | |
| 385 | + // | |
| 386 | + private static boolean isLDHChar(int ch){ | |
| 387 | + // high runner case | |
| 388 | + if(ch > 0x007A){ | |
| 389 | + return false; | |
| 390 | + } | |
| 391 | + //['-' '0'..'9' 'A'..'Z' 'a'..'z'] | |
| 392 | + if((ch == 0x002D) || | |
| 393 | + (0x0030 <= ch && ch <= 0x0039) || | |
| 394 | + (0x0041 <= ch && ch <= 0x005A) || | |
| 395 | + (0x0061 <= ch && ch <= 0x007A) | |
| 396 | + ){ | |
| 397 | + return true; | |
| 398 | + } | |
| 399 | + return false; | |
| 400 | + } | |
| 401 | + | |
| 402 | + | |
| 403 | + // | |
| 404 | + // search dots in a string and return the index of that character; | |
| 405 | + // or if there is no dots, return the length of input string | |
| 406 | + // dots might be: \u002E (full stop), \u3002 (ideographic full stop), \uFF0E (fullwidth full stop), | |
| 407 | + // and \uFF61 (halfwidth ideographic full stop). | |
| 408 | + // | |
| 409 | + private static int searchDots(String s, int start) { | |
| 410 | + int i; | |
| 411 | + for (i = start; i < s.length(); i++) { | |
| 412 | + char c = s.charAt(i); | |
| 413 | + if (c == '.' || c == '\u3002' || c == '\uFF0E' || c == '\uFF61') { | |
| 414 | + break; | |
| 415 | + } | |
| 416 | + } | |
| 417 | + | |
| 418 | + return i; | |
| 419 | + } | |
| 420 | + | |
| 421 | + | |
| 422 | + // | |
| 423 | + // to check if a string only contains US-ASCII code point | |
| 424 | + // | |
| 425 | + private static boolean isAllASCII(String input) { | |
| 426 | + boolean isASCII = true; | |
| 427 | + for (int i = 0; i < input.length(); i++) { | |
| 428 | + int c = input.charAt(i); | |
| 429 | + if (c > 0x7F) { | |
| 430 | + isASCII = false; | |
| 431 | + break; | |
| 432 | + } | |
| 433 | + } | |
| 434 | + return isASCII; | |
| 435 | + } | |
| 436 | + | |
| 437 | + // | |
| 438 | + // to check if a string starts with ACE-prefix | |
| 439 | + // | |
| 440 | + private static boolean startsWithACEPrefix(StringBuffer input){ | |
| 441 | + boolean startsWithPrefix = true; | |
| 442 | + | |
| 443 | + if(input.length() < ACE_PREFIX_LENGTH){ | |
| 444 | + return false; | |
| 445 | + } | |
| 446 | + for(int i = 0; i < ACE_PREFIX_LENGTH; i++){ | |
| 447 | + if(toASCIILower(input.charAt(i)) != ACE_PREFIX.charAt(i)){ | |
| 448 | + startsWithPrefix = false; | |
| 449 | + } | |
| 450 | + } | |
| 451 | + return startsWithPrefix; | |
| 452 | + } | |
| 453 | + | |
| 454 | + private static char toASCIILower(char ch){ | |
| 455 | + if('A' <= ch && ch <= 'Z'){ | |
| 456 | + return (char)(ch + 'a' - 'A'); | |
| 457 | + } | |
| 458 | + return ch; | |
| 459 | + } | |
| 460 | + | |
| 461 | + private static StringBuffer toASCIILower(StringBuffer input){ | |
| 462 | + StringBuffer dest = new StringBuffer(); | |
| 463 | + for(int i = 0; i < input.length();i++){ | |
| 464 | + dest.append(toASCIILower(input.charAt(i))); | |
| 465 | + } | |
| 466 | + return dest; | |
| 467 | + } | |
| 468 | +} | |
Binary file not shown.
| @@ -0,0 +1,393 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +import java.net.URI; | |
| 29 | +import java.net.CookieStore; | |
| 30 | +import java.net.HttpCookie; | |
| 31 | +import java.net.URISyntaxException; | |
| 32 | +import java.util.List; | |
| 33 | +import java.util.Map; | |
| 34 | +import java.util.ArrayList; | |
| 35 | +import java.util.HashMap; | |
| 36 | +import java.util.Collections; | |
| 37 | +import java.util.Iterator; | |
| 38 | +import java.util.concurrent.locks.ReentrantLock; | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * A simple in-memory java.net.CookieStore implementation | |
| 42 | + * | |
| 43 | + * @author Edward Wang | |
| 44 | + * @since 1.6 | |
| 45 | + */ | |
| 46 | +class InMemoryCookieStore implements CookieStore { | |
| 47 | + // the in-memory representation of cookies | |
| 48 | + private List<HttpCookie> cookieJar = null; | |
| 49 | + | |
| 50 | + // the cookies are indexed by its domain and associated uri (if present) | |
| 51 | + // CAUTION: when a cookie removed from main data structure (i.e. cookieJar), | |
| 52 | + // it won't be cleared in domainIndex & uriIndex. Double-check the | |
| 53 | + // presence of cookie when retrieve one form index store. | |
| 54 | + private Map<String, List<HttpCookie>> domainIndex = null; | |
| 55 | + private Map<URI, List<HttpCookie>> uriIndex = null; | |
| 56 | + | |
| 57 | + // use ReentrantLock instead of syncronized for scalability | |
| 58 | + private ReentrantLock lock = null; | |
| 59 | + | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * The default ctor | |
| 63 | + */ | |
| 64 | + public InMemoryCookieStore() { | |
| 65 | + cookieJar = new ArrayList<HttpCookie>(); | |
| 66 | + domainIndex = new HashMap<String, List<HttpCookie>>(); | |
| 67 | + uriIndex = new HashMap<URI, List<HttpCookie>>(); | |
| 68 | + | |
| 69 | + lock = new ReentrantLock(false); | |
| 70 | + } | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * Add one cookie into cookie store. | |
| 74 | + */ | |
| 75 | + public void add(URI uri, HttpCookie cookie) { | |
| 76 | + // pre-condition : argument can't be null | |
| 77 | + if (cookie == null) { | |
| 78 | + throw new NullPointerException("cookie is null"); | |
| 79 | + } | |
| 80 | + | |
| 81 | + | |
| 82 | + lock.lock(); | |
| 83 | + try { | |
| 84 | + // remove the ole cookie if there has had one | |
| 85 | + cookieJar.remove(cookie); | |
| 86 | + | |
| 87 | + // add new cookie if it has a non-zero max-age | |
| 88 | + if (cookie.getMaxAge() != 0) { | |
| 89 | + cookieJar.add(cookie); | |
| 90 | + // and add it to domain index | |
| 91 | + if (cookie.getDomain() != null) { | |
| 92 | + addIndex(domainIndex, cookie.getDomain(), cookie); | |
| 93 | + } | |
| 94 | + // add it to uri index, too | |
| 95 | + addIndex(uriIndex, getEffectiveURI(uri), cookie); | |
| 96 | + } | |
| 97 | + } finally { | |
| 98 | + lock.unlock(); | |
| 99 | + } | |
| 100 | + } | |
| 101 | + | |
| 102 | + | |
| 103 | + /** | |
| 104 | + * Get all cookies, which: | |
| 105 | + * 1) given uri domain-matches with, or, associated with | |
| 106 | + * given uri when added to the cookie store. | |
| 107 | + * 3) not expired. | |
| 108 | + * See RFC 2965 sec. 3.3.4 for more detail. | |
| 109 | + */ | |
| 110 | + public List<HttpCookie> get(URI uri) { | |
| 111 | + // argument can't be null | |
| 112 | + if (uri == null) { | |
| 113 | + throw new NullPointerException("uri is null"); | |
| 114 | + } | |
| 115 | + | |
| 116 | + List<HttpCookie> cookies = new ArrayList<HttpCookie>(); | |
| 117 | + boolean secureLink = "https".equalsIgnoreCase(uri.getScheme()); | |
| 118 | + lock.lock(); | |
| 119 | + try { | |
| 120 | + // check domainIndex first | |
| 121 | + getInternal1(cookies, domainIndex, uri.getHost(), secureLink); | |
| 122 | + // check uriIndex then | |
| 123 | + getInternal2(cookies, uriIndex, getEffectiveURI(uri), secureLink); | |
| 124 | + } finally { | |
| 125 | + lock.unlock(); | |
| 126 | + } | |
| 127 | + | |
| 128 | + return cookies; | |
| 129 | + } | |
| 130 | + | |
| 131 | + /** | |
| 132 | + * Get all cookies in cookie store, except those have expired | |
| 133 | + */ | |
| 134 | + public List<HttpCookie> getCookies() { | |
| 135 | + List<HttpCookie> rt; | |
| 136 | + | |
| 137 | + lock.lock(); | |
| 138 | + try { | |
| 139 | + Iterator<HttpCookie> it = cookieJar.iterator(); | |
| 140 | + while (it.hasNext()) { | |
| 141 | + if (it.next().hasExpired()) { | |
| 142 | + it.remove(); | |
| 143 | + } | |
| 144 | + } | |
| 145 | + } finally { | |
| 146 | + rt = Collections.unmodifiableList(cookieJar); | |
| 147 | + lock.unlock(); | |
| 148 | + } | |
| 149 | + | |
| 150 | + return rt; | |
| 151 | + } | |
| 152 | + | |
| 153 | + /** | |
| 154 | + * Get all URIs, which are associated with at least one cookie | |
| 155 | + * of this cookie store. | |
| 156 | + */ | |
| 157 | + public List<URI> getURIs() { | |
| 158 | + List<URI> uris = new ArrayList<URI>(); | |
| 159 | + | |
| 160 | + lock.lock(); | |
| 161 | + try { | |
| 162 | + Iterator<URI> it = uriIndex.keySet().iterator(); | |
| 163 | + while (it.hasNext()) { | |
| 164 | + URI uri = it.next(); | |
| 165 | + List<HttpCookie> cookies = uriIndex.get(uri); | |
| 166 | + if (cookies == null || cookies.size() == 0) { | |
| 167 | + // no cookies list or an empty list associated with | |
| 168 | + // this uri entry, delete it | |
| 169 | + it.remove(); | |
| 170 | + } | |
| 171 | + } | |
| 172 | + } finally { | |
| 173 | + uris.addAll(uriIndex.keySet()); | |
| 174 | + lock.unlock(); | |
| 175 | + } | |
| 176 | + | |
| 177 | + return uris; | |
| 178 | + } | |
| 179 | + | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * Remove a cookie from store | |
| 183 | + */ | |
| 184 | + public boolean remove(URI uri, HttpCookie ck) { | |
| 185 | + // argument can't be null | |
| 186 | + if (ck == null) { | |
| 187 | + throw new NullPointerException("cookie is null"); | |
| 188 | + } | |
| 189 | + | |
| 190 | + boolean modified = false; | |
| 191 | + lock.lock(); | |
| 192 | + try { | |
| 193 | + modified = cookieJar.remove(ck); | |
| 194 | + } finally { | |
| 195 | + lock.unlock(); | |
| 196 | + } | |
| 197 | + | |
| 198 | + return modified; | |
| 199 | + } | |
| 200 | + | |
| 201 | + | |
| 202 | + /** | |
| 203 | + * Remove all cookies in this cookie store. | |
| 204 | + */ | |
| 205 | + public boolean removeAll() { | |
| 206 | + lock.lock(); | |
| 207 | + try { | |
| 208 | + cookieJar.clear(); | |
| 209 | + domainIndex.clear(); | |
| 210 | + uriIndex.clear(); | |
| 211 | + } finally { | |
| 212 | + lock.unlock(); | |
| 213 | + } | |
| 214 | + | |
| 215 | + return true; | |
| 216 | + } | |
| 217 | + | |
| 218 | + | |
| 219 | + /* ---------------- Private operations -------------- */ | |
| 220 | + | |
| 221 | + | |
| 222 | + /* | |
| 223 | + * This is almost the same as HttpCookie.domainMatches except for | |
| 224 | + * one difference: It won't reject cookies when the 'H' part of the | |
| 225 | + * domain contains a dot ('.'). | |
| 226 | + * I.E.: RFC 2965 section 3.3.2 says that if host is x.y.domain.com | |
| 227 | + * and the cookie domain is .domain.com, then it should be rejected. | |
| 228 | + * However that's not how the real world works. Browsers don't reject and | |
| 229 | + * some sites, like yahoo.com do actually expect these cookies to be | |
| 230 | + * passed along. | |
| 231 | + * And should be used for 'old' style cookies (aka Netscape type of cookies) | |
| 232 | + */ | |
| 233 | + private boolean netscapeDomainMatches(String domain, String host) | |
| 234 | + { | |
| 235 | + if (domain == null || host == null) { | |
| 236 | + return false; | |
| 237 | + } | |
| 238 | + | |
| 239 | + // if there's no embedded dot in domain and domain is not .local | |
| 240 | + boolean isLocalDomain = ".local".equalsIgnoreCase(domain); | |
| 241 | + int embeddedDotInDomain = domain.indexOf('.'); | |
| 242 | + if (embeddedDotInDomain == 0) { | |
| 243 | + embeddedDotInDomain = domain.indexOf('.', 1); | |
| 244 | + } | |
| 245 | + if (!isLocalDomain && (embeddedDotInDomain == -1 || embeddedDotInDomain == domain.length() - 1)) { | |
| 246 | + return false; | |
| 247 | + } | |
| 248 | + | |
| 249 | + // if the host name contains no dot and the domain name is .local | |
| 250 | + int firstDotInHost = host.indexOf('.'); | |
| 251 | + if (firstDotInHost == -1 && isLocalDomain) { | |
| 252 | + return true; | |
| 253 | + } | |
| 254 | + | |
| 255 | + int domainLength = domain.length(); | |
| 256 | + int lengthDiff = host.length() - domainLength; | |
| 257 | + if (lengthDiff == 0) { | |
| 258 | + // if the host name and the domain name are just string-compare euqal | |
| 259 | + return host.equalsIgnoreCase(domain); | |
| 260 | + } else if (lengthDiff > 0) { | |
| 261 | + // need to check H & D component | |
| 262 | + String H = host.substring(0, lengthDiff); | |
| 263 | + String D = host.substring(lengthDiff); | |
| 264 | + | |
| 265 | + return (D.equalsIgnoreCase(domain)); | |
| 266 | + } else if (lengthDiff == -1) { | |
| 267 | + // if domain is actually .host | |
| 268 | + return (domain.charAt(0) == '.' && | |
| 269 | + host.equalsIgnoreCase(domain.substring(1))); | |
| 270 | + } | |
| 271 | + | |
| 272 | + return false; | |
| 273 | + } | |
| 274 | + | |
| 275 | + private void getInternal1(List<HttpCookie> cookies, Map<String, List<HttpCookie>> cookieIndex, | |
| 276 | + String host, boolean secureLink) { | |
| 277 | + // Use a separate list to handle cookies that need to be removed so | |
| 278 | + // that there is no conflict with iterators. | |
| 279 | + ArrayList<HttpCookie> toRemove = new ArrayList<HttpCookie>(); | |
| 280 | + for (Map.Entry<String, List<HttpCookie>> entry : cookieIndex.entrySet()) { | |
| 281 | + String domain = entry.getKey(); | |
| 282 | + List<HttpCookie> lst = entry.getValue(); | |
| 283 | + for (HttpCookie c : lst) { | |
| 284 | + if ((c.getVersion() == 0 && netscapeDomainMatches(domain, host)) || | |
| 285 | + (c.getVersion() == 1 && HttpCookie.domainMatches(domain, host))) { | |
| 286 | + if ((cookieJar.indexOf(c) != -1)) { | |
| 287 | + // the cookie still in main cookie store | |
| 288 | + if (!c.hasExpired()) { | |
| 289 | + // don't add twice and make sure it's the proper | |
| 290 | + // security level | |
| 291 | + if ((secureLink || !c.getSecure()) && | |
| 292 | + !cookies.contains(c)) { | |
| 293 | + cookies.add(c); | |
| 294 | + } | |
| 295 | + } else { | |
| 296 | + toRemove.add(c); | |
| 297 | + } | |
| 298 | + } else { | |
| 299 | + // the cookie has beed removed from main store, | |
| 300 | + // so also remove it from domain indexed store | |
| 301 | + toRemove.add(c); | |
| 302 | + } | |
| 303 | + } | |
| 304 | + } | |
| 305 | + // Clear up the cookies that need to be removed | |
| 306 | + for (HttpCookie c : toRemove) { | |
| 307 | + lst.remove(c); | |
| 308 | + cookieJar.remove(c); | |
| 309 | + | |
| 310 | + } | |
| 311 | + toRemove.clear(); | |
| 312 | + } | |
| 313 | + } | |
| 314 | + | |
| 315 | + // @param cookies [OUT] contains the found cookies | |
| 316 | + // @param cookieIndex the index | |
| 317 | + // @param comparator the prediction to decide whether or not | |
| 318 | + // a cookie in index should be returned | |
| 319 | + private <T> void getInternal2(List<HttpCookie> cookies, | |
| 320 | + Map<T, List<HttpCookie>> cookieIndex, | |
| 321 | + Comparable<T> comparator, boolean secureLink) | |
| 322 | + { | |
| 323 | + for (T index : cookieIndex.keySet()) { | |
| 324 | + if (comparator.compareTo(index) == 0) { | |
| 325 | + List<HttpCookie> indexedCookies = cookieIndex.get(index); | |
| 326 | + // check the list of cookies associated with this domain | |
| 327 | + if (indexedCookies != null) { | |
| 328 | + Iterator<HttpCookie> it = indexedCookies.iterator(); | |
| 329 | + while (it.hasNext()) { | |
| 330 | + HttpCookie ck = it.next(); | |
| 331 | + if (cookieJar.indexOf(ck) != -1) { | |
| 332 | + // the cookie still in main cookie store | |
| 333 | + if (!ck.hasExpired()) { | |
| 334 | + // don't add twice | |
| 335 | + if ((secureLink || !ck.getSecure()) && | |
| 336 | + !cookies.contains(ck)) | |
| 337 | + cookies.add(ck); | |
| 338 | + } else { | |
| 339 | + it.remove(); | |
| 340 | + cookieJar.remove(ck); | |
| 341 | + } | |
| 342 | + } else { | |
| 343 | + // the cookie has beed removed from main store, | |
| 344 | + // so also remove it from domain indexed store | |
| 345 | + it.remove(); | |
| 346 | + } | |
| 347 | + } | |
| 348 | + } // end of indexedCookies != null | |
| 349 | + } // end of comparator.compareTo(index) == 0 | |
| 350 | + } // end of cookieIndex iteration | |
| 351 | + } | |
| 352 | + | |
| 353 | + // add 'cookie' indexed by 'index' into 'indexStore' | |
| 354 | + private <T> void addIndex(Map<T, List<HttpCookie>> indexStore, | |
| 355 | + T index, | |
| 356 | + HttpCookie cookie) | |
| 357 | + { | |
| 358 | + if (index != null) { | |
| 359 | + List<HttpCookie> cookies = indexStore.get(index); | |
| 360 | + if (cookies != null) { | |
| 361 | + // there may already have the same cookie, so remove it first | |
| 362 | + cookies.remove(cookie); | |
| 363 | + | |
| 364 | + cookies.add(cookie); | |
| 365 | + } else { | |
| 366 | + cookies = new ArrayList<HttpCookie>(); | |
| 367 | + cookies.add(cookie); | |
| 368 | + indexStore.put(index, cookies); | |
| 369 | + } | |
| 370 | + } | |
| 371 | + } | |
| 372 | + | |
| 373 | + | |
| 374 | + // | |
| 375 | + // for cookie purpose, the effective uri should only be http://host | |
| 376 | + // the path will be taken into account when path-match algorithm applied | |
| 377 | + // | |
| 378 | + private URI getEffectiveURI(URI uri) { | |
| 379 | + URI effectiveURI = null; | |
| 380 | + try { | |
| 381 | + effectiveURI = new URI("http", | |
| 382 | + uri.getHost(), | |
| 383 | + null, // path component | |
| 384 | + null, // query component | |
| 385 | + null // fragment component | |
| 386 | + ); | |
| 387 | + } catch (URISyntaxException ignored) { | |
| 388 | + effectiveURI = uri; | |
| 389 | + } | |
| 390 | + | |
| 391 | + return effectiveURI; | |
| 392 | + } | |
| 393 | +} | |
Binary file not shown.
| @@ -0,0 +1,374 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 2006, 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 java.net; | |
| 27 | + | |
| 28 | +import java.security.AccessController; | |
| 29 | +import java.io.ObjectStreamException; | |
| 30 | +import sun.security.action.*; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * This class represents an Internet Protocol version 4 (IPv4) address. | |
| 34 | + * Defined by <a href="http://www.ietf.org/rfc/rfc790.txt"> | |
| 35 | + * <i>RFC 790: Assigned Numbers</i></a>, | |
| 36 | + * <a href="http://www.ietf.org/rfc/rfc1918.txt"> | |
| 37 | + * <i>RFC 1918: Address Allocation for Private Internets</i></a>, | |
| 38 | + * and <a href="http://www.ietf.org/rfc/rfc2365.txt"><i>RFC 2365: | |
| 39 | + * Administratively Scoped IP Multicast</i></a> | |
| 40 | + * | |
| 41 | + * <h4> <A NAME="format">Textual representation of IP addresses</a> </h4> | |
| 42 | + * | |
| 43 | + * Textual representation of IPv4 address used as input to methods | |
| 44 | + * takes one of the following forms: | |
| 45 | + * | |
| 46 | + * <blockquote><table cellpadding=0 cellspacing=0 summary="layout"> | |
| 47 | + * <tr><td><tt>d.d.d.d</tt></td></tr> | |
| 48 | + * <tr><td><tt>d.d.d</tt></td></tr> | |
| 49 | + * <tr><td><tt>d.d</tt></td></tr> | |
| 50 | + * <tr><td><tt>d</tt></td></tr> | |
| 51 | + * </table></blockquote> | |
| 52 | + * | |
| 53 | + * <p> When four parts are specified, each is interpreted as a byte of | |
| 54 | + * data and assigned, from left to right, to the four bytes of an IPv4 | |
| 55 | + * address. | |
| 56 | + | |
| 57 | + * <p> When a three part address is specified, the last part is | |
| 58 | + * interpreted as a 16-bit quantity and placed in the right most two | |
| 59 | + * bytes of the network address. This makes the three part address | |
| 60 | + * format convenient for specifying Class B net- work addresses as | |
| 61 | + * 128.net.host. | |
| 62 | + * | |
| 63 | + * <p> When a two part address is supplied, the last part is | |
| 64 | + * interpreted as a 24-bit quantity and placed in the right most three | |
| 65 | + * bytes of the network address. This makes the two part address | |
| 66 | + * format convenient for specifying Class A network addresses as | |
| 67 | + * net.host. | |
| 68 | + * | |
| 69 | + * <p> When only one part is given, the value is stored directly in | |
| 70 | + * the network address without any byte rearrangement. | |
| 71 | + * | |
| 72 | + * <p> For methods that return a textual representation as output | |
| 73 | + * value, the first form, i.e. a dotted-quad string, is used. | |
| 74 | + * | |
| 75 | + * <h4> The Scope of a Multicast Address </h4> | |
| 76 | + * | |
| 77 | + * Historically the IPv4 TTL field in the IP header has doubled as a | |
| 78 | + * multicast scope field: a TTL of 0 means node-local, 1 means | |
| 79 | + * link-local, up through 32 means site-local, up through 64 means | |
| 80 | + * region-local, up through 128 means continent-local, and up through | |
| 81 | + * 255 are global. However, the administrative scoping is preferred. | |
| 82 | + * Please refer to <a href="http://www.ietf.org/rfc/rfc2365.txt"> | |
| 83 | + * <i>RFC 2365: Administratively Scoped IP Multicast</i></a> | |
| 84 | + * @since 1.4 | |
| 85 | + */ | |
| 86 | + | |
| 87 | +public final | |
| 88 | +class Inet4Address extends InetAddress { | |
| 89 | + final static int INADDRSZ = 4; | |
| 90 | + | |
| 91 | + /** use serialVersionUID from InetAddress, but Inet4Address instance | |
| 92 | + * is always replaced by an InetAddress instance before being | |
| 93 | + * serialized */ | |
| 94 | + private static final long serialVersionUID = 3286316764910316507L; | |
| 95 | + | |
| 96 | + /* | |
| 97 | + * Perform initializations. | |
| 98 | + */ | |
| 99 | + static { | |
| 100 | + init(); | |
| 101 | + } | |
| 102 | + | |
| 103 | + Inet4Address() { | |
| 104 | + super(); | |
| 105 | + hostName = null; | |
| 106 | + address = 0; | |
| 107 | + family = IPv4; | |
| 108 | + } | |
| 109 | + | |
| 110 | + Inet4Address(String hostName, byte addr[]) { | |
| 111 | + this.hostName = hostName; | |
| 112 | + this.family = IPv4; | |
| 113 | + if (addr != null) { | |
| 114 | + if (addr.length == INADDRSZ) { | |
| 115 | + address = addr[3] & 0xFF; | |
| 116 | + address |= ((addr[2] << 8) & 0xFF00); | |
| 117 | + address |= ((addr[1] << 16) & 0xFF0000); | |
| 118 | + address |= ((addr[0] << 24) & 0xFF000000); | |
| 119 | + } | |
| 120 | + } | |
| 121 | + } | |
| 122 | + Inet4Address(String hostName, int address) { | |
| 123 | + this.hostName = hostName; | |
| 124 | + this.family = IPv4; | |
| 125 | + this.address = address; | |
| 126 | + } | |
| 127 | + | |
| 128 | + /** | |
| 129 | + * Replaces the object to be serialized with an InetAddress object. | |
| 130 | + * | |
| 131 | + * @return the alternate object to be serialized. | |
| 132 | + * | |
| 133 | + * @throws ObjectStreamException if a new object replacing this | |
| 134 | + * object could not be created | |
| 135 | + */ | |
| 136 | + private Object writeReplace() throws ObjectStreamException { | |
| 137 | + // will replace the to be serialized 'this' object | |
| 138 | + InetAddress inet = new InetAddress(); | |
| 139 | + inet.hostName = this.hostName; | |
| 140 | + inet.address = this.address; | |
| 141 | + | |
| 142 | + /** | |
| 143 | + * Prior to 1.4 an InetAddress was created with a family | |
| 144 | + * based on the platform AF_INET value (usually 2). | |
| 145 | + * For compatibility reasons we must therefore write the | |
| 146 | + * the InetAddress with this family. | |
| 147 | + */ | |
| 148 | + inet.family = 2; | |
| 149 | + | |
| 150 | + return inet; | |
| 151 | + } | |
| 152 | + | |
| 153 | + /** | |
| 154 | + * Utility routine to check if the InetAddress is an | |
| 155 | + * IP multicast address. IP multicast address is a Class D | |
| 156 | + * address i.e first four bits of the address are 1110. | |
| 157 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 158 | + * an IP multicast address | |
| 159 | + * @since JDK1.1 | |
| 160 | + */ | |
| 161 | + public boolean isMulticastAddress() { | |
| 162 | + return ((address & 0xf0000000) == 0xe0000000); | |
| 163 | + } | |
| 164 | + | |
| 165 | + /** | |
| 166 | + * Utility routine to check if the InetAddress in a wildcard address. | |
| 167 | + * @return a <code>boolean</code> indicating if the Inetaddress is | |
| 168 | + * a wildcard address. | |
| 169 | + * @since 1.4 | |
| 170 | + */ | |
| 171 | + public boolean isAnyLocalAddress() { | |
| 172 | + return address == 0; | |
| 173 | + } | |
| 174 | + | |
| 175 | + /** | |
| 176 | + * Utility routine to check if the InetAddress is a loopback address. | |
| 177 | + * | |
| 178 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 179 | + * a loopback address; or false otherwise. | |
| 180 | + * @since 1.4 | |
| 181 | + */ | |
| 182 | + private static final int loopback = 2130706433; /* 127.0.0.1 */ | |
| 183 | + public boolean isLoopbackAddress() { | |
| 184 | + /* 127.x.x.x */ | |
| 185 | + byte[] byteAddr = getAddress(); | |
| 186 | + return byteAddr[0] == 127; | |
| 187 | + } | |
| 188 | + | |
| 189 | + /** | |
| 190 | + * Utility routine to check if the InetAddress is an link local address. | |
| 191 | + * | |
| 192 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 193 | + * a link local address; or false if address is not a link local unicast address. | |
| 194 | + * @since 1.4 | |
| 195 | + */ | |
| 196 | + public boolean isLinkLocalAddress() { | |
| 197 | + // link-local unicast in IPv4 (169.254.0.0/16) | |
| 198 | + // defined in "Documenting Special Use IPv4 Address Blocks | |
| 199 | + // that have been Registered with IANA" by Bill Manning | |
| 200 | + // draft-manning-dsua-06.txt | |
| 201 | + return (((address >>> 24) & 0xFF) == 169) | |
| 202 | + && (((address >>> 16) & 0xFF) == 254); | |
| 203 | + } | |
| 204 | + | |
| 205 | + /** | |
| 206 | + * Utility routine to check if the InetAddress is a site local address. | |
| 207 | + * | |
| 208 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 209 | + * a site local address; or false if address is not a site local unicast address. | |
| 210 | + * @since 1.4 | |
| 211 | + */ | |
| 212 | + public boolean isSiteLocalAddress() { | |
| 213 | + // refer to RFC 1918 | |
| 214 | + // 10/8 prefix | |
| 215 | + // 172.16/12 prefix | |
| 216 | + // 192.168/16 prefix | |
| 217 | + return (((address >>> 24) & 0xFF) == 10) | |
| 218 | + || ((((address >>> 24) & 0xFF) == 172) | |
| 219 | + && (((address >>> 16) & 0xF0) == 16)) | |
| 220 | + || ((((address >>> 24) & 0xFF) == 192) | |
| 221 | + && (((address >>> 16) & 0xFF) == 168)); | |
| 222 | + } | |
| 223 | + | |
| 224 | + /** | |
| 225 | + * Utility routine to check if the multicast address has global scope. | |
| 226 | + * | |
| 227 | + * @return a <code>boolean</code> indicating if the address has | |
| 228 | + * is a multicast address of global scope, false if it is not | |
| 229 | + * of global scope or it is not a multicast address | |
| 230 | + * @since 1.4 | |
| 231 | + */ | |
| 232 | + public boolean isMCGlobal() { | |
| 233 | + // 224.0.1.0 to 238.255.255.255 | |
| 234 | + byte[] byteAddr = getAddress(); | |
| 235 | + return ((byteAddr[0] & 0xff) >= 224 && (byteAddr[0] & 0xff) <= 238 ) && | |
| 236 | + !((byteAddr[0] & 0xff) == 224 && byteAddr[1] == 0 && | |
| 237 | + byteAddr[2] == 0); | |
| 238 | + } | |
| 239 | + | |
| 240 | + /** | |
| 241 | + * Utility routine to check if the multicast address has node scope. | |
| 242 | + * | |
| 243 | + * @return a <code>boolean</code> indicating if the address has | |
| 244 | + * is a multicast address of node-local scope, false if it is not | |
| 245 | + * of node-local scope or it is not a multicast address | |
| 246 | + * @since 1.4 | |
| 247 | + */ | |
| 248 | + public boolean isMCNodeLocal() { | |
| 249 | + // unless ttl == 0 | |
| 250 | + return false; | |
| 251 | + } | |
| 252 | + | |
| 253 | + /** | |
| 254 | + * Utility routine to check if the multicast address has link scope. | |
| 255 | + * | |
| 256 | + * @return a <code>boolean</code> indicating if the address has | |
| 257 | + * is a multicast address of link-local scope, false if it is not | |
| 258 | + * of link-local scope or it is not a multicast address | |
| 259 | + * @since 1.4 | |
| 260 | + */ | |
| 261 | + public boolean isMCLinkLocal() { | |
| 262 | + // 224.0.0/24 prefix and ttl == 1 | |
| 263 | + return (((address >>> 24) & 0xFF) == 224) | |
| 264 | + && (((address >>> 16) & 0xFF) == 0) | |
| 265 | + && (((address >>> 8) & 0xFF) == 0); | |
| 266 | + } | |
| 267 | + | |
| 268 | + /** | |
| 269 | + * Utility routine to check if the multicast address has site scope. | |
| 270 | + * | |
| 271 | + * @return a <code>boolean</code> indicating if the address has | |
| 272 | + * is a multicast address of site-local scope, false if it is not | |
| 273 | + * of site-local scope or it is not a multicast address | |
| 274 | + * @since 1.4 | |
| 275 | + */ | |
| 276 | + public boolean isMCSiteLocal() { | |
| 277 | + // 239.255/16 prefix or ttl < 32 | |
| 278 | + return (((address >>> 24) & 0xFF) == 239) | |
| 279 | + && (((address >>> 16) & 0xFF) == 255); | |
| 280 | + } | |
| 281 | + | |
| 282 | + /** | |
| 283 | + * Utility routine to check if the multicast address has organization scope. | |
| 284 | + * | |
| 285 | + * @return a <code>boolean</code> indicating if the address has | |
| 286 | + * is a multicast address of organization-local scope, | |
| 287 | + * false if it is not of organization-local scope | |
| 288 | + * or it is not a multicast address | |
| 289 | + * @since 1.4 | |
| 290 | + */ | |
| 291 | + public boolean isMCOrgLocal() { | |
| 292 | + // 239.192 - 239.195 | |
| 293 | + return (((address >>> 24) & 0xFF) == 239) | |
| 294 | + && (((address >>> 16) & 0xFF) >= 192) | |
| 295 | + && (((address >>> 16) & 0xFF) <= 195); | |
| 296 | + } | |
| 297 | + | |
| 298 | + /** | |
| 299 | + * Returns the raw IP address of this <code>InetAddress</code> | |
| 300 | + * object. The result is in network byte order: the highest order | |
| 301 | + * byte of the address is in <code>getAddress()[0]</code>. | |
| 302 | + * | |
| 303 | + * @return the raw IP address of this object. | |
| 304 | + */ | |
| 305 | + public byte[] getAddress() { | |
| 306 | + byte[] addr = new byte[INADDRSZ]; | |
| 307 | + | |
| 308 | + addr[0] = (byte) ((address >>> 24) & 0xFF); | |
| 309 | + addr[1] = (byte) ((address >>> 16) & 0xFF); | |
| 310 | + addr[2] = (byte) ((address >>> 8) & 0xFF); | |
| 311 | + addr[3] = (byte) (address & 0xFF); | |
| 312 | + return addr; | |
| 313 | + } | |
| 314 | + | |
| 315 | + /** | |
| 316 | + * Returns the IP address string in textual presentation form. | |
| 317 | + * | |
| 318 | + * @return the raw IP address in a string format. | |
| 319 | + * @since JDK1.0.2 | |
| 320 | + */ | |
| 321 | + public String getHostAddress() { | |
| 322 | + return numericToTextFormat(getAddress()); | |
| 323 | + } | |
| 324 | + | |
| 325 | + /** | |
| 326 | + * Returns a hashcode for this IP address. | |
| 327 | + * | |
| 328 | + * @return a hash code value for this IP address. | |
| 329 | + */ | |
| 330 | + public int hashCode() { | |
| 331 | + return address; | |
| 332 | + } | |
| 333 | + | |
| 334 | + /** | |
| 335 | + * Compares this object against the specified object. | |
| 336 | + * The result is <code>true</code> if and only if the argument is | |
| 337 | + * not <code>null</code> and it represents the same IP address as | |
| 338 | + * this object. | |
| 339 | + * <p> | |
| 340 | + * Two instances of <code>InetAddress</code> represent the same IP | |
| 341 | + * address if the length of the byte arrays returned by | |
| 342 | + * <code>getAddress</code> is the same for both, and each of the | |
| 343 | + * array components is the same for the byte arrays. | |
| 344 | + * | |
| 345 | + * @param obj the object to compare against. | |
| 346 | + * @return <code>true</code> if the objects are the same; | |
| 347 | + * <code>false</code> otherwise. | |
| 348 | + * @see java.net.InetAddress#getAddress() | |
| 349 | + */ | |
| 350 | + public boolean equals(Object obj) { | |
| 351 | + return (obj != null) && (obj instanceof Inet4Address) && | |
| 352 | + (((InetAddress)obj).address == address); | |
| 353 | + } | |
| 354 | + | |
| 355 | + // Utilities | |
| 356 | + /* | |
| 357 | + * Converts IPv4 binary address into a string suitable for presentation. | |
| 358 | + * | |
| 359 | + * @param src a byte array representing an IPv4 numeric address | |
| 360 | + * @return a String representing the IPv4 address in | |
| 361 | + * textual representation format | |
| 362 | + * @since 1.4 | |
| 363 | + */ | |
| 364 | + | |
| 365 | + static String numericToTextFormat(byte[] src) | |
| 366 | + { | |
| 367 | + return (src[0] & 0xff) + "." + (src[1] & 0xff) + "." + (src[2] & 0xff) + "." + (src[3] & 0xff); | |
| 368 | + } | |
| 369 | + | |
| 370 | + /** | |
| 371 | + * Perform class load-time initializations. | |
| 372 | + */ | |
| 373 | + private static native void init(); | |
| 374 | +} | |
Binary file not shown.
| @@ -0,0 +1,74 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2002, 2005, 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 | +package java.net; | |
| 26 | +import java.io.IOException; | |
| 27 | + | |
| 28 | +/* | |
| 29 | + * Package private implementation of InetAddressImpl for IPv4. | |
| 30 | + * | |
| 31 | + * @since 1.4 | |
| 32 | + */ | |
| 33 | +class Inet4AddressImpl implements InetAddressImpl { | |
| 34 | + public native String getLocalHostName() throws UnknownHostException; | |
| 35 | + public native InetAddress[] | |
| 36 | + lookupAllHostAddr(String hostname) throws UnknownHostException; | |
| 37 | + public native String getHostByAddr(byte[] addr) throws UnknownHostException; | |
| 38 | + private native boolean isReachable0(byte[] addr, int timeout, byte[] ifaddr, int ttl) throws IOException; | |
| 39 | + | |
| 40 | + public synchronized InetAddress anyLocalAddress() { | |
| 41 | + if (anyLocalAddress == null) { | |
| 42 | + anyLocalAddress = new Inet4Address(); // {0x00,0x00,0x00,0x00} | |
| 43 | + anyLocalAddress.hostName = "0.0.0.0"; | |
| 44 | + } | |
| 45 | + return anyLocalAddress; | |
| 46 | + } | |
| 47 | + | |
| 48 | + public synchronized InetAddress loopbackAddress() { | |
| 49 | + if (loopbackAddress == null) { | |
| 50 | + byte[] loopback = {0x7f,0x00,0x00,0x01}; | |
| 51 | + loopbackAddress = new Inet4Address("localhost", loopback); | |
| 52 | + } | |
| 53 | + return loopbackAddress; | |
| 54 | + } | |
| 55 | + | |
| 56 | + public boolean isReachable(InetAddress addr, int timeout, NetworkInterface netif, int ttl) throws IOException { | |
| 57 | + byte[] ifaddr = null; | |
| 58 | + if (netif != null) { | |
| 59 | + /* | |
| 60 | + * Let's make sure we use an address of the proper family | |
| 61 | + */ | |
| 62 | + java.util.Enumeration it = netif.getInetAddresses(); | |
| 63 | + InetAddress inetaddr = null; | |
| 64 | + while (!(inetaddr instanceof Inet4Address) && | |
| 65 | + it.hasMoreElements()) | |
| 66 | + inetaddr = (InetAddress) it.nextElement(); | |
| 67 | + if (inetaddr instanceof Inet4Address) | |
| 68 | + ifaddr = inetaddr.getAddress(); | |
| 69 | + } | |
| 70 | + return isReachable0(addr.getAddress(), timeout, ifaddr, ttl); | |
| 71 | + } | |
| 72 | + private InetAddress anyLocalAddress; | |
| 73 | + private InetAddress loopbackAddress; | |
| 74 | +} | |
Binary file not shown.
| @@ -0,0 +1,774 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 2010, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.ObjectInputStream; | |
| 29 | +import java.io.IOException; | |
| 30 | +import java.io.InvalidObjectException; | |
| 31 | +import java.util.Enumeration; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * This class represents an Internet Protocol version 6 (IPv6) address. | |
| 35 | + * Defined by <a href="http://www.ietf.org/rfc/rfc2373.txt"> | |
| 36 | + * <i>RFC 2373: IP Version 6 Addressing Architecture</i></a>. | |
| 37 | + * | |
| 38 | + * <h4> <A NAME="format">Textual representation of IP addresses</a> </h4> | |
| 39 | + * | |
| 40 | + * Textual representation of IPv6 address used as input to methods | |
| 41 | + * takes one of the following forms: | |
| 42 | + * | |
| 43 | + * <ol> | |
| 44 | + * <li><p> <A NAME="lform">The preferred form</a> is x:x:x:x:x:x:x:x, | |
| 45 | + * where the 'x's are | |
| 46 | + * the hexadecimal values of the eight 16-bit pieces of the | |
| 47 | + * address. This is the full form. For example, | |
| 48 | + * | |
| 49 | + * <blockquote><table cellpadding=0 cellspacing=0 summary="layout"> | |
| 50 | + * <tr><td><tt>1080:0:0:0:8:800:200C:417A</tt><td></tr> | |
| 51 | + * </table></blockquote> | |
| 52 | + * | |
| 53 | + * <p> Note that it is not necessary to write the leading zeros in | |
| 54 | + * an individual field. However, there must be at least one numeral | |
| 55 | + * in every field, except as described below.</li> | |
| 56 | + * | |
| 57 | + * <li><p> Due to some methods of allocating certain styles of IPv6 | |
| 58 | + * addresses, it will be common for addresses to contain long | |
| 59 | + * strings of zero bits. In order to make writing addresses | |
| 60 | + * containing zero bits easier, a special syntax is available to | |
| 61 | + * compress the zeros. The use of "::" indicates multiple groups | |
| 62 | + * of 16-bits of zeros. The "::" can only appear once in an address. | |
| 63 | + * The "::" can also be used to compress the leading and/or trailing | |
| 64 | + * zeros in an address. For example, | |
| 65 | + * | |
| 66 | + * <blockquote><table cellpadding=0 cellspacing=0 summary="layout"> | |
| 67 | + * <tr><td><tt>1080::8:800:200C:417A</tt><td></tr> | |
| 68 | + * </table></blockquote> | |
| 69 | + * | |
| 70 | + * <li><p> An alternative form that is sometimes more convenient | |
| 71 | + * when dealing with a mixed environment of IPv4 and IPv6 nodes is | |
| 72 | + * x:x:x:x:x:x:d.d.d.d, where the 'x's are the hexadecimal values | |
| 73 | + * of the six high-order 16-bit pieces of the address, and the 'd's | |
| 74 | + * are the decimal values of the four low-order 8-bit pieces of the | |
| 75 | + * standard IPv4 representation address, for example, | |
| 76 | + * | |
| 77 | + * <blockquote><table cellpadding=0 cellspacing=0 summary="layout"> | |
| 78 | + * <tr><td><tt>::FFFF:129.144.52.38</tt><td></tr> | |
| 79 | + * <tr><td><tt>::129.144.52.38</tt><td></tr> | |
| 80 | + * </table></blockquote> | |
| 81 | + * | |
| 82 | + * <p> where "::FFFF:d.d.d.d" and "::d.d.d.d" are, respectively, the | |
| 83 | + * general forms of an IPv4-mapped IPv6 address and an | |
| 84 | + * IPv4-compatible IPv6 address. Note that the IPv4 portion must be | |
| 85 | + * in the "d.d.d.d" form. The following forms are invalid: | |
| 86 | + * | |
| 87 | + * <blockquote><table cellpadding=0 cellspacing=0 summary="layout"> | |
| 88 | + * <tr><td><tt>::FFFF:d.d.d</tt><td></tr> | |
| 89 | + * <tr><td><tt>::FFFF:d.d</tt><td></tr> | |
| 90 | + * <tr><td><tt>::d.d.d</tt><td></tr> | |
| 91 | + * <tr><td><tt>::d.d</tt><td></tr> | |
| 92 | + * </table></blockquote> | |
| 93 | + * | |
| 94 | + * <p> The following form: | |
| 95 | + * | |
| 96 | + * <blockquote><table cellpadding=0 cellspacing=0 summary="layout"> | |
| 97 | + * <tr><td><tt>::FFFF:d</tt><td></tr> | |
| 98 | + * </table></blockquote> | |
| 99 | + * | |
| 100 | + * <p> is valid, however it is an unconventional representation of | |
| 101 | + * the IPv4-compatible IPv6 address, | |
| 102 | + * | |
| 103 | + * <blockquote><table cellpadding=0 cellspacing=0 summary="layout"> | |
| 104 | + * <tr><td><tt>::255.255.0.d</tt><td></tr> | |
| 105 | + * </table></blockquote> | |
| 106 | + * | |
| 107 | + * <p> while "::d" corresponds to the general IPv6 address | |
| 108 | + * "0:0:0:0:0:0:0:d".</li> | |
| 109 | + * </ol> | |
| 110 | + * | |
| 111 | + * <p> For methods that return a textual representation as output | |
| 112 | + * value, the full form is used. Inet6Address will return the full | |
| 113 | + * form because it is unambiguous when used in combination with other | |
| 114 | + * textual data. | |
| 115 | + * | |
| 116 | + * <h4> Special IPv6 address </h4> | |
| 117 | + * | |
| 118 | + * <blockquote> | |
| 119 | + * <table cellspacing=2 summary="Description of IPv4-mapped address"> <tr><th valign=top><i>IPv4-mapped address</i></th> | |
| 120 | + * <td>Of the form::ffff:w.x.y.z, this IPv6 address is used to | |
| 121 | + * represent an IPv4 address. It allows the native program to | |
| 122 | + * use the same address data structure and also the same | |
| 123 | + * socket when communicating with both IPv4 and IPv6 nodes. | |
| 124 | + * | |
| 125 | + * <p>In InetAddress and Inet6Address, it is used for internal | |
| 126 | + * representation; it has no functional role. Java will never | |
| 127 | + * return an IPv4-mapped address. These classes can take an | |
| 128 | + * IPv4-mapped address as input, both in byte array and text | |
| 129 | + * representation. However, it will be converted into an IPv4 | |
| 130 | + * address.</td></tr> | |
| 131 | + * </table></blockquote> | |
| 132 | + * <p> | |
| 133 | + * <h4> <A NAME="scoped">Textual representation of IPv6 scoped addresses</a> </h4> | |
| 134 | + * <p> | |
| 135 | + * The textual representation of IPv6 addresses as described above can be extended | |
| 136 | + * to specify IPv6 scoped addresses. This extension to the basic addressing architecture | |
| 137 | + * is described in [draft-ietf-ipngwg-scoping-arch-04.txt]. | |
| 138 | + * <p> | |
| 139 | + * Because link-local and site-local addresses are non-global, it is possible that different hosts | |
| 140 | + * may have the same destination address and may be reachable through different interfaces on the | |
| 141 | + * same originating system. In this case, the originating system is said to be connected | |
| 142 | + * to multiple zones of the same scope. In order to disambiguate which is the intended destination | |
| 143 | + * zone, it is possible to append a zone identifier (or <i>scope_id</i>) to an IPv6 address. | |
| 144 | + * <p> | |
| 145 | + * The general format for specifying the <i>scope_id</i> is the following: | |
| 146 | + * <p><blockquote><i>IPv6-address</i>%<i>scope_id</i></blockquote> | |
| 147 | + * <p> The IPv6-address is a literal IPv6 address as described above. | |
| 148 | + * The <i>scope_id</i> refers to an interface on the local system, and it can be specified | |
| 149 | + * in two ways. | |
| 150 | + * <p><ol><li><i>As a numeric identifier.</i> This must be a positive integer that identifies the | |
| 151 | + * particular interface and scope as understood by the system. Usually, the numeric | |
| 152 | + * values can be determined through administration tools on the system. Each interface may | |
| 153 | + * have multiple values, one for each scope. If the scope is unspecified, then the default value | |
| 154 | + * used is zero.</li><p> | |
| 155 | + * <li><i>As a string.</i> This must be the exact string that is returned by | |
| 156 | + * {@link java.net.NetworkInterface#getName()} for the particular interface in question. | |
| 157 | + * When an Inet6Address is created in this way, the numeric scope-id is determined at the time | |
| 158 | + * the object is created by querying the relevant NetworkInterface.</li> | |
| 159 | + * </ol><p> | |
| 160 | + * Note also, that the numeric <i>scope_id</i> can be retrieved from Inet6Address instances returned from the | |
| 161 | + * NetworkInterface class. This can be used to find out the current scope ids configured on the system. | |
| 162 | + * @since 1.4 | |
| 163 | + */ | |
| 164 | + | |
| 165 | +public final | |
| 166 | +class Inet6Address extends InetAddress { | |
| 167 | + final static int INADDRSZ = 16; | |
| 168 | + | |
| 169 | + /* | |
| 170 | + * cached scope_id - for link-local address use only. | |
| 171 | + */ | |
| 172 | + private transient int cached_scope_id = 0; | |
| 173 | + | |
| 174 | + /** | |
| 175 | + * Holds a 128-bit (16 bytes) IPv6 address. | |
| 176 | + * | |
| 177 | + * @serial | |
| 178 | + */ | |
| 179 | + byte[] ipaddress; | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * scope_id. The scope specified when the object is created. If the object is created | |
| 183 | + * with an interface name, then the scope_id is not determined until the time it is needed. | |
| 184 | + */ | |
| 185 | + private int scope_id = 0; | |
| 186 | + | |
| 187 | + /** | |
| 188 | + * This will be set to true when the scope_id field contains a valid | |
| 189 | + * integer scope_id. | |
| 190 | + */ | |
| 191 | + private boolean scope_id_set = false; | |
| 192 | + | |
| 193 | + /** | |
| 194 | + * scoped interface. scope_id is derived from this as the scope_id of the first | |
| 195 | + * address whose scope is the same as this address for the named interface. | |
| 196 | + */ | |
| 197 | + private transient NetworkInterface scope_ifname = null; | |
| 198 | + | |
| 199 | + /** | |
| 200 | + * set if the object is constructed with a scoped interface instead of a | |
| 201 | + * numeric scope id. | |
| 202 | + */ | |
| 203 | + private boolean scope_ifname_set = false; | |
| 204 | + | |
| 205 | + private static final long serialVersionUID = 6880410070516793377L; | |
| 206 | + | |
| 207 | + /* | |
| 208 | + * Perform initializations. | |
| 209 | + */ | |
| 210 | + static { | |
| 211 | + init(); | |
| 212 | + } | |
| 213 | + | |
| 214 | + Inet6Address() { | |
| 215 | + super(); | |
| 216 | + hostName = null; | |
| 217 | + ipaddress = new byte[INADDRSZ]; | |
| 218 | + family = IPv6; | |
| 219 | + } | |
| 220 | + | |
| 221 | + /* checking of value for scope_id should be done by caller | |
| 222 | + * scope_id must be >= 0, or -1 to indicate not being set | |
| 223 | + */ | |
| 224 | + Inet6Address(String hostName, byte addr[], int scope_id) { | |
| 225 | + this.hostName = hostName; | |
| 226 | + if (addr.length == INADDRSZ) { // normal IPv6 address | |
| 227 | + family = IPv6; | |
| 228 | + ipaddress = addr.clone(); | |
| 229 | + } | |
| 230 | + if (scope_id >= 0) { | |
| 231 | + this.scope_id = scope_id; | |
| 232 | + scope_id_set = true; | |
| 233 | + } | |
| 234 | + } | |
| 235 | + | |
| 236 | + Inet6Address(String hostName, byte addr[]) { | |
| 237 | + try { | |
| 238 | + initif (hostName, addr, null); | |
| 239 | + } catch (UnknownHostException e) {} /* cant happen if ifname is null */ | |
| 240 | + } | |
| 241 | + | |
| 242 | + Inet6Address (String hostName, byte addr[], NetworkInterface nif) throws UnknownHostException { | |
| 243 | + initif (hostName, addr, nif); | |
| 244 | + } | |
| 245 | + | |
| 246 | + Inet6Address (String hostName, byte addr[], String ifname) throws UnknownHostException { | |
| 247 | + initstr (hostName, addr, ifname); | |
| 248 | + } | |
| 249 | + | |
| 250 | + /** | |
| 251 | + * Create an Inet6Address in the exact manner of {@link InetAddress#getByAddress(String,byte[])} | |
| 252 | + * except that the IPv6 scope_id is set to the value corresponding to the given interface | |
| 253 | + * for the address type specified in <code>addr</code>. | |
| 254 | + * The call will fail with an UnknownHostException if the given interface does not have a numeric | |
| 255 | + * scope_id assigned for the given address type (eg. link-local or site-local). | |
| 256 | + * See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6 | |
| 257 | + * scoped addresses. | |
| 258 | + * | |
| 259 | + * @param host the specified host | |
| 260 | + * @param addr the raw IP address in network byte order | |
| 261 | + * @param nif an interface this address must be associated with. | |
| 262 | + * @return an Inet6Address object created from the raw IP address. | |
| 263 | + * @exception UnknownHostException if IP address is of illegal length, or if the interface | |
| 264 | + * does not have a numeric scope_id assigned for the given address type. | |
| 265 | + * | |
| 266 | + * @since 1.5 | |
| 267 | + */ | |
| 268 | + | |
| 269 | + public static Inet6Address getByAddress(String host, byte[] addr, NetworkInterface nif) | |
| 270 | + throws UnknownHostException { | |
| 271 | + if (host != null && host.length() > 0 && host.charAt(0) == '[') { | |
| 272 | + if (host.charAt(host.length()-1) == ']') { | |
| 273 | + host = host.substring(1, host.length() -1); | |
| 274 | + } | |
| 275 | + } | |
| 276 | + if (addr != null) { | |
| 277 | + if (addr.length == Inet6Address.INADDRSZ) { | |
| 278 | + return new Inet6Address(host, addr, nif); | |
| 279 | + } | |
| 280 | + } | |
| 281 | + throw new UnknownHostException("addr is of illegal length"); | |
| 282 | + } | |
| 283 | + | |
| 284 | + /** | |
| 285 | + * Create an Inet6Address in the exact manner of {@link InetAddress#getByAddress(String,byte[])} | |
| 286 | + * except that the IPv6 scope_id is set to the given numeric value. | |
| 287 | + * The scope_id is not checked to determine if it corresponds to any interface on the system. | |
| 288 | + * See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6 | |
| 289 | + * scoped addresses. | |
| 290 | + * | |
| 291 | + * @param host the specified host | |
| 292 | + * @param addr the raw IP address in network byte order | |
| 293 | + * @param scope_id the numeric scope_id for the address. | |
| 294 | + * @return an Inet6Address object created from the raw IP address. | |
| 295 | + * @exception UnknownHostException if IP address is of illegal length. | |
| 296 | + * | |
| 297 | + * @since 1.5 | |
| 298 | + */ | |
| 299 | + | |
| 300 | + public static Inet6Address getByAddress(String host, byte[] addr, int scope_id) | |
| 301 | + throws UnknownHostException { | |
| 302 | + if (host != null && host.length() > 0 && host.charAt(0) == '[') { | |
| 303 | + if (host.charAt(host.length()-1) == ']') { | |
| 304 | + host = host.substring(1, host.length() -1); | |
| 305 | + } | |
| 306 | + } | |
| 307 | + if (addr != null) { | |
| 308 | + if (addr.length == Inet6Address.INADDRSZ) { | |
| 309 | + return new Inet6Address(host, addr, scope_id); | |
| 310 | + } | |
| 311 | + } | |
| 312 | + throw new UnknownHostException("addr is of illegal length"); | |
| 313 | + } | |
| 314 | + | |
| 315 | + private void initstr (String hostName, byte addr[], String ifname) throws UnknownHostException { | |
| 316 | + try { | |
| 317 | + NetworkInterface nif = NetworkInterface.getByName (ifname); | |
| 318 | + if (nif == null) { | |
| 319 | + throw new UnknownHostException ("no such interface " + ifname); | |
| 320 | + } | |
| 321 | + initif (hostName, addr, nif); | |
| 322 | + } catch (SocketException e) { | |
| 323 | + throw new UnknownHostException ("SocketException thrown" + ifname); | |
| 324 | + } | |
| 325 | + } | |
| 326 | + | |
| 327 | + private void initif(String hostName, byte addr[],NetworkInterface nif) throws UnknownHostException { | |
| 328 | + this.hostName = hostName; | |
| 329 | + if (addr.length == INADDRSZ) { // normal IPv6 address | |
| 330 | + family = IPv6; | |
| 331 | + ipaddress = addr.clone(); | |
| 332 | + } | |
| 333 | + if (nif != null) { | |
| 334 | + this.scope_ifname = nif; | |
| 335 | + scope_ifname_set = true; | |
| 336 | + scope_id = deriveNumericScope (nif); | |
| 337 | + scope_id_set = true; | |
| 338 | + } | |
| 339 | + } | |
| 340 | + | |
| 341 | + /* check the two Ipv6 addresses and return false if they are both | |
| 342 | + * non global address types, but not the same. | |
| 343 | + * (ie. one is sitelocal and the other linklocal) | |
| 344 | + * return true otherwise. | |
| 345 | + */ | |
| 346 | + private boolean differentLocalAddressTypes(Inet6Address other) { | |
| 347 | + | |
| 348 | + if (isLinkLocalAddress() && !other.isLinkLocalAddress()) { | |
| 349 | + return false; | |
| 350 | + } | |
| 351 | + if (isSiteLocalAddress() && !other.isSiteLocalAddress()) { | |
| 352 | + return false; | |
| 353 | + } | |
| 354 | + return true; | |
| 355 | + } | |
| 356 | + | |
| 357 | + private int deriveNumericScope (NetworkInterface ifc) throws UnknownHostException { | |
| 358 | + Enumeration<InetAddress> addresses = ifc.getInetAddresses(); | |
| 359 | + while (addresses.hasMoreElements()) { | |
| 360 | + InetAddress addr = addresses.nextElement(); | |
| 361 | + if (!(addr instanceof Inet6Address)) { | |
| 362 | + continue; | |
| 363 | + } | |
| 364 | + Inet6Address ia6_addr = (Inet6Address)addr; | |
| 365 | + /* check if site or link local prefixes match */ | |
| 366 | + if (!differentLocalAddressTypes(ia6_addr)){ | |
| 367 | + /* type not the same, so carry on searching */ | |
| 368 | + continue; | |
| 369 | + } | |
| 370 | + /* found a matching address - return its scope_id */ | |
| 371 | + return ia6_addr.scope_id; | |
| 372 | + } | |
| 373 | + throw new UnknownHostException ("no scope_id found"); | |
| 374 | + } | |
| 375 | + | |
| 376 | + private int deriveNumericScope (String ifname) throws UnknownHostException { | |
| 377 | + Enumeration<NetworkInterface> en; | |
| 378 | + try { | |
| 379 | + en = NetworkInterface.getNetworkInterfaces(); | |
| 380 | + } catch (SocketException e) { | |
| 381 | + throw new UnknownHostException ("could not enumerate local network interfaces"); | |
| 382 | + } | |
| 383 | + while (en.hasMoreElements()) { | |
| 384 | + NetworkInterface ifc = en.nextElement(); | |
| 385 | + if (ifc.getName().equals (ifname)) { | |
| 386 | + Enumeration addresses = ifc.getInetAddresses(); | |
| 387 | + while (addresses.hasMoreElements()) { | |
| 388 | + InetAddress addr = (InetAddress)addresses.nextElement(); | |
| 389 | + if (!(addr instanceof Inet6Address)) { | |
| 390 | + continue; | |
| 391 | + } | |
| 392 | + Inet6Address ia6_addr = (Inet6Address)addr; | |
| 393 | + /* check if site or link local prefixes match */ | |
| 394 | + if (!differentLocalAddressTypes(ia6_addr)){ | |
| 395 | + /* type not the same, so carry on searching */ | |
| 396 | + continue; | |
| 397 | + } | |
| 398 | + /* found a matching address - return its scope_id */ | |
| 399 | + return ia6_addr.scope_id; | |
| 400 | + } | |
| 401 | + } | |
| 402 | + } | |
| 403 | + throw new UnknownHostException ("No matching address found for interface : " +ifname); | |
| 404 | + } | |
| 405 | + | |
| 406 | + /** | |
| 407 | + * restore the state of this object from stream | |
| 408 | + * including the scope information, only if the | |
| 409 | + * scoped interface name is valid on this system | |
| 410 | + */ | |
| 411 | + private void readObject(ObjectInputStream s) | |
| 412 | + throws IOException, ClassNotFoundException { | |
| 413 | + scope_ifname = null; | |
| 414 | + scope_ifname_set = false; | |
| 415 | + s.defaultReadObject(); | |
| 416 | + | |
| 417 | + if (ifname != null && !"".equals (ifname)) { | |
| 418 | + try { | |
| 419 | + scope_ifname = NetworkInterface.getByName(ifname); | |
| 420 | + if (scope_ifname == null) { | |
| 421 | + /* the interface does not exist on this system, so we clear | |
| 422 | + * the scope information completely */ | |
| 423 | + scope_id_set = false; | |
| 424 | + scope_ifname_set = false; | |
| 425 | + scope_id = 0; | |
| 426 | + } else { | |
| 427 | + try { | |
| 428 | + scope_id = deriveNumericScope (scope_ifname); | |
| 429 | + } catch (UnknownHostException e) { | |
| 430 | + // typically should not happen, but it may be that | |
| 431 | + // the machine being used for deserialization has | |
| 432 | + // the same interface name but without IPv6 configured. | |
| 433 | + } | |
| 434 | + } | |
| 435 | + } catch (SocketException e) {} | |
| 436 | + | |
| 437 | + } | |
| 438 | + /* if ifname was not supplied, then the numeric info is used */ | |
| 439 | + | |
| 440 | + ipaddress = ipaddress.clone(); | |
| 441 | + | |
| 442 | + // Check that our invariants are satisfied | |
| 443 | + if (ipaddress.length != INADDRSZ) { | |
| 444 | + throw new InvalidObjectException("invalid address length: "+ | |
| 445 | + ipaddress.length); | |
| 446 | + } | |
| 447 | + | |
| 448 | + if (family != IPv6) { | |
| 449 | + throw new InvalidObjectException("invalid address family type"); | |
| 450 | + } | |
| 451 | + } | |
| 452 | + | |
| 453 | + /** | |
| 454 | + * Utility routine to check if the InetAddress is an IP multicast | |
| 455 | + * address. 11111111 at the start of the address identifies the | |
| 456 | + * address as being a multicast address. | |
| 457 | + * | |
| 458 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 459 | + * an IP multicast address | |
| 460 | + * @since JDK1.1 | |
| 461 | + */ | |
| 462 | + @Override | |
| 463 | + public boolean isMulticastAddress() { | |
| 464 | + return ((ipaddress[0] & 0xff) == 0xff); | |
| 465 | + } | |
| 466 | + | |
| 467 | + /** | |
| 468 | + * Utility routine to check if the InetAddress in a wildcard address. | |
| 469 | + * @return a <code>boolean</code> indicating if the Inetaddress is | |
| 470 | + * a wildcard address. | |
| 471 | + * @since 1.4 | |
| 472 | + */ | |
| 473 | + @Override | |
| 474 | + public boolean isAnyLocalAddress() { | |
| 475 | + byte test = 0x00; | |
| 476 | + for (int i = 0; i < INADDRSZ; i++) { | |
| 477 | + test |= ipaddress[i]; | |
| 478 | + } | |
| 479 | + return (test == 0x00); | |
| 480 | + } | |
| 481 | + | |
| 482 | + /** | |
| 483 | + * Utility routine to check if the InetAddress is a loopback address. | |
| 484 | + * | |
| 485 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 486 | + * a loopback address; or false otherwise. | |
| 487 | + * @since 1.4 | |
| 488 | + */ | |
| 489 | + @Override | |
| 490 | + public boolean isLoopbackAddress() { | |
| 491 | + byte test = 0x00; | |
| 492 | + for (int i = 0; i < 15; i++) { | |
| 493 | + test |= ipaddress[i]; | |
| 494 | + } | |
| 495 | + return (test == 0x00) && (ipaddress[15] == 0x01); | |
| 496 | + } | |
| 497 | + | |
| 498 | + /** | |
| 499 | + * Utility routine to check if the InetAddress is an link local address. | |
| 500 | + * | |
| 501 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 502 | + * a link local address; or false if address is not a link local unicast address. | |
| 503 | + * @since 1.4 | |
| 504 | + */ | |
| 505 | + @Override | |
| 506 | + public boolean isLinkLocalAddress() { | |
| 507 | + return ((ipaddress[0] & 0xff) == 0xfe | |
| 508 | + && (ipaddress[1] & 0xc0) == 0x80); | |
| 509 | + } | |
| 510 | + | |
| 511 | + /** | |
| 512 | + * Utility routine to check if the InetAddress is a site local address. | |
| 513 | + * | |
| 514 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 515 | + * a site local address; or false if address is not a site local unicast address. | |
| 516 | + * @since 1.4 | |
| 517 | + */ | |
| 518 | + @Override | |
| 519 | + public boolean isSiteLocalAddress() { | |
| 520 | + return ((ipaddress[0] & 0xff) == 0xfe | |
| 521 | + && (ipaddress[1] & 0xc0) == 0xc0); | |
| 522 | + } | |
| 523 | + | |
| 524 | + /** | |
| 525 | + * Utility routine to check if the multicast address has global scope. | |
| 526 | + * | |
| 527 | + * @return a <code>boolean</code> indicating if the address has | |
| 528 | + * is a multicast address of global scope, false if it is not | |
| 529 | + * of global scope or it is not a multicast address | |
| 530 | + * @since 1.4 | |
| 531 | + */ | |
| 532 | + @Override | |
| 533 | + public boolean isMCGlobal() { | |
| 534 | + return ((ipaddress[0] & 0xff) == 0xff | |
| 535 | + && (ipaddress[1] & 0x0f) == 0x0e); | |
| 536 | + } | |
| 537 | + | |
| 538 | + /** | |
| 539 | + * Utility routine to check if the multicast address has node scope. | |
| 540 | + * | |
| 541 | + * @return a <code>boolean</code> indicating if the address has | |
| 542 | + * is a multicast address of node-local scope, false if it is not | |
| 543 | + * of node-local scope or it is not a multicast address | |
| 544 | + * @since 1.4 | |
| 545 | + */ | |
| 546 | + @Override | |
| 547 | + public boolean isMCNodeLocal() { | |
| 548 | + return ((ipaddress[0] & 0xff) == 0xff | |
| 549 | + && (ipaddress[1] & 0x0f) == 0x01); | |
| 550 | + } | |
| 551 | + | |
| 552 | + /** | |
| 553 | + * Utility routine to check if the multicast address has link scope. | |
| 554 | + * | |
| 555 | + * @return a <code>boolean</code> indicating if the address has | |
| 556 | + * is a multicast address of link-local scope, false if it is not | |
| 557 | + * of link-local scope or it is not a multicast address | |
| 558 | + * @since 1.4 | |
| 559 | + */ | |
| 560 | + @Override | |
| 561 | + public boolean isMCLinkLocal() { | |
| 562 | + return ((ipaddress[0] & 0xff) == 0xff | |
| 563 | + && (ipaddress[1] & 0x0f) == 0x02); | |
| 564 | + } | |
| 565 | + | |
| 566 | + /** | |
| 567 | + * Utility routine to check if the multicast address has site scope. | |
| 568 | + * | |
| 569 | + * @return a <code>boolean</code> indicating if the address has | |
| 570 | + * is a multicast address of site-local scope, false if it is not | |
| 571 | + * of site-local scope or it is not a multicast address | |
| 572 | + * @since 1.4 | |
| 573 | + */ | |
| 574 | + @Override | |
| 575 | + public boolean isMCSiteLocal() { | |
| 576 | + return ((ipaddress[0] & 0xff) == 0xff | |
| 577 | + && (ipaddress[1] & 0x0f) == 0x05); | |
| 578 | + } | |
| 579 | + | |
| 580 | + /** | |
| 581 | + * Utility routine to check if the multicast address has organization scope. | |
| 582 | + * | |
| 583 | + * @return a <code>boolean</code> indicating if the address has | |
| 584 | + * is a multicast address of organization-local scope, | |
| 585 | + * false if it is not of organization-local scope | |
| 586 | + * or it is not a multicast address | |
| 587 | + * @since 1.4 | |
| 588 | + */ | |
| 589 | + @Override | |
| 590 | + public boolean isMCOrgLocal() { | |
| 591 | + return ((ipaddress[0] & 0xff) == 0xff | |
| 592 | + && (ipaddress[1] & 0x0f) == 0x08); | |
| 593 | + } | |
| 594 | + | |
| 595 | + /** | |
| 596 | + * Returns the raw IP address of this <code>InetAddress</code> | |
| 597 | + * object. The result is in network byte order: the highest order | |
| 598 | + * byte of the address is in <code>getAddress()[0]</code>. | |
| 599 | + * | |
| 600 | + * @return the raw IP address of this object. | |
| 601 | + */ | |
| 602 | + @Override | |
| 603 | + public byte[] getAddress() { | |
| 604 | + return ipaddress.clone(); | |
| 605 | + } | |
| 606 | + | |
| 607 | + /** | |
| 608 | + * Returns the numeric scopeId, if this instance is associated with | |
| 609 | + * an interface. If no scoped_id is set, the returned value is zero. | |
| 610 | + * | |
| 611 | + * @return the scopeId, or zero if not set. | |
| 612 | + * @since 1.5 | |
| 613 | + */ | |
| 614 | + public int getScopeId () { | |
| 615 | + return scope_id; | |
| 616 | + } | |
| 617 | + | |
| 618 | + /** | |
| 619 | + * Returns the scoped interface, if this instance was created with | |
| 620 | + * with a scoped interface. | |
| 621 | + * | |
| 622 | + * @return the scoped interface, or null if not set. | |
| 623 | + * @since 1.5 | |
| 624 | + */ | |
| 625 | + public NetworkInterface getScopedInterface () { | |
| 626 | + return scope_ifname; | |
| 627 | + } | |
| 628 | + | |
| 629 | + /** | |
| 630 | + * Returns the IP address string in textual presentation. If the instance was created | |
| 631 | + * specifying a scope identifier then the scope id is appended to the IP address preceded by | |
| 632 | + * a "%" (per-cent) character. This can be either a numeric value or a string, depending on which | |
| 633 | + * was used to createthe instance. | |
| 634 | + * | |
| 635 | + * @return the raw IP address in a string format. | |
| 636 | + */ | |
| 637 | + @Override | |
| 638 | + public String getHostAddress() { | |
| 639 | + String s = numericToTextFormat(ipaddress); | |
| 640 | + if (scope_ifname_set) { /* must check this first */ | |
| 641 | + s = s + "%" + scope_ifname.getName(); | |
| 642 | + } else if (scope_id_set) { | |
| 643 | + s = s + "%" + scope_id; | |
| 644 | + } | |
| 645 | + return s; | |
| 646 | + } | |
| 647 | + | |
| 648 | + /** | |
| 649 | + * Returns a hashcode for this IP address. | |
| 650 | + * | |
| 651 | + * @return a hash code value for this IP address. | |
| 652 | + */ | |
| 653 | + @Override | |
| 654 | + public int hashCode() { | |
| 655 | + if (ipaddress != null) { | |
| 656 | + | |
| 657 | + int hash = 0; | |
| 658 | + int i=0; | |
| 659 | + while (i<INADDRSZ) { | |
| 660 | + int j=0; | |
| 661 | + int component=0; | |
| 662 | + while (j<4 && i<INADDRSZ) { | |
| 663 | + component = (component << 8) + ipaddress[i]; | |
| 664 | + j++; | |
| 665 | + i++; | |
| 666 | + } | |
| 667 | + hash += component; | |
| 668 | + } | |
| 669 | + return hash; | |
| 670 | + | |
| 671 | + } else { | |
| 672 | + return 0; | |
| 673 | + } | |
| 674 | + } | |
| 675 | + | |
| 676 | + /** | |
| 677 | + * Compares this object against the specified object. | |
| 678 | + * The result is <code>true</code> if and only if the argument is | |
| 679 | + * not <code>null</code> and it represents the same IP address as | |
| 680 | + * this object. | |
| 681 | + * <p> | |
| 682 | + * Two instances of <code>InetAddress</code> represent the same IP | |
| 683 | + * address if the length of the byte arrays returned by | |
| 684 | + * <code>getAddress</code> is the same for both, and each of the | |
| 685 | + * array components is the same for the byte arrays. | |
| 686 | + * | |
| 687 | + * @param obj the object to compare against. | |
| 688 | + * @return <code>true</code> if the objects are the same; | |
| 689 | + * <code>false</code> otherwise. | |
| 690 | + * @see java.net.InetAddress#getAddress() | |
| 691 | + */ | |
| 692 | + @Override | |
| 693 | + public boolean equals(Object obj) { | |
| 694 | + if (obj == null || | |
| 695 | + !(obj instanceof Inet6Address)) | |
| 696 | + return false; | |
| 697 | + | |
| 698 | + Inet6Address inetAddr = (Inet6Address)obj; | |
| 699 | + | |
| 700 | + for (int i = 0; i < INADDRSZ; i++) { | |
| 701 | + if (ipaddress[i] != inetAddr.ipaddress[i]) | |
| 702 | + return false; | |
| 703 | + } | |
| 704 | + | |
| 705 | + return true; | |
| 706 | + } | |
| 707 | + | |
| 708 | + /** | |
| 709 | + * Utility routine to check if the InetAddress is an | |
| 710 | + * IPv4 compatible IPv6 address. | |
| 711 | + * | |
| 712 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 713 | + * an IPv4 compatible IPv6 address; or false if address is IPv4 address. | |
| 714 | + * @since 1.4 | |
| 715 | + */ | |
| 716 | + public boolean isIPv4CompatibleAddress() { | |
| 717 | + if ((ipaddress[0] == 0x00) && (ipaddress[1] == 0x00) && | |
| 718 | + (ipaddress[2] == 0x00) && (ipaddress[3] == 0x00) && | |
| 719 | + (ipaddress[4] == 0x00) && (ipaddress[5] == 0x00) && | |
| 720 | + (ipaddress[6] == 0x00) && (ipaddress[7] == 0x00) && | |
| 721 | + (ipaddress[8] == 0x00) && (ipaddress[9] == 0x00) && | |
| 722 | + (ipaddress[10] == 0x00) && (ipaddress[11] == 0x00)) { | |
| 723 | + return true; | |
| 724 | + } | |
| 725 | + return false; | |
| 726 | + } | |
| 727 | + | |
| 728 | + // Utilities | |
| 729 | + private final static int INT16SZ = 2; | |
| 730 | + /* | |
| 731 | + * Convert IPv6 binary address into presentation (printable) format. | |
| 732 | + * | |
| 733 | + * @param src a byte array representing the IPv6 numeric address | |
| 734 | + * @return a String representing an IPv6 address in | |
| 735 | + * textual representation format | |
| 736 | + * @since 1.4 | |
| 737 | + */ | |
| 738 | + static String numericToTextFormat(byte[] src) | |
| 739 | + { | |
| 740 | + StringBuffer sb = new StringBuffer(39); | |
| 741 | + for (int i = 0; i < (INADDRSZ / INT16SZ); i++) { | |
| 742 | + sb.append(Integer.toHexString(((src[i<<1]<<8) & 0xff00) | |
| 743 | + | (src[(i<<1)+1] & 0xff))); | |
| 744 | + if (i < (INADDRSZ / INT16SZ) -1 ) { | |
| 745 | + sb.append(":"); | |
| 746 | + } | |
| 747 | + } | |
| 748 | + return sb.toString(); | |
| 749 | + } | |
| 750 | + | |
| 751 | + /** | |
| 752 | + * Perform class load-time initializations. | |
| 753 | + */ | |
| 754 | + private static native void init(); | |
| 755 | + | |
| 756 | + /** | |
| 757 | + * Following field is only used during (de)/serialization | |
| 758 | + */ | |
| 759 | + private String ifname; | |
| 760 | + | |
| 761 | + /** | |
| 762 | + * default behavior is overridden in order to write the | |
| 763 | + * scope_ifname field as a String, rather than a NetworkInterface | |
| 764 | + * which is not serializable | |
| 765 | + */ | |
| 766 | + private synchronized void writeObject(java.io.ObjectOutputStream s) | |
| 767 | + throws IOException | |
| 768 | + { | |
| 769 | + if (scope_ifname_set) { | |
| 770 | + ifname = scope_ifname.getName(); | |
| 771 | + } | |
| 772 | + s.defaultWriteObject(); | |
| 773 | + } | |
| 774 | +} | |
Binary file not shown.
| @@ -0,0 +1,108 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2002, 2005, 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 | +package java.net; | |
| 26 | +import java.io.IOException; | |
| 27 | + | |
| 28 | +/* | |
| 29 | + * Package private implementation of InetAddressImpl for dual | |
| 30 | + * IPv4/IPv6 stack. | |
| 31 | + * <p> | |
| 32 | + * If InetAddress.preferIPv6Address is true then anyLocalAddress(), | |
| 33 | + * loopbackAddress(), and localHost() will return IPv6 addresses, | |
| 34 | + * otherwise IPv4 addresses. | |
| 35 | + * | |
| 36 | + * @since 1.4 | |
| 37 | + */ | |
| 38 | + | |
| 39 | +class Inet6AddressImpl implements InetAddressImpl { | |
| 40 | + public native String getLocalHostName() throws UnknownHostException; | |
| 41 | + public native InetAddress[] | |
| 42 | + lookupAllHostAddr(String hostname) throws UnknownHostException; | |
| 43 | + public native String getHostByAddr(byte[] addr) throws UnknownHostException; | |
| 44 | + private native boolean isReachable0(byte[] addr, int scope, int timeout, byte[] inf, int ttl, int if_scope) throws IOException; | |
| 45 | + | |
| 46 | + public boolean isReachable(InetAddress addr, int timeout, NetworkInterface netif, int ttl) throws IOException { | |
| 47 | + byte[] ifaddr = null; | |
| 48 | + int scope = -1; | |
| 49 | + int netif_scope = -1; | |
| 50 | + if (netif != null) { | |
| 51 | + /* | |
| 52 | + * Let's make sure we bind to an address of the proper family. | |
| 53 | + * Which means same family as addr because at this point it could | |
| 54 | + * be either an IPv6 address or an IPv4 address (case of a dual | |
| 55 | + * stack system). | |
| 56 | + */ | |
| 57 | + java.util.Enumeration it = netif.getInetAddresses(); | |
| 58 | + InetAddress inetaddr = null; | |
| 59 | + while (it.hasMoreElements()) { | |
| 60 | + inetaddr = (InetAddress) it.nextElement(); | |
| 61 | + if (inetaddr.getClass().isInstance(addr)) { | |
| 62 | + ifaddr = inetaddr.getAddress(); | |
| 63 | + if (inetaddr instanceof Inet6Address) { | |
| 64 | + netif_scope = ((Inet6Address) inetaddr).getScopeId(); | |
| 65 | + } | |
| 66 | + break; | |
| 67 | + } | |
| 68 | + } | |
| 69 | + if (ifaddr == null) { | |
| 70 | + // Interface doesn't support the address family of | |
| 71 | + // the destination | |
| 72 | + return false; | |
| 73 | + } | |
| 74 | + } | |
| 75 | + if (addr instanceof Inet6Address) | |
| 76 | + scope = ((Inet6Address) addr).getScopeId(); | |
| 77 | + return isReachable0(addr.getAddress(), scope, timeout, ifaddr, ttl, netif_scope); | |
| 78 | + } | |
| 79 | + | |
| 80 | + public synchronized InetAddress anyLocalAddress() { | |
| 81 | + if (anyLocalAddress == null) { | |
| 82 | + if (InetAddress.preferIPv6Address) { | |
| 83 | + anyLocalAddress = new Inet6Address(); | |
| 84 | + anyLocalAddress.hostName = "::"; | |
| 85 | + } else { | |
| 86 | + anyLocalAddress = (new Inet4AddressImpl()).anyLocalAddress(); | |
| 87 | + } | |
| 88 | + } | |
| 89 | + return anyLocalAddress; | |
| 90 | + } | |
| 91 | + | |
| 92 | + public synchronized InetAddress loopbackAddress() { | |
| 93 | + if (loopbackAddress == null) { | |
| 94 | + if (InetAddress.preferIPv6Address) { | |
| 95 | + byte[] loopback = | |
| 96 | + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 97 | + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; | |
| 98 | + loopbackAddress = new Inet6Address("localhost", loopback); | |
| 99 | + } else { | |
| 100 | + loopbackAddress = (new Inet4AddressImpl()).loopbackAddress(); | |
| 101 | + } | |
| 102 | + } | |
| 103 | + return loopbackAddress; | |
| 104 | + } | |
| 105 | + | |
| 106 | + private InetAddress anyLocalAddress; | |
| 107 | + private InetAddress loopbackAddress; | |
| 108 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,1540 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2011, 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 java.net; | |
| 27 | + | |
| 28 | +import java.util.HashMap; | |
| 29 | +import java.util.LinkedHashMap; | |
| 30 | +import java.util.Random; | |
| 31 | +import java.util.Iterator; | |
| 32 | +import java.util.LinkedList; | |
| 33 | +import java.util.List; | |
| 34 | +import java.util.ArrayList; | |
| 35 | +import java.security.AccessController; | |
| 36 | +import java.io.ObjectStreamException; | |
| 37 | +import java.io.IOException; | |
| 38 | +import java.io.ObjectInputStream; | |
| 39 | +import sun.security.action.*; | |
| 40 | +import sun.net.InetAddressCachePolicy; | |
| 41 | +import sun.net.util.IPAddressUtil; | |
| 42 | +import sun.misc.Service; | |
| 43 | +import sun.net.spi.nameservice.*; | |
| 44 | + | |
| 45 | +/** | |
| 46 | + * This class represents an Internet Protocol (IP) address. | |
| 47 | + * | |
| 48 | + * <p> An IP address is either a 32-bit or 128-bit unsigned number | |
| 49 | + * used by IP, a lower-level protocol on which protocols like UDP and | |
| 50 | + * TCP are built. The IP address architecture is defined by <a | |
| 51 | + * href="http://www.ietf.org/rfc/rfc790.txt"><i>RFC 790: | |
| 52 | + * Assigned Numbers</i></a>, <a | |
| 53 | + * href="http://www.ietf.org/rfc/rfc1918.txt"> <i>RFC 1918: | |
| 54 | + * Address Allocation for Private Internets</i></a>, <a | |
| 55 | + * href="http://www.ietf.org/rfc/rfc2365.txt"><i>RFC 2365: | |
| 56 | + * Administratively Scoped IP Multicast</i></a>, and <a | |
| 57 | + * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC 2373: IP | |
| 58 | + * Version 6 Addressing Architecture</i></a>. An instance of an | |
| 59 | + * InetAddress consists of an IP address and possibly its | |
| 60 | + * corresponding host name (depending on whether it is constructed | |
| 61 | + * with a host name or whether it has already done reverse host name | |
| 62 | + * resolution). | |
| 63 | + * | |
| 64 | + * <h4> Address types </h4> | |
| 65 | + * | |
| 66 | + * <blockquote><table cellspacing=2 summary="Description of unicast and multicast address types"> | |
| 67 | + * <tr><th valign=top><i>unicast</i></th> | |
| 68 | + * <td>An identifier for a single interface. A packet sent to | |
| 69 | + * a unicast address is delivered to the interface identified by | |
| 70 | + * that address. | |
| 71 | + * | |
| 72 | + * <p> The Unspecified Address -- Also called anylocal or wildcard | |
| 73 | + * address. It must never be assigned to any node. It indicates the | |
| 74 | + * absence of an address. One example of its use is as the target of | |
| 75 | + * bind, which allows a server to accept a client connection on any | |
| 76 | + * interface, in case the server host has multiple interfaces. | |
| 77 | + * | |
| 78 | + * <p> The <i>unspecified</i> address must not be used as | |
| 79 | + * the destination address of an IP packet. | |
| 80 | + * | |
| 81 | + * <p> The <i>Loopback</i> Addresses -- This is the address | |
| 82 | + * assigned to the loopback interface. Anything sent to this | |
| 83 | + * IP address loops around and becomes IP input on the local | |
| 84 | + * host. This address is often used when testing a | |
| 85 | + * client.</td></tr> | |
| 86 | + * <tr><th valign=top><i>multicast</i></th> | |
| 87 | + * <td>An identifier for a set of interfaces (typically belonging | |
| 88 | + * to different nodes). A packet sent to a multicast address is | |
| 89 | + * delivered to all interfaces identified by that address.</td></tr> | |
| 90 | + * </table></blockquote> | |
| 91 | + * | |
| 92 | + * <h4> IP address scope </h4> | |
| 93 | + * | |
| 94 | + * <p> <i>Link-local</i> addresses are designed to be used for addressing | |
| 95 | + * on a single link for purposes such as auto-address configuration, | |
| 96 | + * neighbor discovery, or when no routers are present. | |
| 97 | + * | |
| 98 | + * <p> <i>Site-local</i> addresses are designed to be used for addressing | |
| 99 | + * inside of a site without the need for a global prefix. | |
| 100 | + * | |
| 101 | + * <p> <i>Global</i> addresses are unique across the internet. | |
| 102 | + * | |
| 103 | + * <h4> Textual representation of IP addresses </h4> | |
| 104 | + * | |
| 105 | + * The textual representation of an IP address is address family specific. | |
| 106 | + * | |
| 107 | + * <p> | |
| 108 | + * | |
| 109 | + * For IPv4 address format, please refer to <A | |
| 110 | + * HREF="Inet4Address.html#format">Inet4Address#format</A>; For IPv6 | |
| 111 | + * address format, please refer to <A | |
| 112 | + * HREF="Inet6Address.html#format">Inet6Address#format</A>. | |
| 113 | + * | |
| 114 | + * <P>There is a <a href="doc-files/net-properties.html#Ipv4IPv6">couple of | |
| 115 | + * System Properties</a> affecting how IPv4 and IPv6 addresses are used.</P> | |
| 116 | + * | |
| 117 | + * <h4> Host Name Resolution </h4> | |
| 118 | + * | |
| 119 | + * Host name-to-IP address <i>resolution</i> is accomplished through | |
| 120 | + * the use of a combination of local machine configuration information | |
| 121 | + * and network naming services such as the Domain Name System (DNS) | |
| 122 | + * and Network Information Service(NIS). The particular naming | |
| 123 | + * services(s) being used is by default the local machine configured | |
| 124 | + * one. For any host name, its corresponding IP address is returned. | |
| 125 | + * | |
| 126 | + * <p> <i>Reverse name resolution</i> means that for any IP address, | |
| 127 | + * the host associated with the IP address is returned. | |
| 128 | + * | |
| 129 | + * <p> The InetAddress class provides methods to resolve host names to | |
| 130 | + * their IP addresses and vice versa. | |
| 131 | + * | |
| 132 | + * <h4> InetAddress Caching </h4> | |
| 133 | + * | |
| 134 | + * The InetAddress class has a cache to store successful as well as | |
| 135 | + * unsuccessful host name resolutions. | |
| 136 | + * | |
| 137 | + * <p> By default, when a security manager is installed, in order to | |
| 138 | + * protect against DNS spoofing attacks, | |
| 139 | + * the result of positive host name resolutions are | |
| 140 | + * cached forever. When a security manager is not installed, the default | |
| 141 | + * behavior is to cache entries for a finite (implementation dependent) | |
| 142 | + * period of time. The result of unsuccessful host | |
| 143 | + * name resolution is cached for a very short period of time (10 | |
| 144 | + * seconds) to improve performance. | |
| 145 | + * | |
| 146 | + * <p> If the default behavior is not desired, then a Java security property | |
| 147 | + * can be set to a different Time-to-live (TTL) value for positive | |
| 148 | + * caching. Likewise, a system admin can configure a different | |
| 149 | + * negative caching TTL value when needed. | |
| 150 | + * | |
| 151 | + * <p> Two Java security properties control the TTL values used for | |
| 152 | + * positive and negative host name resolution caching: | |
| 153 | + * | |
| 154 | + * <blockquote> | |
| 155 | + * <dl> | |
| 156 | + * <dt><b>networkaddress.cache.ttl</b></dt> | |
| 157 | + * <dd>Indicates the caching policy for successful name lookups from | |
| 158 | + * the name service. The value is specified as as integer to indicate | |
| 159 | + * the number of seconds to cache the successful lookup. The default | |
| 160 | + * setting is to cache for an implementation specific period of time. | |
| 161 | + * <p> | |
| 162 | + * A value of -1 indicates "cache forever". | |
| 163 | + * </dd> | |
| 164 | + * <p> | |
| 165 | + * <dt><b>networkaddress.cache.negative.ttl</b> (default: 10)</dt> | |
| 166 | + * <dd>Indicates the caching policy for un-successful name lookups | |
| 167 | + * from the name service. The value is specified as as integer to | |
| 168 | + * indicate the number of seconds to cache the failure for | |
| 169 | + * un-successful lookups. | |
| 170 | + * <p> | |
| 171 | + * A value of 0 indicates "never cache". | |
| 172 | + * A value of -1 indicates "cache forever". | |
| 173 | + * </dd> | |
| 174 | + * </dl> | |
| 175 | + * </blockquote> | |
| 176 | + * | |
| 177 | + * @author Chris Warth | |
| 178 | + * @see java.net.InetAddress#getByAddress(byte[]) | |
| 179 | + * @see java.net.InetAddress#getByAddress(java.lang.String, byte[]) | |
| 180 | + * @see java.net.InetAddress#getAllByName(java.lang.String) | |
| 181 | + * @see java.net.InetAddress#getByName(java.lang.String) | |
| 182 | + * @see java.net.InetAddress#getLocalHost() | |
| 183 | + * @since JDK1.0 | |
| 184 | + */ | |
| 185 | +public | |
| 186 | +class InetAddress implements java.io.Serializable { | |
| 187 | + /** | |
| 188 | + * Specify the address family: Internet Protocol, Version 4 | |
| 189 | + * @since 1.4 | |
| 190 | + */ | |
| 191 | + static final int IPv4 = 1; | |
| 192 | + | |
| 193 | + /** | |
| 194 | + * Specify the address family: Internet Protocol, Version 6 | |
| 195 | + * @since 1.4 | |
| 196 | + */ | |
| 197 | + static final int IPv6 = 2; | |
| 198 | + | |
| 199 | + /* Specify address family preference */ | |
| 200 | + static transient boolean preferIPv6Address = false; | |
| 201 | + | |
| 202 | + /** | |
| 203 | + * @serial | |
| 204 | + */ | |
| 205 | + String hostName; | |
| 206 | + | |
| 207 | + /** | |
| 208 | + * Holds a 32-bit IPv4 address. | |
| 209 | + * | |
| 210 | + * @serial | |
| 211 | + */ | |
| 212 | + int address; | |
| 213 | + | |
| 214 | + /** | |
| 215 | + * Specifies the address family type, for instance, '1' for IPv4 | |
| 216 | + * addresses, and '2' for IPv6 addresses. | |
| 217 | + * | |
| 218 | + * @serial | |
| 219 | + */ | |
| 220 | + int family; | |
| 221 | + | |
| 222 | + /* Used to store the name service provider */ | |
| 223 | + private static List<NameService> nameServices = null; | |
| 224 | + | |
| 225 | + /* Used to store the best available hostname */ | |
| 226 | + private transient String canonicalHostName = null; | |
| 227 | + | |
| 228 | + /** use serialVersionUID from JDK 1.0.2 for interoperability */ | |
| 229 | + private static final long serialVersionUID = 3286316764910316507L; | |
| 230 | + | |
| 231 | + /* | |
| 232 | + * Load net library into runtime, and perform initializations. | |
| 233 | + */ | |
| 234 | + static { | |
| 235 | + preferIPv6Address = java.security.AccessController.doPrivileged( | |
| 236 | + new GetBooleanAction("java.net.preferIPv6Addresses")).booleanValue(); | |
| 237 | + AccessController.doPrivileged(new LoadLibraryAction("net")); | |
| 238 | + init(); | |
| 239 | + } | |
| 240 | + | |
| 241 | + /** | |
| 242 | + * Constructor for the Socket.accept() method. | |
| 243 | + * This creates an empty InetAddress, which is filled in by | |
| 244 | + * the accept() method. This InetAddress, however, is not | |
| 245 | + * put in the address cache, since it is not created by name. | |
| 246 | + */ | |
| 247 | + InetAddress() { | |
| 248 | + } | |
| 249 | + | |
| 250 | + /** | |
| 251 | + * Replaces the de-serialized object with an Inet4Address object. | |
| 252 | + * | |
| 253 | + * @return the alternate object to the de-serialized object. | |
| 254 | + * | |
| 255 | + * @throws ObjectStreamException if a new object replacing this | |
| 256 | + * object could not be created | |
| 257 | + */ | |
| 258 | + private Object readResolve() throws ObjectStreamException { | |
| 259 | + // will replace the deserialized 'this' object | |
| 260 | + return new Inet4Address(this.hostName, this.address); | |
| 261 | + } | |
| 262 | + | |
| 263 | + /** | |
| 264 | + * Utility routine to check if the InetAddress is an | |
| 265 | + * IP multicast address. | |
| 266 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 267 | + * an IP multicast address | |
| 268 | + * @since JDK1.1 | |
| 269 | + */ | |
| 270 | + public boolean isMulticastAddress() { | |
| 271 | + return false; | |
| 272 | + } | |
| 273 | + | |
| 274 | + /** | |
| 275 | + * Utility routine to check if the InetAddress in a wildcard address. | |
| 276 | + * @return a <code>boolean</code> indicating if the Inetaddress is | |
| 277 | + * a wildcard address. | |
| 278 | + * @since 1.4 | |
| 279 | + */ | |
| 280 | + public boolean isAnyLocalAddress() { | |
| 281 | + return false; | |
| 282 | + } | |
| 283 | + | |
| 284 | + /** | |
| 285 | + * Utility routine to check if the InetAddress is a loopback address. | |
| 286 | + * | |
| 287 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 288 | + * a loopback address; or false otherwise. | |
| 289 | + * @since 1.4 | |
| 290 | + */ | |
| 291 | + public boolean isLoopbackAddress() { | |
| 292 | + return false; | |
| 293 | + } | |
| 294 | + | |
| 295 | + /** | |
| 296 | + * Utility routine to check if the InetAddress is an link local address. | |
| 297 | + * | |
| 298 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 299 | + * a link local address; or false if address is not a link local unicast address. | |
| 300 | + * @since 1.4 | |
| 301 | + */ | |
| 302 | + public boolean isLinkLocalAddress() { | |
| 303 | + return false; | |
| 304 | + } | |
| 305 | + | |
| 306 | + /** | |
| 307 | + * Utility routine to check if the InetAddress is a site local address. | |
| 308 | + * | |
| 309 | + * @return a <code>boolean</code> indicating if the InetAddress is | |
| 310 | + * a site local address; or false if address is not a site local unicast address. | |
| 311 | + * @since 1.4 | |
| 312 | + */ | |
| 313 | + public boolean isSiteLocalAddress() { | |
| 314 | + return false; | |
| 315 | + } | |
| 316 | + | |
| 317 | + /** | |
| 318 | + * Utility routine to check if the multicast address has global scope. | |
| 319 | + * | |
| 320 | + * @return a <code>boolean</code> indicating if the address has | |
| 321 | + * is a multicast address of global scope, false if it is not | |
| 322 | + * of global scope or it is not a multicast address | |
| 323 | + * @since 1.4 | |
| 324 | + */ | |
| 325 | + public boolean isMCGlobal() { | |
| 326 | + return false; | |
| 327 | + } | |
| 328 | + | |
| 329 | + /** | |
| 330 | + * Utility routine to check if the multicast address has node scope. | |
| 331 | + * | |
| 332 | + * @return a <code>boolean</code> indicating if the address has | |
| 333 | + * is a multicast address of node-local scope, false if it is not | |
| 334 | + * of node-local scope or it is not a multicast address | |
| 335 | + * @since 1.4 | |
| 336 | + */ | |
| 337 | + public boolean isMCNodeLocal() { | |
| 338 | + return false; | |
| 339 | + } | |
| 340 | + | |
| 341 | + /** | |
| 342 | + * Utility routine to check if the multicast address has link scope. | |
| 343 | + * | |
| 344 | + * @return a <code>boolean</code> indicating if the address has | |
| 345 | + * is a multicast address of link-local scope, false if it is not | |
| 346 | + * of link-local scope or it is not a multicast address | |
| 347 | + * @since 1.4 | |
| 348 | + */ | |
| 349 | + public boolean isMCLinkLocal() { | |
| 350 | + return false; | |
| 351 | + } | |
| 352 | + | |
| 353 | + /** | |
| 354 | + * Utility routine to check if the multicast address has site scope. | |
| 355 | + * | |
| 356 | + * @return a <code>boolean</code> indicating if the address has | |
| 357 | + * is a multicast address of site-local scope, false if it is not | |
| 358 | + * of site-local scope or it is not a multicast address | |
| 359 | + * @since 1.4 | |
| 360 | + */ | |
| 361 | + public boolean isMCSiteLocal() { | |
| 362 | + return false; | |
| 363 | + } | |
| 364 | + | |
| 365 | + /** | |
| 366 | + * Utility routine to check if the multicast address has organization scope. | |
| 367 | + * | |
| 368 | + * @return a <code>boolean</code> indicating if the address has | |
| 369 | + * is a multicast address of organization-local scope, | |
| 370 | + * false if it is not of organization-local scope | |
| 371 | + * or it is not a multicast address | |
| 372 | + * @since 1.4 | |
| 373 | + */ | |
| 374 | + public boolean isMCOrgLocal() { | |
| 375 | + return false; | |
| 376 | + } | |
| 377 | + | |
| 378 | + | |
| 379 | + /** | |
| 380 | + * Test whether that address is reachable. Best effort is made by the | |
| 381 | + * implementation to try to reach the host, but firewalls and server | |
| 382 | + * configuration may block requests resulting in a unreachable status | |
| 383 | + * while some specific ports may be accessible. | |
| 384 | + * A typical implementation will use ICMP ECHO REQUESTs if the | |
| 385 | + * privilege can be obtained, otherwise it will try to establish | |
| 386 | + * a TCP connection on port 7 (Echo) of the destination host. | |
| 387 | + * <p> | |
| 388 | + * The timeout value, in milliseconds, indicates the maximum amount of time | |
| 389 | + * the try should take. If the operation times out before getting an | |
| 390 | + * answer, the host is deemed unreachable. A negative value will result | |
| 391 | + * in an IllegalArgumentException being thrown. | |
| 392 | + * | |
| 393 | + * @param timeout the time, in milliseconds, before the call aborts | |
| 394 | + * @return a <code>boolean</code> indicating if the address is reachable. | |
| 395 | + * @throws IOException if a network error occurs | |
| 396 | + * @throws IllegalArgumentException if <code>timeout</code> is negative. | |
| 397 | + * @since 1.5 | |
| 398 | + */ | |
| 399 | + public boolean isReachable(int timeout) throws IOException { | |
| 400 | + return isReachable(null, 0 , timeout); | |
| 401 | + } | |
| 402 | + | |
| 403 | + /** | |
| 404 | + * Test whether that address is reachable. Best effort is made by the | |
| 405 | + * implementation to try to reach the host, but firewalls and server | |
| 406 | + * configuration may block requests resulting in a unreachable status | |
| 407 | + * while some specific ports may be accessible. | |
| 408 | + * A typical implementation will use ICMP ECHO REQUESTs if the | |
| 409 | + * privilege can be obtained, otherwise it will try to establish | |
| 410 | + * a TCP connection on port 7 (Echo) of the destination host. | |
| 411 | + * <p> | |
| 412 | + * The <code>network interface</code> and <code>ttl</code> parameters | |
| 413 | + * let the caller specify which network interface the test will go through | |
| 414 | + * and the maximum number of hops the packets should go through. | |
| 415 | + * A negative value for the <code>ttl</code> will result in an | |
| 416 | + * IllegalArgumentException being thrown. | |
| 417 | + * <p> | |
| 418 | + * The timeout value, in milliseconds, indicates the maximum amount of time | |
| 419 | + * the try should take. If the operation times out before getting an | |
| 420 | + * answer, the host is deemed unreachable. A negative value will result | |
| 421 | + * in an IllegalArgumentException being thrown. | |
| 422 | + * | |
| 423 | + * @param netif the NetworkInterface through which the | |
| 424 | + * test will be done, or null for any interface | |
| 425 | + * @param ttl the maximum numbers of hops to try or 0 for the | |
| 426 | + * default | |
| 427 | + * @param timeout the time, in milliseconds, before the call aborts | |
| 428 | + * @throws IllegalArgumentException if either <code>timeout</code> | |
| 429 | + * or <code>ttl</code> are negative. | |
| 430 | + * @return a <code>boolean</code>indicating if the address is reachable. | |
| 431 | + * @throws IOException if a network error occurs | |
| 432 | + * @since 1.5 | |
| 433 | + */ | |
| 434 | + public boolean isReachable(NetworkInterface netif, int ttl, | |
| 435 | + int timeout) throws IOException { | |
| 436 | + if (ttl < 0) | |
| 437 | + throw new IllegalArgumentException("ttl can't be negative"); | |
| 438 | + if (timeout < 0) | |
| 439 | + throw new IllegalArgumentException("timeout can't be negative"); | |
| 440 | + | |
| 441 | + return impl.isReachable(this, timeout, netif, ttl); | |
| 442 | + } | |
| 443 | + | |
| 444 | + /** | |
| 445 | + * Gets the host name for this IP address. | |
| 446 | + * | |
| 447 | + * <p>If this InetAddress was created with a host name, | |
| 448 | + * this host name will be remembered and returned; | |
| 449 | + * otherwise, a reverse name lookup will be performed | |
| 450 | + * and the result will be returned based on the system | |
| 451 | + * configured name lookup service. If a lookup of the name service | |
| 452 | + * is required, call | |
| 453 | + * {@link #getCanonicalHostName() getCanonicalHostName}. | |
| 454 | + * | |
| 455 | + * <p>If there is a security manager, its | |
| 456 | + * <code>checkConnect</code> method is first called | |
| 457 | + * with the hostname and <code>-1</code> | |
| 458 | + * as its arguments to see if the operation is allowed. | |
| 459 | + * If the operation is not allowed, it will return | |
| 460 | + * the textual representation of the IP address. | |
| 461 | + * | |
| 462 | + * @return the host name for this IP address, or if the operation | |
| 463 | + * is not allowed by the security check, the textual | |
| 464 | + * representation of the IP address. | |
| 465 | + * | |
| 466 | + * @see InetAddress#getCanonicalHostName | |
| 467 | + * @see SecurityManager#checkConnect | |
| 468 | + */ | |
| 469 | + public String getHostName() { | |
| 470 | + return getHostName(true); | |
| 471 | + } | |
| 472 | + | |
| 473 | + /** | |
| 474 | + * Returns the hostname for this address. | |
| 475 | + * If the host is equal to null, then this address refers to any | |
| 476 | + * of the local machine's available network addresses. | |
| 477 | + * this is package private so SocketPermission can make calls into | |
| 478 | + * here without a security check. | |
| 479 | + * | |
| 480 | + * <p>If there is a security manager, this method first | |
| 481 | + * calls its <code>checkConnect</code> method | |
| 482 | + * with the hostname and <code>-1</code> | |
| 483 | + * as its arguments to see if the calling code is allowed to know | |
| 484 | + * the hostname for this IP address, i.e., to connect to the host. | |
| 485 | + * If the operation is not allowed, it will return | |
| 486 | + * the textual representation of the IP address. | |
| 487 | + * | |
| 488 | + * @return the host name for this IP address, or if the operation | |
| 489 | + * is not allowed by the security check, the textual | |
| 490 | + * representation of the IP address. | |
| 491 | + * | |
| 492 | + * @param check make security check if true | |
| 493 | + * | |
| 494 | + * @see SecurityManager#checkConnect | |
| 495 | + */ | |
| 496 | + String getHostName(boolean check) { | |
| 497 | + if (hostName == null) { | |
| 498 | + hostName = InetAddress.getHostFromNameService(this, check); | |
| 499 | + } | |
| 500 | + return hostName; | |
| 501 | + } | |
| 502 | + | |
| 503 | + /** | |
| 504 | + * Gets the fully qualified domain name for this IP address. | |
| 505 | + * Best effort method, meaning we may not be able to return | |
| 506 | + * the FQDN depending on the underlying system configuration. | |
| 507 | + * | |
| 508 | + * <p>If there is a security manager, this method first | |
| 509 | + * calls its <code>checkConnect</code> method | |
| 510 | + * with the hostname and <code>-1</code> | |
| 511 | + * as its arguments to see if the calling code is allowed to know | |
| 512 | + * the hostname for this IP address, i.e., to connect to the host. | |
| 513 | + * If the operation is not allowed, it will return | |
| 514 | + * the textual representation of the IP address. | |
| 515 | + * | |
| 516 | + * @return the fully qualified domain name for this IP address, | |
| 517 | + * or if the operation is not allowed by the security check, | |
| 518 | + * the textual representation of the IP address. | |
| 519 | + * | |
| 520 | + * @see SecurityManager#checkConnect | |
| 521 | + * | |
| 522 | + * @since 1.4 | |
| 523 | + */ | |
| 524 | + public String getCanonicalHostName() { | |
| 525 | + if (canonicalHostName == null) { | |
| 526 | + canonicalHostName = | |
| 527 | + InetAddress.getHostFromNameService(this, true); | |
| 528 | + } | |
| 529 | + return canonicalHostName; | |
| 530 | + } | |
| 531 | + | |
| 532 | + /** | |
| 533 | + * Returns the hostname for this address. | |
| 534 | + * | |
| 535 | + * <p>If there is a security manager, this method first | |
| 536 | + * calls its <code>checkConnect</code> method | |
| 537 | + * with the hostname and <code>-1</code> | |
| 538 | + * as its arguments to see if the calling code is allowed to know | |
| 539 | + * the hostname for this IP address, i.e., to connect to the host. | |
| 540 | + * If the operation is not allowed, it will return | |
| 541 | + * the textual representation of the IP address. | |
| 542 | + * | |
| 543 | + * @return the host name for this IP address, or if the operation | |
| 544 | + * is not allowed by the security check, the textual | |
| 545 | + * representation of the IP address. | |
| 546 | + * | |
| 547 | + * @param check make security check if true | |
| 548 | + * | |
| 549 | + * @see SecurityManager#checkConnect | |
| 550 | + */ | |
| 551 | + private static String getHostFromNameService(InetAddress addr, boolean check) { | |
| 552 | + String host = null; | |
| 553 | + for (NameService nameService : nameServices) { | |
| 554 | + try { | |
| 555 | + // first lookup the hostname | |
| 556 | + host = nameService.getHostByAddr(addr.getAddress()); | |
| 557 | + | |
| 558 | + /* check to see if calling code is allowed to know | |
| 559 | + * the hostname for this IP address, ie, connect to the host | |
| 560 | + */ | |
| 561 | + if (check) { | |
| 562 | + SecurityManager sec = System.getSecurityManager(); | |
| 563 | + if (sec != null) { | |
| 564 | + sec.checkConnect(host, -1); | |
| 565 | + } | |
| 566 | + } | |
| 567 | + | |
| 568 | + /* now get all the IP addresses for this hostname, | |
| 569 | + * and make sure one of them matches the original IP | |
| 570 | + * address. We do this to try and prevent spoofing. | |
| 571 | + */ | |
| 572 | + | |
| 573 | + InetAddress[] arr = InetAddress.getAllByName0(host, check); | |
| 574 | + boolean ok = false; | |
| 575 | + | |
| 576 | + if(arr != null) { | |
| 577 | + for(int i = 0; !ok && i < arr.length; i++) { | |
| 578 | + ok = addr.equals(arr[i]); | |
| 579 | + } | |
| 580 | + } | |
| 581 | + | |
| 582 | + //XXX: if it looks a spoof just return the address? | |
| 583 | + if (!ok) { | |
| 584 | + host = addr.getHostAddress(); | |
| 585 | + return host; | |
| 586 | + } | |
| 587 | + | |
| 588 | + break; | |
| 589 | + | |
| 590 | + } catch (SecurityException e) { | |
| 591 | + host = addr.getHostAddress(); | |
| 592 | + break; | |
| 593 | + } catch (UnknownHostException e) { | |
| 594 | + host = addr.getHostAddress(); | |
| 595 | + // let next provider resolve the hostname | |
| 596 | + } | |
| 597 | + } | |
| 598 | + | |
| 599 | + return host; | |
| 600 | + } | |
| 601 | + | |
| 602 | + /** | |
| 603 | + * Returns the raw IP address of this <code>InetAddress</code> | |
| 604 | + * object. The result is in network byte order: the highest order | |
| 605 | + * byte of the address is in <code>getAddress()[0]</code>. | |
| 606 | + * | |
| 607 | + * @return the raw IP address of this object. | |
| 608 | + */ | |
| 609 | + public byte[] getAddress() { | |
| 610 | + return null; | |
| 611 | + } | |
| 612 | + | |
| 613 | + /** | |
| 614 | + * Returns the IP address string in textual presentation. | |
| 615 | + * | |
| 616 | + * @return the raw IP address in a string format. | |
| 617 | + * @since JDK1.0.2 | |
| 618 | + */ | |
| 619 | + public String getHostAddress() { | |
| 620 | + return null; | |
| 621 | + } | |
| 622 | + | |
| 623 | + /** | |
| 624 | + * Returns a hashcode for this IP address. | |
| 625 | + * | |
| 626 | + * @return a hash code value for this IP address. | |
| 627 | + */ | |
| 628 | + public int hashCode() { | |
| 629 | + return -1; | |
| 630 | + } | |
| 631 | + | |
| 632 | + /** | |
| 633 | + * Compares this object against the specified object. | |
| 634 | + * The result is <code>true</code> if and only if the argument is | |
| 635 | + * not <code>null</code> and it represents the same IP address as | |
| 636 | + * this object. | |
| 637 | + * <p> | |
| 638 | + * Two instances of <code>InetAddress</code> represent the same IP | |
| 639 | + * address if the length of the byte arrays returned by | |
| 640 | + * <code>getAddress</code> is the same for both, and each of the | |
| 641 | + * array components is the same for the byte arrays. | |
| 642 | + * | |
| 643 | + * @param obj the object to compare against. | |
| 644 | + * @return <code>true</code> if the objects are the same; | |
| 645 | + * <code>false</code> otherwise. | |
| 646 | + * @see java.net.InetAddress#getAddress() | |
| 647 | + */ | |
| 648 | + public boolean equals(Object obj) { | |
| 649 | + return false; | |
| 650 | + } | |
| 651 | + | |
| 652 | + /** | |
| 653 | + * Converts this IP address to a <code>String</code>. The | |
| 654 | + * string returned is of the form: hostname / literal IP | |
| 655 | + * address. | |
| 656 | + * | |
| 657 | + * If the host name is unresolved, no reverse name service lookup | |
| 658 | + * is performed. The hostname part will be represented by an empty string. | |
| 659 | + * | |
| 660 | + * @return a string representation of this IP address. | |
| 661 | + */ | |
| 662 | + public String toString() { | |
| 663 | + return ((hostName != null) ? hostName : "") | |
| 664 | + + "/" + getHostAddress(); | |
| 665 | + } | |
| 666 | + | |
| 667 | + /* | |
| 668 | + * Cached addresses - our own litle nis, not! | |
| 669 | + */ | |
| 670 | + private static Cache addressCache = new Cache(Cache.Type.Positive); | |
| 671 | + | |
| 672 | + private static Cache negativeCache = new Cache(Cache.Type.Negative); | |
| 673 | + | |
| 674 | + private static boolean addressCacheInit = false; | |
| 675 | + | |
| 676 | + static InetAddress[] unknown_array; // put THIS in cache | |
| 677 | + | |
| 678 | + static InetAddressImpl impl; | |
| 679 | + | |
| 680 | + private static final HashMap<String, Void> lookupTable = new HashMap<>(); | |
| 681 | + | |
| 682 | + /** | |
| 683 | + * Represents a cache entry | |
| 684 | + */ | |
| 685 | + static final class CacheEntry { | |
| 686 | + | |
| 687 | + CacheEntry(InetAddress[] addresses, long expiration) { | |
| 688 | + this.addresses = addresses; | |
| 689 | + this.expiration = expiration; | |
| 690 | + } | |
| 691 | + | |
| 692 | + InetAddress[] addresses; | |
| 693 | + long expiration; | |
| 694 | + } | |
| 695 | + | |
| 696 | + /** | |
| 697 | + * A cache that manages entries based on a policy specified | |
| 698 | + * at creation time. | |
| 699 | + */ | |
| 700 | + static final class Cache { | |
| 701 | + private LinkedHashMap<String, CacheEntry> cache; | |
| 702 | + private Type type; | |
| 703 | + | |
| 704 | + enum Type {Positive, Negative}; | |
| 705 | + | |
| 706 | + /** | |
| 707 | + * Create cache | |
| 708 | + */ | |
| 709 | + public Cache(Type type) { | |
| 710 | + this.type = type; | |
| 711 | + cache = new LinkedHashMap<String, CacheEntry>(); | |
| 712 | + } | |
| 713 | + | |
| 714 | + private int getPolicy() { | |
| 715 | + if (type == Type.Positive) { | |
| 716 | + return InetAddressCachePolicy.get(); | |
| 717 | + } else { | |
| 718 | + return InetAddressCachePolicy.getNegative(); | |
| 719 | + } | |
| 720 | + } | |
| 721 | + | |
| 722 | + /** | |
| 723 | + * Add an entry to the cache. If there's already an | |
| 724 | + * entry then for this host then the entry will be | |
| 725 | + * replaced. | |
| 726 | + */ | |
| 727 | + public Cache put(String host, InetAddress[] addresses) { | |
| 728 | + int policy = getPolicy(); | |
| 729 | + if (policy == InetAddressCachePolicy.NEVER) { | |
| 730 | + return this; | |
| 731 | + } | |
| 732 | + | |
| 733 | + // purge any expired entries | |
| 734 | + | |
| 735 | + if (policy != InetAddressCachePolicy.FOREVER) { | |
| 736 | + | |
| 737 | + // As we iterate in insertion order we can | |
| 738 | + // terminate when a non-expired entry is found. | |
| 739 | + LinkedList<String> expired = new LinkedList<>(); | |
| 740 | + long now = System.currentTimeMillis(); | |
| 741 | + for (String key : cache.keySet()) { | |
| 742 | + CacheEntry entry = cache.get(key); | |
| 743 | + | |
| 744 | + if (entry.expiration >= 0 && entry.expiration < now) { | |
| 745 | + expired.add(key); | |
| 746 | + } else { | |
| 747 | + break; | |
| 748 | + } | |
| 749 | + } | |
| 750 | + | |
| 751 | + for (String key : expired) { | |
| 752 | + cache.remove(key); | |
| 753 | + } | |
| 754 | + } | |
| 755 | + | |
| 756 | + // create new entry and add it to the cache | |
| 757 | + // -- as a HashMap replaces existing entries we | |
| 758 | + // don't need to explicitly check if there is | |
| 759 | + // already an entry for this host. | |
| 760 | + long expiration; | |
| 761 | + if (policy == InetAddressCachePolicy.FOREVER) { | |
| 762 | + expiration = -1; | |
| 763 | + } else { | |
| 764 | + expiration = System.currentTimeMillis() + (policy * 1000); | |
| 765 | + } | |
| 766 | + CacheEntry entry = new CacheEntry(addresses, expiration); | |
| 767 | + cache.put(host, entry); | |
| 768 | + return this; | |
| 769 | + } | |
| 770 | + | |
| 771 | + /** | |
| 772 | + * Query the cache for the specific host. If found then | |
| 773 | + * return its CacheEntry, or null if not found. | |
| 774 | + */ | |
| 775 | + public CacheEntry get(String host) { | |
| 776 | + int policy = getPolicy(); | |
| 777 | + if (policy == InetAddressCachePolicy.NEVER) { | |
| 778 | + return null; | |
| 779 | + } | |
| 780 | + CacheEntry entry = cache.get(host); | |
| 781 | + | |
| 782 | + // check if entry has expired | |
| 783 | + if (entry != null && policy != InetAddressCachePolicy.FOREVER) { | |
| 784 | + if (entry.expiration >= 0 && | |
| 785 | + entry.expiration < System.currentTimeMillis()) { | |
| 786 | + cache.remove(host); | |
| 787 | + entry = null; | |
| 788 | + } | |
| 789 | + } | |
| 790 | + | |
| 791 | + return entry; | |
| 792 | + } | |
| 793 | + } | |
| 794 | + | |
| 795 | + /* | |
| 796 | + * Initialize cache and insert anyLocalAddress into the | |
| 797 | + * unknown array with no expiry. | |
| 798 | + */ | |
| 799 | + private static void cacheInitIfNeeded() { | |
| 800 | + assert Thread.holdsLock(addressCache); | |
| 801 | + if (addressCacheInit) { | |
| 802 | + return; | |
| 803 | + } | |
| 804 | + unknown_array = new InetAddress[1]; | |
| 805 | + unknown_array[0] = impl.anyLocalAddress(); | |
| 806 | + | |
| 807 | + addressCache.put(impl.anyLocalAddress().getHostName(), | |
| 808 | + unknown_array); | |
| 809 | + | |
| 810 | + addressCacheInit = true; | |
| 811 | + } | |
| 812 | + | |
| 813 | + /* | |
| 814 | + * Cache the given hostname and addresses. | |
| 815 | + */ | |
| 816 | + private static void cacheAddresses(String hostname, | |
| 817 | + InetAddress[] addresses, | |
| 818 | + boolean success) { | |
| 819 | + hostname = hostname.toLowerCase(); | |
| 820 | + synchronized (addressCache) { | |
| 821 | + cacheInitIfNeeded(); | |
| 822 | + if (success) { | |
| 823 | + addressCache.put(hostname, addresses); | |
| 824 | + } else { | |
| 825 | + negativeCache.put(hostname, addresses); | |
| 826 | + } | |
| 827 | + } | |
| 828 | + } | |
| 829 | + | |
| 830 | + /* | |
| 831 | + * Lookup hostname in cache (positive & negative cache). If | |
| 832 | + * found return addresses, null if not found. | |
| 833 | + */ | |
| 834 | + private static InetAddress[] getCachedAddresses(String hostname) { | |
| 835 | + hostname = hostname.toLowerCase(); | |
| 836 | + | |
| 837 | + // search both positive & negative caches | |
| 838 | + | |
| 839 | + synchronized (addressCache) { | |
| 840 | + cacheInitIfNeeded(); | |
| 841 | + | |
| 842 | + CacheEntry entry = addressCache.get(hostname); | |
| 843 | + if (entry == null) { | |
| 844 | + entry = negativeCache.get(hostname); | |
| 845 | + } | |
| 846 | + | |
| 847 | + if (entry != null) { | |
| 848 | + return entry.addresses; | |
| 849 | + } | |
| 850 | + } | |
| 851 | + | |
| 852 | + // not found | |
| 853 | + return null; | |
| 854 | + } | |
| 855 | + | |
| 856 | + private static NameService createNSProvider(String provider) { | |
| 857 | + if (provider == null) | |
| 858 | + return null; | |
| 859 | + | |
| 860 | + NameService nameService = null; | |
| 861 | + if (provider.equals("default")) { | |
| 862 | + // initialize the default name service | |
| 863 | + nameService = new NameService() { | |
| 864 | + public InetAddress[] lookupAllHostAddr(String host) | |
| 865 | + throws UnknownHostException { | |
| 866 | + return impl.lookupAllHostAddr(host); | |
| 867 | + } | |
| 868 | + public String getHostByAddr(byte[] addr) | |
| 869 | + throws UnknownHostException { | |
| 870 | + return impl.getHostByAddr(addr); | |
| 871 | + } | |
| 872 | + }; | |
| 873 | + } else { | |
| 874 | + final String providerName = provider; | |
| 875 | + try { | |
| 876 | + nameService = java.security.AccessController.doPrivileged( | |
| 877 | + new java.security.PrivilegedExceptionAction<NameService>() { | |
| 878 | + public NameService run() { | |
| 879 | + Iterator itr = Service.providers(NameServiceDescriptor.class); | |
| 880 | + while (itr.hasNext()) { | |
| 881 | + NameServiceDescriptor nsd | |
| 882 | + = (NameServiceDescriptor)itr.next(); | |
| 883 | + if (providerName. | |
| 884 | + equalsIgnoreCase(nsd.getType()+"," | |
| 885 | + +nsd.getProviderName())) { | |
| 886 | + try { | |
| 887 | + return nsd.createNameService(); | |
| 888 | + } catch (Exception e) { | |
| 889 | + e.printStackTrace(); | |
| 890 | + System.err.println( | |
| 891 | + "Cannot create name service:" | |
| 892 | + +providerName+": " + e); | |
| 893 | + } | |
| 894 | + } | |
| 895 | + } | |
| 896 | + | |
| 897 | + return null; | |
| 898 | + } | |
| 899 | + } | |
| 900 | + ); | |
| 901 | + } catch (java.security.PrivilegedActionException e) { | |
| 902 | + } | |
| 903 | + } | |
| 904 | + | |
| 905 | + return nameService; | |
| 906 | + } | |
| 907 | + | |
| 908 | + static { | |
| 909 | + // create the impl | |
| 910 | + impl = InetAddressImplFactory.create(); | |
| 911 | + | |
| 912 | + // get name service if provided and requested | |
| 913 | + String provider = null;; | |
| 914 | + String propPrefix = "sun.net.spi.nameservice.provider."; | |
| 915 | + int n = 1; | |
| 916 | + nameServices = new ArrayList<NameService>(); | |
| 917 | + provider = AccessController.doPrivileged( | |
| 918 | + new GetPropertyAction(propPrefix + n)); | |
| 919 | + while (provider != null) { | |
| 920 | + NameService ns = createNSProvider(provider); | |
| 921 | + if (ns != null) | |
| 922 | + nameServices.add(ns); | |
| 923 | + | |
| 924 | + n++; | |
| 925 | + provider = AccessController.doPrivileged( | |
| 926 | + new GetPropertyAction(propPrefix + n)); | |
| 927 | + } | |
| 928 | + | |
| 929 | + // if not designate any name services provider, | |
| 930 | + // create a default one | |
| 931 | + if (nameServices.size() == 0) { | |
| 932 | + NameService ns = createNSProvider("default"); | |
| 933 | + nameServices.add(ns); | |
| 934 | + } | |
| 935 | + } | |
| 936 | + | |
| 937 | + /** | |
| 938 | + * Creates an InetAddress based on the provided host name and IP address. | |
| 939 | + * No name service is checked for the validity of the address. | |
| 940 | + * | |
| 941 | + * <p> The host name can either be a machine name, such as | |
| 942 | + * "<code>java.sun.com</code>", or a textual representation of its IP | |
| 943 | + * address. | |
| 944 | + * <p> No validity checking is done on the host name either. | |
| 945 | + * | |
| 946 | + * <p> If addr specifies an IPv4 address an instance of Inet4Address | |
| 947 | + * will be returned; otherwise, an instance of Inet6Address | |
| 948 | + * will be returned. | |
| 949 | + * | |
| 950 | + * <p> IPv4 address byte array must be 4 bytes long and IPv6 byte array | |
| 951 | + * must be 16 bytes long | |
| 952 | + * | |
| 953 | + * @param host the specified host | |
| 954 | + * @param addr the raw IP address in network byte order | |
| 955 | + * @return an InetAddress object created from the raw IP address. | |
| 956 | + * @exception UnknownHostException if IP address is of illegal length | |
| 957 | + * @since 1.4 | |
| 958 | + */ | |
| 959 | + public static InetAddress getByAddress(String host, byte[] addr) | |
| 960 | + throws UnknownHostException { | |
| 961 | + if (host != null && host.length() > 0 && host.charAt(0) == '[') { | |
| 962 | + if (host.charAt(host.length()-1) == ']') { | |
| 963 | + host = host.substring(1, host.length() -1); | |
| 964 | + } | |
| 965 | + } | |
| 966 | + if (addr != null) { | |
| 967 | + if (addr.length == Inet4Address.INADDRSZ) { | |
| 968 | + return new Inet4Address(host, addr); | |
| 969 | + } else if (addr.length == Inet6Address.INADDRSZ) { | |
| 970 | + byte[] newAddr | |
| 971 | + = IPAddressUtil.convertFromIPv4MappedAddress(addr); | |
| 972 | + if (newAddr != null) { | |
| 973 | + return new Inet4Address(host, newAddr); | |
| 974 | + } else { | |
| 975 | + return new Inet6Address(host, addr); | |
| 976 | + } | |
| 977 | + } | |
| 978 | + } | |
| 979 | + throw new UnknownHostException("addr is of illegal length"); | |
| 980 | + } | |
| 981 | + | |
| 982 | + | |
| 983 | + /** | |
| 984 | + * Determines the IP address of a host, given the host's name. | |
| 985 | + * | |
| 986 | + * <p> The host name can either be a machine name, such as | |
| 987 | + * "<code>java.sun.com</code>", or a textual representation of its | |
| 988 | + * IP address. If a literal IP address is supplied, only the | |
| 989 | + * validity of the address format is checked. | |
| 990 | + * | |
| 991 | + * <p> For <code>host</code> specified in literal IPv6 address, | |
| 992 | + * either the form defined in RFC 2732 or the literal IPv6 address | |
| 993 | + * format defined in RFC 2373 is accepted. IPv6 scoped addresses are also | |
| 994 | + * supported. See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6 | |
| 995 | + * scoped addresses. | |
| 996 | + * | |
| 997 | + * <p> If the host is <tt>null</tt> then an <tt>InetAddress</tt> | |
| 998 | + * representing an address of the loopback interface is returned. | |
| 999 | + * See <a href="http://www.ietf.org/rfc/rfc3330.txt">RFC 3330</a> | |
| 1000 | + * section 2 and <a href="http://www.ietf.org/rfc/rfc2373.txt">RFC 2373</a> | |
| 1001 | + * section 2.5.3. </p> | |
| 1002 | + * | |
| 1003 | + * @param host the specified host, or <code>null</code>. | |
| 1004 | + * @return an IP address for the given host name. | |
| 1005 | + * @exception UnknownHostException if no IP address for the | |
| 1006 | + * <code>host</code> could be found, or if a scope_id was specified | |
| 1007 | + * for a global IPv6 address. | |
| 1008 | + * @exception SecurityException if a security manager exists | |
| 1009 | + * and its checkConnect method doesn't allow the operation | |
| 1010 | + */ | |
| 1011 | + public static InetAddress getByName(String host) | |
| 1012 | + throws UnknownHostException { | |
| 1013 | + return InetAddress.getAllByName(host)[0]; | |
| 1014 | + } | |
| 1015 | + | |
| 1016 | + // called from deployment cache manager | |
| 1017 | + private static InetAddress getByName(String host, InetAddress reqAddr) | |
| 1018 | + throws UnknownHostException { | |
| 1019 | + return InetAddress.getAllByName(host, reqAddr)[0]; | |
| 1020 | + } | |
| 1021 | + | |
| 1022 | + /** | |
| 1023 | + * Given the name of a host, returns an array of its IP addresses, | |
| 1024 | + * based on the configured name service on the system. | |
| 1025 | + * | |
| 1026 | + * <p> The host name can either be a machine name, such as | |
| 1027 | + * "<code>java.sun.com</code>", or a textual representation of its IP | |
| 1028 | + * address. If a literal IP address is supplied, only the | |
| 1029 | + * validity of the address format is checked. | |
| 1030 | + * | |
| 1031 | + * <p> For <code>host</code> specified in <i>literal IPv6 address</i>, | |
| 1032 | + * either the form defined in RFC 2732 or the literal IPv6 address | |
| 1033 | + * format defined in RFC 2373 is accepted. A literal IPv6 address may | |
| 1034 | + * also be qualified by appending a scoped zone identifier or scope_id. | |
| 1035 | + * The syntax and usage of scope_ids is described | |
| 1036 | + * <a href="Inet6Address.html#scoped">here</a>. | |
| 1037 | + * <p> If the host is <tt>null</tt> then an <tt>InetAddress</tt> | |
| 1038 | + * representing an address of the loopback interface is returned. | |
| 1039 | + * See <a href="http://www.ietf.org/rfc/rfc3330.txt">RFC 3330</a> | |
| 1040 | + * section 2 and <a href="http://www.ietf.org/rfc/rfc2373.txt">RFC 2373</a> | |
| 1041 | + * section 2.5.3. </p> | |
| 1042 | + * | |
| 1043 | + * <p> If there is a security manager and <code>host</code> is not | |
| 1044 | + * null and <code>host.length() </code> is not equal to zero, the | |
| 1045 | + * security manager's | |
| 1046 | + * <code>checkConnect</code> method is called | |
| 1047 | + * with the hostname and <code>-1</code> | |
| 1048 | + * as its arguments to see if the operation is allowed. | |
| 1049 | + * | |
| 1050 | + * @param host the name of the host, or <code>null</code>. | |
| 1051 | + * @return an array of all the IP addresses for a given host name. | |
| 1052 | + * | |
| 1053 | + * @exception UnknownHostException if no IP address for the | |
| 1054 | + * <code>host</code> could be found, or if a scope_id was specified | |
| 1055 | + * for a global IPv6 address. | |
| 1056 | + * @exception SecurityException if a security manager exists and its | |
| 1057 | + * <code>checkConnect</code> method doesn't allow the operation. | |
| 1058 | + * | |
| 1059 | + * @see SecurityManager#checkConnect | |
| 1060 | + */ | |
| 1061 | + public static InetAddress[] getAllByName(String host) | |
| 1062 | + throws UnknownHostException { | |
| 1063 | + return getAllByName(host, null); | |
| 1064 | + } | |
| 1065 | + | |
| 1066 | + private static InetAddress[] getAllByName(String host, InetAddress reqAddr) | |
| 1067 | + throws UnknownHostException { | |
| 1068 | + | |
| 1069 | + if (host == null || host.length() == 0) { | |
| 1070 | + InetAddress[] ret = new InetAddress[1]; | |
| 1071 | + ret[0] = impl.loopbackAddress(); | |
| 1072 | + return ret; | |
| 1073 | + } | |
| 1074 | + | |
| 1075 | + boolean ipv6Expected = false; | |
| 1076 | + if (host.charAt(0) == '[') { | |
| 1077 | + // This is supposed to be an IPv6 literal | |
| 1078 | + if (host.length() > 2 && host.charAt(host.length()-1) == ']') { | |
| 1079 | + host = host.substring(1, host.length() -1); | |
| 1080 | + ipv6Expected = true; | |
| 1081 | + } else { | |
| 1082 | + // This was supposed to be a IPv6 address, but it's not! | |
| 1083 | + throw new UnknownHostException(host + ": invalid IPv6 address"); | |
| 1084 | + } | |
| 1085 | + } | |
| 1086 | + | |
| 1087 | + // if host is an IP address, we won't do further lookup | |
| 1088 | + if (Character.digit(host.charAt(0), 16) != -1 | |
| 1089 | + || (host.charAt(0) == ':')) { | |
| 1090 | + byte[] addr = null; | |
| 1091 | + int numericZone = -1; | |
| 1092 | + String ifname = null; | |
| 1093 | + // see if it is IPv4 address | |
| 1094 | + addr = IPAddressUtil.textToNumericFormatV4(host); | |
| 1095 | + if (addr == null) { | |
| 1096 | + // see if it is IPv6 address | |
| 1097 | + // Check if a numeric or string zone id is present | |
| 1098 | + int pos; | |
| 1099 | + if ((pos=host.indexOf ("%")) != -1) { | |
| 1100 | + numericZone = checkNumericZone (host); | |
| 1101 | + if (numericZone == -1) { /* remainder of string must be an ifname */ | |
| 1102 | + ifname = host.substring (pos+1); | |
| 1103 | + } | |
| 1104 | + } | |
| 1105 | + addr = IPAddressUtil.textToNumericFormatV6(host); | |
| 1106 | + } else if (ipv6Expected) { | |
| 1107 | + // Means an IPv4 litteral between brackets! | |
| 1108 | + throw new UnknownHostException("["+host+"]"); | |
| 1109 | + } | |
| 1110 | + InetAddress[] ret = new InetAddress[1]; | |
| 1111 | + if(addr != null) { | |
| 1112 | + if (addr.length == Inet4Address.INADDRSZ) { | |
| 1113 | + ret[0] = new Inet4Address(null, addr); | |
| 1114 | + } else { | |
| 1115 | + if (ifname != null) { | |
| 1116 | + ret[0] = new Inet6Address(null, addr, ifname); | |
| 1117 | + } else { | |
| 1118 | + ret[0] = new Inet6Address(null, addr, numericZone); | |
| 1119 | + } | |
| 1120 | + } | |
| 1121 | + return ret; | |
| 1122 | + } | |
| 1123 | + } else if (ipv6Expected) { | |
| 1124 | + // We were expecting an IPv6 Litteral, but got something else | |
| 1125 | + throw new UnknownHostException("["+host+"]"); | |
| 1126 | + } | |
| 1127 | + return getAllByName0(host, reqAddr, true); | |
| 1128 | + } | |
| 1129 | + | |
| 1130 | + /** | |
| 1131 | + * Returns the loopback address. | |
| 1132 | + * <p> | |
| 1133 | + * The InetAddress returned will represent the IPv4 | |
| 1134 | + * loopback address, 127.0.0.1, or the IPv6 loopback | |
| 1135 | + * address, ::1. The IPv4 loopback address returned | |
| 1136 | + * is only one of many in the form 127.*.*.* | |
| 1137 | + * | |
| 1138 | + * @return the InetAddress loopback instance. | |
| 1139 | + * @since 1.7 | |
| 1140 | + */ | |
| 1141 | + public static InetAddress getLoopbackAddress() { | |
| 1142 | + return impl.loopbackAddress(); | |
| 1143 | + } | |
| 1144 | + | |
| 1145 | + | |
| 1146 | + /** | |
| 1147 | + * check if the literal address string has %nn appended | |
| 1148 | + * returns -1 if not, or the numeric value otherwise. | |
| 1149 | + * | |
| 1150 | + * %nn may also be a string that represents the displayName of | |
| 1151 | + * a currently available NetworkInterface. | |
| 1152 | + */ | |
| 1153 | + private static int checkNumericZone (String s) throws UnknownHostException { | |
| 1154 | + int percent = s.indexOf ('%'); | |
| 1155 | + int slen = s.length(); | |
| 1156 | + int digit, zone=0; | |
| 1157 | + if (percent == -1) { | |
| 1158 | + return -1; | |
| 1159 | + } | |
| 1160 | + for (int i=percent+1; i<slen; i++) { | |
| 1161 | + char c = s.charAt(i); | |
| 1162 | + if (c == ']') { | |
| 1163 | + if (i == percent+1) { | |
| 1164 | + /* empty per-cent field */ | |
| 1165 | + return -1; | |
| 1166 | + } | |
| 1167 | + break; | |
| 1168 | + } | |
| 1169 | + if ((digit = Character.digit (c, 10)) < 0) { | |
| 1170 | + return -1; | |
| 1171 | + } | |
| 1172 | + zone = (zone * 10) + digit; | |
| 1173 | + } | |
| 1174 | + return zone; | |
| 1175 | + } | |
| 1176 | + | |
| 1177 | + private static InetAddress[] getAllByName0 (String host) | |
| 1178 | + throws UnknownHostException | |
| 1179 | + { | |
| 1180 | + return getAllByName0(host, true); | |
| 1181 | + } | |
| 1182 | + | |
| 1183 | + /** | |
| 1184 | + * package private so SocketPermission can call it | |
| 1185 | + */ | |
| 1186 | + static InetAddress[] getAllByName0 (String host, boolean check) | |
| 1187 | + throws UnknownHostException { | |
| 1188 | + return getAllByName0 (host, null, check); | |
| 1189 | + } | |
| 1190 | + | |
| 1191 | + private static InetAddress[] getAllByName0 (String host, InetAddress reqAddr, boolean check) | |
| 1192 | + throws UnknownHostException { | |
| 1193 | + | |
| 1194 | + /* If it gets here it is presumed to be a hostname */ | |
| 1195 | + /* Cache.get can return: null, unknownAddress, or InetAddress[] */ | |
| 1196 | + | |
| 1197 | + /* make sure the connection to the host is allowed, before we | |
| 1198 | + * give out a hostname | |
| 1199 | + */ | |
| 1200 | + if (check) { | |
| 1201 | + SecurityManager security = System.getSecurityManager(); | |
| 1202 | + if (security != null) { | |
| 1203 | + security.checkConnect(host, -1); | |
| 1204 | + } | |
| 1205 | + } | |
| 1206 | + | |
| 1207 | + InetAddress[] addresses = getCachedAddresses(host); | |
| 1208 | + | |
| 1209 | + /* If no entry in cache, then do the host lookup */ | |
| 1210 | + if (addresses == null) { | |
| 1211 | + addresses = getAddressesFromNameService(host, reqAddr); | |
| 1212 | + } | |
| 1213 | + | |
| 1214 | + if (addresses == unknown_array) | |
| 1215 | + throw new UnknownHostException(host); | |
| 1216 | + | |
| 1217 | + return addresses.clone(); | |
| 1218 | + } | |
| 1219 | + | |
| 1220 | + private static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr) | |
| 1221 | + throws UnknownHostException | |
| 1222 | + { | |
| 1223 | + InetAddress[] addresses = null; | |
| 1224 | + boolean success = false; | |
| 1225 | + UnknownHostException ex = null; | |
| 1226 | + | |
| 1227 | + // Check whether the host is in the lookupTable. | |
| 1228 | + // 1) If the host isn't in the lookupTable when | |
| 1229 | + // checkLookupTable() is called, checkLookupTable() | |
| 1230 | + // would add the host in the lookupTable and | |
| 1231 | + // return null. So we will do the lookup. | |
| 1232 | + // 2) If the host is in the lookupTable when | |
| 1233 | + // checkLookupTable() is called, the current thread | |
| 1234 | + // would be blocked until the host is removed | |
| 1235 | + // from the lookupTable. Then this thread | |
| 1236 | + // should try to look up the addressCache. | |
| 1237 | + // i) if it found the addresses in the | |
| 1238 | + // addressCache, checkLookupTable() would | |
| 1239 | + // return the addresses. | |
| 1240 | + // ii) if it didn't find the addresses in the | |
| 1241 | + // addressCache for any reason, | |
| 1242 | + // it should add the host in the | |
| 1243 | + // lookupTable and return null so the | |
| 1244 | + // following code would do a lookup itself. | |
| 1245 | + if ((addresses = checkLookupTable(host)) == null) { | |
| 1246 | + try { | |
| 1247 | + // This is the first thread which looks up the addresses | |
| 1248 | + // this host or the cache entry for this host has been | |
| 1249 | + // expired so this thread should do the lookup. | |
| 1250 | + for (NameService nameService : nameServices) { | |
| 1251 | + try { | |
| 1252 | + /* | |
| 1253 | + * Do not put the call to lookup() inside the | |
| 1254 | + * constructor. if you do you will still be | |
| 1255 | + * allocating space when the lookup fails. | |
| 1256 | + */ | |
| 1257 | + | |
| 1258 | + addresses = nameService.lookupAllHostAddr(host); | |
| 1259 | + success = true; | |
| 1260 | + break; | |
| 1261 | + } catch (UnknownHostException uhe) { | |
| 1262 | + if (host.equalsIgnoreCase("localhost")) { | |
| 1263 | + InetAddress[] local = new InetAddress[] { impl.loopbackAddress() }; | |
| 1264 | + addresses = local; | |
| 1265 | + success = true; | |
| 1266 | + break; | |
| 1267 | + } | |
| 1268 | + else { | |
| 1269 | + addresses = unknown_array; | |
| 1270 | + success = false; | |
| 1271 | + ex = uhe; | |
| 1272 | + } | |
| 1273 | + } | |
| 1274 | + } | |
| 1275 | + | |
| 1276 | + // More to do? | |
| 1277 | + if (reqAddr != null && addresses.length > 1 && !addresses[0].equals(reqAddr)) { | |
| 1278 | + // Find it? | |
| 1279 | + int i = 1; | |
| 1280 | + for (; i < addresses.length; i++) { | |
| 1281 | + if (addresses[i].equals(reqAddr)) { | |
| 1282 | + break; | |
| 1283 | + } | |
| 1284 | + } | |
| 1285 | + // Rotate | |
| 1286 | + if (i < addresses.length) { | |
| 1287 | + InetAddress tmp, tmp2 = reqAddr; | |
| 1288 | + for (int j = 0; j < i; j++) { | |
| 1289 | + tmp = addresses[j]; | |
| 1290 | + addresses[j] = tmp2; | |
| 1291 | + tmp2 = tmp; | |
| 1292 | + } | |
| 1293 | + addresses[i] = tmp2; | |
| 1294 | + } | |
| 1295 | + } | |
| 1296 | + // Cache the address. | |
| 1297 | + cacheAddresses(host, addresses, success); | |
| 1298 | + | |
| 1299 | + if (!success && ex != null) | |
| 1300 | + throw ex; | |
| 1301 | + | |
| 1302 | + } finally { | |
| 1303 | + // Delete host from the lookupTable and notify | |
| 1304 | + // all threads waiting on the lookupTable monitor. | |
| 1305 | + updateLookupTable(host); | |
| 1306 | + } | |
| 1307 | + } | |
| 1308 | + | |
| 1309 | + return addresses; | |
| 1310 | + } | |
| 1311 | + | |
| 1312 | + | |
| 1313 | + private static InetAddress[] checkLookupTable(String host) { | |
| 1314 | + synchronized (lookupTable) { | |
| 1315 | + // If the host isn't in the lookupTable, add it in the | |
| 1316 | + // lookuptable and return null. The caller should do | |
| 1317 | + // the lookup. | |
| 1318 | + if (lookupTable.containsKey(host) == false) { | |
| 1319 | + lookupTable.put(host, null); | |
| 1320 | + return null; | |
| 1321 | + } | |
| 1322 | + | |
| 1323 | + // If the host is in the lookupTable, it means that another | |
| 1324 | + // thread is trying to look up the addresses of this host. | |
| 1325 | + // This thread should wait. | |
| 1326 | + while (lookupTable.containsKey(host)) { | |
| 1327 | + try { | |
| 1328 | + lookupTable.wait(); | |
| 1329 | + } catch (InterruptedException e) { | |
| 1330 | + } | |
| 1331 | + } | |
| 1332 | + } | |
| 1333 | + | |
| 1334 | + // The other thread has finished looking up the addresses of | |
| 1335 | + // the host. This thread should retry to get the addresses | |
| 1336 | + // from the addressCache. If it doesn't get the addresses from | |
| 1337 | + // the cache, it will try to look up the addresses itself. | |
| 1338 | + InetAddress[] addresses = getCachedAddresses(host); | |
| 1339 | + if (addresses == null) { | |
| 1340 | + synchronized (lookupTable) { | |
| 1341 | + lookupTable.put(host, null); | |
| 1342 | + return null; | |
| 1343 | + } | |
| 1344 | + } | |
| 1345 | + | |
| 1346 | + return addresses; | |
| 1347 | + } | |
| 1348 | + | |
| 1349 | + private static void updateLookupTable(String host) { | |
| 1350 | + synchronized (lookupTable) { | |
| 1351 | + lookupTable.remove(host); | |
| 1352 | + lookupTable.notifyAll(); | |
| 1353 | + } | |
| 1354 | + } | |
| 1355 | + | |
| 1356 | + /** | |
| 1357 | + * Returns an <code>InetAddress</code> object given the raw IP address . | |
| 1358 | + * The argument is in network byte order: the highest order | |
| 1359 | + * byte of the address is in <code>getAddress()[0]</code>. | |
| 1360 | + * | |
| 1361 | + * <p> This method doesn't block, i.e. no reverse name service lookup | |
| 1362 | + * is performed. | |
| 1363 | + * | |
| 1364 | + * <p> IPv4 address byte array must be 4 bytes long and IPv6 byte array | |
| 1365 | + * must be 16 bytes long | |
| 1366 | + * | |
| 1367 | + * @param addr the raw IP address in network byte order | |
| 1368 | + * @return an InetAddress object created from the raw IP address. | |
| 1369 | + * @exception UnknownHostException if IP address is of illegal length | |
| 1370 | + * @since 1.4 | |
| 1371 | + */ | |
| 1372 | + public static InetAddress getByAddress(byte[] addr) | |
| 1373 | + throws UnknownHostException { | |
| 1374 | + return getByAddress(null, addr); | |
| 1375 | + } | |
| 1376 | + | |
| 1377 | + private static InetAddress cachedLocalHost = null; | |
| 1378 | + private static long cacheTime = 0; | |
| 1379 | + private static final long maxCacheTime = 5000L; | |
| 1380 | + private static final Object cacheLock = new Object(); | |
| 1381 | + | |
| 1382 | + /** | |
| 1383 | + * Returns the address of the local host. This is achieved by retrieving | |
| 1384 | + * the name of the host from the system, then resolving that name into | |
| 1385 | + * an <code>InetAddress</code>. | |
| 1386 | + * | |
| 1387 | + * <P>Note: The resolved address may be cached for a short period of time. | |
| 1388 | + * </P> | |
| 1389 | + * | |
| 1390 | + * <p>If there is a security manager, its | |
| 1391 | + * <code>checkConnect</code> method is called | |
| 1392 | + * with the local host name and <code>-1</code> | |
| 1393 | + * as its arguments to see if the operation is allowed. | |
| 1394 | + * If the operation is not allowed, an InetAddress representing | |
| 1395 | + * the loopback address is returned. | |
| 1396 | + * | |
| 1397 | + * @return the address of the local host. | |
| 1398 | + * | |
| 1399 | + * @exception UnknownHostException if the local host name could not | |
| 1400 | + * be resolved into an address. | |
| 1401 | + * | |
| 1402 | + * @see SecurityManager#checkConnect | |
| 1403 | + * @see java.net.InetAddress#getByName(java.lang.String) | |
| 1404 | + */ | |
| 1405 | + public static InetAddress getLocalHost() throws UnknownHostException { | |
| 1406 | + | |
| 1407 | + SecurityManager security = System.getSecurityManager(); | |
| 1408 | + try { | |
| 1409 | + String local = impl.getLocalHostName(); | |
| 1410 | + | |
| 1411 | + if (security != null) { | |
| 1412 | + security.checkConnect(local, -1); | |
| 1413 | + } | |
| 1414 | + | |
| 1415 | + if (local.equals("localhost")) { | |
| 1416 | + return impl.loopbackAddress(); | |
| 1417 | + } | |
| 1418 | + | |
| 1419 | + InetAddress ret = null; | |
| 1420 | + synchronized (cacheLock) { | |
| 1421 | + long now = System.currentTimeMillis(); | |
| 1422 | + if (cachedLocalHost != null) { | |
| 1423 | + if ((now - cacheTime) < maxCacheTime) // Less than 5s old? | |
| 1424 | + ret = cachedLocalHost; | |
| 1425 | + else | |
| 1426 | + cachedLocalHost = null; | |
| 1427 | + } | |
| 1428 | + | |
| 1429 | + // we are calling getAddressesFromNameService directly | |
| 1430 | + // to avoid getting localHost from cache | |
| 1431 | + if (ret == null) { | |
| 1432 | + InetAddress[] localAddrs; | |
| 1433 | + try { | |
| 1434 | + localAddrs = | |
| 1435 | + InetAddress.getAddressesFromNameService(local, null); | |
| 1436 | + } catch (UnknownHostException uhe) { | |
| 1437 | + // Rethrow with a more informative error message. | |
| 1438 | + UnknownHostException uhe2 = | |
| 1439 | + new UnknownHostException(local + ": " + | |
| 1440 | + uhe.getMessage()); | |
| 1441 | + uhe2.initCause(uhe); | |
| 1442 | + throw uhe2; | |
| 1443 | + } | |
| 1444 | + cachedLocalHost = localAddrs[0]; | |
| 1445 | + cacheTime = now; | |
| 1446 | + ret = localAddrs[0]; | |
| 1447 | + } | |
| 1448 | + } | |
| 1449 | + return ret; | |
| 1450 | + } catch (java.lang.SecurityException e) { | |
| 1451 | + return impl.loopbackAddress(); | |
| 1452 | + } | |
| 1453 | + } | |
| 1454 | + | |
| 1455 | + /** | |
| 1456 | + * Perform class load-time initializations. | |
| 1457 | + */ | |
| 1458 | + private static native void init(); | |
| 1459 | + | |
| 1460 | + | |
| 1461 | + /* | |
| 1462 | + * Returns the InetAddress representing anyLocalAddress | |
| 1463 | + * (typically 0.0.0.0 or ::0) | |
| 1464 | + */ | |
| 1465 | + static InetAddress anyLocalAddress() { | |
| 1466 | + return impl.anyLocalAddress(); | |
| 1467 | + } | |
| 1468 | + | |
| 1469 | + /* | |
| 1470 | + * Load and instantiate an underlying impl class | |
| 1471 | + */ | |
| 1472 | + static InetAddressImpl loadImpl(String implName) { | |
| 1473 | + Object impl = null; | |
| 1474 | + | |
| 1475 | + /* | |
| 1476 | + * Property "impl.prefix" will be prepended to the classname | |
| 1477 | + * of the implementation object we instantiate, to which we | |
| 1478 | + * delegate the real work (like native methods). This | |
| 1479 | + * property can vary across implementations of the java. | |
| 1480 | + * classes. The default is an empty String "". | |
| 1481 | + */ | |
| 1482 | + String prefix = AccessController.doPrivileged( | |
| 1483 | + new GetPropertyAction("impl.prefix", "")); | |
| 1484 | + try { | |
| 1485 | + impl = Class.forName("java.net." + prefix + implName).newInstance(); | |
| 1486 | + } catch (ClassNotFoundException e) { | |
| 1487 | + System.err.println("Class not found: java.net." + prefix + | |
| 1488 | + implName + ":\ncheck impl.prefix property " + | |
| 1489 | + "in your properties file."); | |
| 1490 | + } catch (InstantiationException e) { | |
| 1491 | + System.err.println("Could not instantiate: java.net." + prefix + | |
| 1492 | + implName + ":\ncheck impl.prefix property " + | |
| 1493 | + "in your properties file."); | |
| 1494 | + } catch (IllegalAccessException e) { | |
| 1495 | + System.err.println("Cannot access class: java.net." + prefix + | |
| 1496 | + implName + ":\ncheck impl.prefix property " + | |
| 1497 | + "in your properties file."); | |
| 1498 | + } | |
| 1499 | + | |
| 1500 | + if (impl == null) { | |
| 1501 | + try { | |
| 1502 | + impl = Class.forName(implName).newInstance(); | |
| 1503 | + } catch (Exception e) { | |
| 1504 | + throw new Error("System property impl.prefix incorrect"); | |
| 1505 | + } | |
| 1506 | + } | |
| 1507 | + | |
| 1508 | + return (InetAddressImpl) impl; | |
| 1509 | + } | |
| 1510 | + | |
| 1511 | + private void readObjectNoData (ObjectInputStream s) throws | |
| 1512 | + IOException, ClassNotFoundException { | |
| 1513 | + if (getClass().getClassLoader() != null) { | |
| 1514 | + throw new SecurityException ("invalid address type"); | |
| 1515 | + } | |
| 1516 | + } | |
| 1517 | + | |
| 1518 | + private void readObject (ObjectInputStream s) throws | |
| 1519 | + IOException, ClassNotFoundException { | |
| 1520 | + s.defaultReadObject (); | |
| 1521 | + if (getClass().getClassLoader() != null) { | |
| 1522 | + hostName = null; | |
| 1523 | + address = 0; | |
| 1524 | + throw new SecurityException ("invalid address type"); | |
| 1525 | + } | |
| 1526 | + } | |
| 1527 | +} | |
| 1528 | + | |
| 1529 | +/* | |
| 1530 | + * Simple factory to create the impl | |
| 1531 | + */ | |
| 1532 | +class InetAddressImplFactory { | |
| 1533 | + | |
| 1534 | + static InetAddressImpl create() { | |
| 1535 | + return InetAddress.loadImpl(isIPv6Supported() ? | |
| 1536 | + "Inet6AddressImpl" : "Inet4AddressImpl"); | |
| 1537 | + } | |
| 1538 | + | |
| 1539 | + static native boolean isIPv6Supported(); | |
| 1540 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,48 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2002, 2005, 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 java.net; | |
| 27 | +import java.io.IOException; | |
| 28 | +/* | |
| 29 | + * Package private interface to "implementation" used by | |
| 30 | + * {@link InetAddress}. | |
| 31 | + * <p> | |
| 32 | + * See {@link java.net.Inet4AddressImp} and | |
| 33 | + * {@link java.net.Inet6AddressImp}. | |
| 34 | + * | |
| 35 | + * @since 1.4 | |
| 36 | + */ | |
| 37 | +interface InetAddressImpl { | |
| 38 | + | |
| 39 | + String getLocalHostName() throws UnknownHostException; | |
| 40 | + InetAddress[] | |
| 41 | + lookupAllHostAddr(String hostname) throws UnknownHostException; | |
| 42 | + String getHostByAddr(byte[] addr) throws UnknownHostException; | |
| 43 | + | |
| 44 | + InetAddress anyLocalAddress(); | |
| 45 | + InetAddress loopbackAddress(); | |
| 46 | + boolean isReachable(InetAddress addr, int timeout, NetworkInterface netif, | |
| 47 | + int ttl) throws IOException; | |
| 48 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,327 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 2007, 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 | +package java.net; | |
| 26 | + | |
| 27 | +import java.io.ObjectInputStream; | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.io.InvalidObjectException; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * | |
| 33 | + * This class implements an IP Socket Address (IP address + port number) | |
| 34 | + * It can also be a pair (hostname + port number), in which case an attempt | |
| 35 | + * will be made to resolve the hostname. If resolution fails then the address | |
| 36 | + * is said to be <I>unresolved</I> but can still be used on some circumstances | |
| 37 | + * like connecting through a proxy. | |
| 38 | + * <p> | |
| 39 | + * It provides an immutable object used by sockets for binding, connecting, or | |
| 40 | + * as returned values. | |
| 41 | + * <p> | |
| 42 | + * The <i>wildcard</i> is a special local IP address. It usually means "any" | |
| 43 | + * and can only be used for <code>bind</code> operations. | |
| 44 | + * | |
| 45 | + * @see java.net.Socket | |
| 46 | + * @see java.net.ServerSocket | |
| 47 | + * @since 1.4 | |
| 48 | + */ | |
| 49 | +public class InetSocketAddress extends SocketAddress { | |
| 50 | + /* The hostname of the Socket Address | |
| 51 | + * @serial | |
| 52 | + */ | |
| 53 | + private String hostname = null; | |
| 54 | + /* The IP address of the Socket Address | |
| 55 | + * @serial | |
| 56 | + */ | |
| 57 | + private InetAddress addr = null; | |
| 58 | + /* The port number of the Socket Address | |
| 59 | + * @serial | |
| 60 | + */ | |
| 61 | + private int port; | |
| 62 | + | |
| 63 | + private static final long serialVersionUID = 5076001401234631237L; | |
| 64 | + | |
| 65 | + private InetSocketAddress() { | |
| 66 | + } | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * Creates a socket address where the IP address is the wildcard address | |
| 70 | + * and the port number a specified value. | |
| 71 | + * <p> | |
| 72 | + * A valid port value is between 0 and 65535. | |
| 73 | + * A port number of <code>zero</code> will let the system pick up an | |
| 74 | + * ephemeral port in a <code>bind</code> operation. | |
| 75 | + * <p> | |
| 76 | + * @param port The port number | |
| 77 | + * @throws IllegalArgumentException if the port parameter is outside the specified | |
| 78 | + * range of valid port values. | |
| 79 | + */ | |
| 80 | + public InetSocketAddress(int port) { | |
| 81 | + this(InetAddress.anyLocalAddress(), port); | |
| 82 | + } | |
| 83 | + | |
| 84 | + /** | |
| 85 | + * | |
| 86 | + * Creates a socket address from an IP address and a port number. | |
| 87 | + * <p> | |
| 88 | + * A valid port value is between 0 and 65535. | |
| 89 | + * A port number of <code>zero</code> will let the system pick up an | |
| 90 | + * ephemeral port in a <code>bind</code> operation. | |
| 91 | + * <P> | |
| 92 | + * A <code>null</code> address will assign the <i>wildcard</i> address. | |
| 93 | + * <p> | |
| 94 | + * @param addr The IP address | |
| 95 | + * @param port The port number | |
| 96 | + * @throws IllegalArgumentException if the port parameter is outside the specified | |
| 97 | + * range of valid port values. | |
| 98 | + */ | |
| 99 | + public InetSocketAddress(InetAddress addr, int port) { | |
| 100 | + if (port < 0 || port > 0xFFFF) { | |
| 101 | + throw new IllegalArgumentException("port out of range:" + port); | |
| 102 | + } | |
| 103 | + this.port = port; | |
| 104 | + if (addr == null) | |
| 105 | + this.addr = InetAddress.anyLocalAddress(); | |
| 106 | + else | |
| 107 | + this.addr = addr; | |
| 108 | + } | |
| 109 | + | |
| 110 | + /** | |
| 111 | + * | |
| 112 | + * Creates a socket address from a hostname and a port number. | |
| 113 | + * <p> | |
| 114 | + * An attempt will be made to resolve the hostname into an InetAddress. | |
| 115 | + * If that attempt fails, the address will be flagged as <I>unresolved</I>. | |
| 116 | + * <p> | |
| 117 | + * If there is a security manager, its <code>checkConnect</code> method | |
| 118 | + * is called with the host name as its argument to check the permissiom | |
| 119 | + * to resolve it. This could result in a SecurityException. | |
| 120 | + * <P> | |
| 121 | + * A valid port value is between 0 and 65535. | |
| 122 | + * A port number of <code>zero</code> will let the system pick up an | |
| 123 | + * ephemeral port in a <code>bind</code> operation. | |
| 124 | + * <P> | |
| 125 | + * @param hostname the Host name | |
| 126 | + * @param port The port number | |
| 127 | + * @throws IllegalArgumentException if the port parameter is outside the range | |
| 128 | + * of valid port values, or if the hostname parameter is <TT>null</TT>. | |
| 129 | + * @throws SecurityException if a security manager is present and | |
| 130 | + * permission to resolve the host name is | |
| 131 | + * denied. | |
| 132 | + * @see #isUnresolved() | |
| 133 | + */ | |
| 134 | + public InetSocketAddress(String hostname, int port) { | |
| 135 | + if (port < 0 || port > 0xFFFF) { | |
| 136 | + throw new IllegalArgumentException("port out of range:" + port); | |
| 137 | + } | |
| 138 | + if (hostname == null) { | |
| 139 | + throw new IllegalArgumentException("hostname can't be null"); | |
| 140 | + } | |
| 141 | + try { | |
| 142 | + addr = InetAddress.getByName(hostname); | |
| 143 | + } catch(UnknownHostException e) { | |
| 144 | + this.hostname = hostname; | |
| 145 | + addr = null; | |
| 146 | + } | |
| 147 | + this.port = port; | |
| 148 | + } | |
| 149 | + | |
| 150 | + /** | |
| 151 | + * | |
| 152 | + * Creates an unresolved socket address from a hostname and a port number. | |
| 153 | + * <p> | |
| 154 | + * No attempt will be made to resolve the hostname into an InetAddress. | |
| 155 | + * The address will be flagged as <I>unresolved</I>. | |
| 156 | + * <p> | |
| 157 | + * A valid port value is between 0 and 65535. | |
| 158 | + * A port number of <code>zero</code> will let the system pick up an | |
| 159 | + * ephemeral port in a <code>bind</code> operation. | |
| 160 | + * <P> | |
| 161 | + * @param host the Host name | |
| 162 | + * @param port The port number | |
| 163 | + * @throws IllegalArgumentException if the port parameter is outside | |
| 164 | + * the range of valid port values, or if the hostname | |
| 165 | + * parameter is <TT>null</TT>. | |
| 166 | + * @see #isUnresolved() | |
| 167 | + * @return a <code>InetSocketAddress</code> representing the unresolved | |
| 168 | + * socket address | |
| 169 | + * @since 1.5 | |
| 170 | + */ | |
| 171 | + public static InetSocketAddress createUnresolved(String host, int port) { | |
| 172 | + if (port < 0 || port > 0xFFFF) { | |
| 173 | + throw new IllegalArgumentException("port out of range:" + port); | |
| 174 | + } | |
| 175 | + if (host == null) { | |
| 176 | + throw new IllegalArgumentException("hostname can't be null"); | |
| 177 | + } | |
| 178 | + InetSocketAddress s = new InetSocketAddress(); | |
| 179 | + s.port = port; | |
| 180 | + s.hostname = host; | |
| 181 | + s.addr = null; | |
| 182 | + return s; | |
| 183 | + } | |
| 184 | + | |
| 185 | + private void readObject(ObjectInputStream s) | |
| 186 | + throws IOException, ClassNotFoundException { | |
| 187 | + s.defaultReadObject(); | |
| 188 | + | |
| 189 | + // Check that our invariants are satisfied | |
| 190 | + if (port < 0 || port > 0xFFFF) { | |
| 191 | + throw new InvalidObjectException("port out of range:" + port); | |
| 192 | + } | |
| 193 | + | |
| 194 | + if (hostname == null && addr == null) { | |
| 195 | + throw new InvalidObjectException("hostname and addr " + | |
| 196 | + "can't both be null"); | |
| 197 | + } | |
| 198 | + } | |
| 199 | + | |
| 200 | + /** | |
| 201 | + * Gets the port number. | |
| 202 | + * | |
| 203 | + * @return the port number. | |
| 204 | + */ | |
| 205 | + public final int getPort() { | |
| 206 | + return port; | |
| 207 | + } | |
| 208 | + | |
| 209 | + /** | |
| 210 | + * | |
| 211 | + * Gets the <code>InetAddress</code>. | |
| 212 | + * | |
| 213 | + * @return the InetAdress or <code>null</code> if it is unresolved. | |
| 214 | + */ | |
| 215 | + public final InetAddress getAddress() { | |
| 216 | + return addr; | |
| 217 | + } | |
| 218 | + | |
| 219 | + /** | |
| 220 | + * Gets the <code>hostname</code>. | |
| 221 | + * Note: This method may trigger a name service reverse lookup if the | |
| 222 | + * address was created with a literal IP address. | |
| 223 | + * | |
| 224 | + * @return the hostname part of the address. | |
| 225 | + */ | |
| 226 | + public final String getHostName() { | |
| 227 | + if (hostname != null) | |
| 228 | + return hostname; | |
| 229 | + if (addr != null) | |
| 230 | + return addr.getHostName(); | |
| 231 | + return null; | |
| 232 | + } | |
| 233 | + | |
| 234 | + /** | |
| 235 | + * Returns the hostname, or the String form of the address if it | |
| 236 | + * doesn't have a hostname (it was created using a literal). | |
| 237 | + * This has the benefit of <b>not</b> attemptimg a reverse lookup. | |
| 238 | + * | |
| 239 | + * @return the hostname, or String representation of the address. | |
| 240 | + * @since 1.7 | |
| 241 | + */ | |
| 242 | + public final String getHostString() { | |
| 243 | + if (hostname != null) | |
| 244 | + return hostname; | |
| 245 | + if (addr != null) { | |
| 246 | + if (addr.hostName != null) | |
| 247 | + return addr.hostName; | |
| 248 | + else | |
| 249 | + return addr.getHostAddress(); | |
| 250 | + } | |
| 251 | + return null; | |
| 252 | + } | |
| 253 | + | |
| 254 | + /** | |
| 255 | + * Checks whether the address has been resolved or not. | |
| 256 | + * | |
| 257 | + * @return <code>true</code> if the hostname couldn't be resolved into | |
| 258 | + * an <code>InetAddress</code>. | |
| 259 | + */ | |
| 260 | + public final boolean isUnresolved() { | |
| 261 | + return addr == null; | |
| 262 | + } | |
| 263 | + | |
| 264 | + /** | |
| 265 | + * Constructs a string representation of this InetSocketAddress. | |
| 266 | + * This String is constructed by calling toString() on the InetAddress | |
| 267 | + * and concatenating the port number (with a colon). If the address | |
| 268 | + * is unresolved then the part before the colon will only contain the hostname. | |
| 269 | + * | |
| 270 | + * @return a string representation of this object. | |
| 271 | + */ | |
| 272 | + public String toString() { | |
| 273 | + if (isUnresolved()) { | |
| 274 | + return hostname + ":" + port; | |
| 275 | + } else { | |
| 276 | + return addr.toString() + ":" + port; | |
| 277 | + } | |
| 278 | + } | |
| 279 | + | |
| 280 | + /** | |
| 281 | + * Compares this object against the specified object. | |
| 282 | + * The result is <code>true</code> if and only if the argument is | |
| 283 | + * not <code>null</code> and it represents the same address as | |
| 284 | + * this object. | |
| 285 | + * <p> | |
| 286 | + * Two instances of <code>InetSocketAddress</code> represent the same | |
| 287 | + * address if both the InetAddresses (or hostnames if it is unresolved) and port | |
| 288 | + * numbers are equal. | |
| 289 | + * If both addresses are unresolved, then the hostname & the port number | |
| 290 | + * are compared. | |
| 291 | + * | |
| 292 | + * Note: Hostnames are case insensitive. e.g. "FooBar" and "foobar" are | |
| 293 | + * considered equal. | |
| 294 | + * | |
| 295 | + * @param obj the object to compare against. | |
| 296 | + * @return <code>true</code> if the objects are the same; | |
| 297 | + * <code>false</code> otherwise. | |
| 298 | + * @see java.net.InetAddress#equals(java.lang.Object) | |
| 299 | + */ | |
| 300 | + public final boolean equals(Object obj) { | |
| 301 | + if (obj == null || !(obj instanceof InetSocketAddress)) | |
| 302 | + return false; | |
| 303 | + InetSocketAddress sockAddr = (InetSocketAddress) obj; | |
| 304 | + boolean sameIP = false; | |
| 305 | + if (this.addr != null) | |
| 306 | + sameIP = this.addr.equals(sockAddr.addr); | |
| 307 | + else if (this.hostname != null) | |
| 308 | + sameIP = (sockAddr.addr == null) && | |
| 309 | + this.hostname.equalsIgnoreCase(sockAddr.hostname); | |
| 310 | + else | |
| 311 | + sameIP = (sockAddr.addr == null) && (sockAddr.hostname == null); | |
| 312 | + return sameIP && (this.port == sockAddr.port); | |
| 313 | + } | |
| 314 | + | |
| 315 | + /** | |
| 316 | + * Returns a hashcode for this socket address. | |
| 317 | + * | |
| 318 | + * @return a hash code value for this socket address. | |
| 319 | + */ | |
| 320 | + public final int hashCode() { | |
| 321 | + if (addr != null) | |
| 322 | + return addr.hashCode() + port; | |
| 323 | + if (hostname != null) | |
| 324 | + return hostname.toLowerCase().hashCode() + port; | |
| 325 | + return port; | |
| 326 | + } | |
| 327 | +} | |
Binary file not shown.
| @@ -0,0 +1,134 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2005, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class represents a Network Interface address. In short it's an | |
| 30 | + * IP address, a subnet mask and a broadcast address when the address is | |
| 31 | + * an IPv4 one. An IP address and a network prefix length in the case | |
| 32 | + * of IPv6 address. | |
| 33 | + * | |
| 34 | + * @see java.net.NetworkInterface | |
| 35 | + * @since 1.6 | |
| 36 | + */ | |
| 37 | +public class InterfaceAddress { | |
| 38 | + private InetAddress address = null; | |
| 39 | + private Inet4Address broadcast = null; | |
| 40 | + private short maskLength = 0; | |
| 41 | + | |
| 42 | + /* | |
| 43 | + * Package private constructor. Can't be built directly, instances are | |
| 44 | + * obtained through the NetworkInterface class. | |
| 45 | + */ | |
| 46 | + InterfaceAddress() { | |
| 47 | + } | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * Returns an <code>InetAddress</code> for this address. | |
| 51 | + * | |
| 52 | + * @return the <code>InetAddress</code> for this address. | |
| 53 | + */ | |
| 54 | + public InetAddress getAddress() { | |
| 55 | + return address; | |
| 56 | + } | |
| 57 | + | |
| 58 | + /** | |
| 59 | + * Returns an <code>InetAddress</code> for the brodcast address | |
| 60 | + * for this InterfaceAddress. | |
| 61 | + * <p> | |
| 62 | + * Only IPv4 networks have broadcast address therefore, in the case | |
| 63 | + * of an IPv6 network, <code>null</code> will be returned. | |
| 64 | + * | |
| 65 | + * @return the <code>InetAddress</code> representing the broadcast | |
| 66 | + * address or <code>null</code> if there is no broadcast address. | |
| 67 | + */ | |
| 68 | + public InetAddress getBroadcast() { | |
| 69 | + return broadcast; | |
| 70 | + } | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * Returns the network prefix length for this address. This is also known | |
| 74 | + * as the subnet mask in the context of IPv4 addresses. | |
| 75 | + * Typical IPv4 values would be 8 (255.0.0.0), 16 (255.255.0.0) | |
| 76 | + * or 24 (255.255.255.0). <p> | |
| 77 | + * Typical IPv6 values would be 128 (::1/128) or 10 (fe80::203:baff:fe27:1243/10) | |
| 78 | + * | |
| 79 | + * @return a <code>short</code> representing the prefix length for the | |
| 80 | + * subnet of that address. | |
| 81 | + */ | |
| 82 | + public short getNetworkPrefixLength() { | |
| 83 | + return maskLength; | |
| 84 | + } | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * Compares this object against the specified object. | |
| 88 | + * The result is <code>true</code> if and only if the argument is | |
| 89 | + * not <code>null</code> and it represents the same interface address as | |
| 90 | + * this object. | |
| 91 | + * <p> | |
| 92 | + * Two instances of <code>InterfaceAddress</code> represent the same | |
| 93 | + * address if the InetAddress, the prefix length and the broadcast are | |
| 94 | + * the same for both. | |
| 95 | + * | |
| 96 | + * @param obj the object to compare against. | |
| 97 | + * @return <code>true</code> if the objects are the same; | |
| 98 | + * <code>false</code> otherwise. | |
| 99 | + * @see java.net.InterfaceAddress#hashCode() | |
| 100 | + */ | |
| 101 | + public boolean equals(Object obj) { | |
| 102 | + if (!(obj instanceof InterfaceAddress)) { | |
| 103 | + return false; | |
| 104 | + } | |
| 105 | + InterfaceAddress cmp = (InterfaceAddress) obj; | |
| 106 | + if ( !(address == null ? cmp.address == null : address.equals(cmp.address)) ) | |
| 107 | + return false; | |
| 108 | + if ( !(broadcast == null ? cmp.broadcast == null : broadcast.equals(cmp.broadcast)) ) | |
| 109 | + return false; | |
| 110 | + if (maskLength != cmp.maskLength) | |
| 111 | + return false; | |
| 112 | + return true; | |
| 113 | + } | |
| 114 | + | |
| 115 | + /** | |
| 116 | + * Returns a hashcode for this Interface address. | |
| 117 | + * | |
| 118 | + * @return a hash code value for this Interface address. | |
| 119 | + */ | |
| 120 | + public int hashCode() { | |
| 121 | + return address.hashCode() + ((broadcast != null) ? broadcast.hashCode() : 0) + maskLength; | |
| 122 | + } | |
| 123 | + | |
| 124 | + /** | |
| 125 | + * Converts this Interface address to a <code>String</code>. The | |
| 126 | + * string returned is of the form: InetAddress / prefix length [ broadcast address ]. | |
| 127 | + * | |
| 128 | + * @return a string representation of this Interface address. | |
| 129 | + */ | |
| 130 | + public String toString() { | |
| 131 | + return address + "/" + maskLength + " [" + broadcast + "]"; | |
| 132 | + } | |
| 133 | + | |
| 134 | +} | |
Binary file not shown.
| @@ -0,0 +1,313 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2006, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.util.jar.JarFile; | |
| 30 | +import java.util.jar.JarEntry; | |
| 31 | +import java.util.jar.Attributes; | |
| 32 | +import java.util.jar.Manifest; | |
| 33 | +import java.security.Permission; | |
| 34 | +import sun.net.www.ParseUtil; | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * A URL Connection to a Java ARchive (JAR) file or an entry in a JAR | |
| 38 | + * file. | |
| 39 | + * | |
| 40 | + * <p>The syntax of a JAR URL is: | |
| 41 | + * | |
| 42 | + * <pre> | |
| 43 | + * jar:<url>!/{entry} | |
| 44 | + * </pre> | |
| 45 | + * | |
| 46 | + * <p>for example: | |
| 47 | + * | |
| 48 | + * <p><code> | |
| 49 | + * jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class<br> | |
| 50 | + * </code> | |
| 51 | + * | |
| 52 | + * <p>Jar URLs should be used to refer to a JAR file or entries in | |
| 53 | + * a JAR file. The example above is a JAR URL which refers to a JAR | |
| 54 | + * entry. If the entry name is omitted, the URL refers to the whole | |
| 55 | + * JAR file: | |
| 56 | + * | |
| 57 | + * <code> | |
| 58 | + * jar:http://www.foo.com/bar/baz.jar!/ | |
| 59 | + * </code> | |
| 60 | + * | |
| 61 | + * <p>Users should cast the generic URLConnection to a | |
| 62 | + * JarURLConnection when they know that the URL they created is a JAR | |
| 63 | + * URL, and they need JAR-specific functionality. For example: | |
| 64 | + * | |
| 65 | + * <pre> | |
| 66 | + * URL url = new URL("jar:file:/home/duke/duke.jar!/"); | |
| 67 | + * JarURLConnection jarConnection = (JarURLConnection)url.openConnection(); | |
| 68 | + * Manifest manifest = jarConnection.getManifest(); | |
| 69 | + * </pre> | |
| 70 | + * | |
| 71 | + * <p>JarURLConnection instances can only be used to read from JAR files. | |
| 72 | + * It is not possible to get a {@link java.io.OutputStream} to modify or write | |
| 73 | + * to the underlying JAR file using this class. | |
| 74 | + * <p>Examples: | |
| 75 | + * | |
| 76 | + * <dl> | |
| 77 | + * | |
| 78 | + * <dt>A Jar entry | |
| 79 | + * <dd><code>jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class</code> | |
| 80 | + * | |
| 81 | + * <dt>A Jar file | |
| 82 | + * <dd><code>jar:http://www.foo.com/bar/baz.jar!/</code> | |
| 83 | + * | |
| 84 | + * <dt>A Jar directory | |
| 85 | + * <dd><code>jar:http://www.foo.com/bar/baz.jar!/COM/foo/</code> | |
| 86 | + * | |
| 87 | + * </dl> | |
| 88 | + * | |
| 89 | + * <p><code>!/</code> is refered to as the <em>separator</em>. | |
| 90 | + * | |
| 91 | + * <p>When constructing a JAR url via <code>new URL(context, spec)</code>, | |
| 92 | + * the following rules apply: | |
| 93 | + * | |
| 94 | + * <ul> | |
| 95 | + * | |
| 96 | + * <li>if there is no context URL and the specification passed to the | |
| 97 | + * URL constructor doesn't contain a separator, the URL is considered | |
| 98 | + * to refer to a JarFile. | |
| 99 | + * | |
| 100 | + * <li>if there is a context URL, the context URL is assumed to refer | |
| 101 | + * to a JAR file or a Jar directory. | |
| 102 | + * | |
| 103 | + * <li>if the specification begins with a '/', the Jar directory is | |
| 104 | + * ignored, and the spec is considered to be at the root of the Jar | |
| 105 | + * file. | |
| 106 | + * | |
| 107 | + * <p>Examples: | |
| 108 | + * | |
| 109 | + * <dl> | |
| 110 | + * | |
| 111 | + * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/</b>, | |
| 112 | + * spec:<b>baz/entry.txt</b> | |
| 113 | + * | |
| 114 | + * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/baz/entry.txt</b> | |
| 115 | + * | |
| 116 | + * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/baz</b>, | |
| 117 | + * spec:<b>entry.txt</b> | |
| 118 | + * | |
| 119 | + * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/baz/entry.txt</b> | |
| 120 | + * | |
| 121 | + * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/baz</b>, | |
| 122 | + * spec:<b>/entry.txt</b> | |
| 123 | + * | |
| 124 | + * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/entry.txt</b> | |
| 125 | + * | |
| 126 | + * </dl> | |
| 127 | + * | |
| 128 | + * </ul> | |
| 129 | + * | |
| 130 | + * @see java.net.URL | |
| 131 | + * @see java.net.URLConnection | |
| 132 | + * | |
| 133 | + * @see java.util.jar.JarFile | |
| 134 | + * @see java.util.jar.JarInputStream | |
| 135 | + * @see java.util.jar.Manifest | |
| 136 | + * @see java.util.zip.ZipEntry | |
| 137 | + * | |
| 138 | + * @author Benjamin Renaud | |
| 139 | + * @since 1.2 | |
| 140 | + */ | |
| 141 | +public abstract class JarURLConnection extends URLConnection { | |
| 142 | + | |
| 143 | + private URL jarFileURL; | |
| 144 | + private String entryName; | |
| 145 | + | |
| 146 | + /** | |
| 147 | + * The connection to the JAR file URL, if the connection has been | |
| 148 | + * initiated. This should be set by connect. | |
| 149 | + */ | |
| 150 | + protected URLConnection jarFileURLConnection; | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * Creates the new JarURLConnection to the specified URL. | |
| 154 | + * @param url the URL | |
| 155 | + * @throws MalformedURLException if no legal protocol | |
| 156 | + * could be found in a specification string or the | |
| 157 | + * string could not be parsed. | |
| 158 | + */ | |
| 159 | + | |
| 160 | + protected JarURLConnection(URL url) throws MalformedURLException { | |
| 161 | + super(url); | |
| 162 | + parseSpecs(url); | |
| 163 | + } | |
| 164 | + | |
| 165 | + /* get the specs for a given url out of the cache, and compute and | |
| 166 | + * cache them if they're not there. | |
| 167 | + */ | |
| 168 | + private void parseSpecs(URL url) throws MalformedURLException { | |
| 169 | + String spec = url.getFile(); | |
| 170 | + | |
| 171 | + int separator = spec.indexOf("!/"); | |
| 172 | + /* | |
| 173 | + * REMIND: we don't handle nested JAR URLs | |
| 174 | + */ | |
| 175 | + if (separator == -1) { | |
| 176 | + throw new MalformedURLException("no !/ found in url spec:" + spec); | |
| 177 | + } | |
| 178 | + | |
| 179 | + jarFileURL = new URL(spec.substring(0, separator++)); | |
| 180 | + entryName = null; | |
| 181 | + | |
| 182 | + /* if ! is the last letter of the innerURL, entryName is null */ | |
| 183 | + if (++separator != spec.length()) { | |
| 184 | + entryName = spec.substring(separator, spec.length()); | |
| 185 | + entryName = ParseUtil.decode (entryName); | |
| 186 | + } | |
| 187 | + } | |
| 188 | + | |
| 189 | + /** | |
| 190 | + * Returns the URL for the Jar file for this connection. | |
| 191 | + * | |
| 192 | + * @return the URL for the Jar file for this connection. | |
| 193 | + */ | |
| 194 | + public URL getJarFileURL() { | |
| 195 | + return jarFileURL; | |
| 196 | + } | |
| 197 | + | |
| 198 | + /** | |
| 199 | + * Return the entry name for this connection. This method | |
| 200 | + * returns null if the JAR file URL corresponding to this | |
| 201 | + * connection points to a JAR file and not a JAR file entry. | |
| 202 | + * | |
| 203 | + * @return the entry name for this connection, if any. | |
| 204 | + */ | |
| 205 | + public String getEntryName() { | |
| 206 | + return entryName; | |
| 207 | + } | |
| 208 | + | |
| 209 | + /** | |
| 210 | + * Return the JAR file for this connection. | |
| 211 | + * | |
| 212 | + * @return the JAR file for this connection. If the connection is | |
| 213 | + * a connection to an entry of a JAR file, the JAR file object is | |
| 214 | + * returned | |
| 215 | + * | |
| 216 | + * @exception IOException if an IOException occurs while trying to | |
| 217 | + * connect to the JAR file for this connection. | |
| 218 | + * | |
| 219 | + * @see #connect | |
| 220 | + */ | |
| 221 | + public abstract JarFile getJarFile() throws IOException; | |
| 222 | + | |
| 223 | + /** | |
| 224 | + * Returns the Manifest for this connection, or null if none. | |
| 225 | + * | |
| 226 | + * @return the manifest object corresponding to the JAR file object | |
| 227 | + * for this connection. | |
| 228 | + * | |
| 229 | + * @exception IOException if getting the JAR file for this | |
| 230 | + * connection causes an IOException to be trown. | |
| 231 | + * | |
| 232 | + * @see #getJarFile | |
| 233 | + */ | |
| 234 | + public Manifest getManifest() throws IOException { | |
| 235 | + return getJarFile().getManifest(); | |
| 236 | + } | |
| 237 | + | |
| 238 | + /** | |
| 239 | + * Return the JAR entry object for this connection, if any. This | |
| 240 | + * method returns null if the JAR file URL corresponding to this | |
| 241 | + * connection points to a JAR file and not a JAR file entry. | |
| 242 | + * | |
| 243 | + * @return the JAR entry object for this connection, or null if | |
| 244 | + * the JAR URL for this connection points to a JAR file. | |
| 245 | + * | |
| 246 | + * @exception IOException if getting the JAR file for this | |
| 247 | + * connection causes an IOException to be trown. | |
| 248 | + * | |
| 249 | + * @see #getJarFile | |
| 250 | + * @see #getJarEntry | |
| 251 | + */ | |
| 252 | + public JarEntry getJarEntry() throws IOException { | |
| 253 | + return getJarFile().getJarEntry(entryName); | |
| 254 | + } | |
| 255 | + | |
| 256 | + /** | |
| 257 | + * Return the Attributes object for this connection if the URL | |
| 258 | + * for it points to a JAR file entry, null otherwise. | |
| 259 | + * | |
| 260 | + * @return the Attributes object for this connection if the URL | |
| 261 | + * for it points to a JAR file entry, null otherwise. | |
| 262 | + * | |
| 263 | + * @exception IOException if getting the JAR entry causes an | |
| 264 | + * IOException to be thrown. | |
| 265 | + * | |
| 266 | + * @see #getJarEntry | |
| 267 | + */ | |
| 268 | + public Attributes getAttributes() throws IOException { | |
| 269 | + JarEntry e = getJarEntry(); | |
| 270 | + return e != null ? e.getAttributes() : null; | |
| 271 | + } | |
| 272 | + | |
| 273 | + /** | |
| 274 | + * Returns the main Attributes for the JAR file for this | |
| 275 | + * connection. | |
| 276 | + * | |
| 277 | + * @return the main Attributes for the JAR file for this | |
| 278 | + * connection. | |
| 279 | + * | |
| 280 | + * @exception IOException if getting the manifest causes an | |
| 281 | + * IOException to be thrown. | |
| 282 | + * | |
| 283 | + * @see #getJarFile | |
| 284 | + * @see #getManifest | |
| 285 | + */ | |
| 286 | + public Attributes getMainAttributes() throws IOException { | |
| 287 | + Manifest man = getManifest(); | |
| 288 | + return man != null ? man.getMainAttributes() : null; | |
| 289 | + } | |
| 290 | + | |
| 291 | + /** | |
| 292 | + * Return the Certificate object for this connection if the URL | |
| 293 | + * for it points to a JAR file entry, null otherwise. This method | |
| 294 | + * can only be called once | |
| 295 | + * the connection has been completely verified by reading | |
| 296 | + * from the input stream until the end of the stream has been | |
| 297 | + * reached. Otherwise, this method will return <code>null</code> | |
| 298 | + * | |
| 299 | + * @return the Certificate object for this connection if the URL | |
| 300 | + * for it points to a JAR file entry, null otherwise. | |
| 301 | + * | |
| 302 | + * @exception IOException if getting the JAR entry causes an | |
| 303 | + * IOException to be thrown. | |
| 304 | + * | |
| 305 | + * @see #getJarEntry | |
| 306 | + */ | |
| 307 | + public java.security.cert.Certificate[] getCertificates() | |
| 308 | + throws IOException | |
| 309 | + { | |
| 310 | + JarEntry e = getJarEntry(); | |
| 311 | + return e != null ? e.getCertificates() : null; | |
| 312 | + } | |
| 313 | +} | |
Binary file not shown.
| @@ -0,0 +1,56 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * Thrown to indicate that a malformed URL has occurred. Either no | |
| 32 | + * legal protocol could be found in a specification string or the | |
| 33 | + * string could not be parsed. | |
| 34 | + * | |
| 35 | + * @author Arthur van Hoff | |
| 36 | + * @since JDK1.0 | |
| 37 | + */ | |
| 38 | +public class MalformedURLException extends IOException { | |
| 39 | + private static final long serialVersionUID = -182787522200415866L; | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * Constructs a <code>MalformedURLException</code> with no detail message. | |
| 43 | + */ | |
| 44 | + public MalformedURLException() { | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Constructs a <code>MalformedURLException</code> with the | |
| 49 | + * specified detail message. | |
| 50 | + * | |
| 51 | + * @param msg the detail message. | |
| 52 | + */ | |
| 53 | + public MalformedURLException(String msg) { | |
| 54 | + super(msg); | |
| 55 | + } | |
| 56 | +} | |
Binary file not shown.
| @@ -0,0 +1,686 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2007, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.io.InterruptedIOException; | |
| 30 | +import java.util.Enumeration; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * The multicast datagram socket class is useful for sending | |
| 34 | + * and receiving IP multicast packets. A MulticastSocket is | |
| 35 | + * a (UDP) DatagramSocket, with additional capabilities for | |
| 36 | + * joining "groups" of other multicast hosts on the internet. | |
| 37 | + * <P> | |
| 38 | + * A multicast group is specified by a class D IP address | |
| 39 | + * and by a standard UDP port number. Class D IP addresses | |
| 40 | + * are in the range <CODE>224.0.0.0</CODE> to <CODE>239.255.255.255</CODE>, | |
| 41 | + * inclusive. The address 224.0.0.0 is reserved and should not be used. | |
| 42 | + * <P> | |
| 43 | + * One would join a multicast group by first creating a MulticastSocket | |
| 44 | + * with the desired port, then invoking the | |
| 45 | + * <CODE>joinGroup(InetAddress groupAddr)</CODE> | |
| 46 | + * method: | |
| 47 | + * <PRE> | |
| 48 | + * // join a Multicast group and send the group salutations | |
| 49 | + * ... | |
| 50 | + * String msg = "Hello"; | |
| 51 | + * InetAddress group = InetAddress.getByName("228.5.6.7"); | |
| 52 | + * MulticastSocket s = new MulticastSocket(6789); | |
| 53 | + * s.joinGroup(group); | |
| 54 | + * DatagramPacket hi = new DatagramPacket(msg.getBytes(), msg.length(), | |
| 55 | + * group, 6789); | |
| 56 | + * s.send(hi); | |
| 57 | + * // get their responses! | |
| 58 | + * byte[] buf = new byte[1000]; | |
| 59 | + * DatagramPacket recv = new DatagramPacket(buf, buf.length); | |
| 60 | + * s.receive(recv); | |
| 61 | + * ... | |
| 62 | + * // OK, I'm done talking - leave the group... | |
| 63 | + * s.leaveGroup(group); | |
| 64 | + * </PRE> | |
| 65 | + * | |
| 66 | + * When one sends a message to a multicast group, <B>all</B> subscribing | |
| 67 | + * recipients to that host and port receive the message (within the | |
| 68 | + * time-to-live range of the packet, see below). The socket needn't | |
| 69 | + * be a member of the multicast group to send messages to it. | |
| 70 | + * <P> | |
| 71 | + * When a socket subscribes to a multicast group/port, it receives | |
| 72 | + * datagrams sent by other hosts to the group/port, as do all other | |
| 73 | + * members of the group and port. A socket relinquishes membership | |
| 74 | + * in a group by the leaveGroup(InetAddress addr) method. <B> | |
| 75 | + * Multiple MulticastSocket's</B> may subscribe to a multicast group | |
| 76 | + * and port concurrently, and they will all receive group datagrams. | |
| 77 | + * <P> | |
| 78 | + * Currently applets are not allowed to use multicast sockets. | |
| 79 | + * | |
| 80 | + * @author Pavani Diwanji | |
| 81 | + * @since JDK1.1 | |
| 82 | + */ | |
| 83 | +public | |
| 84 | +class MulticastSocket extends DatagramSocket { | |
| 85 | + /** | |
| 86 | + * Create a multicast socket. | |
| 87 | + * | |
| 88 | + * <p>If there is a security manager, | |
| 89 | + * its <code>checkListen</code> method is first called | |
| 90 | + * with 0 as its argument to ensure the operation is allowed. | |
| 91 | + * This could result in a SecurityException. | |
| 92 | + * <p> | |
| 93 | + * When the socket is created the | |
| 94 | + * {@link DatagramSocket#setReuseAddress(boolean)} method is | |
| 95 | + * called to enable the SO_REUSEADDR socket option. | |
| 96 | + * | |
| 97 | + * @exception IOException if an I/O exception occurs | |
| 98 | + * while creating the MulticastSocket | |
| 99 | + * @exception SecurityException if a security manager exists and its | |
| 100 | + * <code>checkListen</code> method doesn't allow the operation. | |
| 101 | + * @see SecurityManager#checkListen | |
| 102 | + * @see java.net.DatagramSocket#setReuseAddress(boolean) | |
| 103 | + */ | |
| 104 | + public MulticastSocket() throws IOException { | |
| 105 | + this(new InetSocketAddress(0)); | |
| 106 | + } | |
| 107 | + | |
| 108 | + /** | |
| 109 | + * Create a multicast socket and bind it to a specific port. | |
| 110 | + * | |
| 111 | + * <p>If there is a security manager, | |
| 112 | + * its <code>checkListen</code> method is first called | |
| 113 | + * with the <code>port</code> argument | |
| 114 | + * as its argument to ensure the operation is allowed. | |
| 115 | + * This could result in a SecurityException. | |
| 116 | + * <p> | |
| 117 | + * When the socket is created the | |
| 118 | + * {@link DatagramSocket#setReuseAddress(boolean)} method is | |
| 119 | + * called to enable the SO_REUSEADDR socket option. | |
| 120 | + * | |
| 121 | + * @param port port to use | |
| 122 | + * @exception IOException if an I/O exception occurs | |
| 123 | + * while creating the MulticastSocket | |
| 124 | + * @exception SecurityException if a security manager exists and its | |
| 125 | + * <code>checkListen</code> method doesn't allow the operation. | |
| 126 | + * @see SecurityManager#checkListen | |
| 127 | + * @see java.net.DatagramSocket#setReuseAddress(boolean) | |
| 128 | + */ | |
| 129 | + public MulticastSocket(int port) throws IOException { | |
| 130 | + this(new InetSocketAddress(port)); | |
| 131 | + } | |
| 132 | + | |
| 133 | + /** | |
| 134 | + * Create a MulticastSocket bound to the specified socket address. | |
| 135 | + * <p> | |
| 136 | + * Or, if the address is <code>null</code>, create an unbound socket. | |
| 137 | + * <p> | |
| 138 | + * <p>If there is a security manager, | |
| 139 | + * its <code>checkListen</code> method is first called | |
| 140 | + * with the SocketAddress port as its argument to ensure the operation is allowed. | |
| 141 | + * This could result in a SecurityException. | |
| 142 | + * <p> | |
| 143 | + * When the socket is created the | |
| 144 | + * {@link DatagramSocket#setReuseAddress(boolean)} method is | |
| 145 | + * called to enable the SO_REUSEADDR socket option. | |
| 146 | + * | |
| 147 | + * @param bindaddr Socket address to bind to, or <code>null</code> for | |
| 148 | + * an unbound socket. | |
| 149 | + * @exception IOException if an I/O exception occurs | |
| 150 | + * while creating the MulticastSocket | |
| 151 | + * @exception SecurityException if a security manager exists and its | |
| 152 | + * <code>checkListen</code> method doesn't allow the operation. | |
| 153 | + * @see SecurityManager#checkListen | |
| 154 | + * @see java.net.DatagramSocket#setReuseAddress(boolean) | |
| 155 | + * | |
| 156 | + * @since 1.4 | |
| 157 | + */ | |
| 158 | + public MulticastSocket(SocketAddress bindaddr) throws IOException { | |
| 159 | + super((SocketAddress) null); | |
| 160 | + | |
| 161 | + // Enable SO_REUSEADDR before binding | |
| 162 | + setReuseAddress(true); | |
| 163 | + | |
| 164 | + if (bindaddr != null) { | |
| 165 | + bind(bindaddr); | |
| 166 | + } | |
| 167 | + } | |
| 168 | + | |
| 169 | + /** | |
| 170 | + * The lock on the socket's TTL. This is for set/getTTL and | |
| 171 | + * send(packet,ttl). | |
| 172 | + */ | |
| 173 | + private Object ttlLock = new Object(); | |
| 174 | + | |
| 175 | + /** | |
| 176 | + * The lock on the socket's interface - used by setInterface | |
| 177 | + * and getInterface | |
| 178 | + */ | |
| 179 | + private Object infLock = new Object(); | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * The "last" interface set by setInterface on this MulticastSocket | |
| 183 | + */ | |
| 184 | + private InetAddress infAddress = null; | |
| 185 | + | |
| 186 | + | |
| 187 | + /** | |
| 188 | + * Set the default time-to-live for multicast packets sent out | |
| 189 | + * on this <code>MulticastSocket</code> in order to control the | |
| 190 | + * scope of the multicasts. | |
| 191 | + * | |
| 192 | + * <p>The ttl is an <b>unsigned</b> 8-bit quantity, and so <B>must</B> be | |
| 193 | + * in the range <code> 0 <= ttl <= 0xFF </code>. | |
| 194 | + * | |
| 195 | + * @param ttl the time-to-live | |
| 196 | + * @exception IOException if an I/O exception occurs | |
| 197 | + * while setting the default time-to-live value | |
| 198 | + * @deprecated use the setTimeToLive method instead, which uses | |
| 199 | + * <b>int</b> instead of <b>byte</b> as the type for ttl. | |
| 200 | + * @see #getTTL() | |
| 201 | + */ | |
| 202 | + @Deprecated | |
| 203 | + public void setTTL(byte ttl) throws IOException { | |
| 204 | + if (isClosed()) | |
| 205 | + throw new SocketException("Socket is closed"); | |
| 206 | + getImpl().setTTL(ttl); | |
| 207 | + } | |
| 208 | + | |
| 209 | + /** | |
| 210 | + * Set the default time-to-live for multicast packets sent out | |
| 211 | + * on this {@code MulticastSocket} in order to control the | |
| 212 | + * scope of the multicasts. | |
| 213 | + * | |
| 214 | + * <P> The ttl <B>must</B> be in the range {@code 0 <= ttl <= | |
| 215 | + * 255} or an {@code IllegalArgumentException} will be thrown. | |
| 216 | + * Multicast packets sent with a TTL of {@code 0} are not transmitted | |
| 217 | + * on the network but may be delivered locally. | |
| 218 | + * | |
| 219 | + * @param ttl | |
| 220 | + * the time-to-live | |
| 221 | + * | |
| 222 | + * @throws IOException | |
| 223 | + * if an I/O exception occurs while setting the | |
| 224 | + * default time-to-live value | |
| 225 | + * | |
| 226 | + * @see #getTimeToLive() | |
| 227 | + */ | |
| 228 | + public void setTimeToLive(int ttl) throws IOException { | |
| 229 | + if (ttl < 0 || ttl > 255) { | |
| 230 | + throw new IllegalArgumentException("ttl out of range"); | |
| 231 | + } | |
| 232 | + if (isClosed()) | |
| 233 | + throw new SocketException("Socket is closed"); | |
| 234 | + getImpl().setTimeToLive(ttl); | |
| 235 | + } | |
| 236 | + | |
| 237 | + /** | |
| 238 | + * Get the default time-to-live for multicast packets sent out on | |
| 239 | + * the socket. | |
| 240 | + * | |
| 241 | + * @exception IOException if an I/O exception occurs | |
| 242 | + * while getting the default time-to-live value | |
| 243 | + * @return the default time-to-live value | |
| 244 | + * @deprecated use the getTimeToLive method instead, which returns | |
| 245 | + * an <b>int</b> instead of a <b>byte</b>. | |
| 246 | + * @see #setTTL(byte) | |
| 247 | + */ | |
| 248 | + @Deprecated | |
| 249 | + public byte getTTL() throws IOException { | |
| 250 | + if (isClosed()) | |
| 251 | + throw new SocketException("Socket is closed"); | |
| 252 | + return getImpl().getTTL(); | |
| 253 | + } | |
| 254 | + | |
| 255 | + /** | |
| 256 | + * Get the default time-to-live for multicast packets sent out on | |
| 257 | + * the socket. | |
| 258 | + * @exception IOException if an I/O exception occurs while | |
| 259 | + * getting the default time-to-live value | |
| 260 | + * @return the default time-to-live value | |
| 261 | + * @see #setTimeToLive(int) | |
| 262 | + */ | |
| 263 | + public int getTimeToLive() throws IOException { | |
| 264 | + if (isClosed()) | |
| 265 | + throw new SocketException("Socket is closed"); | |
| 266 | + return getImpl().getTimeToLive(); | |
| 267 | + } | |
| 268 | + | |
| 269 | + /** | |
| 270 | + * Joins a multicast group. Its behavior may be affected by | |
| 271 | + * <code>setInterface</code> or <code>setNetworkInterface</code>. | |
| 272 | + * | |
| 273 | + * <p>If there is a security manager, this method first | |
| 274 | + * calls its <code>checkMulticast</code> method | |
| 275 | + * with the <code>mcastaddr</code> argument | |
| 276 | + * as its argument. | |
| 277 | + * | |
| 278 | + * @param mcastaddr is the multicast address to join | |
| 279 | + * | |
| 280 | + * @exception IOException if there is an error joining | |
| 281 | + * or when the address is not a multicast address. | |
| 282 | + * @exception SecurityException if a security manager exists and its | |
| 283 | + * <code>checkMulticast</code> method doesn't allow the join. | |
| 284 | + * | |
| 285 | + * @see SecurityManager#checkMulticast(InetAddress) | |
| 286 | + */ | |
| 287 | + public void joinGroup(InetAddress mcastaddr) throws IOException { | |
| 288 | + if (isClosed()) { | |
| 289 | + throw new SocketException("Socket is closed"); | |
| 290 | + } | |
| 291 | + | |
| 292 | + checkAddress(mcastaddr, "joinGroup"); | |
| 293 | + SecurityManager security = System.getSecurityManager(); | |
| 294 | + if (security != null) { | |
| 295 | + security.checkMulticast(mcastaddr); | |
| 296 | + } | |
| 297 | + | |
| 298 | + if (!mcastaddr.isMulticastAddress()) { | |
| 299 | + throw new SocketException("Not a multicast address"); | |
| 300 | + } | |
| 301 | + | |
| 302 | + getImpl().join(mcastaddr); | |
| 303 | + } | |
| 304 | + | |
| 305 | + /** | |
| 306 | + * Leave a multicast group. Its behavior may be affected by | |
| 307 | + * <code>setInterface</code> or <code>setNetworkInterface</code>. | |
| 308 | + * | |
| 309 | + * <p>If there is a security manager, this method first | |
| 310 | + * calls its <code>checkMulticast</code> method | |
| 311 | + * with the <code>mcastaddr</code> argument | |
| 312 | + * as its argument. | |
| 313 | + * | |
| 314 | + * @param mcastaddr is the multicast address to leave | |
| 315 | + * @exception IOException if there is an error leaving | |
| 316 | + * or when the address is not a multicast address. | |
| 317 | + * @exception SecurityException if a security manager exists and its | |
| 318 | + * <code>checkMulticast</code> method doesn't allow the operation. | |
| 319 | + * | |
| 320 | + * @see SecurityManager#checkMulticast(InetAddress) | |
| 321 | + */ | |
| 322 | + public void leaveGroup(InetAddress mcastaddr) throws IOException { | |
| 323 | + if (isClosed()) { | |
| 324 | + throw new SocketException("Socket is closed"); | |
| 325 | + } | |
| 326 | + | |
| 327 | + checkAddress(mcastaddr, "leaveGroup"); | |
| 328 | + SecurityManager security = System.getSecurityManager(); | |
| 329 | + if (security != null) { | |
| 330 | + security.checkMulticast(mcastaddr); | |
| 331 | + } | |
| 332 | + | |
| 333 | + if (!mcastaddr.isMulticastAddress()) { | |
| 334 | + throw new SocketException("Not a multicast address"); | |
| 335 | + } | |
| 336 | + | |
| 337 | + getImpl().leave(mcastaddr); | |
| 338 | + } | |
| 339 | + | |
| 340 | + /** | |
| 341 | + * Joins the specified multicast group at the specified interface. | |
| 342 | + * | |
| 343 | + * <p>If there is a security manager, this method first | |
| 344 | + * calls its <code>checkMulticast</code> method | |
| 345 | + * with the <code>mcastaddr</code> argument | |
| 346 | + * as its argument. | |
| 347 | + * | |
| 348 | + * @param mcastaddr is the multicast address to join | |
| 349 | + * @param netIf specifies the local interface to receive multicast | |
| 350 | + * datagram packets, or <i>null</i> to defer to the interface set by | |
| 351 | + * {@link MulticastSocket#setInterface(InetAddress)} or | |
| 352 | + * {@link MulticastSocket#setNetworkInterface(NetworkInterface)} | |
| 353 | + * | |
| 354 | + * @exception IOException if there is an error joining | |
| 355 | + * or when the address is not a multicast address. | |
| 356 | + * @exception SecurityException if a security manager exists and its | |
| 357 | + * <code>checkMulticast</code> method doesn't allow the join. | |
| 358 | + * @throws IllegalArgumentException if mcastaddr is null or is a | |
| 359 | + * SocketAddress subclass not supported by this socket | |
| 360 | + * | |
| 361 | + * @see SecurityManager#checkMulticast(InetAddress) | |
| 362 | + * @since 1.4 | |
| 363 | + */ | |
| 364 | + public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) | |
| 365 | + throws IOException { | |
| 366 | + if (isClosed()) | |
| 367 | + throw new SocketException("Socket is closed"); | |
| 368 | + | |
| 369 | + if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) | |
| 370 | + throw new IllegalArgumentException("Unsupported address type"); | |
| 371 | + | |
| 372 | + if (oldImpl) | |
| 373 | + throw new UnsupportedOperationException(); | |
| 374 | + | |
| 375 | + checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "joinGroup"); | |
| 376 | + SecurityManager security = System.getSecurityManager(); | |
| 377 | + if (security != null) { | |
| 378 | + security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress()); | |
| 379 | + } | |
| 380 | + | |
| 381 | + if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) { | |
| 382 | + throw new SocketException("Not a multicast address"); | |
| 383 | + } | |
| 384 | + | |
| 385 | + getImpl().joinGroup(mcastaddr, netIf); | |
| 386 | + } | |
| 387 | + | |
| 388 | + /** | |
| 389 | + * Leave a multicast group on a specified local interface. | |
| 390 | + * | |
| 391 | + * <p>If there is a security manager, this method first | |
| 392 | + * calls its <code>checkMulticast</code> method | |
| 393 | + * with the <code>mcastaddr</code> argument | |
| 394 | + * as its argument. | |
| 395 | + * | |
| 396 | + * @param mcastaddr is the multicast address to leave | |
| 397 | + * @param netIf specifies the local interface or <i>null</i> to defer | |
| 398 | + * to the interface set by | |
| 399 | + * {@link MulticastSocket#setInterface(InetAddress)} or | |
| 400 | + * {@link MulticastSocket#setNetworkInterface(NetworkInterface)} | |
| 401 | + * @exception IOException if there is an error leaving | |
| 402 | + * or when the address is not a multicast address. | |
| 403 | + * @exception SecurityException if a security manager exists and its | |
| 404 | + * <code>checkMulticast</code> method doesn't allow the operation. | |
| 405 | + * @throws IllegalArgumentException if mcastaddr is null or is a | |
| 406 | + * SocketAddress subclass not supported by this socket | |
| 407 | + * | |
| 408 | + * @see SecurityManager#checkMulticast(InetAddress) | |
| 409 | + * @since 1.4 | |
| 410 | + */ | |
| 411 | + public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) | |
| 412 | + throws IOException { | |
| 413 | + if (isClosed()) | |
| 414 | + throw new SocketException("Socket is closed"); | |
| 415 | + | |
| 416 | + if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) | |
| 417 | + throw new IllegalArgumentException("Unsupported address type"); | |
| 418 | + | |
| 419 | + if (oldImpl) | |
| 420 | + throw new UnsupportedOperationException(); | |
| 421 | + | |
| 422 | + checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "leaveGroup"); | |
| 423 | + SecurityManager security = System.getSecurityManager(); | |
| 424 | + if (security != null) { | |
| 425 | + security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress()); | |
| 426 | + } | |
| 427 | + | |
| 428 | + if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) { | |
| 429 | + throw new SocketException("Not a multicast address"); | |
| 430 | + } | |
| 431 | + | |
| 432 | + getImpl().leaveGroup(mcastaddr, netIf); | |
| 433 | + } | |
| 434 | + | |
| 435 | + /** | |
| 436 | + * Set the multicast network interface used by methods | |
| 437 | + * whose behavior would be affected by the value of the | |
| 438 | + * network interface. Useful for multihomed hosts. | |
| 439 | + * @param inf the InetAddress | |
| 440 | + * @exception SocketException if there is an error in | |
| 441 | + * the underlying protocol, such as a TCP error. | |
| 442 | + * @see #getInterface() | |
| 443 | + */ | |
| 444 | + public void setInterface(InetAddress inf) throws SocketException { | |
| 445 | + if (isClosed()) { | |
| 446 | + throw new SocketException("Socket is closed"); | |
| 447 | + } | |
| 448 | + checkAddress(inf, "setInterface"); | |
| 449 | + synchronized (infLock) { | |
| 450 | + getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf); | |
| 451 | + infAddress = inf; | |
| 452 | + } | |
| 453 | + } | |
| 454 | + | |
| 455 | + /** | |
| 456 | + * Retrieve the address of the network interface used for | |
| 457 | + * multicast packets. | |
| 458 | + * | |
| 459 | + * @return An <code>InetAddress</code> representing | |
| 460 | + * the address of the network interface used for | |
| 461 | + * multicast packets. | |
| 462 | + * | |
| 463 | + * @exception SocketException if there is an error in | |
| 464 | + * the underlying protocol, such as a TCP error. | |
| 465 | + * | |
| 466 | + * @see #setInterface(java.net.InetAddress) | |
| 467 | + */ | |
| 468 | + public InetAddress getInterface() throws SocketException { | |
| 469 | + if (isClosed()) { | |
| 470 | + throw new SocketException("Socket is closed"); | |
| 471 | + } | |
| 472 | + synchronized (infLock) { | |
| 473 | + InetAddress ia = | |
| 474 | + (InetAddress)getImpl().getOption(SocketOptions.IP_MULTICAST_IF); | |
| 475 | + | |
| 476 | + /** | |
| 477 | + * No previous setInterface or interface can be | |
| 478 | + * set using setNetworkInterface | |
| 479 | + */ | |
| 480 | + if (infAddress == null) { | |
| 481 | + return ia; | |
| 482 | + } | |
| 483 | + | |
| 484 | + /** | |
| 485 | + * Same interface set with setInterface? | |
| 486 | + */ | |
| 487 | + if (ia.equals(infAddress)) { | |
| 488 | + return ia; | |
| 489 | + } | |
| 490 | + | |
| 491 | + /** | |
| 492 | + * Different InetAddress from what we set with setInterface | |
| 493 | + * so enumerate the current interface to see if the | |
| 494 | + * address set by setInterface is bound to this interface. | |
| 495 | + */ | |
| 496 | + try { | |
| 497 | + NetworkInterface ni = NetworkInterface.getByInetAddress(ia); | |
| 498 | + Enumeration addrs = ni.getInetAddresses(); | |
| 499 | + while (addrs.hasMoreElements()) { | |
| 500 | + InetAddress addr = (InetAddress)(addrs.nextElement()); | |
| 501 | + if (addr.equals(infAddress)) { | |
| 502 | + return infAddress; | |
| 503 | + } | |
| 504 | + } | |
| 505 | + | |
| 506 | + /** | |
| 507 | + * No match so reset infAddress to indicate that the | |
| 508 | + * interface has changed via means | |
| 509 | + */ | |
| 510 | + infAddress = null; | |
| 511 | + return ia; | |
| 512 | + } catch (Exception e) { | |
| 513 | + return ia; | |
| 514 | + } | |
| 515 | + } | |
| 516 | + } | |
| 517 | + | |
| 518 | + /** | |
| 519 | + * Specify the network interface for outgoing multicast datagrams | |
| 520 | + * sent on this socket. | |
| 521 | + * | |
| 522 | + * @param netIf the interface | |
| 523 | + * @exception SocketException if there is an error in | |
| 524 | + * the underlying protocol, such as a TCP error. | |
| 525 | + * @see #getNetworkInterface() | |
| 526 | + * @since 1.4 | |
| 527 | + */ | |
| 528 | + public void setNetworkInterface(NetworkInterface netIf) | |
| 529 | + throws SocketException { | |
| 530 | + | |
| 531 | + synchronized (infLock) { | |
| 532 | + getImpl().setOption(SocketOptions.IP_MULTICAST_IF2, netIf); | |
| 533 | + infAddress = null; | |
| 534 | + } | |
| 535 | + } | |
| 536 | + | |
| 537 | + /** | |
| 538 | + * Get the multicast network interface set. | |
| 539 | + * | |
| 540 | + * @exception SocketException if there is an error in | |
| 541 | + * the underlying protocol, such as a TCP error. | |
| 542 | + * @return the multicast <code>NetworkInterface</code> currently set | |
| 543 | + * @see #setNetworkInterface(NetworkInterface) | |
| 544 | + * @since 1.4 | |
| 545 | + */ | |
| 546 | + public NetworkInterface getNetworkInterface() throws SocketException { | |
| 547 | + NetworkInterface ni | |
| 548 | + = (NetworkInterface)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2); | |
| 549 | + if (ni.getIndex() == 0) { | |
| 550 | + InetAddress[] addrs = new InetAddress[1]; | |
| 551 | + addrs[0] = InetAddress.anyLocalAddress(); | |
| 552 | + return new NetworkInterface(addrs[0].getHostName(), 0, addrs); | |
| 553 | + } else { | |
| 554 | + return ni; | |
| 555 | + } | |
| 556 | + } | |
| 557 | + | |
| 558 | + /** | |
| 559 | + * Disable/Enable local loopback of multicast datagrams | |
| 560 | + * The option is used by the platform's networking code as a hint | |
| 561 | + * for setting whether multicast data will be looped back to | |
| 562 | + * the local socket. | |
| 563 | + * | |
| 564 | + * <p>Because this option is a hint, applications that want to | |
| 565 | + * verify what loopback mode is set to should call | |
| 566 | + * {@link #getLoopbackMode()} | |
| 567 | + * @param disable <code>true</code> to disable the LoopbackMode | |
| 568 | + * @throws SocketException if an error occurs while setting the value | |
| 569 | + * @since 1.4 | |
| 570 | + * @see #getLoopbackMode | |
| 571 | + */ | |
| 572 | + public void setLoopbackMode(boolean disable) throws SocketException { | |
| 573 | + getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable)); | |
| 574 | + } | |
| 575 | + | |
| 576 | + /** | |
| 577 | + * Get the setting for local loopback of multicast datagrams. | |
| 578 | + * | |
| 579 | + * @throws SocketException if an error occurs while getting the value | |
| 580 | + * @return true if the LoopbackMode has been disabled | |
| 581 | + * @since 1.4 | |
| 582 | + * @see #setLoopbackMode | |
| 583 | + */ | |
| 584 | + public boolean getLoopbackMode() throws SocketException { | |
| 585 | + return ((Boolean)getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP)).booleanValue(); | |
| 586 | + } | |
| 587 | + | |
| 588 | + /** | |
| 589 | + * Sends a datagram packet to the destination, with a TTL (time- | |
| 590 | + * to-live) other than the default for the socket. This method | |
| 591 | + * need only be used in instances where a particular TTL is desired; | |
| 592 | + * otherwise it is preferable to set a TTL once on the socket, and | |
| 593 | + * use that default TTL for all packets. This method does <B>not | |
| 594 | + * </B> alter the default TTL for the socket. Its behavior may be | |
| 595 | + * affected by <code>setInterface</code>. | |
| 596 | + * | |
| 597 | + * <p>If there is a security manager, this method first performs some | |
| 598 | + * security checks. First, if <code>p.getAddress().isMulticastAddress()</code> | |
| 599 | + * is true, this method calls the | |
| 600 | + * security manager's <code>checkMulticast</code> method | |
| 601 | + * with <code>p.getAddress()</code> and <code>ttl</code> as its arguments. | |
| 602 | + * If the evaluation of that expression is false, | |
| 603 | + * this method instead calls the security manager's | |
| 604 | + * <code>checkConnect</code> method with arguments | |
| 605 | + * <code>p.getAddress().getHostAddress()</code> and | |
| 606 | + * <code>p.getPort()</code>. Each call to a security manager method | |
| 607 | + * could result in a SecurityException if the operation is not allowed. | |
| 608 | + * | |
| 609 | + * @param p is the packet to be sent. The packet should contain | |
| 610 | + * the destination multicast ip address and the data to be sent. | |
| 611 | + * One does not need to be the member of the group to send | |
| 612 | + * packets to a destination multicast address. | |
| 613 | + * @param ttl optional time to live for multicast packet. | |
| 614 | + * default ttl is 1. | |
| 615 | + * | |
| 616 | + * @exception IOException is raised if an error occurs i.e | |
| 617 | + * error while setting ttl. | |
| 618 | + * @exception SecurityException if a security manager exists and its | |
| 619 | + * <code>checkMulticast</code> or <code>checkConnect</code> | |
| 620 | + * method doesn't allow the send. | |
| 621 | + * | |
| 622 | + * @deprecated Use the following code or its equivalent instead: | |
| 623 | + * ...... | |
| 624 | + * int ttl = mcastSocket.getTimeToLive(); | |
| 625 | + * mcastSocket.setTimeToLive(newttl); | |
| 626 | + * mcastSocket.send(p); | |
| 627 | + * mcastSocket.setTimeToLive(ttl); | |
| 628 | + * ...... | |
| 629 | + * | |
| 630 | + * @see DatagramSocket#send | |
| 631 | + * @see DatagramSocket#receive | |
| 632 | + * @see SecurityManager#checkMulticast(java.net.InetAddress, byte) | |
| 633 | + * @see SecurityManager#checkConnect | |
| 634 | + */ | |
| 635 | + @Deprecated | |
| 636 | + public void send(DatagramPacket p, byte ttl) | |
| 637 | + throws IOException { | |
| 638 | + if (isClosed()) | |
| 639 | + throw new SocketException("Socket is closed"); | |
| 640 | + checkAddress(p.getAddress(), "send"); | |
| 641 | + synchronized(ttlLock) { | |
| 642 | + synchronized(p) { | |
| 643 | + if (connectState == ST_NOT_CONNECTED) { | |
| 644 | + // Security manager makes sure that the multicast address | |
| 645 | + // is allowed one and that the ttl used is less | |
| 646 | + // than the allowed maxttl. | |
| 647 | + SecurityManager security = System.getSecurityManager(); | |
| 648 | + if (security != null) { | |
| 649 | + if (p.getAddress().isMulticastAddress()) { | |
| 650 | + security.checkMulticast(p.getAddress(), ttl); | |
| 651 | + } else { | |
| 652 | + security.checkConnect(p.getAddress().getHostAddress(), | |
| 653 | + p.getPort()); | |
| 654 | + } | |
| 655 | + } | |
| 656 | + } else { | |
| 657 | + // we're connected | |
| 658 | + InetAddress packetAddress = null; | |
| 659 | + packetAddress = p.getAddress(); | |
| 660 | + if (packetAddress == null) { | |
| 661 | + p.setAddress(connectedAddress); | |
| 662 | + p.setPort(connectedPort); | |
| 663 | + } else if ((!packetAddress.equals(connectedAddress)) || | |
| 664 | + p.getPort() != connectedPort) { | |
| 665 | + throw new SecurityException("connected address and packet address" + | |
| 666 | + " differ"); | |
| 667 | + } | |
| 668 | + } | |
| 669 | + byte dttl = getTTL(); | |
| 670 | + try { | |
| 671 | + if (ttl != dttl) { | |
| 672 | + // set the ttl | |
| 673 | + getImpl().setTTL(ttl); | |
| 674 | + } | |
| 675 | + // call the datagram method to send | |
| 676 | + getImpl().send(p); | |
| 677 | + } finally { | |
| 678 | + // set it back to default | |
| 679 | + if (ttl != dttl) { | |
| 680 | + getImpl().setTTL(dttl); | |
| 681 | + } | |
| 682 | + } | |
| 683 | + } // synch p | |
| 684 | + } //synch ttl | |
| 685 | + } //method | |
| 686 | +} | |
Binary file not shown.
| @@ -0,0 +1,205 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2011, 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 java.net; | |
| 27 | + | |
| 28 | +import java.security.*; | |
| 29 | +import java.util.Enumeration; | |
| 30 | +import java.util.Hashtable; | |
| 31 | +import java.util.StringTokenizer; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * This class is for various network permissions. | |
| 35 | + * A NetPermission contains a name (also referred to as a "target name") but | |
| 36 | + * no actions list; you either have the named permission | |
| 37 | + * or you don't. | |
| 38 | + * <P> | |
| 39 | + * The target name is the name of the network permission (see below). The naming | |
| 40 | + * convention follows the hierarchical property naming convention. | |
| 41 | + * Also, an asterisk | |
| 42 | + * may appear at the end of the name, following a ".", or by itself, to | |
| 43 | + * signify a wildcard match. For example: "foo.*" or "*" is valid, | |
| 44 | + * "*foo" or "a*b" is not valid. | |
| 45 | + * <P> | |
| 46 | + * The following table lists all the possible NetPermission target names, | |
| 47 | + * and for each provides a description of what the permission allows | |
| 48 | + * and a discussion of the risks of granting code the permission. | |
| 49 | + * <P> | |
| 50 | + * | |
| 51 | + * <table border=1 cellpadding=5 summary="Permission target name, what the permission allows, and associated risks"> | |
| 52 | + * <tr> | |
| 53 | + * <th>Permission Target Name</th> | |
| 54 | + * <th>What the Permission Allows</th> | |
| 55 | + * <th>Risks of Allowing this Permission</th> | |
| 56 | + * </tr> | |
| 57 | + * <tr> | |
| 58 | + * <td>allowHttpTrace</td> | |
| 59 | + * <td>The ability to use the HTTP TRACE method in HttpURLConnection.</td> | |
| 60 | + * <td>Malicious code using HTTP TRACE could get access to security sensitive | |
| 61 | + * information in the HTTP headers (such as cookies) that it might not | |
| 62 | + * otherwise have access to.</td> | |
| 63 | + * </tr> | |
| 64 | + * | |
| 65 | + * <tr> | |
| 66 | + * <td>getCookieHandler</td> | |
| 67 | + * <td>The ability to get the cookie handler that processes highly | |
| 68 | + * security sensitive cookie information for an Http session.</td> | |
| 69 | + * <td>Malicious code can get a cookie handler to obtain access to | |
| 70 | + * highly security sensitive cookie information. Some web servers | |
| 71 | + * use cookies to save user private information such as access | |
| 72 | + * control information, or to track user browsing habit.</td> | |
| 73 | + * </tr> | |
| 74 | + * | |
| 75 | + * <tr> | |
| 76 | + * <td>getNetworkInformation</td> | |
| 77 | + * <td>The ability to retrieve all information about local network interfaces.</td> | |
| 78 | + * <td>Malicious code can read information about network hardware such as | |
| 79 | + * MAC addresses, which could be used to construct local IPv6 addresses.</td> | |
| 80 | + * </tr> | |
| 81 | + * | |
| 82 | + * <tr> | |
| 83 | + * <td>getProxySelector</td> | |
| 84 | + * <td>The ability to get the proxy selector used to make decisions | |
| 85 | + * on which proxies to use when making network connections.</td> | |
| 86 | + * <td>Malicious code can get a ProxySelector to discover proxy | |
| 87 | + * hosts and ports on internal networks, which could then become | |
| 88 | + * targets for attack.</td> | |
| 89 | + * </tr> | |
| 90 | + * | |
| 91 | + * <tr> | |
| 92 | + * <td>getResponseCache</td> | |
| 93 | + * <td>The ability to get the response cache that provides | |
| 94 | + * access to a local response cache.</td> | |
| 95 | + * <td>Malicious code getting access to the local response cache | |
| 96 | + * could access security sensitive information.</td> | |
| 97 | + * </tr> | |
| 98 | + * | |
| 99 | + * <tr> | |
| 100 | + * <td>requestPasswordAuthentication</td> | |
| 101 | + * <td>The ability | |
| 102 | + * to ask the authenticator registered with the system for | |
| 103 | + * a password</td> | |
| 104 | + * <td>Malicious code may steal this password.</td> | |
| 105 | + * </tr> | |
| 106 | + * | |
| 107 | + * <tr> | |
| 108 | + * <td>setCookieHandler</td> | |
| 109 | + * <td>The ability to set the cookie handler that processes highly | |
| 110 | + * security sensitive cookie information for an Http session.</td> | |
| 111 | + * <td>Malicious code can set a cookie handler to obtain access to | |
| 112 | + * highly security sensitive cookie information. Some web servers | |
| 113 | + * use cookies to save user private information such as access | |
| 114 | + * control information, or to track user browsing habit.</td> | |
| 115 | + * </tr> | |
| 116 | + * | |
| 117 | + * <tr> | |
| 118 | + * <td>setDefaultAuthenticator</td> | |
| 119 | + * <td>The ability to set the | |
| 120 | + * way authentication information is retrieved when | |
| 121 | + * a proxy or HTTP server asks for authentication</td> | |
| 122 | + * <td>Malicious | |
| 123 | + * code can set an authenticator that monitors and steals user | |
| 124 | + * authentication input as it retrieves the input from the user.</td> | |
| 125 | + * </tr> | |
| 126 | + * | |
| 127 | + * <tr> | |
| 128 | + * <td>setProxySelector</td> | |
| 129 | + * <td>The ability to set the proxy selector used to make decisions | |
| 130 | + * on which proxies to use when making network connections.</td> | |
| 131 | + * <td>Malicious code can set a ProxySelector that directs network | |
| 132 | + * traffic to an arbitrary network host.</td> | |
| 133 | + * </tr> | |
| 134 | + * | |
| 135 | + * <tr> | |
| 136 | + * <td>setResponseCache</td> | |
| 137 | + * <td>The ability to set the response cache that provides access to | |
| 138 | + * a local response cache.</td> | |
| 139 | + * <td>Malicious code getting access to the local response cache | |
| 140 | + * could access security sensitive information, or create false | |
| 141 | + * entries in the response cache.</td> | |
| 142 | + * </tr> | |
| 143 | + * | |
| 144 | + * <tr> | |
| 145 | + * <td>specifyStreamHandler</td> | |
| 146 | + * <td>The ability | |
| 147 | + * to specify a stream handler when constructing a URL</td> | |
| 148 | + * <td>Malicious code may create a URL with resources that it would | |
| 149 | +normally not have access to (like file:/foo/fum/), specifying a | |
| 150 | +stream handler that gets the actual bytes from someplace it does | |
| 151 | +have access to. Thus it might be able to trick the system into | |
| 152 | +creating a ProtectionDomain/CodeSource for a class even though | |
| 153 | +that class really didn't come from that location.</td> | |
| 154 | + * </tr> | |
| 155 | + * </table> | |
| 156 | + * | |
| 157 | + * @see java.security.BasicPermission | |
| 158 | + * @see java.security.Permission | |
| 159 | + * @see java.security.Permissions | |
| 160 | + * @see java.security.PermissionCollection | |
| 161 | + * @see java.lang.SecurityManager | |
| 162 | + * | |
| 163 | + * | |
| 164 | + * @author Marianne Mueller | |
| 165 | + * @author Roland Schemers | |
| 166 | + */ | |
| 167 | + | |
| 168 | +public final class NetPermission extends BasicPermission { | |
| 169 | + private static final long serialVersionUID = -8343910153355041693L; | |
| 170 | + | |
| 171 | + /** | |
| 172 | + * Creates a new NetPermission with the specified name. | |
| 173 | + * The name is the symbolic name of the NetPermission, such as | |
| 174 | + * "setDefaultAuthenticator", etc. An asterisk | |
| 175 | + * may appear at the end of the name, following a ".", or by itself, to | |
| 176 | + * signify a wildcard match. | |
| 177 | + * | |
| 178 | + * @param name the name of the NetPermission. | |
| 179 | + * | |
| 180 | + * @throws NullPointerException if <code>name</code> is <code>null</code>. | |
| 181 | + * @throws IllegalArgumentException if <code>name</code> is empty. | |
| 182 | + */ | |
| 183 | + | |
| 184 | + public NetPermission(String name) | |
| 185 | + { | |
| 186 | + super(name); | |
| 187 | + } | |
| 188 | + | |
| 189 | + /** | |
| 190 | + * Creates a new NetPermission object with the specified name. | |
| 191 | + * The name is the symbolic name of the NetPermission, and the | |
| 192 | + * actions String is currently unused and should be null. | |
| 193 | + * | |
| 194 | + * @param name the name of the NetPermission. | |
| 195 | + * @param actions should be null. | |
| 196 | + * | |
| 197 | + * @throws NullPointerException if <code>name</code> is <code>null</code>. | |
| 198 | + * @throws IllegalArgumentException if <code>name</code> is empty. | |
| 199 | + */ | |
| 200 | + | |
| 201 | + public NetPermission(String name, String actions) | |
| 202 | + { | |
| 203 | + super(name, actions); | |
| 204 | + } | |
| 205 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,554 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 2011, 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 java.net; | |
| 27 | + | |
| 28 | +import java.util.Enumeration; | |
| 29 | +import java.util.NoSuchElementException; | |
| 30 | +import sun.security.action.*; | |
| 31 | +import java.security.AccessController; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * This class represents a Network Interface made up of a name, | |
| 35 | + * and a list of IP addresses assigned to this interface. | |
| 36 | + * It is used to identify the local interface on which a multicast group | |
| 37 | + * is joined. | |
| 38 | + * | |
| 39 | + * Interfaces are normally known by names such as "le0". | |
| 40 | + * | |
| 41 | + * @since 1.4 | |
| 42 | + */ | |
| 43 | +public final class NetworkInterface { | |
| 44 | + private String name; | |
| 45 | + private String displayName; | |
| 46 | + private int index; | |
| 47 | + private InetAddress addrs[]; | |
| 48 | + private InterfaceAddress bindings[]; | |
| 49 | + private NetworkInterface childs[]; | |
| 50 | + private NetworkInterface parent = null; | |
| 51 | + private boolean virtual = false; | |
| 52 | + | |
| 53 | + static { | |
| 54 | + AccessController.doPrivileged(new LoadLibraryAction("net")); | |
| 55 | + init(); | |
| 56 | + } | |
| 57 | + | |
| 58 | + /** | |
| 59 | + * Returns an NetworkInterface object with index set to 0 and name to null. | |
| 60 | + * Setting such an interface on a MulticastSocket will cause the | |
| 61 | + * kernel to choose one interface for sending multicast packets. | |
| 62 | + * | |
| 63 | + */ | |
| 64 | + NetworkInterface() { | |
| 65 | + } | |
| 66 | + | |
| 67 | + NetworkInterface(String name, int index, InetAddress[] addrs) { | |
| 68 | + this.name = name; | |
| 69 | + this.index = index; | |
| 70 | + this.addrs = addrs; | |
| 71 | + } | |
| 72 | + | |
| 73 | + /** | |
| 74 | + * Get the name of this network interface. | |
| 75 | + * | |
| 76 | + * @return the name of this network interface | |
| 77 | + */ | |
| 78 | + public String getName() { | |
| 79 | + return name; | |
| 80 | + } | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * Convenience method to return an Enumeration with all or a | |
| 84 | + * subset of the InetAddresses bound to this network interface. | |
| 85 | + * <p> | |
| 86 | + * If there is a security manager, its <code>checkConnect</code> | |
| 87 | + * method is called for each InetAddress. Only InetAddresses where | |
| 88 | + * the <code>checkConnect</code> doesn't throw a SecurityException | |
| 89 | + * will be returned in the Enumeration. However, if the caller has the | |
| 90 | + * {@link NetPermission}("getNetworkInformation") permission, then all | |
| 91 | + * InetAddresses are returned. | |
| 92 | + * @return an Enumeration object with all or a subset of the InetAddresses | |
| 93 | + * bound to this network interface | |
| 94 | + */ | |
| 95 | + public Enumeration<InetAddress> getInetAddresses() { | |
| 96 | + | |
| 97 | + class checkedAddresses implements Enumeration<InetAddress> { | |
| 98 | + | |
| 99 | + private int i=0, count=0; | |
| 100 | + private InetAddress local_addrs[]; | |
| 101 | + | |
| 102 | + checkedAddresses() { | |
| 103 | + local_addrs = new InetAddress[addrs.length]; | |
| 104 | + boolean trusted = true; | |
| 105 | + | |
| 106 | + SecurityManager sec = System.getSecurityManager(); | |
| 107 | + if (sec != null) { | |
| 108 | + try { | |
| 109 | + sec.checkPermission(new NetPermission("getNetworkInformation")); | |
| 110 | + } catch (SecurityException e) { | |
| 111 | + trusted = false; | |
| 112 | + } | |
| 113 | + } | |
| 114 | + for (int j=0; j<addrs.length; j++) { | |
| 115 | + try { | |
| 116 | + if (sec != null && !trusted) { | |
| 117 | + sec.checkConnect(addrs[j].getHostAddress(), -1); | |
| 118 | + } | |
| 119 | + local_addrs[count++] = addrs[j]; | |
| 120 | + } catch (SecurityException e) { } | |
| 121 | + } | |
| 122 | + | |
| 123 | + } | |
| 124 | + | |
| 125 | + public InetAddress nextElement() { | |
| 126 | + if (i < count) { | |
| 127 | + return local_addrs[i++]; | |
| 128 | + } else { | |
| 129 | + throw new NoSuchElementException(); | |
| 130 | + } | |
| 131 | + } | |
| 132 | + | |
| 133 | + public boolean hasMoreElements() { | |
| 134 | + return (i < count); | |
| 135 | + } | |
| 136 | + } | |
| 137 | + return new checkedAddresses(); | |
| 138 | + | |
| 139 | + } | |
| 140 | + | |
| 141 | + /** | |
| 142 | + * Get a List of all or a subset of the <code>InterfaceAddresses</code> | |
| 143 | + * of this network interface. | |
| 144 | + * <p> | |
| 145 | + * If there is a security manager, its <code>checkConnect</code> | |
| 146 | + * method is called with the InetAddress for each InterfaceAddress. | |
| 147 | + * Only InterfaceAddresses where the <code>checkConnect</code> doesn't throw | |
| 148 | + * a SecurityException will be returned in the List. | |
| 149 | + * | |
| 150 | + * @return a <code>List</code> object with all or a subset of the | |
| 151 | + * InterfaceAddresss of this network interface | |
| 152 | + * @since 1.6 | |
| 153 | + */ | |
| 154 | + public java.util.List<InterfaceAddress> getInterfaceAddresses() { | |
| 155 | + java.util.List<InterfaceAddress> lst = new java.util.ArrayList<InterfaceAddress>(1); | |
| 156 | + SecurityManager sec = System.getSecurityManager(); | |
| 157 | + for (int j=0; j<bindings.length; j++) { | |
| 158 | + try { | |
| 159 | + if (sec != null) { | |
| 160 | + sec.checkConnect(bindings[j].getAddress().getHostAddress(), -1); | |
| 161 | + } | |
| 162 | + lst.add(bindings[j]); | |
| 163 | + } catch (SecurityException e) { } | |
| 164 | + } | |
| 165 | + return lst; | |
| 166 | + } | |
| 167 | + | |
| 168 | + /** | |
| 169 | + * Get an Enumeration with all the subinterfaces (also known as virtual | |
| 170 | + * interfaces) attached to this network interface. | |
| 171 | + * <p> | |
| 172 | + * For instance eth0:1 will be a subinterface to eth0. | |
| 173 | + * | |
| 174 | + * @return an Enumeration object with all of the subinterfaces | |
| 175 | + * of this network interface | |
| 176 | + * @since 1.6 | |
| 177 | + */ | |
| 178 | + public Enumeration<NetworkInterface> getSubInterfaces() { | |
| 179 | + class subIFs implements Enumeration<NetworkInterface> { | |
| 180 | + | |
| 181 | + private int i=0; | |
| 182 | + | |
| 183 | + subIFs() { | |
| 184 | + } | |
| 185 | + | |
| 186 | + public NetworkInterface nextElement() { | |
| 187 | + if (i < childs.length) { | |
| 188 | + return childs[i++]; | |
| 189 | + } else { | |
| 190 | + throw new NoSuchElementException(); | |
| 191 | + } | |
| 192 | + } | |
| 193 | + | |
| 194 | + public boolean hasMoreElements() { | |
| 195 | + return (i < childs.length); | |
| 196 | + } | |
| 197 | + } | |
| 198 | + return new subIFs(); | |
| 199 | + | |
| 200 | + } | |
| 201 | + | |
| 202 | + /** | |
| 203 | + * Returns the parent NetworkInterface of this interface if this is | |
| 204 | + * a subinterface, or <code>null</code> if it is a physical | |
| 205 | + * (non virtual) interface or has no parent. | |
| 206 | + * | |
| 207 | + * @return The <code>NetworkInterface</code> this interface is attached to. | |
| 208 | + * @since 1.6 | |
| 209 | + */ | |
| 210 | + public NetworkInterface getParent() { | |
| 211 | + return parent; | |
| 212 | + } | |
| 213 | + | |
| 214 | + /** | |
| 215 | + * Returns the index of this network interface. The index is an integer greater | |
| 216 | + * or equal to zero, or {@code -1} for unknown. This is a system specific value | |
| 217 | + * and interfaces with the same name can have different indexes on different | |
| 218 | + * machines. | |
| 219 | + * | |
| 220 | + * @return the index of this network interface or {@code -1} if the index is | |
| 221 | + * unknown | |
| 222 | + * @see #getByIndex(int) | |
| 223 | + * @since 1.7 | |
| 224 | + */ | |
| 225 | + public int getIndex() { | |
| 226 | + return index; | |
| 227 | + } | |
| 228 | + | |
| 229 | + /** | |
| 230 | + * Get the display name of this network interface. | |
| 231 | + * A display name is a human readable String describing the network | |
| 232 | + * device. | |
| 233 | + * | |
| 234 | + * @return a non-empty string representing the display name of this network | |
| 235 | + * interface, or null if no display name is available. | |
| 236 | + */ | |
| 237 | + public String getDisplayName() { | |
| 238 | + /* strict TCK conformance */ | |
| 239 | + return "".equals(displayName) ? null : displayName; | |
| 240 | + } | |
| 241 | + | |
| 242 | + /** | |
| 243 | + * Searches for the network interface with the specified name. | |
| 244 | + * | |
| 245 | + * @param name | |
| 246 | + * The name of the network interface. | |
| 247 | + * | |
| 248 | + * @return A <tt>NetworkInterface</tt> with the specified name, | |
| 249 | + * or <tt>null</tt> if there is no network interface | |
| 250 | + * with the specified name. | |
| 251 | + * | |
| 252 | + * @throws SocketException | |
| 253 | + * If an I/O error occurs. | |
| 254 | + * | |
| 255 | + * @throws NullPointerException | |
| 256 | + * If the specified name is <tt>null</tt>. | |
| 257 | + */ | |
| 258 | + public static NetworkInterface getByName(String name) throws SocketException { | |
| 259 | + if (name == null) | |
| 260 | + throw new NullPointerException(); | |
| 261 | + return getByName0(name); | |
| 262 | + } | |
| 263 | + | |
| 264 | + /** | |
| 265 | + * Get a network interface given its index. | |
| 266 | + * | |
| 267 | + * @param index an integer, the index of the interface | |
| 268 | + * @return the NetworkInterface obtained from its index, or {@code null} if | |
| 269 | + * there is no interface with such an index on the system | |
| 270 | + * @throws SocketException if an I/O error occurs. | |
| 271 | + * @throws IllegalArgumentException if index has a negative value | |
| 272 | + * @see #getIndex() | |
| 273 | + * @since 1.7 | |
| 274 | + */ | |
| 275 | + public static NetworkInterface getByIndex(int index) throws SocketException { | |
| 276 | + if (index < 0) | |
| 277 | + throw new IllegalArgumentException("Interface index can't be negative"); | |
| 278 | + return getByIndex0(index); | |
| 279 | + } | |
| 280 | + | |
| 281 | + /** | |
| 282 | + * Convenience method to search for a network interface that | |
| 283 | + * has the specified Internet Protocol (IP) address bound to | |
| 284 | + * it. | |
| 285 | + * <p> | |
| 286 | + * If the specified IP address is bound to multiple network | |
| 287 | + * interfaces it is not defined which network interface is | |
| 288 | + * returned. | |
| 289 | + * | |
| 290 | + * @param addr | |
| 291 | + * The <tt>InetAddress</tt> to search with. | |
| 292 | + * | |
| 293 | + * @return A <tt>NetworkInterface</tt> | |
| 294 | + * or <tt>null</tt> if there is no network interface | |
| 295 | + * with the specified IP address. | |
| 296 | + * | |
| 297 | + * @throws SocketException | |
| 298 | + * If an I/O error occurs. | |
| 299 | + * | |
| 300 | + * @throws NullPointerException | |
| 301 | + * If the specified address is <tt>null</tt>. | |
| 302 | + */ | |
| 303 | + public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketException { | |
| 304 | + if (addr == null) { | |
| 305 | + throw new NullPointerException(); | |
| 306 | + } | |
| 307 | + if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) { | |
| 308 | + throw new IllegalArgumentException ("invalid address type"); | |
| 309 | + } | |
| 310 | + return getByInetAddress0(addr); | |
| 311 | + } | |
| 312 | + | |
| 313 | + /** | |
| 314 | + * Returns all the interfaces on this machine. Returns null if no | |
| 315 | + * network interfaces could be found on this machine. | |
| 316 | + * | |
| 317 | + * NOTE: can use getNetworkInterfaces()+getInetAddresses() | |
| 318 | + * to obtain all IP addresses for this node | |
| 319 | + * | |
| 320 | + * @return an Enumeration of NetworkInterfaces found on this machine | |
| 321 | + * @exception SocketException if an I/O error occurs. | |
| 322 | + */ | |
| 323 | + | |
| 324 | + public static Enumeration<NetworkInterface> getNetworkInterfaces() | |
| 325 | + throws SocketException { | |
| 326 | + final NetworkInterface[] netifs = getAll(); | |
| 327 | + | |
| 328 | + // specified to return null if no network interfaces | |
| 329 | + if (netifs == null) | |
| 330 | + return null; | |
| 331 | + | |
| 332 | + return new Enumeration<NetworkInterface>() { | |
| 333 | + private int i = 0; | |
| 334 | + public NetworkInterface nextElement() { | |
| 335 | + if (netifs != null && i < netifs.length) { | |
| 336 | + NetworkInterface netif = netifs[i++]; | |
| 337 | + return netif; | |
| 338 | + } else { | |
| 339 | + throw new NoSuchElementException(); | |
| 340 | + } | |
| 341 | + } | |
| 342 | + | |
| 343 | + public boolean hasMoreElements() { | |
| 344 | + return (netifs != null && i < netifs.length); | |
| 345 | + } | |
| 346 | + }; | |
| 347 | + } | |
| 348 | + | |
| 349 | + private native static NetworkInterface[] getAll() | |
| 350 | + throws SocketException; | |
| 351 | + | |
| 352 | + private native static NetworkInterface getByName0(String name) | |
| 353 | + throws SocketException; | |
| 354 | + | |
| 355 | + private native static NetworkInterface getByIndex0(int index) | |
| 356 | + throws SocketException; | |
| 357 | + | |
| 358 | + private native static NetworkInterface getByInetAddress0(InetAddress addr) | |
| 359 | + throws SocketException; | |
| 360 | + | |
| 361 | + /** | |
| 362 | + * Returns whether a network interface is up and running. | |
| 363 | + * | |
| 364 | + * @return <code>true</code> if the interface is up and running. | |
| 365 | + * @exception SocketException if an I/O error occurs. | |
| 366 | + * @since 1.6 | |
| 367 | + */ | |
| 368 | + | |
| 369 | + public boolean isUp() throws SocketException { | |
| 370 | + return isUp0(name, index); | |
| 371 | + } | |
| 372 | + | |
| 373 | + /** | |
| 374 | + * Returns whether a network interface is a loopback interface. | |
| 375 | + * | |
| 376 | + * @return <code>true</code> if the interface is a loopback interface. | |
| 377 | + * @exception SocketException if an I/O error occurs. | |
| 378 | + * @since 1.6 | |
| 379 | + */ | |
| 380 | + | |
| 381 | + public boolean isLoopback() throws SocketException { | |
| 382 | + return isLoopback0(name, index); | |
| 383 | + } | |
| 384 | + | |
| 385 | + /** | |
| 386 | + * Returns whether a network interface is a point to point interface. | |
| 387 | + * A typical point to point interface would be a PPP connection through | |
| 388 | + * a modem. | |
| 389 | + * | |
| 390 | + * @return <code>true</code> if the interface is a point to point | |
| 391 | + * interface. | |
| 392 | + * @exception SocketException if an I/O error occurs. | |
| 393 | + * @since 1.6 | |
| 394 | + */ | |
| 395 | + | |
| 396 | + public boolean isPointToPoint() throws SocketException { | |
| 397 | + return isP2P0(name, index); | |
| 398 | + } | |
| 399 | + | |
| 400 | + /** | |
| 401 | + * Returns whether a network interface supports multicasting or not. | |
| 402 | + * | |
| 403 | + * @return <code>true</code> if the interface supports Multicasting. | |
| 404 | + * @exception SocketException if an I/O error occurs. | |
| 405 | + * @since 1.6 | |
| 406 | + */ | |
| 407 | + | |
| 408 | + public boolean supportsMulticast() throws SocketException { | |
| 409 | + return supportsMulticast0(name, index); | |
| 410 | + } | |
| 411 | + | |
| 412 | + /** | |
| 413 | + * Returns the hardware address (usually MAC) of the interface if it | |
| 414 | + * has one and if it can be accessed given the current privileges. | |
| 415 | + * If a security manager is set, then the caller must have | |
| 416 | + * the permission {@link NetPermission}("getNetworkInformation"). | |
| 417 | + * | |
| 418 | + * @return a byte array containing the address, or <code>null</code> if | |
| 419 | + * the address doesn't exist, is not accessible or a security | |
| 420 | + * manager is set and the caller does not have the permission | |
| 421 | + * NetPermission("getNetworkInformation") | |
| 422 | + * | |
| 423 | + * @exception SocketException if an I/O error occurs. | |
| 424 | + * @since 1.6 | |
| 425 | + */ | |
| 426 | + public byte[] getHardwareAddress() throws SocketException { | |
| 427 | + SecurityManager sec = System.getSecurityManager(); | |
| 428 | + if (sec != null) { | |
| 429 | + try { | |
| 430 | + sec.checkPermission(new NetPermission("getNetworkInformation")); | |
| 431 | + } catch (SecurityException e) { | |
| 432 | + if (!getInetAddresses().hasMoreElements()) { | |
| 433 | + // don't have connect permission to any local address | |
| 434 | + return null; | |
| 435 | + } | |
| 436 | + } | |
| 437 | + } | |
| 438 | + for (InetAddress addr : addrs) { | |
| 439 | + if (addr instanceof Inet4Address) { | |
| 440 | + return getMacAddr0(((Inet4Address)addr).getAddress(), name, index); | |
| 441 | + } | |
| 442 | + } | |
| 443 | + return getMacAddr0(null, name, index); | |
| 444 | + } | |
| 445 | + | |
| 446 | + /** | |
| 447 | + * Returns the Maximum Transmission Unit (MTU) of this interface. | |
| 448 | + * | |
| 449 | + * @return the value of the MTU for that interface. | |
| 450 | + * @exception SocketException if an I/O error occurs. | |
| 451 | + * @since 1.6 | |
| 452 | + */ | |
| 453 | + public int getMTU() throws SocketException { | |
| 454 | + return getMTU0(name, index); | |
| 455 | + } | |
| 456 | + | |
| 457 | + /** | |
| 458 | + * Returns whether this interface is a virtual interface (also called | |
| 459 | + * subinterface). | |
| 460 | + * Virtual interfaces are, on some systems, interfaces created as a child | |
| 461 | + * of a physical interface and given different settings (like address or | |
| 462 | + * MTU). Usually the name of the interface will the name of the parent | |
| 463 | + * followed by a colon (:) and a number identifying the child since there | |
| 464 | + * can be several virtual interfaces attached to a single physical | |
| 465 | + * interface. | |
| 466 | + * | |
| 467 | + * @return <code>true</code> if this interface is a virtual interface. | |
| 468 | + * @since 1.6 | |
| 469 | + */ | |
| 470 | + public boolean isVirtual() { | |
| 471 | + return virtual; | |
| 472 | + } | |
| 473 | + | |
| 474 | + private native static boolean isUp0(String name, int ind) throws SocketException; | |
| 475 | + private native static boolean isLoopback0(String name, int ind) throws SocketException; | |
| 476 | + private native static boolean supportsMulticast0(String name, int ind) throws SocketException; | |
| 477 | + private native static boolean isP2P0(String name, int ind) throws SocketException; | |
| 478 | + private native static byte[] getMacAddr0(byte[] inAddr, String name, int ind) throws SocketException; | |
| 479 | + private native static int getMTU0(String name, int ind) throws SocketException; | |
| 480 | + | |
| 481 | + /** | |
| 482 | + * Compares this object against the specified object. | |
| 483 | + * The result is <code>true</code> if and only if the argument is | |
| 484 | + * not <code>null</code> and it represents the same NetworkInterface | |
| 485 | + * as this object. | |
| 486 | + * <p> | |
| 487 | + * Two instances of <code>NetworkInterface</code> represent the same | |
| 488 | + * NetworkInterface if both name and addrs are the same for both. | |
| 489 | + * | |
| 490 | + * @param obj the object to compare against. | |
| 491 | + * @return <code>true</code> if the objects are the same; | |
| 492 | + * <code>false</code> otherwise. | |
| 493 | + * @see java.net.InetAddress#getAddress() | |
| 494 | + */ | |
| 495 | + public boolean equals(Object obj) { | |
| 496 | + if (!(obj instanceof NetworkInterface)) { | |
| 497 | + return false; | |
| 498 | + } | |
| 499 | + NetworkInterface that = (NetworkInterface)obj; | |
| 500 | + if (this.name != null ) { | |
| 501 | + if (!this.name.equals(that.name)) { | |
| 502 | + return false; | |
| 503 | + } | |
| 504 | + } else { | |
| 505 | + if (that.name != null) { | |
| 506 | + return false; | |
| 507 | + } | |
| 508 | + } | |
| 509 | + | |
| 510 | + if (this.addrs == null) { | |
| 511 | + return that.addrs == null; | |
| 512 | + } else if (that.addrs == null) { | |
| 513 | + return false; | |
| 514 | + } | |
| 515 | + | |
| 516 | + /* Both addrs not null. Compare number of addresses */ | |
| 517 | + | |
| 518 | + if (this.addrs.length != that.addrs.length) { | |
| 519 | + return false; | |
| 520 | + } | |
| 521 | + | |
| 522 | + InetAddress[] thatAddrs = that.addrs; | |
| 523 | + int count = thatAddrs.length; | |
| 524 | + | |
| 525 | + for (int i=0; i<count; i++) { | |
| 526 | + boolean found = false; | |
| 527 | + for (int j=0; j<count; j++) { | |
| 528 | + if (addrs[i].equals(thatAddrs[j])) { | |
| 529 | + found = true; | |
| 530 | + break; | |
| 531 | + } | |
| 532 | + } | |
| 533 | + if (!found) { | |
| 534 | + return false; | |
| 535 | + } | |
| 536 | + } | |
| 537 | + return true; | |
| 538 | + } | |
| 539 | + | |
| 540 | + public int hashCode() { | |
| 541 | + return name == null? 0: name.hashCode(); | |
| 542 | + } | |
| 543 | + | |
| 544 | + public String toString() { | |
| 545 | + String result = "name:"; | |
| 546 | + result += name == null? "null": name; | |
| 547 | + if (displayName != null) { | |
| 548 | + result += " (" + displayName + ")"; | |
| 549 | + } | |
| 550 | + return result; | |
| 551 | + } | |
| 552 | + | |
| 553 | + private static native void init(); | |
| 554 | +} | |
Binary file not shown.
| @@ -0,0 +1,54 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Signals that an error occurred while attempting to connect a | |
| 30 | + * socket to a remote address and port. Typically, the remote | |
| 31 | + * host cannot be reached because of an intervening firewall, or | |
| 32 | + * if an intermediate router is down. | |
| 33 | + * | |
| 34 | + * @since JDK1.1 | |
| 35 | + */ | |
| 36 | +public class NoRouteToHostException extends SocketException { | |
| 37 | + private static final long serialVersionUID = -1897550894873493790L; | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * Constructs a new NoRouteToHostException with the specified detail | |
| 41 | + * message as to why the remote host cannot be reached. | |
| 42 | + * A detail message is a String that gives a specific | |
| 43 | + * description of this error. | |
| 44 | + * @param msg the detail message | |
| 45 | + */ | |
| 46 | + public NoRouteToHostException(String msg) { | |
| 47 | + super(msg); | |
| 48 | + } | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Construct a new NoRouteToHostException with no detailed message. | |
| 52 | + */ | |
| 53 | + public NoRouteToHostException() {} | |
| 54 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,81 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2001, 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 java.net; | |
| 27 | + | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * The class PasswordAuthentication is a data holder that is used by | |
| 31 | + * Authenticator. It is simply a repository for a user name and a password. | |
| 32 | + * | |
| 33 | + * @see java.net.Authenticator | |
| 34 | + * @see java.net.Authenticator#getPasswordAuthentication() | |
| 35 | + * | |
| 36 | + * @author Bill Foote | |
| 37 | + * @since 1.2 | |
| 38 | + */ | |
| 39 | + | |
| 40 | +public final class PasswordAuthentication { | |
| 41 | + | |
| 42 | + private String userName; | |
| 43 | + private char[] password; | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * Creates a new <code>PasswordAuthentication</code> object from the given | |
| 47 | + * user name and password. | |
| 48 | + * | |
| 49 | + * <p> Note that the given user password is cloned before it is stored in | |
| 50 | + * the new <code>PasswordAuthentication</code> object. | |
| 51 | + * | |
| 52 | + * @param userName the user name | |
| 53 | + * @param password the user's password | |
| 54 | + */ | |
| 55 | + public PasswordAuthentication(String userName, char[] password) { | |
| 56 | + this.userName = userName; | |
| 57 | + this.password = password.clone(); | |
| 58 | + } | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * Returns the user name. | |
| 62 | + * | |
| 63 | + * @return the user name | |
| 64 | + */ | |
| 65 | + public String getUserName() { | |
| 66 | + return userName; | |
| 67 | + } | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * Returns the user password. | |
| 71 | + * | |
| 72 | + * <p> Note that this method returns a reference to the password. It is | |
| 73 | + * the caller's responsibility to zero out the password information after | |
| 74 | + * it is no longer needed. | |
| 75 | + * | |
| 76 | + * @return the password | |
| 77 | + */ | |
| 78 | + public char[] getPassword() { | |
| 79 | + return password; | |
| 80 | + } | |
| 81 | +} | |
Binary file not shown.
| @@ -0,0 +1,52 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2001, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Signals that an ICMP Port Unreachable message has been | |
| 30 | + * received on a connected datagram. | |
| 31 | + * | |
| 32 | + * @since 1.4 | |
| 33 | + */ | |
| 34 | + | |
| 35 | +public class PortUnreachableException extends SocketException { | |
| 36 | + private static final long serialVersionUID = 8462541992376507323L; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * Constructs a new <code>PortUnreachableException</code> with a | |
| 40 | + * detail message. | |
| 41 | + * @param msg the detail message | |
| 42 | + */ | |
| 43 | + public PortUnreachableException(String msg) { | |
| 44 | + super(msg); | |
| 45 | + } | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * Construct a new <code>PortUnreachableException</code> with no | |
| 49 | + * detailed message. | |
| 50 | + */ | |
| 51 | + public PortUnreachableException() {} | |
| 52 | +} | |
Binary file not shown.
| @@ -0,0 +1,56 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * Thrown to indicate that there is an error in the underlying | |
| 32 | + * protocol, such as a TCP error. | |
| 33 | + * | |
| 34 | + * @author Chris Warth | |
| 35 | + * @since JDK1.0 | |
| 36 | + */ | |
| 37 | +public | |
| 38 | +class ProtocolException extends IOException { | |
| 39 | + private static final long serialVersionUID = -6098449442062388080L; | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * Constructs a new <code>ProtocolException</code> with the | |
| 43 | + * specified detail message. | |
| 44 | + * | |
| 45 | + * @param host the detail message. | |
| 46 | + */ | |
| 47 | + public ProtocolException(String host) { | |
| 48 | + super(host); | |
| 49 | + } | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * Constructs a new <code>ProtocolException</code> with no detail message. | |
| 53 | + */ | |
| 54 | + public ProtocolException() { | |
| 55 | + } | |
| 56 | +} | |
Binary file not shown.
| @@ -0,0 +1,39 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Represents a family of communication protocols. | |
| 30 | + * | |
| 31 | + * @since 1.7 | |
| 32 | + */ | |
| 33 | + | |
| 34 | +public interface ProtocolFamily { | |
| 35 | + /** | |
| 36 | + * Returns the name of the protocol family. | |
| 37 | + */ | |
| 38 | + String name(); | |
| 39 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,171 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2005, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This class represents a proxy setting, typically a type (http, socks) and | |
| 30 | + * a socket address. | |
| 31 | + * A <code>Proxy</code> is an immutable object. | |
| 32 | + * | |
| 33 | + * @see java.net.ProxySelector | |
| 34 | + * @author Yingxian Wang | |
| 35 | + * @author Jean-Christophe Collet | |
| 36 | + * @since 1.5 | |
| 37 | + */ | |
| 38 | +public class Proxy { | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * Represents the proxy type. | |
| 42 | + * | |
| 43 | + * @since 1.5 | |
| 44 | + */ | |
| 45 | + public enum Type { | |
| 46 | + /** | |
| 47 | + * Represents a direct connection, or the absence of a proxy. | |
| 48 | + */ | |
| 49 | + DIRECT, | |
| 50 | + /** | |
| 51 | + * Represents proxy for high level protocols such as HTTP or FTP. | |
| 52 | + */ | |
| 53 | + HTTP, | |
| 54 | + /** | |
| 55 | + * Represents a SOCKS (V4 or V5) proxy. | |
| 56 | + */ | |
| 57 | + SOCKS | |
| 58 | + }; | |
| 59 | + | |
| 60 | + private Type type; | |
| 61 | + private SocketAddress sa; | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * A proxy setting that represents a <code>DIRECT</code> connection, | |
| 65 | + * basically telling the protocol handler not to use any proxying. | |
| 66 | + * Used, for instance, to create sockets bypassing any other global | |
| 67 | + * proxy settings (like SOCKS): | |
| 68 | + * <P> | |
| 69 | + * <code>Socket s = new Socket(Proxy.NO_PROXY);</code><br> | |
| 70 | + * <P> | |
| 71 | + */ | |
| 72 | + public final static Proxy NO_PROXY = new Proxy(); | |
| 73 | + | |
| 74 | + // Creates the proxy that represents a <code>DIRECT</code> connection. | |
| 75 | + private Proxy() { | |
| 76 | + type = type.DIRECT; | |
| 77 | + sa = null; | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * Creates an entry representing a PROXY connection. | |
| 82 | + * Certain combinations are illegal. For instance, for types Http, and | |
| 83 | + * Socks, a SocketAddress <b>must</b> be provided. | |
| 84 | + * <P> | |
| 85 | + * Use the <code>Proxy.NO_PROXY</code> constant | |
| 86 | + * for representing a direct connection. | |
| 87 | + * | |
| 88 | + * @param type the <code>Type</code> of the proxy | |
| 89 | + * @param sa the <code>SocketAddress</code> for that proxy | |
| 90 | + * @throws IllegalArgumentException when the type and the address are | |
| 91 | + * incompatible | |
| 92 | + */ | |
| 93 | + public Proxy(Type type, SocketAddress sa) { | |
| 94 | + if ((type == Type.DIRECT) || !(sa instanceof InetSocketAddress)) | |
| 95 | + throw new IllegalArgumentException("type " + type + " is not compatible with address " + sa); | |
| 96 | + this.type = type; | |
| 97 | + this.sa = sa; | |
| 98 | + } | |
| 99 | + | |
| 100 | + /** | |
| 101 | + * Returns the proxy type. | |
| 102 | + * | |
| 103 | + * @return a Type representing the proxy type | |
| 104 | + */ | |
| 105 | + public Type type() { | |
| 106 | + return type; | |
| 107 | + } | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * Returns the socket address of the proxy, or | |
| 111 | + * <code>null</code> if its a direct connection. | |
| 112 | + * | |
| 113 | + * @return a <code>SocketAddress</code> representing the socket end | |
| 114 | + * point of the proxy | |
| 115 | + */ | |
| 116 | + public SocketAddress address() { | |
| 117 | + return sa; | |
| 118 | + } | |
| 119 | + | |
| 120 | + /** | |
| 121 | + * Constructs a string representation of this Proxy. | |
| 122 | + * This String is constructed by calling toString() on its type | |
| 123 | + * and concatenating " @ " and the toString() result from its address | |
| 124 | + * if its type is not <code>DIRECT</code>. | |
| 125 | + * | |
| 126 | + * @return a string representation of this object. | |
| 127 | + */ | |
| 128 | + public String toString() { | |
| 129 | + if (type() == Type.DIRECT) | |
| 130 | + return "DIRECT"; | |
| 131 | + return type() + " @ " + address(); | |
| 132 | + } | |
| 133 | + | |
| 134 | + /** | |
| 135 | + * Compares this object against the specified object. | |
| 136 | + * The result is <code>true</code> if and only if the argument is | |
| 137 | + * not <code>null</code> and it represents the same proxy as | |
| 138 | + * this object. | |
| 139 | + * <p> | |
| 140 | + * Two instances of <code>Proxy</code> represent the same | |
| 141 | + * address if both the SocketAddresses and type are equal. | |
| 142 | + * | |
| 143 | + * @param obj the object to compare against. | |
| 144 | + * @return <code>true</code> if the objects are the same; | |
| 145 | + * <code>false</code> otherwise. | |
| 146 | + * @see java.net.InetSocketAddress#equals(java.lang.Object) | |
| 147 | + */ | |
| 148 | + public final boolean equals(Object obj) { | |
| 149 | + if (obj == null || !(obj instanceof Proxy)) | |
| 150 | + return false; | |
| 151 | + Proxy p = (Proxy) obj; | |
| 152 | + if (p.type() == type()) { | |
| 153 | + if (address() == null) { | |
| 154 | + return (p.address() == null); | |
| 155 | + } else | |
| 156 | + return address().equals(p.address()); | |
| 157 | + } | |
| 158 | + return false; | |
| 159 | + } | |
| 160 | + | |
| 161 | + /** | |
| 162 | + * Returns a hashcode for this Proxy. | |
| 163 | + * | |
| 164 | + * @return a hash code value for this Proxy. | |
| 165 | + */ | |
| 166 | + public final int hashCode() { | |
| 167 | + if (address() == null) | |
| 168 | + return type().hashCode(); | |
| 169 | + return type().hashCode() + address().hashCode(); | |
| 170 | + } | |
| 171 | +} | |
Binary file not shown.
| @@ -0,0 +1,166 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2006, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.util.List; | |
| 30 | +import sun.security.util.SecurityConstants; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * Selects the proxy server to use, if any, when connecting to the | |
| 34 | + * network resource referenced by a URL. A proxy selector is a | |
| 35 | + * concrete sub-class of this class and is registered by invoking the | |
| 36 | + * {@link java.net.ProxySelector#setDefault setDefault} method. The | |
| 37 | + * currently registered proxy selector can be retrieved by calling | |
| 38 | + * {@link java.net.ProxySelector#getDefault getDefault} method. | |
| 39 | + * | |
| 40 | + * <p> When a proxy selector is registered, for instance, a subclass | |
| 41 | + * of URLConnection class should call the {@link #select select} | |
| 42 | + * method for each URL request so that the proxy selector can decide | |
| 43 | + * if a direct, or proxied connection should be used. The {@link | |
| 44 | + * #select select} method returns an iterator over a collection with | |
| 45 | + * the preferred connection approach. | |
| 46 | + * | |
| 47 | + * <p> If a connection cannot be established to a proxy (PROXY or | |
| 48 | + * SOCKS) servers then the caller should call the proxy selector's | |
| 49 | + * {@link #connectFailed connectFailed} method to notify the proxy | |
| 50 | + * selector that the proxy server is unavailable. </p> | |
| 51 | + * | |
| 52 | + * <P>The default proxy selector does enforce a | |
| 53 | + * <a href="doc-files/net-properties.html#Proxies">set of System Properties</a> | |
| 54 | + * related to proxy settings.</P> | |
| 55 | + * | |
| 56 | + * @author Yingxian Wang | |
| 57 | + * @author Jean-Christophe Collet | |
| 58 | + * @since 1.5 | |
| 59 | + */ | |
| 60 | +public abstract class ProxySelector { | |
| 61 | + /** | |
| 62 | + * The system wide proxy selector that selects the proxy server to | |
| 63 | + * use, if any, when connecting to a remote object referenced by | |
| 64 | + * an URL. | |
| 65 | + * | |
| 66 | + * @see #setDefault(ProxySelector) | |
| 67 | + */ | |
| 68 | + private static ProxySelector theProxySelector; | |
| 69 | + | |
| 70 | + static { | |
| 71 | + try { | |
| 72 | + Class c = Class.forName("sun.net.spi.DefaultProxySelector"); | |
| 73 | + if (c != null && ProxySelector.class.isAssignableFrom(c)) { | |
| 74 | + theProxySelector = (ProxySelector) c.newInstance(); | |
| 75 | + } | |
| 76 | + } catch (Exception e) { | |
| 77 | + theProxySelector = null; | |
| 78 | + } | |
| 79 | + } | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * Gets the system-wide proxy selector. | |
| 83 | + * | |
| 84 | + * @throws SecurityException | |
| 85 | + * If a security manager has been installed and it denies | |
| 86 | + * {@link NetPermission}<tt>("getProxySelector")</tt> | |
| 87 | + * @see #setDefault(ProxySelector) | |
| 88 | + * @return the system-wide <code>ProxySelector</code> | |
| 89 | + * @since 1.5 | |
| 90 | + */ | |
| 91 | + public static ProxySelector getDefault() { | |
| 92 | + SecurityManager sm = System.getSecurityManager(); | |
| 93 | + if (sm != null) { | |
| 94 | + sm.checkPermission(SecurityConstants.GET_PROXYSELECTOR_PERMISSION); | |
| 95 | + } | |
| 96 | + return theProxySelector; | |
| 97 | + } | |
| 98 | + | |
| 99 | + /** | |
| 100 | + * Sets (or unsets) the system-wide proxy selector. | |
| 101 | + * | |
| 102 | + * Note: non-standard protocol handlers may ignore this setting. | |
| 103 | + * | |
| 104 | + * @param ps The HTTP proxy selector, or | |
| 105 | + * <code>null</code> to unset the proxy selector. | |
| 106 | + * | |
| 107 | + * @throws SecurityException | |
| 108 | + * If a security manager has been installed and it denies | |
| 109 | + * {@link NetPermission}<tt>("setProxySelector")</tt> | |
| 110 | + * | |
| 111 | + * @see #getDefault() | |
| 112 | + * @since 1.5 | |
| 113 | + */ | |
| 114 | + public static void setDefault(ProxySelector ps) { | |
| 115 | + SecurityManager sm = System.getSecurityManager(); | |
| 116 | + if (sm != null) { | |
| 117 | + sm.checkPermission(SecurityConstants.SET_PROXYSELECTOR_PERMISSION); | |
| 118 | + } | |
| 119 | + theProxySelector = ps; | |
| 120 | + } | |
| 121 | + | |
| 122 | + /** | |
| 123 | + * Selects all the applicable proxies based on the protocol to | |
| 124 | + * access the resource with and a destination address to access | |
| 125 | + * the resource at. | |
| 126 | + * The format of the URI is defined as follow: | |
| 127 | + * <UL> | |
| 128 | + * <LI>http URI for http connections</LI> | |
| 129 | + * <LI>https URI for https connections | |
| 130 | + * <LI>ftp URI for ftp connections</LI> | |
| 131 | + * <LI><code>socket://host:port</code><br> | |
| 132 | + * for tcp client sockets connections</LI> | |
| 133 | + * </UL> | |
| 134 | + * | |
| 135 | + * @param uri | |
| 136 | + * The URI that a connection is required to | |
| 137 | + * | |
| 138 | + * @return a List of Proxies. Each element in the | |
| 139 | + * the List is of type | |
| 140 | + * {@link java.net.Proxy Proxy}; | |
| 141 | + * when no proxy is available, the list will | |
| 142 | + * contain one element of type | |
| 143 | + * {@link java.net.Proxy Proxy} | |
| 144 | + * that represents a direct connection. | |
| 145 | + * @throws IllegalArgumentException if the argument is null | |
| 146 | + */ | |
| 147 | + public abstract List<Proxy> select(URI uri); | |
| 148 | + | |
| 149 | + /** | |
| 150 | + * Called to indicate that a connection could not be established | |
| 151 | + * to a proxy/socks server. An implementation of this method can | |
| 152 | + * temporarily remove the proxies or reorder the sequence of | |
| 153 | + * proxies returned by {@link #select(URI)}, using the address | |
| 154 | + * and the IOException caught when trying to connect. | |
| 155 | + * | |
| 156 | + * @param uri | |
| 157 | + * The URI that the proxy at sa failed to serve. | |
| 158 | + * @param sa | |
| 159 | + * The socket address of the proxy/SOCKS server | |
| 160 | + * | |
| 161 | + * @param ioe | |
| 162 | + * The I/O exception thrown when the connect failed. | |
| 163 | + * @throws IllegalArgumentException if either argument is null | |
| 164 | + */ | |
| 165 | + public abstract void connectFailed(URI uri, SocketAddress sa, IOException ioe); | |
| 166 | +} | |
Binary file not shown.
| @@ -0,0 +1,163 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.util.Map; | |
| 30 | +import java.util.List; | |
| 31 | +import sun.security.util.SecurityConstants; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * Represents implementations of URLConnection caches. An instance of | |
| 35 | + * such a class can be registered with the system by doing | |
| 36 | + * ResponseCache.setDefault(ResponseCache), and the system will call | |
| 37 | + * this object in order to: | |
| 38 | + * | |
| 39 | + * <ul><li>store resource data which has been retrieved from an | |
| 40 | + * external source into the cache</li> | |
| 41 | + * <li>try to fetch a requested resource that may have been | |
| 42 | + * stored in the cache</li> | |
| 43 | + * </ul> | |
| 44 | + * | |
| 45 | + * The ResponseCache implementation decides which resources | |
| 46 | + * should be cached, and for how long they should be cached. If a | |
| 47 | + * request resource cannot be retrieved from the cache, then the | |
| 48 | + * protocol handlers will fetch the resource from its original | |
| 49 | + * location. | |
| 50 | + * | |
| 51 | + * The settings for URLConnection#useCaches controls whether the | |
| 52 | + * protocol is allowed to use a cached response. | |
| 53 | + * | |
| 54 | + * For more information on HTTP caching, see <a | |
| 55 | + * href="http://www.ietf.org/rfc/rfc2616.txt"><i>RFC 2616: Hypertext | |
| 56 | + * Transfer Protocol -- HTTP/1.1</i></a> | |
| 57 | + * | |
| 58 | + * @author Yingxian Wang | |
| 59 | + * @since 1.5 | |
| 60 | + */ | |
| 61 | +public abstract class ResponseCache { | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * The system wide cache that provides access to a url | |
| 65 | + * caching mechanism. | |
| 66 | + * | |
| 67 | + * @see #setDefault(ResponseCache) | |
| 68 | + * @see #getDefault() | |
| 69 | + */ | |
| 70 | + private static ResponseCache theResponseCache; | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * Gets the system-wide response cache. | |
| 74 | + * | |
| 75 | + * @throws SecurityException | |
| 76 | + * If a security manager has been installed and it denies | |
| 77 | + * {@link NetPermission}<tt>("getResponseCache")</tt> | |
| 78 | + * | |
| 79 | + * @see #setDefault(ResponseCache) | |
| 80 | + * @return the system-wide <code>ResponseCache</code> | |
| 81 | + * @since 1.5 | |
| 82 | + */ | |
| 83 | + public synchronized static ResponseCache getDefault() { | |
| 84 | + SecurityManager sm = System.getSecurityManager(); | |
| 85 | + if (sm != null) { | |
| 86 | + sm.checkPermission(SecurityConstants.GET_RESPONSECACHE_PERMISSION); | |
| 87 | + } | |
| 88 | + return theResponseCache; | |
| 89 | + } | |
| 90 | + | |
| 91 | + /** | |
| 92 | + * Sets (or unsets) the system-wide cache. | |
| 93 | + * | |
| 94 | + * Note: non-standard procotol handlers may ignore this setting. | |
| 95 | + * | |
| 96 | + * @param responseCache The response cache, or | |
| 97 | + * <code>null</code> to unset the cache. | |
| 98 | + * | |
| 99 | + * @throws SecurityException | |
| 100 | + * If a security manager has been installed and it denies | |
| 101 | + * {@link NetPermission}<tt>("setResponseCache")</tt> | |
| 102 | + * | |
| 103 | + * @see #getDefault() | |
| 104 | + * @since 1.5 | |
| 105 | + */ | |
| 106 | + public synchronized static void setDefault(ResponseCache responseCache) { | |
| 107 | + SecurityManager sm = System.getSecurityManager(); | |
| 108 | + if (sm != null) { | |
| 109 | + sm.checkPermission(SecurityConstants.SET_RESPONSECACHE_PERMISSION); | |
| 110 | + } | |
| 111 | + theResponseCache = responseCache; | |
| 112 | + } | |
| 113 | + | |
| 114 | + /** | |
| 115 | + * Retrieve the cached response based on the requesting uri, | |
| 116 | + * request method and request headers. Typically this method is | |
| 117 | + * called by the protocol handler before it sends out the request | |
| 118 | + * to get the network resource. If a cached response is returned, | |
| 119 | + * that resource is used instead. | |
| 120 | + * | |
| 121 | + * @param uri a <code>URI</code> used to reference the requested | |
| 122 | + * network resource | |
| 123 | + * @param rqstMethod a <code>String</code> representing the request | |
| 124 | + * method | |
| 125 | + * @param rqstHeaders - a Map from request header | |
| 126 | + * field names to lists of field values representing | |
| 127 | + * the current request headers | |
| 128 | + * @return a <code>CacheResponse</code> instance if available | |
| 129 | + * from cache, or null otherwise | |
| 130 | + * @throws IOException if an I/O error occurs | |
| 131 | + * @throws IllegalArgumentException if any one of the arguments is null | |
| 132 | + * | |
| 133 | + * @see java.net.URLConnection#setUseCaches(boolean) | |
| 134 | + * @see java.net.URLConnection#getUseCaches() | |
| 135 | + * @see java.net.URLConnection#setDefaultUseCaches(boolean) | |
| 136 | + * @see java.net.URLConnection#getDefaultUseCaches() | |
| 137 | + */ | |
| 138 | + public abstract CacheResponse | |
| 139 | + get(URI uri, String rqstMethod, Map<String, List<String>> rqstHeaders) | |
| 140 | + throws IOException; | |
| 141 | + | |
| 142 | + /** | |
| 143 | + * The protocol handler calls this method after a resource has | |
| 144 | + * been retrieved, and the ResponseCache must decide whether or | |
| 145 | + * not to store the resource in its cache. If the resource is to | |
| 146 | + * be cached, then put() must return a CacheRequest object which | |
| 147 | + * contains an OutputStream that the protocol handler will | |
| 148 | + * use to write the resource into the cache. If the resource is | |
| 149 | + * not to be cached, then put must return null. | |
| 150 | + * | |
| 151 | + * @param uri a <code>URI</code> used to reference the requested | |
| 152 | + * network resource | |
| 153 | + * @param conn - a URLConnection instance that is used to fetch | |
| 154 | + * the response to be cached | |
| 155 | + * @return a <code>CacheRequest</code> for recording the | |
| 156 | + * response to be cached. Null return indicates that | |
| 157 | + * the caller does not intend to cache the response. | |
| 158 | + * @throws IOException if an I/O error occurs | |
| 159 | + * @throws IllegalArgumentException if any one of the arguments is | |
| 160 | + * null | |
| 161 | + */ | |
| 162 | + public abstract CacheRequest put(URI uri, URLConnection conn) throws IOException; | |
| 163 | +} | |
Binary file not shown.
| @@ -0,0 +1,49 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2010, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.io.FileDescriptor; | |
| 30 | + | |
| 31 | +import sun.net.sdp.SdpSupport; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * SocketImpl that supports the SDP protocol | |
| 35 | + */ | |
| 36 | +class SdpSocketImpl extends PlainSocketImpl { | |
| 37 | + SdpSocketImpl() { } | |
| 38 | + | |
| 39 | + @Override | |
| 40 | + protected void create(boolean stream) throws IOException { | |
| 41 | + if (!stream) | |
| 42 | + throw new UnsupportedOperationException("Must be a stream socket"); | |
| 43 | + fd = SdpSupport.createSocket(); | |
| 44 | + if (socket != null) | |
| 45 | + socket.setCreated(); | |
| 46 | + if (serverSocket != null) | |
| 47 | + serverSocket.setCreated(); | |
| 48 | + } | |
| 49 | +} | |
Binary file not shown.
| @@ -0,0 +1,108 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2003, 2004, 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 java.net; | |
| 27 | + | |
| 28 | +import java.security.cert.Certificate; | |
| 29 | +import javax.net.ssl.SSLPeerUnverifiedException; | |
| 30 | +import java.security.Principal; | |
| 31 | +import java.util.List; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * Represents a cache response originally retrieved through secure | |
| 35 | + * means, such as TLS. | |
| 36 | + * | |
| 37 | + * @since 1.5 | |
| 38 | + */ | |
| 39 | +public abstract class SecureCacheResponse extends CacheResponse { | |
| 40 | + /** | |
| 41 | + * Returns the cipher suite in use on the original connection that | |
| 42 | + * retrieved the network resource. | |
| 43 | + * | |
| 44 | + * @return a string representing the cipher suite | |
| 45 | + */ | |
| 46 | + public abstract String getCipherSuite(); | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * Returns the certificate chain that were sent to the server during | |
| 50 | + * handshaking of the original connection that retrieved the | |
| 51 | + * network resource. Note: This method is useful only | |
| 52 | + * when using certificate-based cipher suites. | |
| 53 | + * | |
| 54 | + * @return an immutable List of Certificate representing the | |
| 55 | + * certificate chain that was sent to the server. If no | |
| 56 | + * certificate chain was sent, null will be returned. | |
| 57 | + * @see #getLocalPrincipal() | |
| 58 | + */ | |
| 59 | + public abstract List<Certificate> getLocalCertificateChain(); | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * Returns the server's certificate chain, which was established as | |
| 63 | + * part of defining the session in the original connection that | |
| 64 | + * retrieved the network resource, from cache. Note: This method | |
| 65 | + * can be used only when using certificate-based cipher suites; | |
| 66 | + * using it with non-certificate-based cipher suites, such as | |
| 67 | + * Kerberos, will throw an SSLPeerUnverifiedException. | |
| 68 | + * | |
| 69 | + * @return an immutable List of Certificate representing the server's | |
| 70 | + * certificate chain. | |
| 71 | + * @throws SSLPeerUnverifiedException if the peer is not verified. | |
| 72 | + * @see #getPeerPrincipal() | |
| 73 | + */ | |
| 74 | + public abstract List<Certificate> getServerCertificateChain() | |
| 75 | + throws SSLPeerUnverifiedException; | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * Returns the server's principal which was established as part of | |
| 79 | + * defining the session during the original connection that | |
| 80 | + * retrieved the network resource. | |
| 81 | + * | |
| 82 | + * @return the server's principal. Returns an X500Principal of the | |
| 83 | + * end-entity certiticate for X509-based cipher suites, and | |
| 84 | + * KerberosPrincipal for Kerberos cipher suites. | |
| 85 | + * | |
| 86 | + * @throws SSLPeerUnverifiedException if the peer was not verified. | |
| 87 | + * | |
| 88 | + * @see #getServerCertificateChain() | |
| 89 | + * @see #getLocalPrincipal() | |
| 90 | + */ | |
| 91 | + public abstract Principal getPeerPrincipal() | |
| 92 | + throws SSLPeerUnverifiedException; | |
| 93 | + | |
| 94 | + /** | |
| 95 | + * Returns the principal that was sent to the server during | |
| 96 | + * handshaking in the original connection that retrieved the | |
| 97 | + * network resource. | |
| 98 | + * | |
| 99 | + * @return the principal sent to the server. Returns an X500Principal | |
| 100 | + * of the end-entity certificate for X509-based cipher suites, and | |
| 101 | + * KerberosPrincipal for Kerberos cipher suites. If no principal was | |
| 102 | + * sent, then null is returned. | |
| 103 | + * | |
| 104 | + * @see #getLocalCertificateChain() | |
| 105 | + * @see #getPeerPrincipal() | |
| 106 | + */ | |
| 107 | + public abstract Principal getLocalPrincipal(); | |
| 108 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,886 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2010, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.FileDescriptor; | |
| 29 | +import java.io.IOException; | |
| 30 | +import java.nio.channels.ServerSocketChannel; | |
| 31 | +import java.security.AccessController; | |
| 32 | +import java.security.PrivilegedExceptionAction; | |
| 33 | + | |
| 34 | +/** | |
| 35 | + * This class implements server sockets. A server socket waits for | |
| 36 | + * requests to come in over the network. It performs some operation | |
| 37 | + * based on that request, and then possibly returns a result to the requester. | |
| 38 | + * <p> | |
| 39 | + * The actual work of the server socket is performed by an instance | |
| 40 | + * of the <code>SocketImpl</code> class. An application can | |
| 41 | + * change the socket factory that creates the socket | |
| 42 | + * implementation to configure itself to create sockets | |
| 43 | + * appropriate to the local firewall. | |
| 44 | + * | |
| 45 | + * @author unascribed | |
| 46 | + * @see java.net.SocketImpl | |
| 47 | + * @see java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory) | |
| 48 | + * @see java.nio.channels.ServerSocketChannel | |
| 49 | + * @since JDK1.0 | |
| 50 | + */ | |
| 51 | +public | |
| 52 | +class ServerSocket implements java.io.Closeable { | |
| 53 | + /** | |
| 54 | + * Various states of this socket. | |
| 55 | + */ | |
| 56 | + private boolean created = false; | |
| 57 | + private boolean bound = false; | |
| 58 | + private boolean closed = false; | |
| 59 | + private Object closeLock = new Object(); | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * The implementation of this Socket. | |
| 63 | + */ | |
| 64 | + private SocketImpl impl; | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Are we using an older SocketImpl? | |
| 68 | + */ | |
| 69 | + private boolean oldImpl = false; | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * Package-private constructor to create a ServerSocket associated with | |
| 73 | + * the given SocketImpl. | |
| 74 | + */ | |
| 75 | + ServerSocket(SocketImpl impl) { | |
| 76 | + this.impl = impl; | |
| 77 | + impl.setServerSocket(this); | |
| 78 | + } | |
| 79 | + | |
| 80 | + /** | |
| 81 | + * Creates an unbound server socket. | |
| 82 | + * | |
| 83 | + * @exception IOException IO error when opening the socket. | |
| 84 | + * @revised 1.4 | |
| 85 | + */ | |
| 86 | + public ServerSocket() throws IOException { | |
| 87 | + setImpl(); | |
| 88 | + } | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * Creates a server socket, bound to the specified port. A port number | |
| 92 | + * of <code>0</code> means that the port number is automatically | |
| 93 | + * allocated, typically from an ephemeral port range. This port | |
| 94 | + * number can then be retrieved by calling {@link #getLocalPort getLocalPort}. | |
| 95 | + * <p> | |
| 96 | + * The maximum queue length for incoming connection indications (a | |
| 97 | + * request to connect) is set to <code>50</code>. If a connection | |
| 98 | + * indication arrives when the queue is full, the connection is refused. | |
| 99 | + * <p> | |
| 100 | + * If the application has specified a server socket factory, that | |
| 101 | + * factory's <code>createSocketImpl</code> method is called to create | |
| 102 | + * the actual socket implementation. Otherwise a "plain" socket is created. | |
| 103 | + * <p> | |
| 104 | + * If there is a security manager, | |
| 105 | + * its <code>checkListen</code> method is called | |
| 106 | + * with the <code>port</code> argument | |
| 107 | + * as its argument to ensure the operation is allowed. | |
| 108 | + * This could result in a SecurityException. | |
| 109 | + * | |
| 110 | + * | |
| 111 | + * @param port the port number, or <code>0</code> to use a port | |
| 112 | + * number that is automatically allocated. | |
| 113 | + * | |
| 114 | + * @exception IOException if an I/O error occurs when opening the socket. | |
| 115 | + * @exception SecurityException | |
| 116 | + * if a security manager exists and its <code>checkListen</code> | |
| 117 | + * method doesn't allow the operation. | |
| 118 | + * @exception IllegalArgumentException if the port parameter is outside | |
| 119 | + * the specified range of valid port values, which is between | |
| 120 | + * 0 and 65535, inclusive. | |
| 121 | + * | |
| 122 | + * @see java.net.SocketImpl | |
| 123 | + * @see java.net.SocketImplFactory#createSocketImpl() | |
| 124 | + * @see java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory) | |
| 125 | + * @see SecurityManager#checkListen | |
| 126 | + */ | |
| 127 | + public ServerSocket(int port) throws IOException { | |
| 128 | + this(port, 50, null); | |
| 129 | + } | |
| 130 | + | |
| 131 | + /** | |
| 132 | + * Creates a server socket and binds it to the specified local port | |
| 133 | + * number, with the specified backlog. | |
| 134 | + * A port number of <code>0</code> means that the port number is | |
| 135 | + * automatically allocated, typically from an ephemeral port range. | |
| 136 | + * This port number can then be retrieved by calling | |
| 137 | + * {@link #getLocalPort getLocalPort}. | |
| 138 | + * <p> | |
| 139 | + * The maximum queue length for incoming connection indications (a | |
| 140 | + * request to connect) is set to the <code>backlog</code> parameter. If | |
| 141 | + * a connection indication arrives when the queue is full, the | |
| 142 | + * connection is refused. | |
| 143 | + * <p> | |
| 144 | + * If the application has specified a server socket factory, that | |
| 145 | + * factory's <code>createSocketImpl</code> method is called to create | |
| 146 | + * the actual socket implementation. Otherwise a "plain" socket is created. | |
| 147 | + * <p> | |
| 148 | + * If there is a security manager, | |
| 149 | + * its <code>checkListen</code> method is called | |
| 150 | + * with the <code>port</code> argument | |
| 151 | + * as its argument to ensure the operation is allowed. | |
| 152 | + * This could result in a SecurityException. | |
| 153 | + * | |
| 154 | + * The <code>backlog</code> argument is the requested maximum number of | |
| 155 | + * pending connections on the socket. Its exact semantics are implementation | |
| 156 | + * specific. In particular, an implementation may impose a maximum length | |
| 157 | + * or may choose to ignore the parameter altogther. The value provided | |
| 158 | + * should be greater than <code>0</code>. If it is less than or equal to | |
| 159 | + * <code>0</code>, then an implementation specific default will be used. | |
| 160 | + * <P> | |
| 161 | + * | |
| 162 | + * @param port the port number, or <code>0</code> to use a port | |
| 163 | + * number that is automatically allocated. | |
| 164 | + * @param backlog requested maximum length of the queue of incoming | |
| 165 | + * connections. | |
| 166 | + * | |
| 167 | + * @exception IOException if an I/O error occurs when opening the socket. | |
| 168 | + * @exception SecurityException | |
| 169 | + * if a security manager exists and its <code>checkListen</code> | |
| 170 | + * method doesn't allow the operation. | |
| 171 | + * @exception IllegalArgumentException if the port parameter is outside | |
| 172 | + * the specified range of valid port values, which is between | |
| 173 | + * 0 and 65535, inclusive. | |
| 174 | + * | |
| 175 | + * @see java.net.SocketImpl | |
| 176 | + * @see java.net.SocketImplFactory#createSocketImpl() | |
| 177 | + * @see java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory) | |
| 178 | + * @see SecurityManager#checkListen | |
| 179 | + */ | |
| 180 | + public ServerSocket(int port, int backlog) throws IOException { | |
| 181 | + this(port, backlog, null); | |
| 182 | + } | |
| 183 | + | |
| 184 | + /** | |
| 185 | + * Create a server with the specified port, listen backlog, and | |
| 186 | + * local IP address to bind to. The <i>bindAddr</i> argument | |
| 187 | + * can be used on a multi-homed host for a ServerSocket that | |
| 188 | + * will only accept connect requests to one of its addresses. | |
| 189 | + * If <i>bindAddr</i> is null, it will default accepting | |
| 190 | + * connections on any/all local addresses. | |
| 191 | + * The port must be between 0 and 65535, inclusive. | |
| 192 | + * A port number of <code>0</code> means that the port number is | |
| 193 | + * automatically allocated, typically from an ephemeral port range. | |
| 194 | + * This port number can then be retrieved by calling | |
| 195 | + * {@link #getLocalPort getLocalPort}. | |
| 196 | + * | |
| 197 | + * <P>If there is a security manager, this method | |
| 198 | + * calls its <code>checkListen</code> method | |
| 199 | + * with the <code>port</code> argument | |
| 200 | + * as its argument to ensure the operation is allowed. | |
| 201 | + * This could result in a SecurityException. | |
| 202 | + * | |
| 203 | + * The <code>backlog</code> argument is the requested maximum number of | |
| 204 | + * pending connections on the socket. Its exact semantics are implementation | |
| 205 | + * specific. In particular, an implementation may impose a maximum length | |
| 206 | + * or may choose to ignore the parameter altogther. The value provided | |
| 207 | + * should be greater than <code>0</code>. If it is less than or equal to | |
| 208 | + * <code>0</code>, then an implementation specific default will be used. | |
| 209 | + * <P> | |
| 210 | + * @param port the port number, or <code>0</code> to use a port | |
| 211 | + * number that is automatically allocated. | |
| 212 | + * @param backlog requested maximum length of the queue of incoming | |
| 213 | + * connections. | |
| 214 | + * @param bindAddr the local InetAddress the server will bind to | |
| 215 | + * | |
| 216 | + * @throws SecurityException if a security manager exists and | |
| 217 | + * its <code>checkListen</code> method doesn't allow the operation. | |
| 218 | + * | |
| 219 | + * @throws IOException if an I/O error occurs when opening the socket. | |
| 220 | + * @exception IllegalArgumentException if the port parameter is outside | |
| 221 | + * the specified range of valid port values, which is between | |
| 222 | + * 0 and 65535, inclusive. | |
| 223 | + * | |
| 224 | + * @see SocketOptions | |
| 225 | + * @see SocketImpl | |
| 226 | + * @see SecurityManager#checkListen | |
| 227 | + * @since JDK1.1 | |
| 228 | + */ | |
| 229 | + public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException { | |
| 230 | + setImpl(); | |
| 231 | + if (port < 0 || port > 0xFFFF) | |
| 232 | + throw new IllegalArgumentException( | |
| 233 | + "Port value out of range: " + port); | |
| 234 | + if (backlog < 1) | |
| 235 | + backlog = 50; | |
| 236 | + try { | |
| 237 | + bind(new InetSocketAddress(bindAddr, port), backlog); | |
| 238 | + } catch(SecurityException e) { | |
| 239 | + close(); | |
| 240 | + throw e; | |
| 241 | + } catch(IOException e) { | |
| 242 | + close(); | |
| 243 | + throw e; | |
| 244 | + } | |
| 245 | + } | |
| 246 | + | |
| 247 | + /** | |
| 248 | + * Get the <code>SocketImpl</code> attached to this socket, creating | |
| 249 | + * it if necessary. | |
| 250 | + * | |
| 251 | + * @return the <code>SocketImpl</code> attached to that ServerSocket. | |
| 252 | + * @throws SocketException if creation fails. | |
| 253 | + * @since 1.4 | |
| 254 | + */ | |
| 255 | + SocketImpl getImpl() throws SocketException { | |
| 256 | + if (!created) | |
| 257 | + createImpl(); | |
| 258 | + return impl; | |
| 259 | + } | |
| 260 | + | |
| 261 | + private void checkOldImpl() { | |
| 262 | + if (impl == null) | |
| 263 | + return; | |
| 264 | + // SocketImpl.connect() is a protected method, therefore we need to use | |
| 265 | + // getDeclaredMethod, therefore we need permission to access the member | |
| 266 | + try { | |
| 267 | + AccessController.doPrivileged( | |
| 268 | + new PrivilegedExceptionAction<Void>() { | |
| 269 | + public Void run() throws NoSuchMethodException { | |
| 270 | + Class[] cl = new Class[2]; | |
| 271 | + cl[0] = SocketAddress.class; | |
| 272 | + cl[1] = Integer.TYPE; | |
| 273 | + impl.getClass().getDeclaredMethod("connect", cl); | |
| 274 | + return null; | |
| 275 | + } | |
| 276 | + }); | |
| 277 | + } catch (java.security.PrivilegedActionException e) { | |
| 278 | + oldImpl = true; | |
| 279 | + } | |
| 280 | + } | |
| 281 | + | |
| 282 | + private void setImpl() { | |
| 283 | + if (factory != null) { | |
| 284 | + impl = factory.createSocketImpl(); | |
| 285 | + checkOldImpl(); | |
| 286 | + } else { | |
| 287 | + // No need to do a checkOldImpl() here, we know it's an up to date | |
| 288 | + // SocketImpl! | |
| 289 | + impl = new SocksSocketImpl(); | |
| 290 | + } | |
| 291 | + if (impl != null) | |
| 292 | + impl.setServerSocket(this); | |
| 293 | + } | |
| 294 | + | |
| 295 | + /** | |
| 296 | + * Creates the socket implementation. | |
| 297 | + * | |
| 298 | + * @throws IOException if creation fails | |
| 299 | + * @since 1.4 | |
| 300 | + */ | |
| 301 | + void createImpl() throws SocketException { | |
| 302 | + if (impl == null) | |
| 303 | + setImpl(); | |
| 304 | + try { | |
| 305 | + impl.create(true); | |
| 306 | + created = true; | |
| 307 | + } catch (IOException e) { | |
| 308 | + throw new SocketException(e.getMessage()); | |
| 309 | + } | |
| 310 | + } | |
| 311 | + | |
| 312 | + /** | |
| 313 | + * | |
| 314 | + * Binds the <code>ServerSocket</code> to a specific address | |
| 315 | + * (IP address and port number). | |
| 316 | + * <p> | |
| 317 | + * If the address is <code>null</code>, then the system will pick up | |
| 318 | + * an ephemeral port and a valid local address to bind the socket. | |
| 319 | + * <p> | |
| 320 | + * @param endpoint The IP address & port number to bind to. | |
| 321 | + * @throws IOException if the bind operation fails, or if the socket | |
| 322 | + * is already bound. | |
| 323 | + * @throws SecurityException if a <code>SecurityManager</code> is present and | |
| 324 | + * its <code>checkListen</code> method doesn't allow the operation. | |
| 325 | + * @throws IllegalArgumentException if endpoint is a | |
| 326 | + * SocketAddress subclass not supported by this socket | |
| 327 | + * @since 1.4 | |
| 328 | + */ | |
| 329 | + public void bind(SocketAddress endpoint) throws IOException { | |
| 330 | + bind(endpoint, 50); | |
| 331 | + } | |
| 332 | + | |
| 333 | + /** | |
| 334 | + * | |
| 335 | + * Binds the <code>ServerSocket</code> to a specific address | |
| 336 | + * (IP address and port number). | |
| 337 | + * <p> | |
| 338 | + * If the address is <code>null</code>, then the system will pick up | |
| 339 | + * an ephemeral port and a valid local address to bind the socket. | |
| 340 | + * <P> | |
| 341 | + * The <code>backlog</code> argument is the requested maximum number of | |
| 342 | + * pending connections on the socket. Its exact semantics are implementation | |
| 343 | + * specific. In particular, an implementation may impose a maximum length | |
| 344 | + * or may choose to ignore the parameter altogther. The value provided | |
| 345 | + * should be greater than <code>0</code>. If it is less than or equal to | |
| 346 | + * <code>0</code>, then an implementation specific default will be used. | |
| 347 | + * @param endpoint The IP address & port number to bind to. | |
| 348 | + * @param backlog requested maximum length of the queue of | |
| 349 | + * incoming connections. | |
| 350 | + * @throws IOException if the bind operation fails, or if the socket | |
| 351 | + * is already bound. | |
| 352 | + * @throws SecurityException if a <code>SecurityManager</code> is present and | |
| 353 | + * its <code>checkListen</code> method doesn't allow the operation. | |
| 354 | + * @throws IllegalArgumentException if endpoint is a | |
| 355 | + * SocketAddress subclass not supported by this socket | |
| 356 | + * @since 1.4 | |
| 357 | + */ | |
| 358 | + public void bind(SocketAddress endpoint, int backlog) throws IOException { | |
| 359 | + if (isClosed()) | |
| 360 | + throw new SocketException("Socket is closed"); | |
| 361 | + if (!oldImpl && isBound()) | |
| 362 | + throw new SocketException("Already bound"); | |
| 363 | + if (endpoint == null) | |
| 364 | + endpoint = new InetSocketAddress(0); | |
| 365 | + if (!(endpoint instanceof InetSocketAddress)) | |
| 366 | + throw new IllegalArgumentException("Unsupported address type"); | |
| 367 | + InetSocketAddress epoint = (InetSocketAddress) endpoint; | |
| 368 | + if (epoint.isUnresolved()) | |
| 369 | + throw new SocketException("Unresolved address"); | |
| 370 | + if (backlog < 1) | |
| 371 | + backlog = 50; | |
| 372 | + try { | |
| 373 | + SecurityManager security = System.getSecurityManager(); | |
| 374 | + if (security != null) | |
| 375 | + security.checkListen(epoint.getPort()); | |
| 376 | + getImpl().bind(epoint.getAddress(), epoint.getPort()); | |
| 377 | + getImpl().listen(backlog); | |
| 378 | + bound = true; | |
| 379 | + } catch(SecurityException e) { | |
| 380 | + bound = false; | |
| 381 | + throw e; | |
| 382 | + } catch(IOException e) { | |
| 383 | + bound = false; | |
| 384 | + throw e; | |
| 385 | + } | |
| 386 | + } | |
| 387 | + | |
| 388 | + /** | |
| 389 | + * Returns the local address of this server socket. | |
| 390 | + * <p> | |
| 391 | + * If the socket was bound prior to being {@link #close closed}, | |
| 392 | + * then this method will continue to return the local address | |
| 393 | + * after the socket is closed. | |
| 394 | + * | |
| 395 | + * @return the address to which this socket is bound, | |
| 396 | + * or <code>null</code> if the socket is unbound. | |
| 397 | + */ | |
| 398 | + public InetAddress getInetAddress() { | |
| 399 | + if (!isBound()) | |
| 400 | + return null; | |
| 401 | + try { | |
| 402 | + return getImpl().getInetAddress(); | |
| 403 | + } catch (SocketException e) { | |
| 404 | + // nothing | |
| 405 | + // If we're bound, the impl has been created | |
| 406 | + // so we shouldn't get here | |
| 407 | + } | |
| 408 | + return null; | |
| 409 | + } | |
| 410 | + | |
| 411 | + /** | |
| 412 | + * Returns the port number on which this socket is listening. | |
| 413 | + * <p> | |
| 414 | + * If the socket was bound prior to being {@link #close closed}, | |
| 415 | + * then this method will continue to return the port number | |
| 416 | + * after the socket is closed. | |
| 417 | + * | |
| 418 | + * @return the port number to which this socket is listening or | |
| 419 | + * -1 if the socket is not bound yet. | |
| 420 | + */ | |
| 421 | + public int getLocalPort() { | |
| 422 | + if (!isBound()) | |
| 423 | + return -1; | |
| 424 | + try { | |
| 425 | + return getImpl().getLocalPort(); | |
| 426 | + } catch (SocketException e) { | |
| 427 | + // nothing | |
| 428 | + // If we're bound, the impl has been created | |
| 429 | + // so we shouldn't get here | |
| 430 | + } | |
| 431 | + return -1; | |
| 432 | + } | |
| 433 | + | |
| 434 | + /** | |
| 435 | + * Returns the address of the endpoint this socket is bound to, or | |
| 436 | + * <code>null</code> if it is not bound yet. | |
| 437 | + * <p> | |
| 438 | + * If the socket was bound prior to being {@link #close closed}, | |
| 439 | + * then this method will continue to return the address of the endpoint | |
| 440 | + * after the socket is closed. | |
| 441 | + * | |
| 442 | + * @return a <code>SocketAddress</code> representing the local endpoint of this | |
| 443 | + * socket, or <code>null</code> if it is not bound yet. | |
| 444 | + * @see #getInetAddress() | |
| 445 | + * @see #getLocalPort() | |
| 446 | + * @see #bind(SocketAddress) | |
| 447 | + * @since 1.4 | |
| 448 | + */ | |
| 449 | + | |
| 450 | + public SocketAddress getLocalSocketAddress() { | |
| 451 | + if (!isBound()) | |
| 452 | + return null; | |
| 453 | + return new InetSocketAddress(getInetAddress(), getLocalPort()); | |
| 454 | + } | |
| 455 | + | |
| 456 | + /** | |
| 457 | + * Listens for a connection to be made to this socket and accepts | |
| 458 | + * it. The method blocks until a connection is made. | |
| 459 | + * | |
| 460 | + * <p>A new Socket <code>s</code> is created and, if there | |
| 461 | + * is a security manager, | |
| 462 | + * the security manager's <code>checkAccept</code> method is called | |
| 463 | + * with <code>s.getInetAddress().getHostAddress()</code> and | |
| 464 | + * <code>s.getPort()</code> | |
| 465 | + * as its arguments to ensure the operation is allowed. | |
| 466 | + * This could result in a SecurityException. | |
| 467 | + * | |
| 468 | + * @exception IOException if an I/O error occurs when waiting for a | |
| 469 | + * connection. | |
| 470 | + * @exception SecurityException if a security manager exists and its | |
| 471 | + * <code>checkAccept</code> method doesn't allow the operation. | |
| 472 | + * @exception SocketTimeoutException if a timeout was previously set with setSoTimeout and | |
| 473 | + * the timeout has been reached. | |
| 474 | + * @exception java.nio.channels.IllegalBlockingModeException | |
| 475 | + * if this socket has an associated channel, the channel is in | |
| 476 | + * non-blocking mode, and there is no connection ready to be | |
| 477 | + * accepted | |
| 478 | + * | |
| 479 | + * @return the new Socket | |
| 480 | + * @see SecurityManager#checkAccept | |
| 481 | + * @revised 1.4 | |
| 482 | + * @spec JSR-51 | |
| 483 | + */ | |
| 484 | + public Socket accept() throws IOException { | |
| 485 | + if (isClosed()) | |
| 486 | + throw new SocketException("Socket is closed"); | |
| 487 | + if (!isBound()) | |
| 488 | + throw new SocketException("Socket is not bound yet"); | |
| 489 | + Socket s = new Socket((SocketImpl) null); | |
| 490 | + implAccept(s); | |
| 491 | + return s; | |
| 492 | + } | |
| 493 | + | |
| 494 | + /** | |
| 495 | + * Subclasses of ServerSocket use this method to override accept() | |
| 496 | + * to return their own subclass of socket. So a FooServerSocket | |
| 497 | + * will typically hand this method an <i>empty</i> FooSocket. On | |
| 498 | + * return from implAccept the FooSocket will be connected to a client. | |
| 499 | + * | |
| 500 | + * @param s the Socket | |
| 501 | + * @throws java.nio.channels.IllegalBlockingModeException | |
| 502 | + * if this socket has an associated channel, | |
| 503 | + * and the channel is in non-blocking mode | |
| 504 | + * @throws IOException if an I/O error occurs when waiting | |
| 505 | + * for a connection. | |
| 506 | + * @since JDK1.1 | |
| 507 | + * @revised 1.4 | |
| 508 | + * @spec JSR-51 | |
| 509 | + */ | |
| 510 | + protected final void implAccept(Socket s) throws IOException { | |
| 511 | + SocketImpl si = null; | |
| 512 | + try { | |
| 513 | + if (s.impl == null) | |
| 514 | + s.setImpl(); | |
| 515 | + else { | |
| 516 | + s.impl.reset(); | |
| 517 | + } | |
| 518 | + si = s.impl; | |
| 519 | + s.impl = null; | |
| 520 | + si.address = new InetAddress(); | |
| 521 | + si.fd = new FileDescriptor(); | |
| 522 | + getImpl().accept(si); | |
| 523 | + | |
| 524 | + SecurityManager security = System.getSecurityManager(); | |
| 525 | + if (security != null) { | |
| 526 | + security.checkAccept(si.getInetAddress().getHostAddress(), | |
| 527 | + si.getPort()); | |
| 528 | + } | |
| 529 | + } catch (IOException e) { | |
| 530 | + if (si != null) | |
| 531 | + si.reset(); | |
| 532 | + s.impl = si; | |
| 533 | + throw e; | |
| 534 | + } catch (SecurityException e) { | |
| 535 | + if (si != null) | |
| 536 | + si.reset(); | |
| 537 | + s.impl = si; | |
| 538 | + throw e; | |
| 539 | + } | |
| 540 | + s.impl = si; | |
| 541 | + s.postAccept(); | |
| 542 | + } | |
| 543 | + | |
| 544 | + /** | |
| 545 | + * Closes this socket. | |
| 546 | + * | |
| 547 | + * Any thread currently blocked in {@link #accept()} will throw | |
| 548 | + * a {@link SocketException}. | |
| 549 | + * | |
| 550 | + * <p> If this socket has an associated channel then the channel is closed | |
| 551 | + * as well. | |
| 552 | + * | |
| 553 | + * @exception IOException if an I/O error occurs when closing the socket. | |
| 554 | + * @revised 1.4 | |
| 555 | + * @spec JSR-51 | |
| 556 | + */ | |
| 557 | + public void close() throws IOException { | |
| 558 | + synchronized(closeLock) { | |
| 559 | + if (isClosed()) | |
| 560 | + return; | |
| 561 | + if (created) | |
| 562 | + impl.close(); | |
| 563 | + closed = true; | |
| 564 | + } | |
| 565 | + } | |
| 566 | + | |
| 567 | + /** | |
| 568 | + * Returns the unique {@link java.nio.channels.ServerSocketChannel} object | |
| 569 | + * associated with this socket, if any. | |
| 570 | + * | |
| 571 | + * <p> A server socket will have a channel if, and only if, the channel | |
| 572 | + * itself was created via the {@link | |
| 573 | + * java.nio.channels.ServerSocketChannel#open ServerSocketChannel.open} | |
| 574 | + * method. | |
| 575 | + * | |
| 576 | + * @return the server-socket channel associated with this socket, | |
| 577 | + * or <tt>null</tt> if this socket was not created | |
| 578 | + * for a channel | |
| 579 | + * | |
| 580 | + * @since 1.4 | |
| 581 | + * @spec JSR-51 | |
| 582 | + */ | |
| 583 | + public ServerSocketChannel getChannel() { | |
| 584 | + return null; | |
| 585 | + } | |
| 586 | + | |
| 587 | + /** | |
| 588 | + * Returns the binding state of the ServerSocket. | |
| 589 | + * | |
| 590 | + * @return true if the ServerSocket succesfuly bound to an address | |
| 591 | + * @since 1.4 | |
| 592 | + */ | |
| 593 | + public boolean isBound() { | |
| 594 | + // Before 1.3 ServerSockets were always bound during creation | |
| 595 | + return bound || oldImpl; | |
| 596 | + } | |
| 597 | + | |
| 598 | + /** | |
| 599 | + * Returns the closed state of the ServerSocket. | |
| 600 | + * | |
| 601 | + * @return true if the socket has been closed | |
| 602 | + * @since 1.4 | |
| 603 | + */ | |
| 604 | + public boolean isClosed() { | |
| 605 | + synchronized(closeLock) { | |
| 606 | + return closed; | |
| 607 | + } | |
| 608 | + } | |
| 609 | + | |
| 610 | + /** | |
| 611 | + * Enable/disable SO_TIMEOUT with the specified timeout, in | |
| 612 | + * milliseconds. With this option set to a non-zero timeout, | |
| 613 | + * a call to accept() for this ServerSocket | |
| 614 | + * will block for only this amount of time. If the timeout expires, | |
| 615 | + * a <B>java.net.SocketTimeoutException</B> is raised, though the | |
| 616 | + * ServerSocket is still valid. The option <B>must</B> be enabled | |
| 617 | + * prior to entering the blocking operation to have effect. The | |
| 618 | + * timeout must be > 0. | |
| 619 | + * A timeout of zero is interpreted as an infinite timeout. | |
| 620 | + * @param timeout the specified timeout, in milliseconds | |
| 621 | + * @exception SocketException if there is an error in | |
| 622 | + * the underlying protocol, such as a TCP error. | |
| 623 | + * @since JDK1.1 | |
| 624 | + * @see #getSoTimeout() | |
| 625 | + */ | |
| 626 | + public synchronized void setSoTimeout(int timeout) throws SocketException { | |
| 627 | + if (isClosed()) | |
| 628 | + throw new SocketException("Socket is closed"); | |
| 629 | + getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); | |
| 630 | + } | |
| 631 | + | |
| 632 | + /** | |
| 633 | + * Retrieve setting for SO_TIMEOUT. 0 returns implies that the | |
| 634 | + * option is disabled (i.e., timeout of infinity). | |
| 635 | + * @return the SO_TIMEOUT value | |
| 636 | + * @exception IOException if an I/O error occurs | |
| 637 | + * @since JDK1.1 | |
| 638 | + * @see #setSoTimeout(int) | |
| 639 | + */ | |
| 640 | + public synchronized int getSoTimeout() throws IOException { | |
| 641 | + if (isClosed()) | |
| 642 | + throw new SocketException("Socket is closed"); | |
| 643 | + Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT); | |
| 644 | + /* extra type safety */ | |
| 645 | + if (o instanceof Integer) { | |
| 646 | + return ((Integer) o).intValue(); | |
| 647 | + } else { | |
| 648 | + return 0; | |
| 649 | + } | |
| 650 | + } | |
| 651 | + | |
| 652 | + /** | |
| 653 | + * Enable/disable the SO_REUSEADDR socket option. | |
| 654 | + * <p> | |
| 655 | + * When a TCP connection is closed the connection may remain | |
| 656 | + * in a timeout state for a period of time after the connection | |
| 657 | + * is closed (typically known as the <tt>TIME_WAIT</tt> state | |
| 658 | + * or <tt>2MSL</tt> wait state). | |
| 659 | + * For applications using a well known socket address or port | |
| 660 | + * it may not be possible to bind a socket to the required | |
| 661 | + * <tt>SocketAddress</tt> if there is a connection in the | |
| 662 | + * timeout state involving the socket address or port. | |
| 663 | + * <p> | |
| 664 | + * Enabling <tt>SO_REUSEADDR</tt> prior to binding the socket | |
| 665 | + * using {@link #bind(SocketAddress)} allows the socket to be | |
| 666 | + * bound even though a previous connection is in a timeout | |
| 667 | + * state. | |
| 668 | + * <p> | |
| 669 | + * When a <tt>ServerSocket</tt> is created the initial setting | |
| 670 | + * of <tt>SO_REUSEADDR</tt> is not defined. Applications can | |
| 671 | + * use {@link #getReuseAddress()} to determine the initial | |
| 672 | + * setting of <tt>SO_REUSEADDR</tt>. | |
| 673 | + * <p> | |
| 674 | + * The behaviour when <tt>SO_REUSEADDR</tt> is enabled or | |
| 675 | + * disabled after a socket is bound (See {@link #isBound()}) | |
| 676 | + * is not defined. | |
| 677 | + * | |
| 678 | + * @param on whether to enable or disable the socket option | |
| 679 | + * @exception SocketException if an error occurs enabling or | |
| 680 | + * disabling the <tt>SO_RESUEADDR</tt> socket option, | |
| 681 | + * or the socket is closed. | |
| 682 | + * @since 1.4 | |
| 683 | + * @see #getReuseAddress() | |
| 684 | + * @see #bind(SocketAddress) | |
| 685 | + * @see #isBound() | |
| 686 | + * @see #isClosed() | |
| 687 | + */ | |
| 688 | + public void setReuseAddress(boolean on) throws SocketException { | |
| 689 | + if (isClosed()) | |
| 690 | + throw new SocketException("Socket is closed"); | |
| 691 | + getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); | |
| 692 | + } | |
| 693 | + | |
| 694 | + /** | |
| 695 | + * Tests if SO_REUSEADDR is enabled. | |
| 696 | + * | |
| 697 | + * @return a <code>boolean</code> indicating whether or not SO_REUSEADDR is enabled. | |
| 698 | + * @exception SocketException if there is an error | |
| 699 | + * in the underlying protocol, such as a TCP error. | |
| 700 | + * @since 1.4 | |
| 701 | + * @see #setReuseAddress(boolean) | |
| 702 | + */ | |
| 703 | + public boolean getReuseAddress() throws SocketException { | |
| 704 | + if (isClosed()) | |
| 705 | + throw new SocketException("Socket is closed"); | |
| 706 | + return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue(); | |
| 707 | + } | |
| 708 | + | |
| 709 | + /** | |
| 710 | + * Returns the implementation address and implementation port of | |
| 711 | + * this socket as a <code>String</code>. | |
| 712 | + * | |
| 713 | + * @return a string representation of this socket. | |
| 714 | + */ | |
| 715 | + public String toString() { | |
| 716 | + if (!isBound()) | |
| 717 | + return "ServerSocket[unbound]"; | |
| 718 | + return "ServerSocket[addr=" + impl.getInetAddress() + | |
| 719 | + ",port=" + impl.getPort() + | |
| 720 | + ",localport=" + impl.getLocalPort() + "]"; | |
| 721 | + } | |
| 722 | + | |
| 723 | + void setBound() { | |
| 724 | + bound = true; | |
| 725 | + } | |
| 726 | + | |
| 727 | + void setCreated() { | |
| 728 | + created = true; | |
| 729 | + } | |
| 730 | + | |
| 731 | + /** | |
| 732 | + * The factory for all server sockets. | |
| 733 | + */ | |
| 734 | + private static SocketImplFactory factory = null; | |
| 735 | + | |
| 736 | + /** | |
| 737 | + * Sets the server socket implementation factory for the | |
| 738 | + * application. The factory can be specified only once. | |
| 739 | + * <p> | |
| 740 | + * When an application creates a new server socket, the socket | |
| 741 | + * implementation factory's <code>createSocketImpl</code> method is | |
| 742 | + * called to create the actual socket implementation. | |
| 743 | + * <p> | |
| 744 | + * Passing <code>null</code> to the method is a no-op unless the factory | |
| 745 | + * was already set. | |
| 746 | + * <p> | |
| 747 | + * If there is a security manager, this method first calls | |
| 748 | + * the security manager's <code>checkSetFactory</code> method | |
| 749 | + * to ensure the operation is allowed. | |
| 750 | + * This could result in a SecurityException. | |
| 751 | + * | |
| 752 | + * @param fac the desired factory. | |
| 753 | + * @exception IOException if an I/O error occurs when setting the | |
| 754 | + * socket factory. | |
| 755 | + * @exception SocketException if the factory has already been defined. | |
| 756 | + * @exception SecurityException if a security manager exists and its | |
| 757 | + * <code>checkSetFactory</code> method doesn't allow the operation. | |
| 758 | + * @see java.net.SocketImplFactory#createSocketImpl() | |
| 759 | + * @see SecurityManager#checkSetFactory | |
| 760 | + */ | |
| 761 | + public static synchronized void setSocketFactory(SocketImplFactory fac) throws IOException { | |
| 762 | + if (factory != null) { | |
| 763 | + throw new SocketException("factory already defined"); | |
| 764 | + } | |
| 765 | + SecurityManager security = System.getSecurityManager(); | |
| 766 | + if (security != null) { | |
| 767 | + security.checkSetFactory(); | |
| 768 | + } | |
| 769 | + factory = fac; | |
| 770 | + } | |
| 771 | + | |
| 772 | + /** | |
| 773 | + * Sets a default proposed value for the SO_RCVBUF option for sockets | |
| 774 | + * accepted from this <tt>ServerSocket</tt>. The value actually set | |
| 775 | + * in the accepted socket must be determined by calling | |
| 776 | + * {@link Socket#getReceiveBufferSize()} after the socket | |
| 777 | + * is returned by {@link #accept()}. | |
| 778 | + * <p> | |
| 779 | + * The value of SO_RCVBUF is used both to set the size of the internal | |
| 780 | + * socket receive buffer, and to set the size of the TCP receive window | |
| 781 | + * that is advertized to the remote peer. | |
| 782 | + * <p> | |
| 783 | + * It is possible to change the value subsequently, by calling | |
| 784 | + * {@link Socket#setReceiveBufferSize(int)}. However, if the application | |
| 785 | + * wishes to allow a receive window larger than 64K bytes, as defined by RFC1323 | |
| 786 | + * then the proposed value must be set in the ServerSocket <B>before</B> | |
| 787 | + * it is bound to a local address. This implies, that the ServerSocket must be | |
| 788 | + * created with the no-argument constructor, then setReceiveBufferSize() must | |
| 789 | + * be called and lastly the ServerSocket is bound to an address by calling bind(). | |
| 790 | + * <p> | |
| 791 | + * Failure to do this will not cause an error, and the buffer size may be set to the | |
| 792 | + * requested value but the TCP receive window in sockets accepted from | |
| 793 | + * this ServerSocket will be no larger than 64K bytes. | |
| 794 | + * | |
| 795 | + * @exception SocketException if there is an error | |
| 796 | + * in the underlying protocol, such as a TCP error. | |
| 797 | + * | |
| 798 | + * @param size the size to which to set the receive buffer | |
| 799 | + * size. This value must be greater than 0. | |
| 800 | + * | |
| 801 | + * @exception IllegalArgumentException if the | |
| 802 | + * value is 0 or is negative. | |
| 803 | + * | |
| 804 | + * @since 1.4 | |
| 805 | + * @see #getReceiveBufferSize | |
| 806 | + */ | |
| 807 | + public synchronized void setReceiveBufferSize (int size) throws SocketException { | |
| 808 | + if (!(size > 0)) { | |
| 809 | + throw new IllegalArgumentException("negative receive size"); | |
| 810 | + } | |
| 811 | + if (isClosed()) | |
| 812 | + throw new SocketException("Socket is closed"); | |
| 813 | + getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size)); | |
| 814 | + } | |
| 815 | + | |
| 816 | + /** | |
| 817 | + * Gets the value of the SO_RCVBUF option for this <tt>ServerSocket</tt>, | |
| 818 | + * that is the proposed buffer size that will be used for Sockets accepted | |
| 819 | + * from this <tt>ServerSocket</tt>. | |
| 820 | + * | |
| 821 | + * <p>Note, the value actually set in the accepted socket is determined by | |
| 822 | + * calling {@link Socket#getReceiveBufferSize()}. | |
| 823 | + * @return the value of the SO_RCVBUF option for this <tt>Socket</tt>. | |
| 824 | + * @exception SocketException if there is an error | |
| 825 | + * in the underlying protocol, such as a TCP error. | |
| 826 | + * @see #setReceiveBufferSize(int) | |
| 827 | + * @since 1.4 | |
| 828 | + */ | |
| 829 | + public synchronized int getReceiveBufferSize() | |
| 830 | + throws SocketException{ | |
| 831 | + if (isClosed()) | |
| 832 | + throw new SocketException("Socket is closed"); | |
| 833 | + int result = 0; | |
| 834 | + Object o = getImpl().getOption(SocketOptions.SO_RCVBUF); | |
| 835 | + if (o instanceof Integer) { | |
| 836 | + result = ((Integer)o).intValue(); | |
| 837 | + } | |
| 838 | + return result; | |
| 839 | + } | |
| 840 | + | |
| 841 | + /** | |
| 842 | + * Sets performance preferences for this ServerSocket. | |
| 843 | + * | |
| 844 | + * <p> Sockets use the TCP/IP protocol by default. Some implementations | |
| 845 | + * may offer alternative protocols which have different performance | |
| 846 | + * characteristics than TCP/IP. This method allows the application to | |
| 847 | + * express its own preferences as to how these tradeoffs should be made | |
| 848 | + * when the implementation chooses from the available protocols. | |
| 849 | + * | |
| 850 | + * <p> Performance preferences are described by three integers | |
| 851 | + * whose values indicate the relative importance of short connection time, | |
| 852 | + * low latency, and high bandwidth. The absolute values of the integers | |
| 853 | + * are irrelevant; in order to choose a protocol the values are simply | |
| 854 | + * compared, with larger values indicating stronger preferences. If the | |
| 855 | + * application prefers short connection time over both low latency and high | |
| 856 | + * bandwidth, for example, then it could invoke this method with the values | |
| 857 | + * <tt>(1, 0, 0)</tt>. If the application prefers high bandwidth above low | |
| 858 | + * latency, and low latency above short connection time, then it could | |
| 859 | + * invoke this method with the values <tt>(0, 1, 2)</tt>. | |
| 860 | + * | |
| 861 | + * <p> Invoking this method after this socket has been bound | |
| 862 | + * will have no effect. This implies that in order to use this capability | |
| 863 | + * requires the socket to be created with the no-argument constructor. | |
| 864 | + * | |
| 865 | + * @param connectionTime | |
| 866 | + * An <tt>int</tt> expressing the relative importance of a short | |
| 867 | + * connection time | |
| 868 | + * | |
| 869 | + * @param latency | |
| 870 | + * An <tt>int</tt> expressing the relative importance of low | |
| 871 | + * latency | |
| 872 | + * | |
| 873 | + * @param bandwidth | |
| 874 | + * An <tt>int</tt> expressing the relative importance of high | |
| 875 | + * bandwidth | |
| 876 | + * | |
| 877 | + * @since 1.5 | |
| 878 | + */ | |
| 879 | + public void setPerformancePreferences(int connectionTime, | |
| 880 | + int latency, | |
| 881 | + int bandwidth) | |
| 882 | + { | |
| 883 | + /* Not implemented yet */ | |
| 884 | + } | |
| 885 | + | |
| 886 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,1663 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.InputStream; | |
| 29 | +import java.io.OutputStream; | |
| 30 | +import java.io.IOException; | |
| 31 | +import java.io.InterruptedIOException; | |
| 32 | +import java.nio.channels.SocketChannel; | |
| 33 | +import java.security.AccessController; | |
| 34 | +import java.security.PrivilegedExceptionAction; | |
| 35 | +import java.security.PrivilegedAction; | |
| 36 | + | |
| 37 | +/** | |
| 38 | + * This class implements client sockets (also called just | |
| 39 | + * "sockets"). A socket is an endpoint for communication | |
| 40 | + * between two machines. | |
| 41 | + * <p> | |
| 42 | + * The actual work of the socket is performed by an instance of the | |
| 43 | + * <code>SocketImpl</code> class. An application, by changing | |
| 44 | + * the socket factory that creates the socket implementation, | |
| 45 | + * can configure itself to create sockets appropriate to the local | |
| 46 | + * firewall. | |
| 47 | + * | |
| 48 | + * @author unascribed | |
| 49 | + * @see java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory) | |
| 50 | + * @see java.net.SocketImpl | |
| 51 | + * @see java.nio.channels.SocketChannel | |
| 52 | + * @since JDK1.0 | |
| 53 | + */ | |
| 54 | +public | |
| 55 | +class Socket implements java.io.Closeable { | |
| 56 | + /** | |
| 57 | + * Various states of this socket. | |
| 58 | + */ | |
| 59 | + private boolean created = false; | |
| 60 | + private boolean bound = false; | |
| 61 | + private boolean connected = false; | |
| 62 | + private boolean closed = false; | |
| 63 | + private Object closeLock = new Object(); | |
| 64 | + private boolean shutIn = false; | |
| 65 | + private boolean shutOut = false; | |
| 66 | + | |
| 67 | + /** | |
| 68 | + * The implementation of this Socket. | |
| 69 | + */ | |
| 70 | + SocketImpl impl; | |
| 71 | + | |
| 72 | + /** | |
| 73 | + * Are we using an older SocketImpl? | |
| 74 | + */ | |
| 75 | + private boolean oldImpl = false; | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * Creates an unconnected socket, with the | |
| 79 | + * system-default type of SocketImpl. | |
| 80 | + * | |
| 81 | + * @since JDK1.1 | |
| 82 | + * @revised 1.4 | |
| 83 | + */ | |
| 84 | + public Socket() { | |
| 85 | + setImpl(); | |
| 86 | + } | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * Creates an unconnected socket, specifying the type of proxy, if any, | |
| 90 | + * that should be used regardless of any other settings. | |
| 91 | + * <P> | |
| 92 | + * If there is a security manager, its <code>checkConnect</code> method | |
| 93 | + * is called with the proxy host address and port number | |
| 94 | + * as its arguments. This could result in a SecurityException. | |
| 95 | + * <P> | |
| 96 | + * Examples: | |
| 97 | + * <UL> <LI><code>Socket s = new Socket(Proxy.NO_PROXY);</code> will create | |
| 98 | + * a plain socket ignoring any other proxy configuration.</LI> | |
| 99 | + * <LI><code>Socket s = new Socket(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("socks.mydom.com", 1080)));</code> | |
| 100 | + * will create a socket connecting through the specified SOCKS proxy | |
| 101 | + * server.</LI> | |
| 102 | + * </UL> | |
| 103 | + * | |
| 104 | + * @param proxy a {@link java.net.Proxy Proxy} object specifying what kind | |
| 105 | + * of proxying should be used. | |
| 106 | + * @throws IllegalArgumentException if the proxy is of an invalid type | |
| 107 | + * or <code>null</code>. | |
| 108 | + * @throws SecurityException if a security manager is present and | |
| 109 | + * permission to connect to the proxy is | |
| 110 | + * denied. | |
| 111 | + * @see java.net.ProxySelector | |
| 112 | + * @see java.net.Proxy | |
| 113 | + * | |
| 114 | + * @since 1.5 | |
| 115 | + */ | |
| 116 | + public Socket(Proxy proxy) { | |
| 117 | + // Create a copy of Proxy as a security measure | |
| 118 | + if (proxy == null) { | |
| 119 | + throw new IllegalArgumentException("Invalid Proxy"); | |
| 120 | + } | |
| 121 | + Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY : sun.net.ApplicationProxy.create(proxy); | |
| 122 | + if (p.type() == Proxy.Type.SOCKS) { | |
| 123 | + SecurityManager security = System.getSecurityManager(); | |
| 124 | + InetSocketAddress epoint = (InetSocketAddress) p.address(); | |
| 125 | + if (epoint.getAddress() != null) { | |
| 126 | + checkAddress (epoint.getAddress(), "Socket"); | |
| 127 | + } | |
| 128 | + if (security != null) { | |
| 129 | + if (epoint.isUnresolved()) | |
| 130 | + epoint = new InetSocketAddress(epoint.getHostName(), epoint.getPort()); | |
| 131 | + if (epoint.isUnresolved()) | |
| 132 | + security.checkConnect(epoint.getHostName(), epoint.getPort()); | |
| 133 | + else | |
| 134 | + security.checkConnect(epoint.getAddress().getHostAddress(), | |
| 135 | + epoint.getPort()); | |
| 136 | + } | |
| 137 | + impl = new SocksSocketImpl(p); | |
| 138 | + impl.setSocket(this); | |
| 139 | + } else { | |
| 140 | + if (p == Proxy.NO_PROXY) { | |
| 141 | + if (factory == null) { | |
| 142 | + impl = new PlainSocketImpl(); | |
| 143 | + impl.setSocket(this); | |
| 144 | + } else | |
| 145 | + setImpl(); | |
| 146 | + } else | |
| 147 | + throw new IllegalArgumentException("Invalid Proxy"); | |
| 148 | + } | |
| 149 | + } | |
| 150 | + | |
| 151 | + /** | |
| 152 | + * Creates an unconnected Socket with a user-specified | |
| 153 | + * SocketImpl. | |
| 154 | + * <P> | |
| 155 | + * @param impl an instance of a <B>SocketImpl</B> | |
| 156 | + * the subclass wishes to use on the Socket. | |
| 157 | + * | |
| 158 | + * @exception SocketException if there is an error in the underlying protocol, | |
| 159 | + * such as a TCP error. | |
| 160 | + * @since JDK1.1 | |
| 161 | + */ | |
| 162 | + protected Socket(SocketImpl impl) throws SocketException { | |
| 163 | + this.impl = impl; | |
| 164 | + if (impl != null) { | |
| 165 | + checkOldImpl(); | |
| 166 | + this.impl.setSocket(this); | |
| 167 | + } | |
| 168 | + } | |
| 169 | + | |
| 170 | + /** | |
| 171 | + * Creates a stream socket and connects it to the specified port | |
| 172 | + * number on the named host. | |
| 173 | + * <p> | |
| 174 | + * If the specified host is <tt>null</tt> it is the equivalent of | |
| 175 | + * specifying the address as <tt>{@link java.net.InetAddress#getByName InetAddress.getByName}(null)</tt>. | |
| 176 | + * In other words, it is equivalent to specifying an address of the | |
| 177 | + * loopback interface. </p> | |
| 178 | + * <p> | |
| 179 | + * If the application has specified a server socket factory, that | |
| 180 | + * factory's <code>createSocketImpl</code> method is called to create | |
| 181 | + * the actual socket implementation. Otherwise a "plain" socket is created. | |
| 182 | + * <p> | |
| 183 | + * If there is a security manager, its | |
| 184 | + * <code>checkConnect</code> method is called | |
| 185 | + * with the host address and <code>port</code> | |
| 186 | + * as its arguments. This could result in a SecurityException. | |
| 187 | + * | |
| 188 | + * @param host the host name, or <code>null</code> for the loopback address. | |
| 189 | + * @param port the port number. | |
| 190 | + * | |
| 191 | + * @exception UnknownHostException if the IP address of | |
| 192 | + * the host could not be determined. | |
| 193 | + * | |
| 194 | + * @exception IOException if an I/O error occurs when creating the socket. | |
| 195 | + * @exception SecurityException if a security manager exists and its | |
| 196 | + * <code>checkConnect</code> method doesn't allow the operation. | |
| 197 | + * @exception IllegalArgumentException if the port parameter is outside | |
| 198 | + * the specified range of valid port values, which is between | |
| 199 | + * 0 and 65535, inclusive. | |
| 200 | + * @see java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory) | |
| 201 | + * @see java.net.SocketImpl | |
| 202 | + * @see java.net.SocketImplFactory#createSocketImpl() | |
| 203 | + * @see SecurityManager#checkConnect | |
| 204 | + */ | |
| 205 | + public Socket(String host, int port) | |
| 206 | + throws UnknownHostException, IOException | |
| 207 | + { | |
| 208 | + this(host != null ? new InetSocketAddress(host, port) : | |
| 209 | + new InetSocketAddress(InetAddress.getByName(null), port), | |
| 210 | + (SocketAddress) null, true); | |
| 211 | + } | |
| 212 | + | |
| 213 | + /** | |
| 214 | + * Creates a stream socket and connects it to the specified port | |
| 215 | + * number at the specified IP address. | |
| 216 | + * <p> | |
| 217 | + * If the application has specified a socket factory, that factory's | |
| 218 | + * <code>createSocketImpl</code> method is called to create the | |
| 219 | + * actual socket implementation. Otherwise a "plain" socket is created. | |
| 220 | + * <p> | |
| 221 | + * If there is a security manager, its | |
| 222 | + * <code>checkConnect</code> method is called | |
| 223 | + * with the host address and <code>port</code> | |
| 224 | + * as its arguments. This could result in a SecurityException. | |
| 225 | + * | |
| 226 | + * @param address the IP address. | |
| 227 | + * @param port the port number. | |
| 228 | + * @exception IOException if an I/O error occurs when creating the socket. | |
| 229 | + * @exception SecurityException if a security manager exists and its | |
| 230 | + * <code>checkConnect</code> method doesn't allow the operation. | |
| 231 | + * @exception IllegalArgumentException if the port parameter is outside | |
| 232 | + * the specified range of valid port values, which is between | |
| 233 | + * 0 and 65535, inclusive. | |
| 234 | + * @exception NullPointerException if <code>address</code> is null. | |
| 235 | + * @see java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory) | |
| 236 | + * @see java.net.SocketImpl | |
| 237 | + * @see java.net.SocketImplFactory#createSocketImpl() | |
| 238 | + * @see SecurityManager#checkConnect | |
| 239 | + */ | |
| 240 | + public Socket(InetAddress address, int port) throws IOException { | |
| 241 | + this(address != null ? new InetSocketAddress(address, port) : null, | |
| 242 | + (SocketAddress) null, true); | |
| 243 | + } | |
| 244 | + | |
| 245 | + /** | |
| 246 | + * Creates a socket and connects it to the specified remote host on | |
| 247 | + * the specified remote port. The Socket will also bind() to the local | |
| 248 | + * address and port supplied. | |
| 249 | + * <p> | |
| 250 | + * If the specified host is <tt>null</tt> it is the equivalent of | |
| 251 | + * specifying the address as <tt>{@link java.net.InetAddress#getByName InetAddress.getByName}(null)</tt>. | |
| 252 | + * In other words, it is equivalent to specifying an address of the | |
| 253 | + * loopback interface. </p> | |
| 254 | + * <p> | |
| 255 | + * A local port number of <code>zero</code> will let the system pick up a | |
| 256 | + * free port in the <code>bind</code> operation.</p> | |
| 257 | + * <p> | |
| 258 | + * If there is a security manager, its | |
| 259 | + * <code>checkConnect</code> method is called | |
| 260 | + * with the host address and <code>port</code> | |
| 261 | + * as its arguments. This could result in a SecurityException. | |
| 262 | + * | |
| 263 | + * @param host the name of the remote host, or <code>null</code> for the loopback address. | |
| 264 | + * @param port the remote port | |
| 265 | + * @param localAddr the local address the socket is bound to, or | |
| 266 | + * <code>null</code> for the <code>anyLocal</code> address. | |
| 267 | + * @param localPort the local port the socket is bound to, or | |
| 268 | + * <code>zero</code> for a system selected free port. | |
| 269 | + * @exception IOException if an I/O error occurs when creating the socket. | |
| 270 | + * @exception SecurityException if a security manager exists and its | |
| 271 | + * <code>checkConnect</code> method doesn't allow the operation. | |
| 272 | + * @exception IllegalArgumentException if the port parameter or localPort | |
| 273 | + * parameter is outside the specified range of valid port values, | |
| 274 | + * which is between 0 and 65535, inclusive. | |
| 275 | + * @see SecurityManager#checkConnect | |
| 276 | + * @since JDK1.1 | |
| 277 | + */ | |
| 278 | + public Socket(String host, int port, InetAddress localAddr, | |
| 279 | + int localPort) throws IOException { | |
| 280 | + this(host != null ? new InetSocketAddress(host, port) : | |
| 281 | + new InetSocketAddress(InetAddress.getByName(null), port), | |
| 282 | + new InetSocketAddress(localAddr, localPort), true); | |
| 283 | + } | |
| 284 | + | |
| 285 | + /** | |
| 286 | + * Creates a socket and connects it to the specified remote address on | |
| 287 | + * the specified remote port. The Socket will also bind() to the local | |
| 288 | + * address and port supplied. | |
| 289 | + * <p> | |
| 290 | + * If the specified local address is <tt>null</tt> it is the equivalent of | |
| 291 | + * specifying the address as the AnyLocal address (see <tt>{@link java.net.InetAddress#isAnyLocalAddress InetAddress.isAnyLocalAddress}()</tt>). | |
| 292 | + * <p> | |
| 293 | + * A local port number of <code>zero</code> will let the system pick up a | |
| 294 | + * free port in the <code>bind</code> operation.</p> | |
| 295 | + * <p> | |
| 296 | + * If there is a security manager, its | |
| 297 | + * <code>checkConnect</code> method is called | |
| 298 | + * with the host address and <code>port</code> | |
| 299 | + * as its arguments. This could result in a SecurityException. | |
| 300 | + * | |
| 301 | + * @param address the remote address | |
| 302 | + * @param port the remote port | |
| 303 | + * @param localAddr the local address the socket is bound to, or | |
| 304 | + * <code>null</code> for the <code>anyLocal</code> address. | |
| 305 | + * @param localPort the local port the socket is bound to or | |
| 306 | + * <code>zero</code> for a system selected free port. | |
| 307 | + * @exception IOException if an I/O error occurs when creating the socket. | |
| 308 | + * @exception SecurityException if a security manager exists and its | |
| 309 | + * <code>checkConnect</code> method doesn't allow the operation. | |
| 310 | + * @exception IllegalArgumentException if the port parameter or localPort | |
| 311 | + * parameter is outside the specified range of valid port values, | |
| 312 | + * which is between 0 and 65535, inclusive. | |
| 313 | + * @exception NullPointerException if <code>address</code> is null. | |
| 314 | + * @see SecurityManager#checkConnect | |
| 315 | + * @since JDK1.1 | |
| 316 | + */ | |
| 317 | + public Socket(InetAddress address, int port, InetAddress localAddr, | |
| 318 | + int localPort) throws IOException { | |
| 319 | + this(address != null ? new InetSocketAddress(address, port) : null, | |
| 320 | + new InetSocketAddress(localAddr, localPort), true); | |
| 321 | + } | |
| 322 | + | |
| 323 | + /** | |
| 324 | + * Creates a stream socket and connects it to the specified port | |
| 325 | + * number on the named host. | |
| 326 | + * <p> | |
| 327 | + * If the specified host is <tt>null</tt> it is the equivalent of | |
| 328 | + * specifying the address as <tt>{@link java.net.InetAddress#getByName InetAddress.getByName}(null)</tt>. | |
| 329 | + * In other words, it is equivalent to specifying an address of the | |
| 330 | + * loopback interface. </p> | |
| 331 | + * <p> | |
| 332 | + * If the stream argument is <code>true</code>, this creates a | |
| 333 | + * stream socket. If the stream argument is <code>false</code>, it | |
| 334 | + * creates a datagram socket. | |
| 335 | + * <p> | |
| 336 | + * If the application has specified a server socket factory, that | |
| 337 | + * factory's <code>createSocketImpl</code> method is called to create | |
| 338 | + * the actual socket implementation. Otherwise a "plain" socket is created. | |
| 339 | + * <p> | |
| 340 | + * If there is a security manager, its | |
| 341 | + * <code>checkConnect</code> method is called | |
| 342 | + * with the host address and <code>port</code> | |
| 343 | + * as its arguments. This could result in a SecurityException. | |
| 344 | + * <p> | |
| 345 | + * If a UDP socket is used, TCP/IP related socket options will not apply. | |
| 346 | + * | |
| 347 | + * @param host the host name, or <code>null</code> for the loopback address. | |
| 348 | + * @param port the port number. | |
| 349 | + * @param stream a <code>boolean</code> indicating whether this is | |
| 350 | + * a stream socket or a datagram socket. | |
| 351 | + * @exception IOException if an I/O error occurs when creating the socket. | |
| 352 | + * @exception SecurityException if a security manager exists and its | |
| 353 | + * <code>checkConnect</code> method doesn't allow the operation. | |
| 354 | + * @exception IllegalArgumentException if the port parameter is outside | |
| 355 | + * the specified range of valid port values, which is between | |
| 356 | + * 0 and 65535, inclusive. | |
| 357 | + * @see java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory) | |
| 358 | + * @see java.net.SocketImpl | |
| 359 | + * @see java.net.SocketImplFactory#createSocketImpl() | |
| 360 | + * @see SecurityManager#checkConnect | |
| 361 | + * @deprecated Use DatagramSocket instead for UDP transport. | |
| 362 | + */ | |
| 363 | + @Deprecated | |
| 364 | + public Socket(String host, int port, boolean stream) throws IOException { | |
| 365 | + this(host != null ? new InetSocketAddress(host, port) : | |
| 366 | + new InetSocketAddress(InetAddress.getByName(null), port), | |
| 367 | + (SocketAddress) null, stream); | |
| 368 | + } | |
| 369 | + | |
| 370 | + /** | |
| 371 | + * Creates a socket and connects it to the specified port number at | |
| 372 | + * the specified IP address. | |
| 373 | + * <p> | |
| 374 | + * If the stream argument is <code>true</code>, this creates a | |
| 375 | + * stream socket. If the stream argument is <code>false</code>, it | |
| 376 | + * creates a datagram socket. | |
| 377 | + * <p> | |
| 378 | + * If the application has specified a server socket factory, that | |
| 379 | + * factory's <code>createSocketImpl</code> method is called to create | |
| 380 | + * the actual socket implementation. Otherwise a "plain" socket is created. | |
| 381 | + * | |
| 382 | + * <p>If there is a security manager, its | |
| 383 | + * <code>checkConnect</code> method is called | |
| 384 | + * with <code>host.getHostAddress()</code> and <code>port</code> | |
| 385 | + * as its arguments. This could result in a SecurityException. | |
| 386 | + * <p> | |
| 387 | + * If UDP socket is used, TCP/IP related socket options will not apply. | |
| 388 | + * | |
| 389 | + * @param host the IP address. | |
| 390 | + * @param port the port number. | |
| 391 | + * @param stream if <code>true</code>, create a stream socket; | |
| 392 | + * otherwise, create a datagram socket. | |
| 393 | + * @exception IOException if an I/O error occurs when creating the socket. | |
| 394 | + * @exception SecurityException if a security manager exists and its | |
| 395 | + * <code>checkConnect</code> method doesn't allow the operation. | |
| 396 | + * @exception IllegalArgumentException if the port parameter is outside | |
| 397 | + * the specified range of valid port values, which is between | |
| 398 | + * 0 and 65535, inclusive. | |
| 399 | + * @exception NullPointerException if <code>host</code> is null. | |
| 400 | + * @see java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory) | |
| 401 | + * @see java.net.SocketImpl | |
| 402 | + * @see java.net.SocketImplFactory#createSocketImpl() | |
| 403 | + * @see SecurityManager#checkConnect | |
| 404 | + * @deprecated Use DatagramSocket instead for UDP transport. | |
| 405 | + */ | |
| 406 | + @Deprecated | |
| 407 | + public Socket(InetAddress host, int port, boolean stream) throws IOException { | |
| 408 | + this(host != null ? new InetSocketAddress(host, port) : null, | |
| 409 | + new InetSocketAddress(0), stream); | |
| 410 | + } | |
| 411 | + | |
| 412 | + private Socket(SocketAddress address, SocketAddress localAddr, | |
| 413 | + boolean stream) throws IOException { | |
| 414 | + setImpl(); | |
| 415 | + | |
| 416 | + // backward compatibility | |
| 417 | + if (address == null) | |
| 418 | + throw new NullPointerException(); | |
| 419 | + | |
| 420 | + try { | |
| 421 | + createImpl(stream); | |
| 422 | + if (localAddr != null) | |
| 423 | + bind(localAddr); | |
| 424 | + if (address != null) | |
| 425 | + connect(address); | |
| 426 | + } catch (IOException e) { | |
| 427 | + close(); | |
| 428 | + throw e; | |
| 429 | + } | |
| 430 | + } | |
| 431 | + | |
| 432 | + /** | |
| 433 | + * Creates the socket implementation. | |
| 434 | + * | |
| 435 | + * @param stream a <code>boolean</code> value : <code>true</code> for a TCP socket, | |
| 436 | + * <code>false</code> for UDP. | |
| 437 | + * @throws IOException if creation fails | |
| 438 | + * @since 1.4 | |
| 439 | + */ | |
| 440 | + void createImpl(boolean stream) throws SocketException { | |
| 441 | + if (impl == null) | |
| 442 | + setImpl(); | |
| 443 | + try { | |
| 444 | + impl.create(stream); | |
| 445 | + created = true; | |
| 446 | + } catch (IOException e) { | |
| 447 | + throw new SocketException(e.getMessage()); | |
| 448 | + } | |
| 449 | + } | |
| 450 | + | |
| 451 | + private void checkOldImpl() { | |
| 452 | + if (impl == null) | |
| 453 | + return; | |
| 454 | + // SocketImpl.connect() is a protected method, therefore we need to use | |
| 455 | + // getDeclaredMethod, therefore we need permission to access the member | |
| 456 | + | |
| 457 | + oldImpl = AccessController.doPrivileged | |
| 458 | + (new PrivilegedAction<Boolean>() { | |
| 459 | + public Boolean run() { | |
| 460 | + Class[] cl = new Class[2]; | |
| 461 | + cl[0] = SocketAddress.class; | |
| 462 | + cl[1] = Integer.TYPE; | |
| 463 | + Class clazz = impl.getClass(); | |
| 464 | + while (true) { | |
| 465 | + try { | |
| 466 | + clazz.getDeclaredMethod("connect", cl); | |
| 467 | + return Boolean.FALSE; | |
| 468 | + } catch (NoSuchMethodException e) { | |
| 469 | + clazz = clazz.getSuperclass(); | |
| 470 | + // java.net.SocketImpl class will always have this abstract method. | |
| 471 | + // If we have not found it by now in the hierarchy then it does not | |
| 472 | + // exist, we are an old style impl. | |
| 473 | + if (clazz.equals(java.net.SocketImpl.class)) { | |
| 474 | + return Boolean.TRUE; | |
| 475 | + } | |
| 476 | + } | |
| 477 | + } | |
| 478 | + } | |
| 479 | + }); | |
| 480 | + } | |
| 481 | + | |
| 482 | + /** | |
| 483 | + * Sets impl to the system-default type of SocketImpl. | |
| 484 | + * @since 1.4 | |
| 485 | + */ | |
| 486 | + void setImpl() { | |
| 487 | + if (factory != null) { | |
| 488 | + impl = factory.createSocketImpl(); | |
| 489 | + checkOldImpl(); | |
| 490 | + } else { | |
| 491 | + // No need to do a checkOldImpl() here, we know it's an up to date | |
| 492 | + // SocketImpl! | |
| 493 | + impl = new SocksSocketImpl(); | |
| 494 | + } | |
| 495 | + if (impl != null) | |
| 496 | + impl.setSocket(this); | |
| 497 | + } | |
| 498 | + | |
| 499 | + | |
| 500 | + /** | |
| 501 | + * Get the <code>SocketImpl</code> attached to this socket, creating | |
| 502 | + * it if necessary. | |
| 503 | + * | |
| 504 | + * @return the <code>SocketImpl</code> attached to that ServerSocket. | |
| 505 | + * @throws SocketException if creation fails | |
| 506 | + * @since 1.4 | |
| 507 | + */ | |
| 508 | + SocketImpl getImpl() throws SocketException { | |
| 509 | + if (!created) | |
| 510 | + createImpl(true); | |
| 511 | + return impl; | |
| 512 | + } | |
| 513 | + | |
| 514 | + /** | |
| 515 | + * Connects this socket to the server. | |
| 516 | + * | |
| 517 | + * @param endpoint the <code>SocketAddress</code> | |
| 518 | + * @throws IOException if an error occurs during the connection | |
| 519 | + * @throws java.nio.channels.IllegalBlockingModeException | |
| 520 | + * if this socket has an associated channel, | |
| 521 | + * and the channel is in non-blocking mode | |
| 522 | + * @throws IllegalArgumentException if endpoint is null or is a | |
| 523 | + * SocketAddress subclass not supported by this socket | |
| 524 | + * @since 1.4 | |
| 525 | + * @spec JSR-51 | |
| 526 | + */ | |
| 527 | + public void connect(SocketAddress endpoint) throws IOException { | |
| 528 | + connect(endpoint, 0); | |
| 529 | + } | |
| 530 | + | |
| 531 | + /** | |
| 532 | + * Connects this socket to the server with a specified timeout value. | |
| 533 | + * A timeout of zero is interpreted as an infinite timeout. The connection | |
| 534 | + * will then block until established or an error occurs. | |
| 535 | + * | |
| 536 | + * @param endpoint the <code>SocketAddress</code> | |
| 537 | + * @param timeout the timeout value to be used in milliseconds. | |
| 538 | + * @throws IOException if an error occurs during the connection | |
| 539 | + * @throws SocketTimeoutException if timeout expires before connecting | |
| 540 | + * @throws java.nio.channels.IllegalBlockingModeException | |
| 541 | + * if this socket has an associated channel, | |
| 542 | + * and the channel is in non-blocking mode | |
| 543 | + * @throws IllegalArgumentException if endpoint is null or is a | |
| 544 | + * SocketAddress subclass not supported by this socket | |
| 545 | + * @since 1.4 | |
| 546 | + * @spec JSR-51 | |
| 547 | + */ | |
| 548 | + public void connect(SocketAddress endpoint, int timeout) throws IOException { | |
| 549 | + if (endpoint == null) | |
| 550 | + throw new IllegalArgumentException("connect: The address can't be null"); | |
| 551 | + | |
| 552 | + if (timeout < 0) | |
| 553 | + throw new IllegalArgumentException("connect: timeout can't be negative"); | |
| 554 | + | |
| 555 | + if (isClosed()) | |
| 556 | + throw new SocketException("Socket is closed"); | |
| 557 | + | |
| 558 | + if (!oldImpl && isConnected()) | |
| 559 | + throw new SocketException("already connected"); | |
| 560 | + | |
| 561 | + if (!(endpoint instanceof InetSocketAddress)) | |
| 562 | + throw new IllegalArgumentException("Unsupported address type"); | |
| 563 | + | |
| 564 | + InetSocketAddress epoint = (InetSocketAddress) endpoint; | |
| 565 | + InetAddress addr = epoint.getAddress (); | |
| 566 | + int port = epoint.getPort(); | |
| 567 | + checkAddress(addr, "connect"); | |
| 568 | + | |
| 569 | + SecurityManager security = System.getSecurityManager(); | |
| 570 | + if (security != null) { | |
| 571 | + if (epoint.isUnresolved()) | |
| 572 | + security.checkConnect(epoint.getHostName(), port); | |
| 573 | + else | |
| 574 | + security.checkConnect(addr.getHostAddress(), port); | |
| 575 | + } | |
| 576 | + if (!created) | |
| 577 | + createImpl(true); | |
| 578 | + if (!oldImpl) | |
| 579 | + impl.connect(epoint, timeout); | |
| 580 | + else if (timeout == 0) { | |
| 581 | + if (epoint.isUnresolved()) | |
| 582 | + impl.connect(addr.getHostName(), port); | |
| 583 | + else | |
| 584 | + impl.connect(addr, port); | |
| 585 | + } else | |
| 586 | + throw new UnsupportedOperationException("SocketImpl.connect(addr, timeout)"); | |
| 587 | + connected = true; | |
| 588 | + /* | |
| 589 | + * If the socket was not bound before the connect, it is now because | |
| 590 | + * the kernel will have picked an ephemeral port & a local address | |
| 591 | + */ | |
| 592 | + bound = true; | |
| 593 | + } | |
| 594 | + | |
| 595 | + /** | |
| 596 | + * Binds the socket to a local address. | |
| 597 | + * <P> | |
| 598 | + * If the address is <code>null</code>, then the system will pick up | |
| 599 | + * an ephemeral port and a valid local address to bind the socket. | |
| 600 | + * | |
| 601 | + * @param bindpoint the <code>SocketAddress</code> to bind to | |
| 602 | + * @throws IOException if the bind operation fails, or if the socket | |
| 603 | + * is already bound. | |
| 604 | + * @throws IllegalArgumentException if bindpoint is a | |
| 605 | + * SocketAddress subclass not supported by this socket | |
| 606 | + * | |
| 607 | + * @since 1.4 | |
| 608 | + * @see #isBound | |
| 609 | + */ | |
| 610 | + public void bind(SocketAddress bindpoint) throws IOException { | |
| 611 | + if (isClosed()) | |
| 612 | + throw new SocketException("Socket is closed"); | |
| 613 | + if (!oldImpl && isBound()) | |
| 614 | + throw new SocketException("Already bound"); | |
| 615 | + | |
| 616 | + if (bindpoint != null && (!(bindpoint instanceof InetSocketAddress))) | |
| 617 | + throw new IllegalArgumentException("Unsupported address type"); | |
| 618 | + InetSocketAddress epoint = (InetSocketAddress) bindpoint; | |
| 619 | + if (epoint != null && epoint.isUnresolved()) | |
| 620 | + throw new SocketException("Unresolved address"); | |
| 621 | + if (epoint == null) { | |
| 622 | + epoint = new InetSocketAddress(0); | |
| 623 | + } | |
| 624 | + InetAddress addr = epoint.getAddress(); | |
| 625 | + int port = epoint.getPort(); | |
| 626 | + checkAddress (addr, "bind"); | |
| 627 | + getImpl().bind (addr, port); | |
| 628 | + bound = true; | |
| 629 | + } | |
| 630 | + | |
| 631 | + private void checkAddress (InetAddress addr, String op) { | |
| 632 | + if (addr == null) { | |
| 633 | + return; | |
| 634 | + } | |
| 635 | + if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) { | |
| 636 | + throw new IllegalArgumentException(op + ": invalid address type"); | |
| 637 | + } | |
| 638 | + } | |
| 639 | + | |
| 640 | + /** | |
| 641 | + * set the flags after an accept() call. | |
| 642 | + */ | |
| 643 | + final void postAccept() { | |
| 644 | + connected = true; | |
| 645 | + created = true; | |
| 646 | + bound = true; | |
| 647 | + } | |
| 648 | + | |
| 649 | + void setCreated() { | |
| 650 | + created = true; | |
| 651 | + } | |
| 652 | + | |
| 653 | + void setBound() { | |
| 654 | + bound = true; | |
| 655 | + } | |
| 656 | + | |
| 657 | + void setConnected() { | |
| 658 | + connected = true; | |
| 659 | + } | |
| 660 | + | |
| 661 | + /** | |
| 662 | + * Returns the address to which the socket is connected. | |
| 663 | + * <p> | |
| 664 | + * If the socket was connected prior to being {@link #close closed}, | |
| 665 | + * then this method will continue to return the connected address | |
| 666 | + * after the socket is closed. | |
| 667 | + * | |
| 668 | + * @return the remote IP address to which this socket is connected, | |
| 669 | + * or <code>null</code> if the socket is not connected. | |
| 670 | + */ | |
| 671 | + public InetAddress getInetAddress() { | |
| 672 | + if (!isConnected()) | |
| 673 | + return null; | |
| 674 | + try { | |
| 675 | + return getImpl().getInetAddress(); | |
| 676 | + } catch (SocketException e) { | |
| 677 | + } | |
| 678 | + return null; | |
| 679 | + } | |
| 680 | + | |
| 681 | + /** | |
| 682 | + * Gets the local address to which the socket is bound. | |
| 683 | + * | |
| 684 | + * @return the local address to which the socket is bound, or | |
| 685 | + * the {@link InetAddress#isAnyLocalAddress wildcard} address | |
| 686 | + * if the socket is closed or not bound yet. | |
| 687 | + * @since JDK1.1 | |
| 688 | + */ | |
| 689 | + public InetAddress getLocalAddress() { | |
| 690 | + // This is for backward compatibility | |
| 691 | + if (!isBound()) | |
| 692 | + return InetAddress.anyLocalAddress(); | |
| 693 | + InetAddress in = null; | |
| 694 | + try { | |
| 695 | + in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR); | |
| 696 | + if (in.isAnyLocalAddress()) { | |
| 697 | + in = InetAddress.anyLocalAddress(); | |
| 698 | + } | |
| 699 | + } catch (Exception e) { | |
| 700 | + in = InetAddress.anyLocalAddress(); // "0.0.0.0" | |
| 701 | + } | |
| 702 | + return in; | |
| 703 | + } | |
| 704 | + | |
| 705 | + /** | |
| 706 | + * Returns the remote port number to which this socket is connected. | |
| 707 | + * <p> | |
| 708 | + * If the socket was connected prior to being {@link #close closed}, | |
| 709 | + * then this method will continue to return the connected port number | |
| 710 | + * after the socket is closed. | |
| 711 | + * | |
| 712 | + * @return the remote port number to which this socket is connected, or | |
| 713 | + * 0 if the socket is not connected yet. | |
| 714 | + */ | |
| 715 | + public int getPort() { | |
| 716 | + if (!isConnected()) | |
| 717 | + return 0; | |
| 718 | + try { | |
| 719 | + return getImpl().getPort(); | |
| 720 | + } catch (SocketException e) { | |
| 721 | + // Shouldn't happen as we're connected | |
| 722 | + } | |
| 723 | + return -1; | |
| 724 | + } | |
| 725 | + | |
| 726 | + /** | |
| 727 | + * Returns the local port number to which this socket is bound. | |
| 728 | + * <p> | |
| 729 | + * If the socket was bound prior to being {@link #close closed}, | |
| 730 | + * then this method will continue to return the local port number | |
| 731 | + * after the socket is closed. | |
| 732 | + * | |
| 733 | + * @return the local port number to which this socket is bound or -1 | |
| 734 | + * if the socket is not bound yet. | |
| 735 | + */ | |
| 736 | + public int getLocalPort() { | |
| 737 | + if (!isBound()) | |
| 738 | + return -1; | |
| 739 | + try { | |
| 740 | + return getImpl().getLocalPort(); | |
| 741 | + } catch(SocketException e) { | |
| 742 | + // shouldn't happen as we're bound | |
| 743 | + } | |
| 744 | + return -1; | |
| 745 | + } | |
| 746 | + | |
| 747 | + /** | |
| 748 | + * Returns the address of the endpoint this socket is connected to, or | |
| 749 | + * <code>null</code> if it is unconnected. | |
| 750 | + * <p> | |
| 751 | + * If the socket was connected prior to being {@link #close closed}, | |
| 752 | + * then this method will continue to return the connected address | |
| 753 | + * after the socket is closed. | |
| 754 | + * | |
| 755 | + | |
| 756 | + * @return a <code>SocketAddress</code> representing the remote endpoint of this | |
| 757 | + * socket, or <code>null</code> if it is not connected yet. | |
| 758 | + * @see #getInetAddress() | |
| 759 | + * @see #getPort() | |
| 760 | + * @see #connect(SocketAddress, int) | |
| 761 | + * @see #connect(SocketAddress) | |
| 762 | + * @since 1.4 | |
| 763 | + */ | |
| 764 | + public SocketAddress getRemoteSocketAddress() { | |
| 765 | + if (!isConnected()) | |
| 766 | + return null; | |
| 767 | + return new InetSocketAddress(getInetAddress(), getPort()); | |
| 768 | + } | |
| 769 | + | |
| 770 | + /** | |
| 771 | + * Returns the address of the endpoint this socket is bound to, or | |
| 772 | + * <code>null</code> if it is not bound yet. | |
| 773 | + * <p> | |
| 774 | + * If a socket bound to an endpoint represented by an | |
| 775 | + * <code>InetSocketAddress </code> is {@link #close closed}, | |
| 776 | + * then this method will continue to return an <code>InetSocketAddress</code> | |
| 777 | + * after the socket is closed. In that case the returned | |
| 778 | + * <code>InetSocketAddress</code>'s address is the | |
| 779 | + * {@link InetAddress#isAnyLocalAddress wildcard} address | |
| 780 | + * and its port is the local port that it was bound to. | |
| 781 | + * | |
| 782 | + * @return a <code>SocketAddress</code> representing the local endpoint of this | |
| 783 | + * socket, or <code>null</code> if it is not bound yet. | |
| 784 | + * @see #getLocalAddress() | |
| 785 | + * @see #getLocalPort() | |
| 786 | + * @see #bind(SocketAddress) | |
| 787 | + * @since 1.4 | |
| 788 | + */ | |
| 789 | + | |
| 790 | + public SocketAddress getLocalSocketAddress() { | |
| 791 | + if (!isBound()) | |
| 792 | + return null; | |
| 793 | + return new InetSocketAddress(getLocalAddress(), getLocalPort()); | |
| 794 | + } | |
| 795 | + | |
| 796 | + /** | |
| 797 | + * Returns the unique {@link java.nio.channels.SocketChannel SocketChannel} | |
| 798 | + * object associated with this socket, if any. | |
| 799 | + * | |
| 800 | + * <p> A socket will have a channel if, and only if, the channel itself was | |
| 801 | + * created via the {@link java.nio.channels.SocketChannel#open | |
| 802 | + * SocketChannel.open} or {@link | |
| 803 | + * java.nio.channels.ServerSocketChannel#accept ServerSocketChannel.accept} | |
| 804 | + * methods. | |
| 805 | + * | |
| 806 | + * @return the socket channel associated with this socket, | |
| 807 | + * or <tt>null</tt> if this socket was not created | |
| 808 | + * for a channel | |
| 809 | + * | |
| 810 | + * @since 1.4 | |
| 811 | + * @spec JSR-51 | |
| 812 | + */ | |
| 813 | + public SocketChannel getChannel() { | |
| 814 | + return null; | |
| 815 | + } | |
| 816 | + | |
| 817 | + /** | |
| 818 | + * Returns an input stream for this socket. | |
| 819 | + * | |
| 820 | + * <p> If this socket has an associated channel then the resulting input | |
| 821 | + * stream delegates all of its operations to the channel. If the channel | |
| 822 | + * is in non-blocking mode then the input stream's <tt>read</tt> operations | |
| 823 | + * will throw an {@link java.nio.channels.IllegalBlockingModeException}. | |
| 824 | + * | |
| 825 | + * <p>Under abnormal conditions the underlying connection may be | |
| 826 | + * broken by the remote host or the network software (for example | |
| 827 | + * a connection reset in the case of TCP connections). When a | |
| 828 | + * broken connection is detected by the network software the | |
| 829 | + * following applies to the returned input stream :- | |
| 830 | + * | |
| 831 | + * <ul> | |
| 832 | + * | |
| 833 | + * <li><p>The network software may discard bytes that are buffered | |
| 834 | + * by the socket. Bytes that aren't discarded by the network | |
| 835 | + * software can be read using {@link java.io.InputStream#read read}. | |
| 836 | + * | |
| 837 | + * <li><p>If there are no bytes buffered on the socket, or all | |
| 838 | + * buffered bytes have been consumed by | |
| 839 | + * {@link java.io.InputStream#read read}, then all subsequent | |
| 840 | + * calls to {@link java.io.InputStream#read read} will throw an | |
| 841 | + * {@link java.io.IOException IOException}. | |
| 842 | + * | |
| 843 | + * <li><p>If there are no bytes buffered on the socket, and the | |
| 844 | + * socket has not been closed using {@link #close close}, then | |
| 845 | + * {@link java.io.InputStream#available available} will | |
| 846 | + * return <code>0</code>. | |
| 847 | + * | |
| 848 | + * </ul> | |
| 849 | + * | |
| 850 | + * <p> Closing the returned {@link java.io.InputStream InputStream} | |
| 851 | + * will close the associated socket. | |
| 852 | + * | |
| 853 | + * @return an input stream for reading bytes from this socket. | |
| 854 | + * @exception IOException if an I/O error occurs when creating the | |
| 855 | + * input stream, the socket is closed, the socket is | |
| 856 | + * not connected, or the socket input has been shutdown | |
| 857 | + * using {@link #shutdownInput()} | |
| 858 | + * | |
| 859 | + * @revised 1.4 | |
| 860 | + * @spec JSR-51 | |
| 861 | + */ | |
| 862 | + public InputStream getInputStream() throws IOException { | |
| 863 | + if (isClosed()) | |
| 864 | + throw new SocketException("Socket is closed"); | |
| 865 | + if (!isConnected()) | |
| 866 | + throw new SocketException("Socket is not connected"); | |
| 867 | + if (isInputShutdown()) | |
| 868 | + throw new SocketException("Socket input is shutdown"); | |
| 869 | + final Socket s = this; | |
| 870 | + InputStream is = null; | |
| 871 | + try { | |
| 872 | + is = AccessController.doPrivileged( | |
| 873 | + new PrivilegedExceptionAction<InputStream>() { | |
| 874 | + public InputStream run() throws IOException { | |
| 875 | + return impl.getInputStream(); | |
| 876 | + } | |
| 877 | + }); | |
| 878 | + } catch (java.security.PrivilegedActionException e) { | |
| 879 | + throw (IOException) e.getException(); | |
| 880 | + } | |
| 881 | + return is; | |
| 882 | + } | |
| 883 | + | |
| 884 | + /** | |
| 885 | + * Returns an output stream for this socket. | |
| 886 | + * | |
| 887 | + * <p> If this socket has an associated channel then the resulting output | |
| 888 | + * stream delegates all of its operations to the channel. If the channel | |
| 889 | + * is in non-blocking mode then the output stream's <tt>write</tt> | |
| 890 | + * operations will throw an {@link | |
| 891 | + * java.nio.channels.IllegalBlockingModeException}. | |
| 892 | + * | |
| 893 | + * <p> Closing the returned {@link java.io.OutputStream OutputStream} | |
| 894 | + * will close the associated socket. | |
| 895 | + * | |
| 896 | + * @return an output stream for writing bytes to this socket. | |
| 897 | + * @exception IOException if an I/O error occurs when creating the | |
| 898 | + * output stream or if the socket is not connected. | |
| 899 | + * @revised 1.4 | |
| 900 | + * @spec JSR-51 | |
| 901 | + */ | |
| 902 | + public OutputStream getOutputStream() throws IOException { | |
| 903 | + if (isClosed()) | |
| 904 | + throw new SocketException("Socket is closed"); | |
| 905 | + if (!isConnected()) | |
| 906 | + throw new SocketException("Socket is not connected"); | |
| 907 | + if (isOutputShutdown()) | |
| 908 | + throw new SocketException("Socket output is shutdown"); | |
| 909 | + final Socket s = this; | |
| 910 | + OutputStream os = null; | |
| 911 | + try { | |
| 912 | + os = AccessController.doPrivileged( | |
| 913 | + new PrivilegedExceptionAction<OutputStream>() { | |
| 914 | + public OutputStream run() throws IOException { | |
| 915 | + return impl.getOutputStream(); | |
| 916 | + } | |
| 917 | + }); | |
| 918 | + } catch (java.security.PrivilegedActionException e) { | |
| 919 | + throw (IOException) e.getException(); | |
| 920 | + } | |
| 921 | + return os; | |
| 922 | + } | |
| 923 | + | |
| 924 | + /** | |
| 925 | + * Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). | |
| 926 | + * | |
| 927 | + * @param on <code>true</code> to enable TCP_NODELAY, | |
| 928 | + * <code>false</code> to disable. | |
| 929 | + * | |
| 930 | + * @exception SocketException if there is an error | |
| 931 | + * in the underlying protocol, such as a TCP error. | |
| 932 | + * | |
| 933 | + * @since JDK1.1 | |
| 934 | + * | |
| 935 | + * @see #getTcpNoDelay() | |
| 936 | + */ | |
| 937 | + public void setTcpNoDelay(boolean on) throws SocketException { | |
| 938 | + if (isClosed()) | |
| 939 | + throw new SocketException("Socket is closed"); | |
| 940 | + getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on)); | |
| 941 | + } | |
| 942 | + | |
| 943 | + /** | |
| 944 | + * Tests if TCP_NODELAY is enabled. | |
| 945 | + * | |
| 946 | + * @return a <code>boolean</code> indicating whether or not TCP_NODELAY is enabled. | |
| 947 | + * @exception SocketException if there is an error | |
| 948 | + * in the underlying protocol, such as a TCP error. | |
| 949 | + * @since JDK1.1 | |
| 950 | + * @see #setTcpNoDelay(boolean) | |
| 951 | + */ | |
| 952 | + public boolean getTcpNoDelay() throws SocketException { | |
| 953 | + if (isClosed()) | |
| 954 | + throw new SocketException("Socket is closed"); | |
| 955 | + return ((Boolean) getImpl().getOption(SocketOptions.TCP_NODELAY)).booleanValue(); | |
| 956 | + } | |
| 957 | + | |
| 958 | + /** | |
| 959 | + * Enable/disable SO_LINGER with the specified linger time in seconds. | |
| 960 | + * The maximum timeout value is platform specific. | |
| 961 | + * | |
| 962 | + * The setting only affects socket close. | |
| 963 | + * | |
| 964 | + * @param on whether or not to linger on. | |
| 965 | + * @param linger how long to linger for, if on is true. | |
| 966 | + * @exception SocketException if there is an error | |
| 967 | + * in the underlying protocol, such as a TCP error. | |
| 968 | + * @exception IllegalArgumentException if the linger value is negative. | |
| 969 | + * @since JDK1.1 | |
| 970 | + * @see #getSoLinger() | |
| 971 | + */ | |
| 972 | + public void setSoLinger(boolean on, int linger) throws SocketException { | |
| 973 | + if (isClosed()) | |
| 974 | + throw new SocketException("Socket is closed"); | |
| 975 | + if (!on) { | |
| 976 | + getImpl().setOption(SocketOptions.SO_LINGER, new Boolean(on)); | |
| 977 | + } else { | |
| 978 | + if (linger < 0) { | |
| 979 | + throw new IllegalArgumentException("invalid value for SO_LINGER"); | |
| 980 | + } | |
| 981 | + if (linger > 65535) | |
| 982 | + linger = 65535; | |
| 983 | + getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger)); | |
| 984 | + } | |
| 985 | + } | |
| 986 | + | |
| 987 | + /** | |
| 988 | + * Returns setting for SO_LINGER. -1 returns implies that the | |
| 989 | + * option is disabled. | |
| 990 | + * | |
| 991 | + * The setting only affects socket close. | |
| 992 | + * | |
| 993 | + * @return the setting for SO_LINGER. | |
| 994 | + * @exception SocketException if there is an error | |
| 995 | + * in the underlying protocol, such as a TCP error. | |
| 996 | + * @since JDK1.1 | |
| 997 | + * @see #setSoLinger(boolean, int) | |
| 998 | + */ | |
| 999 | + public int getSoLinger() throws SocketException { | |
| 1000 | + if (isClosed()) | |
| 1001 | + throw new SocketException("Socket is closed"); | |
| 1002 | + Object o = getImpl().getOption(SocketOptions.SO_LINGER); | |
| 1003 | + if (o instanceof Integer) { | |
| 1004 | + return ((Integer) o).intValue(); | |
| 1005 | + } else { | |
| 1006 | + return -1; | |
| 1007 | + } | |
| 1008 | + } | |
| 1009 | + | |
| 1010 | + /** | |
| 1011 | + * Send one byte of urgent data on the socket. The byte to be sent is the lowest eight | |
| 1012 | + * bits of the data parameter. The urgent byte is | |
| 1013 | + * sent after any preceding writes to the socket OutputStream | |
| 1014 | + * and before any future writes to the OutputStream. | |
| 1015 | + * @param data The byte of data to send | |
| 1016 | + * @exception IOException if there is an error | |
| 1017 | + * sending the data. | |
| 1018 | + * @since 1.4 | |
| 1019 | + */ | |
| 1020 | + public void sendUrgentData (int data) throws IOException { | |
| 1021 | + if (!getImpl().supportsUrgentData ()) { | |
| 1022 | + throw new SocketException ("Urgent data not supported"); | |
| 1023 | + } | |
| 1024 | + getImpl().sendUrgentData (data); | |
| 1025 | + } | |
| 1026 | + | |
| 1027 | + /** | |
| 1028 | + * Enable/disable OOBINLINE (receipt of TCP urgent data) | |
| 1029 | + * | |
| 1030 | + * By default, this option is disabled and TCP urgent data received on a | |
| 1031 | + * socket is silently discarded. If the user wishes to receive urgent data, then | |
| 1032 | + * this option must be enabled. When enabled, urgent data is received | |
| 1033 | + * inline with normal data. | |
| 1034 | + * <p> | |
| 1035 | + * Note, only limited support is provided for handling incoming urgent | |
| 1036 | + * data. In particular, no notification of incoming urgent data is provided | |
| 1037 | + * and there is no capability to distinguish between normal data and urgent | |
| 1038 | + * data unless provided by a higher level protocol. | |
| 1039 | + * | |
| 1040 | + * @param on <code>true</code> to enable OOBINLINE, | |
| 1041 | + * <code>false</code> to disable. | |
| 1042 | + * | |
| 1043 | + * @exception SocketException if there is an error | |
| 1044 | + * in the underlying protocol, such as a TCP error. | |
| 1045 | + * | |
| 1046 | + * @since 1.4 | |
| 1047 | + * | |
| 1048 | + * @see #getOOBInline() | |
| 1049 | + */ | |
| 1050 | + public void setOOBInline(boolean on) throws SocketException { | |
| 1051 | + if (isClosed()) | |
| 1052 | + throw new SocketException("Socket is closed"); | |
| 1053 | + getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on)); | |
| 1054 | + } | |
| 1055 | + | |
| 1056 | + /** | |
| 1057 | + * Tests if OOBINLINE is enabled. | |
| 1058 | + * | |
| 1059 | + * @return a <code>boolean</code> indicating whether or not OOBINLINE is enabled. | |
| 1060 | + * @exception SocketException if there is an error | |
| 1061 | + * in the underlying protocol, such as a TCP error. | |
| 1062 | + * @since 1.4 | |
| 1063 | + * @see #setOOBInline(boolean) | |
| 1064 | + */ | |
| 1065 | + public boolean getOOBInline() throws SocketException { | |
| 1066 | + if (isClosed()) | |
| 1067 | + throw new SocketException("Socket is closed"); | |
| 1068 | + return ((Boolean) getImpl().getOption(SocketOptions.SO_OOBINLINE)).booleanValue(); | |
| 1069 | + } | |
| 1070 | + | |
| 1071 | + /** | |
| 1072 | + * Enable/disable SO_TIMEOUT with the specified timeout, in | |
| 1073 | + * milliseconds. With this option set to a non-zero timeout, | |
| 1074 | + * a read() call on the InputStream associated with this Socket | |
| 1075 | + * will block for only this amount of time. If the timeout expires, | |
| 1076 | + * a <B>java.net.SocketTimeoutException</B> is raised, though the | |
| 1077 | + * Socket is still valid. The option <B>must</B> be enabled | |
| 1078 | + * prior to entering the blocking operation to have effect. The | |
| 1079 | + * timeout must be > 0. | |
| 1080 | + * A timeout of zero is interpreted as an infinite timeout. | |
| 1081 | + * @param timeout the specified timeout, in milliseconds. | |
| 1082 | + * @exception SocketException if there is an error | |
| 1083 | + * in the underlying protocol, such as a TCP error. | |
| 1084 | + * @since JDK 1.1 | |
| 1085 | + * @see #getSoTimeout() | |
| 1086 | + */ | |
| 1087 | + public synchronized void setSoTimeout(int timeout) throws SocketException { | |
| 1088 | + if (isClosed()) | |
| 1089 | + throw new SocketException("Socket is closed"); | |
| 1090 | + if (timeout < 0) | |
| 1091 | + throw new IllegalArgumentException("timeout can't be negative"); | |
| 1092 | + | |
| 1093 | + getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout)); | |
| 1094 | + } | |
| 1095 | + | |
| 1096 | + /** | |
| 1097 | + * Returns setting for SO_TIMEOUT. 0 returns implies that the | |
| 1098 | + * option is disabled (i.e., timeout of infinity). | |
| 1099 | + * @return the setting for SO_TIMEOUT | |
| 1100 | + * @exception SocketException if there is an error | |
| 1101 | + * in the underlying protocol, such as a TCP error. | |
| 1102 | + * @since JDK1.1 | |
| 1103 | + * @see #setSoTimeout(int) | |
| 1104 | + */ | |
| 1105 | + public synchronized int getSoTimeout() throws SocketException { | |
| 1106 | + if (isClosed()) | |
| 1107 | + throw new SocketException("Socket is closed"); | |
| 1108 | + Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT); | |
| 1109 | + /* extra type safety */ | |
| 1110 | + if (o instanceof Integer) { | |
| 1111 | + return ((Integer) o).intValue(); | |
| 1112 | + } else { | |
| 1113 | + return 0; | |
| 1114 | + } | |
| 1115 | + } | |
| 1116 | + | |
| 1117 | + /** | |
| 1118 | + * Sets the SO_SNDBUF option to the specified value for this | |
| 1119 | + * <tt>Socket</tt>. The SO_SNDBUF option is used by the platform's | |
| 1120 | + * networking code as a hint for the size to set | |
| 1121 | + * the underlying network I/O buffers. | |
| 1122 | + * | |
| 1123 | + * <p>Because SO_SNDBUF is a hint, applications that want to | |
| 1124 | + * verify what size the buffers were set to should call | |
| 1125 | + * {@link #getSendBufferSize()}. | |
| 1126 | + * | |
| 1127 | + * @exception SocketException if there is an error | |
| 1128 | + * in the underlying protocol, such as a TCP error. | |
| 1129 | + * | |
| 1130 | + * @param size the size to which to set the send buffer | |
| 1131 | + * size. This value must be greater than 0. | |
| 1132 | + * | |
| 1133 | + * @exception IllegalArgumentException if the | |
| 1134 | + * value is 0 or is negative. | |
| 1135 | + * | |
| 1136 | + * @see #getSendBufferSize() | |
| 1137 | + * @since 1.2 | |
| 1138 | + */ | |
| 1139 | + public synchronized void setSendBufferSize(int size) | |
| 1140 | + throws SocketException{ | |
| 1141 | + if (!(size > 0)) { | |
| 1142 | + throw new IllegalArgumentException("negative send size"); | |
| 1143 | + } | |
| 1144 | + if (isClosed()) | |
| 1145 | + throw new SocketException("Socket is closed"); | |
| 1146 | + getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size)); | |
| 1147 | + } | |
| 1148 | + | |
| 1149 | + /** | |
| 1150 | + * Get value of the SO_SNDBUF option for this <tt>Socket</tt>, | |
| 1151 | + * that is the buffer size used by the platform | |
| 1152 | + * for output on this <tt>Socket</tt>. | |
| 1153 | + * @return the value of the SO_SNDBUF option for this <tt>Socket</tt>. | |
| 1154 | + * | |
| 1155 | + * @exception SocketException if there is an error | |
| 1156 | + * in the underlying protocol, such as a TCP error. | |
| 1157 | + * | |
| 1158 | + * @see #setSendBufferSize(int) | |
| 1159 | + * @since 1.2 | |
| 1160 | + */ | |
| 1161 | + public synchronized int getSendBufferSize() throws SocketException { | |
| 1162 | + if (isClosed()) | |
| 1163 | + throw new SocketException("Socket is closed"); | |
| 1164 | + int result = 0; | |
| 1165 | + Object o = getImpl().getOption(SocketOptions.SO_SNDBUF); | |
| 1166 | + if (o instanceof Integer) { | |
| 1167 | + result = ((Integer)o).intValue(); | |
| 1168 | + } | |
| 1169 | + return result; | |
| 1170 | + } | |
| 1171 | + | |
| 1172 | + /** | |
| 1173 | + * Sets the SO_RCVBUF option to the specified value for this | |
| 1174 | + * <tt>Socket</tt>. The SO_RCVBUF option is used by the platform's | |
| 1175 | + * networking code as a hint for the size to set | |
| 1176 | + * the underlying network I/O buffers. | |
| 1177 | + * | |
| 1178 | + * <p>Increasing the receive buffer size can increase the performance of | |
| 1179 | + * network I/O for high-volume connection, while decreasing it can | |
| 1180 | + * help reduce the backlog of incoming data. | |
| 1181 | + * | |
| 1182 | + * <p>Because SO_RCVBUF is a hint, applications that want to | |
| 1183 | + * verify what size the buffers were set to should call | |
| 1184 | + * {@link #getReceiveBufferSize()}. | |
| 1185 | + * | |
| 1186 | + * <p>The value of SO_RCVBUF is also used to set the TCP receive window | |
| 1187 | + * that is advertized to the remote peer. Generally, the window size | |
| 1188 | + * can be modified at any time when a socket is connected. However, if | |
| 1189 | + * a receive window larger than 64K is required then this must be requested | |
| 1190 | + * <B>before</B> the socket is connected to the remote peer. There are two | |
| 1191 | + * cases to be aware of:<p> | |
| 1192 | + * <ol> | |
| 1193 | + * <li>For sockets accepted from a ServerSocket, this must be done by calling | |
| 1194 | + * {@link ServerSocket#setReceiveBufferSize(int)} before the ServerSocket | |
| 1195 | + * is bound to a local address.<p></li> | |
| 1196 | + * <li>For client sockets, setReceiveBufferSize() must be called before | |
| 1197 | + * connecting the socket to its remote peer.<p></li></ol> | |
| 1198 | + * @param size the size to which to set the receive buffer | |
| 1199 | + * size. This value must be greater than 0. | |
| 1200 | + * | |
| 1201 | + * @exception IllegalArgumentException if the value is 0 or is | |
| 1202 | + * negative. | |
| 1203 | + * | |
| 1204 | + * @exception SocketException if there is an error | |
| 1205 | + * in the underlying protocol, such as a TCP error. | |
| 1206 | + * | |
| 1207 | + * @see #getReceiveBufferSize() | |
| 1208 | + * @see ServerSocket#setReceiveBufferSize(int) | |
| 1209 | + * @since 1.2 | |
| 1210 | + */ | |
| 1211 | + public synchronized void setReceiveBufferSize(int size) | |
| 1212 | + throws SocketException{ | |
| 1213 | + if (size <= 0) { | |
| 1214 | + throw new IllegalArgumentException("invalid receive size"); | |
| 1215 | + } | |
| 1216 | + if (isClosed()) | |
| 1217 | + throw new SocketException("Socket is closed"); | |
| 1218 | + getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size)); | |
| 1219 | + } | |
| 1220 | + | |
| 1221 | + /** | |
| 1222 | + * Gets the value of the SO_RCVBUF option for this <tt>Socket</tt>, | |
| 1223 | + * that is the buffer size used by the platform for | |
| 1224 | + * input on this <tt>Socket</tt>. | |
| 1225 | + * | |
| 1226 | + * @return the value of the SO_RCVBUF option for this <tt>Socket</tt>. | |
| 1227 | + * @exception SocketException if there is an error | |
| 1228 | + * in the underlying protocol, such as a TCP error. | |
| 1229 | + * @see #setReceiveBufferSize(int) | |
| 1230 | + * @since 1.2 | |
| 1231 | + */ | |
| 1232 | + public synchronized int getReceiveBufferSize() | |
| 1233 | + throws SocketException{ | |
| 1234 | + if (isClosed()) | |
| 1235 | + throw new SocketException("Socket is closed"); | |
| 1236 | + int result = 0; | |
| 1237 | + Object o = getImpl().getOption(SocketOptions.SO_RCVBUF); | |
| 1238 | + if (o instanceof Integer) { | |
| 1239 | + result = ((Integer)o).intValue(); | |
| 1240 | + } | |
| 1241 | + return result; | |
| 1242 | + } | |
| 1243 | + | |
| 1244 | + /** | |
| 1245 | + * Enable/disable SO_KEEPALIVE. | |
| 1246 | + * | |
| 1247 | + * @param on whether or not to have socket keep alive turned on. | |
| 1248 | + * @exception SocketException if there is an error | |
| 1249 | + * in the underlying protocol, such as a TCP error. | |
| 1250 | + * @since 1.3 | |
| 1251 | + * @see #getKeepAlive() | |
| 1252 | + */ | |
| 1253 | + public void setKeepAlive(boolean on) throws SocketException { | |
| 1254 | + if (isClosed()) | |
| 1255 | + throw new SocketException("Socket is closed"); | |
| 1256 | + getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on)); | |
| 1257 | + } | |
| 1258 | + | |
| 1259 | + /** | |
| 1260 | + * Tests if SO_KEEPALIVE is enabled. | |
| 1261 | + * | |
| 1262 | + * @return a <code>boolean</code> indicating whether or not SO_KEEPALIVE is enabled. | |
| 1263 | + * @exception SocketException if there is an error | |
| 1264 | + * in the underlying protocol, such as a TCP error. | |
| 1265 | + * @since 1.3 | |
| 1266 | + * @see #setKeepAlive(boolean) | |
| 1267 | + */ | |
| 1268 | + public boolean getKeepAlive() throws SocketException { | |
| 1269 | + if (isClosed()) | |
| 1270 | + throw new SocketException("Socket is closed"); | |
| 1271 | + return ((Boolean) getImpl().getOption(SocketOptions.SO_KEEPALIVE)).booleanValue(); | |
| 1272 | + } | |
| 1273 | + | |
| 1274 | + /** | |
| 1275 | + * Sets traffic class or type-of-service octet in the IP | |
| 1276 | + * header for packets sent from this Socket. | |
| 1277 | + * As the underlying network implementation may ignore this | |
| 1278 | + * value applications should consider it a hint. | |
| 1279 | + * | |
| 1280 | + * <P> The tc <B>must</B> be in the range <code> 0 <= tc <= | |
| 1281 | + * 255</code> or an IllegalArgumentException will be thrown. | |
| 1282 | + * <p>Notes: | |
| 1283 | + * <p>For Internet Protocol v4 the value consists of an | |
| 1284 | + * <code>integer</code>, the least significant 8 bits of which | |
| 1285 | + * represent the value of the TOS octet in IP packets sent by | |
| 1286 | + * the socket. | |
| 1287 | + * RFC 1349 defines the TOS values as follows: | |
| 1288 | + * <p> | |
| 1289 | + * <UL> | |
| 1290 | + * <LI><CODE>IPTOS_LOWCOST (0x02)</CODE></LI> | |
| 1291 | + * <LI><CODE>IPTOS_RELIABILITY (0x04)</CODE></LI> | |
| 1292 | + * <LI><CODE>IPTOS_THROUGHPUT (0x08)</CODE></LI> | |
| 1293 | + * <LI><CODE>IPTOS_LOWDELAY (0x10)</CODE></LI> | |
| 1294 | + * </UL> | |
| 1295 | + * The last low order bit is always ignored as this | |
| 1296 | + * corresponds to the MBZ (must be zero) bit. | |
| 1297 | + * <p> | |
| 1298 | + * Setting bits in the precedence field may result in a | |
| 1299 | + * SocketException indicating that the operation is not | |
| 1300 | + * permitted. | |
| 1301 | + * <p> | |
| 1302 | + * As RFC 1122 section 4.2.4.2 indicates, a compliant TCP | |
| 1303 | + * implementation should, but is not required to, let application | |
| 1304 | + * change the TOS field during the lifetime of a connection. | |
| 1305 | + * So whether the type-of-service field can be changed after the | |
| 1306 | + * TCP connection has been established depends on the implementation | |
| 1307 | + * in the underlying platform. Applications should not assume that | |
| 1308 | + * they can change the TOS field after the connection. | |
| 1309 | + * <p> | |
| 1310 | + * For Internet Protocol v6 <code>tc</code> is the value that | |
| 1311 | + * would be placed into the sin6_flowinfo field of the IP header. | |
| 1312 | + * | |
| 1313 | + * @param tc an <code>int</code> value for the bitset. | |
| 1314 | + * @throws SocketException if there is an error setting the | |
| 1315 | + * traffic class or type-of-service | |
| 1316 | + * @since 1.4 | |
| 1317 | + * @see #getTrafficClass | |
| 1318 | + */ | |
| 1319 | + public void setTrafficClass(int tc) throws SocketException { | |
| 1320 | + if (tc < 0 || tc > 255) | |
| 1321 | + throw new IllegalArgumentException("tc is not in range 0 -- 255"); | |
| 1322 | + | |
| 1323 | + if (isClosed()) | |
| 1324 | + throw new SocketException("Socket is closed"); | |
| 1325 | + getImpl().setOption(SocketOptions.IP_TOS, new Integer(tc)); | |
| 1326 | + } | |
| 1327 | + | |
| 1328 | + /** | |
| 1329 | + * Gets traffic class or type-of-service in the IP header | |
| 1330 | + * for packets sent from this Socket | |
| 1331 | + * <p> | |
| 1332 | + * As the underlying network implementation may ignore the | |
| 1333 | + * traffic class or type-of-service set using {@link #setTrafficClass(int)} | |
| 1334 | + * this method may return a different value than was previously | |
| 1335 | + * set using the {@link #setTrafficClass(int)} method on this Socket. | |
| 1336 | + * | |
| 1337 | + * @return the traffic class or type-of-service already set | |
| 1338 | + * @throws SocketException if there is an error obtaining the | |
| 1339 | + * traffic class or type-of-service value. | |
| 1340 | + * @since 1.4 | |
| 1341 | + * @see #setTrafficClass(int) | |
| 1342 | + */ | |
| 1343 | + public int getTrafficClass() throws SocketException { | |
| 1344 | + return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue(); | |
| 1345 | + } | |
| 1346 | + | |
| 1347 | + /** | |
| 1348 | + * Enable/disable the SO_REUSEADDR socket option. | |
| 1349 | + * <p> | |
| 1350 | + * When a TCP connection is closed the connection may remain | |
| 1351 | + * in a timeout state for a period of time after the connection | |
| 1352 | + * is closed (typically known as the <tt>TIME_WAIT</tt> state | |
| 1353 | + * or <tt>2MSL</tt> wait state). | |
| 1354 | + * For applications using a well known socket address or port | |
| 1355 | + * it may not be possible to bind a socket to the required | |
| 1356 | + * <tt>SocketAddress</tt> if there is a connection in the | |
| 1357 | + * timeout state involving the socket address or port. | |
| 1358 | + * <p> | |
| 1359 | + * Enabling <tt>SO_REUSEADDR</tt> prior to binding the socket | |
| 1360 | + * using {@link #bind(SocketAddress)} allows the socket to be | |
| 1361 | + * bound even though a previous connection is in a timeout | |
| 1362 | + * state. | |
| 1363 | + * <p> | |
| 1364 | + * When a <tt>Socket</tt> is created the initial setting | |
| 1365 | + * of <tt>SO_REUSEADDR</tt> is disabled. | |
| 1366 | + * <p> | |
| 1367 | + * The behaviour when <tt>SO_REUSEADDR</tt> is enabled or | |
| 1368 | + * disabled after a socket is bound (See {@link #isBound()}) | |
| 1369 | + * is not defined. | |
| 1370 | + * | |
| 1371 | + * @param on whether to enable or disable the socket option | |
| 1372 | + * @exception SocketException if an error occurs enabling or | |
| 1373 | + * disabling the <tt>SO_RESUEADDR</tt> socket option, | |
| 1374 | + * or the socket is closed. | |
| 1375 | + * @since 1.4 | |
| 1376 | + * @see #getReuseAddress() | |
| 1377 | + * @see #bind(SocketAddress) | |
| 1378 | + * @see #isClosed() | |
| 1379 | + * @see #isBound() | |
| 1380 | + */ | |
| 1381 | + public void setReuseAddress(boolean on) throws SocketException { | |
| 1382 | + if (isClosed()) | |
| 1383 | + throw new SocketException("Socket is closed"); | |
| 1384 | + getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on)); | |
| 1385 | + } | |
| 1386 | + | |
| 1387 | + /** | |
| 1388 | + * Tests if SO_REUSEADDR is enabled. | |
| 1389 | + * | |
| 1390 | + * @return a <code>boolean</code> indicating whether or not SO_REUSEADDR is enabled. | |
| 1391 | + * @exception SocketException if there is an error | |
| 1392 | + * in the underlying protocol, such as a TCP error. | |
| 1393 | + * @since 1.4 | |
| 1394 | + * @see #setReuseAddress(boolean) | |
| 1395 | + */ | |
| 1396 | + public boolean getReuseAddress() throws SocketException { | |
| 1397 | + if (isClosed()) | |
| 1398 | + throw new SocketException("Socket is closed"); | |
| 1399 | + return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue(); | |
| 1400 | + } | |
| 1401 | + | |
| 1402 | + /** | |
| 1403 | + * Closes this socket. | |
| 1404 | + * <p> | |
| 1405 | + * Any thread currently blocked in an I/O operation upon this socket | |
| 1406 | + * will throw a {@link SocketException}. | |
| 1407 | + * <p> | |
| 1408 | + * Once a socket has been closed, it is not available for further networking | |
| 1409 | + * use (i.e. can't be reconnected or rebound). A new socket needs to be | |
| 1410 | + * created. | |
| 1411 | + * | |
| 1412 | + * <p> Closing this socket will also close the socket's | |
| 1413 | + * {@link java.io.InputStream InputStream} and | |
| 1414 | + * {@link java.io.OutputStream OutputStream}. | |
| 1415 | + * | |
| 1416 | + * <p> If this socket has an associated channel then the channel is closed | |
| 1417 | + * as well. | |
| 1418 | + * | |
| 1419 | + * @exception IOException if an I/O error occurs when closing this socket. | |
| 1420 | + * @revised 1.4 | |
| 1421 | + * @spec JSR-51 | |
| 1422 | + * @see #isClosed | |
| 1423 | + */ | |
| 1424 | + public synchronized void close() throws IOException { | |
| 1425 | + synchronized(closeLock) { | |
| 1426 | + if (isClosed()) | |
| 1427 | + return; | |
| 1428 | + if (created) | |
| 1429 | + impl.close(); | |
| 1430 | + closed = true; | |
| 1431 | + } | |
| 1432 | + } | |
| 1433 | + | |
| 1434 | + /** | |
| 1435 | + * Places the input stream for this socket at "end of stream". | |
| 1436 | + * Any data sent to the input stream side of the socket is acknowledged | |
| 1437 | + * and then silently discarded. | |
| 1438 | + * <p> | |
| 1439 | + * If you read from a socket input stream after invoking | |
| 1440 | + * shutdownInput() on the socket, the stream will return EOF. | |
| 1441 | + * | |
| 1442 | + * @exception IOException if an I/O error occurs when shutting down this | |
| 1443 | + * socket. | |
| 1444 | + * | |
| 1445 | + * @since 1.3 | |
| 1446 | + * @see java.net.Socket#shutdownOutput() | |
| 1447 | + * @see java.net.Socket#close() | |
| 1448 | + * @see java.net.Socket#setSoLinger(boolean, int) | |
| 1449 | + * @see #isInputShutdown | |
| 1450 | + */ | |
| 1451 | + public void shutdownInput() throws IOException | |
| 1452 | + { | |
| 1453 | + if (isClosed()) | |
| 1454 | + throw new SocketException("Socket is closed"); | |
| 1455 | + if (!isConnected()) | |
| 1456 | + throw new SocketException("Socket is not connected"); | |
| 1457 | + if (isInputShutdown()) | |
| 1458 | + throw new SocketException("Socket input is already shutdown"); | |
| 1459 | + getImpl().shutdownInput(); | |
| 1460 | + shutIn = true; | |
| 1461 | + } | |
| 1462 | + | |
| 1463 | + /** | |
| 1464 | + * Disables the output stream for this socket. | |
| 1465 | + * For a TCP socket, any previously written data will be sent | |
| 1466 | + * followed by TCP's normal connection termination sequence. | |
| 1467 | + * | |
| 1468 | + * If you write to a socket output stream after invoking | |
| 1469 | + * shutdownOutput() on the socket, the stream will throw | |
| 1470 | + * an IOException. | |
| 1471 | + * | |
| 1472 | + * @exception IOException if an I/O error occurs when shutting down this | |
| 1473 | + * socket. | |
| 1474 | + * | |
| 1475 | + * @since 1.3 | |
| 1476 | + * @see java.net.Socket#shutdownInput() | |
| 1477 | + * @see java.net.Socket#close() | |
| 1478 | + * @see java.net.Socket#setSoLinger(boolean, int) | |
| 1479 | + * @see #isOutputShutdown | |
| 1480 | + */ | |
| 1481 | + public void shutdownOutput() throws IOException | |
| 1482 | + { | |
| 1483 | + if (isClosed()) | |
| 1484 | + throw new SocketException("Socket is closed"); | |
| 1485 | + if (!isConnected()) | |
| 1486 | + throw new SocketException("Socket is not connected"); | |
| 1487 | + if (isOutputShutdown()) | |
| 1488 | + throw new SocketException("Socket output is already shutdown"); | |
| 1489 | + getImpl().shutdownOutput(); | |
| 1490 | + shutOut = true; | |
| 1491 | + } | |
| 1492 | + | |
| 1493 | + /** | |
| 1494 | + * Converts this socket to a <code>String</code>. | |
| 1495 | + * | |
| 1496 | + * @return a string representation of this socket. | |
| 1497 | + */ | |
| 1498 | + public String toString() { | |
| 1499 | + try { | |
| 1500 | + if (isConnected()) | |
| 1501 | + return "Socket[addr=" + getImpl().getInetAddress() + | |
| 1502 | + ",port=" + getImpl().getPort() + | |
| 1503 | + ",localport=" + getImpl().getLocalPort() + "]"; | |
| 1504 | + } catch (SocketException e) { | |
| 1505 | + } | |
| 1506 | + return "Socket[unconnected]"; | |
| 1507 | + } | |
| 1508 | + | |
| 1509 | + /** | |
| 1510 | + * Returns the connection state of the socket. | |
| 1511 | + * <p> | |
| 1512 | + * Note: Closing a socket doesn't clear its connection state, which means | |
| 1513 | + * this method will return <code>true</code> for a closed socket | |
| 1514 | + * (see {@link #isClosed()}) if it was successfuly connected prior | |
| 1515 | + * to being closed. | |
| 1516 | + * | |
| 1517 | + * @return true if the socket was successfuly connected to a server | |
| 1518 | + * @since 1.4 | |
| 1519 | + */ | |
| 1520 | + public boolean isConnected() { | |
| 1521 | + // Before 1.3 Sockets were always connected during creation | |
| 1522 | + return connected || oldImpl; | |
| 1523 | + } | |
| 1524 | + | |
| 1525 | + /** | |
| 1526 | + * Returns the binding state of the socket. | |
| 1527 | + * <p> | |
| 1528 | + * Note: Closing a socket doesn't clear its binding state, which means | |
| 1529 | + * this method will return <code>true</code> for a closed socket | |
| 1530 | + * (see {@link #isClosed()}) if it was successfuly bound prior | |
| 1531 | + * to being closed. | |
| 1532 | + * | |
| 1533 | + * @return true if the socket was successfuly bound to an address | |
| 1534 | + * @since 1.4 | |
| 1535 | + * @see #bind | |
| 1536 | + */ | |
| 1537 | + public boolean isBound() { | |
| 1538 | + // Before 1.3 Sockets were always bound during creation | |
| 1539 | + return bound || oldImpl; | |
| 1540 | + } | |
| 1541 | + | |
| 1542 | + /** | |
| 1543 | + * Returns the closed state of the socket. | |
| 1544 | + * | |
| 1545 | + * @return true if the socket has been closed | |
| 1546 | + * @since 1.4 | |
| 1547 | + * @see #close | |
| 1548 | + */ | |
| 1549 | + public boolean isClosed() { | |
| 1550 | + synchronized(closeLock) { | |
| 1551 | + return closed; | |
| 1552 | + } | |
| 1553 | + } | |
| 1554 | + | |
| 1555 | + /** | |
| 1556 | + * Returns whether the read-half of the socket connection is closed. | |
| 1557 | + * | |
| 1558 | + * @return true if the input of the socket has been shutdown | |
| 1559 | + * @since 1.4 | |
| 1560 | + * @see #shutdownInput | |
| 1561 | + */ | |
| 1562 | + public boolean isInputShutdown() { | |
| 1563 | + return shutIn; | |
| 1564 | + } | |
| 1565 | + | |
| 1566 | + /** | |
| 1567 | + * Returns whether the write-half of the socket connection is closed. | |
| 1568 | + * | |
| 1569 | + * @return true if the output of the socket has been shutdown | |
| 1570 | + * @since 1.4 | |
| 1571 | + * @see #shutdownOutput | |
| 1572 | + */ | |
| 1573 | + public boolean isOutputShutdown() { | |
| 1574 | + return shutOut; | |
| 1575 | + } | |
| 1576 | + | |
| 1577 | + /** | |
| 1578 | + * The factory for all client sockets. | |
| 1579 | + */ | |
| 1580 | + private static SocketImplFactory factory = null; | |
| 1581 | + | |
| 1582 | + /** | |
| 1583 | + * Sets the client socket implementation factory for the | |
| 1584 | + * application. The factory can be specified only once. | |
| 1585 | + * <p> | |
| 1586 | + * When an application creates a new client socket, the socket | |
| 1587 | + * implementation factory's <code>createSocketImpl</code> method is | |
| 1588 | + * called to create the actual socket implementation. | |
| 1589 | + * <p> | |
| 1590 | + * Passing <code>null</code> to the method is a no-op unless the factory | |
| 1591 | + * was already set. | |
| 1592 | + * <p>If there is a security manager, this method first calls | |
| 1593 | + * the security manager's <code>checkSetFactory</code> method | |
| 1594 | + * to ensure the operation is allowed. | |
| 1595 | + * This could result in a SecurityException. | |
| 1596 | + * | |
| 1597 | + * @param fac the desired factory. | |
| 1598 | + * @exception IOException if an I/O error occurs when setting the | |
| 1599 | + * socket factory. | |
| 1600 | + * @exception SocketException if the factory is already defined. | |
| 1601 | + * @exception SecurityException if a security manager exists and its | |
| 1602 | + * <code>checkSetFactory</code> method doesn't allow the operation. | |
| 1603 | + * @see java.net.SocketImplFactory#createSocketImpl() | |
| 1604 | + * @see SecurityManager#checkSetFactory | |
| 1605 | + */ | |
| 1606 | + public static synchronized void setSocketImplFactory(SocketImplFactory fac) | |
| 1607 | + throws IOException | |
| 1608 | + { | |
| 1609 | + if (factory != null) { | |
| 1610 | + throw new SocketException("factory already defined"); | |
| 1611 | + } | |
| 1612 | + SecurityManager security = System.getSecurityManager(); | |
| 1613 | + if (security != null) { | |
| 1614 | + security.checkSetFactory(); | |
| 1615 | + } | |
| 1616 | + factory = fac; | |
| 1617 | + } | |
| 1618 | + | |
| 1619 | + /** | |
| 1620 | + * Sets performance preferences for this socket. | |
| 1621 | + * | |
| 1622 | + * <p> Sockets use the TCP/IP protocol by default. Some implementations | |
| 1623 | + * may offer alternative protocols which have different performance | |
| 1624 | + * characteristics than TCP/IP. This method allows the application to | |
| 1625 | + * express its own preferences as to how these tradeoffs should be made | |
| 1626 | + * when the implementation chooses from the available protocols. | |
| 1627 | + * | |
| 1628 | + * <p> Performance preferences are described by three integers | |
| 1629 | + * whose values indicate the relative importance of short connection time, | |
| 1630 | + * low latency, and high bandwidth. The absolute values of the integers | |
| 1631 | + * are irrelevant; in order to choose a protocol the values are simply | |
| 1632 | + * compared, with larger values indicating stronger preferences. Negative | |
| 1633 | + * values represent a lower priority than positive values. If the | |
| 1634 | + * application prefers short connection time over both low latency and high | |
| 1635 | + * bandwidth, for example, then it could invoke this method with the values | |
| 1636 | + * <tt>(1, 0, 0)</tt>. If the application prefers high bandwidth above low | |
| 1637 | + * latency, and low latency above short connection time, then it could | |
| 1638 | + * invoke this method with the values <tt>(0, 1, 2)</tt>. | |
| 1639 | + * | |
| 1640 | + * <p> Invoking this method after this socket has been connected | |
| 1641 | + * will have no effect. | |
| 1642 | + * | |
| 1643 | + * @param connectionTime | |
| 1644 | + * An <tt>int</tt> expressing the relative importance of a short | |
| 1645 | + * connection time | |
| 1646 | + * | |
| 1647 | + * @param latency | |
| 1648 | + * An <tt>int</tt> expressing the relative importance of low | |
| 1649 | + * latency | |
| 1650 | + * | |
| 1651 | + * @param bandwidth | |
| 1652 | + * An <tt>int</tt> expressing the relative importance of high | |
| 1653 | + * bandwidth | |
| 1654 | + * | |
| 1655 | + * @since 1.5 | |
| 1656 | + */ | |
| 1657 | + public void setPerformancePreferences(int connectionTime, | |
| 1658 | + int latency, | |
| 1659 | + int bandwidth) | |
| 1660 | + { | |
| 1661 | + /* Not implemented yet */ | |
| 1662 | + } | |
| 1663 | +} | |
Binary file not shown.
| @@ -0,0 +1,42 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 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 | +package java.net; | |
| 26 | + | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * | |
| 30 | + * This class represents a Socket Address with no protocol attachment. | |
| 31 | + * As an abstract class, it is meant to be subclassed with a specific, | |
| 32 | + * protocol dependent, implementation. | |
| 33 | + * <p> | |
| 34 | + * It provides an immutable object used by sockets for binding, connecting, or | |
| 35 | + * as returned values. | |
| 36 | + * | |
| 37 | + * @see java.net.Socket | |
| 38 | + * @see java.net.ServerSocket | |
| 39 | + * @since 1.4 | |
| 40 | + */ | |
| 41 | +public abstract class SocketAddress implements java.io.Serializable { | |
| 42 | +} | |
Binary file not shown.
| @@ -0,0 +1,55 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * Thrown to indicate that there is an error creating or accessing a Socket. | |
| 32 | + * | |
| 33 | + * @author Jonathan Payne | |
| 34 | + * @since JDK1.0 | |
| 35 | + */ | |
| 36 | +public | |
| 37 | +class SocketException extends IOException { | |
| 38 | + private static final long serialVersionUID = -5935874303556886934L; | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * Constructs a new <code>SocketException</code> with the | |
| 42 | + * specified detail message. | |
| 43 | + * | |
| 44 | + * @param msg the detail message. | |
| 45 | + */ | |
| 46 | + public SocketException(String msg) { | |
| 47 | + super(msg); | |
| 48 | + } | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * Constructs a new <code>SocketException</code> with no detail message. | |
| 52 | + */ | |
| 53 | + public SocketException() { | |
| 54 | + } | |
| 55 | +} | |
Binary file not shown.
| @@ -0,0 +1,357 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2006, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.IOException; | |
| 29 | +import java.io.InputStream; | |
| 30 | +import java.io.OutputStream; | |
| 31 | +import java.io.FileDescriptor; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * The abstract class <code>SocketImpl</code> is a common superclass | |
| 35 | + * of all classes that actually implement sockets. It is used to | |
| 36 | + * create both client and server sockets. | |
| 37 | + * <p> | |
| 38 | + * A "plain" socket implements these methods exactly as | |
| 39 | + * described, without attempting to go through a firewall or proxy. | |
| 40 | + * | |
| 41 | + * @author unascribed | |
| 42 | + * @since JDK1.0 | |
| 43 | + */ | |
| 44 | +public abstract class SocketImpl implements SocketOptions { | |
| 45 | + /** | |
| 46 | + * The actual Socket object. | |
| 47 | + */ | |
| 48 | + Socket socket = null; | |
| 49 | + ServerSocket serverSocket = null; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * The file descriptor object for this socket. | |
| 53 | + */ | |
| 54 | + protected FileDescriptor fd; | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * The IP address of the remote end of this socket. | |
| 58 | + */ | |
| 59 | + protected InetAddress address; | |
| 60 | + | |
| 61 | + /** | |
| 62 | + * The port number on the remote host to which this socket is connected. | |
| 63 | + */ | |
| 64 | + protected int port; | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * The local port number to which this socket is connected. | |
| 68 | + */ | |
| 69 | + protected int localport; | |
| 70 | + | |
| 71 | + /** | |
| 72 | + * Creates either a stream or a datagram socket. | |
| 73 | + * | |
| 74 | + * @param stream if <code>true</code>, create a stream socket; | |
| 75 | + * otherwise, create a datagram socket. | |
| 76 | + * @exception IOException if an I/O error occurs while creating the | |
| 77 | + * socket. | |
| 78 | + */ | |
| 79 | + protected abstract void create(boolean stream) throws IOException; | |
| 80 | + | |
| 81 | + /** | |
| 82 | + * Connects this socket to the specified port on the named host. | |
| 83 | + * | |
| 84 | + * @param host the name of the remote host. | |
| 85 | + * @param port the port number. | |
| 86 | + * @exception IOException if an I/O error occurs when connecting to the | |
| 87 | + * remote host. | |
| 88 | + */ | |
| 89 | + protected abstract void connect(String host, int port) throws IOException; | |
| 90 | + | |
| 91 | + /** | |
| 92 | + * Connects this socket to the specified port number on the specified host. | |
| 93 | + * | |
| 94 | + * @param address the IP address of the remote host. | |
| 95 | + * @param port the port number. | |
| 96 | + * @exception IOException if an I/O error occurs when attempting a | |
| 97 | + * connection. | |
| 98 | + */ | |
| 99 | + protected abstract void connect(InetAddress address, int port) throws IOException; | |
| 100 | + | |
| 101 | + /** | |
| 102 | + * Connects this socket to the specified port number on the specified host. | |
| 103 | + * A timeout of zero is interpreted as an infinite timeout. The connection | |
| 104 | + * will then block until established or an error occurs. | |
| 105 | + * | |
| 106 | + * @param address the Socket address of the remote host. | |
| 107 | + * @param timeout the timeout value, in milliseconds, or zero for no timeout. | |
| 108 | + * @exception IOException if an I/O error occurs when attempting a | |
| 109 | + * connection. | |
| 110 | + * @since 1.4 | |
| 111 | + */ | |
| 112 | + protected abstract void connect(SocketAddress address, int timeout) throws IOException; | |
| 113 | + | |
| 114 | + /** | |
| 115 | + * Binds this socket to the specified local IP address and port number. | |
| 116 | + * | |
| 117 | + * @param host an IP address that belongs to a local interface. | |
| 118 | + * @param port the port number. | |
| 119 | + * @exception IOException if an I/O error occurs when binding this socket. | |
| 120 | + */ | |
| 121 | + protected abstract void bind(InetAddress host, int port) throws IOException; | |
| 122 | + | |
| 123 | + /** | |
| 124 | + * Sets the maximum queue length for incoming connection indications | |
| 125 | + * (a request to connect) to the <code>count</code> argument. If a | |
| 126 | + * connection indication arrives when the queue is full, the | |
| 127 | + * connection is refused. | |
| 128 | + * | |
| 129 | + * @param backlog the maximum length of the queue. | |
| 130 | + * @exception IOException if an I/O error occurs when creating the queue. | |
| 131 | + */ | |
| 132 | + protected abstract void listen(int backlog) throws IOException; | |
| 133 | + | |
| 134 | + /** | |
| 135 | + * Accepts a connection. | |
| 136 | + * | |
| 137 | + * @param s the accepted connection. | |
| 138 | + * @exception IOException if an I/O error occurs when accepting the | |
| 139 | + * connection. | |
| 140 | + */ | |
| 141 | + protected abstract void accept(SocketImpl s) throws IOException; | |
| 142 | + | |
| 143 | + /** | |
| 144 | + * Returns an input stream for this socket. | |
| 145 | + * | |
| 146 | + * @return a stream for reading from this socket. | |
| 147 | + * @exception IOException if an I/O error occurs when creating the | |
| 148 | + * input stream. | |
| 149 | + */ | |
| 150 | + protected abstract InputStream getInputStream() throws IOException; | |
| 151 | + | |
| 152 | + /** | |
| 153 | + * Returns an output stream for this socket. | |
| 154 | + * | |
| 155 | + * @return an output stream for writing to this socket. | |
| 156 | + * @exception IOException if an I/O error occurs when creating the | |
| 157 | + * output stream. | |
| 158 | + */ | |
| 159 | + protected abstract OutputStream getOutputStream() throws IOException; | |
| 160 | + | |
| 161 | + /** | |
| 162 | + * Returns the number of bytes that can be read from this socket | |
| 163 | + * without blocking. | |
| 164 | + * | |
| 165 | + * @return the number of bytes that can be read from this socket | |
| 166 | + * without blocking. | |
| 167 | + * @exception IOException if an I/O error occurs when determining the | |
| 168 | + * number of bytes available. | |
| 169 | + */ | |
| 170 | + protected abstract int available() throws IOException; | |
| 171 | + | |
| 172 | + /** | |
| 173 | + * Closes this socket. | |
| 174 | + * | |
| 175 | + * @exception IOException if an I/O error occurs when closing this socket. | |
| 176 | + */ | |
| 177 | + protected abstract void close() throws IOException; | |
| 178 | + | |
| 179 | + /** | |
| 180 | + * Places the input stream for this socket at "end of stream". | |
| 181 | + * Any data sent to this socket is acknowledged and then | |
| 182 | + * silently discarded. | |
| 183 | + * | |
| 184 | + * If you read from a socket input stream after invoking | |
| 185 | + * shutdownInput() on the socket, the stream will return EOF. | |
| 186 | + * | |
| 187 | + * @exception IOException if an I/O error occurs when shutting down this | |
| 188 | + * socket. | |
| 189 | + * @see java.net.Socket#shutdownOutput() | |
| 190 | + * @see java.net.Socket#close() | |
| 191 | + * @see java.net.Socket#setSoLinger(boolean, int) | |
| 192 | + * @since 1.3 | |
| 193 | + */ | |
| 194 | + protected void shutdownInput() throws IOException { | |
| 195 | + throw new IOException("Method not implemented!"); | |
| 196 | + } | |
| 197 | + | |
| 198 | + /** | |
| 199 | + * Disables the output stream for this socket. | |
| 200 | + * For a TCP socket, any previously written data will be sent | |
| 201 | + * followed by TCP's normal connection termination sequence. | |
| 202 | + * | |
| 203 | + * If you write to a socket output stream after invoking | |
| 204 | + * shutdownOutput() on the socket, the stream will throw | |
| 205 | + * an IOException. | |
| 206 | + * | |
| 207 | + * @exception IOException if an I/O error occurs when shutting down this | |
| 208 | + * socket. | |
| 209 | + * @see java.net.Socket#shutdownInput() | |
| 210 | + * @see java.net.Socket#close() | |
| 211 | + * @see java.net.Socket#setSoLinger(boolean, int) | |
| 212 | + * @since 1.3 | |
| 213 | + */ | |
| 214 | + protected void shutdownOutput() throws IOException { | |
| 215 | + throw new IOException("Method not implemented!"); | |
| 216 | + } | |
| 217 | + | |
| 218 | + /** | |
| 219 | + * Returns the value of this socket's <code>fd</code> field. | |
| 220 | + * | |
| 221 | + * @return the value of this socket's <code>fd</code> field. | |
| 222 | + * @see java.net.SocketImpl#fd | |
| 223 | + */ | |
| 224 | + protected FileDescriptor getFileDescriptor() { | |
| 225 | + return fd; | |
| 226 | + } | |
| 227 | + | |
| 228 | + /** | |
| 229 | + * Returns the value of this socket's <code>address</code> field. | |
| 230 | + * | |
| 231 | + * @return the value of this socket's <code>address</code> field. | |
| 232 | + * @see java.net.SocketImpl#address | |
| 233 | + */ | |
| 234 | + protected InetAddress getInetAddress() { | |
| 235 | + return address; | |
| 236 | + } | |
| 237 | + | |
| 238 | + /** | |
| 239 | + * Returns the value of this socket's <code>port</code> field. | |
| 240 | + * | |
| 241 | + * @return the value of this socket's <code>port</code> field. | |
| 242 | + * @see java.net.SocketImpl#port | |
| 243 | + */ | |
| 244 | + protected int getPort() { | |
| 245 | + return port; | |
| 246 | + } | |
| 247 | + | |
| 248 | + /** | |
| 249 | + * Returns whether or not this SocketImpl supports sending | |
| 250 | + * urgent data. By default, false is returned | |
| 251 | + * unless the method is overridden in a sub-class | |
| 252 | + * | |
| 253 | + * @return true if urgent data supported | |
| 254 | + * @see java.net.SocketImpl#address | |
| 255 | + * @since 1.4 | |
| 256 | + */ | |
| 257 | + protected boolean supportsUrgentData () { | |
| 258 | + return false; // must be overridden in sub-class | |
| 259 | + } | |
| 260 | + | |
| 261 | + /** | |
| 262 | + * Send one byte of urgent data on the socket. | |
| 263 | + * The byte to be sent is the low eight bits of the parameter | |
| 264 | + * @param data The byte of data to send | |
| 265 | + * @exception IOException if there is an error | |
| 266 | + * sending the data. | |
| 267 | + * @since 1.4 | |
| 268 | + */ | |
| 269 | + protected abstract void sendUrgentData (int data) throws IOException; | |
| 270 | + | |
| 271 | + /** | |
| 272 | + * Returns the value of this socket's <code>localport</code> field. | |
| 273 | + * | |
| 274 | + * @return the value of this socket's <code>localport</code> field. | |
| 275 | + * @see java.net.SocketImpl#localport | |
| 276 | + */ | |
| 277 | + protected int getLocalPort() { | |
| 278 | + return localport; | |
| 279 | + } | |
| 280 | + | |
| 281 | + void setSocket(Socket soc) { | |
| 282 | + this.socket = soc; | |
| 283 | + } | |
| 284 | + | |
| 285 | + Socket getSocket() { | |
| 286 | + return socket; | |
| 287 | + } | |
| 288 | + | |
| 289 | + void setServerSocket(ServerSocket soc) { | |
| 290 | + this.serverSocket = soc; | |
| 291 | + } | |
| 292 | + | |
| 293 | + ServerSocket getServerSocket() { | |
| 294 | + return serverSocket; | |
| 295 | + } | |
| 296 | + | |
| 297 | + /** | |
| 298 | + * Returns the address and port of this socket as a <code>String</code>. | |
| 299 | + * | |
| 300 | + * @return a string representation of this socket. | |
| 301 | + */ | |
| 302 | + public String toString() { | |
| 303 | + return "Socket[addr=" + getInetAddress() + | |
| 304 | + ",port=" + getPort() + ",localport=" + getLocalPort() + "]"; | |
| 305 | + } | |
| 306 | + | |
| 307 | + void reset() throws IOException { | |
| 308 | + address = null; | |
| 309 | + port = 0; | |
| 310 | + localport = 0; | |
| 311 | + } | |
| 312 | + | |
| 313 | + /** | |
| 314 | + * Sets performance preferences for this socket. | |
| 315 | + * | |
| 316 | + * <p> Sockets use the TCP/IP protocol by default. Some implementations | |
| 317 | + * may offer alternative protocols which have different performance | |
| 318 | + * characteristics than TCP/IP. This method allows the application to | |
| 319 | + * express its own preferences as to how these tradeoffs should be made | |
| 320 | + * when the implementation chooses from the available protocols. | |
| 321 | + * | |
| 322 | + * <p> Performance preferences are described by three integers | |
| 323 | + * whose values indicate the relative importance of short connection time, | |
| 324 | + * low latency, and high bandwidth. The absolute values of the integers | |
| 325 | + * are irrelevant; in order to choose a protocol the values are simply | |
| 326 | + * compared, with larger values indicating stronger preferences. Negative | |
| 327 | + * values represent a lower priority than positive values. If the | |
| 328 | + * application prefers short connection time over both low latency and high | |
| 329 | + * bandwidth, for example, then it could invoke this method with the values | |
| 330 | + * <tt>(1, 0, 0)</tt>. If the application prefers high bandwidth above low | |
| 331 | + * latency, and low latency above short connection time, then it could | |
| 332 | + * invoke this method with the values <tt>(0, 1, 2)</tt>. | |
| 333 | + * | |
| 334 | + * By default, this method does nothing, unless it is overridden in a | |
| 335 | + * a sub-class. | |
| 336 | + * | |
| 337 | + * @param connectionTime | |
| 338 | + * An <tt>int</tt> expressing the relative importance of a short | |
| 339 | + * connection time | |
| 340 | + * | |
| 341 | + * @param latency | |
| 342 | + * An <tt>int</tt> expressing the relative importance of low | |
| 343 | + * latency | |
| 344 | + * | |
| 345 | + * @param bandwidth | |
| 346 | + * An <tt>int</tt> expressing the relative importance of high | |
| 347 | + * bandwidth | |
| 348 | + * | |
| 349 | + * @since 1.5 | |
| 350 | + */ | |
| 351 | + protected void setPerformancePreferences(int connectionTime, | |
| 352 | + int latency, | |
| 353 | + int bandwidth) | |
| 354 | + { | |
| 355 | + /* Not implemented yet */ | |
| 356 | + } | |
| 357 | +} | |
Binary file not shown.
| @@ -0,0 +1,48 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 1999, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * This interface defines a factory for socket implementations. It | |
| 30 | + * is used by the classes <code>Socket</code> and | |
| 31 | + * <code>ServerSocket</code> to create actual socket | |
| 32 | + * implementations. | |
| 33 | + * | |
| 34 | + * @author Arthur van Hoff | |
| 35 | + * @see java.net.Socket | |
| 36 | + * @see java.net.ServerSocket | |
| 37 | + * @since JDK1.0 | |
| 38 | + */ | |
| 39 | +public | |
| 40 | +interface SocketImplFactory { | |
| 41 | + /** | |
| 42 | + * Creates a new <code>SocketImpl</code> instance. | |
| 43 | + * | |
| 44 | + * @return a new instance of <code>SocketImpl</code>. | |
| 45 | + * @see java.net.SocketImpl | |
| 46 | + */ | |
| 47 | + SocketImpl createSocketImpl(); | |
| 48 | +} | |
Binary file not shown.
| @@ -0,0 +1,271 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2010, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.FileDescriptor; | |
| 29 | +import java.io.FileInputStream; | |
| 30 | +import java.io.IOException; | |
| 31 | +import java.nio.channels.FileChannel; | |
| 32 | + | |
| 33 | +import sun.net.ConnectionResetException; | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * This stream extends FileInputStream to implement a | |
| 37 | + * SocketInputStream. Note that this class should <b>NOT</b> be | |
| 38 | + * public. | |
| 39 | + * | |
| 40 | + * @author Jonathan Payne | |
| 41 | + * @author Arthur van Hoff | |
| 42 | + */ | |
| 43 | +class SocketInputStream extends FileInputStream | |
| 44 | +{ | |
| 45 | + static { | |
| 46 | + init(); | |
| 47 | + } | |
| 48 | + | |
| 49 | + private boolean eof; | |
| 50 | + private AbstractPlainSocketImpl impl = null; | |
| 51 | + private byte temp[]; | |
| 52 | + private Socket socket = null; | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * Creates a new SocketInputStream. Can only be called | |
| 56 | + * by a Socket. This method needs to hang on to the owner Socket so | |
| 57 | + * that the fd will not be closed. | |
| 58 | + * @param impl the implemented socket input stream | |
| 59 | + */ | |
| 60 | + SocketInputStream(AbstractPlainSocketImpl impl) throws IOException { | |
| 61 | + super(impl.getFileDescriptor()); | |
| 62 | + this.impl = impl; | |
| 63 | + socket = impl.getSocket(); | |
| 64 | + } | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * Returns the unique {@link java.nio.channels.FileChannel FileChannel} | |
| 68 | + * object associated with this file input stream.</p> | |
| 69 | + * | |
| 70 | + * The <code>getChannel</code> method of <code>SocketInputStream</code> | |
| 71 | + * returns <code>null</code> since it is a socket based stream.</p> | |
| 72 | + * | |
| 73 | + * @return the file channel associated with this file input stream | |
| 74 | + * | |
| 75 | + * @since 1.4 | |
| 76 | + * @spec JSR-51 | |
| 77 | + */ | |
| 78 | + public final FileChannel getChannel() { | |
| 79 | + return null; | |
| 80 | + } | |
| 81 | + | |
| 82 | + /** | |
| 83 | + * Reads into an array of bytes at the specified offset using | |
| 84 | + * the received socket primitive. | |
| 85 | + * @param fd the FileDescriptor | |
| 86 | + * @param b the buffer into which the data is read | |
| 87 | + * @param off the start offset of the data | |
| 88 | + * @param len the maximum number of bytes read | |
| 89 | + * @param timeout the read timeout in ms | |
| 90 | + * @return the actual number of bytes read, -1 is | |
| 91 | + * returned when the end of the stream is reached. | |
| 92 | + * @exception IOException If an I/O error has occurred. | |
| 93 | + */ | |
| 94 | + private native int socketRead0(FileDescriptor fd, | |
| 95 | + byte b[], int off, int len, | |
| 96 | + int timeout) | |
| 97 | + throws IOException; | |
| 98 | + | |
| 99 | + /** | |
| 100 | + * Reads into a byte array data from the socket. | |
| 101 | + * @param b the buffer into which the data is read | |
| 102 | + * @return the actual number of bytes read, -1 is | |
| 103 | + * returned when the end of the stream is reached. | |
| 104 | + * @exception IOException If an I/O error has occurred. | |
| 105 | + */ | |
| 106 | + public int read(byte b[]) throws IOException { | |
| 107 | + return read(b, 0, b.length); | |
| 108 | + } | |
| 109 | + | |
| 110 | + /** | |
| 111 | + * Reads into a byte array <i>b</i> at offset <i>off</i>, | |
| 112 | + * <i>length</i> bytes of data. | |
| 113 | + * @param b the buffer into which the data is read | |
| 114 | + * @param off the start offset of the data | |
| 115 | + * @param len the maximum number of bytes read | |
| 116 | + * @return the actual number of bytes read, -1 is | |
| 117 | + * returned when the end of the stream is reached. | |
| 118 | + * @exception IOException If an I/O error has occurred. | |
| 119 | + */ | |
| 120 | + public int read(byte b[], int off, int length) throws IOException { | |
| 121 | + return read(b, off, length, impl.getTimeout()); | |
| 122 | + } | |
| 123 | + | |
| 124 | + int read(byte b[], int off, int length, int timeout) throws IOException { | |
| 125 | + int n; | |
| 126 | + | |
| 127 | + // EOF already encountered | |
| 128 | + if (eof) { | |
| 129 | + return -1; | |
| 130 | + } | |
| 131 | + | |
| 132 | + // connection reset | |
| 133 | + if (impl.isConnectionReset()) { | |
| 134 | + throw new SocketException("Connection reset"); | |
| 135 | + } | |
| 136 | + | |
| 137 | + // bounds check | |
| 138 | + if (length <= 0 || off < 0 || off + length > b.length) { | |
| 139 | + if (length == 0) { | |
| 140 | + return 0; | |
| 141 | + } | |
| 142 | + throw new ArrayIndexOutOfBoundsException(); | |
| 143 | + } | |
| 144 | + | |
| 145 | + boolean gotReset = false; | |
| 146 | + | |
| 147 | + // acquire file descriptor and do the read | |
| 148 | + FileDescriptor fd = impl.acquireFD(); | |
| 149 | + try { | |
| 150 | + n = socketRead0(fd, b, off, length, timeout); | |
| 151 | + if (n > 0) { | |
| 152 | + return n; | |
| 153 | + } | |
| 154 | + } catch (ConnectionResetException rstExc) { | |
| 155 | + gotReset = true; | |
| 156 | + } finally { | |
| 157 | + impl.releaseFD(); | |
| 158 | + } | |
| 159 | + | |
| 160 | + /* | |
| 161 | + * We receive a "connection reset" but there may be bytes still | |
| 162 | + * buffered on the socket | |
| 163 | + */ | |
| 164 | + if (gotReset) { | |
| 165 | + impl.setConnectionResetPending(); | |
| 166 | + impl.acquireFD(); | |
| 167 | + try { | |
| 168 | + n = socketRead0(fd, b, off, length, timeout); | |
| 169 | + if (n > 0) { | |
| 170 | + return n; | |
| 171 | + } | |
| 172 | + } catch (ConnectionResetException rstExc) { | |
| 173 | + } finally { | |
| 174 | + impl.releaseFD(); | |
| 175 | + } | |
| 176 | + } | |
| 177 | + | |
| 178 | + /* | |
| 179 | + * If we get here we are at EOF, the socket has been closed, | |
| 180 | + * or the connection has been reset. | |
| 181 | + */ | |
| 182 | + if (impl.isClosedOrPending()) { | |
| 183 | + throw new SocketException("Socket closed"); | |
| 184 | + } | |
| 185 | + if (impl.isConnectionResetPending()) { | |
| 186 | + impl.setConnectionReset(); | |
| 187 | + } | |
| 188 | + if (impl.isConnectionReset()) { | |
| 189 | + throw new SocketException("Connection reset"); | |
| 190 | + } | |
| 191 | + eof = true; | |
| 192 | + return -1; | |
| 193 | + } | |
| 194 | + | |
| 195 | + /** | |
| 196 | + * Reads a single byte from the socket. | |
| 197 | + */ | |
| 198 | + public int read() throws IOException { | |
| 199 | + if (eof) { | |
| 200 | + return -1; | |
| 201 | + } | |
| 202 | + temp = new byte[1]; | |
| 203 | + int n = read(temp, 0, 1); | |
| 204 | + if (n <= 0) { | |
| 205 | + return -1; | |
| 206 | + } | |
| 207 | + return temp[0] & 0xff; | |
| 208 | + } | |
| 209 | + | |
| 210 | + /** | |
| 211 | + * Skips n bytes of input. | |
| 212 | + * @param n the number of bytes to skip | |
| 213 | + * @return the actual number of bytes skipped. | |
| 214 | + * @exception IOException If an I/O error has occurred. | |
| 215 | + */ | |
| 216 | + public long skip(long numbytes) throws IOException { | |
| 217 | + if (numbytes <= 0) { | |
| 218 | + return 0; | |
| 219 | + } | |
| 220 | + long n = numbytes; | |
| 221 | + int buflen = (int) Math.min(1024, n); | |
| 222 | + byte data[] = new byte[buflen]; | |
| 223 | + while (n > 0) { | |
| 224 | + int r = read(data, 0, (int) Math.min((long) buflen, n)); | |
| 225 | + if (r < 0) { | |
| 226 | + break; | |
| 227 | + } | |
| 228 | + n -= r; | |
| 229 | + } | |
| 230 | + return numbytes - n; | |
| 231 | + } | |
| 232 | + | |
| 233 | + /** | |
| 234 | + * Returns the number of bytes that can be read without blocking. | |
| 235 | + * @return the number of immediately available bytes | |
| 236 | + */ | |
| 237 | + public int available() throws IOException { | |
| 238 | + return impl.available(); | |
| 239 | + } | |
| 240 | + | |
| 241 | + /** | |
| 242 | + * Closes the stream. | |
| 243 | + */ | |
| 244 | + private boolean closing = false; | |
| 245 | + public void close() throws IOException { | |
| 246 | + // Prevent recursion. See BugId 4484411 | |
| 247 | + if (closing) | |
| 248 | + return; | |
| 249 | + closing = true; | |
| 250 | + if (socket != null) { | |
| 251 | + if (!socket.isClosed()) | |
| 252 | + socket.close(); | |
| 253 | + } else | |
| 254 | + impl.close(); | |
| 255 | + closing = false; | |
| 256 | + } | |
| 257 | + | |
| 258 | + void setEOF(boolean eof) { | |
| 259 | + this.eof = eof; | |
| 260 | + } | |
| 261 | + | |
| 262 | + /** | |
| 263 | + * Overrides finalize, the fd is closed by the Socket. | |
| 264 | + */ | |
| 265 | + protected void finalize() {} | |
| 266 | + | |
| 267 | + /** | |
| 268 | + * Perform class load-time initializations. | |
| 269 | + */ | |
| 270 | + private native static void init(); | |
| 271 | +} | |
Binary file not shown.
| @@ -0,0 +1,55 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2007, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * A socket option associated with a socket. | |
| 30 | + * | |
| 31 | + * <p> In the {@link java.nio.channels channels} package, the {@link | |
| 32 | + * java.nio.channels.NetworkChannel} interface defines the {@link | |
| 33 | + * java.nio.channels.NetworkChannel#setOption(SocketOption,Object) setOption} | |
| 34 | + * and {@link java.nio.channels.NetworkChannel#getOption(SocketOption) getOption} | |
| 35 | + * methods to set and query the channel's socket options. | |
| 36 | + * | |
| 37 | + * @param <T> The type of the socket option value. | |
| 38 | + * | |
| 39 | + * @since 1.7 | |
| 40 | + * | |
| 41 | + * @see StandardSocketOptions | |
| 42 | + */ | |
| 43 | + | |
| 44 | +public interface SocketOption<T> { | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * Returns the name of the socket option. | |
| 48 | + */ | |
| 49 | + String name(); | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * Returns the type of the socket option value. | |
| 53 | + */ | |
| 54 | + Class<T> type(); | |
| 55 | +} | |
Binary file not shown.
| @@ -0,0 +1,329 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1996, 2006, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Interface of methods to get/set socket options. This interface is | |
| 30 | + * implemented by: <B>SocketImpl</B> and <B>DatagramSocketImpl</B>. | |
| 31 | + * Subclasses of these should override the methods | |
| 32 | + * of this interface in order to support their own options. | |
| 33 | + * <P> | |
| 34 | + * The methods and constants which specify options in this interface are | |
| 35 | + * for implementation only. If you're not subclassing SocketImpl or | |
| 36 | + * DatagramSocketImpl, <B>you won't use these directly.</B> There are | |
| 37 | + * type-safe methods to get/set each of these options in Socket, ServerSocket, | |
| 38 | + * DatagramSocket and MulticastSocket. | |
| 39 | + * <P> | |
| 40 | + * @author David Brown | |
| 41 | + */ | |
| 42 | + | |
| 43 | + | |
| 44 | +public interface SocketOptions { | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * Enable/disable the option specified by <I>optID</I>. If the option | |
| 48 | + * is to be enabled, and it takes an option-specific "value", this is | |
| 49 | + * passed in <I>value</I>. The actual type of value is option-specific, | |
| 50 | + * and it is an error to pass something that isn't of the expected type: | |
| 51 | + * <BR><PRE> | |
| 52 | + * SocketImpl s; | |
| 53 | + * ... | |
| 54 | + * s.setOption(SO_LINGER, new Integer(10)); | |
| 55 | + * // OK - set SO_LINGER w/ timeout of 10 sec. | |
| 56 | + * s.setOption(SO_LINGER, new Double(10)); | |
| 57 | + * // ERROR - expects java.lang.Integer | |
| 58 | + *</PRE> | |
| 59 | + * If the requested option is binary, it can be set using this method by | |
| 60 | + * a java.lang.Boolean: | |
| 61 | + * <BR><PRE> | |
| 62 | + * s.setOption(TCP_NODELAY, new Boolean(true)); | |
| 63 | + * // OK - enables TCP_NODELAY, a binary option | |
| 64 | + * </PRE> | |
| 65 | + * <BR> | |
| 66 | + * Any option can be disabled using this method with a Boolean(false): | |
| 67 | + * <BR><PRE> | |
| 68 | + * s.setOption(TCP_NODELAY, new Boolean(false)); | |
| 69 | + * // OK - disables TCP_NODELAY | |
| 70 | + * s.setOption(SO_LINGER, new Boolean(false)); | |
| 71 | + * // OK - disables SO_LINGER | |
| 72 | + * </PRE> | |
| 73 | + * <BR> | |
| 74 | + * For an option that has a notion of on and off, and requires | |
| 75 | + * a non-boolean parameter, setting its value to anything other than | |
| 76 | + * <I>Boolean(false)</I> implicitly enables it. | |
| 77 | + * <BR> | |
| 78 | + * Throws SocketException if the option is unrecognized, | |
| 79 | + * the socket is closed, or some low-level error occurred | |
| 80 | + * <BR> | |
| 81 | + * @param optID identifies the option | |
| 82 | + * @param value the parameter of the socket option | |
| 83 | + * @throws SocketException if the option is unrecognized, | |
| 84 | + * the socket is closed, or some low-level error occurred | |
| 85 | + * @see #getOption(int) | |
| 86 | + */ | |
| 87 | + public void | |
| 88 | + setOption(int optID, Object value) throws SocketException; | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * Fetch the value of an option. | |
| 92 | + * Binary options will return java.lang.Boolean(true) | |
| 93 | + * if enabled, java.lang.Boolean(false) if disabled, e.g.: | |
| 94 | + * <BR><PRE> | |
| 95 | + * SocketImpl s; | |
| 96 | + * ... | |
| 97 | + * Boolean noDelay = (Boolean)(s.getOption(TCP_NODELAY)); | |
| 98 | + * if (noDelay.booleanValue()) { | |
| 99 | + * // true if TCP_NODELAY is enabled... | |
| 100 | + * ... | |
| 101 | + * } | |
| 102 | + * </PRE> | |
| 103 | + * <P> | |
| 104 | + * For options that take a particular type as a parameter, | |
| 105 | + * getOption(int) will return the parameter's value, else | |
| 106 | + * it will return java.lang.Boolean(false): | |
| 107 | + * <PRE> | |
| 108 | + * Object o = s.getOption(SO_LINGER); | |
| 109 | + * if (o instanceof Integer) { | |
| 110 | + * System.out.print("Linger time is " + ((Integer)o).intValue()); | |
| 111 | + * } else { | |
| 112 | + * // the true type of o is java.lang.Boolean(false); | |
| 113 | + * } | |
| 114 | + * </PRE> | |
| 115 | + * | |
| 116 | + * @param optID an <code>int</code> identifying the option to fetch | |
| 117 | + * @return the value of the option | |
| 118 | + * @throws SocketException if the socket is closed | |
| 119 | + * @throws SocketException if <I>optID</I> is unknown along the | |
| 120 | + * protocol stack (including the SocketImpl) | |
| 121 | + * @see #setOption(int, java.lang.Object) | |
| 122 | + */ | |
| 123 | + public Object getOption(int optID) throws SocketException; | |
| 124 | + | |
| 125 | + /** | |
| 126 | + * The java-supported BSD-style options. | |
| 127 | + */ | |
| 128 | + | |
| 129 | + /** | |
| 130 | + * Disable Nagle's algorithm for this connection. Written data | |
| 131 | + * to the network is not buffered pending acknowledgement of | |
| 132 | + * previously written data. | |
| 133 | + *<P> | |
| 134 | + * Valid for TCP only: SocketImpl. | |
| 135 | + * <P> | |
| 136 | + * @see Socket#setTcpNoDelay | |
| 137 | + * @see Socket#getTcpNoDelay | |
| 138 | + */ | |
| 139 | + | |
| 140 | + public final static int TCP_NODELAY = 0x0001; | |
| 141 | + | |
| 142 | + /** | |
| 143 | + * Fetch the local address binding of a socket (this option cannot | |
| 144 | + * be "set" only "gotten", since sockets are bound at creation time, | |
| 145 | + * and so the locally bound address cannot be changed). The default local | |
| 146 | + * address of a socket is INADDR_ANY, meaning any local address on a | |
| 147 | + * multi-homed host. A multi-homed host can use this option to accept | |
| 148 | + * connections to only one of its addresses (in the case of a | |
| 149 | + * ServerSocket or DatagramSocket), or to specify its return address | |
| 150 | + * to the peer (for a Socket or DatagramSocket). The parameter of | |
| 151 | + * this option is an InetAddress. | |
| 152 | + * <P> | |
| 153 | + * This option <B>must</B> be specified in the constructor. | |
| 154 | + * <P> | |
| 155 | + * Valid for: SocketImpl, DatagramSocketImpl | |
| 156 | + * <P> | |
| 157 | + * @see Socket#getLocalAddress | |
| 158 | + * @see DatagramSocket#getLocalAddress | |
| 159 | + */ | |
| 160 | + | |
| 161 | + public final static int SO_BINDADDR = 0x000F; | |
| 162 | + | |
| 163 | + /** Sets SO_REUSEADDR for a socket. This is used only for MulticastSockets | |
| 164 | + * in java, and it is set by default for MulticastSockets. | |
| 165 | + * <P> | |
| 166 | + * Valid for: DatagramSocketImpl | |
| 167 | + */ | |
| 168 | + | |
| 169 | + public final static int SO_REUSEADDR = 0x04; | |
| 170 | + | |
| 171 | + /** | |
| 172 | + * Sets SO_BROADCAST for a socket. This option enables and disables | |
| 173 | + * the ability of the process to send broadcast messages. It is supported | |
| 174 | + * for only datagram sockets and only on networks that support | |
| 175 | + * the concept of a broadcast message (e.g. Ethernet, token ring, etc.), | |
| 176 | + * and it is set by default for DatagramSockets. | |
| 177 | + * @since 1.4 | |
| 178 | + */ | |
| 179 | + | |
| 180 | + public final static int SO_BROADCAST = 0x0020; | |
| 181 | + | |
| 182 | + /** Set which outgoing interface on which to send multicast packets. | |
| 183 | + * Useful on hosts with multiple network interfaces, where applications | |
| 184 | + * want to use other than the system default. Takes/returns an InetAddress. | |
| 185 | + * <P> | |
| 186 | + * Valid for Multicast: DatagramSocketImpl | |
| 187 | + * <P> | |
| 188 | + * @see MulticastSocket#setInterface(InetAddress) | |
| 189 | + * @see MulticastSocket#getInterface() | |
| 190 | + */ | |
| 191 | + | |
| 192 | + public final static int IP_MULTICAST_IF = 0x10; | |
| 193 | + | |
| 194 | + /** Same as above. This option is introduced so that the behaviour | |
| 195 | + * with IP_MULTICAST_IF will be kept the same as before, while | |
| 196 | + * this new option can support setting outgoing interfaces with either | |
| 197 | + * IPv4 and IPv6 addresses. | |
| 198 | + * | |
| 199 | + * NOTE: make sure there is no conflict with this | |
| 200 | + * @see MulticastSocket#setNetworkInterface(NetworkInterface) | |
| 201 | + * @see MulticastSocket#getNetworkInterface() | |
| 202 | + * @since 1.4 | |
| 203 | + */ | |
| 204 | + public final static int IP_MULTICAST_IF2 = 0x1f; | |
| 205 | + | |
| 206 | + /** | |
| 207 | + * This option enables or disables local loopback of multicast datagrams. | |
| 208 | + * This option is enabled by default for Multicast Sockets. | |
| 209 | + * @since 1.4 | |
| 210 | + */ | |
| 211 | + | |
| 212 | + public final static int IP_MULTICAST_LOOP = 0x12; | |
| 213 | + | |
| 214 | + /** | |
| 215 | + * This option sets the type-of-service or traffic class field | |
| 216 | + * in the IP header for a TCP or UDP socket. | |
| 217 | + * @since 1.4 | |
| 218 | + */ | |
| 219 | + | |
| 220 | + public final static int IP_TOS = 0x3; | |
| 221 | + | |
| 222 | + /** | |
| 223 | + * Specify a linger-on-close timeout. This option disables/enables | |
| 224 | + * immediate return from a <B>close()</B> of a TCP Socket. Enabling | |
| 225 | + * this option with a non-zero Integer <I>timeout</I> means that a | |
| 226 | + * <B>close()</B> will block pending the transmission and acknowledgement | |
| 227 | + * of all data written to the peer, at which point the socket is closed | |
| 228 | + * <I>gracefully</I>. Upon reaching the linger timeout, the socket is | |
| 229 | + * closed <I>forcefully</I>, with a TCP RST. Enabling the option with a | |
| 230 | + * timeout of zero does a forceful close immediately. If the specified | |
| 231 | + * timeout value exceeds 65,535 it will be reduced to 65,535. | |
| 232 | + * <P> | |
| 233 | + * Valid only for TCP: SocketImpl | |
| 234 | + * | |
| 235 | + * @see Socket#setSoLinger | |
| 236 | + * @see Socket#getSoLinger | |
| 237 | + */ | |
| 238 | + public final static int SO_LINGER = 0x0080; | |
| 239 | + | |
| 240 | + /** Set a timeout on blocking Socket operations: | |
| 241 | + * <PRE> | |
| 242 | + * ServerSocket.accept(); | |
| 243 | + * SocketInputStream.read(); | |
| 244 | + * DatagramSocket.receive(); | |
| 245 | + * </PRE> | |
| 246 | + * | |
| 247 | + * <P> The option must be set prior to entering a blocking | |
| 248 | + * operation to take effect. If the timeout expires and the | |
| 249 | + * operation would continue to block, | |
| 250 | + * <B>java.io.InterruptedIOException</B> is raised. The Socket is | |
| 251 | + * not closed in this case. | |
| 252 | + * | |
| 253 | + * <P> Valid for all sockets: SocketImpl, DatagramSocketImpl | |
| 254 | + * | |
| 255 | + * @see Socket#setSoTimeout | |
| 256 | + * @see ServerSocket#setSoTimeout | |
| 257 | + * @see DatagramSocket#setSoTimeout | |
| 258 | + */ | |
| 259 | + public final static int SO_TIMEOUT = 0x1006; | |
| 260 | + | |
| 261 | + /** | |
| 262 | + * Set a hint the size of the underlying buffers used by the | |
| 263 | + * platform for outgoing network I/O. When used in set, this is a | |
| 264 | + * suggestion to the kernel from the application about the size of | |
| 265 | + * buffers to use for the data to be sent over the socket. When | |
| 266 | + * used in get, this must return the size of the buffer actually | |
| 267 | + * used by the platform when sending out data on this socket. | |
| 268 | + * | |
| 269 | + * Valid for all sockets: SocketImpl, DatagramSocketImpl | |
| 270 | + * | |
| 271 | + * @see Socket#setSendBufferSize | |
| 272 | + * @see Socket#getSendBufferSize | |
| 273 | + * @see DatagramSocket#setSendBufferSize | |
| 274 | + * @see DatagramSocket#getSendBufferSize | |
| 275 | + */ | |
| 276 | + public final static int SO_SNDBUF = 0x1001; | |
| 277 | + | |
| 278 | + /** | |
| 279 | + * Set a hint the size of the underlying buffers used by the | |
| 280 | + * platform for incoming network I/O. When used in set, this is a | |
| 281 | + * suggestion to the kernel from the application about the size of | |
| 282 | + * buffers to use for the data to be received over the | |
| 283 | + * socket. When used in get, this must return the size of the | |
| 284 | + * buffer actually used by the platform when receiving in data on | |
| 285 | + * this socket. | |
| 286 | + * | |
| 287 | + * Valid for all sockets: SocketImpl, DatagramSocketImpl | |
| 288 | + * | |
| 289 | + * @see Socket#setReceiveBufferSize | |
| 290 | + * @see Socket#getReceiveBufferSize | |
| 291 | + * @see DatagramSocket#setReceiveBufferSize | |
| 292 | + * @see DatagramSocket#getReceiveBufferSize | |
| 293 | + */ | |
| 294 | + public final static int SO_RCVBUF = 0x1002; | |
| 295 | + | |
| 296 | + /** | |
| 297 | + * When the keepalive option is set for a TCP socket and no data | |
| 298 | + * has been exchanged across the socket in either direction for | |
| 299 | + * 2 hours (NOTE: the actual value is implementation dependent), | |
| 300 | + * TCP automatically sends a keepalive probe to the peer. This probe is a | |
| 301 | + * TCP segment to which the peer must respond. | |
| 302 | + * One of three responses is expected: | |
| 303 | + * 1. The peer responds with the expected ACK. The application is not | |
| 304 | + * notified (since everything is OK). TCP will send another probe | |
| 305 | + * following another 2 hours of inactivity. | |
| 306 | + * 2. The peer responds with an RST, which tells the local TCP that | |
| 307 | + * the peer host has crashed and rebooted. The socket is closed. | |
| 308 | + * 3. There is no response from the peer. The socket is closed. | |
| 309 | + * | |
| 310 | + * The purpose of this option is to detect if the peer host crashes. | |
| 311 | + * | |
| 312 | + * Valid only for TCP socket: SocketImpl | |
| 313 | + * | |
| 314 | + * @see Socket#setKeepAlive | |
| 315 | + * @see Socket#getKeepAlive | |
| 316 | + */ | |
| 317 | + public final static int SO_KEEPALIVE = 0x0008; | |
| 318 | + | |
| 319 | + /** | |
| 320 | + * When the OOBINLINE option is set, any TCP urgent data received on | |
| 321 | + * the socket will be received through the socket input stream. | |
| 322 | + * When the option is disabled (which is the default) urgent data | |
| 323 | + * is silently discarded. | |
| 324 | + * | |
| 325 | + * @see Socket#setOOBInline | |
| 326 | + * @see Socket#getOOBInline | |
| 327 | + */ | |
| 328 | + public final static int SO_OOBINLINE = 0x1003; | |
| 329 | +} | |
Binary file not shown.
| @@ -0,0 +1,183 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1995, 2007, 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 java.net; | |
| 27 | + | |
| 28 | +import java.io.FileDescriptor; | |
| 29 | +import java.io.FileOutputStream; | |
| 30 | +import java.io.IOException; | |
| 31 | +import java.nio.channels.FileChannel; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * This stream extends FileOutputStream to implement a | |
| 35 | + * SocketOutputStream. Note that this class should <b>NOT</b> be | |
| 36 | + * public. | |
| 37 | + * | |
| 38 | + * @author Jonathan Payne | |
| 39 | + * @author Arthur van Hoff | |
| 40 | + */ | |
| 41 | +class SocketOutputStream extends FileOutputStream | |
| 42 | +{ | |
| 43 | + static { | |
| 44 | + init(); | |
| 45 | + } | |
| 46 | + | |
| 47 | + private AbstractPlainSocketImpl impl = null; | |
| 48 | + private byte temp[] = new byte[1]; | |
| 49 | + private Socket socket = null; | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * Creates a new SocketOutputStream. Can only be called | |
| 53 | + * by a Socket. This method needs to hang on to the owner Socket so | |
| 54 | + * that the fd will not be closed. | |
| 55 | + * @param impl the socket output stream inplemented | |
| 56 | + */ | |
| 57 | + SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException { | |
| 58 | + super(impl.getFileDescriptor()); | |
| 59 | + this.impl = impl; | |
| 60 | + socket = impl.getSocket(); | |
| 61 | + } | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * Returns the unique {@link java.nio.channels.FileChannel FileChannel} | |
| 65 | + * object associated with this file output stream. </p> | |
| 66 | + * | |
| 67 | + * The <code>getChannel</code> method of <code>SocketOutputStream</code> | |
| 68 | + * returns <code>null</code> since it is a socket based stream.</p> | |
| 69 | + * | |
| 70 | + * @return the file channel associated with this file output stream | |
| 71 | + * | |
| 72 | + * @since 1.4 | |
| 73 | + * @spec JSR-51 | |
| 74 | + */ | |
| 75 | + public final FileChannel getChannel() { | |
| 76 | + return null; | |
| 77 | + } | |
| 78 | + | |
| 79 | + /** | |
| 80 | + * Writes to the socket. | |
| 81 | + * @param fd the FileDescriptor | |
| 82 | + * @param b the data to be written | |
| 83 | + * @param off the start offset in the data | |
| 84 | + * @param len the number of bytes that are written | |
| 85 | + * @exception IOException If an I/O error has occurred. | |
| 86 | + */ | |
| 87 | + private native void socketWrite0(FileDescriptor fd, byte[] b, int off, | |
| 88 | + int len) throws IOException; | |
| 89 | + | |
| 90 | + /** | |
| 91 | + * Writes to the socket with appropriate locking of the | |
| 92 | + * FileDescriptor. | |
| 93 | + * @param b the data to be written | |
| 94 | + * @param off the start offset in the data | |
| 95 | + * @param len the number of bytes that are written | |
| 96 | + * @exception IOException If an I/O error has occurred. | |
| 97 | + */ | |
| 98 | + private void socketWrite(byte b[], int off, int len) throws IOException { | |
| 99 | + | |
| 100 | + if (len <= 0 || off < 0 || off + len > b.length) { | |
| 101 | + if (len == 0) { | |
| 102 | + return; | |
| 103 | + } | |
| 104 | + throw new ArrayIndexOutOfBoundsException(); | |
| 105 | + } | |
| 106 | + | |
| 107 | + FileDescriptor fd = impl.acquireFD(); | |
| 108 | + try { | |
| 109 | + socketWrite0(fd, b, off, len); | |
| 110 | + } catch (SocketException se) { | |
| 111 | + if (se instanceof sun.net.ConnectionResetException) { | |
| 112 | + impl.setConnectionResetPending(); | |
| 113 | + se = new SocketException("Connection reset"); | |
| 114 | + } | |
| 115 | + if (impl.isClosedOrPending()) { | |
| 116 | + throw new SocketException("Socket closed"); | |
| 117 | + } else { | |
| 118 | + throw se; | |
| 119 | + } | |
| 120 | + } finally { | |
| 121 | + impl.releaseFD(); | |
| 122 | + } | |
| 123 | + } | |
| 124 | + | |
| 125 | + /** | |
| 126 | + * Writes a byte to the socket. | |
| 127 | + * @param b the data to be written | |
| 128 | + * @exception IOException If an I/O error has occurred. | |
| 129 | + */ | |
| 130 | + public void write(int b) throws IOException { | |
| 131 | + temp[0] = (byte)b; | |
| 132 | + socketWrite(temp, 0, 1); | |
| 133 | + } | |
| 134 | + | |
| 135 | + /** | |
| 136 | + * Writes the contents of the buffer <i>b</i> to the socket. | |
| 137 | + * @param b the data to be written | |
| 138 | + * @exception SocketException If an I/O error has occurred. | |
| 139 | + */ | |
| 140 | + public void write(byte b[]) throws IOException { | |
| 141 | + socketWrite(b, 0, b.length); | |
| 142 | + } | |
| 143 | + | |
| 144 | + /** | |
| 145 | + * Writes <i>length</i> bytes from buffer <i>b</i> starting at | |
| 146 | + * offset <i>len</i>. | |
| 147 | + * @param b the data to be written | |
| 148 | + * @param off the start offset in the data | |
| 149 | + * @param len the number of bytes that are written | |
| 150 | + * @exception SocketException If an I/O error has occurred. | |
| 151 | + */ | |
| 152 | + public void write(byte b[], int off, int len) throws IOException { | |
| 153 | + socketWrite(b, off, len); | |
| 154 | + } | |
| 155 | + | |
| 156 | + /** | |
| 157 | + * Closes the stream. | |
| 158 | + */ | |
| 159 | + private boolean closing = false; | |
| 160 | + public void close() throws IOException { | |
| 161 | + // Prevent recursion. See BugId 4484411 | |
| 162 | + if (closing) | |
| 163 | + return; | |
| 164 | + closing = true; | |
| 165 | + if (socket != null) { | |
| 166 | + if (!socket.isClosed()) | |
| 167 | + socket.close(); | |
| 168 | + } else | |
| 169 | + impl.close(); | |
| 170 | + closing = false; | |
| 171 | + } | |
| 172 | + | |
| 173 | + /** | |
| 174 | + * Overrides finalize, the fd is closed by the Socket. | |
| 175 | + */ | |
| 176 | + protected void finalize() {} | |
| 177 | + | |
| 178 | + /** | |
| 179 | + * Perform class load-time initializations. | |
| 180 | + */ | |
| 181 | + private native static void init(); | |
| 182 | + | |
| 183 | +} | |
Binary file not shown.
| @@ -0,0 +1,1376 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 1997, 2006, 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 java.net; | |
| 27 | + | |
| 28 | +import java.util.Enumeration; | |
| 29 | +import java.util.Vector; | |
| 30 | +import java.util.List; | |
| 31 | +import java.util.ArrayList; | |
| 32 | +import java.util.Collections; | |
| 33 | +import java.util.StringTokenizer; | |
| 34 | +import java.net.InetAddress; | |
| 35 | +import java.security.Permission; | |
| 36 | +import java.security.PermissionCollection; | |
| 37 | +import java.io.Serializable; | |
| 38 | +import java.io.ObjectStreamField; | |
| 39 | +import java.io.ObjectOutputStream; | |
| 40 | +import java.io.ObjectInputStream; | |
| 41 | +import java.io.IOException; | |
| 42 | +import sun.net.util.IPAddressUtil; | |
| 43 | +import sun.net.RegisteredDomain; | |
| 44 | +import sun.security.util.SecurityConstants; | |
| 45 | +import sun.security.util.Debug; | |
| 46 | + | |
| 47 | + | |
| 48 | +/** | |
| 49 | + * This class represents access to a network via sockets. | |
| 50 | + * A SocketPermission consists of a | |
| 51 | + * host specification and a set of "actions" specifying ways to | |
| 52 | + * connect to that host. The host is specified as | |
| 53 | + * <pre> | |
| 54 | + * host = (hostname | IPv4address | iPv6reference) [:portrange] | |
| 55 | + * portrange = portnumber | -portnumber | portnumber-[portnumber] | |
| 56 | + * </pre> | |
| 57 | + * The host is expressed as a DNS name, as a numerical IP address, | |
| 58 | + * or as "localhost" (for the local machine). | |
| 59 | + * The wildcard "*" may be included once in a DNS name host | |
| 60 | + * specification. If it is included, it must be in the leftmost | |
| 61 | + * position, as in "*.sun.com". | |
| 62 | + * <p> | |
| 63 | + * The format of the IPv6reference should follow that specified in <a | |
| 64 | + * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC 2732: Format | |
| 65 | + * for Literal IPv6 Addresses in URLs</i></a>: | |
| 66 | + * <pre> | |
| 67 | + * ipv6reference = "[" IPv6address "]" | |
| 68 | + *</pre> | |
| 69 | + * For example, you can construct a SocketPermission instance | |
| 70 | + * as the following: | |
| 71 | + * <pre> | |
| 72 | + * String hostAddress = inetaddress.getHostAddress(); | |
| 73 | + * if (inetaddress instanceof Inet6Address) { | |
| 74 | + * sp = new SocketPermission("[" + hostAddress + "]:" + port, action); | |
| 75 | + * } else { | |
| 76 | + * sp = new SocketPermission(hostAddress + ":" + port, action); | |
| 77 | + * } | |
| 78 | + * </pre> | |
| 79 | + * or | |
| 80 | + * <pre> | |
| 81 | + * String host = url.getHost(); | |
| 82 | + * sp = new SocketPermission(host + ":" + port, action); | |
| 83 | + * </pre> | |
| 84 | + * <p> | |
| 85 | + * The <A HREF="Inet6Address.html#lform">full uncompressed form</A> of | |
| 86 | + * an IPv6 literal address is also valid. | |
| 87 | + * <p> | |
| 88 | + * The port or portrange is optional. A port specification of the | |
| 89 | + * form "N-", where <i>N</i> is a port number, signifies all ports | |
| 90 | + * numbered <i>N</i> and above, while a specification of the | |
| 91 | + * form "-N" indicates all ports numbered <i>N</i> and below. | |
| 92 | + * <p> | |
| 93 | + * The possible ways to connect to the host are | |
| 94 | + * <pre> | |
| 95 | + * accept | |
| 96 | + * connect | |
| 97 | + * listen | |
| 98 | + * resolve | |
| 99 | + * </pre> | |
| 100 | + * The "listen" action is only meaningful when used with "localhost". | |
| 101 | + * The "resolve" action is implied when any of the other actions are present. | |
| 102 | + * The action "resolve" refers to host/ip name service lookups. | |
| 103 | + * <P> | |
| 104 | + * The actions string is converted to lowercase before processing. | |
| 105 | + * <p>As an example of the creation and meaning of SocketPermissions, | |
| 106 | + * note that if the following permission: | |
| 107 | + * | |
| 108 | + * <pre> | |
| 109 | + * p1 = new SocketPermission("puffin.eng.sun.com:7777", "connect,accept"); | |
| 110 | + * </pre> | |
| 111 | + * | |
| 112 | + * is granted to some code, it allows that code to connect to port 7777 on | |
| 113 | + * <code>puffin.eng.sun.com</code>, and to accept connections on that port. | |
| 114 | + * | |
| 115 | + * <p>Similarly, if the following permission: | |
| 116 | + * | |
| 117 | + * <pre> | |
| 118 | + * p2 = new SocketPermission("localhost:1024-", "accept,connect,listen"); | |
| 119 | + * </pre> | |
| 120 | + * | |
| 121 | + * is granted to some code, it allows that code to | |
| 122 | + * accept connections on, connect to, or listen on any port between | |
| 123 | + * 1024 and 65535 on the local host. | |
| 124 | + * | |
| 125 | + * <p>Note: Granting code permission to accept or make connections to remote | |
| 126 | + * hosts may be dangerous because malevolent code can then more easily | |
| 127 | + * transfer and share confidential data among parties who may not | |
| 128 | + * otherwise have access to the data. | |
| 129 | + * | |
| 130 | + * @see java.security.Permissions | |
| 131 | + * @see SocketPermission | |
| 132 | + * | |
| 133 | + * | |
| 134 | + * @author Marianne Mueller | |
| 135 | + * @author Roland Schemers | |
| 136 | + * | |
| 137 | + * @serial exclude | |
| 138 | + */ | |
| 139 | + | |
| 140 | +public final class SocketPermission extends Permission | |
| 141 | +implements java.io.Serializable | |
| 142 | +{ | |
| 143 | + private static final long serialVersionUID = -7204263841984476862L; | |
| 144 | + | |
| 145 | + /** | |
| 146 | + * Connect to host:port | |
| 147 | + */ | |
| 148 | + private final static int CONNECT = 0x1; | |
| 149 | + | |
| 150 | + /** | |
| 151 | + * Listen on host:port | |
| 152 | + */ | |
| 153 | + private final static int LISTEN = 0x2; | |
| 154 | + | |
| 155 | + /** | |
| 156 | + * Accept a connection from host:port | |
| 157 | + */ | |
| 158 | + private final static int ACCEPT = 0x4; | |
| 159 | + | |
| 160 | + /** | |
| 161 | + * Resolve DNS queries | |
| 162 | + */ | |
| 163 | + private final static int RESOLVE = 0x8; | |
| 164 | + | |
| 165 | + /** | |
| 166 | + * No actions | |
| 167 | + */ | |
| 168 | + private final static int NONE = 0x0; | |
| 169 | + | |
| 170 | + /** | |
| 171 | + * All actions | |
| 172 | + */ | |
| 173 | + private final static int ALL = CONNECT|LISTEN|ACCEPT|RESOLVE; | |
| 174 | + | |
| 175 | + // various port constants | |
| 176 | + private static final int PORT_MIN = 0; | |
| 177 | + private static final int PORT_MAX = 65535; | |
| 178 | + private static final int PRIV_PORT_MAX = 1023; | |
| 179 | + | |
| 180 | + // the actions mask | |
| 181 | + private transient int mask; | |
| 182 | + | |
| 183 | + /** | |
| 184 | + * the actions string. | |
| 185 | + * | |
| 186 | + * @serial | |
| 187 | + */ | |
| 188 | + | |
| 189 | + private String actions; // Left null as long as possible, then | |
| 190 | + // created and re-used in the getAction function. | |
| 191 | + | |
| 192 | + // hostname part as it is passed | |
| 193 | + private transient String hostname; | |
| 194 | + | |
| 195 | + // the canonical name of the host | |
| 196 | + // in the case of "*.foo.com", cname is ".foo.com". | |
| 197 | + | |
| 198 | + private transient String cname; | |
| 199 | + | |
| 200 | + // all the IP addresses of the host | |
| 201 | + private transient InetAddress[] addresses; | |
| 202 | + | |
| 203 | + // true if the hostname is a wildcard (e.g. "*.sun.com") | |
| 204 | + private transient boolean wildcard; | |
| 205 | + | |
| 206 | + // true if we were initialized with a single numeric IP address | |
| 207 | + private transient boolean init_with_ip; | |
| 208 | + | |
| 209 | + // true if this SocketPermission represents an invalid/unknown host | |
| 210 | + // used for implies when the delayed lookup has already failed | |
| 211 | + private transient boolean invalid; | |
| 212 | + | |
| 213 | + // port range on host | |
| 214 | + private transient int[] portrange; | |
| 215 | + | |
| 216 | + private transient boolean defaultDeny = false; | |
| 217 | + | |
| 218 | + // true if this SocketPermission represents a hostname | |
| 219 | + // that failed our reverse mapping heuristic test | |
| 220 | + private transient boolean untrusted; | |
| 221 | + private transient boolean trusted; | |
| 222 | + | |
| 223 | + // true if the sun.net.trustNameService system property is set | |
| 224 | + private static boolean trustNameService; | |
| 225 | + | |
| 226 | + private static Debug debug = null; | |
| 227 | + private static boolean debugInit = false; | |
| 228 | + | |
| 229 | + static { | |
| 230 | + Boolean tmp = java.security.AccessController.doPrivileged( | |
| 231 | + new sun.security.action.GetBooleanAction("sun.net.trustNameService")); | |
| 232 | + trustNameService = tmp.booleanValue(); | |
| 233 | + } | |
| 234 | + | |
| 235 | + private static synchronized Debug getDebug() | |
| 236 | + { | |
| 237 | + if (!debugInit) { | |
| 238 | + debug = Debug.getInstance("access"); | |
| 239 | + debugInit = true; | |
| 240 | + } | |
| 241 | + return debug; | |
| 242 | + } | |
| 243 | + | |
| 244 | + /** | |
| 245 | + * Creates a new SocketPermission object with the specified actions. | |
| 246 | + * The host is expressed as a DNS name, or as a numerical IP address. | |
| 247 | + * Optionally, a port or a portrange may be supplied (separated | |
| 248 | + * from the DNS name or IP address by a colon). | |
| 249 | + * <p> | |
| 250 | + * To specify the local machine, use "localhost" as the <i>host</i>. | |
| 251 | + * Also note: An empty <i>host</i> String ("") is equivalent to "localhost". | |
| 252 | + * <p> | |
| 253 | + * The <i>actions</i> parameter contains a comma-separated list of the | |
| 254 | + * actions granted for the specified host (and port(s)). Possible actions are | |
| 255 | + * "connect", "listen", "accept", "resolve", or | |
| 256 | + * any combination of those. "resolve" is automatically added | |
| 257 | + * when any of the other three are specified. | |
| 258 | + * <p> | |
| 259 | + * Examples of SocketPermission instantiation are the following: | |
| 260 | + * <pre> | |
| 261 | + * nr = new SocketPermission("www.catalog.com", "connect"); | |
| 262 | + * nr = new SocketPermission("www.sun.com:80", "connect"); | |
| 263 | + * nr = new SocketPermission("*.sun.com", "connect"); | |
| 264 | + * nr = new SocketPermission("*.edu", "resolve"); | |
| 265 | + * nr = new SocketPermission("204.160.241.0", "connect"); | |
| 266 | + * nr = new SocketPermission("localhost:1024-65535", "listen"); | |
| 267 | + * nr = new SocketPermission("204.160.241.0:1024-65535", "connect"); | |
| 268 | + * </pre> | |
| 269 | + * | |
| 270 | + * @param host the hostname or IPaddress of the computer, optionally | |
| 271 | + * including a colon followed by a port or port range. | |
| 272 | + * @param action the action string. | |
| 273 | + */ | |
| 274 | + public SocketPermission(String host, String action) { | |
| 275 | + super(getHost(host)); | |
| 276 | + // name initialized to getHost(host); NPE detected in getHost() | |
| 277 | + init(getName(), getMask(action)); | |
| 278 | + } | |
| 279 | + | |
| 280 | + | |
| 281 | + SocketPermission(String host, int mask) { | |
| 282 | + super(getHost(host)); | |
| 283 | + // name initialized to getHost(host); NPE detected in getHost() | |
| 284 | + init(getName(), mask); | |
| 285 | + } | |
| 286 | + | |
| 287 | + private void setDeny() { | |
| 288 | + defaultDeny = true; | |
| 289 | + } | |
| 290 | + | |
| 291 | + private static String getHost(String host) | |
| 292 | + { | |
| 293 | + if (host.equals("")) { | |
| 294 | + return "localhost"; | |
| 295 | + } else { | |
| 296 | + /* IPv6 literal address used in this context should follow | |
| 297 | + * the format specified in RFC 2732; | |
| 298 | + * if not, we try to solve the unambiguous case | |
| 299 | + */ | |
| 300 | + int ind; | |
| 301 | + if (host.charAt(0) != '[') { | |
| 302 | + if ((ind = host.indexOf(':')) != host.lastIndexOf(':')) { | |
| 303 | + /* More than one ":", meaning IPv6 address is not | |
| 304 | + * in RFC 2732 format; | |
| 305 | + * We will rectify user errors for all unambiguious cases | |
| 306 | + */ | |
| 307 | + StringTokenizer st = new StringTokenizer(host, ":"); | |
| 308 | + int tokens = st.countTokens(); | |
| 309 | + if (tokens == 9) { | |
| 310 | + // IPv6 address followed by port | |
| 311 | + ind = host.lastIndexOf(':'); | |
| 312 | + host = "[" + host.substring(0, ind) + "]" + | |
| 313 | + host.substring(ind); | |
| 314 | + } else if (tokens == 8 && host.indexOf("::") == -1) { | |
| 315 | + // IPv6 address only, not followed by port | |
| 316 | + host = "[" + host + "]"; | |
| 317 | + } else { | |
| 318 | + // could be ambiguous | |
| 319 | + throw new IllegalArgumentException("Ambiguous"+ | |
| 320 | + " hostport part"); | |
| 321 | + } | |
| 322 | + } | |
| 323 | + } | |
| 324 | + return host; | |
| 325 | + } | |
| 326 | + } | |
| 327 | + | |
| 328 | + private int[] parsePort(String port) | |
| 329 | + throws Exception | |
| 330 | + { | |
| 331 | + | |
| 332 | + if (port == null || port.equals("") || port.equals("*")) { | |
| 333 | + return new int[] {PORT_MIN, PORT_MAX}; | |
| 334 | + } | |
| 335 | + | |
| 336 | + int dash = port.indexOf('-'); | |
| 337 | + | |
| 338 | + if (dash == -1) { | |
| 339 | + int p = Integer.parseInt(port); | |
| 340 | + return new int[] {p, p}; | |
| 341 | + } else { | |
| 342 | + String low = port.substring(0, dash); | |
| 343 | + String high = port.substring(dash+1); | |
| 344 | + int l,h; | |
| 345 | + | |
| 346 | + if (low.equals("")) { | |
| 347 | + l = PORT_MIN; | |
| 348 | + } else { | |
| 349 | + l = Integer.parseInt(low); | |
| 350 | + } | |
| 351 | + | |
| 352 | + if (high.equals("")) { | |
| 353 | + h = PORT_MAX; | |
| 354 | + } else { | |
| 355 | + h = Integer.parseInt(high); | |
| 356 | + } | |
| 357 | + if (l < 0 || h < 0 || h<l) | |
| 358 | + throw new IllegalArgumentException("invalid port range"); | |
| 359 | + | |
| 360 | + return new int[] {l, h}; | |
| 361 | + } | |
| 362 | + } | |
| 363 | + | |
| 364 | + /** | |
| 365 | + * Initialize the SocketPermission object. We don't do any DNS lookups | |
| 366 | + * as this point, instead we hold off until the implies method is | |
| 367 | + * called. | |
| 368 | + */ | |
| 369 | + private void init(String host, int mask) { | |
| 370 | + // Set the integer mask that represents the actions | |
| 371 | + | |
| 372 | + if ((mask & ALL) != mask) | |
| 373 | + throw new IllegalArgumentException("invalid actions mask"); | |
| 374 | + | |
| 375 | + // always OR in RESOLVE if we allow any of the others | |
| 376 | + this.mask = mask | RESOLVE; | |
| 377 | + | |
| 378 | + // Parse the host name. A name has up to three components, the | |
| 379 | + // hostname, a port number, or two numbers representing a port | |
| 380 | + // range. "www.sun.com:8080-9090" is a valid host name. | |
| 381 | + | |
| 382 | + // With IPv6 an address can be 2010:836B:4179::836B:4179 | |
| 383 | + // An IPv6 address needs to be enclose in [] | |
| 384 | + // For ex: [2010:836B:4179::836B:4179]:8080-9090 | |
| 385 | + // Refer to RFC 2732 for more information. | |
| 386 | + | |
| 387 | + int rb = 0 ; | |
| 388 | + int start = 0, end = 0; | |
| 389 | + int sep = -1; | |
| 390 | + String hostport = host; | |
| 391 | + if (host.charAt(0) == '[') { | |
| 392 | + start = 1; | |
| 393 | + rb = host.indexOf(']'); | |
| 394 | + if (rb != -1) { | |
| 395 | + host = host.substring(start, rb); | |
| 396 | + } else { | |
| 397 | + throw new | |
| 398 | + IllegalArgumentException("invalid host/port: "+host); | |
| 399 | + } | |
| 400 | + sep = hostport.indexOf(':', rb+1); | |
| 401 | + } else { | |
| 402 | + start = 0; | |
| 403 | + sep = host.indexOf(':', rb); | |
| 404 | + end = sep; | |
| 405 | + if (sep != -1) { | |
| 406 | + host = host.substring(start, end); | |
| 407 | + } | |
| 408 | + } | |
| 409 | + | |
| 410 | + if (sep != -1) { | |
| 411 | + String port = hostport.substring(sep+1); | |
| 412 | + try { | |
| 413 | + portrange = parsePort(port); | |
| 414 | + } catch (Exception e) { | |
| 415 | + throw new | |
| 416 | + IllegalArgumentException("invalid port range: "+port); | |
| 417 | + } | |
| 418 | + } else { | |
| 419 | + portrange = new int[] { PORT_MIN, PORT_MAX }; | |
| 420 | + } | |
| 421 | + | |
| 422 | + hostname = host; | |
| 423 | + | |
| 424 | + // is this a domain wildcard specification | |
| 425 | + if (host.lastIndexOf('*') > 0) { | |
| 426 | + throw new | |
| 427 | + IllegalArgumentException("invalid host wildcard specification"); | |
| 428 | + } else if (host.startsWith("*")) { | |
| 429 | + wildcard = true; | |
| 430 | + if (host.equals("*")) { | |
| 431 | + cname = ""; | |
| 432 | + } else if (host.startsWith("*.")) { | |
| 433 | + cname = host.substring(1).toLowerCase(); | |
| 434 | + } else { | |
| 435 | + throw new | |
| 436 | + IllegalArgumentException("invalid host wildcard specification"); | |
| 437 | + } | |
| 438 | + return; | |
| 439 | + } else { | |
| 440 | + if (host.length() > 0) { | |
| 441 | + // see if we are being initialized with an IP address. | |
| 442 | + char ch = host.charAt(0); | |
| 443 | + if (ch == ':' || Character.digit(ch, 16) != -1) { | |
| 444 | + byte ip[] = IPAddressUtil.textToNumericFormatV4(host); | |
| 445 | + if (ip == null) { | |
| 446 | + ip = IPAddressUtil.textToNumericFormatV6(host); | |
| 447 | + } | |
| 448 | + if (ip != null) { | |
| 449 | + try { | |
| 450 | + addresses = | |
| 451 | + new InetAddress[] | |
| 452 | + {InetAddress.getByAddress(ip) }; | |
| 453 | + init_with_ip = true; | |
| 454 | + } catch (UnknownHostException uhe) { | |
| 455 | + // this shouldn't happen | |
| 456 | + invalid = true; | |
| 457 | + } | |
| 458 | + } | |
| 459 | + } | |
| 460 | + } | |
| 461 | + } | |
| 462 | + } | |
| 463 | + | |
| 464 | + /** | |
| 465 | + * Convert an action string to an integer actions mask. | |
| 466 | + * | |
| 467 | + * @param action the action string | |
| 468 | + * @return the action mask | |
| 469 | + */ | |
| 470 | + private static int getMask(String action) { | |
| 471 | + | |
| 472 | + if (action == null) { | |
| 473 | + throw new NullPointerException("action can't be null"); | |
| 474 | + } | |
| 475 | + | |
| 476 | + if (action.equals("")) { | |
| 477 | + throw new IllegalArgumentException("action can't be empty"); | |
| 478 | + } | |
| 479 | + | |
| 480 | + int mask = NONE; | |
| 481 | + | |
| 482 | + // Check against use of constants (used heavily within the JDK) | |
| 483 | + if (action == SecurityConstants.SOCKET_RESOLVE_ACTION) { | |
| 484 | + return RESOLVE; | |
| 485 | + } else if (action == SecurityConstants.SOCKET_CONNECT_ACTION) { | |
| 486 | + return CONNECT; | |
| 487 | + } else if (action == SecurityConstants.SOCKET_LISTEN_ACTION) { | |
| 488 | + return LISTEN; | |
| 489 | + } else if (action == SecurityConstants.SOCKET_ACCEPT_ACTION) { | |
| 490 | + return ACCEPT; | |
| 491 | + } else if (action == SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION) { | |
| 492 | + return CONNECT|ACCEPT; | |
| 493 | + } | |
| 494 | + | |
| 495 | + char[] a = action.toCharArray(); | |
| 496 | + | |
| 497 | + int i = a.length - 1; | |
| 498 | + if (i < 0) | |
| 499 | + return mask; | |
| 500 | + | |
| 501 | + while (i != -1) { | |
| 502 | + char c; | |
| 503 | + | |
| 504 | + // skip whitespace | |
| 505 | + while ((i!=-1) && ((c = a[i]) == ' ' || | |
| 506 | + c == '\r' || | |
| 507 | + c == '\n' || | |
| 508 | + c == '\f' || | |
| 509 | + c == '\t')) | |
| 510 | + i--; | |
| 511 | + | |
| 512 | + // check for the known strings | |
| 513 | + int matchlen; | |
| 514 | + | |
| 515 | + if (i >= 6 && (a[i-6] == 'c' || a[i-6] == 'C') && | |
| 516 | + (a[i-5] == 'o' || a[i-5] == 'O') && | |
| 517 | + (a[i-4] == 'n' || a[i-4] == 'N') && | |
| 518 | + (a[i-3] == 'n' || a[i-3] == 'N') && | |
| 519 | + (a[i-2] == 'e' || a[i-2] == 'E') && | |
| 520 | + (a[i-1] == 'c' || a[i-1] == 'C') && | |
| 521 | + (a[i] == 't' || a[i] == 'T')) | |
| 522 | + { | |
| 523 | + matchlen = 7; | |
| 524 | + mask |= CONNECT; | |
| 525 | + | |
| 526 | + } else if (i >= 6 && (a[i-6] == 'r' || a[i-6] == 'R') && | |
| 527 | + (a[i-5] == 'e' || a[i-5] == 'E') && | |
| 528 | + (a[i-4] == 's' || a[i-4] == 'S') && | |
| 529 | + (a[i-3] == 'o' || a[i-3] == 'O') && | |
| 530 | + (a[i-2] == 'l' || a[i-2] == 'L') && | |
| 531 | + (a[i-1] == 'v' || a[i-1] == 'V') && | |
| 532 | + (a[i] == 'e' || a[i] == 'E')) | |
| 533 | + { | |
| 534 | + matchlen = 7; | |
| 535 | + mask |= RESOLVE; | |
| 536 | + | |
| 537 | + } else if (i >= 5 && (a[i-5] == 'l' || a[i-5] == 'L') && | |
| 538 | + (a[i-4] == 'i' || a[i-4] == 'I') && | |
| 539 | + (a[i-3] == 's' || a[i-3] == 'S') && | |
| 540 | + (a[i-2] == 't' || a[i-2] == 'T') && | |
| 541 | + (a[i-1] == 'e' || a[i-1] == 'E') && | |
| 542 | + (a[i] == 'n' || a[i] == 'N')) | |
| 543 | + { | |
| 544 | + matchlen = 6; | |
| 545 | + mask |= LISTEN; | |
| 546 | + | |
| 547 | + } else if (i >= 5 && (a[i-5] == 'a' || a[i-5] == 'A') && | |
| 548 | + (a[i-4] == 'c' || a[i-4] == 'C') && | |
| 549 | + (a[i-3] == 'c' || a[i-3] == 'C') && | |
| 550 | + (a[i-2] == 'e' || a[i-2] == 'E') && | |
| 551 | + (a[i-1] == 'p' || a[i-1] == 'P') && | |
| 552 | + (a[i] == 't' || a[i] == 'T')) | |
| 553 | + { | |
| 554 | + matchlen = 6; | |
| 555 | + mask |= ACCEPT; | |
| 556 | + | |
| 557 | + } else { | |
| 558 | + // parse error | |
| 559 | + throw new IllegalArgumentException( | |
| 560 | + "invalid permission: " + action); | |
| 561 | + } | |
| 562 | + | |
| 563 | + // make sure we didn't just match the tail of a word | |
| 564 | + // like "ackbarfaccept". Also, skip to the comma. | |
| 565 | + boolean seencomma = false; | |
| 566 | + while (i >= matchlen && !seencomma) { | |
| 567 | + switch(a[i-matchlen]) { | |
| 568 | + case ',': | |
| 569 | + seencomma = true; | |
| 570 | + /*FALLTHROUGH*/ | |
| 571 | + case ' ': case '\r': case '\n': | |
| 572 | + case '\f': case '\t': | |
| 573 | + break; | |
| 574 | + default: | |
| 575 | + throw new IllegalArgumentException( | |
| 576 | + "invalid permission: " + action); | |
| 577 | + } | |
| 578 | + i--; | |
| 579 | + } | |
| 580 | + | |
| 581 | + // point i at the location of the comma minus one (or -1). | |
| 582 | + i -= matchlen; | |
| 583 | + } | |
| 584 | + | |
| 585 | + return mask; | |
| 586 | + } | |
| 587 | + | |
| 588 | + private boolean isUntrusted() | |
| 589 | + throws UnknownHostException | |
| 590 | + { | |
| 591 | + if (trusted) return false; | |
| 592 | + if (invalid || untrusted) return true; | |
| 593 | + try { | |
| 594 | + if (!trustNameService && (defaultDeny || | |
| 595 | + sun.net.www.URLConnection.isProxiedHost(hostname))) { | |
| 596 | + if (this.cname == null) { | |
| 597 | + this.getCanonName(); | |
| 598 | + } | |
| 599 | + if (!match(cname, hostname)) { | |
| 600 | + // Last chance | |
| 601 | + if (!authorized(hostname, addresses[0].getAddress())) { | |
| 602 | + untrusted = true; | |
| 603 | + Debug debug = getDebug(); | |
| 604 | + if (debug != null && Debug.isOn("failure")) { | |
| 605 | + debug.println("socket access restriction: proxied host " + "(" + addresses[0] + ")" + " does not match " + cname + " from reverse lookup"); | |
| 606 | + } | |
| 607 | + return true; | |
| 608 | + } | |
| 609 | + } | |
| 610 | + trusted = true; | |
| 611 | + } | |
| 612 | + } catch (UnknownHostException uhe) { | |
| 613 | + invalid = true; | |
| 614 | + throw uhe; | |
| 615 | + } | |
| 616 | + return false; | |
| 617 | + } | |
| 618 | + | |
| 619 | + /** | |
| 620 | + * attempt to get the fully qualified domain name | |
| 621 | + * | |
| 622 | + */ | |
| 623 | + void getCanonName() | |
| 624 | + throws UnknownHostException | |
| 625 | + { | |
| 626 | + if (cname != null || invalid || untrusted) return; | |
| 627 | + | |
| 628 | + // attempt to get the canonical name | |
| 629 | + | |
| 630 | + try { | |
| 631 | + // first get the IP addresses if we don't have them yet | |
| 632 | + // this is because we need the IP address to then get | |
| 633 | + // FQDN. | |
| 634 | + if (addresses == null) { | |
| 635 | + getIP(); | |
| 636 | + } | |
| 637 | + | |
| 638 | + // we have to do this check, otherwise we might not | |
| 639 | + // get the fully qualified domain name | |
| 640 | + if (init_with_ip) { | |
| 641 | + cname = addresses[0].getHostName(false).toLowerCase(); | |
| 642 | + } else { | |
| 643 | + cname = InetAddress.getByName(addresses[0].getHostAddress()). | |
| 644 | + getHostName(false).toLowerCase(); | |
| 645 | + } | |
| 646 | + } catch (UnknownHostException uhe) { | |
| 647 | + invalid = true; | |
| 648 | + throw uhe; | |
| 649 | + } | |
| 650 | + } | |
| 651 | + | |
| 652 | + private transient String cdomain, hdomain; | |
| 653 | + | |
| 654 | + private boolean match(String cname, String hname) { | |
| 655 | + String a = cname.toLowerCase(); | |
| 656 | + String b = hname.toLowerCase(); | |
| 657 | + if (a.startsWith(b) && | |
| 658 | + ((a.length() == b.length()) || (a.charAt(b.length()) == '.'))) | |
| 659 | + return true; | |
| 660 | + if (cdomain == null) { | |
| 661 | + cdomain = RegisteredDomain.getRegisteredDomain(a); | |
| 662 | + } | |
| 663 | + if (hdomain == null) { | |
| 664 | + hdomain = RegisteredDomain.getRegisteredDomain(b); | |
| 665 | + } | |
| 666 | + | |
| 667 | + return cdomain.length() != 0 && hdomain.length() != 0 | |
| 668 | + && cdomain.equals(hdomain); | |
| 669 | + } | |
| 670 | + | |
| 671 | + private boolean authorized(String cname, byte[] addr) { | |
| 672 | + if (addr.length == 4) | |
| 673 | + return authorizedIPv4(cname, addr); | |
| 674 | + else if (addr.length == 16) | |
| 675 | + return authorizedIPv6(cname, addr); | |
| 676 | + else | |
| 677 | + return false; | |
| 678 | + } | |
| 679 | + | |
| 680 | + private boolean authorizedIPv4(String cname, byte[] addr) { | |
| 681 | + String authHost = ""; | |
| 682 | + InetAddress auth; | |
| 683 | + | |
| 684 | + try { | |
| 685 | + authHost = "auth." + | |
| 686 | + (addr[3] & 0xff) + "." + (addr[2] & 0xff) + "." + | |
| 687 | + (addr[1] & 0xff) + "." + (addr[0] & 0xff) + | |
| 688 | + ".in-addr.arpa"; | |
| 689 | + // Following check seems unnecessary | |
| 690 | + // auth = InetAddress.getAllByName0(authHost, false)[0]; | |
| 691 | + authHost = hostname + '.' + authHost; | |
| 692 | + auth = InetAddress.getAllByName0(authHost, false)[0]; | |
| 693 | + if (auth.equals(InetAddress.getByAddress(addr))) { | |
| 694 | + return true; | |
| 695 | + } | |
| 696 | + Debug debug = getDebug(); | |
| 697 | + if (debug != null && Debug.isOn("failure")) { | |
| 698 | + debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr)); | |
| 699 | + } | |
| 700 | + } catch (UnknownHostException uhe) { | |
| 701 | + Debug debug = getDebug(); | |
| 702 | + if (debug != null && Debug.isOn("failure")) { | |
| 703 | + debug.println("socket access restriction: forward lookup failed for " + authHost); | |
| 704 | + } | |
| 705 | + } | |
| 706 | + return false; | |
| 707 | + } | |
| 708 | + | |
| 709 | + private boolean authorizedIPv6(String cname, byte[] addr) { | |
| 710 | + String authHost = ""; | |
| 711 | + InetAddress auth; | |
| 712 | + | |
| 713 | + try { | |
| 714 | + StringBuffer sb = new StringBuffer(39); | |
| 715 | + | |
| 716 | + for (int i = 15; i >= 0; i--) { | |
| 717 | + sb.append(Integer.toHexString(((addr[i]) & 0x0f))); | |
| 718 | + sb.append('.'); | |
| 719 | + sb.append(Integer.toHexString(((addr[i] >> 4) & 0x0f))); | |
| 720 | + sb.append('.'); | |
| 721 | + } | |
| 722 | + authHost = "auth." + sb.toString() + "IP6.ARPA"; | |
| 723 | + //auth = InetAddress.getAllByName0(authHost, false)[0]; | |
| 724 | + authHost = hostname + '.' + authHost; | |
| 725 | + auth = InetAddress.getAllByName0(authHost, false)[0]; | |
| 726 | + if (auth.equals(InetAddress.getByAddress(addr))) | |
| 727 | + return true; | |
| 728 | + Debug debug = getDebug(); | |
| 729 | + if (debug != null && Debug.isOn("failure")) { | |
| 730 | + debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr)); | |
| 731 | + } | |
| 732 | + } catch (UnknownHostException uhe) { | |
| 733 | + Debug debug = getDebug(); | |
| 734 | + if (debug != null && Debug.isOn("failure")) { | |
| 735 | + debug.println("socket access restriction: forward lookup failed for " + authHost); | |
| 736 | + } | |
| 737 | + } | |
| 738 | + return false; | |
| 739 | + } | |
| 740 | + | |
| 741 | + | |
| 742 | + /** | |
| 743 | + * get IP addresses. Sets invalid to true if we can't get them. | |
| 744 | + * | |
| 745 | + */ | |
| 746 | + void getIP() | |
| 747 | + throws UnknownHostException | |
| 748 | + { | |
| 749 | + if (addresses != null || wildcard || invalid) return; | |
| 750 | + | |
| 751 | + try { | |
| 752 | + // now get all the IP addresses | |
| 753 | + String host; | |
| 754 | + if (getName().charAt(0) == '[') { | |
| 755 | + // Literal IPv6 address | |
| 756 | + host = getName().substring(1, getName().indexOf(']')); | |
| 757 | + } else { | |
| 758 | + int i = getName().indexOf(":"); | |
| 759 | + if (i == -1) | |
| 760 | + host = getName(); | |
| 761 | + else { | |
| 762 | + host = getName().substring(0,i); | |
| 763 | + } | |
| 764 | + } | |
| 765 | + | |
| 766 | + addresses = | |
| 767 | + new InetAddress[] {InetAddress.getAllByName0(host, false)[0]}; | |
| 768 | + | |
| 769 | + } catch (UnknownHostException uhe) { | |
| 770 | + invalid = true; | |
| 771 | + throw uhe; | |
| 772 | + } catch (IndexOutOfBoundsException iobe) { | |
| 773 | + invalid = true; | |
| 774 | + throw new UnknownHostException(getName()); | |
| 775 | + } | |
| 776 | + } | |
| 777 | + | |
| 778 | + /** | |
| 779 | + * Checks if this socket permission object "implies" the | |
| 780 | + * specified permission. | |
| 781 | + * <P> | |
| 782 | + * More specifically, this method first ensures that all of the following | |
| 783 | + * are true (and returns false if any of them are not):<p> | |
| 784 | + * <ul> | |
| 785 | + * <li> <i>p</i> is an instanceof SocketPermission,<p> | |
| 786 | + * <li> <i>p</i>'s actions are a proper subset of this | |
| 787 | + * object's actions, and<p> | |
| 788 | + * <li> <i>p</i>'s port range is included in this port range. Note: | |
| 789 | + * port range is ignored when p only contains the action, 'resolve'.<p> | |
| 790 | + * </ul> | |
| 791 | + * | |
| 792 | + * Then <code>implies</code> checks each of the following, in order, | |
| 793 | + * and for each returns true if the stated condition is true:<p> | |
| 794 | + * <ul> | |
| 795 | + * <li> If this object was initialized with a single IP address and one of <i>p</i>'s | |
| 796 | + * IP addresses is equal to this object's IP address.<p> | |
| 797 | + * <li>If this object is a wildcard domain (such as *.sun.com), and | |
| 798 | + * <i>p</i>'s canonical name (the name without any preceding *) | |
| 799 | + * ends with this object's canonical host name. For example, *.sun.com | |
| 800 | + * implies *.eng.sun.com..<p> | |
| 801 | + * <li>If this object was not initialized with a single IP address, and one of this | |
| 802 | + * object's IP addresses equals one of <i>p</i>'s IP addresses.<p> | |
| 803 | + * <li>If this canonical name equals <i>p</i>'s canonical name.<p> | |
| 804 | + * </ul> | |
| 805 | + * | |
| 806 | + * If none of the above are true, <code>implies</code> returns false. | |
| 807 | + * @param p the permission to check against. | |
| 808 | + * | |
| 809 | + * @return true if the specified permission is implied by this object, | |
| 810 | + * false if not. | |
| 811 | + */ | |
| 812 | + | |
| 813 | + public boolean implies(Permission p) { | |
| 814 | + int i,j; | |
| 815 | + | |
| 816 | + if (!(p instanceof SocketPermission)) | |
| 817 | + return false; | |
| 818 | + | |
| 819 | + if (p == this) | |
| 820 | + return true; | |
| 821 | + | |
| 822 | + SocketPermission that = (SocketPermission) p; | |
| 823 | + | |
| 824 | + return ((this.mask & that.mask) == that.mask) && | |
| 825 | + impliesIgnoreMask(that); | |
| 826 | + } | |
| 827 | + | |
| 828 | + /** | |
| 829 | + * Checks if the incoming Permission's action are a proper subset of | |
| 830 | + * the this object's actions. | |
| 831 | + * <P> | |
| 832 | + * Check, in the following order: | |
| 833 | + * <ul> | |
| 834 | + * <li> Checks that "p" is an instanceof a SocketPermission | |
| 835 | + * <li> Checks that "p"'s actions are a proper subset of the | |
| 836 | + * current object's actions. | |
| 837 | + * <li> Checks that "p"'s port range is included in this port range | |
| 838 | + * <li> If this object was initialized with an IP address, checks that | |
| 839 | + * one of "p"'s IP addresses is equal to this object's IP address. | |
| 840 | + * <li> If either object is a wildcard domain (i.e., "*.sun.com"), | |
| 841 | + * attempt to match based on the wildcard. | |
| 842 | + * <li> If this object was not initialized with an IP address, attempt | |
| 843 | + * to find a match based on the IP addresses in both objects. | |
| 844 | + * <li> Attempt to match on the canonical hostnames of both objects. | |
| 845 | + * </ul> | |
| 846 | + * @param p the incoming permission request | |
| 847 | + * | |
| 848 | + * @return true if "permission" is a proper subset of the current object, | |
| 849 | + * false if not. | |
| 850 | + */ | |
| 851 | + | |
| 852 | + boolean impliesIgnoreMask(SocketPermission that) { | |
| 853 | + int i,j; | |
| 854 | + | |
| 855 | + if ((that.mask & RESOLVE) != that.mask) { | |
| 856 | + // check port range | |
| 857 | + if ((that.portrange[0] < this.portrange[0]) || | |
| 858 | + (that.portrange[1] > this.portrange[1])) { | |
| 859 | + return false; | |
| 860 | + } | |
| 861 | + } | |
| 862 | + | |
| 863 | + // allow a "*" wildcard to always match anything | |
| 864 | + if (this.wildcard && "".equals(this.cname)) | |
| 865 | + return true; | |
| 866 | + | |
| 867 | + // return if either one of these NetPerm objects are invalid... | |
| 868 | + if (this.invalid || that.invalid) { | |
| 869 | + return compareHostnames(that); | |
| 870 | + } | |
| 871 | + | |
| 872 | + try { | |
| 873 | + if (this.init_with_ip) { // we only check IP addresses | |
| 874 | + if (that.wildcard) | |
| 875 | + return false; | |
| 876 | + | |
| 877 | + if (that.init_with_ip) { | |
| 878 | + return (this.addresses[0].equals(that.addresses[0])); | |
| 879 | + } else { | |
| 880 | + if (that.addresses == null) { | |
| 881 | + that.getIP(); | |
| 882 | + } | |
| 883 | + for (i=0; i < that.addresses.length; i++) { | |
| 884 | + if (this.addresses[0].equals(that.addresses[i])) | |
| 885 | + return true; | |
| 886 | + } | |
| 887 | + } | |
| 888 | + // since "this" was initialized with an IP address, we | |
| 889 | + // don't check any other cases | |
| 890 | + return false; | |
| 891 | + } | |
| 892 | + | |
| 893 | + // check and see if we have any wildcards... | |
| 894 | + if (this.wildcard || that.wildcard) { | |
| 895 | + // if they are both wildcards, return true iff | |
| 896 | + // that's cname ends with this cname (i.e., *.sun.com | |
| 897 | + // implies *.eng.sun.com) | |
| 898 | + if (this.wildcard && that.wildcard) | |
| 899 | + return (that.cname.endsWith(this.cname)); | |
| 900 | + | |
| 901 | + // a non-wildcard can't imply a wildcard | |
| 902 | + if (that.wildcard) | |
| 903 | + return false; | |
| 904 | + | |
| 905 | + // this is a wildcard, lets see if that's cname ends with | |
| 906 | + // it... | |
| 907 | + if (that.cname == null) { | |
| 908 | + that.getCanonName(); | |
| 909 | + } | |
| 910 | + return (that.cname.endsWith(this.cname)); | |
| 911 | + } | |
| 912 | + | |
| 913 | + // comapare IP addresses | |
| 914 | + if (this.addresses == null) { | |
| 915 | + this.getIP(); | |
| 916 | + } | |
| 917 | + | |
| 918 | + if (that.addresses == null) { | |
| 919 | + that.getIP(); | |
| 920 | + } | |
| 921 | + | |
| 922 | + if (!(that.init_with_ip && this.isUntrusted())) { | |
| 923 | + for (j = 0; j < this.addresses.length; j++) { | |
| 924 | + for (i=0; i < that.addresses.length; i++) { | |
| 925 | + if (this.addresses[j].equals(that.addresses[i])) | |
| 926 | + return true; | |
| 927 | + } | |
| 928 | + } | |
| 929 | + | |
| 930 | + // XXX: if all else fails, compare hostnames? | |
| 931 | + // Do we really want this? | |
| 932 | + if (this.cname == null) { | |
| 933 | + this.getCanonName(); | |
| 934 | + } | |
| 935 | + | |
| 936 | + if (that.cname == null) { | |
| 937 | + that.getCanonName(); | |
| 938 | + } | |
| 939 | + | |
| 940 | + return (this.cname.equalsIgnoreCase(that.cname)); | |
| 941 | + } | |
| 942 | + | |
| 943 | + } catch (UnknownHostException uhe) { | |
| 944 | + return compareHostnames(that); | |
| 945 | + } | |
| 946 | + | |
| 947 | + // make sure the first thing that is done here is to return | |
| 948 | + // false. If not, uncomment the return false in the above catch. | |
| 949 | + | |
| 950 | + return false; | |
| 951 | + } | |
| 952 | + | |
| 953 | + private boolean compareHostnames(SocketPermission that) { | |
| 954 | + // we see if the original names/IPs passed in were equal. | |
| 955 | + | |
| 956 | + String thisHost = hostname; | |
| 957 | + String thatHost = that.hostname; | |
| 958 | + | |
| 959 | + if (thisHost == null) | |
| 960 | + return false; | |
| 961 | + else | |
| 962 | + return thisHost.equalsIgnoreCase(thatHost); | |
| 963 | + } | |
| 964 | + | |
| 965 | + /** | |
| 966 | + * Checks two SocketPermission objects for equality. | |
| 967 | + * <P> | |
| 968 | + * @param obj the object to test for equality with this object. | |
| 969 | + * | |
| 970 | + * @return true if <i>obj</i> is a SocketPermission, and has the | |
| 971 | + * same hostname, port range, and actions as this | |
| 972 | + * SocketPermission object. However, port range will be ignored | |
| 973 | + * in the comparison if <i>obj</i> only contains the action, 'resolve'. | |
| 974 | + */ | |
| 975 | + public boolean equals(Object obj) { | |
| 976 | + if (obj == this) | |
| 977 | + return true; | |
| 978 | + | |
| 979 | + if (! (obj instanceof SocketPermission)) | |
| 980 | + return false; | |
| 981 | + | |
| 982 | + SocketPermission that = (SocketPermission) obj; | |
| 983 | + | |
| 984 | + //this is (overly?) complex!!! | |
| 985 | + | |
| 986 | + // check the mask first | |
| 987 | + if (this.mask != that.mask) return false; | |
| 988 | + | |
| 989 | + if ((that.mask & RESOLVE) != that.mask) { | |
| 990 | + // now check the port range... | |
| 991 | + if ((this.portrange[0] != that.portrange[0]) || | |
| 992 | + (this.portrange[1] != that.portrange[1])) { | |
| 993 | + return false; | |
| 994 | + } | |
| 995 | + } | |
| 996 | + | |
| 997 | + // short cut. This catches: | |
| 998 | + // "crypto" equal to "crypto", or | |
| 999 | + // "1.2.3.4" equal to "1.2.3.4.", or | |
| 1000 | + // "*.edu" equal to "*.edu", but it | |
| 1001 | + // does not catch "crypto" equal to | |
| 1002 | + // "crypto.eng.sun.com". | |
| 1003 | + | |
| 1004 | + if (this.getName().equalsIgnoreCase(that.getName())) { | |
| 1005 | + return true; | |
| 1006 | + } | |
| 1007 | + | |
| 1008 | + // we now attempt to get the Canonical (FQDN) name and | |
| 1009 | + // compare that. If this fails, about all we can do is return | |
| 1010 | + // false. | |
| 1011 | + | |
| 1012 | + try { | |
| 1013 | + this.getCanonName(); | |
| 1014 | + that.getCanonName(); | |
| 1015 | + } catch (UnknownHostException uhe) { | |
| 1016 | + return false; | |
| 1017 | + } | |
| 1018 | + | |
| 1019 | + if (this.invalid || that.invalid) | |
| 1020 | + return false; | |
| 1021 | + | |
| 1022 | + if (this.cname != null) { | |
| 1023 | + return this.cname.equalsIgnoreCase(that.cname); | |
| 1024 | + } | |
| 1025 | + | |
| 1026 | + return false; | |
| 1027 | + } | |
| 1028 | + | |
| 1029 | + /** | |
| 1030 | + * Returns the hash code value for this object. | |
| 1031 | + * | |
| 1032 | + * @return a hash code value for this object. | |
| 1033 | + */ | |
| 1034 | + | |
| 1035 | + public int hashCode() { | |
| 1036 | + /* | |
| 1037 | + * If this SocketPermission was initialized with an IP address | |
| 1038 | + * or a wildcard, use getName().hashCode(), otherwise use | |
| 1039 | + * the hashCode() of the host name returned from | |
| 1040 | + * java.net.InetAddress.getHostName method. | |
| 1041 | + */ | |
| 1042 | + | |
| 1043 | + if (init_with_ip || wildcard) { | |
| 1044 | + return this.getName().hashCode(); | |
| 1045 | + } | |
| 1046 | + | |
| 1047 | + try { | |
| 1048 | + getCanonName(); | |
| 1049 | + } catch (UnknownHostException uhe) { | |
| 1050 | + | |
| 1051 | + } | |
| 1052 | + | |
| 1053 | + if (invalid || cname == null) | |
| 1054 | + return this.getName().hashCode(); | |
| 1055 | + else | |
| 1056 | + return this.cname.hashCode(); | |
| 1057 | + } | |
| 1058 | + | |
| 1059 | + /** | |
| 1060 | + * Return the current action mask. | |
| 1061 | + * | |
| 1062 | + * @return the actions mask. | |
| 1063 | + */ | |
| 1064 | + | |
| 1065 | + int getMask() { | |
| 1066 | + return mask; | |
| 1067 | + } | |
| 1068 | + | |
| 1069 | + /** | |
| 1070 | + * Returns the "canonical string representation" of the actions in the | |
| 1071 | + * specified mask. | |
| 1072 | + * Always returns present actions in the following order: | |
| 1073 | + * connect, listen, accept, resolve. | |
| 1074 | + * | |
| 1075 | + * @param mask a specific integer action mask to translate into a string | |
| 1076 | + * @return the canonical string representation of the actions | |
| 1077 | + */ | |
| 1078 | + private static String getActions(int mask) | |
| 1079 | + { | |
| 1080 | + StringBuilder sb = new StringBuilder(); | |
| 1081 | + boolean comma = false; | |
| 1082 | + | |
| 1083 | + if ((mask & CONNECT) == CONNECT) { | |
| 1084 | + comma = true; | |
| 1085 | + sb.append("connect"); | |
| 1086 | + } | |
| 1087 | + | |
| 1088 | + if ((mask & LISTEN) == LISTEN) { | |
| 1089 | + if (comma) sb.append(','); | |
| 1090 | + else comma = true; | |
| 1091 | + sb.append("listen"); | |
| 1092 | + } | |
| 1093 | + | |
| 1094 | + if ((mask & ACCEPT) == ACCEPT) { | |
| 1095 | + if (comma) sb.append(','); | |
| 1096 | + else comma = true; | |
| 1097 | + sb.append("accept"); | |
| 1098 | + } | |
| 1099 | + | |
| 1100 | + | |
| 1101 | + if ((mask & RESOLVE) == RESOLVE) { | |
| 1102 | + if (comma) sb.append(','); | |
| 1103 | + else comma = true; | |
| 1104 | + sb.append("resolve"); | |
| 1105 | + } | |
| 1106 | + | |
| 1107 | + return sb.toString(); | |
| 1108 | + } | |
| 1109 | + | |
| 1110 | + /** | |
| 1111 | + * Returns the canonical string representation of the actions. | |
| 1112 | + * Always returns present actions in the following order: | |
| 1113 | + * connect, listen, accept, resolve. | |
| 1114 | + * | |
| 1115 | + * @return the canonical string representation of the actions. | |
| 1116 | + */ | |
| 1117 | + public String getActions() | |
| 1118 | + { | |
| 1119 | + if (actions == null) | |
| 1120 | + actions = getActions(this.mask); | |
| 1121 | + | |
| 1122 | + return actions; | |
| 1123 | + } | |
| 1124 | + | |
| 1125 | + /** | |
| 1126 | + * Returns a new PermissionCollection object for storing SocketPermission | |
| 1127 | + * objects. | |
| 1128 | + * <p> | |
| 1129 | + * SocketPermission objects must be stored in a manner that allows them | |
| 1130 | + * to be inserted into the collection in any order, but that also enables the | |
| 1131 | + * PermissionCollection <code>implies</code> | |
| 1132 | + * method to be implemented in an efficient (and consistent) manner. | |
| 1133 | + * | |
| 1134 | + * @return a new PermissionCollection object suitable for storing SocketPermissions. | |
| 1135 | + */ | |
| 1136 | + | |
| 1137 | + public PermissionCollection newPermissionCollection() { | |
| 1138 | + return new SocketPermissionCollection(); | |
| 1139 | + } | |
| 1140 | + | |
| 1141 | + /** | |
| 1142 | + * WriteObject is called to save the state of the SocketPermission | |
| 1143 | + * to a stream. The actions are serialized, and the superclass | |
| 1144 | + * takes care of the name. | |
| 1145 | + */ | |
| 1146 | + private synchronized void writeObject(java.io.ObjectOutputStream s) | |
| 1147 | + throws IOException | |
| 1148 | + { | |
| 1149 | + // Write out the actions. The superclass takes care of the name | |
| 1150 | + // call getActions to make sure actions field is initialized | |
| 1151 | + if (actions == null) | |
| 1152 | + getActions(); | |
| 1153 | + s.defaultWriteObject(); | |
| 1154 | + } | |
| 1155 | + | |
| 1156 | + /** | |
| 1157 | + * readObject is called to restore the state of the SocketPermission from | |
| 1158 | + * a stream. | |
| 1159 | + */ | |
| 1160 | + private synchronized void readObject(java.io.ObjectInputStream s) | |
| 1161 | + throws IOException, ClassNotFoundException | |
| 1162 | + { | |
| 1163 | + // Read in the action, then initialize the rest | |
| 1164 | + s.defaultReadObject(); | |
| 1165 | + init(getName(),getMask(actions)); | |
| 1166 | + } | |
| 1167 | + | |
| 1168 | + /* | |
| 1169 | + public String toString() | |
| 1170 | + { | |
| 1171 | + StringBuffer s = new StringBuffer(super.toString() + "\n" + | |
| 1172 | + "cname = " + cname + "\n" + | |
| 1173 | + "wildcard = " + wildcard + "\n" + | |
| 1174 | + "invalid = " + invalid + "\n" + | |
| 1175 | + "portrange = " + portrange[0] + "," + portrange[1] + "\n"); | |
| 1176 | + if (addresses != null) for (int i=0; i<addresses.length; i++) { | |
| 1177 | + s.append( addresses[i].getHostAddress()); | |
| 1178 | + s.append("\n"); | |
| 1179 | + } else { | |
| 1180 | + s.append("(no addresses)\n"); | |
| 1181 | + } | |
| 1182 | + | |
| 1183 | + return s.toString(); | |
| 1184 | + } | |
| 1185 | + | |
| 1186 | + public static void main(String args[]) throws Exception { | |
| 1187 | + SocketPermission this_ = new SocketPermission(args[0], "connect"); | |
| 1188 | + SocketPermission that_ = new SocketPermission(args[1], "connect"); | |
| 1189 | + System.out.println("-----\n"); | |
| 1190 | + System.out.println("this.implies(that) = " + this_.implies(that_)); | |
| 1191 | + System.out.println("-----\n"); | |
| 1192 | + System.out.println("this = "+this_); | |
| 1193 | + System.out.println("-----\n"); | |
| 1194 | + System.out.println("that = "+that_); | |
| 1195 | + System.out.println("-----\n"); | |
| 1196 | + | |
| 1197 | + SocketPermissionCollection nps = new SocketPermissionCollection(); | |
| 1198 | + nps.add(this_); | |
| 1199 | + nps.add(new SocketPermission("www-leland.stanford.edu","connect")); | |
| 1200 | + nps.add(new SocketPermission("www-sun.com","connect")); | |
| 1201 | + System.out.println("nps.implies(that) = " + nps.implies(that_)); | |
| 1202 | + System.out.println("-----\n"); | |
| 1203 | + } | |
| 1204 | + */ | |
| 1205 | +} | |
| 1206 | + | |
| 1207 | +/** | |
| 1208 | + | |
| 1209 | +if (init'd with IP, key is IP as string) | |
| 1210 | +if wildcard, its the wild card | |
| 1211 | +else its the cname? | |
| 1212 | + | |
| 1213 | + * | |
| 1214 | + * @see java.security.Permission | |
| 1215 | + * @see java.security.Permissions | |
| 1216 | + * @see java.security.PermissionCollection | |
| 1217 | + * | |
| 1218 | + * | |
| 1219 | + * @author Roland Schemers | |
| 1220 | + * | |
| 1221 | + * @serial include | |
| 1222 | + */ | |
| 1223 | + | |
| 1224 | +final class SocketPermissionCollection extends PermissionCollection | |
| 1225 | +implements Serializable | |
| 1226 | +{ | |
| 1227 | + // Not serialized; see serialization section at end of class | |
| 1228 | + private transient List perms; | |
| 1229 | + | |
| 1230 | + /** | |
| 1231 | + * Create an empty SocketPermissions object. | |
| 1232 | + * | |
| 1233 | + */ | |
| 1234 | + | |
| 1235 | + public SocketPermissionCollection() { | |
| 1236 | + perms = new ArrayList(); | |
| 1237 | + } | |
| 1238 | + | |
| 1239 | + /** | |
| 1240 | + * Adds a permission to the SocketPermissions. The key for the hash is | |
| 1241 | + * the name in the case of wildcards, or all the IP addresses. | |
| 1242 | + * | |
| 1243 | + * @param permission the Permission object to add. | |
| 1244 | + * | |
| 1245 | + * @exception IllegalArgumentException - if the permission is not a | |
| 1246 | + * SocketPermission | |
| 1247 | + * | |
| 1248 | + * @exception SecurityException - if this SocketPermissionCollection object | |
| 1249 | + * has been marked readonly | |
| 1250 | + */ | |
| 1251 | + | |
| 1252 | + public void add(Permission permission) | |
| 1253 | + { | |
| 1254 | + if (! (permission instanceof SocketPermission)) | |
| 1255 | + throw new IllegalArgumentException("invalid permission: "+ | |
| 1256 | + permission); | |
| 1257 | + if (isReadOnly()) | |
| 1258 | + throw new SecurityException( | |
| 1259 | + "attempt to add a Permission to a readonly PermissionCollection"); | |
| 1260 | + | |
| 1261 | + // optimization to ensure perms most likely to be tested | |
| 1262 | + // show up early (4301064) | |
| 1263 | + synchronized (this) { | |
| 1264 | + perms.add(0, permission); | |
| 1265 | + } | |
| 1266 | + } | |
| 1267 | + | |
| 1268 | + /** | |
| 1269 | + * Check and see if this collection of permissions implies the permissions | |
| 1270 | + * expressed in "permission". | |
| 1271 | + * | |
| 1272 | + * @param p the Permission object to compare | |
| 1273 | + * | |
| 1274 | + * @return true if "permission" is a proper subset of a permission in | |
| 1275 | + * the collection, false if not. | |
| 1276 | + */ | |
| 1277 | + | |
| 1278 | + public boolean implies(Permission permission) | |
| 1279 | + { | |
| 1280 | + if (! (permission instanceof SocketPermission)) | |
| 1281 | + return false; | |
| 1282 | + | |
| 1283 | + SocketPermission np = (SocketPermission) permission; | |
| 1284 | + | |
| 1285 | + int desired = np.getMask(); | |
| 1286 | + int effective = 0; | |
| 1287 | + int needed = desired; | |
| 1288 | + | |
| 1289 | + synchronized (this) { | |
| 1290 | + int len = perms.size(); | |
| 1291 | + //System.out.println("implies "+np); | |
| 1292 | + for (int i = 0; i < len; i++) { | |
| 1293 | + SocketPermission x = (SocketPermission) perms.get(i); | |
| 1294 | + //System.out.println(" trying "+x); | |
| 1295 | + if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(np)) { | |
| 1296 | + effective |= x.getMask(); | |
| 1297 | + if ((effective & desired) == desired) | |
| 1298 | + return true; | |
| 1299 | + needed = (desired ^ effective); | |
| 1300 | + } | |
| 1301 | + } | |
| 1302 | + } | |
| 1303 | + return false; | |
| 1304 | + } | |
| 1305 | + | |
| 1306 | + /** | |
| 1307 | + * Returns an enumeration of all the SocketPermission objects in the | |
| 1308 | + * container. | |
| 1309 | + * | |
| 1310 | + * @return an enumeration of all the SocketPermission objects. | |
| 1311 | + */ | |
| 1312 | + | |
| 1313 | + public Enumeration elements() { | |
| 1314 | + // Convert Iterator into Enumeration | |
| 1315 | + synchronized (this) { | |
| 1316 | + return Collections.enumeration(perms); | |
| 1317 | + } | |
| 1318 | + } | |
| 1319 | + | |
| 1320 | + private static final long serialVersionUID = 2787186408602843674L; | |
| 1321 | + | |
| 1322 | + // Need to maintain serialization interoperability with earlier releases, | |
| 1323 | + // which had the serializable field: | |
| 1324 | + | |
| 1325 | + // | |
| 1326 | + // The SocketPermissions for this set. | |
| 1327 | + // @serial | |
| 1328 | + // | |
| 1329 | + // private Vector permissions; | |
| 1330 | + | |
| 1331 | + /** | |
| 1332 | + * @serialField permissions java.util.Vector | |
| 1333 | + * A list of the SocketPermissions for this set. | |
| 1334 | + */ | |
| 1335 | + private static final ObjectStreamField[] serialPersistentFields = { | |
| 1336 | + new ObjectStreamField("permissions", Vector.class), | |
| 1337 | + }; | |
| 1338 | + | |
| 1339 | + /** | |
| 1340 | + * @serialData "permissions" field (a Vector containing the SocketPermissions). | |
| 1341 | + */ | |
| 1342 | + /* | |
| 1343 | + * Writes the contents of the perms field out as a Vector for | |
| 1344 | + * serialization compatibility with earlier releases. | |
| 1345 | + */ | |
| 1346 | + private void writeObject(ObjectOutputStream out) throws IOException { | |
| 1347 | + // Don't call out.defaultWriteObject() | |
| 1348 | + | |
| 1349 | + // Write out Vector | |
| 1350 | + Vector permissions = new Vector(perms.size()); | |
| 1351 | + | |
| 1352 | + synchronized (this) { | |
| 1353 | + permissions.addAll(perms); | |
| 1354 | + } | |
| 1355 | + | |
| 1356 | + ObjectOutputStream.PutField pfields = out.putFields(); | |
| 1357 | + pfields.put("permissions", permissions); | |
| 1358 | + out.writeFields(); | |
| 1359 | + } | |
| 1360 | + | |
| 1361 | + /* | |
| 1362 | + * Reads in a Vector of SocketPermissions and saves them in the perms field. | |
| 1363 | + */ | |
| 1364 | + private void readObject(ObjectInputStream in) throws IOException, | |
| 1365 | + ClassNotFoundException { | |
| 1366 | + // Don't call in.defaultReadObject() | |
| 1367 | + | |
| 1368 | + // Read in serialized fields | |
| 1369 | + ObjectInputStream.GetField gfields = in.readFields(); | |
| 1370 | + | |
| 1371 | + // Get the one we want | |
| 1372 | + Vector permissions = (Vector)gfields.get("permissions", null); | |
| 1373 | + perms = new ArrayList(permissions.size()); | |
| 1374 | + perms.addAll(permissions); | |
| 1375 | + } | |
| 1376 | +} | |
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,50 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 2008, 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 java.net; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Signals that a timeout has occurred on a socket read or accept. | |
| 30 | + * | |
| 31 | + * @since 1.4 | |
| 32 | + */ | |
| 33 | + | |
| 34 | +public class SocketTimeoutException extends java.io.InterruptedIOException { | |
| 35 | + private static final long serialVersionUID = -8846654841826352300L; | |
| 36 | + | |
| 37 | + /** | |
| 38 | + * Constructs a new SocketTimeoutException with a detail | |
| 39 | + * message. | |
| 40 | + * @param msg the detail message | |
| 41 | + */ | |
| 42 | + public SocketTimeoutException(String msg) { | |
| 43 | + super(msg); | |
| 44 | + } | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * Construct a new SocketTimeoutException with no detailed message. | |
| 48 | + */ | |
| 49 | + public SocketTimeoutException() {} | |
| 50 | +} | |
Binary file not shown.
| @@ -0,0 +1,58 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 2001, 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 | +package java.net; | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * Constants used by the SOCKS protocol implementation. | |
| 29 | + */ | |
| 30 | + | |
| 31 | +interface SocksConsts { | |
| 32 | + static final int PROTO_VERS4 = 4; | |
| 33 | + static final int PROTO_VERS = 5; | |
| 34 | + static final int DEFAULT_PORT = 1080; | |
| 35 | + | |
| 36 | + static final int NO_AUTH = 0; | |
| 37 | + static final int GSSAPI = 1; | |
| 38 | + static final int USER_PASSW = 2; | |
| 39 | + static final int NO_METHODS = -1; | |
| 40 | + | |
| 41 | + static final int CONNECT = 1; | |
| 42 | + static final int BIND = 2; | |
| 43 | + static final int UDP_ASSOC = 3; | |
| 44 | + | |
| 45 | + static final int IPV4 = 1; | |
| 46 | + static final int DOMAIN_NAME = 3; | |
| 47 | + static final int IPV6 = 4; | |
| 48 | + | |
| 49 | + static final int REQUEST_OK = 0; | |
| 50 | + static final int GENERAL_FAILURE = 1; | |
| 51 | + static final int NOT_ALLOWED = 2; | |
| 52 | + static final int NET_UNREACHABLE = 3; | |
| 53 | + static final int HOST_UNREACHABLE = 4; | |
| 54 | + static final int CONN_REFUSED = 5; | |
| 55 | + static final int TTL_EXPIRED = 6; | |
| 56 | + static final int CMD_NOT_SUPPORTED = 7; | |
| 57 | + static final int ADDR_TYPE_NOT_SUP = 8; | |
| 58 | +} | |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,1085 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2000, 2011, 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 | +package java.net; | |
| 26 | +import java.io.IOException; | |
| 27 | +import java.io.InputStream; | |
| 28 | +import java.io.OutputStream; | |
| 29 | +import java.io.BufferedOutputStream; | |
| 30 | +import java.security.AccessController; | |
| 31 | +import java.security.PrivilegedExceptionAction; | |
| 32 | +import sun.net.SocksProxy; | |
| 33 | +import sun.net.www.ParseUtil; | |
| 34 | +/* import org.ietf.jgss.*; */ | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * SOCKS (V4 & V5) TCP socket implementation (RFC 1928). | |
| 38 | + * This is a subclass of PlainSocketImpl. | |
| 39 | + * Note this class should <b>NOT</b> be public. | |
| 40 | + */ | |
| 41 | + | |
| 42 | +class SocksSocketImpl extends PlainSocketImpl implements SocksConsts { | |
| 43 | + private String server = null; | |
| 44 | + private int serverPort = DEFAULT_PORT; | |
| 45 | + private InetSocketAddress external_address; | |
| 46 | + private boolean useV4 = false; | |
| 47 | + private Socket cmdsock = null; | |
| 48 | + private InputStream cmdIn = null; | |
| 49 | + private OutputStream cmdOut = null; | |
| 50 | + /* true if the Proxy has been set programatically */ | |
| 51 | + private boolean applicationSetProxy; /* false */ | |
| 52 | + | |
| 53 | + | |
| 54 | + SocksSocketImpl() { | |
| 55 | + // Nothing needed | |
| 56 | + } | |
| 57 | + | |
| 58 | + SocksSocketImpl(String server, int port) { | |
| 59 | + this.server = server; | |
| 60 | + this.serverPort = (port == -1 ? DEFAULT_PORT : port); | |
| 61 | + } | |
| 62 | + | |
| 63 | + SocksSocketImpl(Proxy proxy) { | |
| 64 | + SocketAddress a = proxy.address(); | |
| 65 | + if (a instanceof InetSocketAddress) { | |
| 66 | + InetSocketAddress ad = (InetSocketAddress) a; | |
| 67 | + // Use getHostString() to avoid reverse lookups | |
| 68 | + server = ad.getHostString(); | |
| 69 | + serverPort = ad.getPort(); | |
| 70 | + } | |
| 71 | + } | |
| 72 | + | |
| 73 | + void setV4() { | |
| 74 | + useV4 = true; | |
| 75 | + } | |
| 76 | + | |
| 77 | + private synchronized void privilegedConnect(final String host, | |
| 78 | + final int port, | |
| 79 | + final int timeout) | |
| 80 | + throws IOException | |
| 81 | + { | |
| 82 | + try { | |
| 83 | + AccessController.doPrivileged( | |
| 84 | + new java.security.PrivilegedExceptionAction<Void>() { | |
| 85 | + public Void run() throws IOException { | |
| 86 | + superConnectServer(host, port, timeout); | |
| 87 | + cmdIn = getInputStream(); | |
| 88 | + cmdOut = getOutputStream(); | |
| 89 | + return null; | |
| 90 | + } | |
| 91 | + }); | |
| 92 | + } catch (java.security.PrivilegedActionException pae) { | |
| 93 | + throw (IOException) pae.getException(); | |
| 94 | + } | |
| 95 | + } | |
| 96 | + | |
| 97 | + private void superConnectServer(String host, int port, | |
| 98 | + int timeout) throws IOException { | |
| 99 | + super.connect(new InetSocketAddress(host, port), timeout); | |
| 100 | + } | |
| 101 | + | |
| 102 | + private static int remainingMillis(long deadlineMillis) throws IOException { | |
| 103 | + if (deadlineMillis == 0L) | |
| 104 | + return 0; | |
| 105 | + | |
| 106 | + final long remaining = deadlineMillis - System.currentTimeMillis(); | |
| 107 | + if (remaining > 0) | |
| 108 | + return (int) remaining; | |
| 109 | + | |
| 110 | + throw new SocketTimeoutException(); | |
| 111 | + } | |
| 112 | + | |
| 113 | + private int readSocksReply(InputStream in, byte[] data) throws IOException { | |
| 114 | + return readSocksReply(in, data, 0L); | |
| 115 | + } | |
| 116 | + | |
| 117 | + private int readSocksReply(InputStream in, byte[] data, long deadlineMillis) throws IOException { | |
| 118 | + int len = data.length; | |
| 119 | + int received = 0; | |
| 120 | + for (int attempts = 0; received < len && attempts < 3; attempts++) { | |
| 121 | + int count; | |
| 122 | + try { | |
| 123 | + count = ((SocketInputStream)in).read(data, received, len - received, remainingMillis(deadlineMillis)); | |
| 124 | + } catch (SocketTimeoutException e) { | |
| 125 | + throw new SocketTimeoutException("Connect timed out"); | |
| 126 | + } | |
| 127 | + if (count < 0) | |
| 128 | + throw new SocketException("Malformed reply from SOCKS server"); | |
| 129 | + received += count; | |
| 130 | + } | |
| 131 | + return received; | |
| 132 | + } | |
| 133 | + | |
| 134 | + /** | |
| 135 | + * Provides the authentication machanism required by the proxy. | |
| 136 | + */ | |
| 137 | + private boolean authenticate(byte method, InputStream in, | |
| 138 | + BufferedOutputStream out) throws IOException { | |
| 139 | + return authenticate(method, in, out, 0L); | |
| 140 | + } | |
| 141 | + | |
| 142 | + private boolean authenticate(byte method, InputStream in, | |
| 143 | + BufferedOutputStream out, | |
| 144 | + long deadlineMillis) throws IOException { | |
| 145 | + // No Authentication required. We're done then! | |
| 146 | + if (method == NO_AUTH) | |
| 147 | + return true; | |
| 148 | + /** | |
| 149 | + * User/Password authentication. Try, in that order : | |
| 150 | + * - The application provided Authenticator, if any | |
| 151 | + * - the user.name & no password (backward compatibility behavior). | |
| 152 | + */ | |
| 153 | + if (method == USER_PASSW) { | |
| 154 | + String userName; | |
| 155 | + String password = null; | |
| 156 | + final InetAddress addr = InetAddress.getByName(server); | |
| 157 | + PasswordAuthentication pw = | |
| 158 | + java.security.AccessController.doPrivileged( | |
| 159 | + new java.security.PrivilegedAction<PasswordAuthentication>() { | |
| 160 | + public PasswordAuthentication run() { | |
| 161 | + return Authenticator.requestPasswordAuthentication( | |
| 162 | + server, addr, serverPort, "SOCKS5", "SOCKS authentication", null); | |
| 163 | + } | |
| 164 | + }); | |
| 165 | + if (pw != null) { | |
| 166 | + userName = pw.getUserName(); | |
| 167 | + password = new String(pw.getPassword()); | |
| 168 | + } else { | |
| 169 | + userName = java.security.AccessController.doPrivileged( | |
| 170 | + new sun.security.action.GetPropertyAction("user.name")); | |
| 171 | + } | |
| 172 | + if (userName == null) | |
| 173 | + return false; | |
| 174 | + out.write(1); | |
| 175 | + out.write(userName.length()); | |
| 176 | + try { | |
| 177 | + out.write(userName.getBytes("ISO-8859-1")); | |
| 178 | + } catch (java.io.UnsupportedEncodingException uee) { | |
| 179 | + assert false; | |
| 180 | + } | |
| 181 | + if (password != null) { | |
| 182 | + out.write(password.length()); | |
| 183 | + try { | |
| 184 | + out.write(password.getBytes("ISO-8859-1")); | |
| 185 | + } catch (java.io.UnsupportedEncodingException uee) { | |
| 186 | + assert false; | |
| 187 | + } | |
| 188 | + } else | |
| 189 | + out.write(0); | |
| 190 | + out.flush(); | |
| 191 | + byte[] data = new byte[2]; | |
| 192 | + int i = readSocksReply(in, data, deadlineMillis); | |
| 193 | + if (i != 2 || data[1] != 0) { | |
| 194 | + /* RFC 1929 specifies that the connection MUST be closed if | |
| 195 | + authentication fails */ | |
| 196 | + out.close(); | |
| 197 | + in.close(); | |
| 198 | + return false; | |
| 199 | + } | |
| 200 | + /* Authentication succeeded */ | |
| 201 | + return true; | |
| 202 | + } | |
| 203 | + /** | |
| 204 | + * GSSAPI authentication mechanism. | |
| 205 | + * Unfortunately the RFC seems out of sync with the Reference | |
| 206 | + * implementation. I'll leave this in for future completion. | |
| 207 | + */ | |
| 208 | +// if (method == GSSAPI) { | |
| 209 | +// try { | |
| 210 | +// GSSManager manager = GSSManager.getInstance(); | |
| 211 | +// GSSName name = manager.createName("SERVICE:socks@"+server, | |
| 212 | +// null); | |
| 213 | +// GSSContext context = manager.createContext(name, null, null, | |
| 214 | +// GSSContext.DEFAULT_LIFETIME); | |
| 215 | +// context.requestMutualAuth(true); | |
| 216 | +// context.requestReplayDet(true); | |
| 217 | +// context.requestSequenceDet(true); | |
| 218 | +// context.requestCredDeleg(true); | |
| 219 | +// byte []inToken = new byte[0]; | |
| 220 | +// while (!context.isEstablished()) { | |
| 221 | +// byte[] outToken | |
| 222 | +// = context.initSecContext(inToken, 0, inToken.length); | |
| 223 | +// // send the output token if generated | |
| 224 | +// if (outToken != null) { | |
| 225 | +// out.write(1); | |
| 226 | +// out.write(1); | |
| 227 | +// out.writeShort(outToken.length); | |
| 228 | +// out.write(outToken); | |
| 229 | +// out.flush(); | |
| 230 | +// data = new byte[2]; | |
| 231 | +// i = readSocksReply(in, data, deadlineMillis); | |
| 232 | +// if (i != 2 || data[1] == 0xff) { | |
| 233 | +// in.close(); | |
| 234 | +// out.close(); | |
| 235 | +// return false; | |
| 236 | +// } | |
| 237 | +// i = readSocksReply(in, data, deadlineMillis); | |
| 238 | +// int len = 0; | |
| 239 | +// len = ((int)data[0] & 0xff) << 8; | |
| 240 | +// len += data[1]; | |
| 241 | +// data = new byte[len]; | |
| 242 | +// i = readSocksReply(in, data, deadlineMillis); | |
| 243 | +// if (i == len) | |
| 244 | +// return true; | |
| 245 | +// in.close(); | |
| 246 | +// out.close(); | |
| 247 | +// } | |
| 248 | +// } | |
| 249 | +// } catch (GSSException e) { | |
| 250 | +// /* RFC 1961 states that if Context initialisation fails the connection | |
| 251 | +// MUST be closed */ | |
| 252 | +// e.printStackTrace(); | |
| 253 | +// in.close(); | |
| 254 | +// out.close(); | |
| 255 | +// } | |
| 256 | +// } | |
| 257 | + return false; | |
| 258 | + } | |
| 259 | + | |
| 260 | + private void connectV4(InputStream in, OutputStream out, | |
| 261 | + InetSocketAddress endpoint, | |
| 262 | + long deadlineMillis) throws IOException { | |
| 263 | + if (!(endpoint.getAddress() instanceof Inet4Address)) { | |
| 264 | + throw new SocketException("SOCKS V4 requires IPv4 only addresses"); | |
| 265 | + } | |
| 266 | + out.write(PROTO_VERS4); | |
| 267 | + out.write(CONNECT); | |
| 268 | + out.write((endpoint.getPort() >> 8) & 0xff); | |
| 269 | + out.write((endpoint.getPort() >> 0) & 0xff); | |
| 270 | + out.write(endpoint.getAddress().getAddress()); | |
| 271 | + String userName = getUserName(); | |
| 272 | + try { | |
| 273 | + out.write(userName.getBytes("ISO-8859-1")); | |
| 274 | + } catch (java.io.UnsupportedEncodingException uee) { | |
| 275 | + assert false; | |
| 276 | + } | |
| 277 | + out.write(0); | |
| 278 | + out.flush(); | |
| 279 | + byte[] data = new byte[8]; | |
| 280 | + int n = readSocksReply(in, data, deadlineMillis); | |
| 281 | + if (n != 8) | |
| 282 | + throw new SocketException("Reply from SOCKS server has bad length: " + n); | |
| 283 | + if (data[0] != 0 && data[0] != 4) | |
| 284 | + throw new SocketException("Reply from SOCKS server has bad version"); | |
| 285 | + SocketException ex = null; | |
| 286 | + switch (data[1]) { | |
| 287 | + case 90: | |
| 288 | + // Success! | |
| 289 | + external_address = endpoint; | |
| 290 | + break; | |
| 291 | + case 91: | |
| 292 | + ex = new SocketException("SOCKS request rejected"); | |
| 293 | + break; | |
| 294 | + case 92: | |
| 295 | + ex = new SocketException("SOCKS server couldn't reach destination"); | |
| 296 | + break; | |
| 297 | + case 93: | |
| 298 | + ex = new SocketException("SOCKS authentication failed"); | |
| 299 | + break; | |
| 300 | + default: | |
| 301 | + ex = new SocketException("Reply from SOCKS server contains bad status"); | |
| 302 | + break; | |
| 303 | + } | |
| 304 | + if (ex != null) { | |
| 305 | + in.close(); | |
| 306 | + out.close(); | |
| 307 | + throw ex; | |
| 308 | + } | |
| 309 | + } | |
| 310 | + | |
| 311 | + /** | |
| 312 | + * Connects the Socks Socket to the specified endpoint. It will first | |
| 313 | + * connect to the SOCKS proxy and negotiate the access. If the proxy | |
| 314 | + * grants the connections, then the connect is successful and all | |
| 315 | + * further traffic will go to the "real" endpoint. | |
| 316 | + * | |
| 317 | + * @param endpoint the <code>SocketAddress</code> to connect to. | |
| 318 | + * @param timeout the timeout value in milliseconds | |
| 319 | + * @throws IOException if the connection can't be established. | |
| 320 | + * @throws SecurityException if there is a security manager and it | |
| 321 | + * doesn't allow the connection | |
| 322 | + * @throws IllegalArgumentException if endpoint is null or a | |
| 323 | + * SocketAddress subclass not supported by this socket | |
| 324 | + */ | |
| 325 | + @Override | |
| 326 | + protected void connect(SocketAddress endpoint, int timeout) throws IOException { | |
| 327 | + final long deadlineMillis; | |
| 328 | + | |
| 329 | + if (timeout == 0) { | |
| 330 | + deadlineMillis = 0L; | |
| 331 | + } else { | |
| 332 | + long finish = System.currentTimeMillis() + timeout; | |
| 333 | + deadlineMillis = finish < 0 ? Long.MAX_VALUE : finish; | |
| 334 | + } | |
| 335 | + | |
| 336 | + SecurityManager security = System.getSecurityManager(); | |
| 337 | + if (endpoint == null || !(endpoint instanceof InetSocketAddress)) | |
| 338 | + throw new IllegalArgumentException("Unsupported address type"); | |
| 339 | + InetSocketAddress epoint = (InetSocketAddress) endpoint; | |
| 340 | + if (security != null) { | |
| 341 | + if (epoint.isUnresolved()) | |
| 342 | + security.checkConnect(epoint.getHostName(), | |
| 343 | + epoint.getPort()); | |
| 344 | + else | |
| 345 | + security.checkConnect(epoint.getAddress().getHostAddress(), | |
| 346 | + epoint.getPort()); | |
| 347 | + } | |
| 348 | + if (server == null) { | |
| 349 | + // This is the general case | |
| 350 | + // server is not null only when the socket was created with a | |
| 351 | + // specified proxy in which case it does bypass the ProxySelector | |
| 352 | + ProxySelector sel = java.security.AccessController.doPrivileged( | |
| 353 | + new java.security.PrivilegedAction<ProxySelector>() { | |
| 354 | + public ProxySelector run() { | |
| 355 | + return ProxySelector.getDefault(); | |
| 356 | + } | |
| 357 | + }); | |
| 358 | + if (sel == null) { | |
| 359 | + /* | |
| 360 | + * No default proxySelector --> direct connection | |
| 361 | + */ | |
| 362 | + super.connect(epoint, remainingMillis(deadlineMillis)); | |
| 363 | + return; | |
| 364 | + } | |
| 365 | + URI uri; | |
| 366 | + // Use getHostString() to avoid reverse lookups | |
| 367 | + String host = epoint.getHostString(); | |
| 368 | + // IPv6 litteral? | |
| 369 | + if (epoint.getAddress() instanceof Inet6Address && | |
| 370 | + (!host.startsWith("[")) && (host.indexOf(":") >= 0)) { | |
| 371 | + host = "[" + host + "]"; | |
| 372 | + } | |
| 373 | + try { | |
| 374 | + uri = new URI("socket://" + ParseUtil.encodePath(host) + ":"+ epoint.getPort()); | |
| 375 | + } catch (URISyntaxException e) { | |
| 376 | + // This shouldn't happen | |
| 377 | + assert false : e; | |
| 378 | + uri = null; | |
| 379 | + } | |
| 380 | + Proxy p = null; | |
| 381 | + IOException savedExc = null; | |
| 382 | + java.util.Iterator<Proxy> iProxy = null; | |
| 383 | + iProxy = sel.select(uri).iterator(); | |
| 384 | + if (iProxy == null || !(iProxy.hasNext())) { | |
| 385 | + super.connect(epoint, remainingMillis(deadlineMillis)); | |
| 386 | + return; | |
| 387 | + } | |
| 388 | + while (iProxy.hasNext()) { | |
| 389 | + p = iProxy.next(); | |
| 390 | + if (p == null || p == Proxy.NO_PROXY) { | |
| 391 | + super.connect(epoint, remainingMillis(deadlineMillis)); | |
| 392 | + return; | |
| 393 | + } | |
| 394 | + if (p.type() != Proxy.Type.SOCKS) | |
| 395 | + throw new SocketException("Unknown proxy type : " + p.type()); | |
| 396 | + if (!(p.address() instanceof InetSocketAddress)) | |
| 397 | + throw new SocketException("Unknow address type for proxy: " + p); | |
| 398 | + // Use getHostString() to avoid reverse lookups | |
| 399 | + server = ((InetSocketAddress) p.address()).getHostString(); | |
| 400 | + serverPort = ((InetSocketAddress) p.address()).getPort(); | |
| 401 | + if (p instanceof SocksProxy) { | |
| 402 | + if (((SocksProxy)p).protocolVersion() == 4) { | |
| 403 | + useV4 = true; | |
| 404 | + } | |
| 405 | + } | |
| 406 | + | |
| 407 | + // Connects to the SOCKS server | |
| 408 | + try { | |
| 409 | + privilegedConnect(server, serverPort, remainingMillis(deadlineMillis)); | |
| 410 | + // Worked, let's get outta here | |
| 411 | + break; | |
| 412 | + } catch (IOException e) { | |
| 413 | + // Ooops, let's notify the ProxySelector | |
| 414 | + sel.connectFailed(uri,p.address(),e); | |
| 415 | + server = null; | |
| 416 | + serverPort = -1; | |
| 417 | + savedExc = e; | |
| 418 | + // Will continue the while loop and try the next proxy | |
| 419 | + } | |
| 420 | + } | |
| 421 | + | |
| 422 | + /* | |
| 423 | + * If server is still null at this point, none of the proxy | |
| 424 | + * worked | |
| 425 | + */ | |
| 426 | + if (server == null) { | |
| 427 | + throw new SocketException("Can't connect to SOCKS proxy:" | |
| 428 | + + savedExc.getMessage()); | |
| 429 | + } | |
| 430 | + } else { | |
| 431 | + // Connects to the SOCKS server | |
| 432 | + try { | |
| 433 | + privilegedConnect(server, serverPort, remainingMillis(deadlineMillis)); | |
| 434 | + } catch (IOException e) { | |
| 435 | + throw new SocketException(e.getMessage()); | |
| 436 | + } | |
| 437 | + } | |
| 438 | + | |
| 439 | + // cmdIn & cmdOut were intialized during the privilegedConnect() call | |
| 440 | + BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512); | |
| 441 | + InputStream in = cmdIn; | |
| 442 | + | |
| 443 | + if (useV4) { | |
| 444 | + // SOCKS Protocol version 4 doesn't know how to deal with | |
| 445 | + // DOMAIN type of addresses (unresolved addresses here) | |
| 446 | + if (epoint.isUnresolved()) | |
| 447 | + throw new UnknownHostException(epoint.toString()); | |
| 448 | + connectV4(in, out, epoint, deadlineMillis); | |
| 449 | + return; | |
| 450 | + } | |
| 451 | + | |
| 452 | + // This is SOCKS V5 | |
| 453 | + out.write(PROTO_VERS); | |
| 454 | + out.write(2); | |
| 455 | + out.write(NO_AUTH); | |
| 456 | + out.write(USER_PASSW); | |
| 457 | + out.flush(); | |
| 458 | + byte[] data = new byte[2]; | |
| 459 | + int i = readSocksReply(in, data, deadlineMillis); | |
| 460 | + if (i != 2 || ((int)data[0]) != PROTO_VERS) { | |
| 461 | + // Maybe it's not a V5 sever after all | |
| 462 | + // Let's try V4 before we give up | |
| 463 | + // SOCKS Protocol version 4 doesn't know how to deal with | |
| 464 | + // DOMAIN type of addresses (unresolved addresses here) | |
| 465 | + if (epoint.isUnresolved()) | |
| 466 | + throw new UnknownHostException(epoint.toString()); | |
| 467 | + connectV4(in, out, epoint, deadlineMillis); | |
| 468 | + return; | |
| 469 | + } | |
| 470 | + if (((int)data[1]) == NO_METHODS) | |
| 471 | + throw new SocketException("SOCKS : No acceptable methods"); | |
| 472 | + if (!authenticate(data[1], in, out, deadlineMillis)) { | |
| 473 | + throw new SocketException("SOCKS : authentication failed"); | |
| 474 | + } | |
| 475 | + out.write(PROTO_VERS); | |
| 476 | + out.write(CONNECT); | |
| 477 | + out.write(0); | |
| 478 | + /* Test for IPV4/IPV6/Unresolved */ | |
| 479 | + if (epoint.isUnresolved()) { | |
| 480 | + out.write(DOMAIN_NAME); | |
| 481 | + out.write(epoint.getHostName().length()); | |
| 482 | + try { | |
| 483 | + out.write(epoint.getHostName().getBytes("ISO-8859-1")); | |
| 484 | + } catch (java.io.UnsupportedEncodingException uee) { | |
| 485 | + assert false; | |
| 486 | + } | |
| 487 | + out.write((epoint.getPort() >> 8) & 0xff); | |
| 488 | + out.write((epoint.getPort() >> 0) & 0xff); | |
| 489 | + } else if (epoint.getAddress() instanceof Inet6Address) { | |
| 490 | + out.write(IPV6); | |
| 491 | + out.write(epoint.getAddress().getAddress()); | |
| 492 | + out.write((epoint.getPort() >> 8) & 0xff); | |
| 493 | + out.write((epoint.getPort() >> 0) & 0xff); | |
| 494 | + } else { | |
| 495 | + out.write(IPV4); | |
| 496 | + out.write(epoint.getAddress().getAddress()); | |
| 497 | + out.write((epoint.getPort() >> 8) & 0xff); | |
| 498 | + out.write((epoint.getPort() >> 0) & 0xff); | |
| 499 | + } | |
| 500 | + out.flush(); | |
| 501 | + data = new byte[4]; | |
| 502 | + i = readSocksReply(in, data, deadlineMillis); | |
| 503 | + if (i != 4) | |
| 504 | + throw new SocketException("Reply from SOCKS server has bad length"); | |
| 505 | + SocketException ex = null; | |
| 506 | + int len; | |
| 507 | + byte[] addr; | |
| 508 | + switch (data[1]) { | |
| 509 | + case REQUEST_OK: | |
| 510 | + // success! | |
| 511 | + switch(data[3]) { | |
| 512 | + case IPV4: | |
| 513 | + addr = new byte[4]; | |
| 514 | + i = readSocksReply(in, addr, deadlineMillis); | |
| 515 | + if (i != 4) | |
| 516 | + throw new SocketException("Reply from SOCKS server badly formatted"); | |
| 517 | + data = new byte[2]; | |
| 518 | + i = readSocksReply(in, data, deadlineMillis); | |
| 519 | + if (i != 2) | |
| 520 | + throw new SocketException("Reply from SOCKS server badly formatted"); | |
| 521 | + break; | |
| 522 | + case DOMAIN_NAME: | |
| 523 | + len = data[1]; | |
| 524 | + byte[] host = new byte[len]; | |
| 525 | + i = readSocksReply(in, host, deadlineMillis); | |
| 526 | + if (i != len) | |
| 527 | + throw new SocketException("Reply from SOCKS server badly formatted"); | |
| 528 | + data = new byte[2]; | |
| 529 | + i = readSocksReply(in, data, deadlineMillis); | |
| 530 | + if (i != 2) | |
| 531 | + throw new SocketException("Reply from SOCKS server badly formatted"); | |
| 532 | + break; | |
| 533 | + case IPV6: | |
| 534 | + len = data[1]; | |
| 535 | + addr = new byte[len]; | |
| 536 | + i = readSocksReply(in, addr, deadlineMillis); | |
| 537 | + if (i != len) | |
| 538 | + throw new SocketException("Reply from SOCKS server badly formatted"); | |
| 539 | + data = new byte[2]; | |
| 540 | + i = readSocksReply(in, data, deadlineMillis); | |
| 541 | + if (i != 2) | |
| 542 | + throw new SocketException("Reply from SOCKS server badly formatted"); | |
| 543 | + break; | |
| 544 | + default: | |
| 545 | + ex = new SocketException("Reply from SOCKS server contains wrong code"); | |
| 546 | + break; | |
| 547 | + } | |
| 548 | + break; | |
| 549 | + case GENERAL_FAILURE: | |
| 550 | + ex = new SocketException("SOCKS server general failure"); | |
| 551 | + break; | |
| 552 | + case NOT_ALLOWED: | |
| 553 | + ex = new SocketException("SOCKS: Connection not allowed by ruleset"); | |
| 554 | + break; | |
| 555 | + case NET_UNREACHABLE: | |
| 556 | + ex = new SocketException("SOCKS: Network unreachable"); | |
| 557 | + break; | |
| 558 | + case HOST_UNREACHABLE: | |
| 559 | + ex = new SocketException("SOCKS: Host unreachable"); | |
| 560 | + break; | |
| 561 | + case CONN_REFUSED: | |
| 562 | + ex = new SocketException("SOCKS: Connection refused"); | |
| 563 | + break; | |
| 564 | + case TTL_EXPIRED: | |
| 565 | + ex = new SocketException("SOCKS: TTL expired"); | |
| 566 | + break; | |
| 567 | + case CMD_NOT_SUPPORTED: | |
| 568 | + ex = new SocketException("SOCKS: Command not supported"); | |
| 569 | + break; | |
| 570 | + case ADDR_TYPE_NOT_SUP: | |
| 571 | + ex = new SocketException("SOCKS: address type not supported"); | |
| 572 | + break; | |
| 573 | + } | |
| 574 | + if (ex != null) { | |
| 575 | + in.close(); | |
| 576 | + out.close(); | |
| 577 | + throw ex; | |
| 578 | + } | |
| 579 | + external_address = epoint; | |
| 580 | + } | |
| 581 | + | |
| 582 | + private void bindV4(InputStream in, OutputStream out, | |
| 583 | + InetAddress baddr, | |
| 584 | + int lport) throws IOException { | |
| 585 | + if (!(baddr instanceof Inet4Address)) { | |
| 586 | + throw new SocketException("SOCKS V4 requires IPv4 only addresses"); | |
| 587 | + } | |
| 588 | + super.bind(baddr, lport); | |
| 589 | + byte[] addr1 = baddr.getAddress(); | |
| 590 | + /* Test for AnyLocal */ | |
| 591 | + InetAddress naddr = baddr; | |
| 592 | + if (naddr.isAnyLocalAddress()) { | |
| 593 | + naddr = cmdsock.getLocalAddress(); | |
| 594 | + addr1 = naddr.getAddress(); | |
| 595 | + } | |
| 596 | + out.write(PROTO_VERS4); | |
| 597 | + out.write(BIND); | |
| 598 | + out.write((super.getLocalPort() >> 8) & 0xff); | |
| 599 | + out.write((super.getLocalPort() >> 0) & 0xff); | |
| 600 | + out.write(addr1); | |
| 601 | + String userName = getUserName(); | |
| 602 | + try { | |
| 603 | + out.write(userName.getBytes("ISO-8859-1")); | |
| 604 | + } catch (java.io.UnsupportedEncodingException uee) { | |
| 605 | + assert false; | |
| 606 | + } | |
| 607 | + out.write(0); | |
| 608 | + out.flush(); | |
| 609 | + byte[] data = new byte[8]; | |
| 610 | + int n = readSocksReply(in, data); | |
| 611 | + if (n != 8) | |
| 612 | + throw new SocketException("Reply from SOCKS server has bad length: " + n); | |
| 613 | + if (data[0] != 0 && data[0] != 4) | |
| 614 | + throw new SocketException("Reply from SOCKS server has bad version"); | |
| 615 | + SocketException ex = null; | |
| 616 | + switch (data[1]) { | |
| 617 | + case 90: | |
| 618 | + // Success! | |
| 619 | + external_address = new InetSocketAddress(baddr, lport); | |
| 620 | + break; | |
| 621 | + case 91: | |
| 622 | + ex = new SocketException("SOCKS request rejected"); | |
| 623 | + break; | |
| 624 | + case 92: | |
| 625 | + ex = new SocketException("SOCKS server couldn't reach destination"); | |
| 626 | + break; | |
| 627 | + case 93: | |
| 628 | + ex = new SocketException("SOCKS authentication failed"); | |
| 629 | + break; | |
| 630 | + default: | |
| 631 | + ex = new SocketException("Reply from SOCKS server contains bad status"); | |
| 632 | + break; | |
| 633 | + } | |
| 634 | + if (ex != null) { | |
| 635 | + in.close(); | |
| 636 | + out.close(); | |
| 637 | + throw ex; | |
| 638 | + } | |
| 639 | + | |
| 640 | + } | |
| 641 | + | |
| 642 | + /** | |
| 643 | + * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind | |
| 644 | + * means "accept incoming connection from", so the SocketAddress is the | |
| 645 | + * the one of the host we do accept connection from. | |
| 646 | + * | |
| 647 | + * @param addr the Socket address of the remote host. | |
| 648 | + * @exception IOException if an I/O error occurs when binding this socket. | |
| 649 | + */ | |
| 650 | + protected synchronized void socksBind(InetSocketAddress saddr) throws IOException { | |
| 651 | + if (socket != null) { | |
| 652 | + // this is a client socket, not a server socket, don't | |
| 653 | + // call the SOCKS proxy for a bind! | |
| 654 | + return; | |
| 655 | + } | |
| 656 | + | |
| 657 | + // Connects to the SOCKS server | |
| 658 | + | |
| 659 | + if (server == null) { | |
| 660 | + // This is the general case | |
| 661 | + // server is not null only when the socket was created with a | |
| 662 | + // specified proxy in which case it does bypass the ProxySelector | |
| 663 | + ProxySelector sel = java.security.AccessController.doPrivileged( | |
| 664 | + new java.security.PrivilegedAction<ProxySelector>() { | |
| 665 | + public ProxySelector run() { | |
| 666 | + return ProxySelector.getDefault(); | |
| 667 | + } | |
| 668 | + }); | |
| 669 | + if (sel == null) { | |
| 670 | + /* | |
| 671 | + * No default proxySelector --> direct connection | |
| 672 | + */ | |
| 673 | + return; | |
| 674 | + } | |
| 675 | + URI uri; | |
| 676 | + // Use getHostString() to avoid reverse lookups | |
| 677 | + String host = saddr.getHostString(); | |
| 678 | + // IPv6 litteral? | |
| 679 | + if (saddr.getAddress() instanceof Inet6Address && | |
| 680 | + (!host.startsWith("[")) && (host.indexOf(":") >= 0)) { | |
| 681 | + host = "[" + host + "]"; | |
| 682 | + } | |
| 683 | + try { | |
| 684 | + uri = new URI("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort()); | |
| 685 | + } catch (URISyntaxException e) { | |
| 686 | + // This shouldn't happen | |
| 687 | + assert false : e; | |
| 688 | + uri = null; | |
| 689 | + } | |
| 690 | + Proxy p = null; | |
| 691 | + Exception savedExc = null; | |
| 692 | + java.util.Iterator<Proxy> iProxy = null; | |
| 693 | + iProxy = sel.select(uri).iterator(); | |
| 694 | + if (iProxy == null || !(iProxy.hasNext())) { | |
| 695 | + return; | |
| 696 | + } | |
| 697 | + while (iProxy.hasNext()) { | |
| 698 | + p = iProxy.next(); | |
| 699 | + if (p == null || p == Proxy.NO_PROXY) { | |
| 700 | + return; | |
| 701 | + } | |
| 702 | + if (p.type() != Proxy.Type.SOCKS) | |
| 703 | + throw new SocketException("Unknown proxy type : " + p.type()); | |
| 704 | + if (!(p.address() instanceof InetSocketAddress)) | |
| 705 | + throw new SocketException("Unknow address type for proxy: " + p); | |
| 706 | + // Use getHostString() to avoid reverse lookups | |
| 707 | + server = ((InetSocketAddress) p.address()).getHostString(); | |
| 708 | + serverPort = ((InetSocketAddress) p.address()).getPort(); | |
| 709 | + if (p instanceof SocksProxy) { | |
| 710 | + if (((SocksProxy)p).protocolVersion() == 4) { | |
| 711 | + useV4 = true; | |
| 712 | + } | |
| 713 | + } | |
| 714 | + | |
| 715 | + // Connects to the SOCKS server | |
| 716 | + try { | |
| 717 | + AccessController.doPrivileged( | |
| 718 | + new PrivilegedExceptionAction<Void>() { | |
| 719 | + public Void run() throws Exception { | |
| 720 | + cmdsock = new Socket(new PlainSocketImpl()); | |
| 721 | + cmdsock.connect(new InetSocketAddress(server, serverPort)); | |
| 722 | + cmdIn = cmdsock.getInputStream(); | |
| 723 | + cmdOut = cmdsock.getOutputStream(); | |
| 724 | + return null; | |
| 725 | + } | |
| 726 | + }); | |
| 727 | + } catch (Exception e) { | |
| 728 | + // Ooops, let's notify the ProxySelector | |
| 729 | + sel.connectFailed(uri,p.address(),new SocketException(e.getMessage())); | |
| 730 | + server = null; | |
| 731 | + serverPort = -1; | |
| 732 | + cmdsock = null; | |
| 733 | + savedExc = e; | |
| 734 | + // Will continue the while loop and try the next proxy | |
| 735 | + } | |
| 736 | + } | |
| 737 | + | |
| 738 | + /* | |
| 739 | + * If server is still null at this point, none of the proxy | |
| 740 | + * worked | |
| 741 | + */ | |
| 742 | + if (server == null || cmdsock == null) { | |
| 743 | + throw new SocketException("Can't connect to SOCKS proxy:" | |
| 744 | + + savedExc.getMessage()); | |
| 745 | + } | |
| 746 | + } else { | |
| 747 | + try { | |
| 748 | + AccessController.doPrivileged( | |
| 749 | + new PrivilegedExceptionAction<Void>() { | |
| 750 | + public Void run() throws Exception { | |
| 751 | + cmdsock = new Socket(new PlainSocketImpl()); | |
| 752 | + cmdsock.connect(new InetSocketAddress(server, serverPort)); | |
| 753 | + cmdIn = cmdsock.getInputStream(); | |
| 754 | + cmdOut = cmdsock.getOutputStream(); | |
| 755 | + return null; | |
| 756 | + } | |
| 757 | + }); | |
| 758 | + } catch (Exception e) { | |
| 759 | + throw new SocketException(e.getMessage()); | |
| 760 | + } | |
| 761 | + } | |
| 762 | + BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512); | |
| 763 | + InputStream in = cmdIn; | |
| 764 | + if (useV4) { | |
| 765 | + bindV4(in, out, saddr.getAddress(), saddr.getPort()); | |
| 766 | + return; | |
| 767 | + } | |
| 768 | + out.write(PROTO_VERS); | |
| 769 | + out.write(2); | |
| 770 | + out.write(NO_AUTH); | |
| 771 | + out.write(USER_PASSW); | |
| 772 | + out.flush(); | |
| 773 | + byte[] data = new byte[2]; | |
| 774 | + int i = readSocksReply(in, data); | |
| 775 | + if (i != 2 || ((int)data[0]) != PROTO_VERS) { | |
| 776 | + // Maybe it's not a V5 sever after all | |
| 777 | + // Let's try V4 before we give up | |
| 778 | + bindV4(in, out, saddr.getAddress(), saddr.getPort()); | |
| 779 | + return; | |
| 780 | + } | |
| 781 | + if (((int)data[1]) == NO_METHODS) | |
| 782 | + throw new SocketException("SOCKS : No acceptable methods"); | |
| 783 | + if (!authenticate(data[1], in, out)) { | |
| 784 | + throw new SocketException("SOCKS : authentication failed"); | |
| 785 | + } | |
| 786 | + // We're OK. Let's issue the BIND command. | |
| 787 | + out.write(PROTO_VERS); | |
| 788 | + out.write(BIND); | |
| 789 | + out.write(0); | |
| 790 | + int lport = saddr.getPort(); | |
| 791 | + if (saddr.isUnresolved()) { | |
| 792 | + out.write(DOMAIN_NAME); | |
| 793 | + out.write(saddr.getHostName().length()); | |
| 794 | + try { | |
| 795 | + out.write(saddr.getHostName().getBytes("ISO-8859-1")); | |
| 796 | + } catch (java.io.UnsupportedEncodingException uee) { | |
| 797 | + assert false; | |
| 798 | + } | |
287 more lines aren’t shown here.
Binary file not shown.
This diff is large: its 46 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
This diff is large: its 368 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
This diff is large: its 3525 lines aren’t shown here.
Binary file not shown.
This diff is large: its 136 lines aren’t shown here.
Binary file not shown.
This diff is large: its 1311 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This diff is large: its 792 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
This diff is large: its 1798 lines aren’t shown here.
Binary file not shown.
This diff is large: its 208 lines aren’t shown here.
Binary file not shown.
This diff is large: its 294 lines aren’t shown here.
Binary file not shown.
This diff is large: its 591 lines aren’t shown here.
Binary file not shown.
This diff is large: its 52 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
This diff is large: its 57 lines aren’t shown here.
Binary file not shown.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 243 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.