/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* 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 net.java.sip.communicator.service.httputil;
import org.apache.http.conn.*;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.params.*;
import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.security.*;
/**
* Wrapper for SSLSocketFactory to use the constructor which is available
* in android. The certificate validation is handled by the SSLContext
* which we use to create sockets for this factory.
*
* TODO: wrap the SSLSocketFactory to use our own DNS resolution
* TODO: register socketfactory for http to use our own DNS resolution
*
* @author Damian Minkov
*/
public class SSLSocketFactoryEx
extends SSLSocketFactory
{
/**
* The context that will be used to create sockets.
*/
private SSLContext context;
/**
* Constructor using the super constructor available for android.
*
* @param context the context to use
* @throws UnrecoverableKeyException
* @throws KeyStoreException
* @throws KeyManagementException
* @throws NoSuchAlgorithmException
*/
public SSLSocketFactoryEx(SSLContext context)
throws
UnrecoverableKeyException,
KeyStoreException,
KeyManagementException,
NoSuchAlgorithmException
{
super((KeyStore) null);
this.context = context;
}
/**
* Creates socket.
* @param params
* @return
* @throws IOException
*/
@Override
public Socket createSocket(final HttpParams params)
throws
IOException
{
return this.context.getSocketFactory().createSocket();
}
/**
* @since 4.2
*/
@Override
public Socket createLayeredSocket(
final Socket socket,
final String host,
final int port,
final HttpParams params)
throws IOException,
UnknownHostException
{
return this.context.getSocketFactory()
.createSocket(
socket,
host,
port,
true);
}
/**
* @since 4.1
*/
@Override
public Socket connectSocket(
final Socket socket,
final InetSocketAddress remoteAddress,
final InetSocketAddress localAddress,
final HttpParams params)
throws IOException,
UnknownHostException,
ConnectTimeoutException
{
if(remoteAddress == null)
{
throw new IllegalArgumentException("Remote address may not be null");
}
if(params == null)
{
throw new IllegalArgumentException("HTTP parameters may not be null");
}
Socket sock = socket != null ?
socket : this.context.getSocketFactory().createSocket();
if(localAddress != null)
{
sock.setReuseAddress(HttpConnectionParams.getSoReuseaddr(params));
sock.bind(localAddress);
}
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
try
{
sock.setSoTimeout(soTimeout);
sock.connect(remoteAddress, connTimeout);
}
catch(SocketTimeoutException ex)
{
throw new ConnectTimeoutException(
"Connect to " + remoteAddress + " timed out");
}
String hostname;
if(remoteAddress instanceof HttpInetSocketAddress)
{
hostname = ((HttpInetSocketAddress) remoteAddress)
.getHttpHost().getHostName();
}
else
{
hostname = remoteAddress.getHostName();
}
SSLSocket sslsock;
// Setup SSL layering if necessary
if(sock instanceof SSLSocket)
{
sslsock = (SSLSocket) sock;
}
else
{
int port = remoteAddress.getPort();
sslsock = (SSLSocket) this.context.getSocketFactory()
.createSocket(sock, hostname, port, true);
}
return sslsock;
}
}