cxd
cxd

Reputation: 27

Boost UDP async_receive_from doesn't wait for timeout or receive

I try to use the async_receive_from method to get data. But when i start, the program doesn't wait for the timeout or is reading something. I know that data is incoming on the port (wireshark). What could be the reason for that. I tried to use different examples from the boost website. When I'm debugging the Code, I always get the errorcode 125 (operation_aborted). Here is the relevant part of my code:

UDPCommunication::UDPCommunication(){
    m_portReceive = 2041;
    m_byteArrayLen = 0;
    m_lengthReceive = 0;
    m_dataReceived = false;
}

void UDPCommunication::openSocketReceive(){
    try{
        m_socketReceive = shared_ptr<udp::socket>(
                new udp::socket(m_ioService,
                        udp::endpoint(udp::v4(), m_portReceive)));

        m_receiveTimeout = shared_ptr<boost::asio::deadline_timer>(
                new boost::asio::deadline_timer(m_ioService));

        m_receiveTimeout->async_wait(
                boost::bind(&UDPCommunication::udpReceiveTimeoutHandler, this,
                        boost::asio::placeholders::error, 0));

        m_dataReceived = false;

    } catch(std::exception& e){
        std::cerr << e.what() << std::endl;
        ErrorLogging::log(e);
    }
}

void UDPCommunication::udpReceiveWithTimeout(long time){    
    try{
        boost::system::error_code ec;
        m_receiveTimeout->expires_from_now(boost::posix_time::seconds(time));
        ec = boost::asio::error::would_block;
        m_lengthReceive = 0;
        m_socketReceive->async_receive_from(buffer(m_bufferReceive),
                m_endpointReceive,
                boost::bind(&UDPCommunication::udpReceiveTimeoutHandler, this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred));
        do{
            m_ioService.run_one();
        }while(ec == boost::asio::error::would_block);

    } catch(std::exception& e){
        std::cerr << e.what() << std::endl;
        ErrorLogging::log(e);
    }   
}

bool UDPCommunication::udpReceiveTimeoutHandler(
        const boost::system::error_code& ec, size_t size){
    try{
        m_socketReceive->cancel();
        m_receiveTimeout->cancel();
        if(ec != boost::asio::error::would_block){

            m_dataReceived = false;
            return false;
        }else{
            m_lengthReceive = sizeof(m_bufferReceive);
            m_vectorBuffer.resize(m_lengthReceive);
            int i = 0;
            for(std::vector<unsigned char>::iterator it =
                    m_vectorBuffer.begin(); it != m_vectorBuffer.end(); ++it){
                *it = m_bufferReceive[i];
                ++i;
            }
            m_dataReceived = true;
            return true;
        }
    } catch(std::exception& e){
        std::cerr << e.what() << std::endl;
        ErrorLogging::log(e);
        return false;
    }
    return false;
}

bool UDPCommunication::dataReceived(){
    return m_dataReceived;
}

void main(){
    udpCommunication = shared_ptr<UDPCommunication>(new UDPCommunication());
    udpCommunication->openSocketReceive();
    udpCommunication->udpReceiveWithTimeout(5);
    bool dataReceived = udpCommunication->dataReceived();

    std::cout<< dataReceived << std::endl; //is data coming?
}

Solution of the upper probblem. This Code works fine:

int m_portReceive;
int m_byteArrayLen;
io_service m_ioService;
udp::endpoint m_endpointReceive;
shared_ptr<udp::socket> m_socketReceive;
shared_ptr<boost::asio::deadline_timer> m_receiveTimeout;
std::vector<unsigned char> m_vectorBuffer;
unsigned char m_bufferReceive[128];
size_t m_lengthReceive;
bool m_dataReceived;
bool m_timeoutFired;
boost::mutex m_mutex;

UDPCommunication::UDPCommunication(){
    m_portReceive = 2041;
    m_byteArrayLen = 0;
    m_lengthReceive = 0;
    m_dataReceived = false;
    m_timeoutFired = false;
}

void UDPCommunication::openSocketReceive(){
    try{
        m_socketReceive = shared_ptr<udp::socket>(
                new udp::socket(m_ioService,
                        udp::endpoint(udp::v4(), m_portReceive)));

        m_receiveTimeout = shared_ptr<boost::asio::deadline_timer>(
                new boost::asio::deadline_timer(m_ioService));

        m_receiveTimeout->expires_at(boost::posix_time::pos_infin);
        UDPCommunication::udpTimeoutHandler();

        m_receiveTimeout->async_wait(
                boost::bind(&UDPCommunication::udpTimeoutHandler, this));

        m_dataReceived = false;

    } catch(std::exception& e){
        std::cerr << e.what() << std::endl;
        ErrorLogging::log(e);
    }
}

