[camel] branch master updated: CAMEL-12711: Add configuration property 'bindAddress' for SFTP to specify the address of the local interface to which the SFTP connection should bind. (#2452)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[camel] branch master updated: CAMEL-12711: Add configuration property 'bindAddress' for SFTP to specify the address of the local interface to which the SFTP connection should bind. (#2452)

davsclaus-2
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/master by this push:
     new e7757e2  CAMEL-12711: Add configuration property 'bindAddress' for SFTP to specify the address of the local interface to which the SFTP connection should bind. (#2452)
e7757e2 is described below

commit e7757e29b10fc55f97b92c2e7c77e69d5011fed4
Author: Felix Feisst <[hidden email]>
AuthorDate: Fri Aug 10 11:03:42 2018 +0200

    CAMEL-12711: Add configuration property 'bindAddress' for SFTP to specify the address of the local interface to which the SFTP connection should bind. (#2452)
---
 .../camel-ftp/src/main/docs/sftp-component.adoc    |  3 +-
 .../component/file/remote/SftpConfiguration.java   | 13 ++++
 .../component/file/remote/SftpOperations.java      | 85 ++++++++++++++++++++++
 3 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/components/camel-ftp/src/main/docs/sftp-component.adoc b/components/camel-ftp/src/main/docs/sftp-component.adoc
index e127442..cf8d950 100644
--- a/components/camel-ftp/src/main/docs/sftp-component.adoc
+++ b/components/camel-ftp/src/main/docs/sftp-component.adoc
@@ -51,7 +51,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (115 parameters):
+==== Query Parameters (116 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -111,6 +111,7 @@ with the following path and query parameters:
 | *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean
 | *throwExceptionOnConnect Failed* (advanced) | Should an exception be thrown if connection failed (exhausted) By default exception is not thrown and a WARN is logged. You can use this to enable exception being thrown and handle the thrown exception from the org.apache.camel.spi.PollingConsumerPollStrategy rollback method. | false | boolean
 | *timeout* (advanced) | Sets the data timeout for waiting for reply Used only by FTPClient | 30000 | int
+| *bindAddress* (bindAddress) | Specifies the address of the local interface against which the connection should bind. |  | String
 | *antExclude* (filter) | Ant style filter exclusion. If both antInclude and antExclude are used, antExclude takes precedence over antInclude. Multiple exclusions may be specified in comma-delimited format. |  | String
 | *antFilterCaseSensitive* (filter) | Sets case sensitive flag on ant filter | true | boolean
 | *antInclude* (filter) | Ant style filter inclusion. Multiple inclusions may be specified in comma-delimited format. |  | String
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConfiguration.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConfiguration.java
index 8fc377a..9be8751 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConfiguration.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConfiguration.java
@@ -69,6 +69,8 @@ public class SftpConfiguration extends RemoteFileConfiguration {
     private LoggingLevel jschLoggingLevel = LoggingLevel.WARN;
     @UriParam(label = "advanced")
     private Integer bulkRequests;
+    @UriParam(label = "bindAddress")
+    private String bindAddress;
 
     public SftpConfiguration() {
         setProtocol("sftp");
@@ -296,4 +298,15 @@ public class SftpConfiguration extends RemoteFileConfiguration {
     public Integer getBulkRequests() {
         return bulkRequests;
     }
+
+    /**
+     * Specifies the address of the local interface against which the connection should bind.
+     */
+    public void setBindAddress(String bindAddress) {
+        this.bindAddress = bindAddress;
+    }
+
+    public String getBindAddress() {
+        return bindAddress;
+    }
 }
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
index 1f58ea8..c3b181e 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
@@ -24,6 +24,9 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
 import java.security.KeyPair;
 import java.security.interfaces.DSAPrivateKey;
 import java.security.interfaces.DSAPublicKey;
@@ -41,11 +44,13 @@ import com.jcraft.jsch.JSchException;
 import com.jcraft.jsch.Proxy;
 import com.jcraft.jsch.Session;
 import com.jcraft.jsch.SftpException;
+import com.jcraft.jsch.SocketFactory;
 import com.jcraft.jsch.UIKeyboardInteractive;
 import com.jcraft.jsch.UserInfo;
 import org.apache.camel.Exchange;
 import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.LoggingLevel;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.file.FileComponent;
 import org.apache.camel.component.file.GenericFile;
 import org.apache.camel.component.file.GenericFileEndpoint;
@@ -358,6 +363,26 @@ public class SftpOperations implements RemoteFileOperations<SftpRemoteFile> {
             session.setProxy(proxy);
         }
 
+        if (isNotEmpty(sftpConfig.getBindAddress())) {
+            session.setSocketFactory(new SocketFactory() {
+
+                @Override
+                public OutputStream getOutputStream(Socket socket) throws IOException {
+                    return socket.getOutputStream();
+                }
+
+                @Override
+                public InputStream getInputStream(Socket socket) throws IOException {
+                    return socket.getInputStream();
+                }
+
+                @Override
+                public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
+                    return createSocketUtil(host, port, sftpConfig.getBindAddress(), session.getTimeout());
+                }
+            });
+        }
+
         return session;
     }
 
@@ -1074,4 +1099,64 @@ public class SftpOperations implements RemoteFileOperations<SftpRemoteFile> {
         // is not implemented
         return true;
     }
+
+    /*
+     * adapted from com.jcraft.jsch.Util.createSocket(String, int, int)
+     *
+     * added possibility to specify the address of the local network interface, against the
+     * connection should bind
+     */
+    static Socket createSocketUtil(final String host, final int port, final String bindAddress, final int timeout) {
+        Socket socket = null;
+        if (timeout == 0) {
+            try {
+                socket = new Socket(InetAddress.getByName(host), port, InetAddress.getByName(bindAddress), 0);
+                return socket;
+            } catch (Exception e) {
+                String message = e.toString();
+                if (e instanceof Throwable) {
+                    throw new RuntimeCamelException(message, (Throwable)e);
+                }
+                throw new RuntimeCamelException(message);
+            }
+        }
+        final Socket[] sockp = new Socket[1];
+        final Exception[] ee = new Exception[1];
+        String message = "";
+        Thread tmp = new Thread(new Runnable() {
+            public void run() {
+                sockp[0] = null;
+                try {
+                    sockp[0] = new Socket(InetAddress.getByName(host), port, InetAddress.getByName(bindAddress), 0);
+                } catch (Exception e) {
+                    ee[0] = e;
+                    if (sockp[0] != null && sockp[0].isConnected()) {
+                        try {
+                            sockp[0].close();
+                        } catch (Exception eee) { }
+                    }
+                    sockp[0] = null;
+                }
+            }
+        });
+        tmp.setName("Opening Socket " + host);
+        tmp.start();
+        try {
+            tmp.join(timeout);
+            message = "timeout: ";
+        } catch (java.lang.InterruptedException eee) {
+        }
+        if (sockp[0] != null && sockp[0].isConnected()) {
+            socket = sockp[0];
+        } else {
+            message += "socket is not established";
+            if (ee[0] != null) {
+                message = ee[0].toString();
+            }
+            tmp.interrupt();
+            tmp = null;
+            throw new RuntimeCamelException(message, ee[0]);
+        }
+        return socket;
+    }
 }