2

我有一个嵌入式应用程序,它使用 OpenSSL v0.9.7e 进行客户端 ssl 事务。我一直在使用与子线程共享的全局会话指针。它监控的每个 COM 端口都有一个线程。它在大多数情况下都有效。但是,每隔一段时间(每 500 次左右的事务),它就会在 SSL_connect() 内部崩溃。我做了一些探索,它似乎正在自行删除会话。因此,我怀疑其中一个线程在执行此操作时处于事务的中间。如果引用计数> 0,我会认为它不会删除它。

有谁知道是否可以通过全局共享会话来做到这一点?我是否应该每个线程(COM 端口)使用一个会话。这是代码。为简洁起见,我省略了所有错误检查。

    int send_ssl_post(){
  BIO *bio;
  SSL *ssl;
  int ret = -1;
  int sockfd;
  int sslRet;

  ssl = NULL;

  g_ctx = setup_client_ctx( );
  ssl = SSL_new( g_ctx );
  SSL_set_session( ssl, g_session );
  sockfd = tcpConnect( url, true );
  bio = BIO_new_socket( sockfd, BIO_NOCLOSE );
  SSL_set_bio( ssl, bio, bio ); // SSL_set_bio cannot fail
  sslRet = SSL_connect( ssl );

  // free the session. We may change sessions below
  if ( g_session != NULL ) {
     SSL_SESSION_free( g_session );
  }

  // SSL write
  ret = SSL_write( ssl, data, strlen( data ) );

  ret = SSL_read( ssl, resp, respSize ); // time-out logic should be in

  g_session = SSL_get1_session( ssl );

  if ( ssl != NULL ) {
     SSL_shutdown( ssl );
     SSL_free( ssl );
  }

  if ( sockfd > 0 ){
     close( sockfd ); 
  }

  ERR_remove_state( 0 ); // free the memory that did not freed (buggy in this SSL version)
  return 0;
}

我也有两个thead锁定回调函数:

static void locking_function( int mode, int n, const char * file, int line ) {
   if ( mode & CRYPTO_LOCK ){
      //logger( DEBUG, "CRYPTO Lock file: %s, line: %d, n: %d", file, line, n );
      pthread_mutex_lock( &ssl_mutex_array[n] );
   } else {
      //logger( DEBUG, "CRYPTO Unlock file: %s, line: %d, n: %d", file, line, n );
      pthread_mutex_unlock( &ssl_mutex_array[n] );
   }
}

static unsigned long id_function( void ) {
   //logger( DEBUG, "CRYPTO Id function");
   return ((unsigned long) pthread_self());
}

int setupSSLThreadLock( void ) {
   int i;

   //logger( DEBUG, "setupSSLThreadLock with %d number of locks", CRYPTO_num_locks() );
   ssl_mutex_array = OPENSSL_malloc( CRYPTO_num_locks( ) * sizeof (pthread_mutex_t) );

   if ( !ssl_mutex_array ){
      return 0;
   }

   for ( i = 0; i < CRYPTO_num_locks( ); i++ ){
      pthread_mutex_init( &ssl_mutex_array[i], NULL );
   }
   CRYPTO_set_id_callback( id_function );
   CRYPTO_set_locking_callback( locking_function );
   return 1;
}

int cleanupSSLThreadLock( void ) {
   int i;

   if ( ssl_mutex_array == NULL ){
      return 0;
   }
   CRYPTO_set_id_callback( NULL );
   CRYPTO_set_locking_callback( NULL );
   for ( i = 0; i < CRYPTO_num_locks( ); i++ ){
      pthread_mutex_destroy( &ssl_mutex_array[i] );
   }
   OPENSSL_free( ssl_mutex_array );
   ssl_mutex_array = NULL;
   return 1;
}

任何帮助将不胜感激。

4

1 回答 1

1

如果send_ssl_post()同时由两个线程运行,你就有了比赛。考虑函数的这两个部分:

  SSL_set_session( ssl, g_session );

  // free the session. We may change sessions below
  if ( g_session != NULL ) {
     SSL_SESSION_free( g_session );
  }

SSL_SESSION_free()当一个线程调用全局会话和尝试使用它来设置会话的其他线程之间存在竞争。如果空闲首先发生,则尝试使用它的线程将访问已释放的内存。

你可以通过互斥来解决这场竞赛。一个周围的SSL_set_session()电话。

acquire_session_lock();
if ( g_session != NULL ) {
    SSL_set_session( ssl, g_session );
}
release_session_lock();

电话周围的其他SSL_SESSION_free()人:

acquire_session_lock();
if ( g_session != NULL ) {
    SSL_SESSION_free( g_session );
    g_session = NULL;
}
release_session_lock();
于 2013-05-31T20:04:03.933 回答