[reSIProcate] AppDialogSet Memory Leak
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;
}
}