MakeBoundCallback and Socket::SetCloseCallbacks

239 views
Skip to first unread message

Christian Kreuzberger

unread,
Dec 23, 2015, 12:21:30 PM12/23/15
to ns-3-users
Hi,

I am having huge problems in using MakeBoundCallback with Socket::SetCloseCallbacks.

I have a class called MyServer which is an Application, and this one creates a new socket, where I just say

socket->SetCloseCallbacks(MakeCallback(&MyServer::OnNormalClose, this), MakeCallback(&MyServer::OnProblemClose));



which works fine with my methods which have the same signature:

void MyServer::OnNormalClose(Ptr<Socket> socket) { ... }




Now I have assigned each socket a unique socket id, which I want to pass to this callback. I found that MakeBoundCallback should do the trick, but I can not get it to compile.
My call was as follows:

int socket_id = rand();
socket
->SetCloseCallbacks(MakeBoundCallback(&MyServer::OnNormalClose, this, socket_id), MakeCallback(&MyServer::OnProblemClose, this, socket_id));



and the signature was

void MyServer::OnNormalClose(int socket_id, Ptr<Socket> socket) { ... }



I also tried it the other way around, with

void MyServer::OnNormalClose(Ptr<Socket> socket, int socket_id) { ... }



Can anyone point out what I am doing wrong and how to do this properly in ns-3? Is MakeBoundCallback maybe the wrong method?


Thanks and merry x-mas!
Christian

Tommaso Pecorella

unread,
Dec 23, 2015, 6:02:30 PM12/23/15
to ns-3-users
Hi,

nope, your second use-case is still a "normal" callback case, see https://www.nsnam.org/docs/manual/html/callbacks.html for a very good description of what BoundCallbacks are used for.

It should work if you do:
socket->SetCloseCallbacks(MakeCallback(&MyServer::OnNormalClose, this, socket_id), MakeCallback(&MyServer::OnProblemClose, this, socket_id));
 and the function signature is
void MyServer::OnNormalClose(Ptr<Socket> socket, int socket_id) { ... }

... because you're passing two params :)

Cheers,

T.

Christian Kreuzberger

unread,
Dec 23, 2015, 7:08:12 PM12/23/15
to ns-3-users
Hi,

thanks for your reply. Unfortunately, this still leads compile errors. Here is my little piece of code, where HttpServerApplication inherits from Application.

void
HttpServerApplication::ConnectionAccepted (Ptr<Socket> socket, const Address& address)
{
  NS_LOG_FUNCTION
(this << socket << address);

  uint64_t socket_id
= RegisterSocket(socket);

  m_activeClients
[socket_id] = new HttpServerClientSocket(socket_id, m_contentDir);

  NS_LOG_DEBUG
(socket << " " << Simulator::Now () << " Successful socket id : " << socket_id << " Connection Accepted From " << address);

 
// set callbacks for this socket to be in HttpServerClientSocket class
  socket
->SetSendCallback (MakeCallback (&HttpServerClientSocket::HandleReadyToTransmit, m_activeClients[socket_id]));
  socket
->SetRecvCallback (MakeCallback (&HttpServerClientSocket::HandleIncomingData, m_activeClients[socket_id]));

  socket
->SetCloseCallbacks (MakeCallback (&HttpServerApplication::ConnectionClosedNormal, this, socket_id),
                             
MakeCallback (&HttpServerApplication::ConnectionClosedError,  this, socket_id));
}

void
HttpServerApplication::ConnectionClosedNormal (Ptr<Socket> socket, uint64_t socket_id)
{
  fprintf
(stderr, "Server(%ld): Socket was closed!\n", socket_id);
}

void
HttpServerApplication::ConnectionClosedError (Ptr<Socket> socket, uint64_t socket_id)
{
  fprintf
(stderr, "Server(%ld): Socket was closed with an error!\n", socket_id);
}




It always ends up with a problem with template argument deduction:
./ns3/callback.h:1609:40: note:   template argument deduction/substitution failed:
../src/applications/model/http-server.cc:210:107: note:   mismatched types R (*)(T1, T2, T3, T4, T5, T6, T7, T8, T9)’ and void (ns3::HttpServerApplication::*)(ns3::Ptr<ns3::Socket>, uint64_t) {aka void (ns3::HttpServerApplication::*)(ns3::Ptr<ns3::Socket>, long unsigned int)}’
                             
