Simplified loading native libraries
This commit is contained in:
parent
3856925cb2
commit
ce4e3bef90
@ -10,6 +10,7 @@ package com.barchart.udt;
|
|||||||
import com.barchart.udt.anno.Native;
|
import com.barchart.udt.anno.Native;
|
||||||
import com.barchart.udt.nio.KindUDT;
|
import com.barchart.udt.nio.KindUDT;
|
||||||
import com.barchart.udt.util.HelpUDT;
|
import com.barchart.udt.util.HelpUDT;
|
||||||
|
import dorkbox.network.util.NativeLoader;
|
||||||
import dorkbox.util.FileUtil;
|
import dorkbox.util.FileUtil;
|
||||||
import dorkbox.util.OS;
|
import dorkbox.util.OS;
|
||||||
import dorkbox.util.OsType;
|
import dorkbox.util.OsType;
|
||||||
@ -17,30 +18,16 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
import java.security.CodeSource;
|
import java.security.CodeSource;
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.jar.JarEntry;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UDT native socket wrapper
|
* UDT native socket wrapper
|
||||||
@ -159,87 +146,32 @@ class SocketUDT {
|
|||||||
if (isContainer) {
|
if (isContainer) {
|
||||||
// have to extract our correct file to temp then load it, ONLY if we are not already loaded!
|
// have to extract our correct file to temp then load it, ONLY if we are not already loaded!
|
||||||
|
|
||||||
|
String sourceFileName = "udt-core-2.3.2";
|
||||||
|
if (OS.isLinux()) {
|
||||||
|
sourceFileName += ".so";
|
||||||
|
}
|
||||||
|
else if (OS.isWindows()) {
|
||||||
|
sourceFileName += ".dll";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sourceFileName += ".dylib";
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
|
||||||
digest.update(TypeUDT.class.getName()
|
|
||||||
.getBytes());
|
|
||||||
|
|
||||||
// convert to alpha-numeric. see https://stackoverflow.com/questions/29183818/why-use-tostring32-and-not-tostring36
|
|
||||||
final String outputFileName = "UDT_driver_" + new BigInteger(1, digest.digest()).toString(32)
|
|
||||||
.toUpperCase(Locale.US);
|
|
||||||
|
|
||||||
final String tempDir = System.getProperty("java.io.tmpdir");
|
|
||||||
|
|
||||||
final File file = new File(tempDir, outputFileName);
|
|
||||||
if (!file.canRead()) {
|
|
||||||
// we need to iterate this jar to get the files
|
|
||||||
|
|
||||||
final String packageName = TypeUDT.class.getPackage()
|
|
||||||
.getName()
|
|
||||||
.replaceAll("\\.", "/");
|
|
||||||
|
|
||||||
final String prefix = packageName + "/natives/" + osName + "/";
|
|
||||||
final List<String> list = Arrays.asList(os.getLibraryNames());
|
|
||||||
|
|
||||||
final String jarFileName = URLDecoder.decode(loc.getPath(), "UTF-8");
|
|
||||||
JarFile jar = new JarFile(jarFileName);
|
|
||||||
Enumeration<JarEntry> entries = jar.entries();
|
|
||||||
JAR_READ:
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
final JarEntry jarEntry = entries.nextElement();
|
|
||||||
String name = jarEntry.getName();
|
|
||||||
|
|
||||||
if (name.startsWith(prefix)) {
|
|
||||||
for (String s : list) {
|
|
||||||
if (name.endsWith(s)) {
|
|
||||||
// there is only one!
|
|
||||||
|
|
||||||
// now we copy it out
|
|
||||||
final InputStream inputStream = jar.getInputStream(jarEntry);
|
|
||||||
|
|
||||||
OutputStream outStream = null;
|
|
||||||
try {
|
|
||||||
outStream = new FileOutputStream(file);
|
|
||||||
|
|
||||||
byte[] buffer = new byte[2048];
|
|
||||||
int read;
|
|
||||||
while ((read = inputStream.read(buffer)) > 0) {
|
|
||||||
outStream.write(buffer, 0, read);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error extracting library from: " + jarFileName, e.getMessage());
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
inputStream.close();
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (outStream != null) {
|
|
||||||
outStream.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break JAR_READ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jar.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("Loading release libraries.");
|
log.info("Loading release libraries.");
|
||||||
|
|
||||||
System.load(file.getAbsolutePath());
|
final String packageName = TypeUDT.class.getPackage()
|
||||||
|
.getName()
|
||||||
|
.replaceAll("\\.", "/");
|
||||||
|
|
||||||
|
sourceFileName = packageName + "/natives/" + osName + "/" + sourceFileName;
|
||||||
|
|
||||||
|
NativeLoader.loadLibrary(sourceFileName, "networkUDT_", TypeUDT.class);
|
||||||
|
|
||||||
log.info("Release libraries loaded.");
|
log.info("Release libraries loaded.");
|
||||||
loaded = true;
|
loaded = true;
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (Exception e) {
|
||||||
log.error("Error loading MD5 checksum.", e.getMessage());
|
log.error(e.getMessage());
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
log.error("Error parsing text.", e.getMessage());
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Error extracting library.", e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
162
src/dorkbox/network/util/NativeLinuxEpoll.java
Normal file
162
src/dorkbox/network/util/NativeLinuxEpoll.java
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package dorkbox.network.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The contents of this method are used to rewrite (via javassist, via the BuildDependencyJars build) the NativeLibraryLoader.load method.
|
||||||
|
*
|
||||||
|
* This is necessary so that we don't continuously recreate the native library every time we start.
|
||||||
|
*
|
||||||
|
* Also, this file is not included in the build process.
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class NativeLinuxEpoll {
|
||||||
|
|
||||||
|
public static
|
||||||
|
void load(String name, ClassLoader loader) {
|
||||||
|
// try {
|
||||||
|
// String var0 = $1;
|
||||||
|
// ClassLoader var1 = $2;
|
||||||
|
// if (var0.equals("netty-transport-native-epoll")) {
|
||||||
|
// String sourceFileName = "META-INF/native/lib" + var0 + ".so";
|
||||||
|
// String suffix = ".so";
|
||||||
|
//
|
||||||
|
// String version = dorkbox.network.Server.getVersion();
|
||||||
|
//
|
||||||
|
// final String outputFileName = "lib" + var0 + "." + version + suffix;
|
||||||
|
// final String tempDir = System.getProperty("java.io.tmpdir");
|
||||||
|
//
|
||||||
|
// final java.io.File file = new java.io.File(tempDir, outputFileName);
|
||||||
|
// if (!file.canRead()) {
|
||||||
|
// java.net.URL url = var1.getResource(sourceFileName);
|
||||||
|
//
|
||||||
|
// System.err.println("Loading: " + file.getAbsolutePath());
|
||||||
|
//
|
||||||
|
// // now we copy it out
|
||||||
|
// final java.io.InputStream inputStream = url.openStream();
|
||||||
|
//
|
||||||
|
// java.io.OutputStream outStream = null;
|
||||||
|
// try {
|
||||||
|
// outStream = new java.io.FileOutputStream(file);
|
||||||
|
//
|
||||||
|
// byte[] buffer = new byte[4096];
|
||||||
|
// int read;
|
||||||
|
// while ((read = inputStream.read(buffer)) > 0) {
|
||||||
|
// outStream.write(buffer, 0, read);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// outStream.flush();
|
||||||
|
// outStream.close();
|
||||||
|
// outStream = null;
|
||||||
|
// } finally {
|
||||||
|
// try {
|
||||||
|
// inputStream.close();
|
||||||
|
// } catch (Exception ignored) {
|
||||||
|
// }
|
||||||
|
// try {
|
||||||
|
// if (outStream != null) {
|
||||||
|
// outStream.close();
|
||||||
|
// }
|
||||||
|
// } catch (Exception ignored) {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// System.load(file.getAbsolutePath());
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// // default file operation
|
||||||
|
//
|
||||||
|
// String libname = System.mapLibraryName(var0);
|
||||||
|
// String path = io.netty.util.internal.NativeLibraryLoader.NATIVE_RESOURCE_HOME + libname;
|
||||||
|
//
|
||||||
|
// java.net.URL url = var1.getResource(path);
|
||||||
|
// if (url == null && io.netty.util.internal.NativeLibraryLoader.isOSX()) {
|
||||||
|
// if (path.endsWith(".jnilib")) {
|
||||||
|
// url = var1.getResource(io.netty.util.internal.NativeLibraryLoader.NATIVE_RESOURCE_HOME + "lib" + var0 + ".dynlib");
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// url = var1.getResource(io.netty.util.internal.NativeLibraryLoader.NATIVE_RESOURCE_HOME + "lib" + var0 + ".jnilib");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (url == null) {
|
||||||
|
// // Fall back to normal loading of JNI stuff
|
||||||
|
// System.loadLibrary(var0);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// int index = libname.lastIndexOf('.');
|
||||||
|
// String prefix = libname.substring(0, index);
|
||||||
|
// String suffix = libname.substring(index, libname.length());
|
||||||
|
// java.io.InputStream in = null;
|
||||||
|
// java.io.OutputStream out = null;
|
||||||
|
// java.io.File tmpFile = null;
|
||||||
|
// boolean loaded = false;
|
||||||
|
// try {
|
||||||
|
// tmpFile = java.io.File.createTempFile(prefix, suffix, io.netty.util.internal.NativeLibraryLoader.WORKDIR);
|
||||||
|
// in = url.openStream();
|
||||||
|
// out = new java.io.FileOutputStream(tmpFile);
|
||||||
|
//
|
||||||
|
// byte[] buffer = new byte[8192];
|
||||||
|
// int length;
|
||||||
|
// while ((length = in.read(buffer)) > 0) {
|
||||||
|
// out.write(buffer, 0, length);
|
||||||
|
// }
|
||||||
|
// out.flush();
|
||||||
|
// out.close();
|
||||||
|
// out = null;
|
||||||
|
//
|
||||||
|
// System.load(tmpFile.getPath());
|
||||||
|
// loaded = true;
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// throw (UnsatisfiedLinkError) new UnsatisfiedLinkError("could not load a native library: " + var0).initCause(e);
|
||||||
|
// } finally {
|
||||||
|
// if (in != null) {
|
||||||
|
// try {
|
||||||
|
// in.close();
|
||||||
|
// } catch (java.io.IOException ignore) {
|
||||||
|
// // ignore
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (out != null) {
|
||||||
|
// try {
|
||||||
|
// out.close();
|
||||||
|
// } catch (java.io.IOException ignore) {
|
||||||
|
// // ignore
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (tmpFile != null) {
|
||||||
|
// if (loaded) {
|
||||||
|
// tmpFile.deleteOnExit();
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// if (!tmpFile.delete()) {
|
||||||
|
// tmpFile.deleteOnExit();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private
|
||||||
|
NativeLinuxEpoll() {
|
||||||
|
}
|
||||||
|
}
|
96
src/dorkbox/network/util/NativeLoader.java
Normal file
96
src/dorkbox/network/util/NativeLoader.java
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package dorkbox.network.util;
|
||||||
|
|
||||||
|
import dorkbox.network.Server;
|
||||||
|
import dorkbox.util.OS;
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.rmi.server.ExportException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the specified library, extracting it from the jar, if necessary
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class NativeLoader {
|
||||||
|
|
||||||
|
public static
|
||||||
|
void loadLibrary(final String sourceFileName, final String destinationPrefix, final Class<?> classLoaderClass) throws Exception {
|
||||||
|
try {
|
||||||
|
String suffix;
|
||||||
|
if (OS.isLinux()) {
|
||||||
|
suffix = ".so";
|
||||||
|
}
|
||||||
|
else if (OS.isWindows()) {
|
||||||
|
suffix = ".dll";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
suffix = ".dylib";
|
||||||
|
}
|
||||||
|
|
||||||
|
final String outputFileName = destinationPrefix + "." + Server.getVersion() + suffix;
|
||||||
|
final String tempDir = System.getProperty("java.io.tmpdir");
|
||||||
|
|
||||||
|
final File file = new File(tempDir, outputFileName);
|
||||||
|
if (!file.canRead()) {
|
||||||
|
ClassLoader loader = PlatformDependent.getClassLoader(classLoaderClass);
|
||||||
|
URL url = loader.getResource(sourceFileName);
|
||||||
|
|
||||||
|
// now we copy it out
|
||||||
|
final InputStream inputStream = url.openStream();
|
||||||
|
|
||||||
|
OutputStream outStream = null;
|
||||||
|
try {
|
||||||
|
outStream = new FileOutputStream(file);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int read;
|
||||||
|
while ((read = inputStream.read(buffer)) > 0) {
|
||||||
|
outStream.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
|
||||||
|
outStream.flush();
|
||||||
|
outStream.close();
|
||||||
|
outStream = null;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
inputStream.close();
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (outStream != null) {
|
||||||
|
outStream.close();
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.load(file.getAbsolutePath());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ExportException("Error extracting library: " + sourceFileName, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private
|
||||||
|
NativeLoader() {
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user