0

接続が成功して使用された後に SSLSocket を削除すると、アクセス違反が発生します

Application_client_example.exe の 0x770f32d0 で未処理の例外: 0xC0000005: アクセス違反の読み取り場所 0x00000dd3c0c76c48。

アクセス違反は、ブースト コードの次の部分から発生しています。

engine::~engine()
{
  if (SSL_get_app_data(ssl_))
  {
    delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));
    SSL_set_app_data(ssl_, 0);
  }

  ::BIO_free(ext_bio_);
  ::SSL_free(ssl_);
}

このコードは、ブースト バージョン 1.47 で機能しました。私が行った唯一の変更は、ブースト ライブラリを現在のバージョン 1.53 に更新し、ライブラリと exe の 64 ビット バージョンをビルドしたことです。

作成および削除される SSL 接続は次のとおりです。

// Connect 
    SSLSocket* socket = new SSLSocket();

    if ((errorCode = socket->connect((char*)server.c_str(), (char*)port.c_str())) != 0) 
    {
        Logger::log(log4cpp::Priority::FATAL, "Secure Socket Error");

        return errorCode;
    }    

    delete socket

これがSSLSocketデストラクタです

SSLSocket::~SSLSocket(void)
{
    try {
        sslSocket->shutdown();
        delete sslSocket;
    }
    catch (std::exception& e)
    {
        std::string exception(e.what());
        Logger::log(log4cpp::Priority::FATAL, "[SSLSocket] Error deleting sslSocket. Exception: " + exception);
    }

}

SSLSocket の定義は次のとおりです。SSLSocket は基本的に、ssl ソケットの単なるラッパー クラスです。

#ifndef __SSLSOCKET__
#define __SSLSOCKET__

#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/asio/ssl.hpp>
#include <string>

#include "Logger.h"
#include "Config.h"

using namespace boost::asio;

class SSLSocket
{
private:
    io_service io_service;
    ssl::stream<ip::tcp::socket>* sslSocket;

public:
    SSLSocket(void);
    ~SSLSocket(void);

    DWORD connect(char* remoteServer, char* remotePort);
    DWORD sendString(std::string data);
    std::string receiveString(void);
};

#endif
4

2 に答える 2

0

これは、SSLSockets クラスでソケット接続をシャットダウンするために使用するコードです。これは、SSL 接続用の ASIO のラッパーでもあります。Windows 用 Boost ASIO バージョン 1.52 と 32 ビット ライブラリを使用しています。私も、適切に行う方法を発見するまで、ソケットをシャットダウンするときに例外を受け取っていました。

void SSLSocket::Stop()
{
   // This method calls the shutdown method on the socket in order to stop reads or writes that might be going on.  If this is not done, then an exception will be thrown
   // when it comes time to delete this object.
   //
   boost::system::error_code EC;
   try
   {
      // This method can be called from the handler as well.  So once the ShuttingDown flag is set, don't go throught the same code again.
      if (ShuttingDown)
         return;
      LockCode->Acquire(); // Single thread the code.
      // Only do this once.
      if (!ShuttingDown)
      {
         ShuttingDown = true;
         pSocket->next_layer().cancel();
         pSocket->shutdown(EC);
         // Note that EC will usually have an error condition, but it does not seem to be a problem.
         delete pSocket;
         pSocket = 0;
         ReqAlive = false;
         SetEvent(hEvent);
         IOService->stop();
         LobbySocketOpen = false;
         // Wait until the 2 threads have exited before returning.
         WorkerThreads.join_all();
      }
      LockCode->Release();
      delete LockCode;
      LockCode = 0;
   }
   catch (std::exception& e)
   {
      stringstream ss;
      ss << "SSLSocket::Stop: threw an error - " << e.what() << ".\n";
      Log.LogString(ss.str(), LogError);
      Stop();
   }
}

Lock 変数に関する質問への回答

Lock は、クリティカル セクション (Microsoft に固有) をカプセル化して、コードをシングル スレッド化できるようにするクラスです。その定義は次のとおりです。

class Lock
{
public:
   Lock()
   {
      ::InitializeCriticalSection(&CS);
   }

