web-dev-qa-db-fra.com

javax.net.ssl.SSLException: Erreur de lecture: ssl = 0x9524b800: erreur d'E/S lors de l'appel système, connexion réinitialisée par un pair

Nos clients commencent à voir des centaines de ces "erreurs SSLException - Connexion réinitialisée par un homologue" au cours des dernières semaines et je ne comprends pas pourquoi.

  1. Nous utilisons Retrofit avec okhttp, pas de configuration spéciale

    public class OkHttpClientProvider implements IOkHttpClientProvider {
    
        OkHttpClient okHttpClient;
    
        public OkHttpClientProvider() {
            this.okHttpClient = createClient();
        }
    
        public OkHttpClient getOkHttpClient() {
            return this.okHttpClient;
        }
    
        private OkHttpClient createClient() {
            return new OkHttpClient();
        }
    }
    

Le fournisseur de client ci-dessus est un singleton. RestAdapter est construit en utilisant ce client injecté (nous utilisons un poignard) - 

RestAdapter.Builder restAdapterBuilder = new RestAdapter.Builder()
                                        .setConverter(converter)
                                        .setEndpoint(networkRequestDetails.getServerUrl())
                                        .setClient(new OkClient(okHttpClientProvider.getOkHttpClient()))
                                        .setErrorHandler(new NetworkSynchronousErrorHandler(eventBus))
                                        );

Basé sur des solutions de débordement de pile, ce que j'ai découvert - 

  1. La durée de conservation sur le serveur est de 180 secondes, OkHttp a une valeur par défaut de 300 secondes.

  2. Le serveur renvoie "Connection: close" dans son en-tête mais la demande du client envoie "Connection: keepAlive"

  3. Le serveur prend en charge TLS 1.0/1.1/1.2 et utilise Open SSL.

  4. Nos serveurs ont récemment migré vers un autre fournisseur d'hébergement dans une autre région. Je ne sais donc pas s'il s'agit ou non d'échecs DNS.

  5. Nous avons essayé de peaufiner des choses telles que KeepAlive, OpenSSL reconfiguré sur le serveur, mais pour une raison quelconque, le client Android ne cesse de recevoir cette erreur.

  6. Cela se produit immédiatement et sans délai lorsque vous essayez d'utiliser l'application pour publier quelque chose ou tirer pour l'actualiser (elle ne va même pas vers le réseau ou ne dispose pas d'un délai avant que cette exception se produit qui impliquerait que la connexion est déjà rompue). Mais l’essayer plusieurs fois en quelque sorte "le corrige" et nous obtenons un succès. Ça se reproduit plus tard

  7. Nous avons invalidé nos entrées DNS sur le serveur pour voir si c'est ce qui l'a causé mais cela n'a pas aidé

  8. Cela arrive surtout sur LTE mais je l'ai aussi vu en Wifi

Je ne veux pas désactiver Keep Alive car la plupart des clients modernes ne le font pas. De plus, nous utilisons OkHttp 2.4 et ceci pose un problème sur les dispositifs "sandwichs à la crème glacée". J'espère donc que cela devrait régler ces problèmes de réseau sous-jacents. Le client iOS obtient également ces exceptions, mais près de 100 fois moins (le client iOS utilise AFNetworking 2.0). J'ai du mal à trouver de nouvelles choses à essayer à ce stade, de l'aide/des idées?

