0

Can not find why this program is failing. It must be my boost usage. Problem is highlighted in comment and there is a small note about some of the function calls

/* Includes Hidden */
using boost::asio::ip::udp;


class UDP_Server {

public:
    UDP_Server(boost::asio::io_service& IO, unsigned short PORT) 
        : sock(IO, udp::endpoint(udp::v4(),PORT)) {
        Listen();
    }
    ~UDP_Server() {
        for(auto& endpoint : Clients) {
            delete endpoint;
        }
        Clients.clear();
    }


    void Listen() {
        //waits for msg to be sent.  Captures end point and sends address
        //so server can store connections
 
        udp::endpoint* T = new udp::endpoint;
        sock.async_receive_from(
            boost::asio::buffer(rbuf),*T, 
            boost::bind(&UDP_Server::handle_rec, this, T, 
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }

    void handle_rec(udp::endpoint* EP, const boost::system::error_code& err, size_t len) {
//When the program enters here, err is 234 (windows error for more data available)
//len is 0 and rbuf is empty.

        if(err && err != boost::asio::error::message_size) {
            std::cerr << err.message() << std::endl;
        }

        std::cout.write(rbuf.data(),rbuf.size());

        bool ThisClient = false;
        std::string Msg = "";

        for( auto& EPs : Clients) {

            if(EPs == EP) {
                ThisClient = true; break; 
            }       
        }

        if(!ThisClient) {
            if(len > 0 && rbuf[0]=='0') {
                Clients.push_back(EP);
                Msg = "Connected";
            }else{
                Msg = "Connection Refused";
            }   
        }else{
            if(rbuf[0]=='0') {
                delete EP;
                Clients.remove(EP);
                Msg = "Disconnected";
            }
        }
        //queue message to send back and call  handle_snd function
        sock.async_send_to(boost::asio::buffer(Msg),*EP,
            boost::bind(&UDP_Server::handle_snd,this,EP,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred
            ));

        Listen(); //listen for some more messages!
    } //debugging through the first time through this function eventually exits here
//and ends up going through a bunch of code I didn't write, and ultimately fail.

    void handle_snd(udp::endpoint *Dest, const boost::system::error_code& err, size_t len) {

    }

private:
    udp::socket sock;
    std::list<udp::endpoint*> Clients;
    std::vector<char> rbuf;
};

void HostStart() {
    try {
        boost::asio::io_service io;
        UDP_Server Host(io,13);
        io.run();
    }catch(std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
}

int main() {


    std::thread thd(HostStart); //start server

    try {
        boost::asio::io_service io2;
        udp::resolver res(io2);
        udp::resolver::query queer(udp::v4(),"127.0.0.1","daytime");
        udp::endpoint HostEP = *res.resolve(queer);
        udp::socket sock(io2);
        sock.open(udp::v4());


        std::string Msg = "0";
        std::vector<char> MsgArray(Msg.begin(),Msg.end());
        
        sock.send_to(boost::asio::buffer(Msg),HostEP);

        io2.run();
        udp::endpoint RecEP;
        std::array<char,128> rbuf;

        sock.receive_from(boost::asio::buffer(rbuf),RecEP);
        std::cout.write(rbuf.data(),rbuf.size());

        sock.send_to(boost::asio::buffer(Msg),HostEP);
        sock.receive_from(boost::asio::buffer(rbuf),RecEP);
        std::cout.write(rbuf.data(),rbuf.size());

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

    Sleep(10000);
    return 0;
}

If I use debugging and walk through this code, I find that I ultimately end up in a file called win_iocp_io_service.ipp and I get this error: Error

In my main, I'm just trying to synch send a couple message to test the asynch server class. I have no idea why the buffer is empty after the async server call and why I am getting this error.

Possibly it is related to when I call run on my io service and the way I am trying to multithread it.

Thank you

Community
  • 1
  • 1
Chemistpp
  • 2,006
  • 2
  • 28
  • 48

1 Answers1

1

This may be the result of the program invoking undefined behavior. Within UDP_Server::handle_rec(), the call to udp::socket::async_send_to() violates the requirement that the underlying memory provided to the buffer must remain valid until the handler is called.

Although the buffers object may be copied as necessary, ownership of the underlying memory blocks is retained by the caller, which must guarantee that they remain valid until the handler is called.

To meet this criteria, consider making Msg a data member of UDP_Server, rather than an automatic variable.

Also, two other points to consider:

  • UDP_Server::rbuf will always maintain a size of zero, causing udp::socket::async_receive_from() in UDP_Server::Listen() to read nothing, as there is no memory into which data can be read. udp::socket::async_receive_from() only modifies the contents of the memory block provided to it as a buffer; it is the caller's responsibility to have already allocated the memory block. Either resize rbuf to a size large enough to handle all incoming datagrams, or lazily allocate the buffer.
  • In main(), rbuf.size() will always return 128, regardless of how much data was actually received. udp::socket::receive_from()'s return value indicates the number of bytes received, and this value should be used when creating a boost::asio::buffer and when writing to std::cout.
Community
  • 1
  • 1
Tanner Sansbury
  • 51,153
  • 9
  • 112
  • 169
  • This makes sense. Msg is destroyed as soon as the function goes out of scope (which is instantly because a few asynch calls are queued and then the function returns). I didn't think that the function couldn't allocate memory as needed, but that makes sense as well. Then `async_receive_from` uses the `boost::asio::placeholder::byte_transfered` for length of the buffer. I found a [tutorial](http://pastebin.com/NnbK1T7G) that is offering some nice clarifications. Appreciate the answer. Can I ask what exactly io.run() does and how often would I have to call that? When does it return? – Chemistpp Oct 31 '13 at 03:07
  • @Chemistpp: `io_service.run()` executes the event loop, running all the asynchronous task within the calling thread, until there is no more task, an exception is thrown, or the `io_service` is explicitly stopped via `io_service.stop()`. How often you call it depends on how you write the program. In almost all programs I write, I only need to call it once. [This](http://stackoverflow.com/a/15575732/1053968) answer may be enlightening. – Tanner Sansbury Oct 31 '13 at 13:21