2017-10-01 4 views
1

J'essaie de lire les données d'un socket lié Openssl en utilisant SSL_read. J'effectue des opérations Openssl en mode client qui envoie une commande et reçoit des données d'un serveur réel. J'ai utilisé deux threads où un thread gère toutes les opérations Openssl comme se connecter, écrire et fermer. J'effectue le SSL_read dans un fil séparé. Je suis capable de lire correctement les données lorsque j'émets SSL_read une fois. Mais j'ai rencontré des problèmes lorsque j'ai essayé d'effectuer plusieurs séquences de connexion, d'écriture et de fermeture. Idéalement, je devrais terminer le thread exécutant SSL_read en réponse à la fermeture. C'est parce que pour la prochaine connexion, nous aurions un nouveau pointeur ssl et donc nous ne voulons pas effectuer de lecture sur l'ancien pointeur ssl. Mais le problème est quand je fais SSL_read, je suis bloqué jusqu'à ce qu'il y ait des données disponibles dans le tampon SSL. Il est bloqué sur le pointeur SSL, même lorsque j'ai fermé la connexion SSL dans l'autre thread.SSL_read bloque indéfiniment

while(1) { 
    memset(sbuf, 0, sizeof(uint8_t) * TLS_READ_RCVBUF_MAX_LEN); 

    read_data_len = SSL_read(con, sbuf, TLS_READ_RCVBUF_MAX_LEN); 
    switch (SSL_get_error(con, read)) { 
     case SSL_ERROR_NONE: 
. 
. 
. 
} 

J'ai essayé toutes les solutions possibles au problème mais ne fonctionne pas. La plupart du temps, j'ai essayé d'indiquer qu'il y avait peut-être des données dans le tampon SSL, mais aucune indication n'est donnée.

J'ai essayé:

- Faire SSL_pending d'abord savoir s'il existe des données dans un tampon SSL. Mais cela renvoie toujours

- En sélectionnant sur la socket Openssl pour voir si elle renvoie une valeur supérieure à zéro. Mais il revient toujours à zéro. - Rendre le socket non bloquant et essayer le select, mais cela ne semble pas fonctionner. Je ne suis pas sûr d'avoir bien compris le code.

Un exemple d'où j'ai utilisé select pour bloquer le socket est le suivant. Mais select renvoie toujours zéro.

while(1) { 
    // The use of Select here is to timeout 
    // while waiting for data to read on SSL. 
    // The timeout is set to 1 second 
    i = select(width, &readfds, NULL, 
      NULL, &tv); 
    if (i < 0) { 
     // Select Error. Take appropriate action for this error 
    } 

    // Check if there is data to be read 
    if (i > 0) { 
     if (FD_ISSET(SSL_get_fd(con), &readfds)) { 
      // TODO: We have data in the SSL buffer. But are we 
      //  sure that the data is from read buffer? If not, 
      //  SSL_read can be stuck indefinitely. 
      //  Maybe we can do SSL_read(con, sbuf, 0) followed 
      //  by SSL_pending to find out? 
      memset(sbuf, 0, sizeof(uint8_t) * TLS_READ_RCVBUF_MAX_LEN); 

      read_data_len = SSL_read(con, sbuf, TLS_READ_RCVBUF_MAX_LEN); 
      error = SSL_get_error(con, read_data_len); 
      switch (error) { 
. 
. 
} 

Comme vous pouvez le voir, je l'ai essayé plusieurs façons d'obtenir le fil d'effectuer SSL_read mettre fin en réponse à fermer, mais je na pas faire fonctionner comme je m'y attendais. Est-ce que quelqu'un a réussi à faire fonctionner SSL_read correctement? La prise non-bloquante est-elle la seule solution à mon problème? Pour bloquer la socket comment résolvez-vous le problème de quitter SSL_read si vous n'obtenez jamais de réponse pour la commande? Pouvez-vous donner un exemple de solution de travail pour socket non bloquant avec lire?

Répondre

0

Je peux vous montrer un exemple de travail de socket client non bloquant avec SSL ... https://github.com/darrenjs/openssl_examples

Il utilise des sockets non bloquants avec linux IO standard (basé sur la boucle d'événements sondage). Les données brutes sont lues à partir de la socket puis introduites dans la mémoire SSL BIO, qui effectue ensuite le déchiffrement.

L'approche que j'ai utilisée était à simple thread. Un seul thread effectue la connexion, l'écriture et la lecture. Cela signifie qu'il ne peut y avoir aucun problème associé à un thread fermant un socket, alors qu'un autre thread essaye d'utiliser ce socket. En outre, comme indiqué par la FAQ SSL, "une connexion SSL ne peut pas être utilisée simultanément par plusieurs threads" (https://www.openssl.org/docs/faq.html#PROG1), donc l'approche mono-thread évite les problèmes avec écriture SSL simultanée & read. Le problème avec l'approche monothread est que vous devez ensuite créer un mécanisme de signalisation de la file d'attente synchronisée & pour l'envoi et la conservation des données en attente de sortie (par exemple, les commandes que vous souhaitez envoyer du client au serveur), et obtenir la boucle d'événement de socket pour détecter quand il y a des données en attente pour l'écrire et le retirer de la file d'attente etc. Pour cela je regarderais standard std :: list, std :: mutex etc., et soit pipe2 ou eventfd pour signaler l'événement boucle.