0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package java.net;
0019:
0020: import java.io.IOException;
0021: import java.io.InputStream;
0022: import java.io.OutputStream;
0023: import java.nio.channels.SocketChannel;
0024: import java.security.AccessController;
0025:
0026: import org.apache.harmony.luni.net.NetUtil;
0027: import org.apache.harmony.luni.net.SocketImplProvider;
0028: import org.apache.harmony.luni.platform.Platform;
0029: import org.apache.harmony.luni.util.Msg;
0030: import org.apache.harmony.luni.util.PriviAction;
0031:
0032: /**
0033: * This class represents sockets to be used in connection-oriented (streaming)
0034: * protocols.
0035: */
0036: public class Socket {
0037:
0038: SocketImpl impl;
0039:
0040: static SocketImplFactory factory;
0041:
0042: private volatile boolean isCreated = false;
0043:
0044: private boolean isBound = false;
0045:
0046: private boolean isConnected = false;
0047:
0048: private boolean isClosed = false;
0049:
0050: private boolean isInputShutdown = false;
0051:
0052: private boolean isOutputShutdown = false;
0053:
0054: private static class ConnectLock {
0055: }
0056:
0057: private Object connectLock = new ConnectLock();
0058:
0059: private Proxy proxy;
0060:
0061: static final int MULTICAST_IF = 1;
0062:
0063: static final int MULTICAST_TTL = 2;
0064:
0065: static final int TCP_NODELAY = 4;
0066:
0067: static final int FLAG_SHUTDOWN = 8;
0068:
0069: static {
0070: Platform.getNetworkSystem().oneTimeInitialization(true);
0071: }
0072:
0073: /**
0074: * Construct a connection-oriented Socket. The Socket is created in the
0075: * <code>factory</code> if declared, or otherwise of the default type.
0076: *
0077: * @see SocketImplFactory
0078: */
0079: public Socket() {
0080: impl = factory != null ? factory.createSocketImpl()
0081: : SocketImplProvider.getSocketImpl();
0082: }
0083:
0084: /**
0085: * Constructs a connection-oriented Socket with specified <code>proxy</code>.
0086: *
0087: * Method <code>checkConnect</code> is called if a security manager
0088: * exists, and the proxy host address and port number are passed as
0089: * parameters.
0090: *
0091: * @param proxy
0092: * the specified proxy for this Socket.
0093: * @throws IllegalArgumentException
0094: * if the proxy is null or of an invalid type.
0095: * @throws SecurityException
0096: * if a security manager exists and it denies the permission to
0097: * connect to proxy.
0098: */
0099: public Socket(Proxy proxy) {
0100: if (null == proxy || Proxy.Type.HTTP == proxy.type()) {
0101: // KA023=Proxy is null or invalid type
0102: throw new IllegalArgumentException(Msg.getString("KA023")); //$NON-NLS-1$
0103: }
0104: InetSocketAddress address = (InetSocketAddress) proxy.address();
0105: if (null != address) {
0106: InetAddress addr = address.getAddress();
0107: String host;
0108: if (null != addr) {
0109: host = addr.getHostAddress();
0110: } else {
0111: host = address.getHostName();
0112: }
0113: int port = address.getPort();
0114: checkConnectPermission(host, port);
0115: }
0116: impl = factory != null ? factory.createSocketImpl()
0117: : SocketImplProvider.getSocketImpl(proxy);
0118: this .proxy = proxy;
0119: }
0120:
0121: /**
0122: * Construct a stream socket connected to the nominated destination
0123: * host/port. By default, the socket binds it to any available port on the
0124: * default localhost.
0125: *
0126: * @param dstName
0127: * the destination host to connect to
0128: * @param dstPort
0129: * the port on the destination host to connect to
0130: *
0131: * @throws UnknownHostException
0132: * if the host cannot be resolved
0133: * @throws IOException
0134: * if an error occurs while instantiating the socket
0135: */
0136: public Socket(String dstName, int dstPort)
0137: throws UnknownHostException, IOException {
0138: this ();
0139: InetAddress dstAddress = InetAddress.getByName(dstName);
0140: checkDestination(dstAddress, dstPort);
0141: startupSocket(dstAddress, dstPort, null, 0, true);
0142: }
0143:
0144: /**
0145: * Construct a stream socket connected to the nominated destination
0146: * host/port. The socket is bound it to the nominated localAddress/port.
0147: *
0148: * @param dstName
0149: * the destination host to connect to
0150: * @param dstPort
0151: * the port on the destination host to connect to
0152: * @param localAddress
0153: * the local host address to bind to
0154: * @param localPort
0155: * the local port to bind to
0156: *
0157: * @throws UnknownHostException
0158: * if the host cannot be resolved
0159: * @throws IOException
0160: * if an error occurs while instantiating the socket
0161: */
0162: public Socket(String dstName, int dstPort,
0163: InetAddress localAddress, int localPort) throws IOException {
0164: this ();
0165: InetAddress dstAddress = InetAddress.getByName(dstName);
0166: checkDestination(dstAddress, dstPort);
0167: startupSocket(dstAddress, dstPort, localAddress, localPort,
0168: true);
0169: }
0170:
0171: /**
0172: * Answer a new socket. This constructor is deprecated.
0173: *
0174: * @param hostName
0175: * the host name
0176: * @param port
0177: * the port on the host
0178: * @param streaming
0179: * if true, answer a stream socket, else answer a a datagram
0180: * socket.
0181: *
0182: * @throws UnknownHostException
0183: * if the host cannot be resolved
0184: * @throws IOException
0185: * if an error occurs while instantiating the socket
0186: *
0187: * @deprecated As of JDK 1.1, replaced by Socket
0188: * @see #Socket(String,int)
0189: */
0190: @Deprecated
0191: public Socket(String hostName, int port, boolean streaming)
0192: throws IOException {
0193: this ();
0194: InetAddress host = InetAddress.getByName(hostName);
0195: checkDestination(host, port);
0196: startupSocket(host, port, null, 0, streaming);
0197: }
0198:
0199: /**
0200: * Construct a stream socket connected to the nominated destination host
0201: * address/port. By default, the socket binds it to any available port on
0202: * the default localhost.
0203: *
0204: * @param dstAddress
0205: * the destination host address to connect to
0206: * @param dstPort
0207: * the port on the destination host to connect to
0208: *
0209: * @throws IOException
0210: * if an error occurs while instantiating the socket
0211: */
0212: public Socket(InetAddress dstAddress, int dstPort)
0213: throws IOException {
0214: this ();
0215: checkDestination(dstAddress, dstPort);
0216: startupSocket(dstAddress, dstPort, null, 0, true);
0217: }
0218:
0219: /**
0220: * Construct a stream socket connected to the nominated destination host
0221: * address/port. The socket is bound it to the nominated localAddress/port.
0222: *
0223: * @param dstAddress
0224: * the destination host address to connect to
0225: * @param dstPort
0226: * the port on the destination host to connect to
0227: * @param localAddress
0228: * the local host address to bind to
0229: * @param localPort
0230: * the local port to bind to
0231: *
0232: * @throws IOException
0233: * if an error occurs while instantiating the socket
0234: */
0235: public Socket(InetAddress dstAddress, int dstPort,
0236: InetAddress localAddress, int localPort) throws IOException {
0237: this ();
0238: checkDestination(dstAddress, dstPort);
0239: startupSocket(dstAddress, dstPort, localAddress, localPort,
0240: true);
0241: }
0242:
0243: /**
0244: * Answer a new socket. This constructor is deprecated.
0245: *
0246: * @param addr
0247: * the internet address
0248: * @param port
0249: * the port on the host
0250: * @param streaming
0251: * if true, answer a stream socket, else answer a datagram
0252: * socket.
0253: *
0254: * @throws UnknownHostException
0255: * if the host cannot be resolved
0256: * @throws IOException
0257: * if an error occurs while instantiating the socket
0258: *
0259: * @deprecated As of JDK 1.1, replaced by Socket
0260: * @see #Socket(InetAddress,int)
0261: */
0262: @Deprecated
0263: public Socket(InetAddress addr, int port, boolean streaming)
0264: throws IOException {
0265: this ();
0266: checkDestination(addr, port);
0267: startupSocket(addr, port, null, 0, streaming);
0268: }
0269:
0270: /**
0271: * Creates an unconnected socket, wrapping the <code>socketImpl</code>
0272: * argument.
0273: *
0274: * @param anImpl
0275: * the socket to wrap
0276: *
0277: * @throws SocketException
0278: * if an error occurs assigning the implementation
0279: */
0280: protected Socket(SocketImpl anImpl) throws SocketException {
0281: impl = anImpl;
0282: }
0283:
0284: /**
0285: * Check the connection destination satisfies the security policy and is in
0286: * the valid port range.
0287: *
0288: * @param destAddr
0289: * the destination host address
0290: * @param dstPort
0291: * the port on the destination host
0292: */
0293: void checkDestination(InetAddress destAddr, int dstPort) {
0294: if (dstPort < 0 || dstPort > 65535) {
0295: throw new IllegalArgumentException(Msg.getString("K0032")); //$NON-NLS-1$
0296: }
0297: checkConnectPermission(destAddr.getHostName(), dstPort);
0298: }
0299:
0300: /*
0301: * Checks the connection destination satisfies the security policy.
0302: *
0303: * @param hostname the destination hostname @param dstPort the port on the
0304: * destination host
0305: */
0306: private void checkConnectPermission(String hostname, int dstPort) {
0307: SecurityManager security = System.getSecurityManager();
0308: if (security != null) {
0309: security.checkConnect(hostname, dstPort);
0310: }
0311: }
0312:
0313: /**
0314: * Close the socket. It is not valid to use the socket thereafter.
0315: *
0316: * @throws IOException
0317: * if an error occurs during the close
0318: */
0319: public synchronized void close() throws IOException {
0320: isClosed = true;
0321: impl.close();
0322: }
0323:
0324: /**
0325: * Returns an {@link InetAddress} instance representing the address this
0326: * socket has connected to.
0327: *
0328: * @return if this socket is connected, the address it is connected to. A
0329: * <code>null</code> return signifies no connection has been made.
0330: */
0331: public InetAddress getInetAddress() {
0332: if (!isConnected()) {
0333: return null;
0334: }
0335: return impl.getInetAddress();
0336: }
0337:
0338: /**
0339: * Answer the socket input stream, to read byte data off the socket. Note,
0340: * multiple input streams may be created on a single socket.
0341: *
0342: * @return a byte oriented read stream for this socket
0343: *
0344: * @throws IOException
0345: * if an error occurs creating the stream
0346: *
0347: * @see org.apache.harmony.luni.net.SocketInputStream
0348: */
0349: public InputStream getInputStream() throws IOException {
0350: checkClosedAndCreate(false);
0351: if (isInputShutdown()) {
0352: throw new SocketException(Msg.getString("K0321")); //$NON-NLS-1$
0353: }
0354: return impl.getInputStream();
0355: }
0356:
0357: /**
0358: * Answer the SO_KEEPALIVE option for this socket.
0359: *
0360: * @return the socket SO_KEEPALIVE option setting
0361: *
0362: * @throws SocketException
0363: * if an error occurs on the option access
0364: */
0365: public boolean getKeepAlive() throws SocketException {
0366: checkClosedAndCreate(true);
0367: return ((Boolean) impl.getOption(SocketOptions.SO_KEEPALIVE))
0368: .booleanValue();
0369: }
0370:
0371: /**
0372: * Returns an {@link InetAddress} instance representing the <i>local</i>
0373: * address this socket is bound to.
0374: *
0375: * @return the local address that this socket has bound to
0376: */
0377: public InetAddress getLocalAddress() {
0378: if (!isBound()) {
0379: return InetAddress.ANY;
0380: }
0381: return Platform.getNetworkSystem().getSocketLocalAddress(
0382: impl.fd, InetAddress.preferIPv6Addresses());
0383: }
0384:
0385: /**
0386: * Answer the local port to which the socket is bound.
0387: *
0388: * @return the local port to which the socket is bound
0389: */
0390: public int getLocalPort() {
0391: if (!isBound()) {
0392: return -1;
0393: }
0394: return impl.getLocalPort();
0395: }
0396:
0397: /**
0398: * Answer the socket output stream, for writing byte data on the socket.
0399: * Note, multiplie output streams may be created on a single socket.
0400: *
0401: * @return OutputStream a byte oriented write stream for this socket
0402: *
0403: * @throws IOException
0404: * if an error occurs creating the stream
0405: *
0406: * @see org.apache.harmony.luni.net.SocketOutputStream
0407: */
0408: public OutputStream getOutputStream() throws IOException {
0409: checkClosedAndCreate(false);
0410: if (isOutputShutdown()) {
0411: throw new SocketException(Msg.getString("KA00f")); //$NON-NLS-1$
0412: }
0413: return impl.getOutputStream();
0414: }
0415:
0416: /**
0417: * Returns the number of the remote port this socket is connected to.
0418: *
0419: * @return int the remote port number that this socket has connected to. A
0420: * return of <code>0</code> (zero) indicates that there is no
0421: * connection in place.
0422: */
0423: public int getPort() {
0424: if (!isConnected()) {
0425: return 0;
0426: }
0427: return impl.getPort();
0428: }
0429:
0430: /**
0431: * Answer the linger-on-close timeout for this socket (the SO_LINGER value).
0432: *
0433: * @return this socket's SO_LINGER value. A value of <code>-1</code> will
0434: * be returned if the option is not enabled.
0435: *
0436: * @throws SocketException
0437: * if an error occurs on querying this property
0438: */
0439: public int getSoLinger() throws SocketException {
0440: checkClosedAndCreate(true);
0441: return ((Integer) impl.getOption(SocketOptions.SO_LINGER))
0442: .intValue();
0443: }
0444:
0445: /**
0446: * Answer the socket receive buffer size (SO_RCVBUF).
0447: *
0448: * @return socket receive buffer size
0449: *
0450: * @throws SocketException
0451: * if an error occurs on the option access
0452: */
0453: public synchronized int getReceiveBufferSize()
0454: throws SocketException {
0455: checkClosedAndCreate(true);
0456: return ((Integer) impl.getOption(SocketOptions.SO_RCVBUF))
0457: .intValue();
0458: }
0459:
0460: /**
0461: * Answer the socket send buffer size (SO_SNDBUF).
0462: *
0463: * @return socket send buffer size
0464: *
0465: * @throws SocketException
0466: * if an error occurs on the option access
0467: */
0468: public synchronized int getSendBufferSize() throws SocketException {
0469: checkClosedAndCreate(true);
0470: return ((Integer) impl.getOption(SocketOptions.SO_SNDBUF))
0471: .intValue();
0472: }
0473:
0474: /**
0475: * Answer the socket read timeout. The SO_TIMEOUT option, a value of 0
0476: * indicates it is disabled and a read operation will block indefinitely
0477: * waiting for data.
0478: *
0479: * @return the socket read timeout
0480: *
0481: * @throws SocketException
0482: * if an error occurs on the option access
0483: */
0484: public synchronized int getSoTimeout() throws SocketException {
0485: checkClosedAndCreate(true);
0486: return ((Integer) impl.getOption(SocketOptions.SO_TIMEOUT))
0487: .intValue();
0488: }
0489:
0490: /**
0491: * Answer true if the socket is using Nagle's algorithm. The TCP_NODELAY
0492: * option setting.
0493: *
0494: * @return the socket TCP_NODELAY option setting
0495: *
0496: * @throws SocketException
0497: * if an error occurs on the option access
0498: */
0499: public boolean getTcpNoDelay() throws SocketException {
0500: checkClosedAndCreate(true);
0501: return ((Boolean) impl.getOption(SocketOptions.TCP_NODELAY))
0502: .booleanValue();
0503: }
0504:
0505: /**
0506: * Set the SO_KEEPALIVE option for this socket.
0507: *
0508: * @param value
0509: * the socket SO_KEEPALIVE option setting
0510: *
0511: * @throws SocketException
0512: * if an error occurs setting the option
0513: */
0514: public void setKeepAlive(boolean value) throws SocketException {
0515: if (impl != null) {
0516: checkClosedAndCreate(true);
0517: impl.setOption(SocketOptions.SO_KEEPALIVE,
0518: value ? Boolean.TRUE : Boolean.FALSE);
0519: }
0520: }
0521:
0522: /**
0523: * Specifies the application's socket implementation factory. This may only
0524: * be executed the once over the lifetime of the application.
0525: *
0526: * @param fac
0527: * the socket factory to set
0528: * @exception IOException
0529: * thrown if the factory has already been set
0530: */
0531: public static synchronized void setSocketImplFactory(
0532: SocketImplFactory fac) throws IOException {
0533: SecurityManager security = System.getSecurityManager();
0534: if (security != null) {
0535: security.checkSetFactory();
0536: }
0537: if (factory != null) {
0538: throw new SocketException(Msg.getString("K0044")); //$NON-NLS-1$
0539: }
0540: factory = fac;
0541: }
0542:
0543: /**
0544: * Set the socket send buffer size.
0545: *
0546: * @param size
0547: * the buffer size, in bytes
0548: *
0549: * @throws SocketException
0550: * if an error occurs while setting the size or the size is
0551: * invalid.
0552: */
0553: public synchronized void setSendBufferSize(int size)
0554: throws SocketException {
0555: checkClosedAndCreate(true);
0556: if (size < 1) {
0557: throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$
0558: }
0559: impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size));
0560: }
0561:
0562: /**
0563: * Set the socket receive buffer size.
0564: *
0565: * @param size
0566: * the buffer size, in bytes
0567: *
0568: * @throws SocketException
0569: * tf an error occurs while setting the size or the size is
0570: * invalid.
0571: */
0572: public synchronized void setReceiveBufferSize(int size)
0573: throws SocketException {
0574: checkClosedAndCreate(true);
0575: if (size < 1) {
0576: throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$
0577: }
0578: impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
0579: }
0580:
0581: /**
0582: * Set the SO_LINGER option, with the specified time, in seconds. The
0583: * SO_LINGER option is silently limited to 65535 seconds.
0584: *
0585: * @param on
0586: * if linger is enabled
0587: * @param timeout
0588: * the linger timeout value, in seconds
0589: *
0590: * @throws SocketException
0591: * if an error occurs setting the option
0592: */
0593: public void setSoLinger(boolean on, int timeout)
0594: throws SocketException {
0595: checkClosedAndCreate(true);
0596: if (on && timeout < 0) {
0597: throw new IllegalArgumentException(Msg.getString("K0045")); //$NON-NLS-1$
0598: }
0599: int val = on ? (65535 < timeout ? 65535 : timeout) : -1;
0600: impl.setOption(SocketOptions.SO_LINGER, Integer.valueOf(val));
0601: }
0602:
0603: /**
0604: * Set the read timeout on this socket. The SO_TIMEOUT option, is specified
0605: * in milliseconds. The read operation will block indefinitely for a zero
0606: * value.
0607: *
0608: * @param timeout
0609: * the read timeout value
0610: *
0611: * @throws SocketException
0612: * if an error occurs setting the option
0613: */
0614: public synchronized void setSoTimeout(int timeout)
0615: throws SocketException {
0616: checkClosedAndCreate(true);
0617: if (timeout < 0) {
0618: throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$
0619: }
0620: impl.setOption(SocketOptions.SO_TIMEOUT, Integer
0621: .valueOf(timeout));
0622: }
0623:
0624: /**
0625: * Set whether the socket is to use Nagle's algorithm. The TCP_NODELAY
0626: * option setting.
0627: *
0628: * @param on
0629: * the socket TCP_NODELAY option setting
0630: *
0631: * @throws SocketException
0632: * if an error occurs setting the option
0633: */
0634: public void setTcpNoDelay(boolean on) throws SocketException {
0635: checkClosedAndCreate(true);
0636: impl.setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
0637: }
0638:
0639: /**
0640: * Creates a stream socket, binds it to the nominated local address/port,
0641: * then connects it to the nominated destination address/port.
0642: *
0643: * @param dstAddress
0644: * the destination host address
0645: * @param dstPort
0646: * the port on the destination host
0647: * @param localAddress
0648: * the address on the local machine to bind
0649: * @param localPort
0650: * the port on the local machine to bind
0651: *
0652: * @throws IOException
0653: * thrown if a error occurs during the bind or connect
0654: * operations
0655: */
0656: void startupSocket(InetAddress dstAddress, int dstPort,
0657: InetAddress localAddress, int localPort, boolean streaming)
0658: throws IOException {
0659:
0660: if (localPort < 0 || localPort > 65535) {
0661: throw new IllegalArgumentException(Msg.getString("K0046")); //$NON-NLS-1$
0662: }
0663:
0664: InetAddress addr = localAddress == null ? InetAddress.ANY
0665: : localAddress;
0666: synchronized (this ) {
0667: impl.create(streaming);
0668: isCreated = true;
0669: try {
0670: if (!streaming || !NetUtil.usingSocks(proxy)) {
0671: impl.bind(addr, localPort);
0672: }
0673: isBound = true;
0674: impl.connect(dstAddress, dstPort);
0675: isConnected = true;
0676: } catch (IOException e) {
0677: impl.close();
0678: throw e;
0679: }
0680: }
0681: }
0682:
0683: /**
0684: * Answers a string containing a concise, human-readable description of the
0685: * socket.
0686: *
0687: * @return the description
0688: */
0689: @Override
0690: public String toString() {
0691: if (!isConnected()) {
0692: return "Socket[unconnected]"; //$NON-NLS-1$
0693: }
0694: return impl.toString();
0695: }
0696:
0697: /**
0698: * Shutdown the input portion of the socket.
0699: *
0700: * @throws IOException
0701: * if an error occurs while closing the socket input
0702: * @throws SocketException
0703: * if the socket is closed
0704: */
0705: public void shutdownInput() throws IOException {
0706: if (isInputShutdown()) {
0707: throw new SocketException(Msg.getString("K0321")); //$NON-NLS-1$
0708: }
0709: checkClosedAndCreate(false);
0710: impl.shutdownInput();
0711: isInputShutdown = true;
0712: }
0713:
0714: /**
0715: * Shutdown the output portion of the socket.
0716: *
0717: * @throws IOException
0718: * if an error occurs while closing the socket output
0719: * @throws SocketException
0720: * if the socket is closed
0721: */
0722: public void shutdownOutput() throws IOException {
0723: if (isOutputShutdown()) {
0724: throw new SocketException(Msg.getString("KA00f")); //$NON-NLS-1$
0725: }
0726: checkClosedAndCreate(false);
0727: impl.shutdownOutput();
0728: isOutputShutdown = true;
0729: }
0730:
0731: /**
0732: * Check if the socket is closed, and throw an exception. Otherwise create
0733: * the underlying SocketImpl.
0734: *
0735: * @throws SocketException
0736: * if the socket is closed
0737: */
0738: private void checkClosedAndCreate(boolean create)
0739: throws SocketException {
0740: if (isClosed()) {
0741: throw new SocketException(Msg.getString("K003d")); //$NON-NLS-1$
0742: }
0743: if (!create) {
0744: if (!isConnected()) {
0745: throw new SocketException(Msg.getString("K0320")); //$NON-NLS-1$
0746: // a connected socket must be created
0747: }
0748:
0749: /*
0750: * return directly to fix a possible bug, if !create, should return
0751: * here
0752: */
0753: return;
0754: }
0755: if (isCreated) {
0756: return;
0757: }
0758: synchronized (this ) {
0759: if (isCreated) {
0760: return;
0761: }
0762: try {
0763: impl.create(true);
0764: } catch (SocketException e) {
0765: throw e;
0766: } catch (IOException e) {
0767: throw new SocketException(e.toString());
0768: }
0769: isCreated = true;
0770: }
0771: }
0772:
0773: /**
0774: * Answer the local SocketAddress for this socket, or null if the socket is
0775: * not bound.
0776: * <p>
0777: * This is useful on multihomed hosts.
0778: *
0779: * @return the local socket address
0780: */
0781: public SocketAddress getLocalSocketAddress() {
0782: if (!isBound()) {
0783: return null;
0784: }
0785: return new InetSocketAddress(getLocalAddress(), getLocalPort());
0786: }
0787:
0788: /**
0789: * Answer the remote SocketAddress for this socket, or null if the socket is
0790: * not connected.
0791: *
0792: * @return the remote socket address
0793: */
0794: public SocketAddress getRemoteSocketAddress() {
0795: if (!isConnected()) {
0796: return null;
0797: }
0798: return new InetSocketAddress(getInetAddress(), getPort());
0799: }
0800:
0801: /**
0802: * Return if the socket is bound to a local address and port.
0803: *
0804: * @return <code>true</code> if the socket is bound to a local address,
0805: * <code>false</code> otherwise.
0806: */
0807: public boolean isBound() {
0808: return isBound;
0809: }
0810:
0811: /**
0812: * Return if the socket is connected.
0813: *
0814: * @return <code>true</code> if the socket is connected,
0815: * <code>false</code> otherwise.
0816: */
0817: public boolean isConnected() {
0818: return isConnected;
0819: }
0820:
0821: /**
0822: * Return if the socket is closed.
0823: *
0824: * @return <code>true</code> if the socket is closed, <code>false</code>
0825: * otherwise.
0826: */
0827: public boolean isClosed() {
0828: return isClosed;
0829: }
0830:
0831: /**
0832: * Bind the Socket to the nominated local host/port.
0833: *
0834: * @param localAddr
0835: * the local machine address and port to bind on
0836: *
0837: * @throws IllegalArgumentException
0838: * if the SocketAddress is not supported
0839: * @throws IOException
0840: * if the socket is already bound, or a problem occurs during
0841: * the bind
0842: */
0843: public void bind(SocketAddress localAddr) throws IOException {
0844: checkClosedAndCreate(true);
0845: if (isBound()) {
0846: throw new BindException(Msg.getString("K0315")); //$NON-NLS-1$
0847: }
0848:
0849: int port = 0;
0850: InetAddress addr = InetAddress.ANY;
0851: if (localAddr != null) {
0852: if (!(localAddr instanceof InetSocketAddress)) {
0853: throw new IllegalArgumentException(Msg.getString(
0854: "K0316", localAddr.getClass())); //$NON-NLS-1$
0855: }
0856: InetSocketAddress inetAddr = (InetSocketAddress) localAddr;
0857: if ((addr = inetAddr.getAddress()) == null) {
0858: throw new SocketException(Msg.getString(
0859: "K0317", inetAddr.getHostName())); //$NON-NLS-1$
0860: }
0861: port = inetAddr.getPort();
0862: }
0863:
0864: synchronized (this ) {
0865: try {
0866: impl.bind(addr, port);
0867: isBound = true;
0868: } catch (IOException e) {
0869: impl.close();
0870: throw e;
0871: }
0872: }
0873: }
0874:
0875: /**
0876: * Connect the Socket to the host/port specified by the SocketAddress.
0877: *
0878: * @param remoteAddr
0879: * the remote machine address and port to connect to
0880: *
0881: * @throws IllegalArgumentException
0882: * if the SocketAddress is not supported
0883: * @throws IOException
0884: * if the socket is already connected, or a problem occurs
0885: * during the connect
0886: */
0887: public void connect(SocketAddress remoteAddr) throws IOException {
0888: connect(remoteAddr, 0);
0889: }
0890:
0891: /**
0892: * Connect the Socket to the host/port specified by the SocketAddress with a
0893: * specified timeout.
0894: *
0895: * @param remoteAddr
0896: * the remote machine address and port to connect to
0897: * @param timeout
0898: * the millisecond timeout value, the connect will block
0899: * indefinitely for a zero value.
0900: *
0901: * @throws IllegalArgumentException
0902: * if the timeout is negative, or the SocketAddress is not
0903: * supported
0904: * @throws IOException
0905: * if the socket is already connected, or a problem occurs
0906: * during the connect
0907: */
0908: public void connect(SocketAddress remoteAddr, int timeout)
0909: throws IOException {
0910: checkClosedAndCreate(true);
0911: if (timeout < 0) {
0912: throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$
0913: }
0914: if (isConnected()) {
0915: throw new SocketException(Msg.getString("K0079")); //$NON-NLS-1$
0916: }
0917: if (remoteAddr == null) {
0918: throw new IllegalArgumentException(Msg.getString("K0318")); //$NON-NLS-1$
0919: }
0920:
0921: if (!(remoteAddr instanceof InetSocketAddress)) {
0922: throw new IllegalArgumentException(Msg.getString(
0923: "K0316", remoteAddr.getClass())); //$NON-NLS-1$
0924: }
0925: InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
0926: InetAddress addr;
0927: if ((addr = inetAddr.getAddress()) == null) {
0928: throw new UnknownHostException(Msg.getString(
0929: "K0317", remoteAddr));//$NON-NLS-1$
0930: }
0931: int port = inetAddr.getPort();
0932:
0933: checkDestination(addr, port);
0934: synchronized (connectLock) {
0935: try {
0936: if (!isBound()) {
0937: // socket allready created at this point by earlier call or
0938: // checkClosedAndCreate this caused us to lose socket
0939: // options on create
0940: // impl.create(true);
0941: if (!NetUtil.usingSocks(proxy)) {
0942: impl.bind(InetAddress.ANY, 0);
0943: }
0944: isBound = true;
0945: }
0946: impl.connect(remoteAddr, timeout);
0947: isConnected = true;
0948: } catch (IOException e) {
0949: impl.close();
0950: throw e;
0951: }
0952: }
0953: }
0954:
0955: /**
0956: * Return if {@link #shutdownInput} has been called.
0957: *
0958: * @return <code>true</code> if <code>shutdownInput</code> has been
0959: * called, <code>false</code> otherwise.
0960: */
0961: public boolean isInputShutdown() {
0962: return isInputShutdown;
0963: }
0964:
0965: /**
0966: * Return if {@link #shutdownOutput} has been called.
0967: *
0968: * @return <code>true</code> if <code>shutdownOutput</code> has been
0969: * called, <code>false</code> otherwise.
0970: */
0971: public boolean isOutputShutdown() {
0972: return isOutputShutdown;
0973: }
0974:
0975: /**
0976: * Set the SO_REUSEADDR socket option.
0977: *
0978: * @param reuse
0979: * the socket SO_REUSEADDR option setting
0980: *
0981: * @throws SocketException
0982: * if the socket is closed or the option is invalid.
0983: */
0984: public void setReuseAddress(boolean reuse) throws SocketException {
0985: checkClosedAndCreate(true);
0986: impl.setOption(SocketOptions.SO_REUSEADDR, reuse ? Boolean.TRUE
0987: : Boolean.FALSE);
0988: }
0989:
0990: /**
0991: * Get the state of the SO_REUSEADDR socket option.
0992: *
0993: * @return <code>true</code> if the SO_REUSEADDR is enabled,
0994: * <code>false</code> otherwise.
0995: *
0996: * @throws SocketException
0997: * if the socket is closed or the option is invalid.
0998: */
0999: public boolean getReuseAddress() throws SocketException {
1000: checkClosedAndCreate(true);
1001: return ((Boolean) impl.getOption(SocketOptions.SO_REUSEADDR))
1002: .booleanValue();
1003: }
1004:
1005: /**
1006: * Set the SO_OOBINLINE socket option. When this option is enabled, out of
1007: * band data is recieved in the normal data stream.
1008: *
1009: * @param oobinline
1010: * the socket SO_OOBINLINE option setting
1011: *
1012: * @throws SocketException
1013: * if the socket is closed or the option is invalid.
1014: */
1015: public void setOOBInline(boolean oobinline) throws SocketException {
1016: checkClosedAndCreate(true);
1017: impl.setOption(SocketOptions.SO_OOBINLINE,
1018: oobinline ? Boolean.TRUE : Boolean.FALSE);
1019: }
1020:
1021: /**
1022: * Get the state of the SO_OOBINLINE socket option.
1023: *
1024: * @return <code>true</code> if the SO_OOBINLINE is enabled,
1025: * <code>false</code> otherwise.
1026: *
1027: * @throws SocketException
1028: * if the socket is closed or the option is invalid.
1029: */
1030: public boolean getOOBInline() throws SocketException {
1031: checkClosedAndCreate(true);
1032: return ((Boolean) impl.getOption(SocketOptions.SO_OOBINLINE))
1033: .booleanValue();
1034: }
1035:
1036: /**
1037: * Set the IP_TOS socket option.
1038: *
1039: * @param value
1040: * the socket IP_TOS setting
1041: *
1042: * @throws SocketException
1043: * if the socket is closed or the option is invalid.
1044: */
1045: public void setTrafficClass(int value) throws SocketException {
1046: checkClosedAndCreate(true);
1047: if (value < 0 || value > 255) {
1048: throw new IllegalArgumentException();
1049: }
1050: impl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value));
1051: }
1052:
1053: /**
1054: * Get the IP_TOS socket option.
1055: *
1056: * @return the IP_TOS socket option value
1057: *
1058: * @throws SocketException
1059: * if the option is invalid
1060: */
1061: public int getTrafficClass() throws SocketException {
1062: checkClosedAndCreate(true);
1063: return ((Number) impl.getOption(SocketOptions.IP_TOS))
1064: .intValue();
1065: }
1066:
1067: /**
1068: * Send the single byte of urgent data on the socket.
1069: *
1070: * @param value
1071: * the byte of urgent data
1072: *
1073: * @exception IOException
1074: * when an error occurs sending urgent data
1075: */
1076: public void sendUrgentData(int value) throws IOException {
1077: if (!impl.supportsUrgentData()) {
1078: throw new SocketException(Msg.getString("K0333")); //$NON-NLS-1$
1079: }
1080: impl.sendUrgentData(value);
1081: }
1082:
1083: /**
1084: * Set the appropriate flags for a Socket created by ServerSocket.accept().
1085: *
1086: * @see ServerSocket#implAccept
1087: */
1088: void accepted() {
1089: isCreated = isBound = isConnected = true;
1090: }
1091:
1092: static boolean preferIPv4Stack() {
1093: String result = AccessController
1094: .doPrivileged(new PriviAction<String>(
1095: "java.net.preferIPv4Stack")); //$NON-NLS-1$
1096: return "true".equals(result); //$NON-NLS-1$
1097: }
1098:
1099: /**
1100: * if Socket is created by a SocketChannel, returns the related
1101: * SocketChannel
1102: *
1103: * @return the related SocketChannel
1104: */
1105: public SocketChannel getChannel() {
1106: return null;
1107: }
1108:
1109: /**
1110: * sets performance preference for connectionTime,latency and bandwidth
1111: *
1112: * @param connectionTime
1113: * the importance of connect time
1114: * @param latency
1115: * the importance of latency
1116: * @param bandwidth
1117: * the importance of bandwidth
1118: */
1119: public void setPerformancePreferences(int connectionTime,
1120: int latency, int bandwidth) {
1121: // Our socket implementation only provide one protocol: TCP/IP, so
1122: // we do nothing for this method
1123: }
1124: }
|