Mise à jour - Ajout d'une trace de pile complète via okhttp

      retrofit.RetrofitError: Read error: ssl=0x9dd07200: I/O error during system call, Connection reset by peer
              at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.Java:390)
              at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.Java:240)
              at Java.lang.reflect.Proxy.invoke(Proxy.Java:397)
              at $Proxy15.getAccessTokenUsingResourceOwnerPasswordCredentials(Unknown Source)
              at com.company.droid.repository.network.NetworkRepository.getAccessTokenUsingResourceOwnerPasswordCredentials(NetworkRepository.Java:76)
              at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.Java:88)
              at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.Java:23)
              at Android.os.AsyncTask$2.call(AsyncTask.Java:292)
              at Java.util.concurrent.FutureTask.run(FutureTask.Java:237)
              at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1112)
              at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:587)
              at Java.lang.Thread.run(Thread.Java:818)
       Caused by: javax.net.ssl.SSLException: Read error: ssl=0x9dd07200: I/O error during system call, Connection reset by peer
              at com.Android.org.conscrypt.NativeCrypto.SSL_read(Native Method)
              at com.Android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream.read(OpenSSLSocketImpl.Java:699)
              at okio.Okio$2.read(Okio.Java:137)
              at okio.AsyncTimeout$2.read(AsyncTimeout.Java:211)
              at okio.RealBufferedSource.indexOf(RealBufferedSource.Java:306)
              at okio.RealBufferedSource.indexOf(RealBufferedSource.Java:300)
              at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.Java:196)
              at com.squareup.okhttp.internal.http.HttpConnection.readResponse(HttpConnection.Java:191)
              at com.squareup.okhttp.internal.http.HttpTransport.readResponseHeaders(HttpTransport.Java:80)
              at com.squareup.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.Java:917)
              at com.squareup.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.Java:793)
              at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.Java:439)
              at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.Java:384)
              at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.Java:497)
              at com.squareup.okhttp.internal.huc.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.Java:105)
              at com.squareup.okhttp.internal.huc.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.Java:25)
              at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.Java:73)
              at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.Java:38)
              at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.Java:321)
              at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.Java:240)
              at Java.lang.reflect.Proxy.invoke(Proxy.Java:397)
              at $Proxy15.getAccessTokenUsingResourceOwnerPasswordCredentials(Unknown Source)
              at com.company.droid.repository.network.NetworkRepository.getAccessTokenUsingResourceOwnerPasswordCredentials(NetworkRepository.Java:76)
              at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.Java:88)
              at com.company.droid.ui.login.LoginTask.doInBackground(LoginTask.Java:23)
              at Android.os.AsyncTask$2.call(AsyncTask.Java:292)
              at Java.util.concurrent.FutureTask.run(FutureTask.Java:237)
              at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1112)
              at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:587)
              at Java.lang.Thread.run(Thread.Java:818)
      ]}
40
Rickster

Récemment, j'ai fait face au problème alors que je travaillais sur un code hérité. Après avoir recherché sur Google, le problème est omniprésent mais sans résolution concrète. J'ai travaillé sur différentes parties du message d'exception et analysé ci-dessous.

Une analyse:

  1. SSLException: une exception s'est produite avec SSL (Secure Socket Layer), qui est implémenté dans le package javax.net.ssl du JDK (openJDK/oracleJDK/AndroidSDK)
  2. Read error ssl=# I/O error during system call: Une erreur s'est produite lors de la lecture à partir du socket sécurisé. Cela s'est produit lors de l'utilisation des bibliothèques/pilotes du système natif. Veuillez noter que toutes les plates-formes solaris, Windows, etc. ont leurs propres bibliothèques de socket qui sont utilisées par le protocole SSL. Windows utilise la bibliothèque WINSOCK.
  3. Connection reset by peer: Ce message est signalé par la bibliothèque système (rapports Solaris ECONNRESET et Windows WSAECONNRESET), indiquant que le socket utilisé dans le transfert de données n'est plus utilisable car une connexion existante a été fermée de force par l'hôte distant. Il faut créer un nouveau chemin sécurisé entre l'hôte et le client.

Raison:

Comprenant ce problème, j’essaie de trouver la raison de la réinitialisation de la connexion et j’énonce les raisons suivantes:

  • L'application homologue de l'hôte distant est soudainement arrêtée, l'hôte est redémarré, l'hôte ou l'interface réseau distante est désactivé ou l'hôte distant utilise une fermeture à froid.
  • Cette erreur peut également survenir si une connexion a été interrompue en raison d'une activité de maintien en activité détectant un échec alors qu'une ou plusieurs opérations sont en cours. Les opérations en cours échouent avec Network dropped connection on reset(On Windows(WSAENETRESET)) et les opérations suivantes échouent avecConnection reset by peer(On Windows(WSAECONNRESET)).
  • Si le serveur cible est protégé par le pare-feu, ce qui est vrai dans la plupart des cas, la durée de vie (TTL) ou le délai d'expiration associé au port ferme de force la connexion idle à l'expiration du délai imparti. c'est quelque chose de notre intérêt

