--- a/.hgtags Thu Apr 19 21:11:32 2018 +0200
+++ b/.hgtags Thu Apr 19 21:21:45 2018 +0200
@@ -481,3 +481,4 @@
755e1b55a4dff510f9639cdb5c5e82549a7e09b3 jdk-11+8
0c3e252cea44f06aef570ef464950ab97c669970 jdk-11+9
6fa770f9f8ab296e1ce255ec17ccf6d4e1051886 jdk-10+46
+69d7398038c54774d9395b6810e0cca335edc02c jdk-11+10
--- a/make/data/charsetmapping/charsets Thu Apr 19 21:11:32 2018 +0200
+++ b/make/data/charsetmapping/charsets Thu Apr 19 21:21:45 2018 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -326,6 +326,8 @@
ascii true
alias cp1252 # JDK historical
alias cp5348 # Euro IBM CCSID
+ alias ibm-1252
+ alias ibm1252
charset windows-1253 MS1253
package sun.nio.cs
@@ -933,11 +935,16 @@
charset x-IBM942C IBM942C
package sun.nio.cs.ext
- type source
+ type template
alias cp942C # JDK historical
alias ibm942C
alias ibm-942C
alias 942C
+ alias cp932
+ alias ibm932
+ alias ibm-932
+ alias 932
+ alias x-ibm932
charset x-IBM943 IBM943
package sun.nio.cs.ext
@@ -952,7 +959,7 @@
charset x-IBM943C IBM943C
package sun.nio.cs.ext
- type source
+ type template
alias cp943C # JDK historical
alias ibm943C
alias ibm-943C
@@ -1519,6 +1526,9 @@
alias ibm1383
alias ibm-1383
alias 1383
+ alias ibmeuccn
+ alias ibm-euccn
+ alias cpeuccn
charset x-IBM970 IBM970
package sun.nio.cs.ext
--- a/make/data/charsetmapping/stdcs-aix Thu Apr 19 21:11:32 2018 +0200
+++ b/make/data/charsetmapping/stdcs-aix Thu Apr 19 21:21:45 2018 +0200
@@ -1,6 +1,26 @@
#
# generate these charsets into sun.nio.cs
#
+Big5
+Big5_Solaris
+Big5_HKSCS
EUC_CN
EUC_KR
GBK
+GB18030
+IBM856
+IBM921
+IBM922
+IBM942
+IBM942C
+IBM943
+IBM943C
+IBM950
+IBM970
+IBM1046
+IBM1124
+IBM1383
+ISO_8859_6
+ISO_8859_8
+MS1252
+TIS_620
--- a/make/jdk/src/classes/build/tools/charsetmapping/SPI.java Thu Apr 19 21:11:32 2018 +0200
+++ b/make/jdk/src/classes/build/tools/charsetmapping/SPI.java Thu Apr 19 21:21:45 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -129,7 +129,7 @@
} else if (line.indexOf("_INCLUDE_ALIASES_MAP_") != -1) {
Hasher.genClass(out, aliasKeys, aliasValues,
null, "Aliases", "String",
- 11, 3, true, false, false);
+ 12, 3, true, false, false);
} else if (line.indexOf("_INCLUDE_CLASSES_MAP_") != -1) {
Hasher.genClass(out, clzKeys, clzValues,
null, "Classes", "String",
--- a/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.cpp Thu Apr 19 21:11:32 2018 +0200
+++ b/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.cpp Thu Apr 19 21:21:45 2018 +0200
@@ -44,12 +44,6 @@
}
}
-
-void ModRefBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Address dst, Register val, Register tmp1, Register tmp2) {
- BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2);
-}
-
void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address dst, Register val, Register tmp1, Register tmp2) {
if (type == T_OBJECT || type == T_ARRAY) {
--- a/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.hpp Thu Apr 19 21:11:32 2018 +0200
+++ b/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.hpp Thu Apr 19 21:21:45 2018 +0200
@@ -40,7 +40,7 @@
Register start, Register end, Register tmp, RegSet saved_regs) {}
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Address dst, Register val, Register tmp1, Register tmp2);
+ Address dst, Register val, Register tmp1, Register tmp2) = 0;
public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
--- a/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp Thu Apr 19 21:11:32 2018 +0200
+++ b/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp Thu Apr 19 21:21:45 2018 +0200
@@ -56,12 +56,6 @@
}
}
-void ModRefBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- Register base, RegisterOrConstant ind_or_offs, Register val,
- Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
- BarrierSetAssembler::store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, needs_frame);
-}
-
void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register base, RegisterOrConstant ind_or_offs, Register val,
Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
--- a/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.hpp Thu Apr 19 21:11:32 2018 +0200
+++ b/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.hpp Thu Apr 19 21:21:45 2018 +0200
@@ -41,7 +41,7 @@
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register base, RegisterOrConstant ind_or_offs, Register val,
- Register tmp1, Register tmp2, Register tmp3, bool needs_frame);
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame) = 0;
public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register src, Register dst, Register count, Register preserve1, Register preserve2);
--- a/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.cpp Thu Apr 19 21:11:32 2018 +0200
+++ b/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.cpp Thu Apr 19 21:21:45 2018 +0200
@@ -50,11 +50,6 @@
}
}
-void ModRefBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
- BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
-}
-
void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
if (type == T_OBJECT || type == T_ARRAY) {
--- a/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.hpp Thu Apr 19 21:11:32 2018 +0200
+++ b/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.hpp Thu Apr 19 21:21:45 2018 +0200
@@ -39,7 +39,7 @@
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count,
bool do_return);
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
- const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3);
+ const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3) = 0;
public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register src, Register dst, Register count);
--- a/src/java.base/share/classes/java/util/zip/Deflater.java Thu Apr 19 21:11:32 2018 +0200
+++ b/src/java.base/share/classes/java/util/zip/Deflater.java Thu Apr 19 21:21:45 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,13 @@
package java.util.zip;
import java.lang.ref.Cleaner.Cleanable;
+import java.lang.ref.Reference;
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.util.Objects;
+
import jdk.internal.ref.CleanerFactory;
+import sun.nio.ch.DirectBuffer;
/**
* This class provides support for general purpose compression using the
@@ -35,8 +41,14 @@
* protected by patents. It is fully described in the specifications at
* the <a href="package-summary.html#package.description">java.util.zip
* package description</a>.
- *
- * <p>The following code fragment demonstrates a trivial compression
+ * <p>
+ * This class deflates sequences of bytes into ZLIB compressed data format.
+ * The input byte sequence is provided in either byte array or byte buffer,
+ * via one of the {@code setInput()} methods. The output byte sequence is
+ * written to the output byte array or byte buffer passed to the
+ * {@code deflate()} methods.
+ * <p>
+ * The following code fragment demonstrates a trivial compression
* and decompression of a string using {@code Deflater} and
* {@code Inflater}.
*
@@ -92,8 +104,9 @@
public class Deflater {
private final DeflaterZStreamRef zsRef;
- private byte[] buf = new byte[0];
- private int off, len;
+ private ByteBuffer input = ZipUtils.defaultBuf;
+ private byte[] inputArray;
+ private int inputPos, inputLim;
private int level, strategy;
private boolean setParams;
private boolean finish, finished;
@@ -170,9 +183,14 @@
*/
public static final int FULL_FLUSH = 3;
+ /**
+ * Flush mode to use at the end of output. Can only be provided by the
+ * user by way of {@link #finish()}.
+ */
+ private static final int FINISH = 4;
+
static {
ZipUtils.loadLibrary();
- initIDs();
}
/**
@@ -208,59 +226,70 @@
}
/**
- * Sets input data for compression. This should be called whenever
- * needsInput() returns true indicating that more input data is required.
- * @param b the input data bytes
+ * Sets input data for compression.
+ * <p>
+ * One of the {@code setInput()} methods should be called whenever
+ * {@code needsInput()} returns true indicating that more input data
+ * is required.
+ * <p>
+ * @param input the input data bytes
* @param off the start offset of the data
* @param len the length of the data
* @see Deflater#needsInput
*/
- public void setInput(byte[] b, int off, int len) {
- if (b== null) {
- throw new NullPointerException();
- }
- if (off < 0 || len < 0 || off > b.length - len) {
+ public void setInput(byte[] input, int off, int len) {
+ if (off < 0 || len < 0 || off > input.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
synchronized (zsRef) {
- this.buf = b;
- this.off = off;
- this.len = len;
+ this.input = null;
+ this.inputArray = input;
+ this.inputPos = off;
+ this.inputLim = off + len;
}
}
/**
- * Sets input data for compression. This should be called whenever
- * needsInput() returns true indicating that more input data is required.
- * @param b the input data bytes
+ * Sets input data for compression.
+ * <p>
+ * One of the {@code setInput()} methods should be called whenever
+ * {@code needsInput()} returns true indicating that more input data
+ * is required.
+ * <p>
+ * @param input the input data bytes
* @see Deflater#needsInput
*/
- public void setInput(byte[] b) {
- setInput(b, 0, b.length);
+ public void setInput(byte[] input) {
+ setInput(input, 0, input.length);
}
/**
- * Sets preset dictionary for compression. A preset dictionary is used
- * when the history buffer can be predetermined. When the data is later
- * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
- * in order to get the Adler-32 value of the dictionary required for
- * decompression.
- * @param b the dictionary data bytes
- * @param off the start offset of the data
- * @param len the length of the data
- * @see Inflater#inflate
- * @see Inflater#getAdler
+ * Sets input data for compression.
+ * <p>
+ * One of the {@code setInput()} methods should be called whenever
+ * {@code needsInput()} returns true indicating that more input data
+ * is required.
+ * <p>
+ * The given buffer's position will be advanced as deflate
+ * operations are performed, up to the buffer's limit.
+ * The input buffer may be modified (refilled) between deflate
+ * operations; doing so is equivalent to creating a new buffer
+ * and setting it with this method.
+ * <p>
+ * Modifying the input buffer's contents, position, or limit
+ * concurrently with an deflate operation will result in
+ * undefined behavior, which may include incorrect operation
+ * results or operation failure.
+ *
+ * @param input the input data bytes
+ * @see Deflater#needsInput
+ * @since 11
*/
- public void setDictionary(byte[] b, int off, int len) {
- if (b == null) {
- throw new NullPointerException();
- }
- if (off < 0 || len < 0 || off > b.length - len) {
- throw new ArrayIndexOutOfBoundsException();
- }
+ public void setInput(ByteBuffer input) {
+ Objects.requireNonNull(input);
synchronized (zsRef) {
- ensureOpen();
- setDictionary(zsRef.address(), b, off, len);
+ this.input = input;
+ this.inputArray = null;
}
}
@@ -270,12 +299,69 @@
* uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
* in order to get the Adler-32 value of the dictionary required for
* decompression.
- * @param b the dictionary data bytes
+ * @param dictionary the dictionary data bytes
+ * @param off the start offset of the data
+ * @param len the length of the data
+ * @see Inflater#inflate
+ * @see Inflater#getAdler
+ */
+ public void setDictionary(byte[] dictionary, int off, int len) {
+ if (off < 0 || len < 0 || off > dictionary.length - len) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ synchronized (zsRef) {
+ ensureOpen();
+ setDictionary(zsRef.address(), dictionary, off, len);
+ }
+ }
+
+ /**
+ * Sets preset dictionary for compression. A preset dictionary is used
+ * when the history buffer can be predetermined. When the data is later
+ * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
+ * in order to get the Adler-32 value of the dictionary required for
+ * decompression.
+ * @param dictionary the dictionary data bytes
* @see Inflater#inflate
* @see Inflater#getAdler
*/
- public void setDictionary(byte[] b) {
- setDictionary(b, 0, b.length);
+ public void setDictionary(byte[] dictionary) {
+ setDictionary(dictionary, 0, dictionary.length);
+ }
+
+ /**
+ * Sets preset dictionary for compression. A preset dictionary is used
+ * when the history buffer can be predetermined. When the data is later
+ * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
+ * in order to get the Adler-32 value of the dictionary required for
+ * decompression.
+ * <p>
+ * The bytes in given byte buffer will be fully consumed by this method. On
+ * return, its position will equal its limit.
+ *
+ * @param dictionary the dictionary data bytes
+ * @see Inflater#inflate
+ * @see Inflater#getAdler
+ */
+ public void setDictionary(ByteBuffer dictionary) {
+ synchronized (zsRef) {
+ int position = dictionary.position();
+ int remaining = Math.max(dictionary.limit() - position, 0);
+ ensureOpen();
+ if (dictionary.isDirect()) {
+ long address = ((DirectBuffer) dictionary).address();
+ try {
+ setDictionaryBuffer(zsRef.address(), address + position, remaining);
+ } finally {
+ Reference.reachabilityFence(dictionary);
+ }
+ } else {
+ byte[] array = ZipUtils.getBufferArray(dictionary);
+ int offset = ZipUtils.getBufferOffset(dictionary);
+ setDictionary(zsRef.address(), array, offset + position, remaining);
+ }
+ dictionary.position(position + remaining);
+ }
}
/**
@@ -331,14 +417,17 @@
}
/**
- * Returns true if the input data buffer is empty and setInput()
- * should be called in order to provide more input.
+ * Returns true if no data remains in the input buffer. This can
+ * be used to determine if one of the {@code setInput()} methods should be
+ * called in order to provide more input.
+ *
* @return true if the input data buffer is empty and setInput()
* should be called in order to provide more input
*/
public boolean needsInput() {
synchronized (zsRef) {
- return len <= 0;
+ ByteBuffer input = this.input;
+ return input == null ? inputLim == inputPos : ! input.hasRemaining();
}
}
@@ -375,14 +464,14 @@
* yields the same result as the invocation of
* {@code deflater.deflate(b, off, len, Deflater.NO_FLUSH)}.
*
- * @param b the buffer for the compressed data
+ * @param output the buffer for the compressed data
* @param off the start offset of the data
* @param len the maximum number of bytes of compressed data
* @return the actual number of bytes of compressed data written to the
* output buffer
*/
- public int deflate(byte[] b, int off, int len) {
- return deflate(b, off, len, NO_FLUSH);
+ public int deflate(byte[] output, int off, int len) {
+ return deflate(output, off, len, NO_FLUSH);
}
/**
@@ -396,12 +485,32 @@
* yields the same result as the invocation of
* {@code deflater.deflate(b, 0, b.length, Deflater.NO_FLUSH)}.
*
- * @param b the buffer for the compressed data
+ * @param output the buffer for the compressed data
* @return the actual number of bytes of compressed data written to the
* output buffer
*/
- public int deflate(byte[] b) {
- return deflate(b, 0, b.length, NO_FLUSH);
+ public int deflate(byte[] output) {
+ return deflate(output, 0, output.length, NO_FLUSH);
+ }
+
+ /**
+ * Compresses the input data and fills specified buffer with compressed
+ * data. Returns actual number of bytes of compressed data. A return value
+ * of 0 indicates that {@link #needsInput() needsInput} should be called
+ * in order to determine if more input data is required.
+ *
+ * <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
+ * An invocation of this method of the form {@code deflater.deflate(output)}
+ * yields the same result as the invocation of
+ * {@code deflater.deflate(output, Deflater.NO_FLUSH)}.
+ *
+ * @param output the buffer for the compressed data
+ * @return the actual number of bytes of compressed data written to the
+ * output buffer
+ * @since 11
+ */
+ public int deflate(ByteBuffer output) {
+ return deflate(output, NO_FLUSH);
}
/**
@@ -441,7 +550,11 @@
* repeatedly output to the output buffer every time this method is
* invoked.
*
- * @param b the buffer for the compressed data
+ * <p>If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
+ * for input, the input buffer's position will be advanced by the number of bytes
+ * consumed by this operation.
+ *
+ * @param output the buffer for the compressed data
* @param off the start offset of the data
* @param len the maximum number of bytes of compressed data
* @param flush the compression flush mode
@@ -451,25 +564,248 @@
* @throws IllegalArgumentException if the flush mode is invalid
* @since 1.7
*/
- public int deflate(byte[] b, int off, int len, int flush) {
- if (b == null) {
- throw new NullPointerException();
+ public int deflate(byte[] output, int off, int len, int flush) {
+ if (off < 0 || len < 0 || off > output.length - len) {
+ throw new ArrayIndexOutOfBoundsException();
}
- if (off < 0 || len < 0 || off > b.length - len) {
- throw new ArrayIndexOutOfBoundsException();
+ if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) {
+ throw new IllegalArgumentException();
}
synchronized (zsRef) {
ensureOpen();
- if (flush == NO_FLUSH || flush == SYNC_FLUSH ||
- flush == FULL_FLUSH) {
- int thisLen = this.len;
- int n = deflateBytes(zsRef.address(), b, off, len, flush);
- bytesWritten += n;
- bytesRead += (thisLen - this.len);
- return n;
+
+ ByteBuffer input = this.input;
+ if (finish) {
+ // disregard given flush mode in this case
+ flush = FINISH;
+ }
+ int params;
+ if (setParams) {
+ // bit 0: true to set params
+ // bit 1-2: strategy (0, 1, or 2)
+ // bit 3-31: level (0..9 or -1)
+ params = 1 | strategy << 1 | level << 3;
+ } else {
+ params = 0;
+ }
+ int inputPos;
+ long result;
+ if (input == null) {
+ inputPos = this.inputPos;
+ result = deflateBytesBytes(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ output, off, len,
+ flush, params);
+ } else {
+ inputPos = input.position();
+ int inputRem = Math.max(input.limit() - inputPos, 0);
+ if (input.isDirect()) {
+ try {
+ long inputAddress = ((DirectBuffer) input).address();
+ result = deflateBufferBytes(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ output, off, len,
+ flush, params);
+ } finally {
+ Reference.reachabilityFence(input);
+ }
+ } else {
+ byte[] inputArray = ZipUtils.getBufferArray(input);
+ int inputOffset = ZipUtils.getBufferOffset(input);
+ result = deflateBytesBytes(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ output, off, len,
+ flush, params);
+ }
+ }
+ int read = (int) (result & 0x7fff_ffffL);
+ int written = (int) (result >>> 31 & 0x7fff_ffffL);
+ if ((result >>> 62 & 1) != 0) {
+ finished = true;
+ }
+ if (params != 0 && (result >>> 63 & 1) == 0) {
+ setParams = false;
+ }
+ if (input != null) {
+ input.position(inputPos + read);
+ } else {
+ this.inputPos = inputPos + read;
}
+ bytesWritten += written;
+ bytesRead += read;
+ return written;
+ }
+ }
+
+ /**
+ * Compresses the input data and fills the specified buffer with compressed
+ * data. Returns actual number of bytes of data compressed.
+ *
+ * <p>Compression flush mode is one of the following three modes:
+ *
+ * <ul>
+ * <li>{@link #NO_FLUSH}: allows the deflater to decide how much data
+ * to accumulate, before producing output, in order to achieve the best
+ * compression (should be used in normal use scenario). A return value
+ * of 0 in this flush mode indicates that {@link #needsInput()} should
+ * be called in order to determine if more input data is required.
+ *
+ * <li>{@link #SYNC_FLUSH}: all pending output in the deflater is flushed,
+ * to the specified output buffer, so that an inflater that works on
+ * compressed data can get all input data available so far (In particular
+ * the {@link #needsInput()} returns {@code true} after this invocation
+ * if enough output space is provided). Flushing with {@link #SYNC_FLUSH}
+ * may degrade compression for some compression algorithms and so it
+ * should be used only when necessary.
+ *
+ * <li>{@link #FULL_FLUSH}: all pending output is flushed out as with
+ * {@link #SYNC_FLUSH}. The compression state is reset so that the inflater
+ * that works on the compressed output data can restart from this point
+ * if previous compressed data has been damaged or if random access is
+ * desired. Using {@link #FULL_FLUSH} too often can seriously degrade
+ * compression.
+ * </ul>
+ *
+ * <p>In the case of {@link #FULL_FLUSH} or {@link #SYNC_FLUSH}, if
+ * the return value is equal to the {@linkplain ByteBuffer#remaining() remaining space}
+ * of the buffer, this method should be invoked again with the same
+ * {@code flush} parameter and more output space. Make sure that
+ * the buffer has at least 6 bytes of remaining space to avoid the
+ * flush marker (5 bytes) being repeatedly output to the output buffer
+ * every time this method is invoked.
+ *
+ * <p>On success, the position of the given {@code output} byte buffer will be
+ * advanced by as many bytes as were produced by the operation, which is equal
+ * to the number returned by this method.
+ *
+ * <p>If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
+ * for input, the input buffer's position will be advanced by the number of bytes
+ * consumed by this operation.
+ *
+ * @param output the buffer for the compressed data
+ * @param flush the compression flush mode
+ * @return the actual number of bytes of compressed data written to
+ * the output buffer
+ *
+ * @throws IllegalArgumentException if the flush mode is invalid
+ * @since 11
+ */
+ public int deflate(ByteBuffer output, int flush) {
+ if (output.isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ }
+ if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) {
throw new IllegalArgumentException();
}
+ synchronized (zsRef) {
+ ensureOpen();
+
+ ByteBuffer input = this.input;
+ if (finish) {
+ // disregard given flush mode in this case
+ flush = FINISH;
+ }
+ int params;
+ if (setParams) {
+ // bit 0: true to set params
+ // bit 1-2: strategy (0, 1, or 2)
+ // bit 3-31: level (0..9 or -1)
+ params = 1 | strategy << 1 | level << 3;
+ } else {
+ params = 0;
+ }
+ int outputPos = output.position();
+ int outputRem = Math.max(output.limit() - outputPos, 0);
+ int inputPos;
+ long result;
+ if (input == null) {
+ inputPos = this.inputPos;
+ if (output.isDirect()) {
+ long outputAddress = ((DirectBuffer) output).address();
+ try {
+ result = deflateBytesBuffer(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ outputAddress + outputPos, outputRem,
+ flush, params);
+ } finally {
+ Reference.reachabilityFence(output);
+ }
+ } else {
+ byte[] outputArray = ZipUtils.getBufferArray(output);
+ int outputOffset = ZipUtils.getBufferOffset(output);
+ result = deflateBytesBytes(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ outputArray, outputOffset + outputPos, outputRem,
+ flush, params);
+ }
+ } else {
+ inputPos = input.position();
+ int inputRem = Math.max(input.limit() - inputPos, 0);
+ if (input.isDirect()) {
+ long inputAddress = ((DirectBuffer) input).address();
+ try {
+ if (output.isDirect()) {
+ long outputAddress = outputPos + ((DirectBuffer) output).address();
+ try {
+ result = deflateBufferBuffer(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ outputAddress, outputRem,
+ flush, params);
+ } finally {
+ Reference.reachabilityFence(output);
+ }
+ } else {
+ byte[] outputArray = ZipUtils.getBufferArray(output);
+ int outputOffset = ZipUtils.getBufferOffset(output);
+ result = deflateBufferBytes(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ outputArray, outputOffset + outputPos, outputRem,
+ flush, params);
+ }
+ } finally {
+ Reference.reachabilityFence(input);
+ }
+ } else {
+ byte[] inputArray = ZipUtils.getBufferArray(input);
+ int inputOffset = ZipUtils.getBufferOffset(input);
+ if (output.isDirect()) {
+ long outputAddress = ((DirectBuffer) output).address();
+ try {
+ result = deflateBytesBuffer(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ outputAddress + outputPos, outputRem,
+ flush, params);
+ } finally {
+ Reference.reachabilityFence(output);
+ }
+ } else {
+ byte[] outputArray = ZipUtils.getBufferArray(output);
+ int outputOffset = ZipUtils.getBufferOffset(output);
+ result = deflateBytesBytes(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ outputArray, outputOffset + outputPos, outputRem,
+ flush, params);
+ }
+ }
+ }
+ int read = (int) (result & 0x7fff_ffffL);
+ int written = (int) (result >>> 31 & 0x7fff_ffffL);
+ if ((result >>> 62 & 1) != 0) {
+ finished = true;
+ }
+ if (params != 0 && (result >>> 63 & 1) == 0) {
+ setParams = false;
+ }
+ if (input != null) {
+ input.position(inputPos + read);
+ } else {
+ this.inputPos = inputPos + read;
+ }
+ output.position(outputPos + written);
+ bytesWritten += written;
+ bytesRead += read;
+ return written;
+ }
}
/**
@@ -545,7 +881,8 @@
reset(zsRef.address());
finish = false;
finished = false;
- off = len = 0;
+ input = ZipUtils.defaultBuf;
+ inputArray = null;
bytesRead = bytesWritten = 0;
}
}
@@ -560,7 +897,7 @@
public void end() {
synchronized (zsRef) {
zsRef.clean();
- buf = null;
+ input = ZipUtils.defaultBuf;
}
}
@@ -585,11 +922,26 @@
throw new NullPointerException("Deflater has been closed");
}
- private static native void initIDs();
private static native long init(int level, int strategy, boolean nowrap);
- private static native void setDictionary(long addr, byte[] b, int off, int len);
- private native int deflateBytes(long addr, byte[] b, int off, int len,
- int flush);
+ private static native void setDictionary(long addr, byte[] b, int off,
+ int len);
+ private static native void setDictionaryBuffer(long addr, long bufAddress, int len);
+ private native long deflateBytesBytes(long addr,
+ byte[] inputArray, int inputOff, int inputLen,
+ byte[] outputArray, int outputOff, int outputLen,
+ int flush, int params);
+ private native long deflateBytesBuffer(long addr,
+ byte[] inputArray, int inputOff, int inputLen,
+ long outputAddress, int outputLen,
+ int flush, int params);
+ private native long deflateBufferBytes(long addr,
+ long inputAddress, int inputLen,
+ byte[] outputArray, int outputOff, int outputLen,
+ int flush, int params);
+ private native long deflateBufferBuffer(long addr,
+ long inputAddress, int inputLen,
+ long outputAddress, int outputLen,
+ int flush, int params);
private static native int getAdler(long addr);
private static native void reset(long addr);
private static native void end(long addr);
--- a/src/java.base/share/classes/java/util/zip/Inflater.java Thu Apr 19 21:11:32 2018 +0200
+++ b/src/java.base/share/classes/java/util/zip/Inflater.java Thu Apr 19 21:21:45 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,13 @@
package java.util.zip;
import java.lang.ref.Cleaner.Cleanable;
+import java.lang.ref.Reference;
+import java.nio.ByteBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.util.Objects;
+
import jdk.internal.ref.CleanerFactory;
+import sun.nio.ch.DirectBuffer;
/**
* This class provides support for general purpose decompression using the
@@ -35,8 +41,13 @@
* protected by patents. It is fully described in the specifications at
* the <a href="package-summary.html#package.description">java.util.zip
* package description</a>.
- *
- * <p>The following code fragment demonstrates a trivial compression
+ * <p>
+ * This class inflates sequences of ZLIB compressed bytes. The input byte
+ * sequence is provided in either byte array or byte buffer, via one of the
+ * {@code setInput()} methods. The output byte sequence is written to the
+ * output byte array or byte buffer passed to the {@code deflate()} methods.
+ * <p>
+ * The following code fragment demonstrates a trivial compression
* and decompression of a string using {@code Deflater} and
* {@code Inflater}.
*
@@ -92,14 +103,20 @@
public class Inflater {
private final InflaterZStreamRef zsRef;
- private byte[] buf = defaultBuf;
- private int off, len;
+ private ByteBuffer input = ZipUtils.defaultBuf;
+ private byte[] inputArray;
+ private int inputPos, inputLim;
private boolean finished;
private boolean needDict;
private long bytesRead;
private long bytesWritten;
- private static final byte[] defaultBuf = new byte[0];
+ /*
+ * These fields are used as an "out" parameter from JNI when a
+ * DataFormatException is thrown during the inflate operation.
+ */
+ private int inputConsumed;
+ private int outputConsumed;
static {
ZipUtils.loadLibrary();
@@ -129,37 +146,71 @@
}
/**
- * Sets input data for decompression. Should be called whenever
- * needsInput() returns true indicating that more input data is
- * required.
- * @param b the input data bytes
+ * Sets input data for decompression.
+ * <p>
+ * One of the {@code setInput()} methods should be called whenever
+ * {@code needsInput()} returns true indicating that more input data
+ * is required.
+ *
+ * @param input the input data bytes
* @param off the start offset of the input data
* @param len the length of the input data
* @see Inflater#needsInput
*/
- public void setInput(byte[] b, int off, int len) {
- if (b == null) {
- throw new NullPointerException();
- }
- if (off < 0 || len < 0 || off > b.length - len) {
+ public void setInput(byte[] input, int off, int len) {
+ if (off < 0 || len < 0 || off > input.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
synchronized (zsRef) {
- this.buf = b;
- this.off = off;
- this.len = len;
+ this.input = null;
+ this.inputArray = input;
+ this.inputPos = off;
+ this.inputLim = off + len;
}
}
/**
- * Sets input data for decompression. Should be called whenever
- * needsInput() returns true indicating that more input data is
- * required.
- * @param b the input data bytes
+ * Sets input data for decompression.
+ * <p>
+ * One of the {@code setInput()} methods should be called whenever
+ * {@code needsInput()} returns true indicating that more input data
+ * is required.
+ *
+ * @param input the input data bytes
* @see Inflater#needsInput
*/
- public void setInput(byte[] b) {
- setInput(b, 0, b.length);
+ public void setInput(byte[] input) {
+ setInput(input, 0, input.length);
+ }
+
+ /**
+ * Sets input data for decompression.
+ * <p>
+ * One of the {@code setInput()} methods should be called whenever
+ * {@code needsInput()} returns true indicating that more input data
+ * is required.
+ * <p>
+ * The given buffer's position will be advanced as inflate
+ * operations are performed, up to the buffer's limit.
+ * The input buffer may be modified (refilled) between inflate
+ * operations; doing so is equivalent to creating a new buffer
+ * and setting it with this method.
+ * <p>
+ * Modifying the input buffer's contents, position, or limit
+ * concurrently with an inflate operation will result in
+ * undefined behavior, which may include incorrect operation
+ * results or operation failure.
+ *
+ * @param input the input data bytes
+ * @see Inflater#needsInput
+ * @since 11
+ */
+ public void setInput(ByteBuffer input) {
+ Objects.requireNonNull(input);
+ synchronized (zsRef) {
+ this.input = input;
+ this.inputArray = null;
+ }
}
/**
@@ -167,22 +218,19 @@
* called when inflate() returns 0 and needsDictionary() returns true
* indicating that a preset dictionary is required. The method getAdler()
* can be used to get the Adler-32 value of the dictionary needed.
- * @param b the dictionary data bytes
+ * @param dictionary the dictionary data bytes
* @param off the start offset of the data
* @param len the length of the data
* @see Inflater#needsDictionary
* @see Inflater#getAdler
*/
- public void setDictionary(byte[] b, int off, int len) {
- if (b == null) {
- throw new NullPointerException();
- }
- if (off < 0 || len < 0 || off > b.length - len) {
+ public void setDictionary(byte[] dictionary, int off, int len) {
+ if (off < 0 || len < 0 || off > dictionary.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
synchronized (zsRef) {
ensureOpen();
- setDictionary(zsRef.address(), b, off, len);
+ setDictionary(zsRef.address(), dictionary, off, len);
needDict = false;
}
}
@@ -192,12 +240,48 @@
* called when inflate() returns 0 and needsDictionary() returns true
* indicating that a preset dictionary is required. The method getAdler()
* can be used to get the Adler-32 value of the dictionary needed.
- * @param b the dictionary data bytes
+ * @param dictionary the dictionary data bytes
* @see Inflater#needsDictionary
* @see Inflater#getAdler
*/
- public void setDictionary(byte[] b) {
- setDictionary(b, 0, b.length);
+ public void setDictionary(byte[] dictionary) {
+ setDictionary(dictionary, 0, dictionary.length);
+ }
+
+ /**
+ * Sets the preset dictionary to the bytes in the given buffer. Should be
+ * called when inflate() returns 0 and needsDictionary() returns true
+ * indicating that a preset dictionary is required. The method getAdler()
+ * can be used to get the Adler-32 value of the dictionary needed.
+ * <p>
+ * The bytes in given byte buffer will be fully consumed by this method. On
+ * return, its position will equal its limit.
+ *
+ * @param dictionary the dictionary data bytes
+ * @see Inflater#needsDictionary
+ * @see Inflater#getAdler
+ * @since 11
+ */
+ public void setDictionary(ByteBuffer dictionary) {
+ synchronized (zsRef) {
+ int position = dictionary.position();
+ int remaining = Math.max(dictionary.limit() - position, 0);
+ ensureOpen();
+ if (dictionary.isDirect()) {
+ long address = ((DirectBuffer) dictionary).address();
+ try {
+ setDictionaryBuffer(zsRef.address(), address + position, remaining);
+ } finally {
+ Reference.reachabilityFence(dictionary);
+ }
+ } else {
+ byte[] array = ZipUtils.getBufferArray(dictionary);
+ int offset = ZipUtils.getBufferOffset(dictionary);
+ setDictionary(zsRef.address(), array, offset + position, remaining);
+ }
+ dictionary.position(position + remaining);
+ needDict = false;
+ }
}
/**
@@ -208,19 +292,22 @@
*/
public int getRemaining() {
synchronized (zsRef) {
- return len;
+ ByteBuffer input = this.input;
+ return input == null ? inputLim - inputPos : input.remaining();
}
}
/**
* Returns true if no data remains in the input buffer. This can
- * be used to determine if #setInput should be called in order
- * to provide more input.
+ * be used to determine if one of the {@code setInput()} methods should be
+ * called in order to provide more input.
+ *
* @return true if no data remains in the input buffer
*/
public boolean needsInput() {
synchronized (zsRef) {
- return len <= 0;
+ ByteBuffer input = this.input;
+ return input == null ? inputLim == inputPos : ! input.hasRemaining();
}
}
@@ -254,30 +341,103 @@
* determine if more input data or a preset dictionary is required.
* In the latter case, getAdler() can be used to get the Adler-32
* value of the dictionary required.
- * @param b the buffer for the uncompressed data
+ * <p>
+ * If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
+ * for input, the input buffer's position will be advanced by the number of bytes
+ * consumed by this operation, even in the event that a {@link DataFormatException}
+ * is thrown.
+ * <p>
+ * The {@linkplain #getRemaining() remaining byte count} will be reduced by
+ * the number of consumed input bytes. If the {@link #setInput(ByteBuffer)}
+ * method was called to provide a buffer for input, the input buffer's position
+ * will be advanced the number of consumed bytes.
+ * <p>
+ * These byte totals, as well as
+ * the {@linkplain #getBytesRead() total bytes read}
+ * and the {@linkplain #getBytesWritten() total bytes written}
+ * values, will be updated even in the event that a {@link DataFormatException}
+ * is thrown to reflect the amount of data consumed and produced before the
+ * exception occurred.
+ *
+ * @param output the buffer for the uncompressed data
* @param off the start offset of the data
* @param len the maximum number of uncompressed bytes
* @return the actual number of uncompressed bytes
- * @exception DataFormatException if the compressed data format is invalid
+ * @throws DataFormatException if the compressed data format is invalid
* @see Inflater#needsInput
* @see Inflater#needsDictionary
*/
- public int inflate(byte[] b, int off, int len)
+ public int inflate(byte[] output, int off, int len)
throws DataFormatException
{
- if (b == null) {
- throw new NullPointerException();
- }
- if (off < 0 || len < 0 || off > b.length - len) {
+ if (off < 0 || len < 0 || off > output.length - len) {
throw new ArrayIndexOutOfBoundsException();
}
synchronized (zsRef) {
ensureOpen();
- int thisLen = this.len;
- int n = inflateBytes(zsRef.address(), b, off, len);
- bytesWritten += n;
- bytesRead += (thisLen - this.len);
- return n;
+ ByteBuffer input = this.input;
+ long result;
+ int inputPos;
+ try {
+ if (input == null) {
+ inputPos = this.inputPos;
+ try {
+ result = inflateBytesBytes(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ output, off, len);
+ } catch (DataFormatException e) {
+ this.inputPos = inputPos + inputConsumed;
+ throw e;
+ }
+ } else {
+ inputPos = input.position();
+ try {
+ int inputRem = Math.max(input.limit() - inputPos, 0);
+ if (input.isDirect()) {
+ try {
+ long inputAddress = ((DirectBuffer) input).address();
+ result = inflateBufferBytes(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ output, off, len);
+ } finally {
+ Reference.reachabilityFence(input);
+ }
+ } else {
+ byte[] inputArray = ZipUtils.getBufferArray(input);
+ int inputOffset = ZipUtils.getBufferOffset(input);
+ result = inflateBytesBytes(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ output, off, len);
+ }
+ } catch (DataFormatException e) {
+ input.position(inputPos + inputConsumed);
+ throw e;
+ }
+ }
+ } catch (DataFormatException e) {
+ bytesRead += inputConsumed;
+ inputConsumed = 0;
+ int written = outputConsumed;
+ bytesWritten += written;
+ outputConsumed = 0;
+ throw e;
+ }
+ int read = (int) (result & 0x7fff_ffffL);
+ int written = (int) (result >>> 31 & 0x7fff_ffffL);
+ if ((result >>> 62 & 1) != 0) {
+ finished = true;
+ }
+ if ((result >>> 63 & 1) != 0) {
+ needDict = true;
+ }
+ if (input != null) {
+ input.position(inputPos + read);
+ } else {
+ this.inputPos = inputPos + read;
+ }
+ bytesWritten += written;
+ bytesRead += read;
+ return written;
}
}
@@ -288,14 +448,177 @@
* determine if more input data or a preset dictionary is required.
* In the latter case, getAdler() can be used to get the Adler-32
* value of the dictionary required.
- * @param b the buffer for the uncompressed data
+ * <p>
+ * The {@linkplain #getRemaining() remaining byte count} will be reduced by
+ * the number of consumed input bytes. If the {@link #setInput(ByteBuffer)}
+ * method was called to provide a buffer for input, the input buffer's position
+ * will be advanced the number of consumed bytes.
+ * <p>
+ * These byte totals, as well as
+ * the {@linkplain #getBytesRead() total bytes read}
+ * and the {@linkplain #getBytesWritten() total bytes written}
+ * values, will be updated even in the event that a {@link DataFormatException}
+ * is thrown to reflect the amount of data consumed and produced before the
+ * exception occurred.
+ *
+ * @param output the buffer for the uncompressed data
* @return the actual number of uncompressed bytes
- * @exception DataFormatException if the compressed data format is invalid
+ * @throws DataFormatException if the compressed data format is invalid
* @see Inflater#needsInput
* @see Inflater#needsDictionary
*/
- public int inflate(byte[] b) throws DataFormatException {
- return inflate(b, 0, b.length);
+ public int inflate(byte[] output) throws DataFormatException {
+ return inflate(output, 0, output.length);
+ }
+
+ /**
+ * Uncompresses bytes into specified buffer. Returns actual number
+ * of bytes uncompressed. A return value of 0 indicates that
+ * needsInput() or needsDictionary() should be called in order to
+ * determine if more input data or a preset dictionary is required.
+ * In the latter case, getAdler() can be used to get the Adler-32
+ * value of the dictionary required.
+ * <p>
+ * On success, the position of the given {@code output} byte buffer will be
+ * advanced by as many bytes as were produced by the operation, which is equal
+ * to the number returned by this method. Note that the position of the
+ * {@code output} buffer will be advanced even in the event that a
+ * {@link DataFormatException} is thrown.
+ * <p>
+ * The {@linkplain #getRemaining() remaining byte count} will be reduced by
+ * the number of consumed input bytes. If the {@link #setInput(ByteBuffer)}
+ * method was called to provide a buffer for input, the input buffer's position
+ * will be advanced the number of consumed bytes.
+ * <p>
+ * These byte totals, as well as
+ * the {@linkplain #getBytesRead() total bytes read}
+ * and the {@linkplain #getBytesWritten() total bytes written}
+ * values, will be updated even in the event that a {@link DataFormatException}
+ * is thrown to reflect the amount of data consumed and produced before the
+ * exception occurred.
+ *
+ * @param output the buffer for the uncompressed data
+ * @return the actual number of uncompressed bytes
+ * @throws DataFormatException if the compressed data format is invalid
+ * @throws ReadOnlyBufferException if the given output buffer is read-only
+ * @see Inflater#needsInput
+ * @see Inflater#needsDictionary
+ * @since 11
+ */
+ public int inflate(ByteBuffer output) throws DataFormatException {
+ if (output.isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ }
+ synchronized (zsRef) {
+ ensureOpen();
+ ByteBuffer input = this.input;
+ long result;
+ int inputPos;
+ int outputPos = output.position();
+ int outputRem = Math.max(output.limit() - outputPos, 0);
+ try {
+ if (input == null) {
+ inputPos = this.inputPos;
+ try {
+ if (output.isDirect()) {
+ long outputAddress = ((DirectBuffer) output).address();
+ try {
+ result = inflateBytesBuffer(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ outputAddress + outputPos, outputRem);
+ } finally {
+ Reference.reachabilityFence(output);
+ }
+ } else {
+ byte[] outputArray = ZipUtils.getBufferArray(output);
+ int outputOffset = ZipUtils.getBufferOffset(output);
+ result = inflateBytesBytes(zsRef.address(),
+ inputArray, inputPos, inputLim - inputPos,
+ outputArray, outputOffset + outputPos, outputRem);
+ }
+ } catch (DataFormatException e) {
+ this.inputPos = inputPos + inputConsumed;
+ throw e;
+ }
+ } else {
+ inputPos = input.position();
+ int inputRem = Math.max(input.limit() - inputPos, 0);
+ try {
+ if (input.isDirect()) {
+ long inputAddress = ((DirectBuffer) input).address();
+ try {
+ if (output.isDirect()) {
+ long outputAddress = ((DirectBuffer) output).address();
+ try {
+ result = inflateBufferBuffer(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ outputAddress + outputPos, outputRem);
+ } finally {
+ Reference.reachabilityFence(output);
+ }
+ } else {
+ byte[] outputArray = ZipUtils.getBufferArray(output);
+ int outputOffset = ZipUtils.getBufferOffset(output);
+ result = inflateBufferBytes(zsRef.address(),
+ inputAddress + inputPos, inputRem,
+ outputArray, outputOffset + outputPos, outputRem);
+ }
+ } finally {
+ Reference.reachabilityFence(input);
+ }
+ } else {
+ byte[] inputArray = ZipUtils.getBufferArray(input);
+ int inputOffset = ZipUtils.getBufferOffset(input);
+ if (output.isDirect()) {
+ long outputAddress = ((DirectBuffer) output).address();
+ try {
+ result = inflateBytesBuffer(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ outputAddress + outputPos, outputRem);
+ } finally {
+ Reference.reachabilityFence(output);
+ }
+ } else {
+ byte[] outputArray = ZipUtils.getBufferArray(output);
+ int outputOffset = ZipUtils.getBufferOffset(output);
+ result = inflateBytesBytes(zsRef.address(),
+ inputArray, inputOffset + inputPos, inputRem,
+ outputArray, outputOffset + outputPos, outputRem);
+ }
+ }
+ } catch (DataFormatException e) {
+ input.position(inputPos + inputConsumed);
+ throw e;
+ }
+ }
+ } catch (DataFormatException e) {
+ bytesRead += inputConsumed;
+ inputConsumed = 0;
+ int written = outputConsumed;
+ output.position(outputPos + written);
+ bytesWritten += written;
+ outputConsumed = 0;
+ throw e;
+ }
+ int read = (int) (result & 0x7fff_ffffL);
+ int written = (int) (result >>> 31 & 0x7fff_ffffL);
+ if ((result >>> 62 & 1) != 0) {
+ finished = true;
+ }
+ if ((result >>> 63 & 1) != 0) {
+ needDict = true;
+ }
+ if (input != null) {
+ input.position(inputPos + read);
+ } else {
+ this.inputPos = inputPos + read;
+ }
+ // Note: this method call also serves to keep the byteBuffer ref alive
+ output.position(outputPos + written);
+ bytesWritten += written;
+ bytesRead += read;
+ return written;
+ }
}
/**
@@ -368,10 +691,10 @@
synchronized (zsRef) {
ensureOpen();
reset(zsRef.address());
- buf = defaultBuf;
+ input = ZipUtils.defaultBuf;
+ inputArray = null;
finished = false;
needDict = false;
- off = len = 0;
bytesRead = bytesWritten = 0;
}
}
@@ -386,7 +709,8 @@
public void end() {
synchronized (zsRef) {
zsRef.clean();
- buf = null;
+ input = ZipUtils.defaultBuf;
+ inputArray = null;
}
}
@@ -416,18 +740,23 @@
throw new NullPointerException("Inflater has been closed");
}
- boolean ended() {
- synchronized (zsRef) {
- return zsRef.address() == 0;
- }
- }
-
private static native void initIDs();
private static native long init(boolean nowrap);
private static native void setDictionary(long addr, byte[] b, int off,
int len);
- private native int inflateBytes(long addr, byte[] b, int off, int len)
- throws DataFormatException;
+ private static native void setDictionaryBuffer(long addr, long bufAddress, int len);
+ private native long inflateBytesBytes(long addr,
+ byte[] inputArray, int inputOff, int inputLen,
+ byte[] outputArray, int outputOff, int outputLen) throws DataFormatException;
+ private native long inflateBytesBuffer(long addr,
+ byte[] inputArray, int inputOff, int inputLen,
+ long outputAddress, int outputLen) throws DataFormatException;
+ private native long inflateBufferBytes(long addr,
+ long inputAddress, int inputLen,
+ byte[] outputArray, int outputOff, int outputLen) throws DataFormatException;
+ private native long inflateBufferBuffer(long addr,
+ long inputAddress, int inputLen,
+ long outputAddress, int outputLen) throws DataFormatException;
private static native int getAdler(long addr);
private static native void reset(long addr);
private static native void end(long addr);
--- a/src/java.base/share/classes/java/util/zip/ZipUtils.java Thu Apr 19 21:11:32 2018 +0200
+++ b/src/java.base/share/classes/java/util/zip/ZipUtils.java Thu Apr 19 21:21:45 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
package java.util.zip;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
import java.nio.file.attribute.FileTime;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -37,6 +39,9 @@
import static java.util.zip.ZipConstants.ENDHDR;
+import jdk.internal.misc.Unsafe;
+import sun.nio.ch.DirectBuffer;
+
class ZipUtils {
// used to adjust values between Windows and java epoch
@@ -45,6 +50,9 @@
// used to indicate the corresponding windows time is not available
public static final long WINDOWS_TIME_NOT_AVAILABLE = Long.MIN_VALUE;
+ // static final ByteBuffer defaultBuf = ByteBuffer.allocateDirect(0);
+ static final ByteBuffer defaultBuf = ByteBuffer.allocate(0);
+
/**
* Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
*/
@@ -281,4 +289,17 @@
AccessController.doPrivileged(pa);
}
}
+
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+ private static final long byteBufferArrayOffset = unsafe.objectFieldOffset(ByteBuffer.class, "hb");
+ private static final long byteBufferOffsetOffset = unsafe.objectFieldOffset(ByteBuffer.class, "offset");
+
+ static byte[] getBufferArray(ByteBuffer byteBuffer) {
+ return (byte[]) unsafe.getObject(byteBuffer, byteBufferArrayOffset);
+ }
+
+ static int getBufferOffset(ByteBuffer byteBuffer) {
+ return unsafe.getInt(byteBuffer, byteBufferOffsetOffset);
+ }
}
--- a/src/java.base/share/native/libzip/Deflater.c Thu Apr 19 21:11:32 2018 +0200
+++ b/src/java.base/share/native/libzip/Deflater.c Thu Apr 19 21:21:45 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,34 +38,6 @@
#define DEF_MEM_LEVEL 8
-static jfieldID levelID;
-static jfieldID strategyID;
-static jfieldID setParamsID;
-static jfieldID finishID;
-static jfieldID finishedID;
-static jfieldID bufID, offID, lenID;
-
-JNIEXPORT void JNICALL
-Java_java_util_zip_Deflater_initIDs(JNIEnv *env, jclass cls)
-{
- levelID = (*env)->GetFieldID(env, cls, "level", "I");
- CHECK_NULL(levelID);
- strategyID = (*env)->GetFieldID(env, cls, "strategy", "I");
- CHECK_NULL(strategyID);
- setParamsID = (*env)->GetFieldID(env, cls, "setParams", "Z");
- CHECK_NULL(setParamsID);
- finishID = (*env)->GetFieldID(env, cls, "finish", "Z");
- CHECK_NULL(finishID);
- finishedID = (*env)->GetFieldID(env, cls, "finished", "Z");
- CHECK_NULL(finishedID);
- bufID = (*env)->GetFieldID(env, cls, "buf", "[B");
- CHECK_NULL(bufID);
- offID = (*env)->GetFieldID(env, cls, "off", "I");
- CHECK_NULL(offID);
- lenID = (*env)->GetFieldID(env, cls, "len", "I");
- CHECK_NULL(lenID);
-}
-
JNIEXPORT jlong JNICALL
Java_java_util_zip_Deflater_init(JNIEnv *env, jclass cls, jint level,
jint strategy, jboolean nowrap)
@@ -104,17 +76,9 @@
}
}
-JNIEXPORT void JNICALL
-Java_java_util_zip_Deflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
- jarray b, jint off, jint len)
+static void doSetDictionary(JNIEnv *env, jlong addr, jbyte *buf, jint len)
{
- Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
- int res;
- if (buf == 0) {/* out of memory */
- return;
- }
- res = deflateSetDictionary((z_stream *)jlong_to_ptr(addr), buf + off, len);
- (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
+ int res = deflateSetDictionary(jlong_to_ptr(addr), (Bytef *) buf, len);
switch (res) {
case Z_OK:
break;
@@ -127,94 +91,173 @@
}
}
-JNIEXPORT jint JNICALL
-Java_java_util_zip_Deflater_deflateBytes(JNIEnv *env, jobject this, jlong addr,
- jarray b, jint off, jint len, jint flush)
+JNIEXPORT void JNICALL
+Java_java_util_zip_Deflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
+ jbyteArray b, jint off, jint len)
+{
+ jbyte *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
+ if (buf == NULL) /* out of memory */
+ return;
+ doSetDictionary(env, addr, buf + off, len);
+ (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Deflater_setDictionaryBuffer(JNIEnv *env, jclass cls, jlong addr,
+ jlong bufferAddr, jint len)
+{
+ jbyte *buf = jlong_to_ptr(bufferAddr);
+ doSetDictionary(env, addr, buf, len);
+}
+
+static jlong doDeflate(JNIEnv *env, jobject this, jlong addr,
+ jbyte *input, jint inputLen,
+ jbyte *output, jint outputLen,
+ jint flush, jint params)
{
z_stream *strm = jlong_to_ptr(addr);
+ jint inputUsed = 0, outputUsed = 0;
+ int finished = 0;
+ int setParams = params & 1;
- jarray this_buf = (*env)->GetObjectField(env, this, bufID);
- jint this_off = (*env)->GetIntField(env, this, offID);
- jint this_len = (*env)->GetIntField(env, this, lenID);
- jbyte *in_buf;
- jbyte *out_buf;
- int res;
- if ((*env)->GetBooleanField(env, this, setParamsID)) {
- int level = (*env)->GetIntField(env, this, levelID);
- int strategy = (*env)->GetIntField(env, this, strategyID);
- in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
- if (in_buf == NULL) {
- // Throw OOME only when length is not zero
- if (this_len != 0 && (*env)->ExceptionOccurred(env) == NULL)
- JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
- }
- out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
- if (out_buf == NULL) {
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
- if (len != 0 && (*env)->ExceptionOccurred(env) == NULL)
- JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
- }
+ strm->next_in = (Bytef *) input;
+ strm->next_out = (Bytef *) output;
+ strm->avail_in = inputLen;
+ strm->avail_out = outputLen;
- strm->next_in = (Bytef *) (in_buf + this_off);
- strm->next_out = (Bytef *) (out_buf + off);
- strm->avail_in = this_len;
- strm->avail_out = len;
- res = deflateParams(strm, level, strategy);
- (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
+ if (setParams) {
+ int strategy = (params >> 1) & 3;
+ int level = params >> 3;
+ int res = deflateParams(strm, level, strategy);
switch (res) {
case Z_OK:
- (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE);
+ setParams = 0;
+ /* fall through */
case Z_BUF_ERROR:
- this_off += this_len - strm->avail_in;
- (*env)->SetIntField(env, this, offID, this_off);
- (*env)->SetIntField(env, this, lenID, strm->avail_in);
- return (jint) (len - strm->avail_out);
+ inputUsed = inputLen - strm->avail_in;
+ outputUsed = outputLen - strm->avail_out;
+ break;
default:
JNU_ThrowInternalError(env, strm->msg);
return 0;
}
} else {
- jboolean finish = (*env)->GetBooleanField(env, this, finishID);
- in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
- if (in_buf == NULL) {
- if (this_len != 0)
- JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
- }
- out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
- if (out_buf == NULL) {
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
- if (len != 0)
- JNU_ThrowOutOfMemoryError(env, 0);
-
- return 0;
- }
-
- strm->next_in = (Bytef *) (in_buf + this_off);
- strm->next_out = (Bytef *) (out_buf + off);
- strm->avail_in = this_len;
- strm->avail_out = len;
- res = deflate(strm, finish ? Z_FINISH : flush);
- (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
+ int res = deflate(strm, flush);
switch (res) {
case Z_STREAM_END:
- (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE);
+ finished = 1;
/* fall through */
case Z_OK:
case Z_BUF_ERROR:
- this_off += this_len - strm->avail_in;
- (*env)->SetIntField(env, this, offID, this_off);
- (*env)->SetIntField(env, this, lenID, strm->avail_in);
- return len - strm->avail_out;
+ inputUsed = inputLen - strm->avail_in;
+ outputUsed = outputLen - strm->avail_out;
+ break;
default:
JNU_ThrowInternalError(env, strm->msg);
return 0;
}
}
+ return ((jlong)inputUsed) | (((jlong)outputUsed) << 31) | (((jlong)finished) << 62) | (((jlong)setParams) << 63);
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Deflater_deflateBytesBytes(JNIEnv *env, jobject this, jlong addr,
+ jbyteArray inputArray, jint inputOff, jint inputLen,
+ jbyteArray outputArray, jint outputOff, jint outputLen,
+ jint flush, jint params)
+{
+ jbyte *input = (*env)->GetPrimitiveArrayCritical(env, inputArray, 0);
+ jbyte *output;
+ jlong retVal;
+ if (input == NULL) {
+ if (inputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+ output = (*env)->GetPrimitiveArrayCritical(env, outputArray, 0);
+ if (output == NULL) {
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+ if (outputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+
+ retVal = doDeflate(env, this, addr,
+ input + inputOff, inputLen,
+ output + outputOff, outputLen,
+ flush, params);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, outputArray, output, 0);
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+
+ return retVal;
+}
+
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Deflater_deflateBytesBuffer(JNIEnv *env, jobject this, jlong addr,
+ jbyteArray inputArray, jint inputOff, jint inputLen,
+ jlong outputBuffer, jint outputLen,
+ jint flush, jint params)
+{
+ jbyte *input = (*env)->GetPrimitiveArrayCritical(env, inputArray, 0);
+ jbyte *output;
+ jlong retVal;
+ if (input == NULL) {
+ if (inputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+ output = jlong_to_ptr(outputBuffer);
+
+ retVal = doDeflate(env, this, addr,
+ input + inputOff, inputLen,
+ output, outputLen,
+ flush, params);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+
+ return retVal;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Deflater_deflateBufferBytes(JNIEnv *env, jobject this, jlong addr,
+ jlong inputBuffer, jint inputLen,
+ jbyteArray outputArray, jint outputOff, jint outputLen,
+ jint flush, jint params)
+{
+ jbyte *input = jlong_to_ptr(inputBuffer);
+ jbyte *output = (*env)->GetPrimitiveArrayCritical(env, outputArray, 0);
+ jlong retVal;
+ if (output == NULL) {
+ if (outputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+
+ retVal = doDeflate(env, this, addr,
+ input, inputLen,
+ output + outputOff, outputLen,
+ flush, params);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, outputArray, input, 0);
+
+ return retVal;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Deflater_deflateBufferBuffer(JNIEnv *env, jobject this, jlong addr,
+ jlong inputBuffer, jint inputLen,
+ jlong outputBuffer, jint outputLen,
+ jint flush, jint params)
+{
+ jbyte *input = jlong_to_ptr(inputBuffer);
+ jbyte *output = jlong_to_ptr(outputBuffer);
+
+ return doDeflate(env, this, addr,
+ input, inputLen,
+ output, outputLen,
+ flush, params);
}
JNIEXPORT jint JNICALL
--- a/src/java.base/share/native/libzip/Inflater.c Thu Apr 19 21:11:32 2018 +0200
+++ b/src/java.base/share/native/libzip/Inflater.c Thu Apr 19 21:21:45 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,23 +42,16 @@
#define ThrowDataFormatException(env, msg) \
JNU_ThrowByName(env, "java/util/zip/DataFormatException", msg)
-static jfieldID needDictID;
-static jfieldID finishedID;
-static jfieldID bufID, offID, lenID;
+static jfieldID inputConsumedID;
+static jfieldID outputConsumedID;
JNIEXPORT void JNICALL
Java_java_util_zip_Inflater_initIDs(JNIEnv *env, jclass cls)
{
- needDictID = (*env)->GetFieldID(env, cls, "needDict", "Z");
- CHECK_NULL(needDictID);
- finishedID = (*env)->GetFieldID(env, cls, "finished", "Z");
- CHECK_NULL(finishedID);
- bufID = (*env)->GetFieldID(env, cls, "buf", "[B");
- CHECK_NULL(bufID);
- offID = (*env)->GetFieldID(env, cls, "off", "I");
- CHECK_NULL(offID);
- lenID = (*env)->GetFieldID(env, cls, "len", "I");
- CHECK_NULL(lenID);
+ inputConsumedID = (*env)->GetFieldID(env, cls, "inputConsumed", "I");
+ outputConsumedID = (*env)->GetFieldID(env, cls, "outputConsumed", "I");
+ CHECK_NULL(inputConsumedID);
+ CHECK_NULL(outputConsumedID);
}
JNIEXPORT jlong JNICALL
@@ -94,16 +87,9 @@
}
}
-JNIEXPORT void JNICALL
-Java_java_util_zip_Inflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
- jarray b, jint off, jint len)
+static void doSetDictionary(JNIEnv *env, jlong addr, jbyte *buf, jint len)
{
- Bytef *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
- int res;
- if (buf == 0) /* out of memory */
- return;
- res = inflateSetDictionary(jlong_to_ptr(addr), buf + off, len);
- (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
+ int res = inflateSetDictionary(jlong_to_ptr(addr), (Bytef *) buf, len);
switch (res) {
case Z_OK:
break;
@@ -117,68 +103,168 @@
}
}
-JNIEXPORT jint JNICALL
-Java_java_util_zip_Inflater_inflateBytes(JNIEnv *env, jobject this, jlong addr,
- jarray b, jint off, jint len)
+JNIEXPORT void JNICALL
+Java_java_util_zip_Inflater_setDictionary(JNIEnv *env, jclass cls, jlong addr,
+ jbyteArray b, jint off, jint len)
+{
+ jbyte *buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
+ if (buf == NULL) /* out of memory */
+ return;
+ doSetDictionary(env, addr, buf + off, len);
+ (*env)->ReleasePrimitiveArrayCritical(env, b, buf, 0);
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_Inflater_setDictionaryBuffer(JNIEnv *env, jclass cls, jlong addr,
+ jlong bufferAddr, jint len)
+{
+ jbyte *buf = jlong_to_ptr(bufferAddr);
+ doSetDictionary(env, addr, buf, len);
+}
+
+static jlong doInflate(JNIEnv *env, jobject this, jlong addr,
+ jbyte *input, jint inputLen,
+ jbyte *output, jint outputLen)
{
z_stream *strm = jlong_to_ptr(addr);
- jarray this_buf = (jarray)(*env)->GetObjectField(env, this, bufID);
- jint this_off = (*env)->GetIntField(env, this, offID);
- jint this_len = (*env)->GetIntField(env, this, lenID);
-
- jbyte *in_buf;
- jbyte *out_buf;
+ jint inputUsed = 0, outputUsed = 0;
+ int finished = 0;
+ int needDict = 0;
int ret;
- in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
- if (in_buf == NULL) {
- if (this_len != 0 && (*env)->ExceptionOccurred(env) == NULL)
- JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
- }
- out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
- if (out_buf == NULL) {
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
- if (len != 0 && (*env)->ExceptionOccurred(env) == NULL)
- JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
- }
- strm->next_in = (Bytef *) (in_buf + this_off);
- strm->next_out = (Bytef *) (out_buf + off);
- strm->avail_in = this_len;
- strm->avail_out = len;
+ strm->next_in = (Bytef *) input;
+ strm->next_out = (Bytef *) output;
+ strm->avail_in = inputLen;
+ strm->avail_out = outputLen;
+
ret = inflate(strm, Z_PARTIAL_FLUSH);
- (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
- (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
switch (ret) {
case Z_STREAM_END:
- (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE);
+ finished = 1;
/* fall through */
case Z_OK:
- this_off += this_len - strm->avail_in;
- (*env)->SetIntField(env, this, offID, this_off);
- (*env)->SetIntField(env, this, lenID, strm->avail_in);
- return (jint) (len - strm->avail_out);
+ inputUsed = inputLen - strm->avail_in;
+ outputUsed = outputLen - strm->avail_out;
+ break;
case Z_NEED_DICT:
- (*env)->SetBooleanField(env, this, needDictID, JNI_TRUE);
+ needDict = 1;
/* Might have consumed some input here! */
- this_off += this_len - strm->avail_in;
- (*env)->SetIntField(env, this, offID, this_off);
- (*env)->SetIntField(env, this, lenID, strm->avail_in);
- return 0;
+ inputUsed = inputLen - strm->avail_in;
+ /* zlib is unclear about whether output may be produced */
+ outputUsed = outputLen - strm->avail_out;
+ break;
case Z_BUF_ERROR:
- return 0;
+ break;
case Z_DATA_ERROR:
+ inputUsed = inputLen - strm->avail_in;
+ (*env)->SetIntField(env, this, inputConsumedID, inputUsed);
+ outputUsed = outputLen - strm->avail_out;
+ (*env)->SetIntField(env, this, outputConsumedID, outputUsed);
ThrowDataFormatException(env, strm->msg);
- return 0;
+ break;
case Z_MEM_ERROR:
JNU_ThrowOutOfMemoryError(env, 0);
- return 0;
+ break;
default:
JNU_ThrowInternalError(env, strm->msg);
- return 0;
+ break;
+ }
+ return ((jlong)inputUsed) | (((jlong)outputUsed) << 31) | (((jlong)finished) << 62) | (((jlong)needDict) << 63);
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Inflater_inflateBytesBytes(JNIEnv *env, jobject this, jlong addr,
+ jbyteArray inputArray, jint inputOff, jint inputLen,
+ jbyteArray outputArray, jint outputOff, jint outputLen)
+{
+ jbyte *input = (*env)->GetPrimitiveArrayCritical(env, inputArray, 0);
+ jbyte *output;
+ jlong retVal;
+
+ if (input == NULL) {
+ if (inputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+ output = (*env)->GetPrimitiveArrayCritical(env, outputArray, 0);
+ if (output == NULL) {
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+ if (outputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
}
+
+ retVal = doInflate(env, this, addr,
+ input + inputOff, inputLen,
+ output + outputOff, outputLen);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, outputArray, output, 0);
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+
+ return retVal;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Inflater_inflateBytesBuffer(JNIEnv *env, jobject this, jlong addr,
+ jbyteArray inputArray, jint inputOff, jint inputLen,
+ jlong outputBuffer, jint outputLen)
+{
+ jbyte *input = (*env)->GetPrimitiveArrayCritical(env, inputArray, 0);
+ jbyte *output;
+ jlong retVal;
+
+ if (input == NULL) {
+ if (inputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+ output = jlong_to_ptr(outputBuffer);
+
+ retVal = doInflate(env, this, addr,
+ input + inputOff, inputLen,
+ output, outputLen);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, inputArray, input, 0);
+
+ return retVal;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Inflater_inflateBufferBytes(JNIEnv *env, jobject this, jlong addr,
+ jlong inputBuffer, jint inputLen,
+ jbyteArray outputArray, jint outputOff, jint outputLen)
+{
+ jbyte *input = jlong_to_ptr(inputBuffer);
+ jbyte *output = (*env)->GetPrimitiveArrayCritical(env, outputArray, 0);
+ jlong retVal;
+
+ if (output == NULL) {
+ if (outputLen != 0 && (*env)->ExceptionOccurred(env) == NULL)
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0L;
+ }
+
+ retVal = doInflate(env, this, addr,
+ input, inputLen,
+ output + outputOff, outputLen);
+
+ (*env)->ReleasePrimitiveArrayCritical(env, outputArray, output, 0);
+
+ return retVal;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_Inflater_inflateBufferBuffer(JNIEnv *env, jobject this, jlong addr,
+ jlong inputBuffer, jint inputLen,
+ jlong outputBuffer, jint outputLen)
+{
+ jbyte *input = jlong_to_ptr(inputBuffer);
+ jbyte *output = jlong_to_ptr(outputBuffer);
+
+ return doInflate(env, this, addr,
+ input, inputLen,
+ output, outputLen);
}
JNIEXPORT jint JNICALL
--- a/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java Thu Apr 19 21:11:32 2018 +0200
+++ b/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java Thu Apr 19 21:21:45 2018 +0200
@@ -26,14 +26,18 @@
import java.io.IOException;
import java.io.FileDescriptor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.security.action.GetPropertyAction;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.JavaIOFileDescriptorAccess;
/**
- * This class defines the plain SocketImpl that is used on Windows platforms
- * greater or equal to Windows Vista. These platforms have a dual
- * layer TCP/IP stack and can handle both IPv4 and IPV6 through a
- * single file descriptor.
+ * This class defines the plain SocketImpl.
+ * When java.net.preferIPv4Stack system property is set to true, it uses
+ * IPv4-only socket.
+ * When java.net.preferIPv4Stack is set to false, it handles both IPv4
+ * and IPv6 through a single file descriptor.
*
* @author Chris Hegarty
*/
@@ -43,30 +47,43 @@
private static final JavaIOFileDescriptorAccess fdAccess =
SharedSecrets.getJavaIOFileDescriptorAccess();
- // true if this socket is exclusively bound
- private final boolean exclusiveBind;
+ private static final boolean preferIPv4Stack =
+ Boolean.parseBoolean(AccessController.doPrivileged(
+ new GetPropertyAction("java.net.preferIPv4Stack", "false")));
+
+ /**
+ * Empty value of sun.net.useExclusiveBind is treated as 'true'.
+ */
+ private static final boolean useExclusiveBind;
- // emulates SO_REUSEADDR when exclusiveBind is true
+ static {
+ String exclBindProp = AccessController.doPrivileged(
+ new GetPropertyAction("sun.net.useExclusiveBind", ""));
+ useExclusiveBind = exclBindProp.isEmpty()
+ || Boolean.parseBoolean(exclBindProp);
+ }
+
+ // emulates SO_REUSEADDR when useExclusiveBind is true
private boolean isReuseAddress;
- public DualStackPlainSocketImpl(boolean exclBind) {
- exclusiveBind = exclBind;
+ public DualStackPlainSocketImpl() {
}
- public DualStackPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
+ public DualStackPlainSocketImpl(FileDescriptor fd) {
this.fd = fd;
- exclusiveBind = exclBind;
}
+ @Override
void socketCreate(boolean stream) throws IOException {
if (fd == null)
throw new SocketException("Socket closed");
- int newfd = socket0(stream, false /*v6 Only*/);
+ int newfd = socket0(stream);
fdAccess.set(fd, newfd);
}
+ @Override
void socketConnect(InetAddress address, int port, int timeout)
throws IOException {
int nativefd = checkAndReturnNativeFD();
@@ -74,6 +91,9 @@
if (address == null)
throw new NullPointerException("inet address argument is null.");
+ if (preferIPv4Stack && !(address instanceof Inet4Address))
+ throw new SocketException("Protocol family not supported");
+
int connectResult;
if (timeout <= 0) {
connectResult = connect0(nativefd, address, port);
@@ -97,13 +117,17 @@
localport = localPort0(nativefd);
}
+ @Override
void socketBind(InetAddress address, int port) throws IOException {
int nativefd = checkAndReturnNativeFD();
if (address == null)
throw new NullPointerException("inet address argument is null.");
- bind0(nativefd, address, port, exclusiveBind);
+ if (preferIPv4Stack && !(address instanceof Inet4Address))
+ throw new SocketException("Protocol family not supported");
+
+ bind0(nativefd, address, port, useExclusiveBind);
if (port == 0) {
localport = localPort0(nativefd);
} else {
@@ -113,12 +137,14 @@
this.address = address;
}
+ @Override
void socketListen(int backlog) throws IOException {
int nativefd = checkAndReturnNativeFD();
listen0(nativefd, backlog);
}
+ @Override
void socketAccept(SocketImpl s) throws IOException {
int nativefd = checkAndReturnNativeFD();
@@ -148,13 +174,17 @@
s.port = isa.getPort();
s.address = isa.getAddress();
s.localport = localport;
+ if (preferIPv4Stack && !(s.address instanceof Inet4Address))
+ throw new SocketException("Protocol family not supported");
}
+ @Override
int socketAvailable() throws IOException {
int nativefd = checkAndReturnNativeFD();
return available0(nativefd);
}
+ @Override
void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
if (fd == null)
throw new SocketException("Socket closed");
@@ -167,6 +197,7 @@
close0(nativefd);
}
+ @Override
void socketShutdown(int howto) throws IOException {
int nativefd = checkAndReturnNativeFD();
shutdown0(nativefd, howto);
@@ -174,41 +205,51 @@
// Intentional fallthrough after SO_REUSEADDR
@SuppressWarnings("fallthrough")
+ @Override
void socketSetOption(int opt, boolean on, Object value)
throws SocketException {
- int nativefd = checkAndReturnNativeFD();
- if (opt == SO_TIMEOUT) { // timeout implemented through select.
- return;
- }
// SO_REUSEPORT is not supported on Windows.
if (opt == SO_REUSEPORT) {
throw new UnsupportedOperationException("unsupported option");
}
+ int nativefd = checkAndReturnNativeFD();
+
+ if (opt == SO_TIMEOUT) {
+ if (preferIPv4Stack) {
+ // Don't enable the socket option on ServerSocket as it's
+ // meaningless (we don't receive on a ServerSocket).
+ if (serverSocket == null) {
+ setSoTimeout0(nativefd, ((Integer)value).intValue());
+ }
+ } // else timeout is implemented through select.
+ return;
+ }
+
int optionValue = 0;
switch(opt) {
- case SO_REUSEADDR :
- if (exclusiveBind) {
+ case SO_REUSEADDR:
+ if (useExclusiveBind) {
// SO_REUSEADDR emulated when using exclusive bind
isReuseAddress = on;
return;
}
// intentional fallthrough
- case TCP_NODELAY :
- case SO_OOBINLINE :
- case SO_KEEPALIVE :
+ case TCP_NODELAY:
+ case SO_OOBINLINE:
+ case SO_KEEPALIVE:
optionValue = on ? 1 : 0;
break;
- case SO_SNDBUF :
- case SO_RCVBUF :
- case IP_TOS :
+ case SO_SNDBUF:
+ case SO_RCVBUF:
+ case IP_TOS:
optionValue = ((Integer)value).intValue();
break;
- case SO_LINGER :
+ case SO_LINGER:
if (on) {
- optionValue = ((Integer)value).intValue();
+ optionValue = ((Integer)value).intValue();
} else {
optionValue = -1;
}
@@ -220,7 +261,15 @@
setIntOption(nativefd, opt, optionValue);
}
- int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
+ @Override
+ int socketGetOption(int opt, Object iaContainerObj)
+ throws SocketException {
+
+ // SO_REUSEPORT is not supported on Windows.
+ if (opt == SO_REUSEPORT) {
+ throw new UnsupportedOperationException("unsupported option");
+ }
+
int nativefd = checkAndReturnNativeFD();
// SO_BINDADDR is not a socket option.
@@ -228,27 +277,24 @@
localAddress(nativefd, (InetAddressContainer)iaContainerObj);
return 0; // return value doesn't matter.
}
- // SO_REUSEPORT is not supported on Windows.
- if (opt == SO_REUSEPORT) {
- throw new UnsupportedOperationException("unsupported option");
- }
// SO_REUSEADDR emulated when using exclusive bind
- if (opt == SO_REUSEADDR && exclusiveBind)
- return isReuseAddress? 1 : -1;
+ if (opt == SO_REUSEADDR && useExclusiveBind)
+ return isReuseAddress ? 1 : -1;
int value = getIntOption(nativefd, opt);
switch (opt) {
- case TCP_NODELAY :
- case SO_OOBINLINE :
- case SO_KEEPALIVE :
- case SO_REUSEADDR :
+ case TCP_NODELAY:
+ case SO_OOBINLINE:
+ case SO_KEEPALIVE:
+ case SO_REUSEADDR:
return (value == 0) ? -1 : 1;
}
return value;
}
+ @Override
void socketSendUrgentData(int data) throws IOException {
int nativefd = checkAndReturnNativeFD();
sendOOB(nativefd, data);
@@ -271,7 +317,7 @@
static native void initIDs();
- static native int socket0(boolean stream, boolean v6Only) throws IOException;
+ static native int socket0(boolean stream) throws IOException;
static native void bind0(int fd, InetAddress localAddress, int localport,
boolean exclBind)
@@ -300,6 +346,8 @@
static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException;
+ static native void setSoTimeout0(int fd, int timeout) throws SocketException;
+
static native int getIntOption(int fd, int cmd) throws SocketException;
static native void sendOOB(int fd, int data) throws IOException;
--- a/src/java.base/windows/classes/java/net/PlainSocketImpl.java Thu Apr 19 21:11:32 2018 +0200
+++ b/src/java.base/windows/classes/java/net/PlainSocketImpl.java Thu Apr 19 21:21:45 2018 +0200
@@ -25,20 +25,13 @@
package java.net;
import java.io.*;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import sun.security.action.GetPropertyAction;
/*
* This class PlainSocketImpl simply delegates to the appropriate real
* SocketImpl. We do this because PlainSocketImpl is already extended
* by SocksSocketImpl.
* <p>
- * There are two possibilities for the real SocketImpl,
- * TwoStacksPlainSocketImpl or DualStackPlainSocketImpl. We use
- * DualStackPlainSocketImpl on systems that have a dual stack
- * TCP implementation. Otherwise we create an instance of
- * TwoStacksPlainSocketImpl and delegate to it.
+ * There is one possibility for the real SocketImpl: DualStackPlainSocketImpl.
*
* @author Chris Hegarty
*/
@@ -46,44 +39,18 @@
class PlainSocketImpl extends AbstractPlainSocketImpl {
private AbstractPlainSocketImpl impl;
- /* java.net.preferIPv4Stack */
- private static final boolean preferIPv4Stack;
-
- /* True if exclusive binding is on for Windows */
- private static final boolean exclusiveBind;
-
- static {
- preferIPv4Stack = Boolean.parseBoolean(
- AccessController.doPrivileged(
- new GetPropertyAction("java.net.preferIPv4Stack")));
-
- String exclBindProp = AccessController.doPrivileged(
- new GetPropertyAction("sun.net.useExclusiveBind", ""));
- exclusiveBind = (exclBindProp.isEmpty())
- ? true
- : Boolean.parseBoolean(exclBindProp);
- }
-
/**
* Constructs an empty instance.
*/
PlainSocketImpl() {
- if (!preferIPv4Stack) {
- impl = new DualStackPlainSocketImpl(exclusiveBind);
- } else {
- impl = new TwoStacksPlainSocketImpl(exclusiveBind);
- }
+ impl = new DualStackPlainSocketImpl();
}
/**
* Constructs an instance with the given file descriptor.
*/
PlainSocketImpl(FileDescriptor fd) {
- if (!preferIPv4Stack) {
- impl = new DualStackPlainSocketImpl(fd, exclusiveBind);
- } else {
- impl = new TwoStacksPlainSocketImpl(fd, exclusiveBind);
- }
+ impl = new DualStackPlainSocketImpl(fd);
}
// Override methods in SocketImpl that access impl's fields.
@@ -148,18 +115,10 @@
}
public void setOption(int opt, Object val) throws SocketException {
- if (opt == SocketOptions.SO_REUSEPORT) {
- // SO_REUSEPORT is not supported on Windows.
- throw new UnsupportedOperationException("unsupported option");
- }
impl.setOption(opt, val);
}
public Object getOption(int opt) throws SocketException {
- if (opt == SocketOptions.SO_REUSEPORT) {
- // SO_REUSEPORT is not supported on Windows.
- throw new UnsupportedOperationException("unsupported option");
- }
return impl.getOption(opt);
}
@@ -271,8 +230,8 @@
// Override methods in AbstractPlainSocketImpl that need to be implemented.
- void socketCreate(boolean isServer) throws IOException {
- impl.socketCreate(isServer);
+ void socketCreate(boolean stream) throws IOException {
+ impl.socketCreate(stream);
}
void socketConnect(InetAddress address, int port, int timeout)
@@ -307,18 +266,10 @@
void socketSetOption(int cmd, boolean on, Object value)
throws SocketException {
- if (cmd == SocketOptions.SO_REUSEPORT) {
- // SO_REUSEPORT is not supported on Windows.
- throw new UnsupportedOperationException("unsupported option");
- }
impl.socketSetOption(cmd, on, value);
}
int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
- if (opt == SocketOptions.SO_REUSEPORT) {
- // SO_REUSEPORT is not supported on Windows.
- throw new UnsupportedOperationException("unsupported option");
- }
return impl.socketGetOption(opt, iaContainerObj);
}
--- a/src/java.base/windows/classes/java/net/TwoStacksPlainSocketImpl.java Thu Apr 19 21:11:32 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,324 +0,0 @@
-/*
- * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.net;
-
-import java.io.IOException;
-import java.io.FileDescriptor;
-import sun.net.ResourceManager;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.misc.JavaIOFileDescriptorAccess;
-
-/*
- * This class defines the plain SocketImpl that is used when
- * the System property java.net.preferIPv4Stack is set to true.
- *
- * @author Chris Hegarty
- */
-
-class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl {
-
- private static final JavaIOFileDescriptorAccess fdAccess =
- SharedSecrets.getJavaIOFileDescriptorAccess();
-
- // true if this socket is exclusively bound
- private final boolean exclusiveBind;
-
- // emulates SO_REUSEADDR when exclusiveBind is true
- private boolean isReuseAddress;
-
- public TwoStacksPlainSocketImpl(boolean exclBind) {
- exclusiveBind = exclBind;
- }
-
- public TwoStacksPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
- this.fd = fd;
- exclusiveBind = exclBind;
- }
-
- void socketCreate(boolean stream) throws IOException {
- if (fd == null)
- throw new SocketException("Socket closed");
-
- int newfd = socket0(stream, false /*v6 Only*/);
-
- fdAccess.set(fd, newfd);
- }
-
- @Override
- void socketConnect(InetAddress address, int port, int timeout)
- throws IOException {
- int nativefd = checkAndReturnNativeFD();
-
- if (address == null)
- throw new NullPointerException("inet address argument is null.");
-
- int connectResult;
- if (timeout <= 0) {
- connectResult = connect0(nativefd, address, port);
- } else {
- configureBlocking(nativefd, false);
- try {
- connectResult = connect0(nativefd, address, port);
- if (connectResult == WOULDBLOCK) {
- waitForConnect(nativefd, timeout);
- }
- } finally {
- configureBlocking(nativefd, true);
- }
- }
- /*
- * We need to set the local port field. If bind was called
- * previous to the connect (by the client) then localport field
- * will already be set.
- */
- if (localport == 0)
- localport = localPort0(nativefd);
- }
-
- @Override
- void socketBind(InetAddress address, int port) throws IOException {
- int nativefd = checkAndReturnNativeFD();
-
- if (address == null)
- throw new NullPointerException("inet address argument is null.");
-
- bind0(nativefd, address, port, exclusiveBind);
- if (port == 0) {
- localport = localPort0(nativefd);
- } else {
- localport = port;
- }
-
- this.address = address;
- }
-
- @Override
- void socketListen(int backlog) throws IOException {
- int nativefd = checkAndReturnNativeFD();
-
- listen0(nativefd, backlog);
- }
-
- @Override
- void socketAccept(SocketImpl s) throws IOException {
- int nativefd = checkAndReturnNativeFD();
-
- if (s == null)
- throw new NullPointerException("socket is null");
-
- int newfd = -1;
- InetSocketAddress[] isaa = new InetSocketAddress[1];
- if (timeout <= 0) {
- newfd = accept0(nativefd, isaa);
- } else {
- configureBlocking(nativefd, false);
- try {
- waitForNewConnection(nativefd, timeout);
- newfd = accept0(nativefd, isaa);
- if (newfd != -1) {
- configureBlocking(newfd, true);
- }
- } finally {
- configureBlocking(nativefd, true);
- }
- }
- /* Update (SocketImpl)s' fd */
- fdAccess.set(s.fd, newfd);
- /* Update socketImpls remote port, address and localport */
- InetSocketAddress isa = isaa[0];
- s.port = isa.getPort();
- s.address = isa.getAddress();
- s.localport = localport;
- }
-
- @Override
- int socketAvailable() throws IOException {
- int nativefd = checkAndReturnNativeFD();
- return available0(nativefd);
- }
-
- @Override
- void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
- if (fd == null)
- throw new SocketException("Socket closed");
-
- if (!fd.valid())
- return;
-
- final int nativefd = fdAccess.get(fd);
- fdAccess.set(fd, -1);
- close0(nativefd);
- }
-
- @Override
- void socketShutdown(int howto) throws IOException {
- int nativefd = checkAndReturnNativeFD();
- shutdown0(nativefd, howto);
- }
-
- // Intentional fallthrough after SO_REUSEADDR
- @SuppressWarnings("fallthrough")
- @Override
- void socketSetOption(int opt, boolean on, Object value)
- throws SocketException {
- int nativefd = checkAndReturnNativeFD();
-
- if (opt == SO_TIMEOUT) {
- // Don't enable the socket option on ServerSocket as it's
- // meaningless (we don't receive on a ServerSocket).
- if (serverSocket == null) {
- setSoTimeout0(nativefd, ((Integer)value).intValue());
- }
- return;
- }
- // SO_REUSEPORT is not supported on Windows.
- if (opt == SO_REUSEPORT) {
- throw new UnsupportedOperationException("unsupported option");
- }
-
- int optionValue = 0;
-
- switch(opt) {
- case SO_REUSEADDR :
- if (exclusiveBind) {
- // SO_REUSEADDR emulated when using exclusive bind
- isReuseAddress = on;
- return;
- }
- // intentional fallthrough
- case TCP_NODELAY :
- case SO_OOBINLINE :
- case SO_KEEPALIVE :
- optionValue = on ? 1 : 0;
- break;
- case SO_SNDBUF :
- case SO_RCVBUF :
- case IP_TOS :
- optionValue = ((Integer)value).intValue();
- break;
- case SO_LINGER :
- if (on) {
- optionValue = ((Integer)value).intValue();
- } else {
- optionValue = -1;
- }
- break;
- default :/* shouldn't get here */
- throw new SocketException("Option not supported");
- }
-
- setIntOption(nativefd, opt, optionValue);
- }
-
- @Override
- int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
- int nativefd = checkAndReturnNativeFD();
-
- // SO_BINDADDR is not a socket option.
- if (opt == SO_BINDADDR) {
- localAddress(nativefd, (InetAddressContainer)iaContainerObj);
- return 0; // return value doesn't matter.
- }
- // SO_REUSEPORT is not supported on Windows.
- if (opt == SO_REUSEPORT) {
- throw new UnsupportedOperationException("unsupported option");
- }
-
- // SO_REUSEADDR emulated when using exclusive bind
- if (opt == SO_REUSEADDR && exclusiveBind)
- return isReuseAddress? 1 : -1;
-
- int value = getIntOption(nativefd, opt);
-
- switch (opt) {
- case TCP_NODELAY :
- case SO_OOBINLINE :
- case SO_KEEPALIVE :
- case SO_REUSEADDR :
- return (value == 0) ? -1 : 1;
- }
- return value;
- }
-
- @Override
- void socketSendUrgentData(int data) throws IOException {
- int nativefd = checkAndReturnNativeFD();
- sendOOB(nativefd, data);
- }
-
- private int checkAndReturnNativeFD() throws SocketException {
- if (fd == null || !fd.valid())
- throw new SocketException("Socket closed");
-
- return fdAccess.get(fd);
- }
-
- static final int WOULDBLOCK = -2; // Nothing available (non-blocking)
-
- static {
- initIDs();
- }
-
- /* Native methods */
-
- static native void initIDs();
-
- static native int socket0(boolean stream, boolean v6Only) throws IOException;
-
- static native void bind0(int fd, InetAddress localAddress, int localport,
- boolean exclBind)
- throws IOException;
-
- static native int connect0(int fd, InetAddress remote, int remotePort)
- throws IOException;
-
- static native void waitForConnect(int fd, int timeout) throws IOException;
-
- static native int localPort0(int fd) throws IOException;
-
- static native void localAddress(int fd, InetAddressContainer in) throws SocketException;
-
- static native void listen0(int fd, int backlog) throws IOException;
-
- static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException;
-
- static native void waitForNewConnection(int fd, int timeout) throws IOException;
-
- static native int available0(int fd) throws IOException;
-
- static native void close0(int fd) throws IOException;
-
- static native void shutdown0(int fd, int howto) throws IOException;
-
- static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException;
-
- static native void setSoTimeout0(int fd, int timeout) throws SocketException;
-
- static native int getIntOption(int fd, int cmd) throws SocketException;
-
- static native void sendOOB(int fd, int data) throws IOException;
-
- static native void configureBlocking(int fd, boolean blocking) throws IOException;
-}
--- a/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Thu Apr 19 21:11:32 2018 +0200
+++ b/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c Thu Apr 19 21:21:45 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,8 +27,8 @@
#include "java_net_DualStackPlainSocketImpl.h"
#include "java_net_SocketOptions.h"
-#define SET_BLOCKING 0
-#define SET_NONBLOCKING 1
+#define SET_BLOCKING 0
+#define SET_NONBLOCKING 1
static jclass isa_class; /* java.net.InetSocketAddress */
static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
@@ -60,22 +60,28 @@
* Signature: (ZZ)I
*/
JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
- (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {
+ (JNIEnv *env, jclass clazz, jboolean stream) {
int fd, rv, opt=0;
+ int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
+ int domain = ipv6_available() ? AF_INET6 : AF_INET;
- fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
+ fd = NET_Socket(domain, type, 0);
+
if (fd == INVALID_SOCKET) {
NET_ThrowNew(env, WSAGetLastError(), "create");
return -1;
}
- rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
- if (rv == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "create");
+ if (domain == AF_INET6) {
+ rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt,
+ sizeof(opt));
+ if (rv == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "create");
+ closesocket(fd);
+ return -1;
+ }
}
- SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
-
return fd;
}
@@ -90,10 +96,11 @@
{
SOCKETADDRESS sa;
int rv, sa_len = 0;
+ jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
- &sa_len, JNI_TRUE) != 0) {
- return;
+ &sa_len, v4MappedAddress) != 0) {
+ return;
}
rv = NET_WinBind(fd, &sa, sa_len, exclBind);
@@ -111,10 +118,11 @@
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
SOCKETADDRESS sa;
int rv, sa_len = 0;
+ jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
- &sa_len, JNI_TRUE) != 0) {
- return -1;
+ &sa_len, v4MappedAddress) != 0) {
+ return -1;
}
rv = connect(fd, &sa.sa, sa_len);
@@ -124,7 +132,8 @@
return java_net_DualStackPlainSocketImpl_WOULDBLOCK;
} else if (err == WSAEADDRNOTAVAIL) {
JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
- "connect: Address is invalid on local machine, or port is not valid on remote machine");
+ "connect: Address is invalid on local machine,"
+ " or port is not valid on remote machine");
} else {
NET_ThrowNew(env, err, "connect");
}
@@ -200,6 +209,10 @@
if (rv == 0) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
"Unable to establish connection");
+ } else if (!ipv6_available() && rv == WSAEADDRNOTAVAIL) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
+ "connect: Address is invalid on local machine,"
+ " or port is not valid on remote machine");
} else {
NET_ThrowNew(env, rv, "connect");
}
@@ -284,13 +297,7 @@
newfd = accept(fd, &sa.sa, &len);
if (newfd == INVALID_SOCKET) {
- if (WSAGetLastError() == -2) {
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- } else {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "socket closed");
- }
+ NET_ThrowNew(env, WSAGetLastError(), "accept failed");
return -1;
}
@@ -298,6 +305,10 @@
ia = NET_SockaddrToInetAddress(env, &sa, &port);
isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
+ if (isa == NULL) {
+ closesocket(newfd);
+ return -1;
+ }
(*env)->SetObjectArrayElement(env, isaa, 0, isa);
return newfd;
@@ -402,6 +413,51 @@
/*
* Class: java_net_DualStackPlainSocketImpl
+ * Method: setSoTimeout0
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_java_net_DualStackPlainSocketImpl_setSoTimeout0
+ (JNIEnv *env, jclass clazz, jint fd, jint timeout)
+{
+ /*
+ * SO_TIMEOUT is the socket option used to specify the timeout
+ * for ServerSocket.accept and Socket.getInputStream().read.
+ * It does not typically map to a native level socket option.
+ * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
+ * socket option to specify a receive timeout on the socket. This
+ * receive timeout is applicable to Socket only and the socket
+ * option should not be set on ServerSocket.
+ */
+
+ /*
+ * SO_RCVTIMEO is only supported on Microsoft's implementation
+ * of Windows Sockets so if WSAENOPROTOOPT returned then
+ * reset flag and timeout will be implemented using
+ * select() -- see SocketInputStream.socketRead.
+ */
+ if (isRcvTimeoutSupported) {
+ /*
+ * Disable SO_RCVTIMEO if timeout is <= 5 second.
+ */
+ if (timeout <= 5000) {
+ timeout = 0;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
+ sizeof(timeout)) < 0) {
+ int err = WSAGetLastError();
+ if (err == WSAENOPROTOOPT) {
+ isRcvTimeoutSupported = JNI_FALSE;
+ } else {
+ NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO");
+ }
+ }
+ }
+}
+
+/*
+ * Class: java_net_DualStackPlainSocketImpl
* Method: getIntOption
* Signature: (II)I
*/
@@ -466,7 +522,7 @@
int result;
if (blocking == JNI_TRUE) {
- arg = SET_BLOCKING; // 0
+ arg = SET_BLOCKING; // 0
} else {
arg = SET_NONBLOCKING; // 1
}
--- a/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c Thu Apr 19 21:11:32 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,550 +0,0 @@
-/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-#include "net_util.h"
-
-#include "java_net_TwoStacksPlainSocketImpl.h"
-#include "java_net_SocketOptions.h"
-#include "java_net_InetAddress.h"
-
-#define SET_BLOCKING 0
-#define SET_NONBLOCKING 1
-
-static jclass isa_class; /* java.net.InetSocketAddress */
-static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
-
-/************************************************************************
- * TwoStacksPlainSocketImpl
- */
-
-/*
- * The initIDs function is called whenever TwoStacksPlainSocketImpl is
- * loaded, to cache fieldIds for efficiency. This is called everytime
- * the Java class is loaded.
- *
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: initIDs
- * Signature: ()V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_initIDs
- (JNIEnv *env, jclass clazz) {
-
- jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
- CHECK_NULL(cls);
- isa_class = (*env)->NewGlobalRef(env, cls);
- CHECK_NULL(isa_class);
- isa_ctorID = (*env)->GetMethodID(env, cls, "<init>",
- "(Ljava/net/InetAddress;I)V");
- CHECK_NULL(isa_ctorID);
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: socket0
- * Signature: (ZZ)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_socket0
- (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {
- int fd;
-
- fd = socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);
- if (fd == INVALID_SOCKET) {
- NET_ThrowNew(env, WSAGetLastError(), "create");
- return -1;
- }
-
- SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
-
- return fd;
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: bind0
- * Signature: (ILjava/net/InetAddress;I)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_bind0
- (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
- jboolean exclBind)
-{
- SOCKETADDRESS sa;
- int rv, sa_len = 0;
- /* family is an int field of iaObj */
- int family;
-
- family = getInetAddress_family(env, iaObj);
- if (family != java_net_InetAddress_IPv4) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Protocol family not supported");
- return;
- }
-
- if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
- &sa_len, JNI_FALSE) != 0) {
- return;
- }
-
- rv = NET_WinBind(fd, &sa, sa_len, exclBind);
-
- if (rv == SOCKET_ERROR)
- NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: connect0
- * Signature: (ILjava/net/InetAddress;I)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_connect0
- (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
- SOCKETADDRESS sa;
- int rv, sa_len = 0;
- int family;
-
- if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
- &sa_len, JNI_FALSE) != 0) {
- return -1;
- }
-
- family = sa.sa.sa_family;
- if (family != AF_INET) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Protocol family not supported");
- return -1;
- }
-
- rv = connect(fd, &sa.sa, sa_len);
- if (rv == SOCKET_ERROR) {
- int err = WSAGetLastError();
- if (err == WSAEWOULDBLOCK) {
- return java_net_TwoStacksPlainSocketImpl_WOULDBLOCK;
- } else if (err == WSAEADDRNOTAVAIL) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
- "connect: Address is invalid on local machine, or port is not valid on remote machine");
- } else {
- NET_ThrowNew(env, err, "connect");
- }
- return -1; // return value not important.
- }
- return rv;
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: waitForConnect
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_waitForConnect
- (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
- int rv, retry;
- int optlen = sizeof(rv);
- fd_set wr, ex;
- struct timeval t;
-
- FD_ZERO(&wr);
- FD_ZERO(&ex);
- FD_SET(fd, &wr);
- FD_SET(fd, &ex);
- t.tv_sec = timeout / 1000;
- t.tv_usec = (timeout % 1000) * 1000;
-
- /*
- * Wait for timeout, connection established or
- * connection failed.
- */
- rv = select(fd+1, 0, &wr, &ex, &t);
-
- /*
- * Timeout before connection is established/failed so
- * we throw exception and shutdown input/output to prevent
- * socket from being used.
- * The socket should be closed immediately by the caller.
- */
- if (rv == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
- "connect timed out");
- shutdown( fd, SD_BOTH );
- return;
- }
- /*
- * Socket is writable or error occurred. On some Windows editions
- * the socket will appear writable when the connect fails so we
- * check for error rather than writable.
- */
- if (!FD_ISSET(fd, &ex)) {
- return; /* connection established */
- }
-
- /*
- * Connection failed. The logic here is designed to work around
- * bug on Windows NT whereby using getsockopt to obtain the
- * last error (SO_ERROR) indicates there is no error. The workaround
- * on NT is to allow winsock to be scheduled and this is done by
- * yielding and retrying. As yielding is problematic in heavy
- * load conditions we attempt up to 3 times to get the error reason.
- */
- for (retry=0; retry<3; retry++) {
- NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
- (char*)&rv, &optlen);
- if (rv) {
- break;
- }
- Sleep(0);
- }
-
- if (rv == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Unable to establish connection");
- } else if (rv == WSAEADDRNOTAVAIL) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
- "connect: Address is invalid on local machine,"
- " or port is not valid on remote machine");
- } else {
- NET_ThrowNew(env, rv, "connect");
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: localPort0
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_localPort0
- (JNIEnv *env, jclass clazz, jint fd) {
- SOCKETADDRESS sa;
- int len = sizeof(sa);
-
- if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
- if (WSAGetLastError() == WSAENOTSOCK) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- } else {
- NET_ThrowNew(env, WSAGetLastError(), "getsockname failed");
- }
- return -1;
- }
- return (int) ntohs((u_short)GET_PORT(&sa));
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: localAddress
- * Signature: (ILjava/net/InetAddressContainer;)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_localAddress
- (JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) {
- int port;
- SOCKETADDRESS sa;
- int len = sizeof(sa);
- jobject iaObj;
- jclass iaContainerClass;
- jfieldID iaFieldID;
-
- if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
- return;
- }
- iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
- CHECK_NULL(iaObj);
-
- iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);
- iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;");
- CHECK_NULL(iaFieldID);
- (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
-}
-
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: listen0
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_listen0
- (JNIEnv *env, jclass clazz, jint fd, jint backlog) {
- if (listen(fd, backlog) == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "listen failed");
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: accept0
- * Signature: (I[Ljava/net/InetSocketAddress;)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_accept0
- (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
- int newfd, port=0;
- jobject isa;
- jobject ia;
- SOCKETADDRESS sa;
- int len = sizeof(sa);
-
- memset((char *)&sa, 0, len);
- newfd = accept(fd, &sa.sa, &len);
-
- if (newfd < 0) {
- if (newfd == -2) {
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- } else {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "socket closed");
- }
- return -1;
- }
-
- SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
-
- if (sa.sa.sa_family != AF_INET) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Protocol family not supported");
- NET_SocketClose(newfd);
- return -1;
- }
-
- ia = NET_SockaddrToInetAddress(env, &sa, &port);
- isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
- (*env)->SetObjectArrayElement(env, isaa, 0, isa);
-
- return newfd;
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: waitForNewConnection
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_waitForNewConnection
- (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
- int rv;
-
- rv = NET_Timeout(fd, timeout);
- if (rv == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
- "Accept timed out");
- } else if (rv == -1) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
- } else if (rv == -2) {
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: available0
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_available0
- (JNIEnv *env, jclass clazz, jint fd) {
- jint available = -1;
-
- if ((ioctlsocket(fd, FIONREAD, &available)) == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "socket available");
- }
-
- return available;
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: close0
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_close0
- (JNIEnv *env, jclass clazz, jint fd) {
- NET_SocketClose(fd);
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: shutdown0
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_shutdown0
- (JNIEnv *env, jclass clazz, jint fd, jint howto) {
- shutdown(fd, howto);
-}
-
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: setIntOption
- * Signature: (III)V
- */
-JNIEXPORT void JNICALL
-Java_java_net_TwoStacksPlainSocketImpl_setIntOption
- (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value)
-{
- int level = 0, opt = 0;
- struct linger linger = {0, 0};
- char *parg;
- int arglen;
-
- if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
- JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
- return;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER) {
- parg = (char *)&linger;
- arglen = sizeof(linger);
- if (value >= 0) {
- linger.l_onoff = 1;
- linger.l_linger = (unsigned short)value;
- } else {
- linger.l_onoff = 0;
- linger.l_linger = 0;
- }
- } else {
- parg = (char *)&value;
- arglen = sizeof(value);
- }
-
- if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {
- NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: setSoTimeout0
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL
-Java_java_net_TwoStacksPlainSocketImpl_setSoTimeout0
- (JNIEnv *env, jclass clazz, jint fd, jint timeout)
-{
- /*
- * SO_TIMEOUT is the socket option used to specify the timeout
- * for ServerSocket.accept and Socket.getInputStream().read.
- * It does not typically map to a native level socket option.
- * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
- * socket option to specify a receive timeout on the socket. This
- * receive timeout is applicable to Socket only and the socket
- * option should not be set on ServerSocket.
- */
-
- /*
- * SO_RCVTIMEO is only supported on Microsoft's implementation
- * of Windows Sockets so if WSAENOPROTOOPT returned then
- * reset flag and timeout will be implemented using
- * select() -- see SocketInputStream.socketRead.
- */
- if (isRcvTimeoutSupported) {
- /*
- * Disable SO_RCVTIMEO if timeout is <= 5 second.
- */
- if (timeout <= 5000) {
- timeout = 0;
- }
-
- if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
- sizeof(timeout)) < 0) {
- int err = WSAGetLastError();
- if (err == WSAENOPROTOOPT) {
- isRcvTimeoutSupported = JNI_FALSE;
- } else {
- NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO");
- }
- }
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: getIntOption
- * Signature: (II)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_getIntOption
- (JNIEnv *env, jclass clazz, jint fd, jint cmd)
-{
- int level = 0, opt = 0;
- int result=0;
- struct linger linger = {0, 0};
- char *arg;
- int arglen;
-
- if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
- JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
- return -1;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER) {
- arg = (char *)&linger;
- arglen = sizeof(linger);
- } else {
- arg = (char *)&result;
- arglen = sizeof(result);
- }
-
- if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) {
- NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
- return -1;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER)
- return linger.l_onoff ? linger.l_linger : -1;
- else
- return result;
-}
-
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: sendOOB
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_sendOOB
- (JNIEnv *env, jclass clazz, jint fd, jint data) {
- jint n;
- unsigned char d = (unsigned char) data & 0xff;
-
- n = send(fd, (char *)&data, 1, MSG_OOB);
- if (n == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "send");
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: configureBlocking
- * Signature: (IZ)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_configureBlocking
- (JNIEnv *env, jclass clazz, jint fd, jboolean blocking) {
- u_long arg;
- int result;
-
- if (blocking == JNI_TRUE) {
- arg = SET_BLOCKING; // 0
- } else {
- arg = SET_NONBLOCKING; // 1
- }
-
- result = ioctlsocket(fd, FIONBIO, &arg);
- if (result == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "configureBlocking");
- }
-}
--- a/src/jdk.charsets/share/classes/sun/nio/cs/ext/IBM942C.java Thu Apr 19 21:11:32 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.nio.cs.ext;
-
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CharsetEncoder;
-import java.util.Arrays;
-import sun.nio.cs.DoubleByte;
-import sun.nio.cs.HistoricallyNamedCharset;
-import static sun.nio.cs.CharsetMapping.*;
-
-public class IBM942C extends Charset implements HistoricallyNamedCharset
-{
- public IBM942C() {
- super("x-IBM942C", ExtendedCharsets.aliasesFor("x-IBM942C"));
- }
-
- public String historicalName() {
- return "Cp942C";
- }
-
- public boolean contains(Charset cs) {
- return ((cs.name().equals("US-ASCII"))
- || (cs instanceof IBM942C));
- }
-
- public CharsetDecoder newDecoder() {
- return new DoubleByte.Decoder(this,
- IBM942.b2c,
- b2cSB,
- 0x40,
- 0xfc);
- }
-
- public CharsetEncoder newEncoder() {
- return new DoubleByte.Encoder(this, c2b, c2bIndex);
- }
-
- final static char[] b2cSB;
- final static char[] c2b;
- final static char[] c2bIndex;
-
- static {
- IBM942.initb2c();
-
- // the mappings need udpate are
- // u+001a <-> 0x1a
- // u+001c <-> 0x1c
- // u+005c <-> 0x5c
- // u+007e <-> 0x7e
- // u+007f <-> 0x7f
-
- b2cSB = Arrays.copyOf(IBM942.b2cSB, IBM942.b2cSB.length);
- b2cSB[0x1a] = 0x1a;
- b2cSB[0x1c] = 0x1c;
- b2cSB[0x5c] = 0x5c;
- b2cSB[0x7e] = 0x7e;
- b2cSB[0x7f] = 0x7f;
-
- IBM942.initc2b();
- c2b = Arrays.copyOf(IBM942.c2b, IBM942.c2b.length);
- c2bIndex = Arrays.copyOf(IBM942.c2bIndex, IBM942.c2bIndex.length);
- c2b[c2bIndex[0] + 0x1a] = 0x1a;
- c2b[c2bIndex[0] + 0x1c] = 0x1c;
- c2b[c2bIndex[0] + 0x5c] = 0x5c;
- c2b[c2bIndex[0] + 0x7e] = 0x7e;
- c2b[c2bIndex[0] + 0x7f] = 0x7f;
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.charsets/share/classes/sun/nio/cs/ext/IBM942C.java.template Thu Apr 19 21:21:45 2018 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package $PACKAGE$;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.util.Arrays;
+import sun.nio.cs.DoubleByte;
+import sun.nio.cs.HistoricallyNamedCharset;
+import static sun.nio.cs.CharsetMapping.*;
+
+public class IBM942C extends Charset implements HistoricallyNamedCharset
+{
+ public IBM942C() {
+ super("x-IBM942C", $ALIASES$);
+ }
+
+ public String historicalName() {
+ return "Cp942C";
+ }
+
+ public boolean contains(Charset cs) {
+ return ((cs.name().equals("US-ASCII"))
+ || (cs instanceof IBM942C));
+ }
+
+ public CharsetDecoder newDecoder() {
+ return new DoubleByte.Decoder(this,
+ IBM942.b2c,
+ b2cSB,
+ 0x40,
+ 0xfc);
+ }
+
+ public CharsetEncoder newEncoder() {
+ return new DoubleByte.Encoder(this, c2b, c2bIndex);
+ }
+
+ final static char[] b2cSB;
+ final static char[] c2b;
+ final static char[] c2bIndex;
+
+ static {
+ IBM942.initb2c();
+
+ // the mappings need udpate are
+ // u+001a <-> 0x1a
+ // u+001c <-> 0x1c
+ // u+005c <-> 0x5c
+ // u+007e <-> 0x7e
+ // u+007f <-> 0x7f
+
+ b2cSB = Arrays.copyOf(IBM942.b2cSB, IBM942.b2cSB.length);
+ b2cSB[0x1a] = 0x1a;
+ b2cSB[0x1c] = 0x1c;
+ b2cSB[0x5c] = 0x5c;
+ b2cSB[0x7e] = 0x7e;
+ b2cSB[0x7f] = 0x7f;
+
+ IBM942.initc2b();
+ c2b = Arrays.copyOf(IBM942.c2b, IBM942.c2b.length);
+ c2bIndex = Arrays.copyOf(IBM942.c2bIndex, IBM942.c2bIndex.length);
+ c2b[c2bIndex[0] + 0x1a] = 0x1a;
+ c2b[c2bIndex[0] + 0x1c] = 0x1c;
+ c2b[c2bIndex[0] + 0x5c] = 0x5c;
+ c2b[c2bIndex[0] + 0x7e] = 0x7e;
+ c2b[c2bIndex[0] + 0x7f] = 0x7f;
+ }
+}
--- a/src/jdk.charsets/share/classes/sun/nio/cs/ext/IBM943C.java Thu Apr 19 21:11:32 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.nio.cs.ext;
-
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CharsetEncoder;
-import java.util.Arrays;
-import sun.nio.cs.DoubleByte;
-import sun.nio.cs.HistoricallyNamedCharset;
-
-public class IBM943C extends Charset implements HistoricallyNamedCharset
-{
-
- public IBM943C() {
- super("x-IBM943C", ExtendedCharsets.aliasesFor("x-IBM943C"));
- }
-
- public String historicalName() {
- return "Cp943C";
- }
-
- public boolean contains(Charset cs) {
- return ((cs.name().equals("US-ASCII"))
- || (cs instanceof IBM943C));
- }
-
- public CharsetDecoder newDecoder() {
- return new DoubleByte.Decoder(this,
- IBM943.b2c,
- b2cSB,
- 0x40,
- 0xfc);
- }
-
- public CharsetEncoder newEncoder() {
- return new DoubleByte.Encoder(this, c2b, c2bIndex);
- }
-
- final static char[] b2cSB;
- final static char[] c2b;
- final static char[] c2bIndex;
-
- static {
- IBM943.initb2c();
- b2cSB = new char[0x100];
- for (int i = 0; i < 0x80; i++) {
- b2cSB[i] = (char)i;
- }
- for (int i = 0x80; i < 0x100; i++) {
- b2cSB[i] = IBM943.b2cSB[i];
- }
-
- IBM943.initc2b();
- c2b = Arrays.copyOf(IBM943.c2b, IBM943.c2b.length);
- c2bIndex = Arrays.copyOf(IBM943.c2bIndex, IBM943.c2bIndex.length);
- for (char c = '\0'; c < '\u0080'; ++c) {
- int index = c2bIndex[c >> 8];
- c2b[index + (c & 0xff)] = c;
- }
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.charsets/share/classes/sun/nio/cs/ext/IBM943C.java.template Thu Apr 19 21:21:45 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package $PACKAGE$;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.util.Arrays;
+import sun.nio.cs.DoubleByte;
+import sun.nio.cs.HistoricallyNamedCharset;
+
+public class IBM943C extends Charset implements HistoricallyNamedCharset
+{
+
+ public IBM943C() {
+ super("x-IBM943C", $ALIASES$);
+ }
+
+ public String historicalName() {
+ return "Cp943C";
+ }
+
+ public boolean contains(Charset cs) {
+ return ((cs.name().equals("US-ASCII"))
+ || (cs instanceof IBM943C));
+ }
+
+ public CharsetDecoder newDecoder() {
+ return new DoubleByte.Decoder(this,
+ IBM943.b2c,
+ b2cSB,
+ 0x40,
+ 0xfc);
+ }
+
+ public CharsetEncoder newEncoder() {
+ return new DoubleByte.Encoder(this, c2b, c2bIndex);
+ }
+
+ final static char[] b2cSB;
+ final static char[] c2b;
+ final static char[] c2bIndex;
+
+ static {
+ IBM943.initb2c();
+ b2cSB = new char[0x100];
+ for (int i = 0; i < 0x80; i++) {
+ b2cSB[i] = (char)i;
+ }
+ for (int i = 0x80; i < 0x100; i++) {
+ b2cSB[i] = IBM943.b2cSB[i];
+ }
+
+ IBM943.initc2b();
+ c2b = Arrays.copyOf(IBM943.c2b, IBM943.c2b.length);
+ c2bIndex = Arrays.copyOf(IBM943.c2bIndex, IBM943.c2bIndex.length);
+ for (char c = '\0'; c < '\u0080'; ++c) {
+ int index = c2bIndex[c >> 8];
+ c2b[index + (c & 0xff)] = c;
+ }
+ }
+}
--- a/test/hotspot/gtest/utilities/test_globalCounter.cpp Thu Apr 19 21:11:32 2018 +0200
+++ b/test/hotspot/gtest/utilities/test_globalCounter.cpp Thu Apr 19 21:21:45 2018 +0200
@@ -29,8 +29,8 @@
#include "utilities/globalCounter.inline.hpp"
#include "utilitiesHelper.inline.hpp"
-#define GOOD 1337
-#define BAD 4711
+#define GOOD_VALUE 1337
+#define BAD_VALUE 4711
struct TestData {
long test_value;
@@ -50,13 +50,13 @@
GlobalCounter::critical_section_begin(this);
volatile TestData* test = OrderAccess::load_acquire(_test);
long value = OrderAccess::load_acquire(&test->test_value);
- ASSERT_EQ(value, GOOD);
+ ASSERT_EQ(value, GOOD_VALUE);
GlobalCounter::critical_section_end(this);
{
GlobalCounter::CriticalSection cs(this);
volatile TestData* test = OrderAccess::load_acquire(_test);
long value = OrderAccess::load_acquire(&test->test_value);
- ASSERT_EQ(value, GOOD);
+ ASSERT_EQ(value, GOOD_VALUE);
}
}
}
@@ -81,7 +81,7 @@
RCUReaderThread* reader4 = new RCUReaderThread(&post, &test, &wrt_start);
TestData* tmp = new TestData();
- tmp->test_value = GOOD;
+ tmp->test_value = GOOD_VALUE;
OrderAccess::release_store_fence(&test, tmp);
reader1->doit();
@@ -98,10 +98,10 @@
for (int i = 0; i < 100000 && stop_ms > os::javaTimeMillis(); i++) {
volatile TestData* free_tmp = test;
tmp = new TestData();
- tmp->test_value = GOOD;
+ tmp->test_value = GOOD_VALUE;
OrderAccess::release_store(&test, tmp);
GlobalCounter::write_synchronize();
- free_tmp->test_value = BAD;
+ free_tmp->test_value = BAD_VALUE;
delete free_tmp;
}
RCUReaderThread::_exit = true;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/Socket/RejectIPv6.java Thu Apr 19 21:21:45 2018 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8201510
+ * @summary Make sure IPv6 addresses are rejected when the System option
+ * java.net.preferIPv4Stack is set to true
+ * @run main/othervm -Djava.net.preferIPv4Stack=true RejectIPv6
+ */
+
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+
+public class RejectIPv6 {
+
+ public static void main(String [] argv) throws Throwable {
+ ServerSocket serverSocket = new ServerSocket(0);
+ serverSocket.setSoTimeout(1000);
+ int serverPort = serverSocket.getLocalPort();
+ Socket clientSocket = new Socket();
+
+ test("bind", () -> clientSocket.bind(
+ new InetSocketAddress("::1", 0)));
+
+ test("connect", () -> clientSocket.connect(
+ new InetSocketAddress("::1", serverPort), 1000));
+ }
+
+ static void test(String msg, CodeToTest codeToTest) throws Throwable {
+ Thread client = new Thread(() ->
+ {
+ try {
+ codeToTest.run();
+ throw new RuntimeException(msg +
+ " failed to reject IPv6 address");
+ } catch (SocketException ok) {
+ } catch (Exception exc) {
+ throw new RuntimeException("unexpected", exc);
+ }
+ });
+ client.start();
+ client.join();
+ }
+
+ interface CodeToTest {
+ void run() throws Exception;
+ }
+}
--- a/test/jdk/java/net/Socket/setReuseAddress/Basic.java Thu Apr 19 21:11:32 2018 +0200
+++ b/test/jdk/java/net/Socket/setReuseAddress/Basic.java Thu Apr 19 21:21:45 2018 +0200
@@ -25,11 +25,15 @@
* @test
* @bug 4476378
* @summary Check the specific behaviour of the setReuseAddress(boolean)
- * method.
+ * method.
* @run main Basic
* @run main/othervm -Dsun.net.useExclusiveBind Basic
+ * @run main/othervm -Dsun.net.useExclusiveBind=true Basic
* @run main/othervm -Djava.net.preferIPv4Stack=true Basic
- * @run main/othervm -Dsun.net.useExclusiveBind -Djava.net.preferIPv4Stack=true Basic
+ * @run main/othervm -Dsun.net.useExclusiveBind
+ * -Djava.net.preferIPv4Stack=true Basic
+ * @run main/othervm -Dsun.net.useExclusiveBind=true
+ * -Djava.net.preferIPv4Stack=true Basic
*/
import java.net.*;
--- a/test/jdk/java/net/Socket/setReuseAddress/Restart.java Thu Apr 19 21:11:32 2018 +0200
+++ b/test/jdk/java/net/Socket/setReuseAddress/Restart.java Thu Apr 19 21:21:45 2018 +0200
@@ -28,8 +28,12 @@
* after a crash.
* @run main Restart
* @run main/othervm -Dsun.net.useExclusiveBind Restart
+ * @run main/othervm -Dsun.net.useExclusiveBind=true Restart
* @run main/othervm -Djava.net.preferIPv4Stack=true Restart
- * @run main/othervm -Dsun.net.useExclusiveBind -Djava.net.preferIPv4Stack=true Restart
+ * @run main/othervm -Dsun.net.useExclusiveBind
+ * -Djava.net.preferIPv4Stack=true Restart
+ * @run main/othervm -Dsun.net.useExclusiveBind=true
+ * -Djava.net.preferIPv4Stack=true Restart
*/
import java.net.*;
--- a/test/jdk/java/util/zip/DeInflate.java Thu Apr 19 21:11:32 2018 +0200
+++ b/test/jdk/java/util/zip/DeInflate.java Thu Apr 19 21:21:45 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,17 +23,23 @@
/**
* @test
- * @bug 7110149 8184306
+ * @bug 7110149 8184306 6341887
* @summary Test basic deflater & inflater functionality
* @key randomness
*/
import java.io.*;
+import java.nio.*;
import java.util.*;
import java.util.zip.*;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
public class DeInflate {
+ private static Random rnd = new Random();
+
+
static void checkStream(Deflater def, byte[] in, int len,
byte[] out1, byte[] out2, boolean nowrap)
throws Throwable
@@ -61,6 +67,57 @@
}
}
+ static void checkByteBuffer(Deflater def, Inflater inf,
+ ByteBuffer in, ByteBuffer out1, ByteBuffer out2,
+ byte[] expected, int len, byte[] result,
+ boolean out1ReadOnlyWhenInflate)
+ throws Throwable {
+ def.reset();
+ inf.reset();
+
+ def.setInput(in);
+ def.finish();
+ int m = def.deflate(out1);
+
+ out1.flip();
+ if (out1ReadOnlyWhenInflate)
+ out1 = out1.asReadOnlyBuffer();
+ inf.setInput(out1);
+ int n = inf.inflate(out2);
+
+ out2.flip();
+ out2.get(result, 0, n);
+
+ if (n != len || out2.position() != len ||
+ !Arrays.equals(Arrays.copyOf(expected, len), Arrays.copyOf(result, len)) ||
+ inf.inflate(result) != 0) {
+ throw new RuntimeException("De/inflater(buffer) failed:" + def);
+ }
+ }
+
+ static void checkByteBufferReadonly(Deflater def, Inflater inf,
+ ByteBuffer in, ByteBuffer out1, ByteBuffer out2)
+ throws Throwable {
+ def.reset();
+ inf.reset();
+ def.setInput(in);
+ def.finish();
+ int m = -1;
+ if (!out2.isReadOnly())
+ out2 = out2.asReadOnlyBuffer();
+ try {
+ m = def.deflate(out2);
+ throw new RuntimeException("deflater: ReadOnlyBufferException: failed");
+ } catch (ReadOnlyBufferException robe) {}
+ m = def.deflate(out1);
+ out1.flip();
+ inf.setInput(out1);
+ try {
+ inf.inflate(out2);
+ throw new RuntimeException("inflater: ReadOnlyBufferException: failed");
+ } catch (ReadOnlyBufferException robe) {}
+ }
+
static void check(Deflater def, byte[] in, int len,
byte[] out1, byte[] out2, boolean nowrap)
throws Throwable
@@ -83,6 +140,107 @@
m, n, len, Arrays.equals(in, out2));
throw new RuntimeException("De/inflater failed:" + def);
}
+
+ // readable
+ Arrays.fill(out1, (byte)0);
+ Arrays.fill(out2, (byte)0);
+ ByteBuffer bbIn = ByteBuffer.wrap(in, 0, len);
+ ByteBuffer bbOut1 = ByteBuffer.wrap(out1);
+ ByteBuffer bbOut2 = ByteBuffer.wrap(out2);
+ checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, false);
+ checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2);
+
+ // readonly in
+ Arrays.fill(out1, (byte)0);
+ Arrays.fill(out2, (byte)0);
+ bbIn = ByteBuffer.wrap(in, 0, len).asReadOnlyBuffer();
+ bbOut1 = ByteBuffer.wrap(out1);
+ bbOut2 = ByteBuffer.wrap(out2);
+ checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, false);
+ checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2);
+
+ // readonly out1 when inflate
+ Arrays.fill(out1, (byte)0);
+ Arrays.fill(out2, (byte)0);
+ bbIn = ByteBuffer.wrap(in, 0, len);
+ bbOut1 = ByteBuffer.wrap(out1);
+ bbOut2 = ByteBuffer.wrap(out2);
+ checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, true);
+ checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2);
+
+ // direct
+ bbIn = ByteBuffer.allocateDirect(in.length);
+ bbIn.put(in, 0, n).flip();
+ bbOut1 = ByteBuffer.allocateDirect(out1.length);
+ bbOut2 = ByteBuffer.allocateDirect(out2.length);
+ checkByteBuffer(def, inf, bbIn, bbOut1, bbOut2, in, len, out2, false);
+ checkByteBufferReadonly(def, inf, bbIn, bbOut1, bbOut2);
+ }
+
+ static void checkDict(Deflater def, Inflater inf, byte[] src,
+ byte[] dstDef, byte[] dstInf,
+ ByteBuffer dictDef, ByteBuffer dictInf) throws Throwable {
+ def.reset();
+ inf.reset();
+
+ def.setDictionary(dictDef);
+ def.setInput(src);
+ def.finish();
+ int n = def.deflate(dstDef);
+
+ inf.setInput(dstDef, 0, n);
+ n = inf.inflate(dstInf);
+ if (n != 0 || !inf.needsDictionary()) {
+ throw new RuntimeException("checkDict failed: need dict to continue");
+ }
+ inf.setDictionary(dictInf);
+ n = inf.inflate(dstInf);
+ // System.out.println("result: " + new String(dstInf, 0, n));
+ if (n != src.length || !Arrays.equals(Arrays.copyOf(dstInf, n), src)) {
+ throw new RuntimeException("checkDict failed: inflate result");
+ }
+ }
+
+ static void checkDict(int level, int strategy) throws Throwable {
+
+ Deflater def = newDeflater(level, strategy, false, new byte[0]);
+ Inflater inf = new Inflater();
+
+ byte[] src = "hello world, hello world, hello sherman".getBytes();
+ byte[] dict = "hello".getBytes();
+
+ byte[] dstDef = new byte[1024];
+ byte[] dstInf = new byte[1024];
+
+ def.setDictionary(dict);
+ def.setInput(src);
+ def.finish();
+ int n = def.deflate(dstDef);
+
+ inf.setInput(dstDef, 0, n);
+ n = inf.inflate(dstInf);
+ if (n != 0 || !inf.needsDictionary()) {
+ throw new RuntimeException("checkDict failed: need dict to continue");
+ }
+ inf.setDictionary(dict);
+ n = inf.inflate(dstInf);
+ //System.out.println("result: " + new String(dstInf, 0, n));
+ if (n != src.length || !Arrays.equals(Arrays.copyOf(dstInf, n), src)) {
+ throw new RuntimeException("checkDict failed: inflate result");
+ }
+
+ ByteBuffer dictDef = ByteBuffer.wrap(dict);
+ ByteBuffer dictInf = ByteBuffer.wrap(dict);
+ checkDict(def, inf, src, dstDef, dstInf, dictDef, dictInf);
+
+ dictDef = ByteBuffer.allocateDirect(dict.length);
+ dictInf = ByteBuffer.allocateDirect(dict.length);
+ dictDef.put(dict).flip();
+ dictInf.put(dict).flip();
+ checkDict(def, inf, src, dstDef, dstInf, dictDef, dictInf);
+
+ def.end();
+ inf.end();
}
private static Deflater newDeflater(int level, int strategy, boolean dowrap, byte[] tmp) {
@@ -109,7 +267,7 @@
public static void main(String[] args) throws Throwable {
byte[] dataIn = new byte[1024 * 512];
- new Random().nextBytes(dataIn);
+ rnd.nextBytes(dataIn);
byte[] dataOut1 = new byte[dataIn.length + 1024];
byte[] dataOut2 = new byte[dataIn.length];
@@ -130,6 +288,7 @@
// use a new deflater
Deflater def = newDeflater(level, strategy, dowrap, dataOut2);
check(def, dataIn, len, dataOut1, dataOut2, dowrap);
+ def.end();
// reuse the deflater (with reset) and test on stream, which
// uses a "smaller" buffer (smaller than the overall data)
@@ -137,6 +296,8 @@
checkStream(def, dataIn, len, dataOut1, dataOut2, dowrap);
}
}
+ // test setDictionary()
+ checkDict(level, strategy);
}
}
}
--- a/test/jdk/java/util/zip/FlaterTest.java Thu Apr 19 21:11:32 2018 +0200
+++ b/test/jdk/java/util/zip/FlaterTest.java Thu Apr 19 21:21:45 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,13 +23,12 @@
/**
* @test
- * @bug 6348045
+ * @bug 6348045 6341887
* @summary GZipOutputStream/InputStream goes critical(calls JNI_Get*Critical)
* and causes slowness. This test uses Deflater and Inflater directly.
* @key randomness
*/
-import java.io.*;
import java.nio.*;
import java.util.*;
import java.util.zip.*;
@@ -41,35 +40,37 @@
*/
public class FlaterTest extends Thread {
private static final int DATA_LEN = 1024 * 128;
- private static byte[] data;
+
+ private static ByteBuffer dataDirect;
+ private static ByteBuffer dataHeap;
// If true, print extra info.
private static final boolean debug = false;
// Set of Flater threads running.
- private static Set flaters =
- Collections.synchronizedSet(new HashSet());
+ private static Set<Flater> flaters =
+ Collections.synchronizedSet(new HashSet<>());
/** Fill in {@code data} with random values. */
static void createData() {
- ByteBuffer bb = ByteBuffer.allocate(8);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- for (int i = 0; i < DATA_LEN; i++) {
- bb.putDouble(0, Math.random());
- baos.write(bb.array(), 0, 8);
+ ByteBuffer bb = ByteBuffer.allocateDirect(DATA_LEN * 8);
+ for (int i = 0; i < DATA_LEN * 8; i += 8) {
+ bb.putDouble(i, Math.random());
}
- data = baos.toByteArray();
- if (debug) System.out.println("data length is " + data.length);
+ dataDirect = bb;
+ final ByteBuffer hb = ByteBuffer.allocate(bb.capacity());
+ hb.duplicate().put(bb.duplicate());
+ dataHeap = hb;
+ if (debug) System.out.println("data length is " + bb.capacity());
}
/** @return the length of the deflated {@code data}. */
- private static int getDeflatedLength() throws Throwable {
- int rc = 0;
+ private static int getDeflatedLength() {
Deflater deflater = new Deflater();
- deflater.setInput(data);
+ deflater.setInput(dataDirect.duplicate());
deflater.finish();
- byte[] out = new byte[data.length];
- rc = deflater.deflate(out);
+ byte[] out = new byte[dataDirect.capacity()];
+ int rc = deflater.deflate(out);
deflater.end();
if (debug) System.out.println("deflatedLength is " + rc);
return rc;
@@ -78,70 +79,98 @@
/** Compares given bytes with those in {@code data}.
* @throws Exception if given bytes don't match {@code data}.
*/
- private static void validate(byte[] buf, int offset, int len) throws Exception {
+ private static void validate(ByteBuffer buf, int offset, int len) throws Exception {
for (int i = 0; i < len; i++ ) {
- if (buf[i] != data[offset+i]) {
+ if (buf.get(i) != dataDirect.get(offset+i)) {
throw new Exception("mismatch at " + (offset + i));
}
}
}
- public static void realMain(String[] args) throws Throwable {
+ public static void realMain(String[] args) {
+ int numThreads = args.length > 0 ? Integer.parseInt(args[0]) : 5;
createData();
- int numThreads = args.length > 0 ? Integer.parseInt(args[0]) : 5;
- new FlaterTest().go(numThreads);
+ for (int srcMode = 0; srcMode <= 2; srcMode ++) {
+ for (int dstMode = 0; dstMode <= 2; dstMode ++) {
+ new FlaterTest().go(numThreads, srcMode, dstMode);
+ }
+ }
}
- private synchronized void go(int numThreads) throws Throwable {
+ private synchronized void go(int numThreads, int srcMode, int dstMode) {
int deflatedLength = getDeflatedLength();
long time = System.currentTimeMillis();
for (int i = 0; i < numThreads; i++) {
- Flater f = new Flater(deflatedLength);
+ Flater f = new Flater(deflatedLength, srcMode, dstMode);
flaters.add(f);
f.start();
}
- while (flaters.size() != 0) {
- try {
- Thread.currentThread().sleep(10);
- } catch (InterruptedException ex) {
- unexpected(ex);
+ synchronized (flaters) {
+ while (flaters.size() != 0) {
+ try {
+ flaters.wait();
+ } catch (InterruptedException ex) {
+ unexpected(ex);
+ }
}
}
time = System.currentTimeMillis() - time;
System.out.println("Time needed for " + numThreads
- + " threads to deflate/inflate: " + time + " ms.");
+ + " threads to deflate/inflate: " + time + " ms (srcMode="+srcMode+",dstMode="+dstMode+")");
}
/** Deflates and inflates data. */
static class Flater extends Thread {
private final int deflatedLength;
+ private final int srcMode, dstMode;
- private Flater(int length) {
+ private Flater(int length, int srcMode, int dstMode) {
this.deflatedLength = length;
+ this.srcMode = srcMode;
+ this.dstMode = dstMode;
}
/** Deflates and inflates {@code data}. */
public void run() {
if (debug) System.out.println(getName() + " starting run()");
try {
- byte[] deflated = DeflateData(deflatedLength);
+ ByteBuffer deflated = DeflateData(deflatedLength);
InflateData(deflated);
} catch (Throwable t) {
t.printStackTrace();
fail(getName() + " failed");
} finally {
- flaters.remove(this);
+ synchronized (flaters) {
+ flaters.remove(this);
+ if (flaters.isEmpty()) {
+ flaters.notifyAll();
+ }
+ }
}
}
/** Returns a copy of {@code data} in deflated form. */
- private byte[] DeflateData(int length) throws Throwable {
+ private ByteBuffer DeflateData(int length) {
Deflater deflater = new Deflater();
- deflater.setInput(data);
+ if (srcMode == 0) {
+ deflater.setInput(dataHeap.array());
+ } else if (srcMode == 1) {
+ deflater.setInput(dataHeap.duplicate());
+ } else {
+ assert srcMode == 2;
+ deflater.setInput(dataDirect.duplicate());
+ }
deflater.finish();
- byte[] out = new byte[length];
- deflater.deflate(out);
+ ByteBuffer out = dstMode == 2 ? ByteBuffer.allocateDirect(length) : ByteBuffer.allocate(length);
+ int deflated;
+ if (dstMode == 0) {
+ deflated = deflater.deflate(out.array(), 0, length);
+ out.position(deflated);
+ } else {
+ deflater.deflate(out);
+ }
+ out.flip();
return out;
}
@@ -149,14 +178,30 @@
* inflation.
* @throws Exception if inflated bytes don't match {@code data}.
*/
- private void InflateData(byte[] bytes) throws Throwable {
+ private void InflateData(ByteBuffer bytes) throws Throwable {
Inflater inflater = new Inflater();
- inflater.setInput(bytes, 0, bytes.length);
+ if (dstMode == 0) {
+ inflater.setInput(bytes.array(), 0, bytes.remaining());
+ } else {
+ inflater.setInput(bytes);
+ }
+ if (inflater.getRemaining() == 0) {
+ throw new Exception("Nothing to inflate (bytes=" + bytes + ")");
+ }
int len = 1024 * 8;
int offset = 0;
+ ByteBuffer buf = srcMode == 2 ? ByteBuffer.allocateDirect(len) : ByteBuffer.allocate(len);
while (inflater.getRemaining() > 0) {
- byte[] buf = new byte[len];
- int inflated = inflater.inflate(buf, 0, len);
+ buf.clear();
+ int inflated;
+ if (srcMode == 0) {
+ inflated = inflater.inflate(buf.array(), 0, buf.remaining());
+ } else {
+ inflated = inflater.inflate(buf);
+ }
+ if (inflated == 0) {
+ throw new Exception("Nothing inflated (dst=" + buf + ",offset=" + offset + ",rem=" + inflater.getRemaining() + ",srcMode="+srcMode+",dstMode="+dstMode+")");
+ }
validate(buf, offset, inflated);
offset += inflated;
}