Hi Stefan,

thanks for your comments, I'm starting to get a better insight into the
internals of SEMS.

I did some more tracing and found that the session gets stuck on the
'waitForEvent();' line in the AmSession main loop.

In the following scenario it gets stuck:
- Call is set up, and enters main event loop
- Call runs through numerous events and is not stopped with
setStopped();
- Bye is sent or received, Dialog status is disconnected, call is still
not stopped with setStopped();
- Session main loop still runs, since the call is not stopped,
waitForEvent(); is called
- setStopped(); is called, but this doesn't generate an event. Session
is still in waitForEvent();
- Because no more events are sent to the session, the session
effectively hangs in waitForEvent();
- Only when SEMS is terminated (ctrl + c), all sessions are sent an
event to clean up, the session wakes from waitForEvent(); and closes
down without a problem.


When I generate a bogus event after calling setStopped(), the session
closes down properly:
        this->setStopped();
        this->postEvent(new AmEvent(93874));

I suspect this is a bug in SEMS, but I'm not entirely sure, since I
haven't traced the internals of the session cleaner to see if it
(should) send an event.

If this is a bug, I suggest either setStopped() would generate an event
to notify the session it is being stopped, or the session cleaner sends
periodic events to clean up the sessions which have stranded this way.

I hope you can shed some light onto this situation.
Thanks,
Bert

-----Original Message-----
From: Stefan Sayer [mailto:[email protected]] 
Sent: vrijdag 6 februari 2009 12:41
To: Bert Fraterman
Cc: [email protected]
Subject: Re: [Sems] AmSipDispatcher 'could not dispatch reply' error

Hello,

o Bert Fraterman [02/06/09 11:08]:
> Another problem in the category 'closing down sessions properly':
> 
> What if I want to wait an amount of time between the bye() and the
> setStopped() calls? Like so:
> 
>       this->dlg.bye();
>       ... Code that takes considerable amount of time to run, a 200 OK
> reply could be received in the mean time ...
>       this->setStopped();
> 
> As far as I can tell from the debug traces, SEMS tries to destroy the
> session when the 200 OK reply is received. If the session is not
stopped
> at that moment with setStopped(), the AmSession::destroy() method will
> not run.
I doubt your analysis. there must have been something else going on. if 
you look at AmSession::run() this is what it does:

      while (!sess_stopped.get() ||
             (dlg.getStatus() == AmSipDialog::Disconnecting)){

        waitForEvent();
        processEvents();

        DBG("%s dlg.getUACTransPending() = %i\n",
            dlg.callid.c_str(),dlg.getUACTransPending());
       }
... send bye if not done and another processEvents() loop until status 
== Disconnected ..

onBeforeDestroy()
destroy()


> Calling setStopped() after the 200 OK reply is received, results in
the
> session not being destroyed (and therefore not cleaned).
why? probably the reason is somewhere else (what is the dialog state?).

Another method you could try is the following:
Index: AmSipDialog.cpp
===================================================================
--- AmSipDialog.cpp     (revision 1212)
+++ AmSipDialog.cpp     (working copy)
@@ -365,7 +365,7 @@
    switch(status){
    case Disconnecting:
    case Connected:
-    status = Disconnected;
+    status = Disconnecting;
      return sendRequest("BYE");
    case Pending:
      status = Disconnecting;

then the session's 'main loop' will run until a FR is received for the 
BYE. maybe that is cleaner, but I think there was a reason why the 
dialog was considered stopped immediately when sending BYE, which I 
don't remember now.

> 
> As workaround, I call AmSession::destroy() manually when I call
> setStopped(), so the session is always destroyed, but in all cases
(even
> when the 200 reply has been received), the internal logic will try to
> destroy the session twice, resulting in warning messages that the
> session could not be found. Not the prettiest solution, but the
session
> is destroyed and cleaned.
> 
> Is it a bug that the session isn't destroyed when setStopped() is
called
> after the 200 reply has been received?
> Am I allowed in SEMS logic to have code in between the bye() and
> setStopped() calls (the voicemail module has it too, but apparently
it's
yes

> quick enough to finish before the 200 reply is received?)?
no, it does not matter whether it takes much or little time to send the 
email, or do any processing at that stage.

Look, there is one thread per session processing the signalling. only at

the end of AmSession::run, the session adds itself in the list of the to

be destroyed sessions, by calling AmSessionContainer::destroySession() 
in destroy(). the AmSessionContainer goes periodically through this 
list, and deletes all session, for which it's signalling thread is 
really stopped.

So you are free to keep that thread running, even after you have called 
destroy() it should not do any harm (you will only see that the session 
container has that session in his to-be-deleted list). the cleaner way 
is obviously to use the main loop as intended.


Regards
Stefan

> 
> Thanks,
> Bert
> 
> -----Original Message-----
> From: Stefan Sayer [mailto:[email protected]] 
> Sent: woensdag 4 februari 2009 21:31
> To: Bert Fraterman
> Cc: [email protected]
> Subject: Re: [Sems] AmSipDispatcher 'could not dispatch reply' error
> 
> Hello,
> 
> o Bert Fraterman [02/04/09 17:55]:
>> I'm making a SEMS module in C++, and when I sent my bye, I also
>> immediately stop the session:
>>
>>      this->dlg.bye();
>>      this->setStopped();
>>
>> This pattern is also used in other modules, like the voicemail.
>>
>> Unfortunately, when the SIP message 200 OK is received from the
> client,
>> the AmSipDispatcher gives an error:
>>      ERROR: [42074940] handleSipMsg (AmSipDispatcher.cpp:48): could
>> not dispatch reply: (Incoming 200 OK reply)
>>
>> I suspect the AmSipDispatcher is trying to post an event to the
> already
>> stopped session. Clearly, I'm not
>> interested in this event, otherwise I would've waited for it.
>> Also, this is not a critical error (I believe the internal state
> machine
>> closes down the call properly), so I
>> would suggest to demote the error to a warning, or even to a debug
>> message (since it could be a very deliberate
>> choice not to wait for the event).
> set unhandled_reply_loglevel in sems.conf (see sems.conf.sample):
> 
> # optional parameter:
> unhandled_reply_loglevel={error|warn|info|debug|no}
> #
> # the default application logic implemented in the applications is to
> stop
> # the session right after sending BYE, without waiting for a reply.
this
> # leads to many log entries of the form
> # ERROR: [b6fa6bb0] handleSipMsg (AmSipDispatcher.cpp:48): unhandled
> #    reply:  [code:200;phrase:[OK];... ]
> #
> # This parameter sets the log lovel of unhandled positive (200 class) 
> replies.
> #
> # default: error
> #
> # unhandled_reply_loglevel=info
> 
>> Is my statement correct, or am I closing down my session in the wrong
>> way?
> Well, I do it the same way, and have not run into problems, even
though 
> there is at least one case when it this is not correct: If BYE needs
to 
> be authenticated. but it would be nice to modify the default
processing 
> to wait until BYE is replied with FR or times out (is it on the
tracker 
> already?).
> 
> Regards
> Stefan
> 
>> Thanks,
>> Bert
>> _______________________________________________
>> Sems mailing list
>> [email protected]
>> http://lists.iptel.org/mailman/listinfo/sems
> 

-- 
Stefan Sayer
VoIP Services

[email protected]
www.iptego.com

IPTEGO GmbH
Am Borsigturm 40
13507 Berlin
Germany

Amtsgericht Charlottenburg, HRB 101010
Geschaeftsfuehrer: Alexander Hoffmann
_______________________________________________
Sems mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/sems

Reply via email to