70 * The implementation of this Socket. |
70 * The implementation of this Socket. |
71 */ |
71 */ |
72 SocketImpl impl; |
72 SocketImpl impl; |
73 |
73 |
74 /** |
74 /** |
75 * Are we using an older SocketImpl? |
|
76 */ |
|
77 private boolean oldImpl = false; |
|
78 |
|
79 /** |
|
80 * Socket input/output streams |
75 * Socket input/output streams |
81 */ |
76 */ |
82 private volatile InputStream in; |
77 private volatile InputStream in; |
83 private volatile OutputStream out; |
78 private volatile OutputStream out; |
84 private static final VarHandle IN, OUT; |
79 private static final VarHandle IN, OUT; |
156 } |
151 } |
157 |
152 |
158 // create a SOCKS or HTTP SocketImpl that delegates to a platform SocketImpl |
153 // create a SOCKS or HTTP SocketImpl that delegates to a platform SocketImpl |
159 SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false); |
154 SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false); |
160 impl = (type == Proxy.Type.SOCKS) ? new SocksSocketImpl(p, delegate) |
155 impl = (type == Proxy.Type.SOCKS) ? new SocksSocketImpl(p, delegate) |
161 : new HttpConnectSocketImpl(p, delegate); |
156 : new HttpConnectSocketImpl(p, delegate, this); |
162 impl.setSocket(this); |
|
163 } else { |
157 } else { |
164 if (p == Proxy.NO_PROXY) { |
158 if (p == Proxy.NO_PROXY) { |
165 // create a platform or custom SocketImpl for the DIRECT case |
159 // create a platform or custom SocketImpl for the DIRECT case |
166 SocketImplFactory factory = Socket.factory; |
160 SocketImplFactory factory = Socket.factory; |
167 if (factory == null) { |
161 if (factory == null) { |
168 impl = SocketImpl.createPlatformSocketImpl(false); |
162 impl = SocketImpl.createPlatformSocketImpl(false); |
169 } else { |
163 } else { |
170 impl = factory.createSocketImpl(); |
164 impl = factory.createSocketImpl(); |
171 } |
165 } |
172 impl.setSocket(this); |
|
173 } else |
166 } else |
174 throw new IllegalArgumentException("Invalid Proxy"); |
167 throw new IllegalArgumentException("Invalid Proxy"); |
175 } |
168 } |
176 } |
169 } |
177 |
170 |
484 } catch (IOException e) { |
473 } catch (IOException e) { |
485 throw new SocketException(e.getMessage()); |
474 throw new SocketException(e.getMessage()); |
486 } |
475 } |
487 } |
476 } |
488 |
477 |
489 private void checkOldImpl() { |
|
490 if (impl == null) |
|
491 return; |
|
492 // SocketImpl.connect() is a protected method, therefore we need to use |
|
493 // getDeclaredMethod, therefore we need permission to access the member |
|
494 |
|
495 oldImpl = AccessController.doPrivileged |
|
496 (new PrivilegedAction<>() { |
|
497 public Boolean run() { |
|
498 Class<?> clazz = impl.getClass(); |
|
499 while (true) { |
|
500 try { |
|
501 clazz.getDeclaredMethod("connect", SocketAddress.class, int.class); |
|
502 return Boolean.FALSE; |
|
503 } catch (NoSuchMethodException e) { |
|
504 clazz = clazz.getSuperclass(); |
|
505 // java.net.SocketImpl class will always have this abstract method. |
|
506 // If we have not found it by now in the hierarchy then it does not |
|
507 // exist, we are an old style impl. |
|
508 if (clazz.equals(java.net.SocketImpl.class)) { |
|
509 return Boolean.TRUE; |
|
510 } |
|
511 } |
|
512 } |
|
513 } |
|
514 }); |
|
515 } |
|
516 |
|
517 void setImpl(SocketImpl si) { |
478 void setImpl(SocketImpl si) { |
518 impl = si; |
479 impl = si; |
519 impl.setSocket(this); |
|
520 } |
480 } |
521 |
481 |
522 /** |
482 /** |
523 * Sets impl to the system-default type of SocketImpl. |
483 * Sets impl to the system-default type of SocketImpl. |
524 * @since 1.4 |
484 * @since 1.4 |
525 */ |
485 */ |
526 void setImpl() { |
486 void setImpl() { |
527 SocketImplFactory factory = Socket.factory; |
487 SocketImplFactory factory = Socket.factory; |
528 if (factory != null) { |
488 if (factory != null) { |
529 impl = factory.createSocketImpl(); |
489 impl = factory.createSocketImpl(); |
530 checkOldImpl(); |
|
531 } else { |
490 } else { |
532 // create a SOCKS SocketImpl that delegates to a platform SocketImpl |
491 // create a SOCKS SocketImpl that delegates to a platform SocketImpl |
533 SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false); |
492 SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false); |
534 impl = new SocksSocketImpl(delegate); |
493 impl = new SocksSocketImpl(delegate); |
535 } |
494 } |
536 if (impl != null) |
|
537 impl.setSocket(this); |
|
538 } |
495 } |
539 |
496 |
540 /** |
497 /** |
541 * Get the {@code SocketImpl} attached to this socket, creating |
498 * Get the {@code SocketImpl} attached to this socket, creating |
542 * it if necessary. |
499 * it if necessary. |
594 throw new IllegalArgumentException("connect: timeout can't be negative"); |
551 throw new IllegalArgumentException("connect: timeout can't be negative"); |
595 |
552 |
596 if (isClosed()) |
553 if (isClosed()) |
597 throw new SocketException("Socket is closed"); |
554 throw new SocketException("Socket is closed"); |
598 |
555 |
599 if (!oldImpl && isConnected()) |
556 if (isConnected()) |
600 throw new SocketException("already connected"); |
557 throw new SocketException("already connected"); |
601 |
558 |
602 if (!(endpoint instanceof InetSocketAddress)) |
559 if (!(endpoint instanceof InetSocketAddress)) |
603 throw new IllegalArgumentException("Unsupported address type"); |
560 throw new IllegalArgumentException("Unsupported address type"); |
604 |
561 |
614 else |
571 else |
615 security.checkConnect(addr.getHostAddress(), port); |
572 security.checkConnect(addr.getHostAddress(), port); |
616 } |
573 } |
617 if (!created) |
574 if (!created) |
618 createImpl(true); |
575 createImpl(true); |
619 if (!oldImpl) |
576 impl.connect(epoint, timeout); |
620 impl.connect(epoint, timeout); |
|
621 else if (timeout == 0) { |
|
622 if (epoint.isUnresolved()) |
|
623 impl.connect(addr.getHostName(), port); |
|
624 else |
|
625 impl.connect(addr, port); |
|
626 } else |
|
627 throw new UnsupportedOperationException("SocketImpl.connect(addr, timeout)"); |
|
628 connected = true; |
577 connected = true; |
629 /* |
578 /* |
630 * If the socket was not bound before the connect, it is now because |
579 * If the socket was not bound before the connect, it is now because |
631 * the kernel will have picked an ephemeral port & a local address |
580 * the kernel will have picked an ephemeral port & a local address |
632 */ |
581 */ |
652 * @see #isBound |
601 * @see #isBound |
653 */ |
602 */ |
654 public void bind(SocketAddress bindpoint) throws IOException { |
603 public void bind(SocketAddress bindpoint) throws IOException { |
655 if (isClosed()) |
604 if (isClosed()) |
656 throw new SocketException("Socket is closed"); |
605 throw new SocketException("Socket is closed"); |
657 if (!oldImpl && isBound()) |
606 if (isBound()) |
658 throw new SocketException("Already bound"); |
607 throw new SocketException("Already bound"); |
659 |
608 |
660 if (bindpoint != null && (!(bindpoint instanceof InetSocketAddress))) |
609 if (bindpoint != null && (!(bindpoint instanceof InetSocketAddress))) |
661 throw new IllegalArgumentException("Unsupported address type"); |
610 throw new IllegalArgumentException("Unsupported address type"); |
662 InetSocketAddress epoint = (InetSocketAddress) bindpoint; |
611 InetSocketAddress epoint = (InetSocketAddress) bindpoint; |
955 * I/O events. |
892 * I/O events. |
956 */ |
893 */ |
957 private static class SocketInputStream extends InputStream { |
894 private static class SocketInputStream extends InputStream { |
958 private final Socket parent; |
895 private final Socket parent; |
959 private final InputStream in; |
896 private final InputStream in; |
|
897 |
960 SocketInputStream(Socket parent, InputStream in) { |
898 SocketInputStream(Socket parent, InputStream in) { |
961 this.parent = parent; |
899 this.parent = parent; |
962 this.in = in; |
900 this.in = in; |
963 } |
901 } |
964 @Override |
902 @Override |