Created
January 20, 2014 23:47
-
-
Save Downchuck/8531692 to your computer and use it in GitHub Desktop.
postgresql jna
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/build.xml b/build.xml | |
index 2b86a36..ddd235e 100644 | |
--- a/build.xml | |
+++ b/build.xml | |
@@ -45,6 +45,9 @@ | |
<include name="${package}/largeobject/**" /> | |
<include name="${package}/util/**" /> | |
+ | |
+ <include name="${package}/jna/**" /> | |
+ | |
<!-- | |
Each jdbcN subpackage is used only if the driver supports *at least* that | |
revision of JDBC. That is, a JDBC2 build uses only jdbc2, a JDBC3 build | |
diff --git a/org/postgresql/core/PGStream.java b/org/postgresql/core/PGStream.java | |
index fad4c12..a7b3443 100644 | |
--- a/org/postgresql/core/PGStream.java | |
+++ b/org/postgresql/core/PGStream.java | |
@@ -23,6 +23,8 @@ import org.postgresql.util.HostSpec; | |
import org.postgresql.util.PSQLState; | |
import org.postgresql.util.PSQLException; | |
+import org.postgresql.jna.UnixSocketFactory; | |
+ | |
/** | |
* Wrapper around the raw connection to the server that implements some basic | |
* primitives (reading/writing formatted data, doing string encoding, etc). | |
@@ -56,9 +58,17 @@ public class PGStream | |
{ | |
this.hostSpec = hostSpec; | |
- Socket socket = new Socket(); | |
- socket.connect(new InetSocketAddress(hostSpec.getHost(), hostSpec.getPort())); | |
- changeSocket(socket); | |
+ Socket socket = new Socket(); | |
+ if(hostSpec.getHost().startsWith("unix:")) { | |
+ UnixSocketFactory unixSocket = new UnixSocketFactory(); | |
+ String unixPath = hostSpec.getHost().substring(5); | |
+ socket = unixSocket.createSocket(unixPath, 0); | |
+ } | |
+ else { | |
+ socket.connect(new InetSocketAddress(hostSpec.getHost(), hostSpec.getPort())); | |
+ } | |
+ changeSocket(socket); | |
+ | |
setEncoding(Encoding.getJVMEncoding("US-ASCII")); | |
_int2buf = new byte[2]; | |
diff --git a/org/postgresql/core/v3/ConnectionFactoryImpl.java b/org/postgresql/core/v3/ConnectionFactoryImpl.java | |
index 3c7d332..0d2b9fc 100644 | |
--- a/org/postgresql/core/v3/ConnectionFactoryImpl.java | |
+++ b/org/postgresql/core/v3/ConnectionFactoryImpl.java | |
@@ -87,6 +87,9 @@ public class ConnectionFactoryImpl extends ConnectionFactory { | |
for (int whichHost = 0; whichHost < hostSpecs.length; ++whichHost) { | |
HostSpec hostSpec = hostSpecs[whichHost]; | |
+ | |
+ String unixSocketPath = info.getProperty("unixSocket"); | |
+ if(unixSocketPath != null) hostSpec = new HostSpec(new String("unix:" + unixSocketPath), 0); | |
if (logger.logDebug()) | |
logger.debug("Trying to establish a protocol version 3 connection to " + hostSpec); | |
diff --git a/org/postgresql/jna/SockAddr.java b/org/postgresql/jna/SockAddr.java | |
new file mode 100644 | |
index 0000000..a357c42 | |
--- /dev/null | |
+++ b/org/postgresql/jna/SockAddr.java | |
@@ -0,0 +1,30 @@ | |
+/*------------------------------------------------------------------------- | |
+ * | |
+ * Copyright (c) 2003-2011, PostgreSQL Global Development Group | |
+ * | |
+ * | |
+ * Authors: J. Yunke, C. Pritchard. | |
+ *------------------------------------------------------------------------- | |
+ */ | |
+ | |
+package org.postgresql.jna; | |
+ | |
+import com.sun.jna.Structure; | |
+import java.util.List; | |
+import java.util.Arrays; | |
+ | |
+public class SockAddr extends Structure { | |
+ public short sa_family = 1; | |
+ public byte[] sa_data; | |
+ public SockAddr(final String path) { | |
+ byte[] bytes = path.getBytes(); | |
+ sa_data = new byte[bytes.length + 1]; | |
+ System.arraycopy(bytes, 0, sa_data, 0, bytes.length); | |
+ allocateMemory(); | |
+ } | |
+ @Override | |
+ protected List getFieldOrder() { | |
+ return Arrays.asList("sa_family", "sa_data"); | |
+ } | |
+} | |
+ | |
diff --git a/org/postgresql/jna/UnixSocket.java b/org/postgresql/jna/UnixSocket.java | |
new file mode 100644 | |
index 0000000..4d63c45 | |
--- /dev/null | |
+++ b/org/postgresql/jna/UnixSocket.java | |
@@ -0,0 +1,213 @@ | |
+/*------------------------------------------------------------------------- | |
+ * | |
+ * Copyright (c) 2003-2011, PostgreSQL Global Development Group | |
+ * | |
+ * | |
+ * Authors: J. Yunke, C. Pritchard. | |
+ *------------------------------------------------------------------------- | |
+ */ | |
+ | |
+package org.postgresql.jna; | |
+ | |
+// Windows not supported by UnixSocketFactory. | |
+import com.sun.jna.Platform; | |
+ | |
+// Exceptions. | |
+import java.io.IOException; | |
+import java.net.SocketException; | |
+import com.sun.jna.LastErrorException; | |
+ | |
+// Implementated interfaces. | |
+import java.net.Socket; | |
+import java.io.InputStream; | |
+import java.io.OutputStream; | |
+ | |
+// Utils. | |
+import java.nio.ByteBuffer; | |
+import java.io.BufferedInputStream; | |
+import java.io.BufferedOutputStream; | |
+import java.util.Arrays; | |
+ | |
+// Socket implementation exposing an InputStream and OutputStream. | |
+class UnixSocket extends Socket { | |
+ UnixSocketLibrary library = null; | |
+ int sockfd = -1; | |
+ public static final int AF_UNIX = 1; | |
+ public static final int SOCK_STREAM = 1; | |
+ public static final int PROTOCOL = 0; | |
+ | |
+ InputStream is = null; | |
+ OutputStream os = null; | |
+ | |
+ UnixSocket(UnixSocketLibrary library, SockAddr sockAddr) throws SocketException { | |
+ this.library = library; | |
+ this.sockfd = socket(AF_UNIX,SOCK_STREAM,PROTOCOL); | |
+ | |
+ try { | |
+ int i = connect(sockAddr,sockAddr.size()); | |
+ if (i != 0) { | |
+ throw new SocketException("UnixSocket(..): could not connect to socket"); | |
+ } | |
+ } catch (LastErrorException lee) { | |
+ throwSocketException("UnixSocket(..): could not connect to socket",lee); | |
+ } | |
+ | |
+ this.is = new BufferedInputStream(new UnixSocketInputStream(this)); | |
+ this.os = new BufferedOutputStream(new UnixSocketOutputStream(this)); | |
+ } | |
+ | |
+ protected void throwIOException(String prefixMessage, LastErrorException lee) throws IOException { | |
+ String strerror = library.strerror(lee.getErrorCode()); | |
+ throw new IOException(prefixMessage + ": " + strerror); | |
+ } | |
+ | |
+ protected void throwSocketException(String prefixMessage, LastErrorException lee) throws SocketException { | |
+ String strerror = library.strerror(lee.getErrorCode()); | |
+ throw new SocketException(prefixMessage + ": " + strerror); | |
+ } | |
+ | |
+ protected int socket(int domain, int type, int protocol) throws SocketException { | |
+ try { | |
+ int sockfd = this.library.socket(domain,type,protocol); | |
+ return sockfd; | |
+ } catch (LastErrorException lee) { | |
+ throwSocketException("socket(..): could not open socket",lee); | |
+ return -1; | |
+ } | |
+ } | |
+ | |
+ public int connect(SockAddr sockaddr, int addrlen) throws SocketException { | |
+ try { | |
+ int result = this.library.connect(this.sockfd,sockaddr,addrlen); | |
+ return result; | |
+ } catch (LastErrorException lee) { | |
+ throwSocketException("connect(..): could not connect to socket",lee); | |
+ return -1; | |
+ } | |
+ } | |
+ | |
+ public int read(byte[] buf, int count) throws IOException { | |
+ try { | |
+ ByteBuffer buffer = ByteBuffer.wrap(buf); | |
+ int length = this.library.read(this.sockfd,buffer,count); | |
+ return length; | |
+ } catch (LastErrorException lee) { | |
+ throwIOException("read(..): could not read from socket",lee); | |
+ return -1; | |
+ } | |
+ } | |
+ | |
+ public int write(byte[] buf, int count) throws IOException { | |
+ try { | |
+ ByteBuffer buffer = ByteBuffer.wrap(buf); | |
+ int length = this.library.write(this.sockfd,buffer,count); | |
+ return length; | |
+ } catch (LastErrorException lee) { | |
+ throwIOException("write(..): could not write to socket",lee); | |
+ return -1; | |
+ } | |
+ } | |
+ | |
+ | |
+ @Override | |
+ public InputStream getInputStream() throws IOException { | |
+ return is; | |
+ } | |
+ | |
+ @Override | |
+ public OutputStream getOutputStream() throws IOException { | |
+ return os; | |
+ } | |
+ | |
+ @Override | |
+ public void shutdownInput() throws IOException { | |
+ is = null; | |
+ } | |
+ | |
+ @Override | |
+ public void shutdownOutput() throws IOException { | |
+ os = null; | |
+ } | |
+ | |
+ @Override | |
+ public synchronized void close() throws IOException { | |
+ try { | |
+ shutdownInput(); | |
+ shutdownOutput(); | |
+ this.library.close(this.sockfd); | |
+ | |
+ } catch (LastErrorException lee) { | |
+ throwIOException("close(..): could not close socket",lee); | |
+ } | |
+ } | |
+} | |
+ | |
+class UnixSocketInputStream extends InputStream { | |
+ UnixSocket unixSocket = null; | |
+ | |
+ UnixSocketInputStream(UnixSocket unixSocket) { | |
+ this.unixSocket = unixSocket; | |
+ } | |
+ | |
+ @Override | |
+ public long skip(long n) throws IOException { | |
+ return -1; | |
+ } | |
+ | |
+ @Override | |
+ public int read(byte[] data, int offset, int length) throws IOException { | |
+ int readLength = 0; | |
+ if (offset != 0) { | |
+ throw new IOException("read(..): offset not implemented"); | |
+ } | |
+ readLength = this.unixSocket.read(data, length); | |
+ return readLength; | |
+ } | |
+ | |
+ @Override | |
+ public int read() throws IOException { | |
+ byte[] data = new byte[1]; | |
+ int read = read(data); | |
+ if (read == 0) return -1; | |
+ if (read != 1) { | |
+ throw new IOException("read(..): could not read one byte"); | |
+ } | |
+ return data[0] & 0xFF; | |
+ } | |
+ | |
+ @Override | |
+ public int read(byte[] data) throws IOException { | |
+ return read(data,0,data.length); | |
+ } | |
+ | |
+} | |
+ | |
+class UnixSocketOutputStream extends OutputStream { | |
+ UnixSocket unixSocket = null; | |
+ | |
+ UnixSocketOutputStream(UnixSocket unixSocket) { | |
+ this.unixSocket = unixSocket; | |
+ } | |
+ | |
+ @Override | |
+ public void write(byte[] data, int offset, int length) throws IOException { | |
+ if (offset != 0) data = Arrays.copyOfRange(data, offset, offset + length); | |
+ if (offset == 0) { | |
+ int writtenLength = this.unixSocket.write(data, length); | |
+ if (writtenLength != length) { | |
+ throw new IOException("write incomplete: length is " + length + " but only wrote " + writtenLength); | |
+ } | |
+ } | |
+ } | |
+ | |
+ @Override | |
+ public void write(int data) throws IOException { | |
+ write(new byte[] { (byte) data },0,1); | |
+ } | |
+ | |
+ @Override | |
+ public void write(byte[] data) throws IOException { | |
+ write(data,0,data.length); | |
+ } | |
+ | |
+} | |
diff --git a/org/postgresql/jna/UnixSocketFactory.java b/org/postgresql/jna/UnixSocketFactory.java | |
new file mode 100644 | |
index 0000000..4bea018 | |
--- /dev/null | |
+++ b/org/postgresql/jna/UnixSocketFactory.java | |
@@ -0,0 +1,90 @@ | |
+/*------------------------------------------------------------------------- | |
+ * | |
+ * Copyright (c) 2003-2011, PostgreSQL Global Development Group | |
+ * | |
+ * | |
+ * Authors: J. Yunke, C. Pritchard. | |
+ *------------------------------------------------------------------------- | |
+ */ | |
+ | |
+package org.postgresql.jna; | |
+ | |
+// Using JNA to access native sockets. | |
+import com.sun.jna.LastErrorException; | |
+import com.sun.jna.Library; | |
+import com.sun.jna.Native; | |
+import com.sun.jna.Structure; | |
+ | |
+// Windows not supported by UnixSocketFactory. | |
+import com.sun.jna.Platform; | |
+ | |
+// Exceptions. | |
+import java.io.IOException; | |
+import java.net.SocketException; | |
+ | |
+// Unix domain sockets have file entries. | |
+import java.io.File; | |
+ | |
+// Implementated interfaces. | |
+import javax.net.SocketFactory; | |
+import java.net.Socket; | |
+ | |
+import java.net.InetAddress; | |
+ | |
+public class UnixSocketFactory extends SocketFactory { | |
+ public static final String DEFAULT_LOCATION="/tmp/.s.PGSQL.5432"; | |
+ | |
+// JNA instance. | |
+ protected static boolean hasInstance = false; | |
+ protected static UnixSocketLibrary instance = null; | |
+ protected synchronized static void loadInstance() throws SocketException { | |
+ if (!hasInstance) { | |
+ if (Platform.isWindows() || Platform.isWindowsCE()) { | |
+ throw new SocketException("loadInstance(): Windows support for named sockets is not implemented."); | |
+ } | |
+ instance = (UnixSocketLibrary) Native.loadLibrary("c", UnixSocketLibrary.class); | |
+ hasInstance = true; | |
+ } | |
+ } | |
+ | |
+ @Override | |
+ public Socket createSocket(String host, int portNumber) throws SocketException, IOException { | |
+ if(!hasInstance) { | |
+ loadInstance(); | |
+ } | |
+ | |
+ String unixSocketPath = host; | |
+ if (unixSocketPath != null && !"".equals(unixSocketPath.trim())) { | |
+ File unixSocketFile = new File(unixSocketPath); | |
+ if (!unixSocketFile.exists()) { | |
+ throw new SocketException("connect(..): could not find Unix socket at \"" + unixSocketPath + "\""); | |
+ } | |
+ } else { | |
+ unixSocketPath = DEFAULT_LOCATION; | |
+ File unixSocketFile = new File(unixSocketPath); | |
+ if (!unixSocketFile.exists()) { | |
+ throw new SocketException("connect(..): could not find Unix socket in the default location \"" + DEFAULT_LOCATION + "\""); | |
+ } | |
+ } | |
+ | |
+ SockAddr sockAddr = new SockAddr(unixSocketPath); | |
+ Socket socket = new UnixSocket(instance,sockAddr); | |
+ return socket; | |
+ } | |
+ | |
+ @Override | |
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { | |
+ return createSocket("", 0); | |
+ } | |
+ | |
+ @Override | |
+ public Socket createSocket(InetAddress host, int port, InetAddress localHost, int localPort) throws IOException { | |
+ return createSocket("", 0); | |
+ } | |
+ | |
+ @Override | |
+ public Socket createSocket(InetAddress host, int port) throws IOException { | |
+ return createSocket("", 0); | |
+ } | |
+} | |
+ | |
diff --git a/org/postgresql/jna/UnixSocketLibrary.java b/org/postgresql/jna/UnixSocketLibrary.java | |
new file mode 100644 | |
index 0000000..60852de | |
--- /dev/null | |
+++ b/org/postgresql/jna/UnixSocketLibrary.java | |
@@ -0,0 +1,23 @@ | |
+/*------------------------------------------------------------------------- | |
+ * | |
+ * Copyright (c) 2003-2011, PostgreSQL Global Development Group | |
+ * | |
+ * | |
+ * Authors: J. Yunke, C. Pritchard. | |
+ *------------------------------------------------------------------------- | |
+ */ | |
+ | |
+package org.postgresql.jna; | |
+ | |
+import com.sun.jna.Library; | |
+import java.nio.ByteBuffer; | |
+ | |
+public interface UnixSocketLibrary extends Library { | |
+ public int socket(int domain, int type, int protocol); | |
+ public int connect(int sockfd, SockAddr sockaddr, int addrlen); | |
+ public int read(int fd, ByteBuffer buffer, int count); | |
+ public int write(int fd, ByteBuffer buffer, int count); | |
+ public int close(int fd); | |
+ public String strerror(int errno); | |
+} | |
+ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
cool! I have updated it to work as jdbc4 driver and on our test system works as expected.
https://github.com/kofemann/pgjdbc/tree/unix-domain-socket
If it's OK for you I will send a pool request to upstream developers.