1
votes

Introduction:

I'm trying to make a server / client application using c++ and boost::asio, I'm also trying to make sync writes received in the other end with continuous async reads. for example my server async read stream of data for a fixed byte length then it moves on to the next bytes sent by sync write from the client.

The Problem:

in the continuous async reads the first stream bytes are read correctly but when it continue to the next async read something is sent from the other end with the same byte length I am excpecting but it is garbage or I cant convert it to valuable data.

The Code:

    private:
      static const int MAX_MTU = 1500;  //Ethernet Maximum Transfer UNIT (MTU)...
      static const int TRASH_CAN = 100; //Amount to substract from the MAX_MTU to make room for basic packet structure elements.
      static const int BUFFER_SIZE = MAX_MTU - TRASH_CAN;
      boost::mutex mutex;
      typedef char* data_bytes;
      std::list<data_bytes> data;

    private:
      tcp::socket socket_;
      boost::asio::io_service& io_service_;
      moqane::tcp_packet *packet_;

    // CTOR for the incoming connection from a client to the server
    public: tcp_session(boost::asio::io_service& io_service)
      : io_service_(io_service),
        socket_(io_service),
        packet_(new moqane::tcp_packet())
    {
        // ......
    }

    // CTOR for the outgoing clinet connection to the server...
    public: tcp_session(boost::asio::io_service& io_service, tcp::resolver::iterator endpoint_iterator)
      : io_service_(io_service),
        socket_(io_service),
        packet_(new moqane::tcp_packet())
    {
        boost::asio::async_connect(socket_,
                                   endpoint_iterator,
                                   boost::bind(&tcp_session::connect_to_server_hndlr,
                                               this,
                                               boost::asio::placeholders::error)
                                   );
    }

    tcp::socket& socket()
    {
        return socket_;
    }

    public:
    void read_header()
    {

        read_packet(packet_->HEADER_LENGTH,
                    boost::bind(
                            &moqane::tcp_session::read_header_hndlr,
                            shared_from_this(),
                            packet_->HEADER_LENGTH,
                            boost::asio::placeholders::error)
                    );
    }

    private:
    void connect_to_server_hndlr(const boost::system::error_code& error)
    {
        if (!error)
        {
            read_header();
        }
        else
        {
            // TODO: fire the error event...
        }
    }

    private:
    template <class T>
    void read_packet(int packet_length, T handler)
    {
        /*
        Packet Structure: (Mohamed Tarek (moqane))
        ==============================================================================================
        HEADER: could be a 3 or 4 bytes that give enough information to the endpoint on how to receive
                those bytes.
        SIZE  : A 4 byte-length number that tell the endpoint how much data in bytes ar comming.
                ex: 0340 which should tell us that the incoming data are 340 bytes, so we will not
                receive more or less than that.
        DATA  : the incoming valuable information that we want to receive in the first place.

        ---------------------------------------------
        |        |      |                            |
        | HEADER | SIZE | DATA...                    | ----> PACKET
        |   3b   |  4b  | N/A b                      |
        ----------------------------------------------
        ==============================================================================================
        */

        if (data.size() > 0)
        {
            data.clear();
        }

        char d[moqane::tcp_session::BUFFER_SIZE];
        data.push_back(d);
        boost::asio::async_read(socket_,
                                boost::asio::buffer(data.back(), packet_length),
                                handler
                                );
    }

    private:
    void write_packet(char* data_bytes)
    {
        boost::asio::write(socket_, boost::asio::buffer(data_bytes, sizeof(data_bytes)));

    }

    private:
    void write_packet_hndlr(const boost::system::error_code& error)
    {
        if (!error)
        {
        }
        else
        {
        }
    }


    private:
    void read_header_hndlr(int packet_length, const boost::system::error_code& error)
    {
        if (!error)
        {
            // convert bytes to wxstring
            // wxString s = moqane::wx2string::To_wxString(packet_->DATA(), packet_->HEADER_LENGTH());

            // convert our bytes to string
            std::string header(data.back(), packet_length);

            if (packet_->is_header(header))
            {
                // read the SIZE packet
                read_packet(packet_->SIZE_LENGTH,
                            boost::bind(
                                    &moqane::tcp_session::read_size_hndlr,
                                    shared_from_this(),
                                    packet_->SIZE_LENGTH,
                                    header,
                                    "",
                                    boost::asio::placeholders::error)
                            );
            }
            else
            {
                // reread the HEADER packet if it's not a valid header
                read_header();
            }
        }

        else
        {
            // TODO: fire the error event...
        }



    }

    private:
    void read_size_hndlr(int packet_length, std::string header, std::string info, const boost::system::error_code& error)
    {
        if (!error)
        {
            std::string str_length(data.back(), packet_length);

            int next_packet_length = moqane::number2string::ToInt(str_length);

            if (next_packet_length > 0)
            {
                if (header == packet_->HEADER_STRING)
                {
                    read_packet(next_packet_length,
                                boost::bind(
                                        &moqane::tcp_session::read_STRING_hndlr,
                                        shared_from_this(),
                                        next_packet_length,
                                        boost::asio::placeholders::error)
                                );
                }
                else if (header == packet_->HEADER_COMMAND)
                {

                }
                else
                {
                    // reread the HEADER packet if it's not a valid header
                    read_header();
                }
            }
            else
            {
                // reread the HEADER packet if it's not a valid size
                read_header();
            }
        }
        else
        {
            // TODO: fire the error event...
        }
    }

    private:
    void read_STRING_hndlr(int packet_length, const boost::system::error_code& error)
    {
        std::string std_str(data.back(), packet_length);
        std::string v = "";
    }

    public:
    void write_STRING(char* string_data)
    {
        boost::mutex::scoped_lock lock(mutex);
        {
            write_packet(moqane::number2string::To_CharArray("STR"));
            write_packet(moqane::number2string::To_CharArray("xxx1"));
            write_packet(moqane::number2string::To_CharArray("a"));
        }
    }

};
2

2 Answers

3
votes

I suspect the problem lies in read_packet

    char d[moqane::tcp_session::BUFFER_SIZE];
    data.push_back(d);
    boost::asio::async_read(socket_,
                            boost::asio::buffer(data.back(), packet_length),
                            handler
                            );

This is creating a buffer d, in a local variable. You then push a pointer to d into data, which is then used to form the buffer for async_read. You then leave the function. This causes the array to be destroyed, with several dangling pointers, including the async_read.

I would recommend creating the buffer for the header, named something like 'header' to be part of your class. I'm not sure you need the separate data vector either.

0
votes

It's now solved, the main problem was in getting wrong packet_length when constructing the buffer while sending. because I was getting the length by sizeof() which was always returning 4 according to my processor architecture. so I get now the length of char* using the following function.

public:
    static int CharArray_Length(char* somedata)
    {
        std::list<char> l;

        while(*somedata != 0)
            l.push_back(*somedata++);

        // If you want to add a terminating NULL character
        // in your list, uncomment the following statement:
        // l.push_back(0);

        return l.size();
    }

reference: https://stackoverflow.com/a/15034741/1301186