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 <ffei...@users.noreply.github.com> 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; + } }