MakeCallback (&HttpServerApplication::ConnectionClosedError,  this, socket_id));



Also, about the bound-callback thing: I was thinking that this was the right thing, because the callback usually gets the Ptr<Socket> socket provided internally (not by me), so if I wanted to add a parameter to that, I would have to bind it by using MakeBoundCallback. But I guess I was wrong? 

Tommaso Pecorella

unread,
Dec 24, 2015, 6:21:11 AM12/24/15
to ns-3-users
Hi,

ok, I'm terribly sorry, I was sleepy yesterday when I wrote that reply. The problem is far from that simple. Well, it is simple, but there are a number of small mistakes here and there.

First things first:
 m_activeClients[socket_id] = new HttpServerClientSocket(socket_id, m_contentDir);

If this is a socket, then do NOT use new. Use Ptr and a Create-like function (Socket does have many), otherwise you'll screw up the garbage collector.
Just consider that "new" is almost never used in ns-3, and where it is used... we plan to remove it :P

Now about your callbacks. Yes, you did need a bound callback if you plan to have a 1st argument always set to the same value when you call the callback. My bad. The problem is (was) elsewhere.

MakeCallback (&HttpServerApplication::ConnectionClosedNormal, this, socket_id)
This is wrong, because MakeCallback accepts only two arguments (the member function and the instance).

MakeBoundCallback (&HttpServerApplication::ConnectionClosedNormal, this, socket_id)
This will work, but it requires a function signature like this:

void
HttpServerApplication::ConnectionClosedError (uint64_t socket_id, Ptr<Socket> socket)

{
 fprintf
(stderr, "Server(%ld): Socket was closed with an error!\n", socket_id);
}

and to be called like this:
connectionClosedErrorCallback (socket);

HOWEVER...
However, MakeBoundCallback does not work wth member function, only with static functions (as far as I know), so all the above is pure speculation.
Moreover, Socket's SetCloseCallbacks is quite precise in its signature.
Pity...

Still, there's hope. Ask yourself: do I need the socket ID ? Answer: no, I already know it.
You created the socket in ConnectionAccepted, thus you (should) know the association between the socket pointer and its ID. Simply search for it.
Alternatively, add a public method in your socket to ask it what is its ID.

Cheers,

T,

PS: triple check your socket management. Beside the "new", you're registering an ID on a socket, then you create another one with the above mentioned ID. Something's not right.

Bill Tao

unread,
Aug 8, 2022, 11:49:42 PM8/8/22
to ns-3-users
Hi, Tommaso.

Sorry for replying to this old thread. I will make a new post if that is more appropriate. 

I only learn from here that MakeBoundCallback does not work with the member function. Is this still true as of 2022? 
I find myself in a situation where it would be nice to be able to make bound callback with member function... because that way I don't need to touch the code in another module. Is there any workaround to this? Maybe make bound callback to a static function which then calls the member function (although that sounds hacky..)

Thanks and regards,
Bill

Tom Henderson

unread,
Aug 9, 2022, 10:45:26 AM8/9/22
to ns-3-...@googlegroups.com
On 8/8/22 20:49, Bill Tao wrote:
> Hi, Tommaso.
>
> Sorry for replying to this old thread. I will make a new post if that
> is more appropriate.
>
> I only learn from here that MakeBoundCallback does not work with the
> member function. Is this still true as of 2022?
> I find myself in a situation where it would be nice to be able to make
> bound callback with member function... because that way I don't need
> to touch the code in another module. Is there any workaround to this?
> Maybe make bound callback to a static function which then calls the
> member function (although that sounds hacky..)
>
> Thanks and regards,
> Bill

Nothing has changed recently with respect to bound callbacks and
accessing a regular method of an instance of an object.

You can access a static member function of a class; see, for example,
line 791 of command-line.cc.

The doxygen also hints at a workaround (indirecting through a static
handler function):

 * There is not a version with bound arguments.  You may be able to
 * get the same result by using \c MakeBoundCallback with a \c static
 * member function, as in:
 * \code
 *   MakeBoundCallback ( & MyClass::StaticHandler, this);
 * \endcode
 * This still leaves two argument slots available for binding.
 */

Bill Tao

unread,
Aug 11, 2022, 3:34:57 AM8/11/22
to ns-3-users
Thanks, Tom. That helped!
Reply all
Reply to author
Forward
0 new messages