2

Overview

I am using the below version of Okhttp com.squareup.okhttp3:okhttp:4.9.3

I need to execute multiple HttpRequests at one go when a transaction happens.

I have taken Singleton OkHttpClient to avoid creation of new client every time so I am reusing the same http client for all my http requests

Scenario

When I execute multiple http requests pararell using the same Singleton OkHttpClient, the SSL Handshake is happening for the 1st http request and it is not happening for the other http requests.

Problem Statement

If there is a delay of more than 30 seconds between 2 http requests then the SSL Handshake is happening every time .. I want to address this issue. SSL Handshake should happen only for the 1st http request. I may send a http request now and take some time and then send another http request. I dont want SSL handshake to happen for the 2nd httprequest. Right now it is happening if there is a delay of 30 seconds. If I execute multiple http requests without any time delay then it is working fine.

Is there any setting in OkttpClient where I can increase the idle time out between 2 http requests so that SSL Handshake wont happen every time.

public class OkHttpSingleton {

private static OkHttpSingleton singletonInstance;

// No need to be static; OkHttpSingleton is unique so is this.
private OkHttpClient httpClient;
int timeoutConnect = 45000;
int timeoutSocket = 45000;


// Private so that this cannot be instantiated.
private OkHttpSingleton() {
    try {
        String tlsVersion = "TLSv1.2";
        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            tlsVersion = "TLSv1";
        }
        SSLContext sslContext = SSLContext.getInstance(tlsVersion);
        sslContext.init(null, null, null);
        SSLSocketFactory socketFactory = sslContext.getSocketFactory();

        httpClient = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)
                .connectTimeout(timeoutConnect, TimeUnit.SECONDS)
                .writeTimeout(timeoutSocket, TimeUnit.SECONDS)
                .readTimeout(timeoutSocket, TimeUnit.SECONDS)
                .sslSocketFactory(socketFactory, new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                    }

                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                })
                .build();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static OkHttpSingleton getInstance() {
    if (singletonInstance == null) {
        singletonInstance = new OkHttpSingleton();
    }
    return singletonInstance;
}

// In case you just need the unique OkHttpClient instance.
public OkHttpClient getClient() {
    return httpClient;
}

public void closeConnections() {
    httpClient.dispatcher().cancelAll();
}

}

Pls find the screenshot of WIRESHARK below . I want to avoid that Client Hello and HandShake

enter image description here

Pls find the RST ACK sent by server after 30 seconds of inactivity

enter image description here

KK_07k11A0585
  • 2,381
  • 3
  • 26
  • 33
  • @Robert Done. pls check – KK_07k11A0585 Aug 28 '23 at 08:01
  • You define a read and write time-out of 45 seconds, so if a HTTP connection is not used for 45 seconds in outgoing or incoming direction it will be closed and next time a request is executed you will see a TLS handshake. If you want avoid TLS handshake increase or kick both values. – Robert Aug 28 '23 at 08:26
  • 1
    Are you sure that what you want is supported by the server? There may need to be some server-side configuration needed to [support multiple HTTP requests over a single TLS session](https://security.stackexchange.com/a/113343). – CommonsWare Aug 28 '23 at 10:51
  • Dear @CommonsWare I am not aware the server side configuration, but will verify it once. Thank you so much for the input :) – KK_07k11A0585 Aug 28 '23 at 12:22
  • @Robert I tried by changing the value from 45 seconds to 10 seconds .. When I try to execute the request after 30 seconds delay it is again making SSL Handshake. ... – KK_07k11A0585 Aug 28 '23 at 12:25
  • Please reread my comment I wrote **increase** not decrease. – Robert Aug 28 '23 at 13:04
  • @Robert I just changed it from 10 sec to 180 sec. But I still see the handshake is happening. I have observed using a stop watch, if the time gap between 2 http requests is 20-25 seconds then it is not doing handshake. If it is more than 30 then it is doing handshake – KK_07k11A0585 Aug 28 '23 at 15:03
  • 1
    Carefully check the Wireshark log who closes the connection. If it is the server you can only test if keep-alive changes something. If not then this is the way the server wants to handle connections. – Robert Aug 28 '23 at 15:18
  • @Robert Sure will check that. Thank you – KK_07k11A0585 Aug 29 '23 at 05:49
  • @Robert I have had a discussion with my network team and they told me that the server is sending RST ACK i.e reset connection tag to the client exactly after 30 seconds when there is no traffic. I have updated the question with the packet details ... Could you please let me know is there anything we can do in application side to stop server from sending this – KK_07k11A0585 Aug 29 '23 at 10:51
  • @CommonsWare I have had a discussion with my network team and they told me that the server is sending RST ACK i.e reset connection tag to the client exactly after 30 seconds when there is no traffic. I have updated the question with the packet details ... Could you please let me know is there anything we can do in application side to stop server from sending this – KK_07k11A0585 Aug 29 '23 at 10:52
  • I am not sure what mechanisms for keeping a connection alive are supported by OkHttp (may in this case dummy HEAD requests would be required). If that doesn't work you have to accept that the server doe snot support persistent connections in a way you prefer. But even if you see a second TLS handshake the second connection should make use of the cached TLS session so the handshake should be faster. https://blog.cloudflare.com/tls-session-resumption-full-speed-and-secure/ You can check Wireshark if the server supports/uses TLS session resume. – Robert Aug 29 '23 at 14:11
  • @Robert I have had call with our network team and they confirmed that there is a server side timeout setting which is forcing server is send the RST flag if there is not traffic for 30 seconds. Issue was resolved now. Thank you so much for your inputs :) – KK_07k11A0585 Aug 30 '23 at 06:49

2 Answers2

1

You can influence the idle time for connections, which indirectly affects the TLS handshake timeout. You do this by configuring the connection pool's eviction policy and the keep-alive duration.

// Increase the idle connection timeout to 10 minutes
ConnectionPool connectionPool = new ConnectionPool(
    /* maxIdleConnections */ 5,
    /* keepAliveDuration */ 10, TimeUnit.MINUTES
);

OkHttpClient client = new OkHttpClient.Builder()
    .connectionPool(connectionPool)
    .build();

In the code above, the keepAliveDuration parameter in the ConnectionPool constructor specifies how long connections can remain idle before they are considered for eviction and cleanup. By increasing this value, you can indirectly influence the timeout for the TLS handshake.

Hope it helps!

viethoang
  • 111
  • 3
1

try keepAliveDuration eg :

import okhttp3.OkHttpClient;

public class MyHttpClient {
    private static OkHttpClient client;

    public static OkHttpClient getClient() {
        if (client == null) {
            client = new OkHttpClient.Builder()
                .keepAliveDuration(60, TimeUnit.SECONDS) 
                .build();
        }
        return client;
    }
}

Use this in newer version :

OkHttpClient client = new OkHttpClient.Builder()
    .connectionPool(new ConnectionPool(5, 30, TimeUnit.SECONDS)) 
    .build();
Hammad Ahmed khan
  • 1,618
  • 7
  • 19