Simplified loading native libraries

This commit is contained in:
nathan 2016-03-19 03:05:54 +01:00
parent 3856925cb2
commit ce4e3bef90
9 changed files with 280 additions and 90 deletions

View File

@ -10,6 +10,7 @@ package com.barchart.udt;
import com.barchart.udt.anno.Native;
import com.barchart.udt.nio.KindUDT;
import com.barchart.udt.util.HelpUDT;
import dorkbox.network.util.NativeLoader;
import dorkbox.util.FileUtil;
import dorkbox.util.OS;
import dorkbox.util.OsType;
@ -17,30 +18,16 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.InetSocketAddress;
import java.net.URI;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.security.CodeSource;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.ProtectionDomain;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* UDT native socket wrapper
@ -159,87 +146,32 @@ class SocketUDT {
if (isContainer) {
// 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 {
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.");
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.");
loaded = true;
} catch (NoSuchAlgorithmException e) {
log.error("Error loading MD5 checksum.", e.getMessage());
} catch (UnsupportedEncodingException e) {
log.error("Error parsing text.", e.getMessage());
} catch (IOException e) {
log.error("Error extracting library.", e.getMessage());
} catch (Exception e) {
log.error(e.getMessage());
}
}
else {

View 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() {
}
}

View 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() {
}
}