Résolution:

  1. Les événements côté serveur tels que l’arrêt soudain du service, le redémarrage, l’interface réseau désactivée ne peuvent être gérés par aucun moyen.
  2. Sur le côté serveur, configurez le pare-feu pour le port donné avec les valeurs de durée de vie (TTL) ou de délai d'expiration supérieures, telles que 3600 secondes.
  3. Les clients peuvent "essayer" garder le réseau actif pour éviter ou réduire le Connection reset by peer.
  4. Normalement, le trafic réseau maintient la connexion en vie et les problèmes/exceptions ne sont pas vus fréquemment. Fort Wifi a moins de chances de Connection reset by peer.
  5. Avec les réseaux mobiles 2G, 3G et 4G lorsque la livraison de données par paquets est intermittente et dépend de la disponibilité du réseau mobile, il est possible que le temporisateur TTL ne soit pas réinitialisé côté serveur et que le résultat se trouve dans Connection reset by peer

Voici les termes suggérés pour définir sur différents forums pour résoudre le problème

  • ConnectionTimeout: Utilisé uniquement à la fin de la connexion. Si l'hôte met du temps à se connecter, une valeur plus élevée oblige le client à attendre la connexion.
  • </ li>
  • SoTimeout: Socket timeout-Il indique le délai maximum dans lequel le paquet de données est reçu pour considérer la connexion comme active. Si aucune donnée n'est reçue dans le délai imparti, la connexion est supposée être interrompue/interrompue.
  • Linger: Jusqu'à quelle heure le socket ne doit pas être fermé lorsque des données sont envoyées en file d'attente et que la fonction de socket proche est appelée sur le socket.
  • TcpNoDelay: Voulez-vous désactiver le tampon qui contient et accumule les paquets TCP et les envoyer une fois qu'un seuil est atteint? Si vous définissez cette valeur sur true, la mise en mémoire tampon TCP est ignorée, de sorte que chaque demande est envoyée immédiatement. Les ralentissements dans le réseau peuvent être dus à une augmentation du trafic réseau due à une transmission de paquets plus petite et plus fréquente.
  • </ li>

Donc, aucun des paramètres ci-dessus ne permet de garder le réseau en vie et donc inefficace.

J'ai trouvé un paramètre qui peut aider à résoudre le problème qui est ce fonctions

setKeepAlive(true)
setSoKeepalive(HttpParams params, enableKeepalive="true") 

Comment ai-je résolu mon problème?

  • Définissez le HttpConnectionParams.setSoKeepAlive(params, true)
  • Catch the SSLException et recherchez le message d'exception pour Connection reset by peer
  • Si une exception est trouvée, enregistrez la progression du téléchargement/de la lecture et créez une nouvelle connexion.
  • Si possible, reprendre le téléchargement/lire sinon redémarrer le téléchargement

J'espère que les détails aident. Bonne codage ...

78
Devendra Vaja

Si vous utilisez Nginx et que vous rencontrez un problème similaire, cela pourrait aider:

Analysez votre domaine sur ce sslTesturl et voyez si la connexion est autorisée pour la version de votre appareil.

Si les périphériques de version inférieure (tels que <Android 4.4.2, etc.) ne peuvent pas se connecter en raison du support TLS, essayez d'ajouter ceci à votre fichier de configuration Nginx

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
11
jayiitb

nous avons eu le même problème à partir de ce matin et je l’ai résolu ... espérons que cela aide ...

SSL sur IIS 8

  1. Tout fonctionnait bien hier et hier soir notre SSL a été mis à jour sur le site IIS.
  2. Lors de la consultation du site, Liaisons au protocole SSL a permis de constater que IIS8 comportait une nouvelle case à cocher. Demande d'indication du nom du serveur.
  3. Cela a déclenché le problème.
  4. Je suis retourné à IIS, désactivé la case à cocher .... Problème résolu !!!!

J'espère que cela t'aides!!!

4
Jorge Navarro

Une autre cause possible de ce message d'erreur est si la méthode HTTP est bloquée par le serveur ou l'équilibreur de charge.

Il semble que la pratique de sécurité standard bloque les méthodes HTTP inutilisées. Nous nous sommes heurtés à ce problème car HEAD était bloqué par l'équilibreur de charge (mais curieusement, tous les serveurs à charge équilibrée ne l'ont pas fait échouer de temps en temps). J'ai pu vérifier que la requête elle-même fonctionnait correctement en la modifiant temporairement pour qu'elle utilise la méthode GET.

