Merge
This commit is contained in:
commit
d40735db17
11
.hgtags
11
.hgtags
@ -496,15 +496,16 @@ e1b3def126240d5433902f3cb0e91a4c27f6db50 jdk-11+18
|
||||
14708e1acdc3974f4539027cbbcfa6d69f83cf51 jdk-11+21
|
||||
00b16d0457e43d23f6ca5ade6b243edce62750a0 jdk-12+1
|
||||
9937ef7499dcd7673714517fd5e450410c14ba4e jdk-11+22
|
||||
1edcf36fe15f79d6228d1a63eb680878e2386480 jdk-11+23
|
||||
ea900a7dc7d77dee30865c60eabd87fc24b1037c jdk-11+24
|
||||
331888ea4a788df801b1edf8836646cd25fc758b jdk-11+25
|
||||
945ba9278a272a5477ffb1b3ea1b04174fed8036 jdk-11+26
|
||||
9d7d74c6f2cbe522e39fa22dc557fdd3f79b32ad jdk-11+27
|
||||
69b438908512d3dfef5852c6a843a5778333a309 jdk-12+2
|
||||
1edcf36fe15f79d6228d1a63eb680878e2386480 jdk-11+23
|
||||
990db216e7199b2ba9989d8fa20b657e0ca7d969 jdk-12+3
|
||||
ea900a7dc7d77dee30865c60eabd87fc24b1037c jdk-11+24
|
||||
499b873761d8e8a1cc4aa649daf04cbe98cbce77 jdk-12+4
|
||||
331888ea4a788df801b1edf8836646cd25fc758b jdk-11+25
|
||||
f8696e0ab9b795030429fc3374ec03e378fd9ed7 jdk-12+5
|
||||
945ba9278a272a5477ffb1b3ea1b04174fed8036 jdk-11+26
|
||||
7939b3c4e4088bf4f70ec5bbd8030393b653372f jdk-12+6
|
||||
9d7d74c6f2cbe522e39fa22dc557fdd3f79b32ad jdk-11+27
|
||||
ef57958c7c511162da8d9a75f0b977f0f7ac464e jdk-12+7
|
||||
76072a077ee1d815152d45d1692c4b36c53c5c49 jdk-11+28
|
||||
492b366f8e5784cc4927c2c98f9b8a3f16c067eb jdk-12+8
|
||||
|
@ -61,7 +61,7 @@ MODULES_SOURCE_PATH := $(call PathList, $(call GetModuleSrcPath) \
|
||||
$(SUPPORT_OUTPUTDIR)/rmic/* $(TOPDIR)/src/*/share/doc/stub)
|
||||
|
||||
# URLs
|
||||
JAVADOC_BASE_URL := http://www.oracle.com/pls/topic/lookup?ctx=javase10&id=homepage
|
||||
JAVADOC_BASE_URL := http://www.oracle.com/pls/topic/lookup?ctx=javase$(VERSION_NUMBER)&id=homepage
|
||||
BUG_SUBMIT_URL := http://bugreport.java.com/bugreport/
|
||||
COPYRIGHT_URL := {@docroot}/../legal/copyright.html
|
||||
LICENSE_URL := http://www.oracle.com/technetwork/java/javase/terms/license/java$(VERSION_NUMBER)speclicense.html
|
||||
|
@ -1107,7 +1107,7 @@ static void restore_args(MacroAssembler *masm, int arg_count, int first_arg, VMR
|
||||
}
|
||||
}
|
||||
__ pop(x, sp);
|
||||
for ( int i = first_arg ; i < arg_count ; i++ ) {
|
||||
for ( int i = arg_count - 1 ; i >= first_arg ; i-- ) {
|
||||
if (args[i].first()->is_Register()) {
|
||||
;
|
||||
} else if (args[i].first()->is_FloatRegister()) {
|
||||
|
@ -1681,7 +1681,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
__ z_lg(Z_R1/*active_handles*/, thread_(active_handles));
|
||||
__ clear_mem(Address(Z_R1, JNIHandleBlock::top_offset_in_bytes()), 4);
|
||||
|
||||
// Bandle exceptions (exception handling will handle unlocking!).
|
||||
// Handle exceptions (exception handling will handle unlocking!).
|
||||
{
|
||||
Label L;
|
||||
__ load_and_test_long(Z_R0/*pending_exception*/, thread_(pending_exception));
|
||||
@ -1710,17 +1710,9 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
__ notify_method_exit(true/*native_method*/, ilgl, InterpreterMacroAssembler::NotifyJVMTI);
|
||||
|
||||
// Move native method result back into proper registers and return.
|
||||
// C++ interpreter does not use result handler. So do we need to here? TODO(ZASM): check if correct.
|
||||
{ NearLabel no_oop_or_null;
|
||||
__ mem2freg_opt(Z_FRET, Address(Z_fp, _z_ijava_state_neg(fresult)));
|
||||
__ load_and_test_long(Z_RET, Address(Z_fp, _z_ijava_state_neg(lresult)));
|
||||
__ z_bre(no_oop_or_null); // No unboxing if the result is NULL.
|
||||
__ load_absolute_address(Z_R1, AbstractInterpreter::result_handler(T_OBJECT));
|
||||
__ compareU64_and_branch(Z_R1, Rresult_handler, Assembler::bcondNotEqual, no_oop_or_null);
|
||||
__ z_lg(Z_RET, oop_tmp_offset, Z_fp);
|
||||
__ verify_oop(Z_RET);
|
||||
__ bind(no_oop_or_null);
|
||||
}
|
||||
__ mem2reg_opt(Z_RET, Address(Z_fp, _z_ijava_state_neg(lresult)));
|
||||
__ call_stub(Rresult_handler);
|
||||
|
||||
// Pop the native method's interpreter frame.
|
||||
__ pop_interpreter_frame(Z_R14 /*return_pc*/, Z_ARG2/*tmp1*/, Z_ARG3/*tmp2*/);
|
||||
|
@ -119,7 +119,7 @@ define_pd_global(bool, ThreadLocalHandshakes, false);
|
||||
product(bool, UseStoreImmI16, true, \
|
||||
"Use store immediate 16-bits value instruction on x86") \
|
||||
\
|
||||
product(intx, UseAVX, 3, \
|
||||
product(intx, UseAVX, 2, \
|
||||
"Highest supported AVX instructions set on x86/x64") \
|
||||
range(0, 99) \
|
||||
\
|
||||
|
@ -1637,6 +1637,12 @@ bool CompileBroker::init_compiler_runtime() {
|
||||
* out to be a problem.
|
||||
*/
|
||||
void CompileBroker::shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread) {
|
||||
// Free buffer blob, if allocated
|
||||
if (thread->get_buffer_blob() != NULL) {
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
CodeCache::free(thread->get_buffer_blob());
|
||||
}
|
||||
|
||||
if (comp->should_perform_shutdown()) {
|
||||
// There are two reasons for shutting down the compiler
|
||||
// 1) compiler runtime initialization failed
|
||||
@ -1767,6 +1773,11 @@ void CompileBroker::compiler_thread_loop() {
|
||||
tty->print_cr("Removing compiler thread %s after " JLONG_FORMAT " ms idle time",
|
||||
thread->name(), thread->idle_time_millis());
|
||||
}
|
||||
// Free buffer blob, if allocated
|
||||
if (thread->get_buffer_blob() != NULL) {
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
CodeCache::free(thread->get_buffer_blob());
|
||||
}
|
||||
return; // Stop this thread.
|
||||
}
|
||||
}
|
||||
|
@ -3340,11 +3340,6 @@ CompilerThread::CompilerThread(CompileQueue* queue,
|
||||
}
|
||||
|
||||
CompilerThread::~CompilerThread() {
|
||||
// Free buffer blob, if allocated
|
||||
if (get_buffer_blob() != NULL) {
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
CodeCache::free(get_buffer_blob());
|
||||
}
|
||||
// Delete objects which were allocated on heap.
|
||||
delete _counters;
|
||||
}
|
||||
|
@ -191,12 +191,12 @@ final class CertSignAlgsExtension {
|
||||
}
|
||||
|
||||
// update the context
|
||||
List<SignatureScheme> shemes =
|
||||
List<SignatureScheme> schemes =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.algorithmConstraints, shc.negotiatedProtocol,
|
||||
spec.signatureSchemes);
|
||||
shc.peerRequestedCertSignSchemes = shemes;
|
||||
shc.handshakeSession.setPeerSupportedSignatureAlgorithms(shemes);
|
||||
shc.peerRequestedCertSignSchemes = schemes;
|
||||
shc.handshakeSession.setPeerSupportedSignatureAlgorithms(schemes);
|
||||
|
||||
if (!shc.isResumption && shc.negotiatedProtocol.useTLS13PlusSpec()) {
|
||||
if (shc.sslConfig.clientAuthType !=
|
||||
@ -337,12 +337,12 @@ final class CertSignAlgsExtension {
|
||||
}
|
||||
|
||||
// update the context
|
||||
List<SignatureScheme> shemes =
|
||||
List<SignatureScheme> schemes =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
chc.algorithmConstraints, chc.negotiatedProtocol,
|
||||
spec.signatureSchemes);
|
||||
chc.peerRequestedCertSignSchemes = shemes;
|
||||
chc.handshakeSession.setPeerSupportedSignatureAlgorithms(shemes);
|
||||
chc.peerRequestedCertSignSchemes = schemes;
|
||||
chc.handshakeSession.setPeerSupportedSignatureAlgorithms(schemes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1031,8 +1031,8 @@ final class CertificateMessage {
|
||||
// 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) {
|
||||
hc.peerRequestedSignatureSchemes,
|
||||
ss, hc.negotiatedProtocol) == null) {
|
||||
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.warning(
|
||||
|
@ -50,7 +50,7 @@ public class HandshakeOutStream extends ByteArrayOutputStream {
|
||||
this.outputRecord = outputRecord;
|
||||
}
|
||||
|
||||
// Complete a handshakin message writing. Called by HandshakeMessage.
|
||||
// Complete a handshaking message write. Called by HandshakeMessage.
|
||||
void complete() throws IOException {
|
||||
if (size() < 4) { // 4: handshake message header size
|
||||
// internal_error alert will be triggered
|
||||
|
@ -379,10 +379,10 @@ enum SSLCipher {
|
||||
private final Map.Entry<WriteCipherGenerator,
|
||||
ProtocolVersion[]>[] writeCipherGenerators;
|
||||
|
||||
// Map of Ciphers listed in jdk.tls.KeyLimit
|
||||
// Map of Ciphers listed in jdk.tls.keyLimits
|
||||
private static final HashMap<String, Long> cipherLimits = new HashMap<>();
|
||||
|
||||
// Keywords found on the jdk.tls.KeyLimit security property.
|
||||
// Keywords found on the jdk.tls.keyLimits security property.
|
||||
final static String tag[] = {"KEYUPDATE"};
|
||||
|
||||
static {
|
||||
@ -407,7 +407,7 @@ enum SSLCipher {
|
||||
index = 0;
|
||||
} else {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||
SSLLogger.fine("jdk.net.keyLimits: Unknown action: " +
|
||||
SSLLogger.fine("jdk.tls.keyLimits: Unknown action: " +
|
||||
entry);
|
||||
}
|
||||
continue;
|
||||
@ -423,17 +423,18 @@ enum SSLCipher {
|
||||
size = Long.parseLong(values[2]);
|
||||
}
|
||||
if (size < 1 || size > max) {
|
||||
throw new NumberFormatException("Length exceeded limits");
|
||||
throw new NumberFormatException(
|
||||
"Length exceeded limits");
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||
SSLLogger.fine("jdk.net.keyLimits: " + e.getMessage() +
|
||||
SSLLogger.fine("jdk.tls.keyLimits: " + e.getMessage() +
|
||||
": " + entry);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||
SSLLogger.fine("jdk.net.keyLimits: entry = " + entry +
|
||||
SSLLogger.fine("jdk.tls.keyLimits: entry = " + entry +
|
||||
". " + values[0] + ":" + tag[index] + " = " + size);
|
||||
}
|
||||
cipherLimits.put(values[0] + ":" + tag[index], size);
|
||||
|
@ -127,9 +127,7 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
||||
}
|
||||
|
||||
// See if the handshaker needs to report back some SSLException.
|
||||
if (conContext.outputRecord.isEmpty()) {
|
||||
checkTaskThrown();
|
||||
} // Otherwise, deliver cached records before throwing task exception.
|
||||
checkTaskThrown();
|
||||
|
||||
// check parameters
|
||||
checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
|
||||
@ -896,18 +894,58 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Depending on whether the error was just a warning and the
|
||||
* handshaker wasn't closed, or fatal and the handshaker is now
|
||||
* null, report back the Exception that happened in the delegated
|
||||
* task(s).
|
||||
*/
|
||||
private synchronized void checkTaskThrown() throws SSLException {
|
||||
|
||||
Exception exc = null;
|
||||
|
||||
// First check the handshake context.
|
||||
HandshakeContext hc = conContext.handshakeContext;
|
||||
if (hc != null && hc.delegatedThrown != null) {
|
||||
try {
|
||||
throw getTaskThrown(hc.delegatedThrown);
|
||||
} finally {
|
||||
hc.delegatedThrown = null;
|
||||
if ((hc != null) && (hc.delegatedThrown != null)) {
|
||||
exc = hc.delegatedThrown;
|
||||
hc.delegatedThrown = null;
|
||||
}
|
||||
|
||||
/*
|
||||
* hc.delegatedThrown and conContext.delegatedThrown are most likely
|
||||
* the same, but it's possible we could have had a non-fatal
|
||||
* exception and thus the new HandshakeContext is still valid
|
||||
* (alert warning). If so, then we may have a secondary exception
|
||||
* waiting to be reported from the TransportContext, so we will
|
||||
* need to clear that on a successive call. Otherwise, clear it now.
|
||||
*/
|
||||
if (conContext.delegatedThrown != null) {
|
||||
if (exc != null) {
|
||||
// hc object comparison
|
||||
if (conContext.delegatedThrown == exc) {
|
||||
// clear if/only if both are the same
|
||||
conContext.delegatedThrown = null;
|
||||
} // otherwise report the hc delegatedThrown
|
||||
} else {
|
||||
// Nothing waiting in HandshakeContext, but one is in the
|
||||
// TransportContext.
|
||||
exc = conContext.delegatedThrown;
|
||||
conContext.delegatedThrown = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (conContext.isBroken && conContext.closeReason != null) {
|
||||
throw getTaskThrown(conContext.closeReason);
|
||||
// Anything to report?
|
||||
if (exc == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If it wasn't a RuntimeException/SSLException, need to wrap it.
|
||||
if (exc instanceof SSLException) {
|
||||
throw (SSLException)exc;
|
||||
} else if (exc instanceof RuntimeException) {
|
||||
throw (RuntimeException)exc;
|
||||
} else {
|
||||
throw getTaskThrown(exc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -963,20 +1001,41 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
||||
} catch (PrivilegedActionException pae) {
|
||||
// Get the handshake context again in case the
|
||||
// handshaking has completed.
|
||||
Exception reportedException = pae.getException();
|
||||
|
||||
// Report to both the TransportContext...
|
||||
if (engine.conContext.delegatedThrown == null) {
|
||||
engine.conContext.delegatedThrown = reportedException;
|
||||
}
|
||||
|
||||
// ...and the HandshakeContext in case condition
|
||||
// wasn't fatal and the handshakeContext is still
|
||||
// around.
|
||||
hc = engine.conContext.handshakeContext;
|
||||
if (hc != null) {
|
||||
hc.delegatedThrown = pae.getException();
|
||||
hc.delegatedThrown = reportedException;
|
||||
} else if (engine.conContext.closeReason != null) {
|
||||
// Update the reason in case there was a previous.
|
||||
engine.conContext.closeReason =
|
||||
getTaskThrown(pae.getException());
|
||||
getTaskThrown(reportedException);
|
||||
}
|
||||
} catch (RuntimeException rte) {
|
||||
// Get the handshake context again in case the
|
||||
// handshaking has completed.
|
||||
|
||||
// Report to both the TransportContext...
|
||||
if (engine.conContext.delegatedThrown == null) {
|
||||
engine.conContext.delegatedThrown = rte;
|
||||
}
|
||||
|
||||
// ...and the HandshakeContext in case condition
|
||||
// wasn't fatal and the handshakeContext is still
|
||||
// around.
|
||||
hc = engine.conContext.handshakeContext;
|
||||
if (hc != null) {
|
||||
hc.delegatedThrown = rte;
|
||||
} else if (engine.conContext.closeReason != null) {
|
||||
// Update the reason in case there was a previous.
|
||||
engine.conContext.closeReason = rte;
|
||||
}
|
||||
}
|
||||
@ -1000,13 +1059,6 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
||||
@Override
|
||||
public Void run() throws Exception {
|
||||
while (!context.delegatedActions.isEmpty()) {
|
||||
// Report back the task SSLException
|
||||
if (context.delegatedThrown != null) {
|
||||
Exception delegatedThrown = context.delegatedThrown;
|
||||
context.delegatedThrown = null;
|
||||
throw getTaskThrown(delegatedThrown);
|
||||
}
|
||||
|
||||
Map.Entry<Byte, ByteBuffer> me =
|
||||
context.delegatedActions.poll();
|
||||
if (me != null) {
|
||||
|
@ -167,9 +167,10 @@ interface SSLTransport {
|
||||
if (plainText == null) {
|
||||
plainText = Plaintext.PLAINTEXT_NULL;
|
||||
} else {
|
||||
// File the destination buffers.
|
||||
if (dsts != null && dstsLength > 0 &&
|
||||
plainText.contentType == ContentType.APPLICATION_DATA.id) {
|
||||
// Fill the destination buffers.
|
||||
if ((dsts != null) && (dstsLength > 0) &&
|
||||
(plainText.contentType ==
|
||||
ContentType.APPLICATION_DATA.id)) {
|
||||
|
||||
ByteBuffer fragment = plainText.fragment;
|
||||
int remains = fragment.remaining();
|
||||
|
@ -40,6 +40,7 @@ import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.SSLProtocolException;
|
||||
import sun.security.ssl.CipherSuite.KeyExchange;
|
||||
import sun.security.ssl.ClientHello.ClientHelloMessage;
|
||||
import sun.security.ssl.SSLCipher.SSLReadCipher;
|
||||
@ -139,8 +140,11 @@ final class ServerHello {
|
||||
|
||||
this.serverRandom = new RandomCookie(m);
|
||||
this.sessionId = new SessionId(Record.getBytes8(m));
|
||||
sessionId.checkLength(serverVersion.id);
|
||||
|
||||
try {
|
||||
sessionId.checkLength(serverVersion.id);
|
||||
} catch (SSLProtocolException ex) {
|
||||
handshakeContext.conContext.fatal(Alert.ILLEGAL_PARAMETER, ex);
|
||||
}
|
||||
|
||||
int cipherSuiteId = Record.getInt16(m);
|
||||
this.cipherSuite = CipherSuite.valueOf(cipherSuiteId);
|
||||
|
@ -362,16 +362,16 @@ final class SignatureAlgorithmsExtension {
|
||||
// certificates and server key exchange), it MUST send the
|
||||
// signature_algorithms extension, listing the algorithms it
|
||||
// is willing to accept.
|
||||
List<SignatureScheme> shemes = Arrays.asList(
|
||||
List<SignatureScheme> schemes = Arrays.asList(
|
||||
SignatureScheme.RSA_PKCS1_SHA1,
|
||||
SignatureScheme.DSA_SHA1,
|
||||
SignatureScheme.ECDSA_SHA1
|
||||
);
|
||||
|
||||
shc.peerRequestedSignatureSchemes = shemes;
|
||||
shc.peerRequestedSignatureSchemes = schemes;
|
||||
if (shc.peerRequestedCertSignSchemes == null ||
|
||||
shc.peerRequestedCertSignSchemes.isEmpty()) {
|
||||
shc.peerRequestedCertSignSchemes = shemes;
|
||||
shc.peerRequestedCertSignSchemes.isEmpty()) {
|
||||
shc.peerRequestedCertSignSchemes = schemes;
|
||||
}
|
||||
|
||||
// Use the default peer signature algorithms.
|
||||
|
@ -403,8 +403,8 @@ enum SignatureScheme {
|
||||
|
||||
for (SignatureScheme ss : schemes) {
|
||||
if (ss.isAvailable &&
|
||||
ss.handshakeSupportedProtocols.contains(version) &&
|
||||
certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
|
||||
ss.handshakeSupportedProtocols.contains(version) &&
|
||||
certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ class TransportContext implements ConnectionContext {
|
||||
boolean isInputCloseNotified = false;
|
||||
boolean peerUserCanceled = false;
|
||||
Exception closeReason = null;
|
||||
Exception delegatedThrown = null;
|
||||
|
||||
// negotiated security parameters
|
||||
SSLSessionImpl conSession;
|
||||
@ -364,12 +365,12 @@ class TransportContext implements ConnectionContext {
|
||||
}
|
||||
}
|
||||
|
||||
// terminal handshake context
|
||||
// terminate the handshake context
|
||||
if (handshakeContext != null) {
|
||||
handshakeContext = null;
|
||||
}
|
||||
|
||||
// terminal the transport
|
||||
// terminate the transport
|
||||
try {
|
||||
transport.shutdown();
|
||||
} catch (IOException ioe) {
|
||||
|
@ -73,7 +73,7 @@ enum X509Authentication implements SSLAuthentication {
|
||||
}
|
||||
|
||||
static X509Authentication valueOf(SignatureScheme signatureScheme) {
|
||||
for (X509Authentication au: X509Authentication.values()) {
|
||||
for (X509Authentication au : X509Authentication.values()) {
|
||||
if (au.keyType.equals(signatureScheme.keyAlgorithm)) {
|
||||
return au;
|
||||
}
|
||||
@ -291,9 +291,9 @@ enum X509Authentication implements SSLAuthentication {
|
||||
((ECPublicKey)serverPublicKey).getParams();
|
||||
NamedGroup namedGroup = NamedGroup.valueOf(params);
|
||||
if ((namedGroup == null) ||
|
||||
(!SupportedGroups.isSupported(namedGroup)) ||
|
||||
((shc.clientRequestedNamedGroups != null) &&
|
||||
!shc.clientRequestedNamedGroups.contains(namedGroup))) {
|
||||
(!SupportedGroups.isSupported(namedGroup)) ||
|
||||
((shc.clientRequestedNamedGroups != null) &&
|
||||
!shc.clientRequestedNamedGroups.contains(namedGroup))) {
|
||||
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||
SSLLogger.warning(
|
||||
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2018 Red Hat, Inc. 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 8207838
|
||||
* @summary Regression test for passing float args to a synchronized jni function.
|
||||
*
|
||||
*
|
||||
* @run main/othervm/native compiler.floatingpoint.TestFloatSyncJNIArgs
|
||||
*/
|
||||
|
||||
package compiler.floatingpoint;
|
||||
|
||||
public class TestFloatSyncJNIArgs {
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("TestFloatSyncJNIArgs");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
System.out.println("could not load native lib: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final int numberOfThreads = 8;
|
||||
|
||||
static volatile Error testFailed = null;
|
||||
|
||||
public synchronized static native float combine15floats(
|
||||
float f1, float f2, float f3, float f4,
|
||||
float f5, float f6, float f7, float f8,
|
||||
float f9, float f10, float f11, float f12,
|
||||
float f13, float f14, float f15);
|
||||
|
||||
public synchronized static native double combine15doubles(
|
||||
double d1, double d2, double d3, double d4,
|
||||
double d5, double d6, double d7, double d8,
|
||||
double d9, double d10, double d11, double d12,
|
||||
double d13, double d14, double d15);
|
||||
|
||||
static void test() throws Exception {
|
||||
Thread[] threads = new Thread[numberOfThreads];
|
||||
|
||||
for (int i = 0; i < numberOfThreads; i++) {
|
||||
threads[i] = new Thread(() -> {
|
||||
for (int j = 0; j < 10000; j++) {
|
||||
float f = combine15floats(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
|
||||
9, 10, 11, 12, 13, 14, 15);
|
||||
if (f != 81720.0f) {
|
||||
testFailed = new Error("jni function didn't combine 15 float args properly: " + f);
|
||||
throw testFailed;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
for (int i = 0; i < numberOfThreads; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
for (int i = 0; i < numberOfThreads; i++) {
|
||||
threads[i].join();
|
||||
}
|
||||
if (testFailed != null) {
|
||||
throw testFailed;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numberOfThreads; i++) {
|
||||
threads[i] = new Thread(() -> {
|
||||
for (int j = 0; j < 10000; j++) {
|
||||
double d = combine15doubles(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0,
|
||||
9, 10, 11, 12, 13, 14, 15);
|
||||
if (d != 81720.0) {
|
||||
testFailed = new Error("jni function didn't combine 15 double args properly: " + d);
|
||||
throw testFailed;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
for (int i = 0; i < numberOfThreads; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
for (int i = 0; i < numberOfThreads; i++) {
|
||||
threads[i].join();
|
||||
}
|
||||
if (testFailed != null) {
|
||||
throw testFailed;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
for (int i = 0; i < 200; ++i) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Red Hat, Inc. 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.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Fletcher checksum. This is a nonlinear function which detects both */
|
||||
/* missing or otherwise incorrect arguments and arguments in the wrong */
|
||||
/* order. */
|
||||
static jfloat fcombine(jfloat f[], int len) {
|
||||
int i;
|
||||
jfloat sum = 0, sum_of_sums = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
sum += f[i];
|
||||
sum_of_sums += sum;
|
||||
}
|
||||
return sum + sum_of_sums * sum;
|
||||
}
|
||||
|
||||
static jdouble combine(jdouble f[], int len) {
|
||||
int i;
|
||||
double sum = 0, sum_of_sums = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
sum += f[i];
|
||||
sum_of_sums += sum;
|
||||
}
|
||||
return sum + sum_of_sums * sum;
|
||||
}
|
||||
|
||||
JNIEXPORT jfloat JNICALL Java_compiler_floatingpoint_TestFloatSyncJNIArgs_combine15floats
|
||||
(JNIEnv *env, jclass cls,
|
||||
jfloat f1, jfloat f2, jfloat f3, jfloat f4,
|
||||
jfloat f5, jfloat f6, jfloat f7, jfloat f8,
|
||||
jfloat f9, jfloat f10, jfloat f11, jfloat f12,
|
||||
jfloat f13, jfloat f14, jfloat f15) {
|
||||
|
||||
jfloat f[15];
|
||||
f[0] = f1; f[1] = f2; f[2] = f3; f[3] = f4; f[4] = f5;
|
||||
f[5] = f6; f[6] = f7; f[7] = f8; f[8] = f9; f[9] = f10;
|
||||
f[10] = f11; f[11] = f12; f[12] = f13; f[13] = f14; f[14] = f15;
|
||||
|
||||
return fcombine(f, sizeof f / sizeof f[0]);
|
||||
}
|
||||
|
||||
JNIEXPORT jdouble JNICALL Java_compiler_floatingpoint_TestFloatSyncJNIArgs_combine15doubles
|
||||
(JNIEnv *env, jclass cls,
|
||||
jdouble f1, jdouble f2, jdouble f3, jdouble f4,
|
||||
jdouble f5, jdouble f6, jdouble f7, jdouble f8,
|
||||
jdouble f9, jdouble f10, jdouble f11, jdouble f12,
|
||||
jdouble f13, jdouble f14, jdouble f15) {
|
||||
|
||||
jdouble f[15];
|
||||
f[0] = f1; f[1] = f2; f[2] = f3; f[3] = f4; f[4] = f5;
|
||||
f[5] = f6; f[6] = f7; f[7] = f8; f[8] = f9; f[9] = f10;
|
||||
f[10] = f11; f[11] = f12; f[12] = f13; f[13] = f14; f[14] = f15;
|
||||
|
||||
return combine(f, sizeof f / sizeof f[0]);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
89
test/hotspot/jtreg/runtime/BoolReturn/JNIBooleanTest.java
Normal file
89
test/hotspot/jtreg/runtime/BoolReturn/JNIBooleanTest.java
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2018 SAP SE. 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 8209637
|
||||
* @summary [s390x] Interpreter doesn't call result handler after native calls
|
||||
* @author Volker Simonis
|
||||
*
|
||||
* @run main/othervm/native -XX:-UseOnStackReplacement -Xbatch JNIBooleanTest 50000
|
||||
* @run main/othervm/native -Xint JNIBooleanTest 256
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class JNIBooleanTest {
|
||||
static native boolean foo(byte b);
|
||||
|
||||
static boolean bar(byte b) {
|
||||
return foo(b);
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
int count = args.length > 0 ? Integer.parseInt(args[0]) : 50_000;
|
||||
byte b = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
boolean bool = foo(b);
|
||||
if ((b == 0 && bool) || (b != 0 && !bool)) {
|
||||
throw new RuntimeException("Error: foo(" + b + ") = " + bool + " in iteration " + i);
|
||||
}
|
||||
b++;
|
||||
}
|
||||
|
||||
b = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
boolean bool = bar(b);
|
||||
if ((b == 0 && bool) || (b != 0 && !bool)) {
|
||||
throw new RuntimeException("Error: bar(" + b + ") = " + bool + " in iteration " + i);
|
||||
}
|
||||
b++;
|
||||
}
|
||||
|
||||
Method foo = JNIBooleanTest.class.getDeclaredMethod("foo", byte.class);
|
||||
|
||||
b = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
boolean bool = ((Boolean)foo.invoke(null, b)).booleanValue();
|
||||
if ((b == 0 && bool) || (b != 0 && !bool)) {
|
||||
throw new RuntimeException("Error: foo(" + b + ") = " + bool + " in iteration " + i + " (reflective)");
|
||||
}
|
||||
b++;
|
||||
}
|
||||
|
||||
Method bar = JNIBooleanTest.class.getDeclaredMethod("bar", byte.class);
|
||||
|
||||
b = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
boolean bool = ((Boolean)bar.invoke(null, b)).booleanValue();
|
||||
if ((b == 0 && bool) || (b != 0 && !bool)) {
|
||||
throw new RuntimeException("Error: bar(" + b + ") = " + bool + " in iteration " + i + " (reflective)");
|
||||
}
|
||||
b++;
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("JNIBooleanTest");
|
||||
}
|
||||
}
|
30
test/hotspot/jtreg/runtime/BoolReturn/libJNIBooleanTest.c
Normal file
30
test/hotspot/jtreg/runtime/BoolReturn/libJNIBooleanTest.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2018 SAP SE. 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.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_JNIBooleanTest_foo(JNIEnv *env, jclass cls, jbyte b) {
|
||||
jboolean old = b;
|
||||
return old;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -30,7 +30,6 @@
|
||||
* @summary SSLEngine has not yet caused Solaris kernel to panic
|
||||
* @run main/othervm SSLEngineTemplate
|
||||
*/
|
||||
|
||||
/**
|
||||
* A SSLEngine usage example which simplifies the presentation
|
||||
* by removing the I/O and multi-threading concerns.
|
||||
@ -66,7 +65,6 @@
|
||||
* unwrap() ... ChangeCipherSpec
|
||||
* unwrap() ... Finished
|
||||
*/
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import javax.net.ssl.SSLEngineResult.*;
|
||||
import java.io.*;
|
||||
@ -115,7 +113,7 @@ public class SSLEngineTemplate {
|
||||
private static final String pathToStores = "../etc";
|
||||
private static final String keyStoreFile = "keystore";
|
||||
private static final String trustStoreFile = "truststore";
|
||||
private static final String passwd = "passphrase";
|
||||
private static final char[] passphrase = "passphrase".toCharArray();
|
||||
|
||||
private static final String keyFilename =
|
||||
System.getProperty("test.src", ".") + "/" + pathToStores +
|
||||
@ -146,8 +144,6 @@ public class SSLEngineTemplate {
|
||||
KeyStore ks = KeyStore.getInstance("JKS");
|
||||
KeyStore ts = KeyStore.getInstance("JKS");
|
||||
|
||||
char[] passphrase = "passphrase".toCharArray();
|
||||
|
||||
ks.load(new FileInputStream(keyFilename), passphrase);
|
||||
ts.load(new FileInputStream(trustFilename), passphrase);
|
||||
|
||||
@ -187,8 +183,11 @@ public class SSLEngineTemplate {
|
||||
createSSLEngines();
|
||||
createBuffers();
|
||||
|
||||
SSLEngineResult clientResult; // results from client's last operation
|
||||
SSLEngineResult serverResult; // results from server's last operation
|
||||
// results from client's last operation
|
||||
SSLEngineResult clientResult;
|
||||
|
||||
// results from server's last operation
|
||||
SSLEngineResult serverResult;
|
||||
|
||||
/*
|
||||
* Examining the SSLEngineResults could be much more involved,
|
||||
@ -198,31 +197,62 @@ public class SSLEngineTemplate {
|
||||
* to write to the output pipe, we could reallocate a larger
|
||||
* pipe, but instead we wait for the peer to drain it.
|
||||
*/
|
||||
while (!isEngineClosed(clientEngine) ||
|
||||
!isEngineClosed(serverEngine)) {
|
||||
Exception clientException = null;
|
||||
Exception serverException = null;
|
||||
|
||||
while (!isEngineClosed(clientEngine)
|
||||
|| !isEngineClosed(serverEngine)) {
|
||||
|
||||
log("================");
|
||||
|
||||
clientResult = clientEngine.wrap(clientOut, cTOs);
|
||||
log("client wrap: ", clientResult);
|
||||
runDelegatedTasks(clientResult, clientEngine);
|
||||
try {
|
||||
clientResult = clientEngine.wrap(clientOut, cTOs);
|
||||
log("client wrap: ", clientResult);
|
||||
} catch (Exception e) {
|
||||
clientException = e;
|
||||
System.out.println("Client wrap() threw: " + e.getMessage());
|
||||
}
|
||||
logEngineStatus(clientEngine);
|
||||
runDelegatedTasks(clientEngine);
|
||||
|
||||
serverResult = serverEngine.wrap(serverOut, sTOc);
|
||||
log("server wrap: ", serverResult);
|
||||
runDelegatedTasks(serverResult, serverEngine);
|
||||
log("----");
|
||||
|
||||
try {
|
||||
serverResult = serverEngine.wrap(serverOut, sTOc);
|
||||
log("server wrap: ", serverResult);
|
||||
} catch (Exception e) {
|
||||
serverException = e;
|
||||
System.out.println("Server wrap() threw: " + e.getMessage());
|
||||
}
|
||||
logEngineStatus(serverEngine);
|
||||
runDelegatedTasks(serverEngine);
|
||||
|
||||
cTOs.flip();
|
||||
sTOc.flip();
|
||||
|
||||
log("--------");
|
||||
|
||||
try {
|
||||
clientResult = clientEngine.unwrap(sTOc, clientIn);
|
||||
log("client unwrap: ", clientResult);
|
||||
} catch (Exception e) {
|
||||
clientException = e;
|
||||
System.out.println("Client unwrap() threw: " + e.getMessage());
|
||||
}
|
||||
logEngineStatus(clientEngine);
|
||||
runDelegatedTasks(clientEngine);
|
||||
|
||||
log("----");
|
||||
|
||||
clientResult = clientEngine.unwrap(sTOc, clientIn);
|
||||
log("client unwrap: ", clientResult);
|
||||
runDelegatedTasks(clientResult, clientEngine);
|
||||
|
||||
serverResult = serverEngine.unwrap(cTOs, serverIn);
|
||||
log("server unwrap: ", serverResult);
|
||||
runDelegatedTasks(serverResult, serverEngine);
|
||||
try {
|
||||
serverResult = serverEngine.unwrap(cTOs, serverIn);
|
||||
log("server unwrap: ", serverResult);
|
||||
} catch (Exception e) {
|
||||
serverException = e;
|
||||
System.out.println("Server unwrap() threw: " + e.getMessage());
|
||||
}
|
||||
logEngineStatus(serverEngine);
|
||||
runDelegatedTasks(serverEngine);
|
||||
|
||||
cTOs.compact();
|
||||
sTOc.compact();
|
||||
@ -244,13 +274,22 @@ public class SSLEngineTemplate {
|
||||
|
||||
log("\tClosing clientEngine's *OUTBOUND*...");
|
||||
clientEngine.closeOutbound();
|
||||
logEngineStatus(clientEngine);
|
||||
|
||||
dataDone = true;
|
||||
log("\tClosing serverEngine's *OUTBOUND*...");
|
||||
serverEngine.closeOutbound();
|
||||
logEngineStatus(serverEngine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void logEngineStatus(SSLEngine engine) {
|
||||
log("\tCurrent HS State " + engine.getHandshakeStatus().toString());
|
||||
log("\tisInboundDone(): " + engine.isInboundDone());
|
||||
log("\tisOutboundDone(): " + engine.isOutboundDone());
|
||||
}
|
||||
|
||||
/*
|
||||
* Using the SSLContext created during object creation,
|
||||
* create/configure the SSLEngines we'll use for this test.
|
||||
@ -264,11 +303,19 @@ public class SSLEngineTemplate {
|
||||
serverEngine.setUseClientMode(false);
|
||||
serverEngine.setNeedClientAuth(true);
|
||||
|
||||
// Get/set parameters if needed
|
||||
SSLParameters paramsServer = serverEngine.getSSLParameters();
|
||||
serverEngine.setSSLParameters(paramsServer);
|
||||
|
||||
/*
|
||||
* Similar to above, but using client mode instead.
|
||||
*/
|
||||
clientEngine = sslc.createSSLEngine("client", 80);
|
||||
clientEngine.setUseClientMode(true);
|
||||
|
||||
// Get/set parameters if needed
|
||||
SSLParameters paramsClient = clientEngine.getSSLParameters();
|
||||
clientEngine.setSSLParameters(paramsClient);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -307,13 +354,12 @@ public class SSLEngineTemplate {
|
||||
* If the result indicates that we have outstanding tasks to do,
|
||||
* go ahead and run them in this thread.
|
||||
*/
|
||||
private static void runDelegatedTasks(SSLEngineResult result,
|
||||
SSLEngine engine) throws Exception {
|
||||
private static void runDelegatedTasks(SSLEngine engine) throws Exception {
|
||||
|
||||
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
||||
if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
||||
Runnable runnable;
|
||||
while ((runnable = engine.getDelegatedTask()) != null) {
|
||||
log("\trunning delegated task...");
|
||||
log(" running delegated task...");
|
||||
runnable.run();
|
||||
}
|
||||
HandshakeStatus hsStatus = engine.getHandshakeStatus();
|
||||
@ -321,7 +367,7 @@ public class SSLEngineTemplate {
|
||||
throw new Exception(
|
||||
"handshake shouldn't need additional tasks");
|
||||
}
|
||||
log("\tnew HandshakeStatus: " + hsStatus);
|
||||
logEngineStatus(engine);
|
||||
}
|
||||
}
|
||||
|
||||
@ -361,14 +407,14 @@ public class SSLEngineTemplate {
|
||||
if (resultOnce) {
|
||||
resultOnce = false;
|
||||
System.out.println("The format of the SSLEngineResult is: \n" +
|
||||
"\t\"getStatus() / getHandshakeStatus()\" +\n" +
|
||||
"\t\"bytesConsumed() / bytesProduced()\"\n");
|
||||
"\t\"getStatus() / getHandshakeStatus()\" +\n" +
|
||||
"\t\"bytesConsumed() / bytesProduced()\"\n");
|
||||
}
|
||||
HandshakeStatus hsStatus = result.getHandshakeStatus();
|
||||
log(str +
|
||||
result.getStatus() + "/" + hsStatus + ", " +
|
||||
result.bytesConsumed() + "/" + result.bytesProduced() +
|
||||
" bytes");
|
||||
result.getStatus() + "/" + hsStatus + ", " +
|
||||
result.bytesConsumed() + "/" + result.bytesProduced() +
|
||||
" bytes");
|
||||
if (hsStatus == HandshakeStatus.FINISHED) {
|
||||
log("\t...ready for application data");
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ import java.security.*;
|
||||
import java.nio.*;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class LengthCheckTest {
|
||||
|
||||
@ -203,7 +204,11 @@ public class LengthCheckTest {
|
||||
|
||||
// Now send each ByteBuffer (each being a complete
|
||||
// TLS record) into the client-side unwrap.
|
||||
for (ByteBuffer bBuf : recList) {
|
||||
// for (ByteBuffer bBuf : recList) {
|
||||
|
||||
Iterator<ByteBuffer> iter = recList.iterator();
|
||||
while (!gotException && (iter.hasNext())) {
|
||||
ByteBuffer bBuf = iter.next();
|
||||
dumpByteBuffer("SERVER-TO-CLIENT", bBuf);
|
||||
try {
|
||||
clientResult = clientEngine.unwrap(bBuf, clientIn);
|
||||
@ -232,8 +237,8 @@ public class LengthCheckTest {
|
||||
// was thrown and the proper action (a TLS alert) was
|
||||
// sent back to the server.
|
||||
if (gotException == false ||
|
||||
!isTlsMessage(cTOs, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
|
||||
TLS_ALERT_UNEXPECTED_MSG)) {
|
||||
!isTlsMessage(cTOs, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
|
||||
TLS_ALERT_ILLEGAL_PARAMETER)) {
|
||||
throw new SSLException(
|
||||
"Client failed to throw Alert:fatal:internal_error");
|
||||
}
|
||||
@ -253,38 +258,36 @@ public class LengthCheckTest {
|
||||
ByteBuffer evilClientHello = createEvilClientHello(64);
|
||||
dumpByteBuffer("CLIENT-TO-SERVER", evilClientHello);
|
||||
|
||||
// Server consumes Client Hello
|
||||
serverResult = serverEngine.unwrap(evilClientHello, serverIn);
|
||||
log("server unwrap: ", serverResult);
|
||||
runDelegatedTasks(serverResult, serverEngine);
|
||||
evilClientHello.compact();
|
||||
|
||||
// Under normal circumstances this should be a ServerHello
|
||||
// But should throw an exception instead due to the invalid
|
||||
// session ID.
|
||||
try {
|
||||
// Server consumes Client Hello
|
||||
serverResult = serverEngine.unwrap(evilClientHello, serverIn);
|
||||
log("server unwrap: ", serverResult);
|
||||
runDelegatedTasks(serverResult, serverEngine);
|
||||
evilClientHello.compact();
|
||||
|
||||
// Under normal circumstances this should be a ServerHello
|
||||
// But should throw an exception instead due to the invalid
|
||||
// session ID.
|
||||
serverResult = serverEngine.wrap(serverOut, sTOc);
|
||||
log("server wrap: ", serverResult);
|
||||
runDelegatedTasks(serverResult, serverEngine);
|
||||
sTOc.flip();
|
||||
dumpByteBuffer("SERVER-TO-CLIENT", sTOc);
|
||||
|
||||
// We expect to see the server generate an alert here
|
||||
serverResult = serverEngine.wrap(serverOut, sTOc);
|
||||
log("server wrap: ", serverResult);
|
||||
runDelegatedTasks(serverResult, serverEngine);
|
||||
sTOc.flip();
|
||||
dumpByteBuffer("SERVER-TO-CLIENT", sTOc);
|
||||
} catch (SSLProtocolException ssle) {
|
||||
log("Received expected SSLProtocolException: " + ssle);
|
||||
gotException = true;
|
||||
}
|
||||
|
||||
// We expect to see the server generate an alert here
|
||||
serverResult = serverEngine.wrap(serverOut, sTOc);
|
||||
log("server wrap: ", serverResult);
|
||||
runDelegatedTasks(serverResult, serverEngine);
|
||||
sTOc.flip();
|
||||
dumpByteBuffer("SERVER-TO-CLIENT", sTOc);
|
||||
|
||||
// At this point we can verify that both an exception
|
||||
// was thrown and the proper action (a TLS alert) was
|
||||
// sent back to the client.
|
||||
if (gotException == false ||
|
||||
!isTlsMessage(sTOc, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
|
||||
!isTlsMessage(sTOc, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
|
||||
TLS_ALERT_ILLEGAL_PARAMETER)) {
|
||||
throw new SSLException(
|
||||
"Server failed to throw Alert:fatal:internal_error");
|
||||
|
449
test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineFailedALPN.java
Normal file
449
test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineFailedALPN.java
Normal file
@ -0,0 +1,449 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// SunJSSE does not support dynamic system properties, no way to re-use
|
||||
// system properties in samevm/agentvm mode.
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8207317
|
||||
* @summary SSLEngine negotiation fail Exception behavior changed from
|
||||
* fail-fast to fail-lazy
|
||||
* @run main/othervm SSLEngineFailedALPN
|
||||
*/
|
||||
/**
|
||||
* A SSLEngine usage example which simplifies the presentation
|
||||
* by removing the I/O and multi-threading concerns.
|
||||
*
|
||||
* The test creates two SSLEngines, simulating a client and server.
|
||||
* The "transport" layer consists two byte buffers: think of them
|
||||
* as directly connected pipes.
|
||||
*
|
||||
* Note, this is a *very* simple example: real code will be much more
|
||||
* involved. For example, different threading and I/O models could be
|
||||
* used, transport mechanisms could close unexpectedly, and so on.
|
||||
*
|
||||
* When this application runs, notice that several messages
|
||||
* (wrap/unwrap) pass before any application data is consumed or
|
||||
* produced. (For more information, please see the SSL/TLS
|
||||
* specifications.) There may several steps for a successful handshake,
|
||||
* so it's typical to see the following series of operations:
|
||||
*
|
||||
* client server message
|
||||
* ====== ====== =======
|
||||
* wrap() ... ClientHello
|
||||
* ... unwrap() ClientHello
|
||||
* ... wrap() ServerHello/Certificate
|
||||
* unwrap() ... ServerHello/Certificate
|
||||
* wrap() ... ClientKeyExchange
|
||||
* wrap() ... ChangeCipherSpec
|
||||
* wrap() ... Finished
|
||||
* ... unwrap() ClientKeyExchange
|
||||
* ... unwrap() ChangeCipherSpec
|
||||
* ... unwrap() Finished
|
||||
* ... wrap() ChangeCipherSpec
|
||||
* ... wrap() Finished
|
||||
* unwrap() ... ChangeCipherSpec
|
||||
* unwrap() ... Finished
|
||||
*/
|
||||
import javax.net.ssl.*;
|
||||
import javax.net.ssl.SSLEngineResult.*;
|
||||
import java.io.*;
|
||||
import java.security.*;
|
||||
import java.nio.*;
|
||||
|
||||
public class SSLEngineFailedALPN {
|
||||
|
||||
/*
|
||||
* Enables logging of the SSLEngine operations.
|
||||
*/
|
||||
private static final boolean logging = true;
|
||||
|
||||
/*
|
||||
* Enables the JSSE system debugging system property:
|
||||
*
|
||||
* -Djavax.net.debug=all
|
||||
*
|
||||
* This gives a lot of low-level information about operations underway,
|
||||
* including specific handshake messages, and might be best examined
|
||||
* after gaining some familiarity with this application.
|
||||
*/
|
||||
private static final boolean debug = false;
|
||||
|
||||
private final SSLContext sslc;
|
||||
|
||||
private SSLEngine clientEngine; // client Engine
|
||||
private ByteBuffer clientOut; // write side of clientEngine
|
||||
private ByteBuffer clientIn; // read side of clientEngine
|
||||
|
||||
private SSLEngine serverEngine; // server Engine
|
||||
private ByteBuffer serverOut; // write side of serverEngine
|
||||
private ByteBuffer serverIn; // read side of serverEngine
|
||||
|
||||
/*
|
||||
* For data transport, this example uses local ByteBuffers. This
|
||||
* isn't really useful, but the purpose of this example is to show
|
||||
* SSLEngine concepts, not how to do network transport.
|
||||
*/
|
||||
private ByteBuffer cTOs; // "reliable" transport client->server
|
||||
private ByteBuffer sTOc; // "reliable" transport server->client
|
||||
|
||||
/*
|
||||
* The following is to set up the keystores.
|
||||
*/
|
||||
private static final String pathToStores = "../../../../javax/net/ssl/etc";
|
||||
private static final String keyStoreFile = "keystore";
|
||||
private static final String trustStoreFile = "truststore";
|
||||
private static final char[] passphrase = "passphrase".toCharArray();
|
||||
|
||||
private static final String keyFilename =
|
||||
System.getProperty("test.src", ".") + "/" + pathToStores +
|
||||
"/" + keyStoreFile;
|
||||
private static final String trustFilename =
|
||||
System.getProperty("test.src", ".") + "/" + pathToStores +
|
||||
"/" + trustStoreFile;
|
||||
|
||||
/*
|
||||
* Main entry point for this test.
|
||||
*/
|
||||
public static void main(String args[]) throws Exception {
|
||||
if (debug) {
|
||||
System.setProperty("javax.net.debug", "all");
|
||||
}
|
||||
|
||||
SSLEngineFailedALPN test = new SSLEngineFailedALPN();
|
||||
test.runTest();
|
||||
|
||||
System.out.println("Test Passed.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an initialized SSLContext to use for these tests.
|
||||
*/
|
||||
public SSLEngineFailedALPN() throws Exception {
|
||||
|
||||
KeyStore ks = KeyStore.getInstance("JKS");
|
||||
KeyStore ts = KeyStore.getInstance("JKS");
|
||||
|
||||
ks.load(new FileInputStream(keyFilename), passphrase);
|
||||
ts.load(new FileInputStream(trustFilename), passphrase);
|
||||
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
kmf.init(ks, passphrase);
|
||||
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
|
||||
tmf.init(ts);
|
||||
|
||||
SSLContext sslCtx = SSLContext.getInstance("TLS");
|
||||
|
||||
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
||||
|
||||
sslc = sslCtx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the test.
|
||||
*
|
||||
* Sit in a tight loop, both engines calling wrap/unwrap regardless
|
||||
* of whether data is available or not. We do this until both engines
|
||||
* report back they are closed.
|
||||
*
|
||||
* The main loop handles all of the I/O phases of the SSLEngine's
|
||||
* lifetime:
|
||||
*
|
||||
* initial handshaking
|
||||
* application data transfer
|
||||
* engine closing
|
||||
*
|
||||
* One could easily separate these phases into separate
|
||||
* sections of code.
|
||||
*/
|
||||
private void runTest() throws Exception {
|
||||
boolean dataDone = false;
|
||||
|
||||
createSSLEngines();
|
||||
createBuffers();
|
||||
|
||||
// results from client's last operation
|
||||
SSLEngineResult clientResult;
|
||||
|
||||
// results from server's last operation
|
||||
SSLEngineResult serverResult;
|
||||
|
||||
/*
|
||||
* Examining the SSLEngineResults could be much more involved,
|
||||
* and may alter the overall flow of the application.
|
||||
*
|
||||
* For example, if we received a BUFFER_OVERFLOW when trying
|
||||
* to write to the output pipe, we could reallocate a larger
|
||||
* pipe, but instead we wait for the peer to drain it.
|
||||
*/
|
||||
Exception clientException = null;
|
||||
Exception serverException = null;
|
||||
|
||||
while (!isEngineClosed(clientEngine)
|
||||
|| !isEngineClosed(serverEngine)) {
|
||||
|
||||
log("================");
|
||||
|
||||
try {
|
||||
clientResult = clientEngine.wrap(clientOut, cTOs);
|
||||
log("client wrap: ", clientResult);
|
||||
} catch (Exception e) {
|
||||
clientException = e;
|
||||
System.out.println("Client wrap() threw: " + e.getMessage());
|
||||
}
|
||||
logEngineStatus(clientEngine);
|
||||
runDelegatedTasks(clientEngine);
|
||||
|
||||
log("----");
|
||||
|
||||
try {
|
||||
serverResult = serverEngine.wrap(serverOut, sTOc);
|
||||
log("server wrap: ", serverResult);
|
||||
} catch (Exception e) {
|
||||
serverException = e;
|
||||
System.out.println("Server wrap() threw: " + e.getMessage());
|
||||
}
|
||||
logEngineStatus(serverEngine);
|
||||
runDelegatedTasks(serverEngine);
|
||||
|
||||
cTOs.flip();
|
||||
sTOc.flip();
|
||||
|
||||
log("--------");
|
||||
|
||||
try {
|
||||
clientResult = clientEngine.unwrap(sTOc, clientIn);
|
||||
log("client unwrap: ", clientResult);
|
||||
} catch (Exception e) {
|
||||
clientException = e;
|
||||
System.out.println("Client unwrap() threw: " + e.getMessage());
|
||||
}
|
||||
logEngineStatus(clientEngine);
|
||||
runDelegatedTasks(clientEngine);
|
||||
|
||||
log("----");
|
||||
|
||||
try {
|
||||
serverResult = serverEngine.unwrap(cTOs, serverIn);
|
||||
log("server unwrap: ", serverResult);
|
||||
} catch (Exception e) {
|
||||
serverException = e;
|
||||
System.out.println("Server unwrap() threw: " + e.getMessage());
|
||||
}
|
||||
logEngineStatus(serverEngine);
|
||||
runDelegatedTasks(serverEngine);
|
||||
|
||||
cTOs.compact();
|
||||
sTOc.compact();
|
||||
|
||||
/*
|
||||
* After we've transfered all application data between the client
|
||||
* and server, we close the clientEngine's outbound stream.
|
||||
* This generates a close_notify handshake message, which the
|
||||
* server engine receives and responds by closing itself.
|
||||
*/
|
||||
if (!dataDone && (clientOut.limit() == serverIn.position()) &&
|
||||
(serverOut.limit() == clientIn.position())) {
|
||||
|
||||
/*
|
||||
* A sanity check to ensure we got what was sent.
|
||||
*/
|
||||
checkTransfer(serverOut, clientIn);
|
||||
checkTransfer(clientOut, serverIn);
|
||||
|
||||
log("\tClosing clientEngine's *OUTBOUND*...");
|
||||
clientEngine.closeOutbound();
|
||||
logEngineStatus(clientEngine);
|
||||
|
||||
dataDone = true;
|
||||
log("\tClosing serverEngine's *OUTBOUND*...");
|
||||
serverEngine.closeOutbound();
|
||||
logEngineStatus(serverEngine);
|
||||
}
|
||||
}
|
||||
|
||||
log("================");
|
||||
|
||||
if ((clientException != null) &&
|
||||
(clientException instanceof SSLHandshakeException)) {
|
||||
log("Client threw proper exception");
|
||||
clientException.printStackTrace(System.out);
|
||||
} else {
|
||||
throw new Exception("Client Exception not seen");
|
||||
}
|
||||
|
||||
if ((serverException != null) &&
|
||||
(serverException instanceof SSLHandshakeException)) {
|
||||
log("Server threw proper exception:");
|
||||
serverException.printStackTrace(System.out);
|
||||
} else {
|
||||
throw new Exception("Server Exception not seen");
|
||||
}
|
||||
}
|
||||
|
||||
private static void logEngineStatus(SSLEngine engine) {
|
||||
log("\tCurrent HS State " + engine.getHandshakeStatus().toString());
|
||||
log("\tisInboundDone(): " + engine.isInboundDone());
|
||||
log("\tisOutboundDone(): " + engine.isOutboundDone());
|
||||
}
|
||||
|
||||
/*
|
||||
* Using the SSLContext created during object creation,
|
||||
* create/configure the SSLEngines we'll use for this test.
|
||||
*/
|
||||
private void createSSLEngines() throws Exception {
|
||||
/*
|
||||
* Configure the serverEngine to act as a server in the SSL/TLS
|
||||
* handshake. Also, require SSL client authentication.
|
||||
*/
|
||||
serverEngine = sslc.createSSLEngine();
|
||||
serverEngine.setUseClientMode(false);
|
||||
serverEngine.setNeedClientAuth(true);
|
||||
|
||||
// Get/set parameters if needed
|
||||
SSLParameters paramsServer = serverEngine.getSSLParameters();
|
||||
paramsServer.setApplicationProtocols(new String[]{"one"});
|
||||
serverEngine.setSSLParameters(paramsServer);
|
||||
|
||||
/*
|
||||
* Similar to above, but using client mode instead.
|
||||
*/
|
||||
clientEngine = sslc.createSSLEngine("client", 80);
|
||||
clientEngine.setUseClientMode(true);
|
||||
|
||||
// Get/set parameters if needed
|
||||
SSLParameters paramsClient = clientEngine.getSSLParameters();
|
||||
paramsClient.setApplicationProtocols(new String[]{"two"});
|
||||
clientEngine.setSSLParameters(paramsClient);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create and size the buffers appropriately.
|
||||
*/
|
||||
private void createBuffers() {
|
||||
|
||||
/*
|
||||
* We'll assume the buffer sizes are the same
|
||||
* between client and server.
|
||||
*/
|
||||
SSLSession session = clientEngine.getSession();
|
||||
int appBufferMax = session.getApplicationBufferSize();
|
||||
int netBufferMax = session.getPacketBufferSize();
|
||||
|
||||
/*
|
||||
* We'll make the input buffers a bit bigger than the max needed
|
||||
* size, so that unwrap()s following a successful data transfer
|
||||
* won't generate BUFFER_OVERFLOWS.
|
||||
*
|
||||
* We'll use a mix of direct and indirect ByteBuffers for
|
||||
* tutorial purposes only. In reality, only use direct
|
||||
* ByteBuffers when they give a clear performance enhancement.
|
||||
*/
|
||||
clientIn = ByteBuffer.allocate(appBufferMax + 50);
|
||||
serverIn = ByteBuffer.allocate(appBufferMax + 50);
|
||||
|
||||
cTOs = ByteBuffer.allocateDirect(netBufferMax);
|
||||
sTOc = ByteBuffer.allocateDirect(netBufferMax);
|
||||
|
||||
clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
|
||||
serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
|
||||
}
|
||||
|
||||
/*
|
||||
* If the result indicates that we have outstanding tasks to do,
|
||||
* go ahead and run them in this thread.
|
||||
*/
|
||||
private static void runDelegatedTasks(SSLEngine engine) throws Exception {
|
||||
|
||||
if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
||||
Runnable runnable;
|
||||
while ((runnable = engine.getDelegatedTask()) != null) {
|
||||
log(" running delegated task...");
|
||||
runnable.run();
|
||||
}
|
||||
HandshakeStatus hsStatus = engine.getHandshakeStatus();
|
||||
if (hsStatus == HandshakeStatus.NEED_TASK) {
|
||||
throw new Exception(
|
||||
"handshake shouldn't need additional tasks");
|
||||
}
|
||||
logEngineStatus(engine);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isEngineClosed(SSLEngine engine) {
|
||||
return (engine.isOutboundDone() && engine.isInboundDone());
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple check to make sure everything came across as expected.
|
||||
*/
|
||||
private static void checkTransfer(ByteBuffer a, ByteBuffer b)
|
||||
throws Exception {
|
||||
a.flip();
|
||||
b.flip();
|
||||
|
||||
if (!a.equals(b)) {
|
||||
throw new Exception("Data didn't transfer cleanly");
|
||||
} else {
|
||||
log("\tData transferred cleanly");
|
||||
}
|
||||
|
||||
a.position(a.limit());
|
||||
b.position(b.limit());
|
||||
a.limit(a.capacity());
|
||||
b.limit(b.capacity());
|
||||
}
|
||||
|
||||
/*
|
||||
* Logging code
|
||||
*/
|
||||
private static boolean resultOnce = true;
|
||||
|
||||
private static void log(String str, SSLEngineResult result) {
|
||||
if (!logging) {
|
||||
return;
|
||||
}
|
||||
if (resultOnce) {
|
||||
resultOnce = false;
|
||||
System.out.println("The format of the SSLEngineResult is: \n" +
|
||||
"\t\"getStatus() / getHandshakeStatus()\" +\n" +
|
||||
"\t\"bytesConsumed() / bytesProduced()\"\n");
|
||||
}
|
||||
HandshakeStatus hsStatus = result.getHandshakeStatus();
|
||||
log(str +
|
||||
result.getStatus() + "/" + hsStatus + ", " +
|
||||
result.bytesConsumed() + "/" + result.bytesProduced() +
|
||||
" bytes");
|
||||
if (hsStatus == HandshakeStatus.FINISHED) {
|
||||
log("\t...ready for application data");
|
||||
}
|
||||
}
|
||||
|
||||
private static void log(String str) {
|
||||
if (logging) {
|
||||
System.out.println(str);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user