tags:

views:

208

answers:

2

See code. :P I am able to receive new connections before async_accept() has been called. My delegate function is also never called so I can't manage any connections I receive, rendering the new connections useless. ;)

So here's my question. Is there a way to prevent the Boost ASIO acceptor from getting new connections on its own and only getting connections from async_accept()?

Thanks!

AlexSocket::AlexSocket(boost::asio::io_service& s): myService(s)
{
    //none at the moment
    connected = false;
    listening = false;

    using boost::asio::ip::tcp;
    mySocket = new tcp::socket(myService);
}

AlexSocket::~AlexSocket()
{
    delete mySocket;
}

bool AlexSocket::StartListening(int port)
{
    bool didStart = false;

    if (!this->listening)
    {
        //try to listen
        acceptor = new tcp::acceptor(this->myService);
        boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
        acceptor->open(endpoint.protocol());
        acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
        acceptor->bind(endpoint);
        //CAN GET NEW CONNECTIONS HERE (before async_accept is called)
        acceptor->listen();

        didStart = true; //probably change?
        tcp::socket* tempNewSocket = new tcp::socket(this->myService);
        //acceptor->async_accept(*tempNewSocket, boost::bind(&AlexSocket::NewConnection, this, tempNewSocket, boost::asio::placeholders::error) );
    }
    else //already started!
        return false;

    this->listening = didStart;
    return didStart;
}

//this function is never called :(
void AlexSocket::NewConnection(tcp::socket* s, const boost::system::error_code& error)
{
    cout << "New Connection Made" << endl;
    //Start new accept async
    tcp::socket* tempNewSocket = new tcp::socket(this->myService);
    acceptor->async_accept(*tempNewSocket, boost::bind(&AlexSocket::NewConnection, this, tempNewSocket, boost::asio::placeholders::error) );
}

bool AlexSocket::ConnectToServer(std::string toConnectTo, string port)
{
    if (connected)
        return false;

    this->serverConnectedTo = toConnectTo;
    this->serverPort = port;

    ip::tcp::resolver resolver(myService);
    ip::tcp::resolver::query newQuery(toConnectTo, port);
    ip::tcp::resolver::iterator myIter = resolver.resolve(newQuery);
    ip::tcp::resolver::iterator end;

    //error
    boost::system::error_code error = boost::asio::error::host_not_found;

    //try each endpoint
    bool connected = false;
    while (error && myIter != end)
    {
        ip::tcp::endpoint endpoint = *myIter++;
        std::cout << endpoint << std::endl;

        mySocket->close();
        mySocket->connect(*myIter, error);

        if (error)
        {
            //try to connect, if it didn't work return false
            cout << "Did not Connect" << endl << error << endl;
        }
        else
        {
            //was able to connect
            cout << "Connected!" << endl;
            connected = true;
        }
        myIter++;
    }   
    this->connected = connected;
    return connected;
}

EDIT: I've changed my code to reflect what the answers so far have said. I am passing in an io_service to the ctor of my class. As you can see below, main is NOT calling run on the service, so I would assume that nothing should be able to connect right?

I have put my debugger on the listen() line and went to "canyouseeme.org". Typed in 57422 and hit Connect. Couldn't. Ran the listen() line. Was able to connect. This shouldn't be possible right? Like never? :(

No idea what to do anymore. main() is below.

int main()
{
    boost::asio::io_service s;
    AlexSocket test(s);

    test.StartListening(57422);

    test.ConnectToServer("localhost", "57422");

    cout << "Enter something to quit" << endl;
    int a2;
    cin >> a2;

    return 0;
}
+1  A: 

So here's my question. Is there a way to prevent the Boost ASIO acceptor from getting new connections on its own and only getting connections from async_accept()?

Why do you think this is happening? If you posted the complete code, that would greatly help. When I take your snippet and put a boilerplate main and io_service::run() around it, everything works fine.

#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include <iostream>

using namespace boost::asio;

class Socket {
public:
    Socket(
            io_service& io_service
          ) :
        _io_service( io_service ),
        _acceptor( new ip::tcp::acceptor(io_service) )
    {

    }

    bool start(int port)
    {
        //try to listen
        ip::tcp::endpoint endpoint(ip::tcp::v4(), port);
        _acceptor->open(endpoint.protocol());
        _acceptor->set_option(ip::tcp::acceptor::reuse_address(true));
        _acceptor->bind(endpoint);
        //CAN GET NEW CONNECTIONS HERE (before async_accept is called)
        _acceptor->listen();

        ip::tcp::socket* temp = new ip::tcp::socket( _io_service );
        _acceptor->async_accept(
                *temp,
                boost::bind(
                    &Socket::NewConnection,
                    this,
                    temp,
                    boost::asio::placeholders::error
                    )
                );
    }

    void NewConnection(
            ip::tcp::socket* s, 
            const boost::system::error_code& error
            )
    {
        std::cout << "New Connection Made" << std::endl;
        //Start new accept async
        ip::tcp::socket* temp = new ip::tcp::socket( _io_service );
        _acceptor->async_accept(
                *temp,
                boost::bind(
                    &Socket::NewConnection, 
                    this,
                    temp,
                    boost::asio::placeholders::error
                    )
                );
    }
private:
    io_service& _io_service;
    ip::tcp::acceptor* _acceptor;
};

int
main()
{
    io_service foo;
    Socket sock( foo );
    sock.start(1234);
    foo.run();

    return 0;
}

compile and run:

macmini:~ samm$ g++ -lboost_system accept.cc
macmini:~ samm$ ./a.out 
New Connection Made

telnet from another terminal

macmini:~ samm$ telnet 127.0.0.1 1234
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Sam Miller
Complete code added.
bobber205
+1  A: 

If you are truly getting a new connection at the point when you call acceptor->listen() then I am puzzled by that. What are you using to determine whether you've gotten a connection or not? The io_service is typically quite "reactive" in that it only reacts to events that it has been explicitly told to react to.

In your example above, the only thing I see that would cause a "new connection" to be initiated is calling async_accept. Additionally, what you described makes little sense from a low-level sockets standpoint (using BSD sockets, typically you must call bind, listen, and accept in that order, and only then can a new connection be made).

My suspicion is that you've actually got some faulty logic somewhere. Who calls StartListening and how often is it called (it should only need to be called once). You've gone through a bunch of extra effort to setup your acceptor object that's usually not necessary in Asio - you can typically just use the acceptor constructor to create an acceptor with all the parameters you need, and then just call async_accept:

acceptor = new tcp::acceptor(
    this->myService,
    boost::asio::ip::tcp::endpoint(
        boost::asio::ip::tcp::v4(),
        port),
    true);

tcp::socket* tempNewSocket = new tcp::socket(this->myService);
acceptor->async_accept(
    *tempNewSocket, 
    boost::bind(
        &AlexSocket::NewConnection, 
        this, 
        tempNewSocket, 
        boost::asio::placeholders::error) );
bjlaub