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