/luni/src/main/java/java/net/Socket.java
Java | 1153 lines | 447 code | 75 blank | 631 comment | 71 complexity | 422775a4f7a877ca30ba10f89b8a25f5 MD5 | raw file
Possible License(s): JSON, BSD-3-Clause
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package java.net;
19
20import java.io.IOException;
21import java.io.InputStream;
22import java.io.OutputStream;
23import java.nio.channels.SocketChannel;
24import org.apache.harmony.luni.net.PlainSocketImpl;
25import org.apache.harmony.luni.platform.Platform;
26
27/**
28 * Provides a client-side TCP socket.
29 */
30public class Socket {
31 private static SocketImplFactory factory;
32
33 final SocketImpl impl;
34 private final Proxy proxy;
35
36 volatile boolean isCreated = false;
37 private boolean isBound = false;
38 private boolean isConnected = false;
39 private boolean isClosed = false;
40 private boolean isInputShutdown = false;
41 private boolean isOutputShutdown = false;
42
43 private InetAddress localAddress = Inet4Address.ANY;
44
45 private static class ConnectLock {
46 }
47
48 private final Object connectLock = new ConnectLock();
49
50 /**
51 * Creates a new unconnected socket. When a SocketImplFactory is defined it
52 * creates the internal socket implementation, otherwise the default socket
53 * implementation will be used for this socket.
54 *
55 * @see SocketImplFactory
56 * @see SocketImpl
57 */
58 public Socket() {
59 this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl();
60 this.proxy = null;
61 }
62
63 /**
64 * Creates a new unconnected socket using the given proxy type. When a
65 * {@code SocketImplFactory} is defined it creates the internal socket
66 * implementation, otherwise the default socket implementation will be used
67 * for this socket.
68 * <p>
69 * Example that will create a socket connection through a {@code SOCKS}
70 * proxy server: <br>
71 * {@code Socket sock = new Socket(new Proxy(Proxy.Type.SOCKS, new
72 * InetSocketAddress("test.domain.org", 2130)));}
73 *
74 * @param proxy
75 * the specified proxy for this socket.
76 * @throws IllegalArgumentException
77 * if the argument {@code proxy} is {@code null} or of an
78 * invalid type.
79 * @throws SecurityException
80 * if a security manager exists and it denies the permission to
81 * connect to the given proxy.
82 * @see SocketImplFactory
83 * @see SocketImpl
84 */
85 public Socket(Proxy proxy) {
86 this.proxy = proxy;
87 if (proxy == null || proxy.type() == Proxy.Type.HTTP) {
88 throw new IllegalArgumentException("Proxy is null or invalid type");
89 }
90 InetSocketAddress address = (InetSocketAddress) proxy.address();
91 if (null != address) {
92 InetAddress addr = address.getAddress();
93 String host;
94 if (null != addr) {
95 host = addr.getHostAddress();
96 } else {
97 host = address.getHostName();
98 }
99 int port = address.getPort();
100 checkConnectPermission(host, port);
101 }
102 this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl(proxy);
103 }
104
105 // BEGIN android-added
106 /**
107 * Tries to connect a socket to all IP addresses of the given hostname.
108 *
109 * @param dstName
110 * the target host name or IP address to connect to.
111 * @param dstPort
112 * the port on the target host to connect to.
113 * @param localAddress
114 * the address on the local host to bind to.
115 * @param localPort
116 * the port on the local host to bind to.
117 * @param streaming
118 * if {@code true} a streaming socket is returned, a datagram
119 * socket otherwise.
120 * @throws UnknownHostException
121 * if the host name could not be resolved into an IP address.
122 * @throws IOException
123 * if an error occurs while creating the socket.
124 * @throws SecurityException
125 * if a security manager exists and it denies the permission to
126 * connect to the given address and port.
127 */
128 private void tryAllAddresses(String dstName, int dstPort, InetAddress
129 localAddress, int localPort, boolean streaming) throws IOException {
130 InetAddress[] dstAddresses = InetAddress.getAllByName(dstName);
131 // Loop through all the destination addresses except the last, trying to
132 // connect to each one and ignoring errors. There must be at least one
133 // address, or getAllByName would have thrown UnknownHostException.
134 InetAddress dstAddress;
135 for (int i = 0; i < dstAddresses.length - 1; i++) {
136 dstAddress = dstAddresses[i];
137 try {
138 checkDestination(dstAddress, dstPort);
139 startupSocket(dstAddress, dstPort, localAddress, localPort, streaming);
140 return;
141 } catch (SecurityException e1) {
142 } catch (IOException e2) {
143 }
144 }
145
146 // Now try to connect to the last address in the array, handing back to
147 // the caller any exceptions that are thrown.
148 dstAddress = dstAddresses[dstAddresses.length - 1];
149 checkDestination(dstAddress, dstPort);
150 startupSocket(dstAddress, dstPort, localAddress, localPort, streaming);
151 }
152 // END android-added
153
154 /**
155 * Creates a new streaming socket connected to the target host specified by
156 * the parameters {@code dstName} and {@code dstPort}. The socket is bound
157 * to any available port on the local host.
158 * <p><strong>Implementation note:</strong> this implementation tries each
159 * IP address for the given hostname until it either connects successfully
160 * or it exhausts the set. It will try both IPv4 and IPv6 addresses in the
161 * order specified by the system property {@code "java.net.preferIPv6Addresses"}.
162 *
163 * @param dstName
164 * the target host name or IP address to connect to.
165 * @param dstPort
166 * the port on the target host to connect to.
167 * @throws UnknownHostException
168 * if the host name could not be resolved into an IP address.
169 * @throws IOException
170 * if an error occurs while creating the socket.
171 * @throws SecurityException
172 * if a security manager exists and it denies the permission to
173 * connect to the given address and port.
174 */
175 public Socket(String dstName, int dstPort) throws UnknownHostException, IOException {
176 this(dstName, dstPort, null, 0);
177 }
178
179 /**
180 * Creates a new streaming socket connected to the target host specified by
181 * the parameters {@code dstName} and {@code dstPort}. On the local endpoint
182 * the socket is bound to the given address {@code localAddress} on port
183 * {@code localPort}.
184 *
185 * If {@code host} is {@code null} a loopback address is used to connect to.
186 * <p><strong>Implementation note:</strong> this implementation tries each
187 * IP address for the given hostname until it either connects successfully
188 * or it exhausts the set. It will try both IPv4 and IPv6 addresses in the
189 * order specified by the system property {@code "java.net.preferIPv6Addresses"}.
190 *
191 * @param dstName
192 * the target host name or IP address to connect to.
193 * @param dstPort
194 * the port on the target host to connect to.
195 * @param localAddress
196 * the address on the local host to bind to.
197 * @param localPort
198 * the port on the local host to bind to.
199 * @throws UnknownHostException
200 * if the host name could not be resolved into an IP address.
201 * @throws IOException
202 * if an error occurs while creating the socket.
203 * @throws SecurityException
204 * if a security manager exists and it denies the permission to
205 * connect to the given address and port.
206 */
207 public Socket(String dstName, int dstPort, InetAddress localAddress, int localPort) throws IOException {
208 this();
209 tryAllAddresses(dstName, dstPort, localAddress, localPort, true);
210 }
211
212 /**
213 * Creates a new streaming or datagram socket connected to the target host
214 * specified by the parameters {@code hostName} and {@code port}. The socket
215 * is bound to any available port on the local host.
216 * <p><strong>Implementation note:</strong> this implementation tries each
217 * IP address for the given hostname until it either connects successfully
218 * or it exhausts the set. It will try both IPv4 and IPv6 addresses in the
219 * order specified by the system property {@code "java.net.preferIPv6Addresses"}.
220 *
221 * @param hostName
222 * the target host name or IP address to connect to.
223 * @param port
224 * the port on the target host to connect to.
225 * @param streaming
226 * if {@code true} a streaming socket is returned, a datagram
227 * socket otherwise.
228 * @throws UnknownHostException
229 * if the host name could not be resolved into an IP address.
230 * @throws IOException
231 * if an error occurs while creating the socket.
232 * @throws SecurityException
233 * if a security manager exists and it denies the permission to
234 * connect to the given address and port.
235 * @deprecated Use {@code Socket(String, int)} instead of this for streaming
236 * sockets or an appropriate constructor of {@code
237 * DatagramSocket} for UDP transport.
238 */
239 @Deprecated
240 public Socket(String hostName, int port, boolean streaming) throws IOException {
241 this();
242 tryAllAddresses(hostName, port, null, 0, streaming);
243 }
244
245 /**
246 * Creates a new streaming socket connected to the target host specified by
247 * the parameters {@code dstAddress} and {@code dstPort}. The socket is
248 * bound to any available port on the local host.
249 *
250 * @param dstAddress
251 * the target host address to connect to.
252 * @param dstPort
253 * the port on the target host to connect to.
254 * @throws IOException
255 * if an error occurs while creating the socket.
256 * @throws SecurityException
257 * if a security manager exists and it denies the permission to
258 * connect to the given address and port.
259 */
260 public Socket(InetAddress dstAddress, int dstPort) throws IOException {
261 this();
262 checkDestination(dstAddress, dstPort);
263 startupSocket(dstAddress, dstPort, null, 0, true);
264 }
265
266 /**
267 * Creates a new streaming socket connected to the target host specified by
268 * the parameters {@code dstAddress} and {@code dstPort}. On the local
269 * endpoint the socket is bound to the given address {@code localAddress} on
270 * port {@code localPort}.
271 *
272 * @param dstAddress
273 * the target host address to connect to.
274 * @param dstPort
275 * the port on the target host to connect to.
276 * @param localAddress
277 * the address on the local host to bind to.
278 * @param localPort
279 * the port on the local host to bind to.
280 * @throws IOException
281 * if an error occurs while creating the socket.
282 * @throws SecurityException
283 * if a security manager exists and it denies the permission to
284 * connect to the given address and port.
285 */
286 public Socket(InetAddress dstAddress, int dstPort,
287 InetAddress localAddress, int localPort) throws IOException {
288 this();
289 checkDestination(dstAddress, dstPort);
290 startupSocket(dstAddress, dstPort, localAddress, localPort, true);
291 }
292
293 /**
294 * Creates a new streaming or datagram socket connected to the target host
295 * specified by the parameters {@code addr} and {@code port}. The socket is
296 * bound to any available port on the local host.
297 *
298 * @param addr
299 * the Internet address to connect to.
300 * @param port
301 * the port on the target host to connect to.
302 * @param streaming
303 * if {@code true} a streaming socket is returned, a datagram
304 * socket otherwise.
305 * @throws IOException
306 * if an error occurs while creating the socket.
307 * @throws SecurityException
308 * if a security manager exists and it denies the permission to
309 * connect to the given address and port.
310 * @deprecated Use {@code Socket(InetAddress, int)} instead of this for
311 * streaming sockets or an appropriate constructor of {@code
312 * DatagramSocket} for UDP transport.
313 */
314 @Deprecated
315 public Socket(InetAddress addr, int port, boolean streaming) throws IOException {
316 this();
317 checkDestination(addr, port);
318 startupSocket(addr, port, null, 0, streaming);
319 }
320
321 /**
322 * Creates an unconnected socket with the given socket implementation.
323 *
324 * @param impl
325 * the socket implementation to be used.
326 * @throws SocketException
327 * if an error occurs while creating the socket.
328 */
329 protected Socket(SocketImpl impl) throws SocketException {
330 this.impl = impl;
331 this.proxy = null;
332 }
333
334 /**
335 * Checks whether the connection destination satisfies the security policy
336 * and the validity of the port range.
337 *
338 * @param destAddr
339 * the destination host address.
340 * @param dstPort
341 * the port on the destination host.
342 */
343 private void checkDestination(InetAddress destAddr, int dstPort) {
344 if (dstPort < 0 || dstPort > 65535) {
345 throw new IllegalArgumentException("Port out of range: " + dstPort);
346 }
347 checkConnectPermission(destAddr.getHostAddress(), dstPort);
348 }
349
350 /**
351 * Checks whether the connection destination satisfies the security policy.
352 *
353 * @param hostname
354 * the destination hostname.
355 * @param dstPort
356 * the port on the destination host.
357 */
358 private void checkConnectPermission(String hostname, int dstPort) {
359 SecurityManager security = System.getSecurityManager();
360 if (security != null) {
361 security.checkConnect(hostname, dstPort);
362 }
363 }
364
365 /**
366 * Closes the socket. It is not possible to reconnect or rebind to this
367 * socket thereafter which means a new socket instance has to be created.
368 *
369 * @throws IOException
370 * if an error occurs while closing the socket.
371 */
372 public synchronized void close() throws IOException {
373 isClosed = true;
374 // RI compatibility: the RI returns the any address (but the original local port) after close.
375 localAddress = Inet4Address.ANY;
376 impl.close();
377 }
378
379 /**
380 * Gets the IP address of the target host this socket is connected to.
381 *
382 * @return the IP address of the connected target host or {@code null} if
383 * this socket is not yet connected.
384 */
385 public InetAddress getInetAddress() {
386 if (!isConnected()) {
387 return null;
388 }
389 return impl.getInetAddress();
390 }
391
392 /**
393 * Gets an input stream to read data from this socket.
394 *
395 * @return the byte-oriented input stream.
396 * @throws IOException
397 * if an error occurs while creating the input stream or the
398 * socket is in an invalid state.
399 */
400 public InputStream getInputStream() throws IOException {
401 checkOpenAndCreate(false);
402 if (isInputShutdown()) {
403 throw new SocketException("Socket input is shutdown");
404 }
405 return impl.getInputStream();
406 }
407
408 /**
409 * Gets the setting of the socket option {@code SocketOptions.SO_KEEPALIVE}.
410 *
411 * @return {@code true} if the {@code SocketOptions.SO_KEEPALIVE} is
412 * enabled, {@code false} otherwise.
413 * @throws SocketException
414 * if an error occurs while reading the socket option.
415 * @see SocketOptions#SO_KEEPALIVE
416 */
417 public boolean getKeepAlive() throws SocketException {
418 checkOpenAndCreate(true);
419 return (Boolean) impl.getOption(SocketOptions.SO_KEEPALIVE);
420 }
421
422 /**
423 * Returns the local IP address this socket is bound to, or {@code InetAddress.ANY} if
424 * the socket is unbound.
425 */
426 public InetAddress getLocalAddress() {
427 return localAddress;
428 }
429
430 /**
431 * Returns the local port this socket is bound to, or -1 if the socket is unbound.
432 */
433 public int getLocalPort() {
434 if (!isBound()) {
435 return -1;
436 }
437 return impl.getLocalPort();
438 }
439
440 /**
441 * Gets an output stream to write data into this socket.
442 *
443 * @return the byte-oriented output stream.
444 * @throws IOException
445 * if an error occurs while creating the output stream or the
446 * socket is in an invalid state.
447 */
448 public OutputStream getOutputStream() throws IOException {
449 checkOpenAndCreate(false);
450 if (isOutputShutdown()) {
451 throw new SocketException("Socket output is shutdown");
452 }
453 return impl.getOutputStream();
454 }
455
456 /**
457 * Gets the port number of the target host this socket is connected to.
458 *
459 * @return the port number of the connected target host or {@code 0} if this
460 * socket is not yet connected.
461 */
462 public int getPort() {
463 if (!isConnected()) {
464 return 0;
465 }
466 return impl.getPort();
467 }
468
469 /**
470 * Gets the value of the socket option {@link SocketOptions#SO_LINGER}.
471 *
472 * @return the current value of the option {@code SocketOptions.SO_LINGER}
473 * or {@code -1} if this option is disabled.
474 * @throws SocketException
475 * if an error occurs while reading the socket option.
476 * @see SocketOptions#SO_LINGER
477 */
478 public int getSoLinger() throws SocketException {
479 checkOpenAndCreate(true);
480 // The RI explicitly guarantees this idiocy in the SocketOptions.setOption documentation.
481 Object value = impl.getOption(SocketOptions.SO_LINGER);
482 if (value instanceof Integer) {
483 return (Integer) value;
484 } else {
485 return -1;
486 }
487 }
488
489 /**
490 * Gets the receive buffer size of this socket.
491 *
492 * @return the current value of the option {@code SocketOptions.SO_RCVBUF}.
493 * @throws SocketException
494 * if an error occurs while reading the socket option.
495 * @see SocketOptions#SO_RCVBUF
496 */
497 public synchronized int getReceiveBufferSize() throws SocketException {
498 checkOpenAndCreate(true);
499 return (Integer) impl.getOption(SocketOptions.SO_RCVBUF);
500 }
501
502 /**
503 * Gets the send buffer size of this socket.
504 *
505 * @return the current value of the option {@code SocketOptions.SO_SNDBUF}.
506 * @throws SocketException
507 * if an error occurs while reading the socket option.
508 * @see SocketOptions#SO_SNDBUF
509 */
510 public synchronized int getSendBufferSize() throws SocketException {
511 checkOpenAndCreate(true);
512 return (Integer) impl.getOption(SocketOptions.SO_SNDBUF);
513 }
514
515 /**
516 * Gets the socket {@link SocketOptions#SO_TIMEOUT receive timeout}.
517 *
518 * @throws SocketException
519 * if an error occurs while reading the socket option.
520 */
521 public synchronized int getSoTimeout() throws SocketException {
522 checkOpenAndCreate(true);
523 return (Integer) impl.getOption(SocketOptions.SO_TIMEOUT);
524 }
525
526 /**
527 * Gets the setting of the socket option {@code SocketOptions.TCP_NODELAY}.
528 *
529 * @return {@code true} if the {@code SocketOptions.TCP_NODELAY} is enabled,
530 * {@code false} otherwise.
531 * @throws SocketException
532 * if an error occurs while reading the socket option.
533 * @see SocketOptions#TCP_NODELAY
534 */
535 public boolean getTcpNoDelay() throws SocketException {
536 checkOpenAndCreate(true);
537 return (Boolean) impl.getOption(SocketOptions.TCP_NODELAY);
538 }
539
540 /**
541 * Sets the state of the {@code SocketOptions.SO_KEEPALIVE} for this socket.
542 *
543 * @param keepAlive
544 * the state whether this option is enabled or not.
545 * @throws SocketException
546 * if an error occurs while setting the option.
547 * @see SocketOptions#SO_KEEPALIVE
548 */
549 public void setKeepAlive(boolean keepAlive) throws SocketException {
550 if (impl != null) {
551 checkOpenAndCreate(true);
552 impl.setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(keepAlive));
553 }
554 }
555
556 /**
557 * Sets the internal factory for creating socket implementations. This may
558 * only be executed once during the lifetime of the application.
559 *
560 * @param fac
561 * the socket implementation factory to be set.
562 * @throws IOException
563 * if the factory has been already set.
564 */
565 public static synchronized void setSocketImplFactory(SocketImplFactory fac)
566 throws IOException {
567 SecurityManager security = System.getSecurityManager();
568 if (security != null) {
569 security.checkSetFactory();
570 }
571 if (factory != null) {
572 throw new SocketException("Factory already set");
573 }
574 factory = fac;
575 }
576
577 /**
578 * Sets the send buffer size of this socket.
579 *
580 * @param size
581 * the buffer size in bytes. This value must be a positive number
582 * greater than {@code 0}.
583 * @throws SocketException
584 * if an error occurs while setting the size or the given value
585 * is an invalid size.
586 * @see SocketOptions#SO_SNDBUF
587 */
588 public synchronized void setSendBufferSize(int size) throws SocketException {
589 checkOpenAndCreate(true);
590 if (size < 1) {
591 throw new IllegalArgumentException("size < 1");
592 }
593 impl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size));
594 }
595
596 /**
597 * Sets the receive buffer size of this socket.
598 *
599 * @param size
600 * the buffer size in bytes. This value must be a positive number
601 * greater than {@code 0}.
602 * @throws SocketException
603 * if an error occurs while setting the size or the given value
604 * is an invalid size.
605 * @see SocketOptions#SO_RCVBUF
606 */
607 public synchronized void setReceiveBufferSize(int size) throws SocketException {
608 checkOpenAndCreate(true);
609 if (size < 1) {
610 throw new IllegalArgumentException("size < 1");
611 }
612 impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
613 }
614
615 /**
616 * Sets the {@link SocketOptions#SO_LINGER} timeout in seconds.
617 *
618 * @param on
619 * the state whether this option is enabled or not.
620 * @param timeout
621 * the linger timeout value in seconds.
622 * @throws SocketException
623 * if an error occurs while setting the option.
624 * @see SocketOptions#SO_LINGER
625 */
626 public void setSoLinger(boolean on, int timeout) throws SocketException {
627 checkOpenAndCreate(true);
628 // The RI explicitly guarantees this idiocy in the SocketOptions.setOption documentation.
629 if (on && timeout < 0) {
630 throw new IllegalArgumentException("timeout < 0");
631 }
632 if (on) {
633 impl.setOption(SocketOptions.SO_LINGER, Integer.valueOf(timeout));
634 } else {
635 impl.setOption(SocketOptions.SO_LINGER, Boolean.FALSE);
636 }
637 }
638
639 /**
640 * Sets the {@link SocketOptions#SO_TIMEOUT read timeout} in milliseconds for this socket.
641 * This receive timeout defines the period the socket will block waiting to
642 * receive data before throwing an {@code InterruptedIOException}. The value
643 * {@code 0} (default) is used to set an infinite timeout. To have effect
644 * this option must be set before the blocking method was called.
645 *
646 * @param timeout the timeout in milliseconds or 0 for no timeout.
647 * @throws SocketException
648 * if an error occurs while setting the option.
649 */
650 public synchronized void setSoTimeout(int timeout) throws SocketException {
651 checkOpenAndCreate(true);
652 if (timeout < 0) {
653 throw new IllegalArgumentException("timeout < 0");
654 }
655 impl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout));
656 }
657
658 /**
659 * Sets the state of the {@code SocketOptions.TCP_NODELAY} for this socket.
660 *
661 * @param on
662 * the state whether this option is enabled or not.
663 * @throws SocketException
664 * if an error occurs while setting the option.
665 * @see SocketOptions#TCP_NODELAY
666 */
667 public void setTcpNoDelay(boolean on) throws SocketException {
668 checkOpenAndCreate(true);
669 impl.setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
670 }
671
672 /**
673 * Creates a stream socket, binds it to the nominated local address/port,
674 * then connects it to the nominated destination address/port.
675 *
676 * @param dstAddress
677 * the destination host address.
678 * @param dstPort
679 * the port on the destination host.
680 * @param localAddress
681 * the address on the local machine to bind.
682 * @param localPort
683 * the port on the local machine to bind.
684 * @throws IOException
685 * thrown if an error occurs during the bind or connect
686 * operations.
687 */
688 private void startupSocket(InetAddress dstAddress, int dstPort,
689 InetAddress localAddress, int localPort, boolean streaming)
690 throws IOException {
691
692 if (localPort < 0 || localPort > 65535) {
693 throw new IllegalArgumentException("Local port out of range: " + localPort);
694 }
695
696 InetAddress addr = localAddress == null ? Inet4Address.ANY : localAddress;
697 synchronized (this) {
698 impl.create(streaming);
699 isCreated = true;
700 try {
701 if (!streaming || !usingSocks()) {
702 impl.bind(addr, localPort);
703 }
704 isBound = true;
705 impl.connect(dstAddress, dstPort);
706 isConnected = true;
707 cacheLocalAddress();
708 } catch (IOException e) {
709 impl.close();
710 throw e;
711 }
712 }
713 }
714
715 private boolean usingSocks() {
716 return proxy != null && proxy.type() == Proxy.Type.SOCKS;
717 }
718
719 /**
720 * Returns a {@code String} containing a concise, human-readable description of the
721 * socket.
722 *
723 * @return the textual representation of this socket.
724 */
725 @Override
726 public String toString() {
727 if (!isConnected()) {
728 return "Socket[unconnected]";
729 }
730 return impl.toString();
731 }
732
733 /**
734 * Closes the input stream of this socket. Any further data sent to this
735 * socket will be discarded. Reading from this socket after this method has
736 * been called will return the value {@code EOF}.
737 *
738 * @throws IOException
739 * if an error occurs while closing the socket input stream.
740 * @throws SocketException
741 * if the input stream is already closed.
742 */
743 public void shutdownInput() throws IOException {
744 if (isInputShutdown()) {
745 throw new SocketException("Socket input is shutdown");
746 }
747 checkOpenAndCreate(false);
748 impl.shutdownInput();
749 isInputShutdown = true;
750 }
751
752 /**
753 * Closes the output stream of this socket. All buffered data will be sent
754 * followed by the termination sequence. Writing to the closed output stream
755 * will cause an {@code IOException}.
756 *
757 * @throws IOException
758 * if an error occurs while closing the socket output stream.
759 * @throws SocketException
760 * if the output stream is already closed.
761 */
762 public void shutdownOutput() throws IOException {
763 if (isOutputShutdown()) {
764 throw new SocketException("Socket output is shutdown");
765 }
766 checkOpenAndCreate(false);
767 impl.shutdownOutput();
768 isOutputShutdown = true;
769 }
770
771 /**
772 * Checks whether the socket is closed, and throws an exception. Otherwise
773 * creates the underlying SocketImpl.
774 *
775 * @throws SocketException
776 * if the socket is closed.
777 */
778 private void checkOpenAndCreate(boolean create) throws SocketException {
779 if (isClosed()) {
780 throw new SocketException("Socket is closed");
781 }
782 if (!create) {
783 if (!isConnected()) {
784 throw new SocketException("Socket is not connected");
785 // a connected socket must be created
786 }
787
788 /*
789 * return directly to fix a possible bug, if !create, should return
790 * here
791 */
792 return;
793 }
794 if (isCreated) {
795 return;
796 }
797 synchronized (this) {
798 if (isCreated) {
799 return;
800 }
801 try {
802 impl.create(true);
803 } catch (SocketException e) {
804 throw e;
805 } catch (IOException e) {
806 throw new SocketException(e.toString());
807 }
808 isCreated = true;
809 }
810 }
811
812 /**
813 * Gets the local address and port of this socket as a SocketAddress or
814 * {@code null} if the socket is unbound. This is useful on multihomed
815 * hosts.
816 *
817 * @return the bound local socket address and port.
818 */
819 public SocketAddress getLocalSocketAddress() {
820 if (!isBound()) {
821 return null;
822 }
823 return new InetSocketAddress(getLocalAddress(), getLocalPort());
824 }
825
826 /**
827 * Gets the remote address and port of this socket as a {@code
828 * SocketAddress} or {@code null} if the socket is not connected.
829 *
830 * @return the remote socket address and port.
831 */
832 public SocketAddress getRemoteSocketAddress() {
833 if (!isConnected()) {
834 return null;
835 }
836 return new InetSocketAddress(getInetAddress(), getPort());
837 }
838
839 /**
840 * Returns whether this socket is bound to a local address and port.
841 *
842 * @return {@code true} if the socket is bound to a local address, {@code
843 * false} otherwise.
844 */
845 public boolean isBound() {
846 return isBound;
847 }
848
849 /**
850 * Returns whether this socket is connected to a remote host.
851 *
852 * @return {@code true} if the socket is connected, {@code false} otherwise.
853 */
854 public boolean isConnected() {
855 return isConnected;
856 }
857
858 /**
859 * Returns whether this socket is closed.
860 *
861 * @return {@code true} if the socket is closed, {@code false} otherwise.
862 */
863 public boolean isClosed() {
864 return isClosed;
865 }
866
867 /**
868 * Binds this socket to the given local host address and port specified by
869 * the SocketAddress {@code localAddr}. If {@code localAddr} is set to
870 * {@code null}, this socket will be bound to an available local address on
871 * any free port.
872 *
873 * @param localAddr
874 * the specific address and port on the local machine to bind to.
875 * @throws IllegalArgumentException
876 * if the given SocketAddress is invalid or not supported.
877 * @throws IOException
878 * if the socket is already bound or an error occurs while
879 * binding.
880 */
881 public void bind(SocketAddress localAddr) throws IOException {
882 checkOpenAndCreate(true);
883 if (isBound()) {
884 throw new BindException("Socket is already bound");
885 }
886
887 int port = 0;
888 InetAddress addr = Inet4Address.ANY;
889 if (localAddr != null) {
890 if (!(localAddr instanceof InetSocketAddress)) {
891 throw new IllegalArgumentException("Local address not an InetSocketAddress: " +
892 localAddr.getClass());
893 }
894 InetSocketAddress inetAddr = (InetSocketAddress) localAddr;
895 if ((addr = inetAddr.getAddress()) == null) {
896 throw new SocketException("Host is unresolved: " + inetAddr.getHostName());
897 }
898 port = inetAddr.getPort();
899 }
900
901 synchronized (this) {
902 try {
903 impl.bind(addr, port);
904 isBound = true;
905 cacheLocalAddress();
906 } catch (IOException e) {
907 impl.close();
908 throw e;
909 }
910 }
911 }
912
913 /**
914 * Connects this socket to the given remote host address and port specified
915 * by the SocketAddress {@code remoteAddr}.
916 *
917 * @param remoteAddr
918 * the address and port of the remote host to connect to.
919 * @throws IllegalArgumentException
920 * if the given SocketAddress is invalid or not supported.
921 * @throws IOException
922 * if the socket is already connected or an error occurs while
923 * connecting.
924 */
925 public void connect(SocketAddress remoteAddr) throws IOException {
926 connect(remoteAddr, 0);
927 }
928
929 /**
930 * Connects this socket to the given remote host address and port specified
931 * by the SocketAddress {@code remoteAddr} with the specified timeout. The
932 * connecting method will block until the connection is established or an
933 * error occurred.
934 *
935 * @param remoteAddr
936 * the address and port of the remote host to connect to.
937 * @param timeout
938 * the timeout value in milliseconds or {@code 0} for an infinite
939 * timeout.
940 * @throws IllegalArgumentException
941 * if the given SocketAddress is invalid or not supported or the
942 * timeout value is negative.
943 * @throws IOException
944 * if the socket is already connected or an error occurs while
945 * connecting.
946 */
947 public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
948 checkOpenAndCreate(true);
949 if (timeout < 0) {
950 throw new IllegalArgumentException("timeout < 0");
951 }
952 if (isConnected()) {
953 throw new SocketException("Already connected");
954 }
955 if (remoteAddr == null) {
956 throw new IllegalArgumentException("remoteAddr == null");
957 }
958
959 if (!(remoteAddr instanceof InetSocketAddress)) {
960 throw new IllegalArgumentException("Remote address not an InetSocketAddress: " +
961 remoteAddr.getClass());
962 }
963 InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
964 InetAddress addr;
965 if ((addr = inetAddr.getAddress()) == null) {
966 throw new SocketException("Host is unresolved: " + inetAddr.getHostName());
967 }
968 int port = inetAddr.getPort();
969
970 checkDestination(addr, port);
971 synchronized (connectLock) {
972 try {
973 if (!isBound()) {
974 // socket already created at this point by earlier call or
975 // checkOpenAndCreate this caused us to lose socket
976 // options on create
977 // impl.create(true);
978 if (!usingSocks()) {
979 impl.bind(Inet4Address.ANY, 0);
980 }
981 isBound = true;
982 }
983 impl.connect(remoteAddr, timeout);
984 isConnected = true;
985 cacheLocalAddress();
986 } catch (IOException e) {
987 impl.close();
988 throw e;
989 }
990 }
991 }
992
993 /**
994 * Returns whether the incoming channel of the socket has already been
995 * closed.
996 *
997 * @return {@code true} if reading from this socket is not possible anymore,
998 * {@code false} otherwise.
999 */
1000 public boolean isInputShutdown() {
1001 return isInputShutdown;
1002 }
1003
1004 /**
1005 * Returns whether the outgoing channel of the socket has already been
1006 * closed.
1007 *
1008 * @return {@code true} if writing to this socket is not possible anymore,
1009 * {@code false} otherwise.
1010 */
1011 public boolean isOutputShutdown() {
1012 return isOutputShutdown;
1013 }
1014
1015 /**
1016 * Sets the state of the {@code SocketOptions.SO_REUSEADDR} for this socket.
1017 *
1018 * @param reuse
1019 * the state whether this option is enabled or not.
1020 * @throws SocketException
1021 * if an error occurs while setting the option.
1022 * @see SocketOptions#SO_REUSEADDR
1023 */
1024 public void setReuseAddress(boolean reuse) throws SocketException {
1025 checkOpenAndCreate(true);
1026 impl.setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(reuse));
1027 }
1028
1029 /**
1030 * Gets the setting of the socket option {@code SocketOptions.SO_REUSEADDR}.
1031 *
1032 * @return {@code true} if the {@code SocketOptions.SO_REUSEADDR} is
1033 * enabled, {@code false} otherwise.
1034 * @throws SocketException
1035 * if an error occurs while reading the socket option.
1036 * @see SocketOptions#SO_REUSEADDR
1037 */
1038 public boolean getReuseAddress() throws SocketException {
1039 checkOpenAndCreate(true);
1040 return (Boolean) impl.getOption(SocketOptions.SO_REUSEADDR);
1041 }
1042
1043 /**
1044 * Sets the state of the {@code SocketOptions.SO_OOBINLINE} for this socket.
1045 * When this option is enabled urgent data can be received in-line with
1046 * normal data.
1047 *
1048 * @param oobinline
1049 * whether this option is enabled or not.
1050 * @throws SocketException
1051 * if an error occurs while setting the option.
1052 * @see SocketOptions#SO_OOBINLINE
1053 */
1054 public void setOOBInline(boolean oobinline) throws SocketException {
1055 checkOpenAndCreate(true);
1056 impl.setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(oobinline));
1057 }
1058
1059 /**
1060 * Gets the setting of the socket option {@code SocketOptions.SO_OOBINLINE}.
1061 *
1062 * @return {@code true} if the {@code SocketOptions.SO_OOBINLINE} is
1063 * enabled, {@code false} otherwise.
1064 * @throws SocketException
1065 * if an error occurs while reading the socket option.
1066 * @see SocketOptions#SO_OOBINLINE
1067 */
1068 public boolean getOOBInline() throws SocketException {
1069 checkOpenAndCreate(true);
1070 return (Boolean) impl.getOption(SocketOptions.SO_OOBINLINE);
1071 }
1072
1073 /**
1074 * Sets the {@see SocketOptions#IP_TOS} value for every packet sent by this socket.
1075 *
1076 * @throws SocketException
1077 * if the socket is closed or the option could not be set.
1078 */
1079 public void setTrafficClass(int value) throws SocketException {
1080 checkOpenAndCreate(true);
1081 if (value < 0 || value > 255) {
1082 throw new IllegalArgumentException();
1083 }
1084 impl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value));
1085 }
1086
1087 /**
1088 * Returns this socket's {@see SocketOptions#IP_TOS} setting.
1089 *
1090 * @throws SocketException
1091 * if the socket is closed or the option is invalid.
1092 */
1093 public int getTrafficClass() throws SocketException {
1094 checkOpenAndCreate(true);
1095 return (Integer) impl.getOption(SocketOptions.IP_TOS);
1096 }
1097
1098 /**
1099 * Sends the given single byte data which is represented by the lowest octet
1100 * of {@code value} as "TCP urgent data".
1101 *
1102 * @param value
1103 * the byte of urgent data to be sent.
1104 * @throws IOException
1105 * if an error occurs while sending urgent data.
1106 */
1107 public void sendUrgentData(int value) throws IOException {
1108 impl.sendUrgentData(value);
1109 }
1110
1111 /**
1112 * Set the appropriate flags for a socket created by {@code
1113 * ServerSocket.accept()}.
1114 *
1115 * @see ServerSocket#implAccept
1116 */
1117 void accepted() {
1118 isCreated = isBound = isConnected = true;
1119 cacheLocalAddress();
1120 }
1121
1122 private void cacheLocalAddress() {
1123 this.localAddress = Platform.getNetworkSystem().getSocketLocalAddress(impl.fd);
1124 }
1125
1126 /**
1127 * Gets the SocketChannel of this socket, if one is available. The current
1128 * implementation of this method returns always {@code null}.
1129 *
1130 * @return the related SocketChannel or {@code null} if no channel exists.
1131 */
1132 public SocketChannel getChannel() {
1133 return null;
1134 }
1135
1136 /**
1137 * Sets performance preferences for connectionTime, latency and bandwidth.
1138 * <p>
1139 * This method does currently nothing.
1140 *
1141 * @param connectionTime
1142 * the value representing the importance of a short connecting
1143 * time.
1144 * @param latency
1145 * the value representing the importance of low latency.
1146 * @param bandwidth
1147 * the value representing the importance of high bandwidth.
1148 */
1149 public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
1150 // Our socket implementation only provide one protocol: TCP/IP, so
1151 // we do nothing for this method
1152 }
1153}