Managing UNIX Domain Sockets on FreeBSD providing MySQL connectivity with Java

I. Introduction

Connecting a Java application to a MySQL database is a rather easy job: you configure a mysql-connector, you pass some settings and you’re good to go. However, in a rare occasion the mysql daemon is only allowing UNIX Domain Sockets to connect. The official MySQL connector only provides TCP/IP connectivity and Java has no out-of-the-box support for UNIX Domain Sockets. So when you connect like you would normally do, you will get an exception:

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
Last packet sent to the server was 0 ms ago.

After an extensive search I found JUnixSocket. JUnixSocketis a Java/JNI library that allows the use of Unix Domain Sockets (AF_UNIX sockets) from Java.

In contrast to other implementations, junixsocket extends the Java Sockets API (java.net.Socket, java.net.SocketAddress etc.) and even supports RMI over AF_UNIX. It is also possible to use it in conjunction with Connector/J to connect to a local MySQL server via Unix domain sockets.

The JUnixSocket Package  contains the jar files that are needed to use UNIX Domain Sockets and to provide connectivity with MySQL through such a socket. It also contains the native library for Darwin (Mac) and Linux which is needed to manage the sockets.

A uname -a told me that I was running FreeBSD amd64 (so not a i386 version) but I had no idea if I required the Darwin or the Linux library since both operating systems are related to FreeBSD, so I uploaded both the .so (Shared Object) files.

II. Getting Started

The first step is to update and prepare your Java Application to use the JUnixSocket library. With Eclipse it’s easy to refer to external jar files in your project. For this project you need the standard archive (junixsocket-1.3.jar) and the mysql archive (junixsocket-mysql-1.3.jar):

  • Download & extract the JUnixSocket Package
  • In Eclipse, right-click on your project and select Build Path > Configure Build Path…
  • In the tab Libraries select Add External JARs…
  • Select junixsocket-1.3.jar & junixsocket-mysql-1.3.jar
  • In your connection class add the following imports:

import java.util.Properties;
import org.newsclub.net.mysql.*;

Update your code so the JDBC connection will use a UNIX Domain Socket to connect to the MySQL Server. An example of a connection class is shown below. I will be using the /tmp/mysql.sock file to connect.

public class MySQL {
    String ConnectionString = "jdbc:mysql://localhost/MyDatabase";
    String Username = "MyUsername";
    String Password = "MyPassword";
    public MySQL() {
    }
    public void ExecuteQuery() {
    try {
        Connection connection = null;
        Statement statement = null;
        Class.forName ("com.mysql.jdbc.Driver").newInstance ();
        Properties props = new Properties();
        props.put("user", Username);
        props.put("password", Password);
        props.put("socketFactory", AFUNIXDatabaseSocketFactory.class.getName());
        props.put("junixsocket.file", "/tmp/mysql.sock");
        connection = DriverManager.getConnection(ConnectionString, props);
        statement = connection.createStatement();
        statement.executeUpdate("INSERT INTO books (id, title) VALUES (4, 'Bible')");
        statement.close();
        connection.close();
    }
    catch (Exception ex)
    {
        ex.printStackTrace();
    }
    }
}

Next, upload libjunixsocket-linux-1.5-amd64.so and libjunixsocket-macosx-1.5-x86_64.dylib to the server (or the i386 files if you’re running the i386 version of FreeBSD). You can now run and test your program.

III. Troubleshooting

Now this is where the fun part starts. After I launched the Java Application I got the following error:

java.lang.UnsatisfiedLinkError: Could not load junixsocket library, tried [/opt/newsclub/lib-native/libjunixsocket-freebsd-1.6-amd64.so, /opt/newsclub/lib-native/libjunixsocket-freebsd-1.5-amd64.so, lib:junixsocket-freebsd-1.6-amd64, lib:junixsocket-freebsd-1.5-amd64]; please define system property org.newsclub.net.unix.library.path

So we must tell the Java Virtual Machine where to look for the library files. You need to add 2 entries in your connection class:

System.setProperty("org.newsclub.net.unix.library.path", "/home/Brecht/lib-native/");
props.put("org.newsclub.net.unix.library.path", "/home/Brecht/lib-native/");

Now both the JVM and the UNIX Domain Socket JNI Wrapper will know where to look for the library files. After another launch of the application the following exception occured:

java.lang.UnsatisfiedLinkError: Could not load junixsocket library, tried [/home/Brecht/lib-native/libjunixsocket-freebsd-1.6-amd64.so, /home/Brecht/lib-native/libjunixsocket-freebsd-1.5-amd64.so, lib:junixsocket-freebsd-1.6-amd64, lib:junixsocket-freebsd-1.5-amd64]; please define system property org.newsclub.net.unix.library.path

