125 private volatile int timeout; |
125 private volatile int timeout; |
126 |
126 |
127 // flags to indicate if the connection is shutdown for input and output |
127 // flags to indicate if the connection is shutdown for input and output |
128 private volatile boolean isInputClosed; |
128 private volatile boolean isInputClosed; |
129 private volatile boolean isOutputClosed; |
129 private volatile boolean isOutputClosed; |
130 |
|
131 // socket input/output streams |
|
132 private volatile InputStream in; |
|
133 private volatile OutputStream out; |
|
134 private static final VarHandle IN, OUT; |
|
135 static { |
|
136 try { |
|
137 MethodHandles.Lookup l = MethodHandles.lookup(); |
|
138 IN = l.findVarHandle(NioSocketImpl.class, "in", InputStream.class); |
|
139 OUT = l.findVarHandle(NioSocketImpl.class, "out", OutputStream.class); |
|
140 } catch (Exception e) { |
|
141 throw new InternalError(e); |
|
142 } |
|
143 } |
|
144 |
130 |
145 /** |
131 /** |
146 * Creates a instance of this SocketImpl. |
132 * Creates a instance of this SocketImpl. |
147 * @param server true if this is a SocketImpl for a ServerSocket |
133 * @param server true if this is a SocketImpl for a ServerSocket |
148 */ |
134 */ |
753 } |
739 } |
754 } |
740 } |
755 |
741 |
756 @Override |
742 @Override |
757 protected InputStream getInputStream() { |
743 protected InputStream getInputStream() { |
758 InputStream in = this.in; |
744 return new InputStream() { |
759 if (in == null) { |
745 // EOF or connection reset detected, not thread safe |
760 in = new SocketInputStream(this); |
746 private boolean eof, reset; |
761 if (!IN.compareAndSet(this, null, in)) { |
747 @Override |
762 in = this.in; |
748 public int read() throws IOException { |
763 } |
749 byte[] a = new byte[1]; |
764 } |
750 int n = read(a, 0, 1); |
765 return in; |
751 return (n > 0) ? (a[0] & 0xff) : -1; |
766 } |
752 } |
767 |
753 @Override |
768 private static class SocketInputStream extends InputStream { |
754 public int read(byte[] b, int off, int len) throws IOException { |
769 private final NioSocketImpl impl; |
755 Objects.checkFromIndexSize(off, len, b.length); |
770 // EOF or connection reset detected, not thread safe |
756 if (eof) { |
771 private boolean eof, reset; |
757 return -1; |
772 SocketInputStream(NioSocketImpl impl) { |
758 } else if (reset) { |
773 this.impl = impl; |
|
774 } |
|
775 @Override |
|
776 public int read() throws IOException { |
|
777 byte[] a = new byte[1]; |
|
778 int n = read(a, 0, 1); |
|
779 return (n > 0) ? (a[0] & 0xff) : -1; |
|
780 } |
|
781 @Override |
|
782 public int read(byte[] b, int off, int len) throws IOException { |
|
783 Objects.checkFromIndexSize(off, len, b.length); |
|
784 if (eof) { |
|
785 return -1; |
|
786 } else if (reset) { |
|
787 throw new SocketException("Connection reset"); |
|
788 } else if (len == 0) { |
|
789 return 0; |
|
790 } else { |
|
791 try { |
|
792 // read up to MAX_BUFFER_SIZE bytes |
|
793 int size = Math.min(len, MAX_BUFFER_SIZE); |
|
794 int n = impl.read(b, off, size); |
|
795 if (n == -1) |
|
796 eof = true; |
|
797 return n; |
|
798 } catch (ConnectionResetException e) { |
|
799 reset = true; |
|
800 throw new SocketException("Connection reset"); |
759 throw new SocketException("Connection reset"); |
801 } catch (SocketTimeoutException e) { |
760 } else if (len == 0) { |
802 throw e; |
761 return 0; |
803 } catch (IOException ioe) { |
762 } else { |
804 throw new SocketException(ioe.getMessage()); |
763 try { |
805 } |
764 // read up to MAX_BUFFER_SIZE bytes |
806 } |
765 int size = Math.min(len, MAX_BUFFER_SIZE); |
807 } |
766 int n = NioSocketImpl.this.read(b, off, size); |
808 @Override |
767 if (n == -1) |
809 public int available() throws IOException { |
768 eof = true; |
810 return impl.available(); |
769 return n; |
811 } |
770 } catch (ConnectionResetException e) { |
812 @Override |
771 reset = true; |
813 public void close() throws IOException { |
772 throw new SocketException("Connection reset"); |
814 impl.close(); |
773 } catch (SocketTimeoutException e) { |
815 } |
774 throw e; |
|
775 } catch (IOException ioe) { |
|
776 throw new SocketException(ioe.getMessage()); |
|
777 } |
|
778 } |
|
779 } |
|
780 @Override |
|
781 public int available() throws IOException { |
|
782 return NioSocketImpl.this.available(); |
|
783 } |
|
784 @Override |
|
785 public void close() throws IOException { |
|
786 NioSocketImpl.this.close(); |
|
787 } |
|
788 }; |
816 } |
789 } |
817 |
790 |
818 @Override |
791 @Override |
819 protected OutputStream getOutputStream() { |
792 protected OutputStream getOutputStream() { |
820 OutputStream out = this.out; |
793 return new OutputStream() { |
821 if (out == null) { |
794 @Override |
822 out = new SocketOutputStream(this); |
795 public void write(int b) throws IOException { |
823 if (!OUT.compareAndSet(this, null, out)) { |
796 byte[] a = new byte[]{(byte) b}; |
824 out = this.out; |
797 write(a, 0, 1); |
825 } |
798 } |
826 } |
799 @Override |
827 return out; |
800 public void write(byte[] b, int off, int len) throws IOException { |
828 } |
801 Objects.checkFromIndexSize(off, len, b.length); |
829 |
802 if (len > 0) { |
830 private static class SocketOutputStream extends OutputStream { |
803 try { |
831 private final NioSocketImpl impl; |
804 int pos = off; |
832 SocketOutputStream(NioSocketImpl impl) { |
805 int end = off + len; |
833 this.impl = impl; |
806 while (pos < end) { |
834 } |
807 // write up to MAX_BUFFER_SIZE bytes |
835 @Override |
808 int size = Math.min((end - pos), MAX_BUFFER_SIZE); |
836 public void write(int b) throws IOException { |
809 int n = NioSocketImpl.this.write(b, pos, size); |
837 byte[] a = new byte[]{(byte) b}; |
810 pos += n; |
838 write(a, 0, 1); |
811 } |
839 } |
812 } catch (IOException ioe) { |
840 @Override |
813 throw new SocketException(ioe.getMessage()); |
841 public void write(byte[] b, int off, int len) throws IOException { |
|
842 Objects.checkFromIndexSize(off, len, b.length); |
|
843 if (len > 0) { |
|
844 try { |
|
845 int pos = off; |
|
846 int end = off + len; |
|
847 while (pos < end) { |
|
848 // write up to MAX_BUFFER_SIZE bytes |
|
849 int size = Math.min((end - pos), MAX_BUFFER_SIZE); |
|
850 int n = impl.write(b, pos, size); |
|
851 pos += n; |
|
852 } |
814 } |
853 } catch (IOException ioe) { |
815 } |
854 throw new SocketException(ioe.getMessage()); |
816 } |
855 } |
817 |
856 } |
818 @Override |
857 } |
819 public void close() throws IOException { |
858 @Override |
820 NioSocketImpl.this.close(); |
859 public void close() throws IOException { |
821 } |
860 impl.close(); |
822 }; |
861 } |
|
862 } |
823 } |
863 |
824 |
864 @Override |
825 @Override |
865 protected int available() throws IOException { |
826 protected int available() throws IOException { |
866 readLock.lock(); |
827 readLock.lock(); |