3

I'm trying to reach my server from WiFi or Mobile Data, depending on which interface is answering. The use case is the following : - WiFi is always on. - If the server is not responding through the WiFi (because there is no internet connection for example), then I redirect future requests to the cellular data. - When the connection is back through the WiFi, I redirect next requests to the WiFi.

To achieve this, I wanted to use the ConnectivityManager with TRANSPORT_CELLULAR or TRANSPORT_WIFI. Then it returns a Network object which I can use.

After that I planned to pass the socketFactory from the Network class to the OkHttpClient.

OkHttpClient client = new OkHttpClient.Builder()
        .socketFactory(network.getSocketFactory())
        .build();

Problem : the server uses a https connection. So I'm building the OkHttpClient using socketSSLFactory, which is build with SSLContext and its method getSocketFactory.

So the question is the following : how can I bind the OkHttpClient to a Network AND to a SSL Socket Factory ?

Mathieu H.
  • 800
  • 8
  • 21
  • 1
    Using `OkHttpClient.Builder.sslSocketFactory()` is the correct solution for creating HTTPS connections with OkHttp. However, since `Network` doesn't provide an `SSLSocketFactory`, you will probably have to resort to implementing your own class that extends `SSLSocketFactory` and pass an instance of that class to `Builder.sslSocketFactory()`. Override `createSocket()` in your class to return a `Socket` from `SSLContext.getSocketFactory().createSocket()`, passing it a `Socket` from `network.getSocketFactory().createSocket()`. Not sure if that would work, but might be worth a try. – Remy Lebeau Dec 11 '17 at 21:25
  • The `getSocketFactory` from `SSLContext` is returning a `SSLSocketFactory`, and the `getSocketFactory` from `Network` is return a `SocketFactory`. So it seems I am stuck because of that. Right now I will use the `bindProcessToNetwork` method and recreate my okhttp client but I am not super fan of this solution – Mathieu H. Dec 20 '17 at 10:31
  • 1
    Read my previous comment again more carefully, and read the documentation. `SSLSocketFactory.createSocket()` takes a `Socket` as input and returns a new `Socket`. The input `Socket` is the underlying connection that SSL runs on top of. The returned `Socket` handles encrypted I/O using that connection. It is fine that the two `Socket`s are from different factories. My suggestion would allow you to get that initial `Socket` from the `Network` and then bind the SSL `Socket` to it. – Remy Lebeau Dec 20 '17 at 16:02

1 Answers1

2

Ok so I finally find out how to perform that. It requires to use both socketFactory and SSLSocketFactory of OkHttp builder.

OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder()
    .sslSocketFactory(new MySSLSocketFactory(), new MyTrustManager())
    .socketFactory(network.getSocketFactory())
    .dns(new NetworkDns())
    .hostnameVerifier(new MyHostnameVerifier());

Concretely, MySSLSocketFactory is not binded to my network object. I don't need to override the createSocket method in it. I just pass the socket factory of my network object to the OkHttp builder.

Don't forget to override the dns as well to perform the name resolution on the network you want. (cf Perform network-specific host name resolutions using Network.getAllByName)

Mathieu H.
  • 800
  • 8
  • 21
  • So, as I understood, BOTH socketFactory and sslSocketFactory has to be set, and SSLSocketFactory can just be a default one. Is HostNameVerifier needed for it to work? – ntoskrnl Sep 24 '21 at 02:22