blob: 4c8fd552a4eab79f013d26404f2e8749c0a96950 [file] [log] [blame]
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (c) 2012-2014 Monty Program Ab
// Copyright (c) 2015-2021 MariaDB Corporation Ab
package org.mariadb.jdbc.client.socket.impl;
import com.sun.jna.platform.win32.Kernel32;
import java.io.*;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.concurrent.TimeUnit;
/** Windows named pipe socket implementation */
@SuppressWarnings("UnnecessaryInitCause")
public class NamedPipeSocket extends Socket {
private final String host;
private final String name;
private RandomAccessFile file;
private InputStream is;
private OutputStream os;
/**
* Constructor
*
* @param host host
* @param name pipe name
*/
public NamedPipeSocket(String host, String name) {
this.host = host;
this.name = name;
}
@Override
public void close() throws IOException {
if (file != null) {
file.close();
file = null;
}
}
/**
* Name pipe connection.
*
* @param endpoint endPoint
* @param timeout timeout in milliseconds
* @throws IOException exception
*/
public void connect(SocketAddress endpoint, int timeout) throws IOException {
String filename =
String.format(
"\\\\%s\\pipe\\%s", (host == null || host.equals("localhost")) ? "." : host, name);
// use a default timeout of 100ms if no timeout set.
int usedTimeout = timeout == 0 ? 100 : timeout;
long initialNano = System.nanoTime();
do {
try {
file = new RandomAccessFile(filename, "rw");
break;
} catch (FileNotFoundException fileNotFoundException) {
try {
// using JNA if available
Kernel32.INSTANCE.WaitNamedPipe(filename, timeout);
// then retry connection
file = new RandomAccessFile(filename, "rw");
} catch (Throwable cle) {
// in case JNA not on classpath, then wait 10ms before next try.
if (System.nanoTime() - initialNano > TimeUnit.MILLISECONDS.toNanos(usedTimeout)) {
if (timeout == 0) {
throw new FileNotFoundException(
fileNotFoundException.getMessage()
+ "\n"
+ "please consider set connectTimeout option, so connection can retry having"
+ " access to named pipe. \n"
+ "(Named pipe can throw ERROR_PIPE_BUSY error)");
}
throw fileNotFoundException;
}
try {
TimeUnit.MILLISECONDS.sleep(5);
} catch (InterruptedException interrupted) {
IOException ioException =
new IOException("Interruption during connection to named pipe");
ioException.initCause(interrupted);
throw ioException;
}
}
}
} while (true);
is =
new InputStream() {
@Override
public int read(byte[] bytes, int off, int len) throws IOException {
return file.read(bytes, off, len);
}
@Override
public int read() throws IOException {
return file.read();
}
@Override
public int read(byte[] bytes) throws IOException {
return file.read(bytes);
}
};
os =
new OutputStream() {
@Override
public void write(byte[] bytes, int off, int len) throws IOException {
file.write(bytes, off, len);
}
@Override
public void write(int value) {}
};
}
public InputStream getInputStream() {
return is;
}
public OutputStream getOutputStream() {
return os;
}
public void setTcpNoDelay(boolean bool) {
// do nothing
}
public void setKeepAlive(boolean bool) {
// do nothing
}
public void setSoLinger(boolean bool, int value) {
// do nothing
}
@Override
public void setSoTimeout(int timeout) {
// do nothing
}
public void shutdownOutput() {
// do nothing
}
}