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;
}