Hello there,

 

New to the list and using Boost Asio.

 

I’ve implemented an SSL connection using async_connect ok, but find that it seems to leave resources allocated when completed and the SSL connection object is destroyed.

The application using the Boost SSL functionality creates a socket connection as required then releases it.

Its running on a windows platform with Microsoft Visual Studio 2008 and Boost 1.36.0.

 

The problem can be easily illustrated by simple modification of http://www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/example/ssl/client.cpp to place the main functionality in a loop.

Then monitoring the process using TaskManager to display Mem Usage and Handles shows both steadily going up. The number of handles increments by 1,2 or 3 on each async_connect.

This happens regardless of whether it actually manages to connect or not.

A modification to not use SSL has no effect.

A further modification to use a synchronous connect and the program then does not bleed resources.

 

 Is this a known problem ?

Or is there something which I should be releasing myself ?

 

The actual code I tested is shown below.

The relevant parts are:

1)      main()  line 140: while (true)

2)      class client() line 32: simple socket connect (resources released ok)

3)      class client() line 41: original async_connect (resources not released ok)

 

Any ideas gratefully received !

 

/Jim

 

//

// client.cpp

// ~~~~~~~~~~

//

// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)

//

// Distributed under the Boost Software License, Version 1.0. (See accompanying

// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

//

 

#include <cstdlib>

#include <iostream>

#include <boost/bind.hpp>

#include <boost/asio.hpp>

#include <boost/asio/ssl.hpp>

using boost::asio::ip::tcp;

 

enum { max_length = 1024 };

 

class client

{

public:

  client(boost::asio::io_service& io_service,

         boost::asio::ssl::context& context,

         boost::asio::ip::tcp::resolver::iterator endpoint_iterator)

    : simpleSocket_(io_service)

      ,socket_(io_service, context)

  {

    boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;

 

// This consumes no resources

    simpleSocket_.connect(endpoint);

 

// This consumes resources

//     simpleSocket_.async_connect(endpoint,

//                       boost::bind(&client::handle_connect, this,

//                       boost::asio::placeholders::error,

//                       ++endpoint_iterator));

 

// This original code consumes resources

//     socket_.lowest_layer().async_connect(endpoint,

//         boost::bind(&client::handle_connect, this,

//           boost::asio::placeholders::error, ++endpoint_iterator));

  }

 

  void handle_connect(const boost::system::error_code& error,

      boost::asio::ip::tcp::resolver::iterator endpoint_iterator)

  {

    std::cout << "handled connect";

      return;

    if (!error)

    {

      socket_.async_handshake(boost::asio::ssl::stream_base::client,

          boost::bind(&client::handle_handshake, this,

            boost::asio::placeholders::error));

    }

    else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator())

    {

      socket_.lowest_layer().close();

      boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;

      socket_.lowest_layer().async_connect(endpoint,

          boost::bind(&client::handle_connect, this,

            boost::asio::placeholders::error, ++endpoint_iterator));

    }

    else

    {

      std::cout << "Connect failed: " << error << "\n";

    }

  }

 

  void handle_handshake(const boost::system::error_code& error)

  {

    if (!error)

    {

      std::cout << "Enter message: ";

      std::cin.getline(request_, max_length);

      size_t request_length = strlen(request_);

 

      boost::asio::async_write(socket_,

          boost::asio::buffer(request_, request_length),

          boost::bind(&client::handle_write, this,

            boost::asio::placeholders::error,

            boost::asio::placeholders::bytes_transferred));

    }

    else

    {

      std::cout << "Handshake failed: " << error << "\n";

    }

  }

 

  void handle_write(const boost::system::error_code& error,

      size_t bytes_transferred)

  {

    if (!error)

    {

      boost::asio::async_read(socket_,

          boost::asio::buffer(reply_, bytes_transferred),

          boost::bind(&client::handle_read, this,

            boost::asio::placeholders::error,

            boost::asio::placeholders::bytes_transferred));

    }

    else

    {

      std::cout << "Write failed: " << error << "\n";

    }

  }

 

  void handle_read(const boost::system::error_code& error,

      size_t bytes_transferred)

  {

    if (!error)

    {

      std::cout << "Reply: ";

      std::cout.write(reply_, bytes_transferred);

      std::cout << "\n";

    }

    else

    {

      std::cout << "Read failed: " << error << "\n";

    }

  }

 

private:

  tcp::socket simpleSocket_;

  boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;

  char request_[max_length];

  char reply_[max_length];

};

 

int main(int argc, char* argv[])

{

  try

  {

    if (argc != 3)

    {

      std::cerr << "Usage: client <host> <port>\n";

      return 1;

    }

 

    while (true)

    {

        std::cout << "Creating service\n";

        boost::asio::io_service io_service;

        boost::asio::ip::tcp::resolver resolver(io_service);

        boost::asio::ip::tcp::resolver::query query(argv[1], argv[2]);

        boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);

 

        boost::asio::ssl::context ctx(io_service, boost::asio::ssl::context::sslv23);

        ctx.set_verify_mode(boost::asio::ssl::context::verify_peer);

        ctx.load_verify_file("ca.pem");

 

        client c(io_service, ctx, iterator);

 

        io_service.run();

    }

  }

  catch (std::exception& e)

  {

    std::cerr << "Exception: " << e.what() << "\n";

  }

 

  return 0;

}