mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
Merge
This commit is contained in:
commit
3e85467bc6
322 changed files with 8135 additions and 4008 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 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
|
||||
|
@ -79,8 +79,6 @@ class FileInputStream extends InputStream
|
|||
|
||||
private volatile boolean closed;
|
||||
|
||||
private final Object altFinalizer;
|
||||
|
||||
/**
|
||||
* Creates a <code>FileInputStream</code> by
|
||||
* opening a connection to an actual file,
|
||||
|
@ -155,10 +153,7 @@ class FileInputStream extends InputStream
|
|||
fd.attach(this);
|
||||
path = name;
|
||||
open(name);
|
||||
altFinalizer = getFinalizer(this);
|
||||
if (altFinalizer == null) {
|
||||
FileCleanable.register(fd); // open set the fd, register the cleanup
|
||||
}
|
||||
FileCleanable.register(fd); // open set the fd, register the cleanup
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -195,7 +190,6 @@ class FileInputStream extends InputStream
|
|||
}
|
||||
fd = fdObj;
|
||||
path = null;
|
||||
altFinalizer = null;
|
||||
|
||||
/*
|
||||
* FileDescriptor is being shared by streams.
|
||||
|
@ -438,85 +432,4 @@ class FileInputStream extends InputStream
|
|||
static {
|
||||
initIDs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the {@link #close} method of this file input stream is
|
||||
* called when there are no more references to it.
|
||||
* The {@link #finalize} method does not call {@link #close} directly.
|
||||
*
|
||||
* @apiNote
|
||||
* To release resources used by this stream {@link #close} should be called
|
||||
* directly or by try-with-resources.
|
||||
*
|
||||
* @implSpec
|
||||
* If this FileInputStream has been subclassed and the {@link #close}
|
||||
* method has been overridden, the {@link #close} method will be
|
||||
* called when the FileInputStream is unreachable.
|
||||
* Otherwise, it is implementation specific how the resource cleanup described in
|
||||
* {@link #close} is performed.
|
||||
*
|
||||
* @deprecated The {@code finalize} method has been deprecated and will be removed.
|
||||
* Subclasses that override {@code finalize} in order to perform cleanup
|
||||
* should be modified to use alternative cleanup mechanisms and
|
||||
* to remove the overriding {@code finalize} method.
|
||||
* When overriding the {@code finalize} method, its implementation must explicitly
|
||||
* ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
|
||||
* See the specification for {@link Object#finalize()} for further
|
||||
* information about migration options.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
* @see java.io.FileInputStream#close()
|
||||
*/
|
||||
@Deprecated(since="9", forRemoval = true)
|
||||
protected void finalize() throws IOException {
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a finalizer object if the FIS needs a finalizer; otherwise null.
|
||||
* If the FIS has a close method; it needs an AltFinalizer.
|
||||
*/
|
||||
private static Object getFinalizer(FileInputStream fis) {
|
||||
Class<?> clazz = fis.getClass();
|
||||
while (clazz != FileInputStream.class) {
|
||||
try {
|
||||
clazz.getDeclaredMethod("close");
|
||||
return new AltFinalizer(fis);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
// ignore
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Class to call {@code FileInputStream.close} when finalized.
|
||||
* If finalization of the stream is needed, an instance is created
|
||||
* in its constructor(s). When the set of instances
|
||||
* related to the stream is unreachable, the AltFinalizer performs
|
||||
* the needed call to the stream's {@code close} method.
|
||||
*/
|
||||
static class AltFinalizer {
|
||||
private final FileInputStream fis;
|
||||
|
||||
AltFinalizer(FileInputStream fis) {
|
||||
this.fis = fis;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected final void finalize() {
|
||||
try {
|
||||
if ((fis.fd != null) && (fis.fd != FileDescriptor.in)) {
|
||||
/* if fd is shared, the references in FileDescriptor
|
||||
* will ensure that finalizer is only called when
|
||||
* safe to do so. All references using the fd have
|
||||
* become unreachable. We can call close()
|
||||
*/
|
||||
fis.close();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 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
|
||||
|
@ -95,8 +95,6 @@ class FileOutputStream extends OutputStream
|
|||
|
||||
private volatile boolean closed;
|
||||
|
||||
private final Object altFinalizer;
|
||||
|
||||
/**
|
||||
* Creates a file output stream to write to the file with the
|
||||
* specified name. A new <code>FileDescriptor</code> object is
|
||||
|
@ -235,10 +233,7 @@ class FileOutputStream extends OutputStream
|
|||
this.path = name;
|
||||
|
||||
open(name, append);
|
||||
altFinalizer = getFinalizer(this);
|
||||
if (altFinalizer == null) {
|
||||
FileCleanable.register(fd); // open sets the fd, register the cleanup
|
||||
}
|
||||
FileCleanable.register(fd); // open sets the fd, register the cleanup
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -274,7 +269,6 @@ class FileOutputStream extends OutputStream
|
|||
}
|
||||
this.fd = fdObj;
|
||||
this.path = null;
|
||||
this.altFinalizer = null;
|
||||
|
||||
fd.attach(this);
|
||||
}
|
||||
|
@ -457,98 +451,9 @@ class FileOutputStream extends OutputStream
|
|||
return fc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the connection to the file, and ensures that the
|
||||
* {@link #close} method of this file output stream is
|
||||
* called when there are no more references to this stream.
|
||||
* The {@link #finalize} method does not call {@link #close} directly.
|
||||
*
|
||||
* @apiNote
|
||||
* To release resources used by this stream {@link #close} should be called
|
||||
* directly or by try-with-resources.
|
||||
*
|
||||
* @implSpec
|
||||
* If this FileOutputStream has been subclassed and the {@link #close}
|
||||
* method has been overridden, the {@link #close} method will be
|
||||
* called when the FileOutputStream is unreachable.
|
||||
* Otherwise, it is implementation specific how the resource cleanup described in
|
||||
* {@link #close} is performed.
|
||||
*
|
||||
* @deprecated The {@code finalize} method has been deprecated and will be removed.
|
||||
* Subclasses that override {@code finalize} in order to perform cleanup
|
||||
* should be modified to use alternative cleanup mechanisms and
|
||||
* to remove the overriding {@code finalize} method.
|
||||
* When overriding the {@code finalize} method, its implementation must explicitly
|
||||
* ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
|
||||
* See the specification for {@link Object#finalize()} for further
|
||||
* information about migration options.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
* @see java.io.FileInputStream#close()
|
||||
*/
|
||||
@Deprecated(since="9", forRemoval = true)
|
||||
protected void finalize() throws IOException {
|
||||
}
|
||||
|
||||
private static native void initIDs();
|
||||
|
||||
static {
|
||||
initIDs();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a finalizer object if the FOS needs a finalizer; otherwise null.
|
||||
* If the FOS has a close method; it needs an AltFinalizer.
|
||||
*/
|
||||
private static Object getFinalizer(FileOutputStream fos) {
|
||||
Class<?> clazz = fos.getClass();
|
||||
while (clazz != FileOutputStream.class) {
|
||||
try {
|
||||
clazz.getDeclaredMethod("close");
|
||||
return new AltFinalizer(fos);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
// ignore
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to call {@code FileOutputStream.close} when finalized.
|
||||
* If finalization of the stream is needed, an instance is created
|
||||
* in its constructor(s). When the set of instances
|
||||
* related to the stream is unreachable, the AltFinalizer performs
|
||||
* the needed call to the stream's {@code close} method.
|
||||
*/
|
||||
static class AltFinalizer {
|
||||
private final FileOutputStream fos;
|
||||
|
||||
AltFinalizer(FileOutputStream fos) {
|
||||
this.fos = fos;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected final void finalize() {
|
||||
try {
|
||||
if (fos.fd != null) {
|
||||
if (fos.fd == FileDescriptor.out || fos.fd == FileDescriptor.err) {
|
||||
// Subclass may override flush; otherwise it is no-op
|
||||
fos.flush();
|
||||
} else {
|
||||
/* if fd is shared, the references in FileDescriptor
|
||||
* will ensure that finalizer is only called when
|
||||
* safe to do so. All references using the fd have
|
||||
* become unreachable. We can call close()
|
||||
*/
|
||||
fos.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -69,10 +69,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
|||
*/
|
||||
int count;
|
||||
|
||||
private static final byte[] EMPTYVALUE = new byte[0];
|
||||
|
||||
/**
|
||||
* This no-arg constructor is necessary for serialization of subclasses.
|
||||
*/
|
||||
AbstractStringBuilder() {
|
||||
value = EMPTYVALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -138,61 +138,6 @@ final class StringConcatHelper {
|
|||
return (byte)(current | value.coder());
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix coder into current coder
|
||||
* @param current current coder
|
||||
* @param value value to mix in
|
||||
* @return new coder
|
||||
*/
|
||||
static byte mixCoder(byte current, boolean value) {
|
||||
// Booleans are represented with Latin1
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix coder into current coder
|
||||
* @param current current coder
|
||||
* @param value value to mix in
|
||||
* @return new coder
|
||||
*/
|
||||
static byte mixCoder(byte current, byte value) {
|
||||
// Bytes are represented with Latin1
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix coder into current coder
|
||||
* @param current current coder
|
||||
* @param value value to mix in
|
||||
* @return new coder
|
||||
*/
|
||||
static byte mixCoder(byte current, short value) {
|
||||
// Shorts are represented with Latin1
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix coder into current coder
|
||||
* @param current current coder
|
||||
* @param value value to mix in
|
||||
* @return new coder
|
||||
*/
|
||||
static byte mixCoder(byte current, int value) {
|
||||
// Ints are represented with Latin1
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix coder into current coder
|
||||
* @param current current coder
|
||||
* @param value value to mix in
|
||||
* @return new coder
|
||||
*/
|
||||
static byte mixCoder(byte current, long value) {
|
||||
// Longs are represented with Latin1
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends the stringly representation of boolean value into buffer,
|
||||
* given the coder and final index. Index is measured in chars, not in bytes!
|
||||
|
|
|
@ -1588,28 +1588,47 @@ public final class StringConcatFactory {
|
|||
|
||||
Class<?> argClass = ptypes[ac];
|
||||
MethodHandle lm = lengthMixer(argClass);
|
||||
MethodHandle cm = coderMixer(argClass);
|
||||
|
||||
// Read this bottom up:
|
||||
// Read these bottom up:
|
||||
|
||||
// 4. Drop old index and coder, producing ("new-index", "new-coder", <args>)
|
||||
mh = MethodHandles.dropArguments(mh, 2, int.class, byte.class);
|
||||
if (argClass.isPrimitive() && argClass != char.class) {
|
||||
|
||||
// 3. Compute "new-index", producing ("new-index", "new-coder", "old-index", "old-coder", <args>)
|
||||
// Length mixer needs old index, plus the appropriate argument
|
||||
mh = MethodHandles.foldArguments(mh, 0, lm,
|
||||
2, // old-index
|
||||
4 + ac // selected argument
|
||||
);
|
||||
// 3. Drop old index, producing ("new-index", "coder", <args>)
|
||||
mh = MethodHandles.dropArguments(mh, 1, int.class);
|
||||
|
||||
// 2. Compute "new-coder", producing ("new-coder", "old-index", "old-coder", <args>)
|
||||
// Coder mixer needs old coder, plus the appropriate argument.
|
||||
mh = MethodHandles.foldArguments(mh, 0, cm,
|
||||
2, // old-coder
|
||||
3 + ac // selected argument
|
||||
);
|
||||
// 2. Compute "new-index", producing ("new-index", "old-index", "coder", <args>)
|
||||
// Length mixer needs old index, plus the appropriate argument
|
||||
mh = MethodHandles.foldArguments(mh, 0, lm,
|
||||
1, // old-index
|
||||
3 + ac // selected argument
|
||||
);
|
||||
|
||||
// 1. The mh shape here is ("old-index", "coder", <args>); we don't need to recalculate
|
||||
// the coder for non-char primitive arguments
|
||||
|
||||
} else {
|
||||
MethodHandle cm = coderMixer(argClass);
|
||||
|
||||
// 4. Drop old index and coder, producing ("new-index", "new-coder", <args>)
|
||||
mh = MethodHandles.dropArguments(mh, 2, int.class, byte.class);
|
||||
|
||||
// 3. Compute "new-index", producing ("new-index", "new-coder", "old-index", "old-coder", <args>)
|
||||
// Length mixer needs old index, plus the appropriate argument
|
||||
mh = MethodHandles.foldArguments(mh, 0, lm,
|
||||
2, // old-index
|
||||
4 + ac // selected argument
|
||||
);
|
||||
|
||||
// 2. Compute "new-coder", producing ("new-coder", "old-index", "old-coder", <args>)
|
||||
// Coder mixer needs old coder, plus the appropriate argument.
|
||||
mh = MethodHandles.foldArguments(mh, 0, cm,
|
||||
2, // old-coder
|
||||
3 + ac // selected argument
|
||||
);
|
||||
|
||||
// 1. The mh shape here is ("old-index", "old-coder", <args>)
|
||||
}
|
||||
|
||||
// 1. The mh shape here is ("old-index", "old-coder", <args>)
|
||||
break;
|
||||
default:
|
||||
throw new StringConcatException("Unhandled tag: " + el.getTag());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
|
@ -100,8 +100,8 @@ import java.util.function.Function;
|
|||
* }
|
||||
* }
|
||||
*
|
||||
* private final State;
|
||||
* private final Cleaner.Cleanable cleanable
|
||||
* private final State state;
|
||||
* private final Cleaner.Cleanable cleanable;
|
||||
*
|
||||
* public CleaningExample() {
|
||||
* this.state = new State(...);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 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
|
||||
|
@ -35,6 +35,7 @@ import java.io.FileNotFoundException;
|
|||
import java.io.ObjectStreamException;
|
||||
import java.io.ObjectStreamField;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectInputStream.GetField;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
@ -1727,8 +1728,11 @@ class InetAddress implements java.io.Serializable {
|
|||
}
|
||||
GetField gf = s.readFields();
|
||||
String host = (String)gf.get("hostName", null);
|
||||
int address= gf.get("address", 0);
|
||||
int family= gf.get("family", 0);
|
||||
int address = gf.get("address", 0);
|
||||
int family = gf.get("family", 0);
|
||||
if (family != IPv4 && family != IPv6) {
|
||||
throw new InvalidObjectException("invalid address family type: " + family);
|
||||
}
|
||||
InetAddressHolder h = new InetAddressHolder(host, address, family);
|
||||
UNSAFE.putObject(this, FIELDS_OFFSET, h);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2017, 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
|
||||
|
@ -321,8 +321,20 @@ public final class NetworkInterface {
|
|||
if (addr == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
|
||||
throw new IllegalArgumentException ("invalid address type");
|
||||
if (addr instanceof Inet4Address) {
|
||||
Inet4Address inet4Address = (Inet4Address) addr;
|
||||
if (inet4Address.holder.family != InetAddress.IPv4) {
|
||||
throw new IllegalArgumentException("invalid family type: "
|
||||
+ inet4Address.holder.family);
|
||||
}
|
||||
} else if (addr instanceof Inet6Address) {
|
||||
Inet6Address inet6Address = (Inet6Address) addr;
|
||||
if (inet6Address.holder.family != InetAddress.IPv6) {
|
||||
throw new IllegalArgumentException("invalid family type: "
|
||||
+ inet6Address.holder.family);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("invalid address type: " + addr);
|
||||
}
|
||||
return getByInetAddress0(addr);
|
||||
}
|
||||
|
|
|
@ -535,13 +535,13 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
|||
* @spec JPMS
|
||||
*/
|
||||
protected Package definePackage(String name, Manifest man, URL url) {
|
||||
String path = name.replace('.', '/').concat("/");
|
||||
String specTitle = null, specVersion = null, specVendor = null;
|
||||
String implTitle = null, implVersion = null, implVendor = null;
|
||||
String sealed = null;
|
||||
URL sealBase = null;
|
||||
|
||||
Attributes attr = man.getAttributes(path);
|
||||
Attributes attr = SharedSecrets.javaUtilJarAccess()
|
||||
.getTrustedAttributes(man, name.replace('.', '/').concat("/"));
|
||||
if (attr != null) {
|
||||
specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
|
||||
specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
|
||||
|
@ -585,10 +585,12 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
|||
/*
|
||||
* Returns true if the specified package name is sealed according to the
|
||||
* given manifest.
|
||||
*
|
||||
* @throws SecurityException if the package name is untrusted in the manifest
|
||||
*/
|
||||
private boolean isSealed(String name, Manifest man) {
|
||||
String path = name.replace('.', '/').concat("/");
|
||||
Attributes attr = man.getAttributes(path);
|
||||
Attributes attr = SharedSecrets.javaUtilJarAccess()
|
||||
.getTrustedAttributes(man, name.replace('.', '/').concat("/"));
|
||||
String sealed = null;
|
||||
if (attr != null) {
|
||||
sealed = attr.getValue(Name.SEALED);
|
||||
|
|
|
@ -417,10 +417,10 @@ class JarFile extends ZipFile {
|
|||
if (manEntry != null) {
|
||||
if (verify) {
|
||||
byte[] b = getBytes(manEntry);
|
||||
man = new Manifest(new ByteArrayInputStream(b), getName());
|
||||
if (!jvInitialized) {
|
||||
jv = new JarVerifier(b);
|
||||
}
|
||||
man = new Manifest(jv, new ByteArrayInputStream(b), getName());
|
||||
} else {
|
||||
man = new Manifest(super.getInputStream(manEntry), getName());
|
||||
}
|
||||
|
@ -1011,29 +1011,13 @@ class JarFile extends ZipFile {
|
|||
int i = match(MULTIRELEASE_CHARS, b, MULTIRELEASE_LASTOCC,
|
||||
MULTIRELEASE_OPTOSFT);
|
||||
if (i != -1) {
|
||||
i += MULTIRELEASE_CHARS.length;
|
||||
if (i < b.length) {
|
||||
byte c = b[i++];
|
||||
// Check that the value is followed by a newline
|
||||
// and does not have a continuation
|
||||
if (c == '\n' &&
|
||||
(i == b.length || b[i] != ' ')) {
|
||||
isMultiRelease = true;
|
||||
} else if (c == '\r') {
|
||||
if (i == b.length) {
|
||||
isMultiRelease = true;
|
||||
} else {
|
||||
c = b[i++];
|
||||
if (c == '\n') {
|
||||
if (i == b.length || b[i] != ' ') {
|
||||
isMultiRelease = true;
|
||||
}
|
||||
} else if (c != ' ') {
|
||||
isMultiRelease = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Read the main attributes of the manifest
|
||||
byte[] lbuf = new byte[512];
|
||||
Attributes attr = new Attributes();
|
||||
attr.read(new Manifest.FastInputStream(
|
||||
new ByteArrayInputStream(b)), lbuf);
|
||||
isMultiRelease = Boolean.parseBoolean(
|
||||
attr.getValue(Attributes.Name.MULTI_RELEASE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1041,7 +1025,7 @@ class JarFile extends ZipFile {
|
|||
}
|
||||
}
|
||||
|
||||
private synchronized void ensureInitialization() {
|
||||
synchronized void ensureInitialization() {
|
||||
try {
|
||||
maybeInstantiateVerifier();
|
||||
} catch (IOException e) {
|
||||
|
|
|
@ -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
|
||||
|
@ -866,4 +866,24 @@ class JarVerifier {
|
|||
static CodeSource getUnsignedCS(URL url) {
|
||||
return new VerifierCodeSource(null, url, (java.security.cert.Certificate[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the name is trusted. Used by
|
||||
* {@link Manifest#getTrustedAttributes(String)}.
|
||||
*/
|
||||
boolean isTrustedManifestEntry(String name) {
|
||||
// How many signers? MANIFEST.MF is always verified
|
||||
CodeSigner[] forMan = verifiedSigners.get(JarFile.MANIFEST_NAME);
|
||||
if (forMan == null) {
|
||||
return true;
|
||||
}
|
||||
// Check sigFileSigners first, because we are mainly dealing with
|
||||
// non-file entries which will stay in sigFileSigners forever.
|
||||
CodeSigner[] forName = sigFileSigners.get(name);
|
||||
if (forName == null) {
|
||||
forName = verifiedSigners.get(name);
|
||||
}
|
||||
// Returns trusted if all signers sign the entry
|
||||
return forName != null && forName.length == forMan.length;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
|
@ -60,4 +60,12 @@ class JavaUtilJarAccessImpl implements JavaUtilJarAccess {
|
|||
public List<Object> getManifestDigests(JarFile jar) {
|
||||
return jar.getManifestDigests();
|
||||
}
|
||||
|
||||
public Attributes getTrustedAttributes(Manifest man, String name) {
|
||||
return man.getTrustedAttributes(name);
|
||||
}
|
||||
|
||||
public void ensureInitialization(JarFile jar) {
|
||||
jar.ensureInitialization();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,10 +50,13 @@ import sun.security.util.SecurityProperties;
|
|||
public class Manifest implements Cloneable {
|
||||
|
||||
// manifest main attributes
|
||||
private Attributes attr = new Attributes();
|
||||
private final Attributes attr = new Attributes();
|
||||
|
||||
// manifest entries
|
||||
private Map<String, Attributes> entries = new HashMap<>();
|
||||
private final Map<String, Attributes> entries = new HashMap<>();
|
||||
|
||||
// associated JarVerifier, not null when called by JarFile::getManifest.
|
||||
private final JarVerifier jv;
|
||||
|
||||
// name of the corresponding jar archive if available.
|
||||
private final String jarFilename;
|
||||
|
@ -63,6 +66,7 @@ public class Manifest implements Cloneable {
|
|||
*/
|
||||
public Manifest() {
|
||||
jarFilename = null;
|
||||
jv = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,8 +76,7 @@ public class Manifest implements Cloneable {
|
|||
* @throws IOException if an I/O error has occurred
|
||||
*/
|
||||
public Manifest(InputStream is) throws IOException {
|
||||
this();
|
||||
read(is);
|
||||
this(null, is, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,8 +87,17 @@ public class Manifest implements Cloneable {
|
|||
* @throws IOException if an I/O error has occured
|
||||
*/
|
||||
Manifest(InputStream is, String jarFilename) throws IOException {
|
||||
this(null, is, jarFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Manifest from the specified input stream
|
||||
* and associates it with a JarVerifier.
|
||||
*/
|
||||
Manifest(JarVerifier jv, InputStream is, String jarFilename) throws IOException {
|
||||
read(is);
|
||||
this.jarFilename = jarFilename;
|
||||
this.jv = jv;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,9 +106,10 @@ public class Manifest implements Cloneable {
|
|||
* @param man the Manifest to copy
|
||||
*/
|
||||
public Manifest(Manifest man) {
|
||||
this();
|
||||
attr.putAll(man.getMainAttributes());
|
||||
entries.putAll(man.getEntries());
|
||||
jarFilename = null;
|
||||
jv = man.jv;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,6 +159,27 @@ public class Manifest implements Cloneable {
|
|||
return getEntries().get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Attributes for the specified entry name, if trusted.
|
||||
*
|
||||
* @param name entry name
|
||||
* @return returns the same result as {@link #getAttributes(String)}
|
||||
* @throws SecurityException if the associated jar is signed but this entry
|
||||
* has been modified after signing (i.e. the section in the manifest
|
||||
* does not exist in SF files of all signers).
|
||||
*/
|
||||
Attributes getTrustedAttributes(String name) {
|
||||
// Note: Before the verification of MANIFEST.MF/.SF/.RSA files is done,
|
||||
// jv.isTrustedManifestEntry() isn't able to detect MANIFEST.MF change.
|
||||
// Users of this method should call SharedSecrets.javaUtilJarAccess()
|
||||
// .ensureInitialization() first.
|
||||
Attributes result = getAttributes(name);
|
||||
if (result != null && jv != null && ! jv.isTrustedManifestEntry(name)) {
|
||||
throw new SecurityException("Untrusted manifest entry: " + name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the main Attributes as well as the entries in this Manifest.
|
||||
*/
|
||||
|
|
|
@ -50,6 +50,13 @@ import javax.crypto.IllegalBlockSizeException;
|
|||
* that are not thrown by its ancestor classes. In particular, the
|
||||
* <code>skip</code> method skips, and the <code>available</code>
|
||||
* method counts only data that have been processed by the encapsulated Cipher.
|
||||
* This class may catch BadPaddingException and other exceptions thrown by
|
||||
* failed integrity checks during decryption. These exceptions are not
|
||||
* re-thrown, so the client may not be informed that integrity checks
|
||||
* failed. Because of this behavior, this class may not be suitable
|
||||
* for use with decryption in an authenticated mode of operation (e.g. GCM).
|
||||
* Applications that require authenticated encryption can use the Cipher API
|
||||
* directly as an alternative to using this class.
|
||||
*
|
||||
* <p> It is crucial for a programmer using this class not to use
|
||||
* methods that are not defined or overridden in this class (such as a
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
|
@ -60,6 +60,7 @@ import java.util.jar.Attributes;
|
|||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.module.ModulePatcher.PatchedModuleReader;
|
||||
import jdk.internal.module.Resources;
|
||||
|
@ -862,7 +863,8 @@ public class BuiltinClassLoader
|
|||
* Manifest are used to get the package version and sealing information.
|
||||
*
|
||||
* @throws IllegalArgumentException if the package name duplicates an
|
||||
* existing package either in this class loader or one of its ancestors
|
||||
* existing package either in this class loader or one of its ancestors
|
||||
* @throws SecurityException if the package name is untrusted in the manifest
|
||||
*/
|
||||
private Package definePackage(String pn, Manifest man, URL url) {
|
||||
String specTitle = null;
|
||||
|
@ -875,7 +877,8 @@ public class BuiltinClassLoader
|
|||
URL sealBase = null;
|
||||
|
||||
if (man != null) {
|
||||
Attributes attr = man.getAttributes(pn.replace('.', '/').concat("/"));
|
||||
Attributes attr = SharedSecrets.javaUtilJarAccess()
|
||||
.getTrustedAttributes(man, pn.replace('.', '/').concat("/"));
|
||||
if (attr != null) {
|
||||
specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
|
||||
specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
|
||||
|
@ -921,10 +924,12 @@ public class BuiltinClassLoader
|
|||
/**
|
||||
* Returns {@code true} if the specified package name is sealed according to
|
||||
* the given manifest.
|
||||
*
|
||||
* @throws SecurityException if the package name is untrusted in the manifest
|
||||
*/
|
||||
private boolean isSealed(String pn, Manifest man) {
|
||||
String path = pn.replace('.', '/').concat("/");
|
||||
Attributes attr = man.getAttributes(path);
|
||||
Attributes attr = SharedSecrets.javaUtilJarAccess()
|
||||
.getTrustedAttributes(man, pn.replace('.', '/').concat("/"));
|
||||
String sealed = null;
|
||||
if (attr != null)
|
||||
sealed = attr.getValue(Attributes.Name.SEALED);
|
||||
|
|
|
@ -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
|
||||
|
@ -34,6 +34,7 @@ import java.io.InputStream;
|
|||
import java.net.HttpURLConnection;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
|
@ -88,6 +89,8 @@ public class URLClassPath {
|
|||
private static final boolean DEBUG;
|
||||
private static final boolean DISABLE_JAR_CHECKING;
|
||||
private static final boolean DISABLE_ACC_CHECKING;
|
||||
private static final boolean DISABLE_CP_URL_CHECK;
|
||||
private static final boolean DEBUG_CP_URL_CHECK;
|
||||
|
||||
static {
|
||||
Properties props = GetPropertyAction.privilegedGetProperties();
|
||||
|
@ -98,6 +101,12 @@ public class URLClassPath {
|
|||
|
||||
p = props.getProperty("jdk.net.URLClassPath.disableRestrictedPermissions");
|
||||
DISABLE_ACC_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
|
||||
|
||||
// This property will be removed in a later release
|
||||
p = props.getProperty("jdk.net.URLClassPath.disableClassPathURLCheck", "true");
|
||||
|
||||
DISABLE_CP_URL_CHECK = p != null ? p.equals("true") || p.isEmpty() : false;
|
||||
DEBUG_CP_URL_CHECK = "debug".equals(p);
|
||||
}
|
||||
|
||||
/* The original search path of URLs. */
|
||||
|
@ -857,8 +866,10 @@ public class URLClassPath {
|
|||
{ return jar.getInputStream(entry); }
|
||||
public int getContentLength()
|
||||
{ return (int)entry.getSize(); }
|
||||
public Manifest getManifest() throws IOException
|
||||
{ return jar.getManifest(); };
|
||||
public Manifest getManifest() throws IOException {
|
||||
SharedSecrets.javaUtilJarAccess().ensureInitialization(jar);
|
||||
return jar.getManifest();
|
||||
}
|
||||
public Certificate[] getCertificates()
|
||||
{ return entry.getCertificates(); };
|
||||
public CodeSigner[] getCodeSigners()
|
||||
|
@ -1081,11 +1092,51 @@ public class URLClassPath {
|
|||
int i = 0;
|
||||
while (st.hasMoreTokens()) {
|
||||
String path = st.nextToken();
|
||||
urls[i] = new URL(base, path);
|
||||
i++;
|
||||
URL url = DISABLE_CP_URL_CHECK ? new URL(base, path) : safeResolve(base, path);
|
||||
if (url != null) {
|
||||
urls[i] = url;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (i == 0) {
|
||||
urls = null;
|
||||
} else if (i != urls.length) {
|
||||
// Truncate nulls from end of array
|
||||
urls = Arrays.copyOf(urls, i);
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a URL for the given path resolved against the base URL, or
|
||||
* null if the resulting URL is invalid.
|
||||
*/
|
||||
static URL safeResolve(URL base, String path) {
|
||||
String child = path.replace(File.separatorChar, '/');
|
||||
try {
|
||||
if (!URI.create(child).isAbsolute()) {
|
||||
URL url = new URL(base, child);
|
||||
if (base.getProtocol().equalsIgnoreCase("file")) {
|
||||
return url;
|
||||
} else {
|
||||
String bp = base.getPath();
|
||||
String urlp = url.getPath();
|
||||
int pos = bp.lastIndexOf('/');
|
||||
if (pos == -1) {
|
||||
pos = bp.length() - 1;
|
||||
}
|
||||
if (urlp.regionMatches(0, bp, 0, pos + 1)
|
||||
&& urlp.indexOf("..", pos) == -1) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (MalformedURLException | IllegalArgumentException e) {}
|
||||
if (DEBUG_CP_URL_CHECK) {
|
||||
System.err.println("Class-Path entry: \"" + path + "\" ignored in JAR file " + base);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
|
@ -30,8 +30,10 @@ import java.net.URL;
|
|||
import java.security.CodeSource;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
public interface JavaUtilJarAccess {
|
||||
public boolean jarFileHasClassPathAttribute(JarFile jar) throws IOException;
|
||||
|
@ -41,4 +43,6 @@ public interface JavaUtilJarAccess {
|
|||
public Enumeration<JarEntry> entries2(JarFile jar);
|
||||
public void setEagerValidation(JarFile jar, boolean eager);
|
||||
public List<Object> getManifestDigests(JarFile jar);
|
||||
public Attributes getTrustedAttributes(Manifest man, String name);
|
||||
public void ensureInitialization(JarFile jar);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 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
|
||||
|
@ -2725,6 +2725,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
|||
// doesn't know about proxy.
|
||||
useProxyResponseCode = true;
|
||||
} else {
|
||||
final URL prevURL = url;
|
||||
|
||||
// maintain previous headers, just change the name
|
||||
// of the file we're getting
|
||||
url = locUrl;
|
||||
|
@ -2753,6 +2755,14 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
|||
poster = null;
|
||||
if (!checkReuseConnection())
|
||||
connect();
|
||||
|
||||
if (!sameDestination(prevURL, url)) {
|
||||
// Ensures pre-redirect user-set cookie will not be reset.
|
||||
// CookieHandler, if any, will be queried to determine
|
||||
// cookies for redirected URL, if any.
|
||||
userCookies = null;
|
||||
userCookies2 = null;
|
||||
}
|
||||
} else {
|
||||
if (!checkReuseConnection())
|
||||
connect();
|
||||
|
@ -2775,11 +2785,52 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
|||
}
|
||||
requests.set("Host", host);
|
||||
}
|
||||
|
||||
if (!sameDestination(prevURL, url)) {
|
||||
// Redirecting to a different destination will drop any
|
||||
// security-sensitive headers, regardless of whether
|
||||
// they are user-set or not. CookieHandler, if any, will be
|
||||
// queried to determine cookies for redirected URL, if any.
|
||||
userCookies = null;
|
||||
userCookies2 = null;
|
||||
requests.remove("Cookie");
|
||||
requests.remove("Cookie2");
|
||||
requests.remove("Authorization");
|
||||
|
||||
// check for preemptive authorization
|
||||
AuthenticationInfo sauth =
|
||||
AuthenticationInfo.getServerAuth(url, getAuthenticatorKey());
|
||||
if (sauth != null && sauth.supportsPreemptiveAuthorization() ) {
|
||||
// Sets "Authorization"
|
||||
requests.setIfNotSet(sauth.getHeaderName(), sauth.getHeaderValue(url,method));
|
||||
currentServerCredentials = sauth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true iff the given URLs have the same host and effective port. */
|
||||
private static boolean sameDestination(URL firstURL, URL secondURL) {
|
||||
assert firstURL.getProtocol().equalsIgnoreCase(secondURL.getProtocol()):
|
||||
"protocols not equal: " + firstURL + " - " + secondURL;
|
||||
|
||||
if (!firstURL.getHost().equalsIgnoreCase(secondURL.getHost()))
|
||||
return false;
|
||||
|
||||
int firstPort = firstURL.getPort();
|
||||
if (firstPort == -1)
|
||||
firstPort = firstURL.getDefaultPort();
|
||||
int secondPort = secondURL.getPort();
|
||||
if (secondPort == -1)
|
||||
secondPort = secondURL.getDefaultPort();
|
||||
if (firstPort != secondPort)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* dummy byte buffer for reading off socket prior to closing */
|
||||
byte[] cdata = new byte [128];
|
||||
|
||||
|
|
|
@ -243,18 +243,16 @@ final class CertSignAlgsExtension {
|
|||
}
|
||||
|
||||
// Produce the extension.
|
||||
if (shc.localSupportedSignAlgs == null) {
|
||||
shc.localSupportedSignAlgs =
|
||||
List<SignatureScheme> sigAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.algorithmConstraints, shc.activeProtocols);
|
||||
}
|
||||
shc.algorithmConstraints,
|
||||
List.of(shc.negotiatedProtocol));
|
||||
|
||||
int vectorLen = SignatureScheme.sizeInRecord() *
|
||||
shc.localSupportedSignAlgs.size();
|
||||
int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size();
|
||||
byte[] extData = new byte[vectorLen + 2];
|
||||
ByteBuffer m = ByteBuffer.wrap(extData);
|
||||
Record.putInt16(m, vectorLen);
|
||||
for (SignatureScheme ss : shc.localSupportedSignAlgs) {
|
||||
for (SignatureScheme ss : sigAlgs) {
|
||||
Record.putInt16(m, ss.id);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,9 @@ import java.security.PrivateKey;
|
|||
import java.security.cert.X509Certificate;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -675,45 +677,86 @@ final class CertificateRequest {
|
|||
chc.peerRequestedSignatureSchemes = sss;
|
||||
chc.peerRequestedCertSignSchemes = sss; // use the same schemes
|
||||
chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss);
|
||||
chc.peerSupportedAuthorities = crm.getAuthorities();
|
||||
|
||||
X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager();
|
||||
String clientAlias = null;
|
||||
if (chc.conContext.transport instanceof SSLSocketImpl) {
|
||||
clientAlias = km.chooseClientAlias(crm.getKeyTypes(),
|
||||
crm.getAuthorities(), (SSLSocket)chc.conContext.transport);
|
||||
} else if (chc.conContext.transport instanceof SSLEngineImpl) {
|
||||
clientAlias = km.chooseEngineClientAlias(crm.getKeyTypes(),
|
||||
crm.getAuthorities(), (SSLEngine)chc.conContext.transport);
|
||||
}
|
||||
|
||||
if (clientAlias == null) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.warning("No available client authentication");
|
||||
}
|
||||
// For TLS 1.2, we no longer use the certificate_types field
|
||||
// from the CertificateRequest message to directly determine
|
||||
// the SSLPossession. Instead, the choosePossession method
|
||||
// will use the accepted signature schemes in the message to
|
||||
// determine the set of acceptable certificate types to select from.
|
||||
SSLPossession pos = choosePossession(chc);
|
||||
if (pos == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PrivateKey clientPrivateKey = km.getPrivateKey(clientAlias);
|
||||
if (clientPrivateKey == null) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.warning("No available client private key");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
X509Certificate[] clientCerts = km.getCertificateChain(clientAlias);
|
||||
if ((clientCerts == null) || (clientCerts.length == 0)) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.warning("No available client certificate");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
chc.handshakePossessions.add(
|
||||
new X509Possession(clientPrivateKey, clientCerts));
|
||||
chc.handshakePossessions.add(pos);
|
||||
chc.handshakeProducers.put(SSLHandshake.CERTIFICATE_VERIFY.id,
|
||||
SSLHandshake.CERTIFICATE_VERIFY);
|
||||
}
|
||||
|
||||
private static SSLPossession choosePossession(HandshakeContext hc)
|
||||
throws IOException {
|
||||
if (hc.peerRequestedCertSignSchemes == null ||
|
||||
hc.peerRequestedCertSignSchemes.isEmpty()) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.warning("No signature and hash algorithms " +
|
||||
"in CertificateRequest");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Collection<String> checkedKeyTypes = new HashSet<>();
|
||||
for (SignatureScheme ss : hc.peerRequestedCertSignSchemes) {
|
||||
if (checkedKeyTypes.contains(ss.keyAlgorithm)) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.warning(
|
||||
"Unsupported authentication scheme: " + ss.name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't select a signature scheme unless we will be able to
|
||||
// produce a CertificateVerify message later
|
||||
if (SignatureScheme.getPreferableAlgorithm(
|
||||
hc.peerRequestedSignatureSchemes,
|
||||
ss, hc.negotiatedProtocol) == null) {
|
||||
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.warning(
|
||||
"Unable to produce CertificateVerify for " +
|
||||
"signature scheme: " + ss.name);
|
||||
}
|
||||
checkedKeyTypes.add(ss.keyAlgorithm);
|
||||
continue;
|
||||
}
|
||||
|
||||
SSLAuthentication ka = X509Authentication.valueOf(ss);
|
||||
if (ka == null) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.warning(
|
||||
"Unsupported authentication scheme: " + ss.name);
|
||||
}
|
||||
checkedKeyTypes.add(ss.keyAlgorithm);
|
||||
continue;
|
||||
}
|
||||
|
||||
SSLPossession pos = ka.createPossession(hc);
|
||||
if (pos == null) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.warning(
|
||||
"Unavailable authentication scheme: " + ss.name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.warning("No available authentication scheme");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.util.Collections;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
|
@ -510,6 +511,23 @@ final class ClientHello {
|
|||
}
|
||||
}
|
||||
|
||||
// ensure that the endpoint identification algorithm matches the
|
||||
// one in the session
|
||||
String identityAlg = chc.sslConfig.identificationProtocol;
|
||||
if (session != null && identityAlg != null) {
|
||||
String sessionIdentityAlg =
|
||||
session.getIdentificationProtocol();
|
||||
if (!Objects.equals(identityAlg, sessionIdentityAlg)) {
|
||||
if (SSLLogger.isOn &&
|
||||
SSLLogger.isOn("ssl,handshake,verbose")) {
|
||||
SSLLogger.finest("Can't resume, endpoint id" +
|
||||
" algorithm does not match, requested: " +
|
||||
identityAlg + ", cached: " + sessionIdentityAlg);
|
||||
}
|
||||
session = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (session != null) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) {
|
||||
SSLLogger.finest("Try resuming session", session);
|
||||
|
@ -1011,6 +1029,23 @@ final class ClientHello {
|
|||
}
|
||||
}
|
||||
|
||||
// ensure that the endpoint identification algorithm matches the
|
||||
// one in the session
|
||||
String identityAlg = shc.sslConfig.identificationProtocol;
|
||||
if (resumingSession && identityAlg != null) {
|
||||
String sessionIdentityAlg =
|
||||
previous.getIdentificationProtocol();
|
||||
if (!Objects.equals(identityAlg, sessionIdentityAlg)) {
|
||||
if (SSLLogger.isOn &&
|
||||
SSLLogger.isOn("ssl,handshake,verbose")) {
|
||||
SSLLogger.finest("Can't resume, endpoint id" +
|
||||
" algorithm does not match, requested: " +
|
||||
identityAlg + ", cached: " + sessionIdentityAlg);
|
||||
}
|
||||
resumingSession = false;
|
||||
}
|
||||
}
|
||||
|
||||
// So far so good. Note that the handshake extensions may reset
|
||||
// the resuming options later.
|
||||
shc.isResumption = resumingSession;
|
||||
|
|
|
@ -43,6 +43,7 @@ import java.util.Queue;
|
|||
import javax.crypto.SecretKey;
|
||||
import javax.net.ssl.SNIServerName;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
|
||||
import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
|
||||
import static sun.security.ssl.SupportedGroupsExtension.NamedGroupType.*;
|
||||
|
@ -136,6 +137,9 @@ abstract class HandshakeContext implements ConnectionContext {
|
|||
List<SignatureScheme> peerRequestedSignatureSchemes;
|
||||
List<SignatureScheme> peerRequestedCertSignSchemes;
|
||||
|
||||
// Known authorities
|
||||
X500Principal[] peerSupportedAuthorities = null;
|
||||
|
||||
// SupportedGroups
|
||||
List<NamedGroup> clientRequestedNamedGroups;
|
||||
|
||||
|
|
|
@ -50,6 +50,9 @@ final class PostHandshakeContext extends HandshakeContext {
|
|||
this.localSupportedSignAlgs = new ArrayList<SignatureScheme>(
|
||||
context.conSession.getLocalSupportedSignatureSchemes());
|
||||
|
||||
this.requestedServerNames =
|
||||
context.conSession.getRequestedServerNames();
|
||||
|
||||
handshakeConsumers = new LinkedHashMap<>(consumers);
|
||||
handshakeFinished = true;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.List;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Collection;
|
||||
import javax.crypto.Mac;
|
||||
|
@ -170,7 +171,7 @@ final class PreSharedKeyExtension {
|
|||
|
||||
int getIdsEncodedLength() {
|
||||
int idEncodedLength = 0;
|
||||
for (PskIdentity curId : identities) {
|
||||
for(PskIdentity curId : identities) {
|
||||
idEncodedLength += curId.getEncodedLength();
|
||||
}
|
||||
|
||||
|
@ -193,7 +194,7 @@ final class PreSharedKeyExtension {
|
|||
byte[] buffer = new byte[encodedLength];
|
||||
ByteBuffer m = ByteBuffer.wrap(buffer);
|
||||
Record.putInt16(m, idsEncodedLength);
|
||||
for (PskIdentity curId : identities) {
|
||||
for(PskIdentity curId : identities) {
|
||||
curId.writeEncoded(m);
|
||||
}
|
||||
Record.putInt16(m, bindersEncodedLength);
|
||||
|
@ -443,6 +444,23 @@ final class PreSharedKeyExtension {
|
|||
}
|
||||
}
|
||||
|
||||
// ensure that the endpoint identification algorithm matches the
|
||||
// one in the session
|
||||
String identityAlg = shc.sslConfig.identificationProtocol;
|
||||
if (result && identityAlg != null) {
|
||||
String sessionIdentityAlg = s.getIdentificationProtocol();
|
||||
if (!Objects.equals(identityAlg, sessionIdentityAlg)) {
|
||||
if (SSLLogger.isOn &&
|
||||
SSLLogger.isOn("ssl,handshake,verbose")) {
|
||||
|
||||
SSLLogger.finest("Can't resume, endpoint id" +
|
||||
" algorithm does not match, requested: " +
|
||||
identityAlg + ", cached: " + sessionIdentityAlg);
|
||||
}
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure cipher suite can be negotiated
|
||||
if (result && (!shc.isNegotiable(s.getSuite()) ||
|
||||
!clientHello.cipherSuites.contains(s.getSuite()))) {
|
||||
|
|
|
@ -132,6 +132,10 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||
// Counter used to create unique nonces in NewSessionTicket
|
||||
private BigInteger ticketNonceCounter = BigInteger.ONE;
|
||||
|
||||
// The endpoint identification algorithm used to check certificates
|
||||
// in this session.
|
||||
private final String identificationProtocol;
|
||||
|
||||
/*
|
||||
* Create a new non-rejoinable session, using the default (null)
|
||||
* cipher spec. This constructor returns a session which could
|
||||
|
@ -149,6 +153,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||
this.requestedServerNames = Collections.<SNIServerName>emptyList();
|
||||
this.useExtendedMasterSecret = false;
|
||||
this.creationTime = System.currentTimeMillis();
|
||||
this.identificationProtocol = null;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -198,6 +203,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||
(!hc.negotiatedProtocol.useTLS13PlusSpec());
|
||||
}
|
||||
this.creationTime = creationTime;
|
||||
this.identificationProtocol = hc.sslConfig.identificationProtocol;
|
||||
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("session")) {
|
||||
SSLLogger.finest("Session initialized: " + this);
|
||||
|
@ -259,6 +265,10 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||
return ticketAgeAdd;
|
||||
}
|
||||
|
||||
String getIdentificationProtocol() {
|
||||
return this.identificationProtocol;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the PSK identity. Take care not to use it in multiple connections.
|
||||
*/
|
||||
|
|
|
@ -410,18 +410,16 @@ final class SignatureAlgorithmsExtension {
|
|||
}
|
||||
|
||||
// Produce the extension.
|
||||
if (shc.localSupportedSignAlgs == null) {
|
||||
shc.localSupportedSignAlgs =
|
||||
List<SignatureScheme> sigAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.algorithmConstraints, shc.activeProtocols);
|
||||
}
|
||||
shc.algorithmConstraints,
|
||||
List.of(shc.negotiatedProtocol));
|
||||
|
||||
int vectorLen = SignatureScheme.sizeInRecord() *
|
||||
shc.localSupportedSignAlgs.size();
|
||||
int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size();
|
||||
byte[] extData = new byte[vectorLen + 2];
|
||||
ByteBuffer m = ByteBuffer.wrap(extData);
|
||||
Record.putInt16(m, vectorLen);
|
||||
for (SignatureScheme ss : shc.localSupportedSignAlgs) {
|
||||
for (SignatureScheme ss : sigAlgs) {
|
||||
Record.putInt16(m, ss.id);
|
||||
}
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ enum X509Authentication implements SSLAuthentication {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Used by TLS 1.3 only.
|
||||
// Used by TLS 1.2 and TLS 1.3.
|
||||
private SSLPossession createClientPossession(
|
||||
ClientHandshakeContext chc, String keyType) {
|
||||
X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager();
|
||||
|
@ -178,11 +178,13 @@ enum X509Authentication implements SSLAuthentication {
|
|||
if (chc.conContext.transport instanceof SSLSocketImpl) {
|
||||
clientAlias = km.chooseClientAlias(
|
||||
new String[] { keyType },
|
||||
null, (SSLSocket)chc.conContext.transport);
|
||||
chc.peerSupportedAuthorities,
|
||||
(SSLSocket)chc.conContext.transport);
|
||||
} else if (chc.conContext.transport instanceof SSLEngineImpl) {
|
||||
clientAlias = km.chooseEngineClientAlias(
|
||||
new String[] { keyType },
|
||||
null, (SSLEngine)chc.conContext.transport);
|
||||
chc.peerSupportedAuthorities,
|
||||
(SSLEngine)chc.conContext.transport);
|
||||
}
|
||||
|
||||
if (clientAlias == null) {
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2016, 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
|
||||
|
@ -1871,6 +1871,20 @@ struct JNIEnv_ {
|
|||
#endif /* __cplusplus */
|
||||
};
|
||||
|
||||
/*
|
||||
* optionString may be any option accepted by the JVM, or one of the
|
||||
* following:
|
||||
*
|
||||
* -D<name>=<value> Set a system property.
|
||||
* -verbose[:class|gc|jni] Enable verbose output, comma-separated. E.g.
|
||||
* "-verbose:class" or "-verbose:gc,class"
|
||||
* Standard names include: gc, class, and jni.
|
||||
* All nonstandard (VM-specific) names must begin
|
||||
* with "X".
|
||||
* vfprintf extraInfo is a pointer to the vfprintf hook.
|
||||
* exit extraInfo is a pointer to the exit hook.
|
||||
* abort extraInfo is a pointer to the abort hook.
|
||||
*/
|
||||
typedef struct JavaVMOption {
|
||||
char *optionString;
|
||||
void *extraInfo;
|
||||
|
|
|
@ -331,9 +331,16 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
|
|||
netif *ifs, *curr;
|
||||
jobject obj = NULL;
|
||||
jboolean match = JNI_FALSE;
|
||||
int family = (getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4) ?
|
||||
AF_INET : AF_INET6;
|
||||
int family = getInetAddress_family(env, iaObj);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
|
||||
if (family == java_net_InetAddress_IPv4) {
|
||||
family = AF_INET;
|
||||
} else if (family == java_net_InetAddress_IPv6) {
|
||||
family = AF_INET6;
|
||||
} else {
|
||||
return NULL; // Invalid family
|
||||
}
|
||||
ifs = enumInterfaces(env);
|
||||
if (ifs == NULL) {
|
||||
return NULL;
|
||||
|
@ -351,7 +358,9 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
|
|||
int address1 = htonl(
|
||||
((struct sockaddr_in *)addrP->addr)->sin_addr.s_addr);
|
||||
int address2 = getInetAddress_addr(env, iaObj);
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (address1 == address2) {
|
||||
match = JNI_TRUE;
|
||||
break;
|
||||
|
@ -397,6 +406,7 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
|
|||
obj = createNetworkInterface(env, curr);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
// release the interface list
|
||||
freeif(ifs);
|
||||
|
||||
|
|
|
@ -280,6 +280,7 @@ int enumInterfaces(JNIEnv *env, netif **netifPP)
|
|||
if (curr->name == NULL || curr->displayName == NULL) {
|
||||
if (curr->name) free(curr->name);
|
||||
if (curr->displayName) free(curr->displayName);
|
||||
free(curr);
|
||||
curr = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -586,7 +587,10 @@ jobject createNetworkInterface
|
|||
/* default ctor will set family to AF_INET */
|
||||
|
||||
setInetAddress_addr(env, iaObj, ntohl(addrs->addr.sa4.sin_addr.s_addr));
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
free_netaddr(netaddrP);
|
||||
return NULL;
|
||||
}
|
||||
if (addrs->mask != -1) {
|
||||
ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
|
||||
if (ibObj == NULL) {
|
||||
|
@ -600,7 +604,10 @@ jobject createNetworkInterface
|
|||
return NULL;
|
||||
}
|
||||
setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.sa4.sin_addr.s_addr));
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
free_netaddr(netaddrP);
|
||||
return NULL;
|
||||
}
|
||||
(*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj);
|
||||
(*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
|
||||
(*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
|
||||
|
@ -611,6 +618,7 @@ jobject createNetworkInterface
|
|||
if (iaObj) {
|
||||
jboolean ret = setInet6Address_ipaddress(env, iaObj, (jbyte *)&(addrs->addr.sa6.sin6_addr.s6_addr));
|
||||
if (ret == JNI_FALSE) {
|
||||
free_netaddr(netaddrP);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -521,8 +521,9 @@ static jobject createNetworkInterfaceXP(JNIEnv *env, netif *ifs)
|
|||
jobjectArray addrArr, bindsArr, childArr;
|
||||
netaddr *addrs;
|
||||
jint addr_index;
|
||||
int netaddrCount=ifs->naddrs;
|
||||
netaddr *netaddrP=ifs->addrs;
|
||||
int netaddrCount = ifs->naddrs;
|
||||
netaddr *netaddrP = ifs->addrs;
|
||||
netaddr *netaddrPToFree = NULL;
|
||||
jint bind_index;
|
||||
|
||||
/*
|
||||
|
@ -553,21 +554,23 @@ static jobject createNetworkInterfaceXP(JNIEnv *env, netif *ifs)
|
|||
* Note that 0 is a valid number of addresses.
|
||||
*/
|
||||
if (netaddrCount < 0) {
|
||||
netaddrCount = enumAddresses_win(env, ifs, &netaddrP);
|
||||
netaddrCount = enumAddresses_win(env, ifs, &netaddrPToFree);
|
||||
if (netaddrCount == -1) {
|
||||
return NULL;
|
||||
}
|
||||
netaddrP = netaddrPToFree;
|
||||
}
|
||||
|
||||
addrArr = (*env)->NewObjectArray(env, netaddrCount, ia_class, NULL);
|
||||
if (addrArr == NULL) {
|
||||
free_netaddr(netaddrPToFree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bindsArr = (*env)->NewObjectArray(env, netaddrCount, ni_ibcls, NULL);
|
||||
if (bindsArr == NULL) {
|
||||
free_netaddr(netaddrP);
|
||||
return NULL;
|
||||
free_netaddr(netaddrPToFree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addrs = netaddrP;
|
||||
|
@ -579,25 +582,32 @@ static jobject createNetworkInterfaceXP(JNIEnv *env, netif *ifs)
|
|||
if (addrs->addr.sa.sa_family == AF_INET) {
|
||||
iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
|
||||
if (iaObj == NULL) {
|
||||
free_netaddr(netaddrPToFree);
|
||||
return NULL;
|
||||
}
|
||||
/* default ctor will set family to AF_INET */
|
||||
|
||||
setInetAddress_addr(env, iaObj, ntohl(addrs->addr.sa4.sin_addr.s_addr));
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
free_netaddr(netaddrPToFree);
|
||||
return NULL;
|
||||
}
|
||||
ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
|
||||
if (ibObj == NULL) {
|
||||
free_netaddr(netaddrP);
|
||||
return NULL;
|
||||
free_netaddr(netaddrPToFree);
|
||||
return NULL;
|
||||
}
|
||||
(*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
|
||||
ia2Obj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
|
||||
if (ia2Obj == NULL) {
|
||||
free_netaddr(netaddrP);
|
||||
return NULL;
|
||||
free_netaddr(netaddrPToFree);
|
||||
return NULL;
|
||||
}
|
||||
setInetAddress_addr(env, ia2Obj, ntohl(addrs->brdcast.sa4.sin_addr.s_addr));
|
||||
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
free_netaddr(netaddrPToFree);
|
||||
return NULL;
|
||||
}
|
||||
(*env)->SetObjectField(env, ibObj, ni_ibbroadcastID, ia2Obj);
|
||||
(*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
|
||||
(*env)->SetObjectArrayElement(env, bindsArr, bind_index++, ibObj);
|
||||
|
@ -606,10 +616,12 @@ static jobject createNetworkInterfaceXP(JNIEnv *env, netif *ifs)
|
|||
jboolean ret;
|
||||
iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
|
||||
if (iaObj == NULL) {
|
||||
free_netaddr(netaddrPToFree);
|
||||
return NULL;
|
||||
}
|
||||
ret = setInet6Address_ipaddress(env, iaObj, (jbyte *)&(addrs->addr.sa6.sin6_addr.s6_addr));
|
||||
if (ret == JNI_FALSE) {
|
||||
free_netaddr(netaddrPToFree);
|
||||
return NULL;
|
||||
}
|
||||
scope = addrs->addr.sa6.sin6_scope_id;
|
||||
|
@ -619,8 +631,8 @@ static jobject createNetworkInterfaceXP(JNIEnv *env, netif *ifs)
|
|||
}
|
||||
ibObj = (*env)->NewObject(env, ni_ibcls, ni_ibctrID);
|
||||
if (ibObj == NULL) {
|
||||
free_netaddr(netaddrP);
|
||||
return NULL;
|
||||
free_netaddr(netaddrPToFree);
|
||||
return NULL;
|
||||
}
|
||||
(*env)->SetObjectField(env, ibObj, ni_ibaddressID, iaObj);
|
||||
(*env)->SetShortField(env, ibObj, ni_ibmaskID, addrs->mask);
|
||||
|
@ -633,6 +645,8 @@ static jobject createNetworkInterfaceXP(JNIEnv *env, netif *ifs)
|
|||
(*env)->SetObjectField(env, netifObj, ni_addrsID, addrArr);
|
||||
(*env)->SetObjectField(env, netifObj, ni_bindsID, bindsArr);
|
||||
|
||||
free_netaddr(netaddrPToFree);
|
||||
|
||||
/*
|
||||
* Windows doesn't have virtual interfaces, so child array
|
||||
* is always empty.
|
||||
|
@ -672,7 +686,7 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0_XP
|
|||
}
|
||||
|
||||
/* if found create a NetworkInterface */
|
||||
if (curr != NULL) {;
|
||||
if (curr != NULL) {
|
||||
netifObj = createNetworkInterfaceXP(env, curr);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue