删除ssl :: stream <ip :: tcp :: socket> * sslSocket </ip :: tcp :: socket>时增加访问冲突

时间:2013-05-02 23:44:45

标签: c++ boost boost-asio

在成功连接并删除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_);
}

此代码适用于boost版本1.47。我所做的唯一更改是将boost库更新为当前版本1.53并构建了64位版本的库和exe。

以下是创建和删除的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的def。 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

2 个答案:

答案 0 :(得分:0)

这是我用来关闭SSLSockets类中的套接字连接的代码,这也是围绕ASIO进行SSL连接的包装器。我正在使用Boost ASIO版本1.52 for Windows 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();
}

答案 1 :(得分:0)

好的,所以在搜索周围并没有找到任何相关内容之后解决这个问题的原因是我正在将所有的boost库构建为MTd。我假设我会使用MTD构建OpenSSL库但是要知道你是否使用非MT Openssl库它可以正常工作。