SSL_connect от клиента, пока сервер находится в SSL_read - PullRequest
0 голосов
/ 17 февраля 2019

У меня есть неблокирующий сокет, и я использую select для обработки подключений от нескольких клиентов SSL:

Я пробовал предложения по обработке SSL_ERROR_WANT_READ, например, повторный вызов SSL_read или возврат обратно в Select, но, похоже,не работать в моем случае.

while (1)
   {
   start:      
      if (readyCount = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &timeout) < 0)
      {
         exit(EXIT_FAILURE);
      }
      for (int i = 0; i < FD_SETSIZE; ++i)
         if (FD_ISSET(i, &read_fd_set))
         {
            if (i == sockfd)
            {               
               newSocket = accept(sockfd, (struct sockaddr *) &clientname, (socklen_t*)&size);                              
            }
            else
            {
               ssl = SSL_new(ctx);
               SSL_set_fd(ssl, i);
            accept:
               int err = SSL_accept(ssl);
               if (0 >= err)
               {                    // it never goes here 
                  int resultCode = SSL_get_error(ssl, err);
                  switch (resultCode)
                  {                 
                     case SSL_ERROR_NONE:
                        goto accept;
                        break;
                     case SSL_ERROR_ZERO_RETURN:
                        SSL_shutdown(ssl);                        
                        break;
                     case SSL_ERROR_SYSCALL:                     
                        break;
                     case SSL_ERROR_WANT_READ:
                        break;
                     case SSL_ERROR_WANT_WRITE:
                        break;
                     case SSL_ERROR_WANT_CONNECT:
                        break;
                     case SSL_ERROR_WANT_ACCEPT:
                        goto accept;
                        break;
                     case SSL_ERROR_WANT_X509_LOOKUP:
                        break;
                     case SSL_ERROR_SSL:
                        break;                     }
                     default:
                        break;
                  }
               }
               else
               {
                  Call_Read(...)
               }

               SSL_free(ssl);
               close(i);
               FD_CLR(i, &active_fd_set);
            }
         }
   }   


Call_Read(...)
{   
   int fd = SSL_get_fd(ssl);
   fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);

   while (data_size > 0)
   {
      bytes_recv = SSL_read(ssl, data, data_size);
      if (bytes_recv <= 0)
      {
         if (SSL_ERROR_WANT_READ == SSL_get_error(ssl, bytes_recv))
         {
            testtt = SSL_pending(ssl); //always 0
            /*SSL_renegotiate(ssl);
            SSL_do_handshake(ssl);*/
            continue;
         }
         if (SSL_ERROR_WANT_WRITE == SSL_get_error(ssl, bytes_recv))
         {            
            testtt = SSL_pending(ssl);
            int blocked_on_SSL_ERROR_WANT_WRITE = 1;                        
            continue;         }
         }
         return bytes_recv;
      }

      data += bytes_recv;
      data_size -= bytes_recv;
   }
   return 1;
}

Client Write:
{
while (data_size > 0)
      {
         bytes_sent = SSL_write(ssl, data_ptr, data_size);
         if (errno == EPIPE) == doesn’t reach this line, debugger stops with EPIPE
         {
            printf("WRITE socket returned EPIPE”);
            return -1;
         }

         if (bytes_sent < 0)
         {
            int err = SSL_get_error(ssl, bytes_sent);
            switch (err)
            {
               case SSL_ERROR_WANT_READ:
                  printf(" SSL_ERROR_WANT_READ\n");
               case SSL_ERROR_WANT_WRITE:
                  printf(" SSL_ERROR_WANT_WRITE\n");
               default:
                  ;
            }
         }         

         data_ptr += bytes_sent;
         data_size -= bytes_sent;
      }

      return 1;
   }

Я не знаю, как справиться с ситуацией, когда сервер находится в SSL_Read, а некоторые клиенты вызывают SSL_Connect.

В таком сценарииCall_Read будет в бесконечном цикле для SSL_ERROR_WANT_READ.Если я заменим выражение «continue» на флаг, который завершит цикл, и вызывающая сторона вернется к «Выбрать», клиент прервется с ошибкой прерванного канала и даже не достигнет строки «ЗАПИСЬ сокета вернула EPIPE».То же самое произойдет, если я вернусь из цикла чтения обратно в Accept, а не в Select.

Я что-то здесь упускаю, и мне интересно, следует ли мне также внести некоторые изменения в клиент.Есть предложения?

...