package org.mariadb.jdbc.internal.mysql;
|
|
import com.sun.jna.LastErrorException;
|
import com.sun.jna.Native;
|
import com.sun.jna.Platform;
|
import com.sun.jna.Structure;
|
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.OutputStream;
|
import java.net.Socket;
|
import java.net.SocketAddress;
|
import java.util.Arrays;
|
import java.util.List;
|
|
public class UnixDomainSocket extends Socket
|
{
|
static public final int AF_UNIX = 1;
|
static public final int SOCK_STREAM = Platform.isSolaris () ? 2 : 1;
|
static public final int PROTOCOL = 0;
|
|
static public class SockAddr extends Structure
|
{
|
public short sun_family = 0;
|
public byte[] sun_path = null;
|
|
public SockAddr (String sunPath)
|
{
|
byte[] arr = sunPath.getBytes ();
|
int size = arr.length;
|
|
sun_family = AF_UNIX;
|
sun_path = new byte[size +1];
|
sun_path[size] = (byte) 0;
|
|
System.arraycopy (arr, 0, sun_path, 0, size);
|
allocateMemory ();
|
}
|
|
@Override
|
protected List getFieldOrder ()
|
{
|
return Arrays.asList (new String[] {"sun_family", "sun_path"});
|
}
|
}
|
|
static public native int socket (int domain, int type, int protocol) throws LastErrorException;
|
static public native int connect (int sockfd, SockAddr sockaddr, int addrlen) throws LastErrorException;
|
static public native int recv (int fd, byte[] buffer, int count, int flags) throws LastErrorException;
|
static public native int send (int fd, byte[] buffer, int count, int flags) throws LastErrorException;
|
static public native int close (int fd) throws LastErrorException;
|
|
static public native String strerror (int errno);
|
|
static
|
{
|
if (Platform.isSolaris ())
|
{
|
System.loadLibrary ("nsl");
|
System.loadLibrary ("socket");
|
}
|
|
if (!Platform.isWindows () && !Platform.isWindowsCE ())
|
{
|
Native.register ("c");
|
}
|
}
|
|
protected String path = null;
|
protected InputStream is = null;
|
protected OutputStream os = null;
|
protected SockAddr sockaddr = null;
|
protected int fd = -1;
|
|
protected class UnixSocketInputStream extends InputStream
|
{
|
@Override
|
public int read (byte[] b,
|
int off,
|
int len) throws IOException
|
{
|
int bytes = 0;
|
|
try
|
{
|
if (off > 0)
|
{
|
int size = (len < 10240) ? len : 10240;
|
byte[] data = new byte[size];
|
|
do
|
{
|
size = (len < 10240) ? len : 10240;
|
size = recv (fd, data, size, 0);
|
|
if (size > 0)
|
{
|
System.arraycopy (data, 0, b, off, size);
|
|
bytes += size;
|
off += size;
|
len -= size;
|
}
|
|
} while ((len > 0) && (size > 0));
|
}
|
else
|
{
|
bytes = recv (fd, b, len, 0);
|
}
|
}
|
|
catch (LastErrorException lee)
|
{
|
throw new IOException ("native read() failed : " + formatError( lee));
|
}
|
|
return (bytes);
|
}
|
|
@Override
|
public int read () throws IOException
|
{
|
byte[] b = new byte[1];
|
int bytes = read (b);
|
|
return ((bytes == 1) ? b[0] : -1);
|
}
|
|
@Override
|
public int read (byte[] b) throws IOException
|
{
|
return read (b, 0, b.length);
|
}
|
}
|
|
class UnixSocketOutputStream extends OutputStream
|
{
|
@Override
|
public void write (byte[] b,
|
int off,
|
int len) throws IOException
|
{
|
int bytes = 0;
|
|
try
|
{
|
if (off > 0)
|
{
|
int size = (len < 10240) ? len : 10240;
|
byte[] data = new byte[size];
|
|
do
|
{
|
size = (len < 10240) ? len : 10240;
|
|
System.arraycopy (b, off,
|
data, 0, size);
|
|
bytes = send (fd, data, size, 0);
|
|
if (bytes > 0)
|
{
|
off += bytes;
|
len -= bytes;
|
|
}
|
|
} while ((len > 0) && (bytes > 0));
|
}
|
else
|
{
|
bytes = send (fd, b, len ,0);
|
}
|
|
if (bytes != len)
|
{
|
throw new IOException ("can't write " + len + "bytes");
|
}
|
}
|
|
catch (LastErrorException lee)
|
{
|
throw new IOException ("native write() failed : " + formatError (lee));
|
}
|
}
|
|
@Override
|
public void write (int b) throws IOException
|
{
|
write (new byte[]{(byte) b});
|
}
|
|
@Override
|
public void write (byte[] b) throws IOException
|
{
|
write (b, 0, b.length);
|
}
|
}
|
|
static String formatError(LastErrorException lee)
|
{
|
String estr = null;
|
|
try
|
{
|
estr = strerror (lee.getErrorCode ());
|
}
|
|
catch (Throwable t)
|
{
|
estr = lee.getMessage ();
|
}
|
|
return (estr);
|
}
|
|
|
public UnixDomainSocket(String spath) throws IOException
|
{
|
if (Platform.isWindows() ||Platform.isWindowsCE())
|
{
|
throw new IOException("Unix domain sockets are not supported on Windows");
|
}
|
|
path = spath;
|
sockaddr = new SockAddr (path);
|
|
try
|
{
|
fd = socket (AF_UNIX,
|
SOCK_STREAM,
|
PROTOCOL);
|
}
|
|
catch ( LastErrorException lee)
|
{
|
throw new IOException ("native socket() failed : " + formatError (lee));
|
}
|
}
|
|
@Override
|
public void close () throws IOException
|
{
|
if (fd >= 0)
|
{
|
int fdc = fd;
|
|
fd = -1;
|
|
try
|
{
|
close (fdc);
|
}
|
|
catch(LastErrorException lee)
|
{
|
throw new IOException ("native close() failed : " + formatError (lee));
|
}
|
}
|
}
|
|
@Override
|
public void connect(SocketAddress endpoint) throws IOException
|
{
|
connect (endpoint, 0);
|
}
|
|
@Override
|
public void connect(SocketAddress endpoint, int timeout) throws IOException
|
{
|
try
|
{
|
if (connect (fd, sockaddr, sockaddr.size ()) != 0)
|
{
|
throw new IOException(strerror(Native.getLastError()));
|
}
|
}
|
|
catch (LastErrorException lee)
|
{
|
throw new IOException ("native connect() failed : " + formatError (lee));
|
}
|
|
is = new UnixSocketInputStream ();
|
os = new UnixSocketOutputStream ();
|
}
|
|
@Override
|
public InputStream getInputStream ()
|
{
|
return (is);
|
}
|
|
@Override
|
public OutputStream getOutputStream ()
|
{
|
return (os);
|
}
|
|
@Override
|
public void setTcpNoDelay (boolean b)
|
{
|
}
|
|
@Override
|
public void setKeepAlive (boolean b)
|
{
|
}
|
|
@Override
|
public void setReceiveBufferSize (int size)
|
{
|
}
|
|
@Override
|
public void setSendBufferSize (int size)
|
{
|
}
|
|
@Override
|
public void setSoLinger (boolean b,
|
int i)
|
{
|
}
|
|
@Override
|
public void setSoTimeout (int timeout)
|
{
|
}
|
|
@Override
|
public void shutdownInput ()
|
{
|
}
|
|
@Override
|
public void shutdownOutput ()
|
{
|
}
|
}
|