OKhttp : SSLProtocolException: SSL handshake terminated

旧时模样 提交于 2019-12-05 13:47:19

This is not a solution but provides some network debugging in case it relates to the issue mentioned above.

If it is the problem with the network interface mentioned in issue 1940 above then you can workaround that issue by implementing the Dns interface, and also the socketFactory. It could be you get back two DNS records and one works for you and the other doesn't, and it changes after a restart.

https://github.com/yschimke/oksocial/blob/master/src/main/java/com/baulsupp/oksocial/network/DnsSelector.java

https://github.com/yschimke/oksocial/blob/master/src/main/java/com/baulsupp/oksocial/network/InterfaceSocketFactory.java

Try confirming by adding debugging looking at the results of

Dns.SYSTEM.lookup(hostname)

NetworkInterface.getByInetAddress(address)

NetworkInterface.getNetworkInterfaces()


UPDATE

Code within the Callback.OnFailure to debug this problem :

@Override
public void onFailure(final Call call, final IOException e) {
    if (call.isCanceled()) {
        SLog.w(TAG, "onFailure: Canceled");
        return;
    }

    if(e instanceof SSLException){

        try {
            Log.d(getClass().getSimpleName(), "Checking DNS hosts ... ");
            List<InetAddress> list = Dns.SYSTEM.lookup(call.request().url().host());
            Log.d(getClass().getSimpleName(), "Number of Entries: "+list.size());
            for (InetAddress address : list) {
                Log.d(getClass().getSimpleName(), address.toString());
            }
            Log.d(getClass().getSimpleName(), "End of Checking DNS hosts");

        } catch (UnknownHostException e1) {
            e1.printStackTrace();
        }


        try {
            Log.d(getClass().getSimpleName(), "Checking Network Interfaces ... ");
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            ArrayList<NetworkInterface> list = Collections.list(interfaces);
            Log.d(getClass().getSimpleName(), "Number of Entries: "+list.size());
            for(NetworkInterface netintface : list) {
                Log.d(getClass().getSimpleName(), netintface.toString());
                List<InterfaceAddress> listaddresses = netintface.getInterfaceAddresses();
                Log.d(getClass().getSimpleName(), "   Number of Interface Addresses: "+listaddresses.size());
                for (InterfaceAddress infcaddress : listaddresses) {
                    Log.d(getClass().getSimpleName(), "   > InterfaceAddress : "+infcaddress.toString());
                }
            }
            Log.d(getClass().getSimpleName(), "End of Checking Network Interfaces");
        } catch (SocketException e1) {
            e1.printStackTrace();
        }


    }
}

DEBUG OUTPUT from code above

06-21 11:43:19.495 12890-12890/com.app.stg D/[StandardRequest]: ->
                                                                   ------------- Request -------------
                                                                   ********** METHOD sendRequest() **********
                                                                   GET
                                                                   -----------------------------------
06-21 11:43:24.330 12890-21401/com.app.stg D/StandardRequestCallback: Checking DNS hosts ... 
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: Number of Entries: 8
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.145
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.20
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.185
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.84
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.249
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.52
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.159
06-21 11:43:24.450 12890-21401/com.app.stg D/StandardRequestCallback: arc.stg.issa.sainsburys.co.uk/52.85.69.246
06-21 11:43:24.460 12890-21401/com.app.stg D/StandardRequestCallback: End of Checking DNS hosts
06-21 11:43:24.460 12890-21401/com.app.stg D/StandardRequestCallback: Checking Network Interfaces ... 
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: Number of Entries: 4
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: [lo][1][/::1%1%1][/127.0.0.1]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback:    Number of Interface Addresses: 2
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback:    > InterfaceAddress : /::1%1%1/128 [null]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback:    > InterfaceAddress : /127.0.0.1/8 [null]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: [sit0][2]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback:    Number of Interface Addresses: 0
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: [wlan0][4][/fe80::4283:deff:fe94:b0ff%wlan0%4][/172.24.90.253]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback:    Number of Interface Addresses: 2
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback:    > InterfaceAddress : /fe80::4283:deff:fe94:b0ff%wlan0%4/64 [null]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback:    > InterfaceAddress : /172.24.90.253/19 [/172.24.95.255]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: [ip6tnl0][3]
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback:    Number of Interface Addresses: 0
06-21 11:43:24.480 12890-21401/com.app.stg D/StandardRequestCallback: End of Checking Network Interfaces
06-21 11:43:24.480 12890-12890/com.app.stg D/JS-[LauncherActivity]: ErrorReport{type='SSLHandshakeException'}

I've found a work around - basically you create a new instance of the OkHttpClient ! See the code below ...

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.IOException;

import javax.net.ssl.SSLException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class ActivityMain extends AppCompatActivity
{
    private Button buttonStart;
    private Button buttonStop;
    private TextView textView;
    private Handler handler;

    private Integer mCount = 0;
    private Boolean mQuit;
    private OkHttpClient client = new OkHttpClient();
    private Runnable mRunnable;

    final int DELAY_SUBSEQUENT_REQUEST = 5000;//5sec
    final String REQUEST_URL = "https://whatever.com/url/to/test";



    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        handler = new Handler();

        buttonStart = (Button)findViewById(R.id.buttonstart);
        buttonStop = (Button)findViewById(R.id.buttonstop);
        textView = (TextView)findViewById(R.id.textview);

        mRunnable = new Runnable() {
            @Override
            public void run() {
                if (!mQuit) {
                    mCount++;
                    textView.setText(String.valueOf(mCount));

                    // do the GET call here
                    RequestGet();
                }
            }
        };

        buttonStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                buttonStart.setEnabled(false);
                triggerDelayedSslRequest(0);
                mQuit = false;
            }
        });

        buttonStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                buttonStart.setEnabled(true);
                mQuit = true;
                handler.removeCallbacks(mRunnable);
                mCount = 0;
            }
        });
    }

    private void triggerDelayedSslRequest(int delay)
    {
        handler.postDelayed(mRunnable, delay);
    }

    private void RequestGet()
    {
        Request request = new Request.Builder()
                .url(REQUEST_URL)
                .build();

        // NOTE: onFailure and onResponse are not on the main thread
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                // the SSL error is trapped here
                e.printStackTrace();

                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(e.getMessage());
                        buttonStart.setEnabled(true);
                    }
                });

                // Crazy "fix" for SSLException
                if(e instanceof SSLException) {
                    client = new OkHttpClient();
                }
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                if (!response.isSuccessful())
                {
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            textView.setText("Error Response: "+response.toString());
                        }
                    });
                } else {
                    System.out.println(response.body().string());
                }

                // schedule the next GET request
                triggerDelayedSslRequest(DELAY_SUBSEQUENT_REQUEST);
            }
        });
    }
}


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="a.b.ssltestapp.ActivityMain">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start"
        android:id="@+id/buttonstart"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Stop"
        android:id="@+id/buttonstop"
        android:layout_below="@+id/buttonstart"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textview"
        android:layout_marginTop="100dp"
        android:text="Press START to test SSL"
        android:gravity="center"
        android:layout_below="@+id/buttonstop"
        android:layout_centerHorizontal="true"/>


</RelativeLayout>

However, this fix is highly inconvenient.

To summarize the fix:

  • Launch the app and let it sit for maybe 20 minutes (maybe at this point make your wifi turn off and back on? I'm sure at work, that's what happens)
  • Now press the START button in the app
  • Observe the SSL Handshake Exception (at this point a new OkHttpClient instance is created).
  • Press the START button again
  • Observe that GET requests are now successful.

What is it about creating a new OkHttpClient object that makes the SSL Handshake work again ?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!