Le code d'erreur sur iOS était: Erreur lors de la demande de code d'application: Domaine d'erreur = Code NSURLErrorDomain = -1005 "La connexion réseau a été perdue."

0
Mykaelos

Android Prend en charge la mise en œuvre SSL par défaut sauf pour Android N (API niveau 24) et inférieur à Android 5.1 (API niveau 22)
J'obtenais l'erreur en effectuant l'appel API en dessous des périphériques de niveau API 22 après avoir implémenté SSL au niveau du serveur; c'était lors de la création de l'objet client OkHttpClient, et résolu en ajoutant la méthode connectionSpecs () de la classe OkHttpClient.Builder.

l'erreur reçue était

échec de la réponse: javax.net.ssl.SSLException: établissement de la liaison SSL interrompu: ssl = 0xb8882c00: erreur d'E/S lors de l'appel système, connexion réinitialisée par un homologue

donc j'ai corrigé cela en ajoutant le chèque comme 

if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.Lollipop_MR1) {
            // Do something for below api level 22
            List<ConnectionSpec> specsList = getSpecsBelowLollipopMR1(okb);
            if (specsList != null) {
                okb.connectionSpecs(specsList);
            }
        }

Aussi pour Android N (API niveau 24); Je recevais l'erreur en faisant l'appel HTTP comme 

HTTP FAILED: javax.net.ssl.SSLHandshakeException: la négociation a échoué

et cela est corrigé en ajoutant le contrôle pour Android 7 en particulier, comme

if (Android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.N){
            // Do something for naugat ; 7
            okb.connectionSpecs(Collections.singletonList(getSpec()));
        }

Donc, mon dernier objet OkHttpClient sera comme:

         OkHttpClient client
         HttpLoggingInterceptor httpLoggingInterceptor2 = new
         HttpLoggingInterceptor();
         httpLoggingInterceptor2.setLevel(HttpLoggingInterceptor.Level.BODY);

         OkHttpClient.Builder okb = new OkHttpClient.Builder()
                 .addInterceptor(httpLoggingInterceptor2)
               .addInterceptor(new Interceptor() {
                     @Override
                     public Response intercept(Chain chain) throws IOException {
                         Request request = chain.request();
                         Request request2 = request.newBuilder().addHeader(AUTH_KEYWORD, AUTH_TYPE_JW + " " + password).build();
                         return chain.proceed(request2);
                     }
                 }).connectTimeout(30, TimeUnit.SECONDS)
                 .writeTimeout(30, TimeUnit.SECONDS)
                 .readTimeout(30, TimeUnit.SECONDS);

         if (Android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.N){
             // Do something for naugat ; 7
             okb.connectionSpecs(Collections.singletonList(getSpec()));
         }

         if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.Lollipop_MR1) {
             List<ConnectionSpec> specsList = getSpecsBelowLollipopMR1(okb);
             if (specsList != null) {
                 okb.connectionSpecs(specsList);
             }
         }

         //init client
         client = okb.build();

getSpecsBelowLollipopMR1 fonctionne comme, 

   private List<ConnectionSpec> getSpecsBelowLollipopMR1(OkHttpClient.Builder okb) {

        try {

            SSLContext sc = SSLContext.getInstance("TLSv1.2");
            sc.init(null, null, null);
            okb.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()));

            ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                    .tlsVersions(TlsVersion.TLS_1_2)
                    .build();

            List<ConnectionSpec> specs = new ArrayList<>();
            specs.add(cs);
            specs.add(ConnectionSpec.COMPATIBLE_TLS);

            return specs;

        } catch (Exception exc) {
            Timber.e("OkHttpTLSCompat Error while setting TLS 1.2"+ exc);

            return null;
        }
    }

La classe Tls12SocketFactory se trouve dans le lien ci-dessous (commentaire de gotev): 

https://github.com/square/okhttp/issues/2372


Pour plus de soutien en ajoutant quelques liens ci-dessous cela vous aidera en détail,

https://developer.Android.com/training/articles/security-ssl

D/OkHttp: <- HTTP FAILED: javax.net.ssl.SSLException: négociation SSL interrompue: ssl = 0x64e3c938: erreur d'E/S lors de l'appel système, réinitialisation de la connexion par homologue

0
tejraj