void UDPCommunication::udpReceiveWithTimeout(long time){

    try{
        boost::system::error_code ec;
        m_receiveTimeout->expires_from_now(
                boost::posix_time::time_duration(
                        boost::posix_time::seconds(time)));

        m_socketReceive->async_receive_from(buffer(m_bufferReceive),
                m_endpointReceive,
                boost::bind(&UDPCommunication::udpReceiveHandler, this,
                        boost::asio::placeholders::error,
                        boost::asio::placeholders::bytes_transferred));
        do{
            m_ioService.run_one();
        }while((m_lengthReceive == 0)
                && (m_timeoutFired == false));

    } catch(std::exception& e){
        std::cerr << e.what() << std::endl;
        ErrorLogging::log(e);
    }
}

void UDPCommunication::udpReceiveHandler(const boost::system::error_code& ec,
        size_t size){
    try{
        m_mutex.lock();
        if(m_timeoutFired == false){
            if(size > 0){
                m_socketReceive->cancel();
                m_receiveTimeout->cancel();
                m_lengthReceive = size;

                m_vectorBuffer.resize(m_lengthReceive);
                int i = 0;
                for(std::vector<unsigned char>::iterator it =
                        m_vectorBuffer.begin(); it != m_vectorBuffer.end();
                        ++it){
                    *it = m_bufferReceive[i];
                    ++i;
                }

                m_dataReceived = true;
            }else{
                m_lengthReceive = 0;
                m_socketReceive->async_receive_from(buffer(m_bufferReceive),
                        m_endpointReceive,
                        boost::bind(&UDPCommunication::udpReceiveHandler, this,
                                boost::asio::placeholders::error,
                                boost::asio::placeholders::bytes_transferred));
            }
        }
        m_mutex.unlock();
    } catch(std::exception& e){
        std::cerr << e.what() << std::endl;
        ErrorLogging::log(e);
        m_mutex.unlock();
    }
}


    void UDPCommunication::udpTimeoutHandler(){
    try{
        m_mutex.lock();
        if(m_lengthReceive == 0){
            if(m_receiveTimeout->expires_at()
                    <= deadline_timer::traits_type::now()){
                std::cout << "timeout: no data received from modem"
                        << std::endl;
                m_socketReceive->cancel();
                m_dataReceived = false;
                m_receiveTimeout->expires_at(boost::posix_time::pos_infin);
                m_timeoutFired = true;
            }
            m_receiveTimeout->async_wait(
                    boost::bind(&UDPCommunication::udpTimeoutHandler, this));
        }
        m_mutex.unlock();
    } catch(std::exception& e){
        std::cerr << e.what() << std::endl;
        ErrorLogging::log(e);
        m_mutex.unlock();
    }
}

bool UDPCommunication::dataReceived(){
    return m_dataReceived;
}

void main(){
    udpCommunication = shared_ptr<UDPCommunication>(new UDPCommunication());
    udpCommunication->openSocketReceive();
    udpCommunication->udpReceiveWithTimeout(5);
    bool dataReceived = udpCommunication->dataReceived();

    std::cout<< dataReceived << std::endl; //is data coming?

    //now do something with data...
}

Upvotes: 2

Views: 2690

Answers (1)

DeVadder
DeVadder

Reputation: 1404

Note that i have not checked every line for other errors but two issues spring to mind:

  1. You async_wait on your deadline_timer without setting an expiry time first.

  2. You use io_service.run_one() without calling io_service.reset() in between.

I am not sure what the first does but the second means, that once the run_one() has returned for the first time (either by posting any handler or by beeing stopped) it will immediatly return every time it is called again, not doing its job.

Possible that the first one calls your timeout handler with operation_aborted and the second point keeps your io_service from ever doing anything else.

edit: There is also a problem with

    do{
        m_ioService.run_one();
    }while(ec == boost::asio::error::would_block);

If you want the run_one() method to alter ec, you have to pass it like so: run_one(ec) As is, the ec is a local variable in that method and should not get modified by anything thus always remain would_block. Of course, in that case run_one would no longer throw anything but store its result in ec.

Upvotes: 2

Related Questions