Hm, that’s strange.. But wait a minute! There are no such files: only the library files for Linux and Darwin were supplied! You can skip the Darwin files, the system is obviously wanting .so files. Since Linux and FreeBSD are very much alike, I gave it a shot and renamed the libjunixsocket-linux-1.5-amd64.so file to libjunixsocket-freebsd-1.5-amd64.so. Let’s try again..

java.lang.UnsatisfiedLinkError: /home/Brecht/lib-native/libjunixsocket-freebsd-1.5-amd64.so: Shared object "libc.so.6" not found, required by "libjunixsocket-freebsd-1.5-amd64.so"

Since I’m running FreeBSD 8.x, the only libc.so file on the system is libc.so.7 which is a more recent version of the libc.so.6 file. I downloaded a random libc.so.6 file of the internet but that didn’t work out very well:

java.lang.UnsatisfiedLinkError: /home/Brecht/lib-native/libjunixsocket-freebsd-1.5-amd64.so: /home/Brecht/lib-native/libc.so.6: unsupported machine

Maybe it’s possible to copy the system library libc.so.7 and rename it to libc.so.6 and hope for the best.

java.lang.UnsatisfiedLinkError: /home/Brecht/lib-native/libjunixsocket-freebsd-1.5-amd64.so: /home/Brecht/lib-native//libc.so.6: version GLIBC_2.2.5 required by /home/Brecht/lib-native/libjunixsocket-freebsd-1.5-amd64.so not found

At least we’re getting some information back.  On this site I searched for packages that contain libc.so.6 version GLIBC_2.2.5. I downloaded the binary package at http://pkgs.org/centos-5-rhel-5/centos-rhel-x86_64/glibc-2.5-58.x86_64.rpm.html

I extracted and uploaded all the library files (I guessed I would be needing more files than this one). Then I tried to run the project again.

java.lang.UnsatisfiedLinkError: /home/Brecht/lib-native/libjunixsocket-freebsd-1.5-amd64.so: Shared object has no run-time symbol table

I really had no idea what this meant and all I could find was that something wasn’t compiled correctly.

IV. Compiling your own Shared Object Library files

It seems the inevitable has happened: I needed to compile my own JUnixSocket library files for FreeBSD. First of all I downloaded the source files from the JUnixSocket website. I read the Building From Source section and started the ant compiler to compile the project with the default build.xml file, except that I changed the path to the junit jar file. The project should compile on FreeBSD as it got a special FreeBSD patch about a year ago.

However the ant build failed with the default build.xml so I edited a couple of things to make it compile without any errors. My build.xml file can be downloaded here. The result was libjunixsocket-freebsd-1.5-amd64.so. I uploaded the file to the server and ran the project one more time.

SUCCES!

V. Resources:

Verifying SSL Certificates with Java on FreeBSD

Creating SSL sockets in java is pretty much the same as creating regular non-SSL sockets.

SocketFactory socketFactory = SSLSocketFactory.getDefault();
Socket socket =  socketFactory.createSocket(hostname, port);

The Java Virtual Machine will now try to validate the SSL certificate which is needed for the secure connection. To verify if the current certificate is signed by a valid Certificate Authority, the JVM has a file called cacerts which contains all root certificates. However some custom JDKs do not contain this file, or dont allow access to it. Such an example is the preinstalled JDK on Amazon Elastic Compute Cloud (Amazon EC2). Another example is the Diablo JDK on FreeBSD. The Diablo JDK is a port provided by the FreeBSD Foundation.

When a SSLSocketFactory from one of those JDKs is used you will get an error when trying to validate the SSL certificate.

java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

The reason for this is that truststore can’t be accessed. The truststore is a keystore which is used when making decisions about what and who to trust. If you receive some data from an entity that you already trust, and if you can verify that the entity is the one it claims to be, then you can assume that the data really came from that entity. If the truststore file can’t be accessed (either because it’s empty or you don’t have access to it) it’s impossible to authenticate any Certificate Authority meaning it’s never possible to establish a secure connection.

A quick (yes, also dirty) solution to this problem is to specify another cacerts file and supply the path to the compiler. In this case the specified cacerts file will be used for certificate validation. The cacerts file in the Windows JDK and the standard Sun JDK for Linux should do just fine, if granted the proper access.

java -Djavax.net.ssl.trustStore=/home/Brecht/mycacerts

In addition the cacerts file can be downloaded here.