My Tomcat instance is listening to multiple IP addresses, but I want to control which source IP address is used when opening a URLConnection
.
How can I
Setting manually socket work fine ...
private HttpsURLConnection openConnection(URL src, URL dest, SSLContext sslContext)
throws IOException, ProtocolException {
HttpsURLConnection connection = (HttpsURLConnection) dest.openConnection();
HttpsHostNameVerifier httpsHostNameVerifier = new HttpsHostNameVerifier();
connection.setHostnameVerifier(httpsHostNameVerifier);
connection.setConnectTimeout(CONNECT_TIMEOUT);
connection.setReadTimeout(READ_TIMEOUT);
connection.setRequestMethod(POST_METHOD);
connection.setRequestProperty(CONTENT_TYPE, SoapConstants.CONTENT_TYPE_HEADER);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setSSLSocketFactory(sslContext.getSocketFactory());
if ( src!=null ) {
InetAddress inetAddress = InetAddress.getByName(src.getHost());
int destPort = dest.getPort();
if ( destPort <=0 )
destPort=SERVER_HTTPS_PORT;
int srcPort = src.getPort();
if ( srcPort <=0 )
srcPort=CLIENT_HTTPS_PORT;
connectionSocket = connection.getSSLSocketFactory().createSocket(dest.getHost(), destPort, inetAddress, srcPort);
}
connection.connect();
return connection;
}
This should do the trick:
URL url = new URL(yourUrlHere);
Proxy proxy = new Proxy(Proxy.Type.DIRECT,
new InetSocketAddress(
InetAddress.getByAddress(
new byte[]{your, ip, interface, here}), yourTcpPortHere));
URLConnection conn = url.openConnection(proxy);
And you are done. Dont forget to handle exceptions nicely and off course change the values to suit your scenario.
Ah and I omitted the import statements
Using the Apache commons HttpClient I have also found the following to work (removed try/catch for clarity):
HostConfiguration hostConfiguration = new HostConfiguration();
byte b[] = new byte[4];
b[0] = new Integer(192).byteValue();
b[1] = new Integer(168).byteValue();
b[2] = new Integer(1).byteValue();
b[3] = new Integer(11).byteValue();
hostConfiguration.setLocalAddress(InetAddress.getByAddress(b));
HttpClient client = new HttpClient();
client.setHostConfiguration(hostConfiguration);
GetMethod method = new GetMethod("http://remoteserver/");
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler(3, false));
int statusCode = client.executeMethod(method);
if (statusCode != HttpStatus.SC_OK) {
System.err.println("Method failed: " + method.getStatusLine());
}
byte[] responseBody = method.getResponseBody();
System.out.println(new String(responseBody));");
However, I still wonder what would happen if the gateway of the IP is down (192.168.1.11 in this case). Will the next gateway be tried or will it fail?
The obvious portable way would be to set a Proxy in URL.openConnection. The proxy can be in local host, you can then write a very simple proxy that binds the local address of the client socket.
If you can't modify the source where the URL is connected, you can replace the URLStreamHandler either when calling the URL constructor or globally through URL.setURLStreamHandlerFactory. The URLStreamHandler can then delegate to the default http/https handler, modifying the openConnection call.
A more extreme method would be to completely replace the handler (perhaps extending the implementation in your JRE). Alternatively, alternative (open source) http clients are available.