Search code examples
c++mysqlstringproxyboost-asio

Tcp proxy mysql.The data received from the mysql-client is output in weird symbols


// std:string _sql_statement;
// char _client_data[max_data_length];
// size_t bytes_transferred;

void tcp_proxy::Bridge::handle_read_fclient(const error_code& error, const size_t & bytes_transferred)
{

    if (!error) {
        
        asio::async_write(*_upstream_socket.get(),
            asio::buffer(_client_data, bytes_transferred),
            boost::bind(&Bridge::handle_write_tserver,
                shared_from_this(),
                asio::placeholders::error)
        );
        
        _sql_statement.append(_client_data, bytes_transferred);
        std::cout << _sql_statement << "\n";
    }
    else {
        stop();
    }
}

When i run mysql-client and send sql query, i get this output:

����=9漢     �\�gOx� �u%e��A ��
��jxt�6����                               �bc ���z�
           �-x��w<�0NH�+�,�/�#�'�0�$�(��g@�kj���        ��
23895�A��<=/��

*(

+-3GEA1�����Ȩf� ��b�_�Epx����D�47�~�;%/x��C)�Q���D3     ���n�]�B�brU�N�ݘ%_\�
                                                                            7F�e����
                                                                                    u��ED�Ϳ�T�Q����XyȀt�xb8��� ����������'�Zm�V엇DT��!»
                                                                                                                                       ����@��2��     Nd۠;��̭�1�t5QtU�M�`�B�<�վmwX[�
�0�5���]��yM!��}/E��|g$�&���8�&~�a?C��_���z��տ�ɝN�D�LJ0�z����|�v,�r�$]���*HJ�$'��xGQ)P�4��TI�=8qc?���)`��N?_U率`���K��U4��8f���  &�

I tried using printf, but it didn't work. I will be glad of any hint, a link to the literature.


Solution

  • It is working. Mysql protocol isn't text-based. Printing it as-if it were text is inappropriate. Instead, consider hex-dumping like e.g.:

    _sql_statement.assign(_client_data, bytes_transferred);
    
    std::cout << "Received " << bytes_transferred << " bytes: ";
    {
        std::ostream hex(std::cout.rdbuf());
        hex << std::hex << std::showbase << std::setfill('0');
        for (auto i = 0; i < bytes_transferred; ++i) {
            uint8_t octet = _client_data[i];
            hex << " " << std::setw(4) << static_cast<int>(octet);
        }
    }
    std::cout << std::endl;
    

    Note I also changed append into assign to avoid infinite growth. Also consider renaming _sql_statemtent into _data to avoid misleading names.

    Review Notes

    A few things:

    • the mutex is useless if only one spot ever locks it

    • to avoid issues, don't close() during potential async operations. Instead cancel() them and let the error handling clean up via shared_from_this()

    • same for the acceptor, just setting _stopped = true doesn't force the pending accept to complete. Instead, cancel() the _acceptor.

    • Don't abuse shared_ptr::get(), atomic<T>::load() and atomic<T>::store() for no reason

    • avoid the code duplication around async read:

       void tcp_proxy::Bridge::handle_connection(error_code const& error) {
           if (!error) {
               do_read_fserver();
               do_read_fclient();
           } else {
               std::cerr << "Connect Error! Error code = " << error.value() << ". Message : " << error.message() << "\n";
               stop();
           }
       }
      

      and re-use the same do_read_fXXX() function in the write completions.

    • handle EOF properly. It's possible to have received data when EOF is encountered. So, write the data to the other end destroying the connection:

      if (!error || error == asio::error::eof) {
      

      I'll leave it as an exercise to the reader to optionally keep track of shutdown states (see e.g. boost::asio cleanly disconnecting)

    • you call proxy.stop_proxy() after ... ios.run() completed. That's useless by definition. Consider just omitting it, or put it in a more useful spot (e.g. in a signal_set::async_wait handler?)

    Demo

    I also created a branch with these review comments on Gitlab: https://gitlab.com/v-danis/tcp-proxy/-/merge_requests/1 (branch https://gitlab.com/bitbucket54/tcp-proxy/-/tree/sehe-review?ref_type=heads).

    Local demo:enter image description here