[reSIProcate] AppDialogSet Memory Leak

Kevin Pickard kpickard at upstreamworks.com
Wed Mar 8 11:06:11 CST 2006


	Hello everyone.

	We have encountered a problem that is resulting in a memory leak due to 
AppDialogSets that are no longer being used but never getting 
released/destroyed. I have taken a look at the DUM source and have 
identified the reason it is happening. It looks like the code for handling 
our particular scenario has not been completed. So I am wondering if what 
we are doing is correct and the code has just not been written yet or if 
there is a better way of handling this situation.

	Basically the scenario is that we create a SUBSCRIBE request via 
Dum.makeSubscription() passing in our own AppDialogSet. We then send the 
request. Now the device we are subscribing to never responds (for whatever 
reason) and the request eventually times out with an internally generated 
408 SipResp. In this simple situation DUM eventually calls destroy() on the 
AppDialogSet and things get cleaned up nicely.

	The problem occurs if we try to kill the request *before* the timeout 
occurs. We are currently calling end() on the AppDialogSet to do this. This 
results in the state of the underlying DialogSet being set to WaitingToEnd. 
Now when the 408 timeout response is then generated, it eventually gets 
passed through to DialogSet::dispatch() for processing. As can be seen from 
the code shown below, using a Release build, the resulting action is to do 
nothing. With a debug build it will assert(). In our scenario mState is 
WaitingToEnd and the last method was SUBSCRIBE.

	So are we doing the right thing? Is it just a matter that no one has 
written the handling code for SUBSCRIBE yet? The code for handling the same 
situation for INVITE is present and I would expect that the equivalent code 
for handling the SUBSCRIBE situation would be similar. Otherwise, is there 
a better way of killing the pending SUBSCRIBE?

	Thanks.


void
DialogSet::dispatch(const SipMessage& msg)
{
    assert(msg.isRequest() || msg.isResponse());

    if (mState == WaitingToEnd)
    {
       assert(mDialogs.empty());
       if (msg.isResponse())
       {
          int code = msg.header(h_StatusLine).statusCode();
          switch(mCreator->getLastRequest()->header(h_CSeq).method())
          {
             case INVITE:
                if (code / 100 == 1)
                {
                   mState = ReceivedProvisional;
                   end();
                }
                else if (code / 100 == 2)
                {
                   Dialog dialog(mDum, msg, *this);

                   SharedPtr<SipMessage> ack(new SipMessage);
                   dialog.makeRequest(*ack, ACK);
                   ack->header(h_CSeq).sequence() = 
msg.header(h_CSeq).sequence();
                   dialog.send(ack);

                   SharedPtr<SipMessage> bye(new SipMessage);
                   dialog.makeRequest(*bye, BYE);
                   dialog.send(bye);

                   // Note:  Destruction of this dialog object will cause 
DialogSet::possiblyDie to be called thus invoking mDum.destroy
                }
                else
                {
                   mState = Destroying;
                   mDum.destroy(this);
                }
                break;
             case SUBSCRIBE:
                assert(0);
                break;
             default:
                break;
          }
       }






More information about the resiprocate-devel mailing list