I need to write a class that handle ssl connection (read/write char array) to a black box server. I need to implement disconnect/connect function. But it ain't work as expected.
Use case:
- User connect to server (worked: can send and receive messages)
- User disconnect to server, wait for a while then reconnect again. (Failed: it only works when the duration is short: like 10 secs. If longer than that handle_connect()return errorconnection timed out)
Here is the source code to the class and how I use it:
boost::asio::io_service &mioService;
SSLHandler* mpSSLConnection;
void Connector::setupConnection()
{
    try{
        std::string port = std::to_string(mPort);
        boost::asio::ip::tcp::resolver resolver(mioService);
        boost::asio::ip::tcp::resolver::query query(mHost, port);
        boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
        boost::asio::ssl::context context(boost::asio::ssl::context::sslv23);
        //    context.load_verify_file("key.pem");
        if(mpSSLConnection == nullptr)
            mpSSLConnection = new SSLHandler(mioService,context,iterator,this);
    }catch (std::exception& e){
        std::cerr << "Exception: " << e.what() << "\n";
    }
    // actually this line is called from outside the func
    mpSSLConnection->connectToServer();
}
and disconnect like this
void Connector::disconnect()
{
    isSetDisconnectedToSrv = true;
    mpSSLConnection->setIsDestructing(true);
    QThread::msleep(500);
    delete mpSSLConnection;
    mpSSLConnection = nullptr;
//    setupConnection();
    isConnectedToServer =false; // we did delete the object handle the ssl connection so...
    mpHandler->onServerDisconnected(); // just report to upper layer
}
Finally, the class source code:
#ifndef SSLHANDLER_H
#define SSLHANDLER_H
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <queue>
#include <boost/lockfree/spsc_queue.hpp>
class Connector;
const int READ_SIZE =0;
const int READ_MSG=1;
class SSLHandler
{
public:
    SSLHandler(boost::asio::io_service& io_service, boost::asio::ssl::context& context, boost::asio::ip::tcp::resolver::iterator endpoint_iterator, Connector* pConnector)
    : socket_(io_service, context) , mEndpointIterator (endpoint_iterator) , mpConnector (pConnector),
    timer_{ io_service},
    isConnectionOk {false}
    {
        LOG_TRACE << "creating new sslhandler";
        socket_.set_verify_mode(boost::asio::ssl::context::verify_none);
        socket_.set_verify_callback(boost::bind(&SSLHandler::verify_certificate, this, _1, _2));
        mode = READ_SIZE;
    }
    ~SSLHandler();
    bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx);
    void handle_connect(const boost::system::error_code& error);
    void handle_handshake(const boost::system::error_code& error);
    void handle_write(const boost::system::error_code& error, size_t bytes_transferred);
    void handle_write_auth(const boost::system::error_code& error, size_t bytes_transferred);
    void handle_read_msgsize(const boost::system::error_code& error, size_t bytes_transferred);
    void handle_read_message(const boost::system::error_code& error, size_t bytes_transferred);
    void connectToServer();
    void do_reconnect();
    void handle_reconnect_timer(boost::system::error_code ec);
    void writeMessage(std::vector<char> &array);
    void setRequestMsg(std::vector<char> &&array);
    void setIsDestructing(bool value);
private:
    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
    boost::asio::ip::tcp::resolver::iterator mEndpointIterator;
    boost::asio::deadline_timer timer_;
    char reply_[0x1 << 16]; //=65356 bytes
    int mode;
    uint32_t size;
    std::vector<char> requestMsg;
    std::vector<char> replyMsg;
    Connector* mpConnector; // ptr to object compose message
    std::queue<std::vector < char> >  mQueueMsg;
    bool isConnectionOk;
    bool isDestructing =false;
