【问题标题】:Segmentation fault (SIGSEGV) using boost asio 1.64 when trying to close a SSL socket尝试关闭 SSL 套接字时使用 boost asio 1.64 的分段错误 (SIGSEGV)
【发布时间】:2017-07-04 07:53:36
【问题描述】:

我不明白我必须如何关闭boost::asio ssl 套接字。我已经尝试过多种方式,但它总是会在某些时候引发Segmentation fault。

我一直在阅读以下帖子来解决这种情况: boost asio ssl async_shutdown always finishes with an error?

具体来说,我正在尝试实现

甲方启动shutdown()并等待乙方回应 关机()

请注意,客户端和服务器都在localhost 中运行。

下面是客户端代码:

typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLSocket;

MyClass::MyClass(const std::string &url,
    const std::string &port) throw() :
    m_socket(NULL), m_url(url), m_port(port), m_isConnected(false)
{
}

void MyClass::disconnect()
{
  // See the section "the disconnect method"
}

bool MyClass::tryConnect() throw()
{ 
  boost::asio::io_service ioService;
  boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
  m_socket = new SSLSocket(ioService, ctx);

  tcp::resolver resolver(ioService);
  tcp::resolver::query query(m_url, m_port);

  tcp::resolver::iterator end;
  tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);

  boost::system::error_code error = boost::asio::error::host_not_found;
  boost::asio::connect(m_socket->lowest_layer(), endpoint_iterator, error);

  if(endpoint_iterator == end || error)
  {
    m_isConnected = false;
  }
  else
  {
    m_socket->set_verify_mode(boost::asio::ssl::verify_none);
    m_socket->handshake(SSLSocket::client);

    m_isConnected = true;
  }

  return m_isConnected;
}

void MyClass::write(const std::string &message)
{
  boost::asio::write(*m_socket, boost::asio::buffer(message));
}

std::string MyClass::readUntil(const std::string &until)
{
  boost::asio::read_until(*m_socket, response, until);
  ...
  return response;
}

int main()
{
  MyClass mc(...);

  while(true)
  {
    bool connected = mc.isConnected();

    if(!connected)
    {
      connected = mc.tryConnect();
    }

    if(connected)
    {
      mc.send(...);
      std::string resp = mc.readUntil(...);
      mc.disconnect();
    }
  }
}

断开方法

我已经阅读了 cmets 中链接的帖子,并且我已经更新了 ssl 服务器和客户端。现在,他们都执行了shutdown()操作以正确关闭ssl连接,但是我在关闭套接字时仍然出现错误。

我更新了disconnect() 方法(程序总是崩溃的地方)如下:

...
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> *m_socket;
...
void MyClass::disconnect()
{
  // Shutdown the connection
  // TODO is this the correct way to close a boost asio socket?
  if(m_socket != NULL)
  {
    std::cout << "shutting down the socket, thread = " <<
        pthread_self() << std::endl;

    // I have checked that the thread is always the same, so the problem 
    // is not related with race conditions or similar.

    boost::system::error_code ec;
    m_socket->lowest_layer().shutdown(
        boost::asio::ip::tcp::socket::shutdown_both, ec);

    std::cout <<
        "Shut down, err = " << ec << ", " <<
        "Category: " << ec.category().name() << std::endl;

    if(!ec)
    {
      std::cout << "closing the socket, thread = " <<
         pthread_self() << std::endl;

      if(m_socket->lowest_layer().is_open())
      {
        m_socket->lowest_layer().close(ec);
      }

      std::cout <<
        "Socket closed, err = " << ec << ", " <<  "Category: " <<
        ec.category().name() << std::endl;

      if(!ec)
      {
        std::cout << "Deleting socket... " << std::endl;
        delete m_socket;
        m_socket = NULL;
        std::cout << "Socket deleted" << std::endl;
      }
    }
  }

  m_isConnected = false;
}

错误回溯

bkactrace(来自 disconnect 方法)在这里:

#0  0x4158114f in boost::system::error_code::operator=<boost::asio::error::basic_errors> (this=0x1d, val=boost::asio::error::operation_aborted)
    at .../include/boost/system/error_code.hpp:344
#1  0x41587308 in boost::asio::detail::epoll_reactor::deregister_descriptor (this=0x46463045, descriptor=27, descriptor_data=@0x812ef14: 0x8151ea8, 
    closing=true) at .../include/boost/asio/detail/impl/epoll_reactor.ipp:351
#2  0x41588550 in boost::asio::detail::reactive_socket_service_base::close (this=0x812efbc, impl=..., ec=...)
    at .../include/boost/asio/detail/impl/reactive_socket_service_base.ipp:104
#3  0x415885da in boost::asio::stream_socket_service<boost::asio::ip::tcp>::close (this=0x812efa8, impl=..., ec=...)
    at .../include/boost/asio/stream_socket_service.hpp:174
#4  0x41588630 in boost::asio::basic_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >::close (this=0x812ef08, ec=...)
    at .../include/boost/asio/basic_socket.hpp:385
#5  0x41576383 in MyClass::disconnect (this=0x80a6f58) at ...

查看frame 1,可以看出boost创建的错误是boost::asio::error::operation_aborted;

另外,使用 gdb 运行进程,有时我会看到以下 断言失败:

pthread_mutex_lock.c:312: __pthread_mutex_lock_full: Assertion `(-(e)) != 3 || !robust' failed.

【问题讨论】:

  • SIGABRT 通常表示断言失败。您是否检查了崩溃中的堆栈跟踪?你究竟是如何杀死这个过程的?在您的代码 sn-p 中没有线程,也没有信号处理。你也无缘无故给resolver.resolve(query)打了两次电话。
  • 这个问题的答案可能对你有帮助:What is the proper way to securely disconnect an asio SSL socket?

标签: c++ multithreading sockets boost boost-asio


【解决方案1】:

我找到了问题。

我打开套接字的方法如下:

void connect()
{
  ...
  boost::asio::io_service m_ioService
  ...
  m_sock = new SSLSocket(m_ioService, ...)
}

当connect 方法返回时,m_ioService 超出范围,因此套接字崩溃,因为ioService 已被删除。请注意,m_ioService 是通过引用传递的,而且它是不可复制的。

【讨论】:

    猜你喜欢
    • 2013-02-25
    • 2016-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    • 2016-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多