   ~Lock()
   {
      ::DeleteCriticalSection(&CS);
   }

   void Acquire()
   {
      ::EnterCriticalSection(&CS);
   }

   void Release()
   {
      ::LeaveCriticalSection(&CS);
   }

private:
   Lock(const Lock&);
   Lock& operator=(const Lock&);
   CRITICAL_SECTION CS;
};

ソケット作成コード

これは、SSL コンテキスト オブジェクトと SSL ソケット オブジェクトを作成するために使用するコードです。

void SSLSocket::Connect(SSLSocket* psSLS, const string& serverPath, string& port)
{
   // Connects to the server.
   // serverPath - specifies the path to the server.  Can be either an ip address or url.
   // port - port server is listening on.
   //
   try
   {
      LockCode->Acquire(); // Single thread the code.
      // If the user has tried to connect before, then make sure everything is clean before trying to do so again.
      if (pSocket)
      {
         delete pSocket;
         pSocket = 0;
      }                                                                                                  
      // If serverPath is a URL, then resolve the address.
      if ((serverPath[0] < '0') || (serverPath[0] > '9')) // Assumes that the first char of the server path is not a number when resolving to an ip addr.
      {
         // Create the resolver and query objects to resolve the host name in serverPath to an ip address.
         boost::asio::ip::tcp::resolver resolver(*IOService);
         boost::asio::ip::tcp::resolver::query query(serverPath, port);
         boost::asio::ip::tcp::resolver::iterator EndpointIterator = resolver.resolve(query);
         // Set up an SSL context.
         boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client);
         // Specify to not verify the server certificiate right now.
         ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
         // Init the socket object used to initially communicate with the server.
         pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx);
         //
         // The thread we are on now, is most likely the user interface thread.  Create a thread to handle all incoming socket work messages.
         // Only one thread is created to handle the socket I/O reading and another thread is created to handle writing.
         if (!RcvThreadCreated)
         {
            WorkerThreads.create_thread(boost::bind(&SSLSocket::RcvWorkerThread, this));
            RcvThreadCreated = true;
            WorkerThreads.create_thread(boost::bind(&SSLSocket::SendWorkerThread, this));
         }
         // Try to connect to the server.  Note - add timeout logic at some point.
         boost::asio::async_connect(pSocket->lowest_layer(), EndpointIterator,
            boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholders::error));
      }
      else
      {
         // serverPath is an ip address, so try to connect using that.
         //
         stringstream ss1;
         boost::system::error_code EC;
         ss1 << "SSLSocket::Connect: Preparing to connect to game server " << serverPath << " : " << port << ".\n";
         Log.LogString(ss1.str(), LogInfo);
         // Create an endpoint with the specified ip address.
         const boost::asio::ip::address IP(boost::asio::ip::address::from_string(serverPath));
         int iport = atoi(port.c_str());
         const boost::asio::ip::tcp::endpoint EP(IP, iport);
         // Set up an SSL context.
         boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client);
         // Specify to not verify the server certificiate right now.
         ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
         // Init the socket object used to initially communicate with the server.
         pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx);
         //
         // Try to connect to the server.  Note - add timeout logic at some point.
         pSocket->next_layer().connect(EP, EC);
         if (EC)
         {
            // Log an error.  This worker thread should exit gracefully after this.
            stringstream ss;
            ss << "SSLSocket::Connect: connect failed to " << sClientIp << " : " << uiClientPort << ".  Error: " << EC.message() + ".\n";
            Log.LogString(ss.str(), LogError);
         }
         stringstream ss;
         ss << "SSLSocket::Connect: Calling HandleConnect for game server " << serverPath << " : " << port << ".\n";
         Log.LogString(ss.str(), LogInfo);
         HandleConnect(EC);
      }
   }
   catch (std::exception& e)
   {
      stringstream ss;
      ss << "SSLSocket::Connect: threw an error - " << e.what() << ".\n";
      Log.LogString(ss.str(), LogError);
      Stop();
   }
   LockCode->Release();
}
于 2013-05-03T01:41:52.150 に答える