private:
    void writeMessageWithQueue(std::vector<char> &array);
};
#endif // SSLHANDLER_H
#include "sslhandler.h"
#include "connector.h"
#include "BoostLogger.h"
#include <QThread>
#include "boost/enable_shared_from_this.hpp"
SSLHandler::~SSLHandler()
{
    LOG_FATAL << "ssl handler shutdown";
    if(isConnectionOk){
        socket_.lowest_layer().close();
        boost::system::error_code ec;
        socket_.shutdown(ec);
        if(ec){
            LOG_FATAL << "ssl handler socket shutdown with err: " << ec.message();
        }
        LOG_TRACE << "ssl handler shutdown complete";
    }
}
bool SSLHandler::verify_certificate(bool preverified, boost::asio::ssl::verify_context &ctx)
{
    char subject_name[256];
    X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
    X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
    std::cout << "Verifying:\n" << subject_name << std::endl;
    return preverified;
}
void SSLHandler::handle_connect(const boost::system::error_code &error)
{
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    LOG_TRACE << "get past destructing";
    if(!error){
        isConnectionOk = true;
        LOG_TRACE << "Connection OK!" << std::endl;
        socket_.async_handshake(boost::asio::ssl::stream_base::client, boost::bind(&SSLHandler::handle_handshake, this, boost::asio::placeholders::error));
    }else{
        LOG_FATAL << "Connect failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}
void SSLHandler::handle_handshake(const boost::system::error_code &error)
{
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    if(!error){
        std::cout << "Sending request: " << std::endl;
        boost::asio::async_write(socket_,
           boost::asio::buffer(requestMsg.data(), requestMsg.size()),
           boost::bind(&SSLHandler::handle_write_auth, this,
               boost::asio::placeholders::error,
               boost::asio::placeholders::bytes_transferred));
    }else{
        LOG_FATAL << "Handshake failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}
void SSLHandler::handle_write(const boost::system::error_code &error, size_t bytes_transferred)
{
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    if (error) {
        LOG_FATAL << "Write failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
    Q_UNUSED(bytes_transferred);
    usleep(1e4);
    if (!mQueueMsg.empty()) {
        mQueueMsg.pop();
        if(!mQueueMsg.empty()){
            auto msg = mQueueMsg.front();
            writeMessageWithQueue(msg);
        }
    }
    else{
        LOG_ERROR << "Empty queue messages!";
    }
}
void SSLHandler::handle_write_auth(const boost::system::error_code &error, size_t bytes_transferred)
{
    usleep(1e5);
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    if (!error){
        if(mode==READ_SIZE){
            mode = READ_MSG;
            std::cerr << "\nSending request read size OK!\n" << std::endl;
            //      char respond[bytes_transferred] = "";
            boost::asio::async_read(socket_, boost::asio::buffer(reply_,4),
                boost::bind(&SSLHandler::handle_read_msgsize,
                    this,
                    boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred));
//            std::cerr << "respond is " ;
        }
    }else{
        LOG_FATAL << "Write failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}
void SSLHandler::handle_read_msgsize(const boost::system::error_code &error, size_t bytes_transferred)
{
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    if (!error){
        //first 4 bytes contain size of message
        size = getFirstFour();
        mode = READ_SIZE;
        boost::asio::async_read(socket_, boost::asio::buffer(reply_,size),
            boost::bind(&SSLHandler::handle_read_message,
                this,
//                                            mWriteId++,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));
    }else{
        LOG_FATAL << "Read failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}
void SSLHandler::handle_read_message(const boost::system::error_code &error, size_t bytes_transferred)
{
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    if (!error){
        replyMsg.clear();
        replyMsg.assign(reply_,reply_+ size);
        mpConnector->setReadMsg(replyMsg);
        mode = READ_SIZE;
        // read next message size
        boost::asio::async_read(socket_, boost::asio::buffer(reply_,4),
            boost::bind(&SSLHandler::handle_read_msgsize,
                this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));
    }else{
        LOG_FATAL << "Read failed: " << error.message() << std::endl;
        mpConnector->sendDisconnectedStatus();
        do_reconnect();
    }
}
void SSLHandler::connectToServer()
{
//    boost::asio::ip::tcp::resolver r(socket_.get_io_service());
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    boost::asio::async_connect(socket_.lowest_layer(), mEndpointIterator, boost::bind(&SSLHandler::handle_connect, this, boost::asio::placeholders::error));
    LOG_TRACE << "async_connect called";
}
void SSLHandler::do_reconnect()
{
//    return;
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
//    socket_.shutdown();
    isConnectionOk = false;
    else{
        socket_.lowest_layer().cancel();
        timer_.expires_from_now(boost::posix_time::millisec(500));
        timer_.async_wait(boost::bind(&SSLHandler::handle_reconnect_timer, this, boost::asio::placeholders::error()));
    }
}
void SSLHandler::handle_reconnect_timer(boost::system::error_code ec)
{
    if(!ec){
        connectToServer();
    }
    else{
        LOG_TRACE << "Error with reconnect timer : " << ec.message();
    }
}
void SSLHandler::writeMessageWithQueue(std::vector<char> &array)
{
//    std::cerr << "write : " << (void*) array.data() << " | " << array.size() << std::endl;
    if(isDestructing){
        LOG_TRACE << "Is destructing ssl connect so abort " ;
        return;
    }
    boost::asio::async_write(socket_,
       boost::asio::buffer(array.data(), array.size()),
       boost::bind(&SSLHandler::handle_write, this,
           boost::asio::placeholders::error,
           boost::asio::placeholders::bytes_transferred));
}
void SSLHandler::writeMessage(std::vector<char> &array)
{
    if(mQueueMsg.size()==0){
        mQueueMsg.push(array);
        writeMessageWithQueue(array);
    }
    else
        mQueueMsg.push(array);
}
void SSLHandler::setRequestMsg(std::vector<char> &&array)
{
    requestMsg = std::move(array);
}
void SSLHandler::setIsDestructing(bool value)
{
    LOG_INFO << "ssl connection destructing set as " << value;
    isDestructing = value;
    if(isDestructing == true){
        if(isConnectionOk){
            socket_.lowest_layer().cancel();
            //        socket_.shutdown();
            LOG_INFO << "ssl connection destructing get pass shutdown";
        }
    }
}
PS: Here is the handler tracking which is weird, after (call) disconnect() and reconnect again: no hander was fired, so no handshake after connection is established :( 
@asio|1521627714.863517|0|resolver@0x7fbe2affc898.cancel Empty fz params!Empty fz rules!Empty fz param!@asio____________ socket_: 0x7fbe10005150 @asio____________192.168.2.36 @asio|1521627714.864161|0*1|socket@0x7fbe10005150.async_connect @asio: connect called @asio|1521627714.865136|>1|ec=system:0 @asio|1521627714.865375|1*2|socket@0x7fbe10005150.async_send @asio|1521627714.865416|<1| @asio|1521627714.865421|>2|ec=system:0,bytes_transferred=517 @asio|1521627714.865429|2*3|socket@0x7fbe10005150.async_receive @asio|1521627714.865451|<2| @asio|1521627714.866829|>3|ec=system:0,bytes_transferred=994 @asio|1521627714.867764|3*4|socket@0x7fbe10005150.async_send @asio|1521627714.867792|<3| @asio|1521627714.867798|>4|ec=system:0,bytes_transferred=326 @asio|1521627714.867809|4*5|socket@0x7fbe10005150.async_receive @asio|1521627714.867817|<4| @asio|1521627714.870094|>5|ec=system:0,bytes_transferred=234 @asio|1521627714.870271|5*6|socket@0x7fbe10005150.async_send @asio|1521627714.870318|<5| @asio|1521627714.870333|>6|ec=system:0,bytes_transferred=154 @asio|1521627714.970430|6*7|socket@0x7fbe10005150.async_receive @asio|1521627714.970443|<6| @asio|1521627714.970449|>7|ec=system:0,bytes_transferred=138 @asio|1521627714.970470|7*8|socket@0x7fbe10005150.async_receive @asio|1521627714.970475|<7| @asio|1521627714.970479|>8|ec=system:0,bytes_transferred=0 @asio|1521627714.971418|8*9|socket@0x7fbe10005150.async_send @asio|1521627714.971771|8*10|deadline_timer@0x5290628.async_wait @asio|1521627714.972004|8*11|socket@0x7fbe10005150.async_receive @asio|1521627714.972012|<8| @asio|1521627714.972017|>9|ec=system:0,bytes_transferred=138 @asio|1521627714.982098|9*12|socket@0x7fbe10005150.async_send @asio|1521627714.982115|<9| @asio|1521627714.982121|>12|ec=system:0,bytes_transferred=138 @asio|1521627714.992214|12*13|socket@0x7fbe10005150.async_send @asio|1521627714.992244|<12| @asio|1521627714.992255|>11|ec=system:0,bytes_transferred=292 @asio|1521627714.992278|11*14|socket@0x7fbe10005150.async_receive @asio|1521627714.992284|<11| @asio|1521627714.992290|>13|ec=system:0,bytes_transferred=186 @asio|1521627715.002355|<13| @asio|1521627715.002363|>14|ec=system:0,bytes_transferred=0 @asio|1521627715.002469|14*15|socket@0x7fbe10005150.async_receive @asio|1521627715.002479|<14| @asio|1521627715.002487|>15|ec=system:0,bytes_transferred=0 @asio|1521627715.002495|15*16|socket@0x7fbe10005150.async_receive @asio|1521627715.002500|<15| @asio|1521627715.002505|>16|ec=system:0,bytes_transferred=0 @asio|1521627715.002550|16*17|socket@0x7fbe10005150.async_receive @asio|1521627715.002561|<16| @asio|1521627715.002566|>17|ec=system:0,bytes_transferred=154 @asio|1521627715.002581|17*18|socket@0x7fbe10005150.async_receive @asio|1521627715.002586|<17| @asio|1521627715.002590|>18|ec=system:0,bytes_transferred=0 @asio|1521627715.002636|18*19|socket@0x7fbe10005150.async_receive @asio|1521627715.002653|<18| @asio|1521627721.861983|>10|ec=system:0 @asio|1521627721.862105|10*20|socket@0x7fbe10005150.async_send @asio|1521627721.862139|10|deadline_timer@0x5290628.cancel @asio|1521627721.862144|10*21|deadline_timer@0x5290628.async_wait @asio|1521627721.862258|<10| @asio|1521627721.862268|>20|ec=system:0,bytes_transferred=138 @asio|1521627721.872365|<20| @asio|1521627721.872398|>19|ec=system:0,bytes_transferred=138 @asio|1521627721.872436|19*22|socket@0x7fbe10005150.async_receive @asio|1521627721.872443|<19| @asio|1521627721.872447|>22|ec=system:0,bytes_transferred=0 @asio|1521627721.872503|22*23|socket@0x7fbe10005150.async_receive @asio|1521627721.872515|<22| @asio|1521627724.861966|>21|ec=system:0 @asio|1521627724.862091|21*24|socket@0x7fbe10005150.async_send @asio|1521627724.862148|21|deadline_timer@0x5290628.cancel @asio|1521627724.862157|21*25|deadline_timer@0x5290628.async_wait @asio|1521627724.862272|<21| @asio|1521627724.862286|>24|ec=system:0,bytes_transferred=138 @asio|1521627724.872375|<24| @asio|1521627724.872409|>23|ec=system:0,bytes_transferred=138 @asio|1521627724.872457|23*26|socket@0x7fbe10005150.async_receive @asio|1521627724.872465|<23| @asio|1521627724.872469|>26|ec=system:0,bytes_transferred=0 @asio|1521627724.872510|26*27|socket@0x7fbe10005150.async_receive @asio|1521627724.872516|<26| @asio|1521627727.861968|>25|ec=system:0 @asio|1521627727.862084|25*28|socket@0x7fbe10005150.async_send @asio|1521627727.862120|25|deadline_timer@0x5290628.cancel @asio|1521627727.862125|25*29|deadline_timer@0x5290628.async_wait @asio|1521627727.862204|<25| @asio|1521627727.862211|>28|ec=system:0,bytes_transferred=138 @asio|1521627727.872283|<28| @asio|1521627727.872314|>27|ec=system:0,bytes_transferred=138 @asio|1521627727.872362|27*30|socket@0x7fbe10005150.async_receive @asio|1521627727.872366|<27| @asio|1521627727.872371|>30|ec=system:0,bytes_transferred=0 @asio|1521627727.872412|30*31|socket@0x7fbe10005150.async_receive @asio|1521627727.872418|<30| @asio|1521627730.861967|>29|ec=system:0 @asio|1521627730.862072|29*32|socket@0x7fbe10005150.async_send @asio|1521627730.862118|29|deadline_timer@0x5290628.cancel @asio|1521627730.862125|29*33|deadline_timer@0x5290628.async_wait @asio|1521627730.862217|<29| @asio|1521627730.862227|>32|ec=system:0,bytes_transferred=138 @asio|1521627730.872315|<32| @asio|1521627730.872360|>31|ec=system:0,bytes_transferred=138 @asio|1521627730.872406|31*34|socket@0x7fbe10005150.async_receive @asio|1521627730.872412|<31| @asio|1521627730.872416|>34|ec=system:0,bytes_transferred=0 @asio|1521627730.872458|34*35|socket@0x7fbe10005150.async_receive @asio|1521627730.872465|<34| @asio|1521627733.862001|>33|ec=system:0 @asio|1521627733.862114|33*36|socket@0x7fbe10005150.async_send @asio|1521627733.862153|33|deadline_timer@0x5290628.cancel @asio|1521627733.862158|33*37|deadline_timer@0x5290628.async_wait @asio|1521627733.862244|<33| @asio|1521627733.862250|>36|ec=system:0,bytes_transferred=138 @asio|1521627733.872342|<36| @asio|1521627733.872379|>35|ec=system:0,bytes_transferred=138 @asio|1521627733.872416|35*38|socket@0x7fbe10005150.async_receive @asio|1521627733.872422|<35| @asio|1521627733.872424|>38|ec=system:0,bytes_transferred=0 @asio|1521627733.872461|38*39|socket@0x7fbe10005150.async_receive @asio|1521627733.872466|<38| @asio|1521627736.861976|>37|ec=system:0 @asio|1521627736.862158|37*40|socket@0x7fbe10005150.async_send @asio|1521627736.862235|37|deadline_timer@0x5290628.cancel @asio|1521627736.862242|37*41|deadline_timer@0x5290628.async_wait @asio|1521627736.862406|<37| @asio|1521627736.862414|>40|ec=system:0,bytes_transferred=138 @asio|1521627736.872497|<40| @asio|1521627736.872555|>39|ec=system:0,bytes_transferred=138 @asio|1521627736.872622|39*42|socket@0x7fbe10005150.async_receive @asio|1521627736.872638|<39| @asio|1521627736.872641|>42|ec=system:0,bytes_transferred=0 @asio|1521627736.872720|42*43|socket@0x7fbe10005150.async_receive @asio|1521627736.872726|<42| @asio|1521627739.861978|>41|ec=system:0 @asio|1521627739.862096|41*44|socket@0x7fbe10005150.async_send @asio|1521627739.862144|41|deadline_timer@0x5290628.cancel @asio|1521627739.862148|41*45|deadline_timer@0x5290628.async_wait @asio|1521627739.862243|<41| @asio|1521627739.862249|>44|ec=system:0,bytes_transferred=138 @asio|1521627739.872335|<44| @asio|1521627739.872375|>43|ec=system:0,bytes_transferred=138 @asio|1521627739.872421|43*46|socket@0x7fbe10005150.async_receive @asio|1521627739.872425|<43| @asio|1521627739.872429|>46|ec=system:0,bytes_transferred=0 @asio|1521627739.872477|46*47|socket@0x7fbe10005150.async_receive @asio|1521627739.872492|<46| @asio|1521627742.861953|>45|ec=system:0 @asio|1521627742.862121|45*48|socket@0x7fbe10005150.async_send @asio|1521627742.862204|45|deadline_timer@0x5290628.cancel @asio|1521627742.862211|45*49|deadline_timer@0x5290628.async_wait @asio|1521627742.862392|<45| @asio|1521627742.862406|>48|ec=system:0,bytes_transferred=138 @asio|1521627742.872491|<48| @asio|1521627742.872543|>47|ec=system:0,bytes_transferred=138 @asio|1521627742.872592|47*50|socket@0x7fbe10005150.async_receive @asio|1521627742.872600|<47| @asio|1521627742.872605|>50|ec=system:0,bytes_transferred=0 @asio|1521627742.872675|50*51|socket@0x7fbe10005150.async_receive @asio|1521627742.872688|<50| @asio|1521627745.316714|0|socket@0x7fbe10005150.close @asio|1521627745.316777|>51|ec=system:125,bytes_transferred=0 @asio|1521627745.316858|<51| @asio: ~SSLHandler @asio|1521627745.817594|0|resolver@0x7fbe00ff8758.cancel @asio|1521627745.861965|>49|ec=system:0 @asio|1521627745.861984|<49| @asio|1521627749.757091|0|resolver@0x7fbe00ff8648.cancel @asio____________ socket_: 0x7fbde4008890 @asio____________192.168.2.36 @asio|1521627749.757178|0*52|socket@0x7fbde4008890.async_connect @asio: connect called
 
    