Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Signed-off-by: jzajic <[email protected]>
  • Loading branch information
jan-zajic committed Nov 20, 2018
1 parent 36e3b9d commit 4d58eda
Show file tree
Hide file tree
Showing 6 changed files with 538 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/main/java/com/spotify/docker/client/DefaultDockerClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@
import com.spotify.docker.client.messages.swarm.SwarmSpec;
import com.spotify.docker.client.messages.swarm.Task;
import com.spotify.docker.client.messages.swarm.UnlockKey;
import com.spotify.docker.client.npipe.NpipeConnectionSocketFactory;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.Closeable;
import java.io.IOException;
Expand Down Expand Up @@ -314,6 +316,7 @@ public void progress(ProgressMessage message) throws DockerException {
// ==========================================================================

private static final String UNIX_SCHEME = "unix";
private static final String NPIPE_SCHEME = "npipe";

private static final Logger log = LoggerFactory.getLogger(DefaultDockerClient.class);

Expand Down Expand Up @@ -438,6 +441,8 @@ protected DefaultDockerClient(final Builder builder) {

if (originalUri.getScheme().equals(UNIX_SCHEME)) {
this.uri = UnixConnectionSocketFactory.sanitizeUri(originalUri);
} else if (originalUri.getScheme().equals(NPIPE_SCHEME)) {
this.uri = NpipeConnectionSocketFactory.sanitizeUri(originalUri);
} else {
this.uri = originalUri;
}
Expand Down Expand Up @@ -558,6 +563,10 @@ private Registry<ConnectionSocketFactory> getSchemeRegistry(final Builder builde
if (builder.uri.getScheme().equals(UNIX_SCHEME)) {
registryBuilder.register(UNIX_SCHEME, new UnixConnectionSocketFactory(builder.uri));
}

if (builder.uri.getScheme().equals(NPIPE_SCHEME)) {
registryBuilder.register(NPIPE_SCHEME, new NpipeConnectionSocketFactory(builder.uri));
}

return registryBuilder.build();
}
Expand Down Expand Up @@ -2924,6 +2933,8 @@ public static Builder fromEnv() throws DockerCertificateException {

if (endpoint.startsWith(UNIX_SCHEME + "://")) {
builder.uri(endpoint);
} else if (endpoint.startsWith(NPIPE_SCHEME + "://")) {
builder.uri(endpoint);
} else {
final String stripped = endpoint.replaceAll(".*://", "");
final HostAndPort hostAndPort = HostAndPort.fromString(stripped);
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/spotify/docker/client/DockerHost.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public String getenv(final String name) {
private static SystemDelegate systemDelegate = defaultSystemDelegate;

private static final String DEFAULT_UNIX_ENDPOINT = "unix:///var/run/docker.sock";
private static final String DEFAULT_WINDOWS_ENDPOINT = "npipe:////./pipe/docker_engine";
private static final String DEFAULT_ADDRESS = "localhost";
private static final int DEFAULT_PORT = 2375;

Expand Down Expand Up @@ -187,6 +188,9 @@ static String defaultDockerEndpoint() {
final String os = osName.toLowerCase(Locale.ENGLISH);
if (os.equalsIgnoreCase("linux") || os.contains("mac")) {
return DEFAULT_UNIX_ENDPOINT;
} else if (System.getProperty("os.name").equalsIgnoreCase("Windows 10")) {
//from Docker doc: Windows 10 64bit: Pro, Enterprise or Education
return DEFAULT_WINDOWS_ENDPOINT;
} else {
return DEFAULT_ADDRESS + ":" + defaultPort();
}
Expand All @@ -200,6 +204,10 @@ public static String defaultUnixEndpoint() {
return DEFAULT_UNIX_ENDPOINT;
}

public static String defaultWindowsEndpoint() {
return DEFAULT_WINDOWS_ENDPOINT;
}

public static String defaultAddress() {
return DEFAULT_ADDRESS;
}
Expand Down
308 changes: 308 additions & 0 deletions src/main/java/com/spotify/docker/client/npipe/NamedPipeSocket.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
/*-
* -\-\-
* docker-client
* --
* Copyright (C) 2018 Spotify AB
* --
* 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 com.spotify.docker.client.npipe;

import java.io.FilterInputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;

public class NamedPipeSocket extends Socket {

private final Object connectLock = new Object();
private volatile boolean inputShutdown;
private volatile boolean outputShutdown;

private String socketPath;
private volatile SocketAddress socketAddress;
private RandomAccessFile namedPipe;

private FileChannel channel;

NamedPipeSocket() throws IOException {
}

@Override
public void connect(SocketAddress endpoint) throws IOException {
connect(endpoint, 0);
}

@Override
public void connect(SocketAddress endpoint, int timeout) throws IOException {
if (timeout < 0) {
throw new IllegalArgumentException("Timeout may not be negative: " + timeout);
}

if (!(endpoint instanceof NpipeSocketAddress)) {
throw new IllegalArgumentException("Unsupported address type: "
+ endpoint.getClass().getName());
}

this.socketAddress = endpoint;
this.socketPath = ((NpipeSocketAddress) endpoint).path();

synchronized (connectLock) {
this.namedPipe = new RandomAccessFile(socketPath, "rw");
this.channel = this.namedPipe.getChannel();
}
}

@Override
public void bind(SocketAddress bindpoint) throws IOException {
throw new SocketException("Bind is not supported");
}

@Override
public InetAddress getInetAddress() {
return null;
}

@Override
public InetAddress getLocalAddress() {
return null;
}

@Override
public int getPort() {
return -1;
}

@Override
public int getLocalPort() {
return -1;
}

@Override
public SocketAddress getRemoteSocketAddress() {
return socketAddress;
}

@Override
public SocketAddress getLocalSocketAddress() {
return null;
}

@Override
public SocketChannel getChannel() {
return null;
}

@Override
public InputStream getInputStream() throws IOException {
if (!channel.isOpen()) {
throw new SocketException("Socket is closed");
}

if (inputShutdown) {
throw new SocketException("Socket input is shutdown");
}

return new FilterInputStream(Channels.newInputStream(channel)) {
@Override
public void close() throws IOException {
shutdownInput();
}
};
}

@Override
public OutputStream getOutputStream() throws IOException {
if (!channel.isOpen()) {
throw new SocketException("Socket is closed");
}

if (outputShutdown) {
throw new SocketException("Socket output is shutdown");
}

return new FilterOutputStream(Channels.newOutputStream(channel)) {
@Override
public void close() throws IOException {
shutdownOutput();
}
};
}

@Override
public void sendUrgentData(int data) throws IOException {
throw new SocketException("Urgent data not supported");
}

@Override
public void setSoTimeout(int timeout) {
}

@Override
public int getSoTimeout() throws SocketException {
return 0;
}

@Override
public void setSendBufferSize(int size) throws SocketException {
if (size <= 0) {
throw new IllegalArgumentException("Send buffer size must be positive: " + size);
}

if (!channel.isOpen()) {
throw new SocketException("Socket is closed");
}

// just ignore
}

@Override
public synchronized int getSendBufferSize() throws SocketException {
if (!channel.isOpen()) {
throw new SocketException("Socket is closed");
}

throw new UnsupportedOperationException("Getting the send buffer size is not supported");
}

@Override
public synchronized void setReceiveBufferSize(int size) throws SocketException {
if (size <= 0) {
throw new IllegalArgumentException("Receive buffer size must be positive: " + size);
}

if (!channel.isOpen()) {
throw new SocketException("Socket is closed");
}

// just ignore
}

@Override
public synchronized int getReceiveBufferSize() throws SocketException {
if (!channel.isOpen()) {
throw new SocketException("Socket is closed");
}

throw new UnsupportedOperationException("Getting the receive buffer size is not supported");
}

@Override
public void setKeepAlive(boolean on) throws SocketException {
}

@Override
public boolean getKeepAlive() throws SocketException {
return true;
}

@Override
public void setTrafficClass(int tc) throws SocketException {
if (tc < 0 || tc > 255) {
throw new IllegalArgumentException("Traffic class is not in range 0 -- 255: " + tc);
}

if (isClosed()) {
throw new SocketException("Socket is closed");
}

// just ignore
}

@Override
public int getTrafficClass() throws SocketException {
throw new UnsupportedOperationException("Getting the traffic class is not supported");
}

@Override
public void setReuseAddress(boolean on) throws SocketException {
// just ignore
}

@Override
public boolean getReuseAddress() throws SocketException {
throw new UnsupportedOperationException("Getting the SO_REUSEADDR option is not supported");
}

@Override
public void close() throws IOException {
if (isClosed()) {
return;
}
if (channel != null) {
channel.close();
}
inputShutdown = true;
outputShutdown = true;
}

@Override
public void shutdownInput() throws IOException {
inputShutdown = true;
}

@Override
public void shutdownOutput() throws IOException {
outputShutdown = true;
}

@Override
public String toString() {
if (isConnected()) {
return "WindowsPipe[addr=" + this.socketPath + ']';
}

return "WindowsPipe[unconnected]";
}

@Override
public boolean isConnected() {
return !isClosed();
}

@Override
public boolean isBound() {
return false;
}

@Override
public boolean isClosed() {
return channel != null && !channel.isOpen();
}

@Override
public boolean isInputShutdown() {
return inputShutdown;
}

@Override
public boolean isOutputShutdown() {
return outputShutdown;
}

@Override
public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
// no-op
}
}
Loading

0 comments on commit 4d58eda

Please sign in to comment.