diff --git a/dev-tools/tests.policy b/dev-tools/tests.policy index 8e485d7af1a..82e23fca6fd 100644 --- a/dev-tools/tests.policy +++ b/dev-tools/tests.policy @@ -70,7 +70,9 @@ grant { // needed by groovy scripting permission java.lang.RuntimePermission "getProtectionDomain"; + // needed for natives calls permission java.lang.RuntimePermission "loadLibrary.*"; + permission java.lang.RuntimePermission "createSecurityManager"; // reflection hacks: // needed for Striped64 (what is this doing), also enables unmap hack diff --git a/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java b/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java index 68005f1a3ca..386da4a5401 100644 --- a/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java +++ b/src/main/java/org/elasticsearch/common/jna/Kernel32Library.java @@ -20,7 +20,6 @@ package org.elasticsearch.common.jna; import com.google.common.collect.ImmutableList; -import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.win32.StdCallLibrary; import org.elasticsearch.common.logging.ESLogger; @@ -37,17 +36,18 @@ public class Kernel32Library { private static ESLogger logger = Loggers.getLogger(Kernel32Library.class); - private Kernel32 internal; - + // Callbacks must be kept around in order to be able to be called later, + // when the Windows ConsoleCtrlHandler sends an event. private List callbacks = new ArrayList<>(); + // Native library instance must be kept around for the same reason. private final static class Holder { private final static Kernel32Library instance = new Kernel32Library(); } private Kernel32Library() { try { - internal = (Kernel32)Native.synchronizedLibrary((Kernel32)Native.loadLibrary("kernel32", Kernel32.class)); + Native.register("kernel32"); logger.debug("windows/Kernel32 library loaded"); } catch (NoClassDefFoundError e) { logger.warn("JNA not found. native methods and handlers will be disabled."); @@ -60,14 +60,19 @@ public class Kernel32Library { return Holder.instance; } + /** + * Adds a Console Ctrl Handler. + * + * @param handler + * @return true if the handler is correctly set + * @throws java.lang.UnsatisfiedLinkError if the Kernel32 library is not loaded or if the native function is not found + * @throws java.lang.NoClassDefFoundError if the library for native calls is missing + */ public boolean addConsoleCtrlHandler(ConsoleCtrlHandler handler) { - if (internal == null) { - throw new UnsupportedOperationException("windows/Kernel32 library not loaded, console ctrl handler cannot be set"); - } boolean result = false; if (handler != null) { NativeHandlerCallback callback = new NativeHandlerCallback(handler); - result = internal.SetConsoleCtrlHandler(callback, true); + result = SetConsoleCtrlHandler(callback, true); if (result) { callbacks.add(callback); } @@ -79,17 +84,16 @@ public class Kernel32Library { return ImmutableList.builder().addAll(callbacks).build(); } - interface Kernel32 extends Library { - - /** - * Registers a Console Ctrl Handler. - * - * @param handler - * @param add - * @return true if the handler is correctly set - */ - public boolean SetConsoleCtrlHandler(StdCallLibrary.StdCallCallback handler, boolean add); - } + /** + * Native call to the Kernel32 API to set a new Console Ctrl Handler. + * + * @param handler + * @param add + * @return true if the handler is correctly set + * @throws java.lang.UnsatisfiedLinkError if the Kernel32 library is not loaded or if the native function is not found + * @throws java.lang.NoClassDefFoundError if the library for native calls is missing + */ + public native boolean SetConsoleCtrlHandler(StdCallLibrary.StdCallCallback handler, boolean add); /** * Handles consoles event with WIN API diff --git a/src/test/java/org/elasticsearch/common/jna/Kernel32LibraryTests.java b/src/test/java/org/elasticsearch/common/jna/NativesTests.java similarity index 78% rename from src/test/java/org/elasticsearch/common/jna/Kernel32LibraryTests.java rename to src/test/java/org/elasticsearch/common/jna/NativesTests.java index 089cfe0663f..6c99f1132fb 100644 --- a/src/test/java/org/elasticsearch/common/jna/Kernel32LibraryTests.java +++ b/src/test/java/org/elasticsearch/common/jna/NativesTests.java @@ -20,7 +20,6 @@ package org.elasticsearch.common.jna; import org.apache.lucene.util.Constants; -import org.apache.lucene.util.LuceneTestCase.AwaitsFix; import org.elasticsearch.common.jna.Kernel32Library.ConsoleCtrlHandler; import org.elasticsearch.test.ElasticsearchTestCase; import org.junit.After; @@ -32,8 +31,7 @@ import java.util.Map; import static org.hamcrest.Matchers.equalTo; -@AwaitsFix(bugUrl = "https://github.com/elasticsearch/elasticsearch/issues/9802") -public class Kernel32LibraryTests extends ElasticsearchTestCase { +public class NativesTests extends ElasticsearchTestCase { /** * Those properties are set by the JNA Api and if not ignored, @@ -65,7 +63,16 @@ public class Kernel32LibraryTests extends ElasticsearchTestCase { } @Test - public void testKernel32Library() { + public void testTryMlockall() { + Natives.tryMlockall(); + + if (Constants.WINDOWS) { + assertFalse("Memory locking is not available on Windows platforms", Natives.LOCAL_MLOCKALL); + } + } + + @Test + public void testAddConsoleCtrlHandler() { ConsoleCtrlHandler handler = new ConsoleCtrlHandler() { @Override public boolean handle(int code) { @@ -73,18 +80,21 @@ public class Kernel32LibraryTests extends ElasticsearchTestCase { } }; - assertNotNull(Kernel32Library.getInstance()); - assertThat(Kernel32Library.getInstance().getCallbacks().size(), equalTo(0)); + Natives.addConsoleCtrlHandler(handler); if (Constants.WINDOWS) { - assertTrue(Kernel32Library.getInstance().addConsoleCtrlHandler(handler)); + assertNotNull(Kernel32Library.getInstance()); assertThat(Kernel32Library.getInstance().getCallbacks().size(), equalTo(1)); + } else { + assertNotNull(Kernel32Library.getInstance()); + assertThat(Kernel32Library.getInstance().getCallbacks().size(), equalTo(0)); + try { Kernel32Library.getInstance().addConsoleCtrlHandler(handler); fail("should have thrown an unsupported operation exception"); - } catch (UnsupportedOperationException e) { - assertThat(e.getMessage(), e.getMessage().contains("console ctrl handler cannot be set"), equalTo(true)); + } catch (UnsatisfiedLinkError e) { + // UnsatisfiedLinkError is expected } } }