diff --git a/.gitignore b/.gitignore index e809dfa2dfa3fbdfded02e02c52560a7ca6b1522..cb4867bb343fe15eb4dca02aa6f6df99911a3275 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ build dist target lib/nblibraries-private.properties +/.settings/ + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..21f85242961a6277853e4a2e1dfbe89cb47e33e8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: java +jdk: + - oraclejdk7 + - openjdk6 diff --git a/pom.xml b/pom.xml index 7001474f01513d49abadc67589e3d1c9eb77acb6..313e603e67ce16b6dcaf5ca50c36c01af82f7d75 100644 --- a/pom.xml +++ b/pom.xml @@ -1,13 +1,19 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> - <groupId>org.jruby.extras</groupId> + <parent> + <groupId>org.sonatype.oss</groupId> + <artifactId>oss-parent</artifactId> + <version>7</version> + </parent> + + <groupId>com.github.jnr</groupId> <artifactId>jnr-netdb</artifactId> <packaging>jar</packaging> - <version>1.0.3</version> + <version>1.1.4</version> <name>jnr-netdb</name> <description>Lookup TCP and UDP services from java</description> - <url>http://github.com/wmeissner/jnr-netdb</url> + <url>http://github.com/jnr/jnr-netdb</url> + <licenses> <license> <name>The Apache Software License, Version 2.0</name> @@ -15,35 +21,13 @@ <distribution>repo</distribution> </license> </licenses> + <scm> - <connection>scm:git:http://github.com/wmeissner/jnr-netdb.git</connection> - <url>http://github.com/wmeissner/jnr-netdb</url> + <connection>scm:git:git@github.com:jnr/jnr-netdb.git</connection> + <developerConnection>scm:git:git@github.com:jnr/jnr-netdb.git</developerConnection> + <url>git@github.com:jnr/jnr-netdb.git</url> </scm> - <distributionManagement> - <repository> - <id>codehaus-jruby-repository</id> - <name>JRuby Central Repository</name> - <url>dav:https://dav.codehaus.org/repository/jruby</url> - </repository> - <snapshotRepository> - <id>codehaus-jruby-snapshot-repository</id> - <name>JRuby Central Development Repository</name> - <url>dav:https://dav.codehaus.org/snapshots.repository/jruby</url> - </snapshotRepository> - </distributionManagement> - <repositories> - <repository> - <id>codehaus</id> - <name>Codehaus Repository</name> - <releases> - <enabled>true</enabled> - </releases> - <snapshots> - <enabled>false</enabled> - </snapshots> - <url>http://repository.codehaus.org</url> - </repository> - </repositories> + <developers> <developer> <id>wmeissner</id> @@ -52,42 +36,28 @@ </developer> </developers> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.source>1.5</maven.compiler.source> + <maven.compiler.target>1.5</maven.compiler.target> + </properties> + <dependencies> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> - <version>4.5</version> + <version>4.11</version> <scope>test</scope> </dependency> + <dependency> - <groupId>org.jruby.extras</groupId> - <artifactId>jaffl</artifactId> - <version>0.5.9</version> + <groupId>com.github.jnr</groupId> + <artifactId>jnr-ffi</artifactId> + <version>2.0.1</version> <scope>compile</scope> </dependency> + </dependencies> - <build> - <sourceDirectory>src</sourceDirectory> - <testSourceDirectory>test</testSourceDirectory> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>2.0.2</version> - <configuration> - <source>1.5</source> - <target>1.5</target> - </configuration> - </plugin> - </plugins> - <extensions> - <extension> - <groupId>org.apache.maven.wagon</groupId> - <artifactId>wagon-webdav</artifactId> - </extension> - </extensions> - </build> - <reporting> - <outputDirectory>build/report</outputDirectory> - </reporting> + </project> diff --git a/src/jnr/netdb/NativeProtocolsDB.java b/src/jnr/netdb/NativeProtocolsDB.java deleted file mode 100644 index ac9e61ea35baaa4efd58096da11cac39f6ee37ad..0000000000000000000000000000000000000000 --- a/src/jnr/netdb/NativeProtocolsDB.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2010 Wayne Meissner - * - * This file is part of jnr. - * - * 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 jnr.netdb; - -import com.kenai.jaffl.CallingConvention; -import com.kenai.jaffl.Library; -import com.kenai.jaffl.LibraryOption; -import com.kenai.jaffl.Platform; -import com.kenai.jaffl.Pointer; -import java.util.ArrayList; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static com.kenai.jaffl.Platform.OS.*; - -/** - * - */ -final class NativeProtocolsDB implements ProtocolsDB { - - private final LibProto lib; - - public static final NativeProtocolsDB getInstance() { - return SingletonHolder.INSTANCE; - } - - private static final class SingletonHolder { - public static final NativeProtocolsDB INSTANCE = load(); - } - - NativeProtocolsDB(LibProto lib) { - this.lib = lib; - } - - private static final NativeProtocolsDB load() { - try { - Platform.OS os = Platform.getPlatform().getOS(); - - // The protoent struct is only known to match on Windows, MacOSX, Linux, Solaris. - // We assume FreeBSD and NetBSD also match. - if (!(os.equals(DARWIN) || (os.equals(WINDOWS) && Platform.getPlatform().getCPU() == Platform.CPU.I386) - || os.equals(LINUX) || os.equals(SOLARIS) - || os.equals(FREEBSD) || os.equals(NETBSD))) { - return null; - } - - LibProto lib; - if (os.equals(WINDOWS)) { - Map<LibraryOption, Object> options = new HashMap<LibraryOption, Object>(); - options.put(LibraryOption.CallingConvention, CallingConvention.STDCALL); - lib = Library.loadLibrary(LibProto.class, options, "Ws2_32"); - } else { - String[] libnames = os.equals(SOLARIS) - ? new String[] { "socket", "nsl", "c" } - : new String[] { "c" }; - lib = Library.loadLibrary(LibProto.class, libnames); - } - - // Try to lookup a protocol to make sure the library loaded and found the functions - lib.getprotobyname("ip"); - lib.getprotobynumber(0); - - return new NativeProtocolsDB(lib); - } catch (Throwable t) { - Logger.getLogger(NativeProtocolsDB.class.getName()).log(Level.WARNING, "Failed to load native protocols db", t); - return null; - } - } - - public static class UnixProtoent extends com.kenai.jaffl.struct.Struct { - public final String name = new UTF8StringRef(); - public final Pointer aliases = new Pointer(); - public final Signed32 proto = new Signed32(); - } - - public static interface LibProto { - UnixProtoent getprotobyname(String name); - UnixProtoent getprotobynumber(int proto); - UnixProtoent getprotoent(); - void endprotoent(); - } - - private final Protocol protocolFromNative(UnixProtoent p) { - if (p == null) { - return null; - } - - List<String> emptyAliases = Collections.emptyList(); - - Pointer ptr; - final Collection<String> aliases = ((ptr = p.aliases.get()) != null) - ? StringUtil.getNullTerminatedStringArray(ptr) : emptyAliases; - - return new Protocol(p.name.get(), (short) p.proto.get(), aliases); - } - - public Protocol getProtocolByName(String name) { - return protocolFromNative(lib.getprotobyname(name)); - } - - public Protocol getProtocolByNumber(Integer proto) { - return protocolFromNative(lib.getprotobynumber(proto)); - } - - public Collection<Protocol> getAllProtocols() { - UnixProtoent p; - List<Protocol> allProtocols = new ArrayList<Protocol>(); - - try { - while ((p = lib.getprotoent()) != null) { - allProtocols.add(protocolFromNative(p)); - } - } finally { - lib.endprotoent(); - } - - return allProtocols; - } -} diff --git a/src/jnr/netdb/NativeServicesDB.java b/src/jnr/netdb/NativeServicesDB.java deleted file mode 100644 index a45d9ae3bbe4c4fa571d0dfcb0280980666288c7..0000000000000000000000000000000000000000 --- a/src/jnr/netdb/NativeServicesDB.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2010 Wayne Meissner - * - * This file is part of jnr. - * - * 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 jnr.netdb; - -import com.kenai.jaffl.CallingConvention; -import com.kenai.jaffl.Library; -import com.kenai.jaffl.LibraryOption; -import com.kenai.jaffl.Platform; -import com.kenai.jaffl.Pointer; -import java.nio.ByteOrder; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static com.kenai.jaffl.Platform.OS.*; - -/** - * - */ -final class NativeServicesDB implements ServicesDB { - - private final LibServices lib; - - public NativeServicesDB(LibServices lib) { - this.lib = lib; - } - - public static final NativeServicesDB getInstance() { - return SingletonHolder.INSTANCE; - } - - private static final class SingletonHolder { - public static final NativeServicesDB INSTANCE = load(); - } - - static final NativeServicesDB load() { - try { - Platform.OS os = Platform.getPlatform().getOS(); - - // The ServiceEntry struct is only known to match on Windows, MacOSX, Linux, Solaris. - // We assume FreeBSD and NetBSD also match. - if (!(os.equals(DARWIN) || (os.equals(WINDOWS) && Platform.getPlatform().getCPU() == Platform.CPU.I386) - || os.equals(LINUX) || os.equals(SOLARIS) - || os.equals(FREEBSD) || os.equals(NETBSD))) { - return null; - } - - LibServices lib; - if (os.equals(WINDOWS)) { - Map<LibraryOption, Object> options = new HashMap<LibraryOption, Object>(); - options.put(LibraryOption.CallingConvention, CallingConvention.STDCALL); - lib = Library.loadLibrary(LibServices.class, options, "Ws2_32"); - } else { - String[] libnames = os.equals(SOLARIS) - ? new String[] { "socket", "nsl", "c" } - : new String[] { "c" }; - lib = Library.loadLibrary(LibServices.class, libnames); - } - - // Try to lookup a service to make sure the library loaded and found the functions - lib.getservbyname("bootps", "udp"); - lib.getservbyport(67, "udp"); - - return new NativeServicesDB(lib); - } catch (Throwable t) { - Logger.getLogger(NativeServicesDB.class.getName()).log(Level.WARNING, "Failed to load native services db", t); - return null; - } - } - - public static class UnixServent extends com.kenai.jaffl.struct.Struct { - public final String name = new UTF8StringRef(); - public final Pointer aliases = new Pointer(); - public final Signed32 port = new Signed32(); - public final String proto = new UTF8StringRef(); - } - - public static interface LibServices { - UnixServent getservbyname(String name, String proto); - UnixServent getservbyport(Integer port, String proto); - UnixServent getservent(); - void endservent(); - } - - public Collection<Service> getAllServices() { - UnixServent s; - List<Service> allServices = new ArrayList<Service>(); - - try { - while ((s = lib.getservent()) != null) { - allServices.add(serviceFromNative(s)); - } - } finally { - lib.endservent(); - } - - return allServices; - } - - private final Service serviceFromNative(UnixServent s) { - if (s == null) { - return null; - } - - // servent#port is in network byte order - but jaffl will assume it is in host byte order - // so it needs to be reversed again to be correct. - int port = ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN) ? Short.reverseBytes((short) s.port.get()) : s.port.get(); - if (port < 0) { - // The s_port field is really an unsigned 16 bit quantity, but the - // byte flipping above will return numbers >= 32768 as a negative value, - // so they need to be converted back to a unsigned 16 bit value. - port = (int) ((port & 0x7FFF) + 0x8000); - } - - List<String> emptyAliases = Collections.emptyList(); - Pointer ptr; - final Collection<String> aliases = ((ptr = s.aliases.get()) != null) - ? StringUtil.getNullTerminatedStringArray(ptr) : emptyAliases; - - return s != null ? new Service(s.name.get(), port, s.proto.get(), aliases) : null; - } - - public Service getServiceByName(String name, String proto) { - return serviceFromNative(lib.getservbyname(name, proto)); - } - - public Service getServiceByPort(Integer port, String proto) { - int nport = ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN) ? Short.reverseBytes(port.shortValue()) : port.shortValue(); - - return serviceFromNative(lib.getservbyport(nport, proto)); - } - - -} diff --git a/src/jnr/netdb/FileProtocolsDB.java b/src/main/java/jnr/netdb/FileProtocolsDB.java similarity index 97% rename from src/jnr/netdb/FileProtocolsDB.java rename to src/main/java/jnr/netdb/FileProtocolsDB.java index 74297e8bd3d89e376db2fb29cf3085f5d510dbd9..c0e5e8e0a6ba84e495033ce6d2a4471dc1b87c55 100644 --- a/src/jnr/netdb/FileProtocolsDB.java +++ b/src/main/java/jnr/netdb/FileProtocolsDB.java @@ -28,9 +28,9 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; -import com.kenai.jaffl.Platform; +import jnr.ffi.Platform; -import static com.kenai.jaffl.Platform.OS.WINDOWS; +import static jnr.ffi.Platform.OS.WINDOWS; /** * @@ -51,7 +51,7 @@ class FileProtocolsDB implements ProtocolsDB { } private static final File locateProtocolsFile() { - if (Platform.getPlatform().getOS().equals(WINDOWS)) { + if (Platform.getNativePlatform().getOS().equals(WINDOWS)) { String systemRoot; try { // FIXME: %SystemRoot% is typically *not* present in Java env, diff --git a/src/jnr/netdb/FileServicesDB.java b/src/main/java/jnr/netdb/FileServicesDB.java similarity index 100% rename from src/jnr/netdb/FileServicesDB.java rename to src/main/java/jnr/netdb/FileServicesDB.java diff --git a/src/jnr/netdb/IANAProtocolsDB.java b/src/main/java/jnr/netdb/IANAProtocolsDB.java similarity index 100% rename from src/jnr/netdb/IANAProtocolsDB.java rename to src/main/java/jnr/netdb/IANAProtocolsDB.java diff --git a/src/jnr/netdb/IANAServicesDB.java b/src/main/java/jnr/netdb/IANAServicesDB.java similarity index 100% rename from src/jnr/netdb/IANAServicesDB.java rename to src/main/java/jnr/netdb/IANAServicesDB.java diff --git a/src/main/java/jnr/netdb/NativeProtocolsDB.java b/src/main/java/jnr/netdb/NativeProtocolsDB.java new file mode 100644 index 0000000000000000000000000000000000000000..4938771ef53170bd1774873ee0ed4c3d68c37f2f --- /dev/null +++ b/src/main/java/jnr/netdb/NativeProtocolsDB.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2010 Wayne Meissner + * + * This file is part of jnr. + * + * 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 jnr.netdb; + +import jnr.ffi.*; +import jnr.ffi.Runtime; +import jnr.ffi.annotations.Direct; + +import java.util.ArrayList; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static jnr.ffi.Platform.OS.*; + +/** + * + */ +abstract class NativeProtocolsDB implements ProtocolsDB { + + public static final NativeProtocolsDB getInstance() { + return SingletonHolder.INSTANCE; + } + + private static final class SingletonHolder { + public static final NativeProtocolsDB INSTANCE = load(); + } + + private static final NativeProtocolsDB load() { + try { + Platform.OS os = Platform.getNativePlatform().getOS(); + + // The protoent struct is only known to match on Windows, MacOSX, Linux, Solaris. + // We assume FreeBSD and NetBSD also match. + if (!(os.equals(DARWIN) || (os.equals(WINDOWS) && Platform.getNativePlatform().getCPU() == Platform.CPU.I386) + || os.equals(LINUX) || os.equals(SOLARIS) + || os.equals(FREEBSD) || os.equals(NETBSD))) { + return null; + } + + LibProto lib; + if (os.equals(WINDOWS)) { + Map<LibraryOption, Object> options = new HashMap<LibraryOption, Object>(); + options.put(LibraryOption.CallingConvention, CallingConvention.STDCALL); + lib = Library.loadLibrary(LibProto.class, options, "Ws2_32"); + } else { + String[] libnames = os.equals(SOLARIS) + ? new String[]{"socket", "nsl", "c"} + : new String[]{"c"}; + lib = os.equals(LINUX) + ? Library.loadLibrary(LinuxLibProto.class, libnames) + : Library.loadLibrary(LibProto.class, libnames); + } + + NativeProtocolsDB protocolsDB = os.equals(LINUX) + ? new LinuxNativeProtocolsDB((LinuxLibProto) lib) + : new DefaultNativeProtocolsDB(lib); + // Try to lookup a protocol to make sure the library loaded and found the functions + protocolsDB.getProtocolByName("ip"); + protocolsDB.getProtocolByNumber(0); + + return protocolsDB; + } catch (Throwable t) { + Logger.getLogger(NativeProtocolsDB.class.getName()).log(Level.WARNING, "Failed to load native protocols db", t); + return null; + } + } + + public static class UnixProtoent extends jnr.ffi.Struct { + public final String name = new UTF8StringRef(); + public final Pointer aliases = new Pointer(); + public final Signed32 proto = new Signed32(); + + public UnixProtoent(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + + public static interface LibProto { + UnixProtoent getprotobyname(String name); + UnixProtoent getprotobynumber(int proto); + UnixProtoent getprotoent(); + void setprotoent(int stayopen); + void endprotoent(); + } + + public static interface LinuxLibProto extends LibProto{ + int getprotobyname_r(String proto, @Direct UnixProtoent protoent, Pointer buf, NativeLong buflen, Pointer result); + int getprotobynumber_r(int proto, @Direct UnixProtoent protoent, Pointer buf, NativeLong buflen, Pointer result); + int getprotoent_r(@Direct UnixProtoent protoent, Pointer buf, NativeLong buflen, Pointer result); + } + + static Protocol protocolFromNative(UnixProtoent p) { + if (p == null) { + return null; + } + + List<String> emptyAliases = Collections.emptyList(); + + Pointer ptr; + final Collection<String> aliases = ((ptr = p.aliases.get()) != null) + ? StringUtil.getNullTerminatedStringArray(ptr) : emptyAliases; + + return new Protocol(p.name.get(), (short) p.proto.get(), aliases); + } + + static final class DefaultNativeProtocolsDB extends NativeProtocolsDB { + private final LibProto lib; + + DefaultNativeProtocolsDB(LibProto lib) { + this.lib = lib; + } + + public synchronized Protocol getProtocolByName(String name) { + return protocolFromNative(lib.getprotobyname(name)); + } + + public synchronized Protocol getProtocolByNumber(Integer proto) { + return protocolFromNative(lib.getprotobynumber(proto)); + } + + public synchronized Collection<Protocol> getAllProtocols() { + UnixProtoent p; + List<Protocol> allProtocols = new ArrayList<Protocol>(); + + lib.setprotoent(0); + try { + while ((p = lib.getprotoent()) != null) { + allProtocols.add(protocolFromNative(p)); + } + } finally { + lib.endprotoent(); + } + + return allProtocols; + } + } + + static final class LinuxNativeProtocolsDB extends NativeProtocolsDB { + private static final int BUFLEN = 4096; + private final Runtime runtime; + private final Pointer buf; + private final LinuxLibProto lib; + + + LinuxNativeProtocolsDB(LinuxLibProto lib) { + this.lib = lib; + this.runtime = Library.getRuntime(lib); + this.buf = Memory.allocateDirect(runtime, BUFLEN); + } + + public synchronized Protocol getProtocolByName(String name) { + UnixProtoent protoent = new UnixProtoent(runtime); + Pointer result = Memory.allocateDirect(runtime, runtime.addressSize()); + if (lib.getprotobyname_r(name, protoent, buf, new NativeLong(BUFLEN), result) == 0) { + return result.getPointer(0) != null ? protocolFromNative(protoent) : null; + } + + throw new RuntimeException("getprotobyname_r failed"); + } + + public synchronized Protocol getProtocolByNumber(Integer number) { + UnixProtoent protoent = new UnixProtoent(runtime); + Pointer result = Memory.allocateDirect(runtime, runtime.addressSize()); + if (lib.getprotobynumber_r(number, protoent, buf, new NativeLong(BUFLEN), result) == 0) { + return result.getPointer(0) != null ? protocolFromNative(protoent) : null; + } + + throw new RuntimeException("getprotobynumber_r failed"); + } + + public synchronized Collection<Protocol> getAllProtocols() { + UnixProtoent p = new UnixProtoent(runtime); + List<Protocol> allProtocols = new ArrayList<Protocol>(); + Pointer result = Memory.allocateDirect(runtime, runtime.addressSize()); + NativeLong buflen = new NativeLong(BUFLEN); + + lib.setprotoent(0); + try { + while (lib.getprotoent_r(p, buf, buflen, result) == 0 && result.getPointer(0) != null) { + allProtocols.add(protocolFromNative(p)); + } + } finally { + lib.endprotoent(); + } + + return allProtocols; + } + } +} diff --git a/src/main/java/jnr/netdb/NativeServicesDB.java b/src/main/java/jnr/netdb/NativeServicesDB.java new file mode 100644 index 0000000000000000000000000000000000000000..f5bc1da20b596f0f0bb9b04eed05118cec6ae83a --- /dev/null +++ b/src/main/java/jnr/netdb/NativeServicesDB.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2010 Wayne Meissner + * + * This file is part of jnr. + * + * 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 jnr.netdb; + +import jnr.ffi.*; +import jnr.ffi.Runtime; +import jnr.ffi.annotations.Direct; +import jnr.ffi.annotations.Out; + +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static jnr.ffi.Platform.OS.*; + +/** + * + */ +abstract class NativeServicesDB implements ServicesDB { + + protected final LibServices lib; + + public NativeServicesDB(LibServices lib) { + this.lib = lib; + } + + public static final NativeServicesDB getInstance() { + return SingletonHolder.INSTANCE; + } + + private static final class SingletonHolder { + public static final NativeServicesDB INSTANCE = load(); + } + + static final NativeServicesDB load() { + try { + Platform.OS os = Platform.getNativePlatform().getOS(); + + // The ServiceEntry struct is only known to match on Windows, MacOSX, Linux, Solaris. + // We assume FreeBSD and NetBSD also match. + if (!(os.equals(DARWIN) || (os.equals(WINDOWS) && Platform.getNativePlatform().getCPU() == Platform.CPU.I386) + || os.equals(LINUX) || os.equals(SOLARIS) + || os.equals(FREEBSD) || os.equals(NETBSD))) { + return null; + } + + LibServices lib; + if (os.equals(WINDOWS)) { + Map<LibraryOption, Object> options = new HashMap<LibraryOption, Object>(); + options.put(LibraryOption.CallingConvention, CallingConvention.STDCALL); + lib = Library.loadLibrary(LibServices.class, options, "Ws2_32"); + + } else { + String[] libnames = os.equals(SOLARIS) + ? new String[] { "socket", "nsl", "c" } + : new String[] { "c" }; + + if (os.equals(LINUX)) { + lib = Library.loadLibrary(LinuxLibServices.class, libnames); + } else { + lib = Library.loadLibrary(LibServices.class, libnames); + } + } + + NativeServicesDB services = os.equals(LINUX) + ? new LinuxServicesDB(lib) + : new DefaultNativeServicesDB(lib); + // Try to lookup a service to make sure the library loaded and found the functions + if (services.getServiceByName("comsat", "udp") == null) { + return null; + } + services.getServiceByName("bootps", "udp"); + services.getServiceByPort(67, "udp"); + + return services; + + } catch (Throwable t) { + Logger.getLogger(NativeServicesDB.class.getName()).log(Level.WARNING, "Failed to load native services db", t); + return null; + } + } + + public static class UnixServent extends jnr.ffi.Struct { + public final String name = new UTF8StringRef(); + public final Pointer aliases = new Pointer(); + public final Signed32 port = new Signed32(); + public final String proto = new UTF8StringRef(); + + public UnixServent(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + + public static class LinuxServent extends UnixServent { + public static final int BUFLEN = 4096; + public final jnr.ffi.Pointer buf; + + public LinuxServent(jnr.ffi.Runtime runtime) { + super(runtime); + this.buf = Memory.allocateDirect(runtime, BUFLEN, true); + } + } + + public static interface LibServices { + UnixServent getservbyname(String name, String proto); + UnixServent getservbyport(Integer port, String proto); + UnixServent getservent(); + void endservent(); + } + + public static interface LinuxLibServices extends LibServices { + int getservbyname_r(String name, String proto, @Direct UnixServent servent, + Pointer buf, NativeLong buflen, @Out Pointer result); + int getservbyport_r(Integer port, String proto, @Direct UnixServent servent, + Pointer buf, NativeLong buflen, @Out Pointer result); + int getservent_r(@Direct UnixServent servent, + Pointer buf, NativeLong buflen, Pointer result); + } + + static int ntohs(int value) { + int hostValue = ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN) ? Short.reverseBytes((short) value) : value; + if (hostValue < 0) { + // The byte flipping above will return numbers >= 32768 as a negative value, + // so they need to be converted back to a unsigned 16 bit value. + hostValue = ((hostValue & 0x7FFF) + 0x8000); + } + + return hostValue; + } + + static int htons(int value) { + return ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN) ? Short.reverseBytes((short) value) : value; + } + + static Service serviceFromNative(UnixServent s) { + if (s == null) { + return null; + } + + List<String> emptyAliases = Collections.emptyList(); + Pointer ptr; + final Collection<String> aliases = ((ptr = s.aliases.get()) != null) + ? StringUtil.getNullTerminatedStringArray(ptr) : emptyAliases; + + return new Service(s.name.get(), ntohs(s.port.get()), s.proto.get(), aliases); + } + + static final class DefaultNativeServicesDB extends NativeServicesDB { + DefaultNativeServicesDB(LibServices lib) { + super(lib); + } + + public Collection<Service> getAllServices() { + UnixServent s; + List<Service> allServices = new ArrayList<Service>(); + + try { + while ((s = lib.getservent()) != null) { + allServices.add(serviceFromNative(s)); + } + } finally { + lib.endservent(); + } + + return allServices; + } + + + public Service getServiceByName(String name, String proto) { + return serviceFromNative(lib.getservbyname(name, proto)); + } + + public Service getServiceByPort(Integer port, String proto) { + return serviceFromNative(lib.getservbyport(htons(port), proto)); + } + } + + static final class LinuxServicesDB extends NativeServicesDB { + private static final int BUFLEN = 4096; + private final LinuxLibServices lib; + private final Runtime runtime; + private final Pointer buf; + + LinuxServicesDB(LibServices lib) { + super(lib); + this.lib = (LinuxLibServices) lib; + this.runtime = Library.getRuntime(lib); + this.buf = Memory.allocateDirect(runtime, BUFLEN); + } + + public synchronized Service getServiceByName(String name, String proto) { + UnixServent servent = new UnixServent(runtime); + Pointer result = Memory.allocateDirect(runtime, runtime.addressSize()); + if (lib.getservbyname_r(name, proto, servent, buf, new NativeLong(BUFLEN), result) == 0) { + return result.getPointer(0) != null ? serviceFromNative(servent) : null; + } + + throw new RuntimeException("getservbyname_r failed"); + } + + public synchronized Service getServiceByPort(Integer port, String proto) { + UnixServent servent = new UnixServent(runtime); + Pointer result = Memory.allocateDirect(runtime, runtime.addressSize()); + if (lib.getservbyport_r(htons(port), proto, servent, buf, new NativeLong(BUFLEN), result) == 0) { + return result.getPointer(0) != null ? serviceFromNative(servent) : null; + } + + throw new RuntimeException("getservbyport_r failed"); + } + + public synchronized Collection<Service> getAllServices() { + UnixServent s = new UnixServent(runtime); + List<Service> allServices = new ArrayList<Service>(); + Pointer result = Memory.allocateDirect(runtime, runtime.addressSize()); + NativeLong buflen = new NativeLong(BUFLEN); + + try { + while (lib.getservent_r(s, buf, buflen, result) == 0 && result.getPointer(0) != null) { + allServices.add(serviceFromNative(s)); + } + } finally { + lib.endservent(); + } + + return allServices; + } + } + +} diff --git a/src/jnr/netdb/NetDBEntry.java b/src/main/java/jnr/netdb/NetDBEntry.java similarity index 100% rename from src/jnr/netdb/NetDBEntry.java rename to src/main/java/jnr/netdb/NetDBEntry.java diff --git a/src/jnr/netdb/NetDBFilter.java b/src/main/java/jnr/netdb/NetDBFilter.java similarity index 100% rename from src/jnr/netdb/NetDBFilter.java rename to src/main/java/jnr/netdb/NetDBFilter.java diff --git a/src/jnr/netdb/NetDBIterator.java b/src/main/java/jnr/netdb/NetDBIterator.java similarity index 100% rename from src/jnr/netdb/NetDBIterator.java rename to src/main/java/jnr/netdb/NetDBIterator.java diff --git a/src/jnr/netdb/NetDBParser.java b/src/main/java/jnr/netdb/NetDBParser.java similarity index 100% rename from src/jnr/netdb/NetDBParser.java rename to src/main/java/jnr/netdb/NetDBParser.java diff --git a/src/jnr/netdb/Protocol.java b/src/main/java/jnr/netdb/Protocol.java similarity index 100% rename from src/jnr/netdb/Protocol.java rename to src/main/java/jnr/netdb/Protocol.java diff --git a/src/jnr/netdb/ProtocolsDB.java b/src/main/java/jnr/netdb/ProtocolsDB.java similarity index 100% rename from src/jnr/netdb/ProtocolsDB.java rename to src/main/java/jnr/netdb/ProtocolsDB.java diff --git a/src/jnr/netdb/Service.java b/src/main/java/jnr/netdb/Service.java similarity index 100% rename from src/jnr/netdb/Service.java rename to src/main/java/jnr/netdb/Service.java diff --git a/src/jnr/netdb/ServicesDB.java b/src/main/java/jnr/netdb/ServicesDB.java similarity index 100% rename from src/jnr/netdb/ServicesDB.java rename to src/main/java/jnr/netdb/ServicesDB.java diff --git a/src/jnr/netdb/StringUtil.java b/src/main/java/jnr/netdb/StringUtil.java similarity index 77% rename from src/jnr/netdb/StringUtil.java rename to src/main/java/jnr/netdb/StringUtil.java index ba5b963021d7efb82ad937232b69cdbb26512f35..86a0d8228a9f495ae328840f132c0b7651065dd9 100644 --- a/src/jnr/netdb/StringUtil.java +++ b/src/main/java/jnr/netdb/StringUtil.java @@ -18,8 +18,8 @@ package jnr.netdb; -import com.kenai.jaffl.Platform; -import com.kenai.jaffl.Pointer; +import jnr.ffi.Platform; +import jnr.ffi.Pointer; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -28,20 +28,19 @@ import java.util.List; * Utility class for native strings */ class StringUtil { - public static final int POINTER_SIZE = Platform.getPlatform().addressSize() / 8; public static final List<String> getNullTerminatedStringArray(Pointer ptr) { - Pointer p; - // If it is an empty list, do not allocate an empty ArrayList for it - if ((p = ptr.getPointer(0)) == null) { + if (ptr == null || ptr.getPointer(0) == null) { return Collections.emptyList(); } + final int pointerSize = ptr.getRuntime().addressSize(); + List<String> array = new ArrayList<String>(); - array.add(p.getString(0)); - - for (int off = POINTER_SIZE; (p = ptr.getPointer(off)) != null; off += POINTER_SIZE) { + + Pointer p; + for (int off = 0; (p = ptr.getPointer(off)) != null; off += pointerSize) { array.add(p.getString(0)); } diff --git a/test/jnr/netdb/FileProtocolDBTest.java b/src/test/java/jnr/netdb/FileProtocolDBTest.java similarity index 100% rename from test/jnr/netdb/FileProtocolDBTest.java rename to src/test/java/jnr/netdb/FileProtocolDBTest.java diff --git a/test/jnr/netdb/FileServicesDBTest.java b/src/test/java/jnr/netdb/FileServicesDBTest.java similarity index 100% rename from test/jnr/netdb/FileServicesDBTest.java rename to src/test/java/jnr/netdb/FileServicesDBTest.java diff --git a/test/jnr/netdb/NativeProtocolsDBTest.java b/src/test/java/jnr/netdb/NativeProtocolsDBTest.java similarity index 100% rename from test/jnr/netdb/NativeProtocolsDBTest.java rename to src/test/java/jnr/netdb/NativeProtocolsDBTest.java diff --git a/test/jnr/netdb/NativeServicesDBTest.java b/src/test/java/jnr/netdb/NativeServicesDBTest.java similarity index 93% rename from test/jnr/netdb/NativeServicesDBTest.java rename to src/test/java/jnr/netdb/NativeServicesDBTest.java index e2e37a511800269cfb37adef806b31634dc27915..6aee497e2b7602dd69726960c0a82f8a6743da26 100644 --- a/test/jnr/netdb/NativeServicesDBTest.java +++ b/src/test/java/jnr/netdb/NativeServicesDBTest.java @@ -1,7 +1,7 @@ package jnr.netdb; -import com.kenai.jaffl.Platform; +import jnr.ffi.Platform; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -34,7 +34,7 @@ public class NativeServicesDBTest { } @Test public void canLookupServiceThan32768ByName() { - if (Platform.getPlatform().getOS().equals(Platform.OS.DARWIN)) { + if (Platform.getNativePlatform().getOS().equals(Platform.OS.DARWIN)) { ServicesDB db = NativeServicesDB.load(); Service s = db.getServiceByName("blp5", "udp"); assertNotNull("could not lookup blp5 service", s); @@ -44,7 +44,7 @@ public class NativeServicesDBTest { } @Test public void canLookupServiceLargerThan32768ByPort() { - if (Platform.getPlatform().getOS().equals(Platform.OS.DARWIN)) { + if (Platform.getNativePlatform().getOS().equals(Platform.OS.DARWIN)) { ServicesDB db = NativeServicesDB.load(); Service s = db.getServiceByPort(48129, "udp"); assertNotNull("could not lookup blp5 service", s); diff --git a/test/jnr/netdb/ProtocolTest.java b/src/test/java/jnr/netdb/ProtocolTest.java similarity index 100% rename from test/jnr/netdb/ProtocolTest.java rename to src/test/java/jnr/netdb/ProtocolTest.java diff --git a/test/jnr/netdb/ServiceTest.java b/src/test/java/jnr/netdb/ServiceTest.java similarity index 100% rename from test/jnr/netdb/ServiceTest.java rename to src/test/java/jnr/netdb/ServiceTest.java