Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sip Dialog terminating mid call #59

Closed
half2me opened this issue Nov 14, 2023 · 6 comments
Closed

Sip Dialog terminating mid call #59

half2me opened this issue Nov 14, 2023 · 6 comments

Comments

@half2me
Copy link

half2me commented Nov 14, 2023

I have had success using the new dialogue server. I used the examples and added my own logic to properly respond to the SDP offer sent in the INVITE. The parts that are working are the dialogue starting when the call starts after the INVITE, and the dialogue properly stops when receiving BYE. My issue is if the call is longer than 30sec, the dialogue also just stops and kills the call. I have a hunch that this is probably due to a timeout somewhere, but I'm not sure what kind of keepalives are needed other than the code here. I've tried this with multiple sip phones and all have the same behaviour. I'm using UDP. Am I doing something wrong?

Here is an excerpt of the code I'm using:

func main() {
	ua, _ := sipgo.NewUA(sipgo.WithUserAgent("foobar"))
	uasContact := sip.ContactHeader{
		Address: sip.Uri{User: "foobar", Host: "192.168.22.122", Port: 5060},
	}
	cli, _ := sipgo.NewClient(ua)
	srv, _ := sipgo.NewServer(ua)
	dialogSrv := sipgo.NewDialogServer(cli, uasContact)

	srv.OnRegister(func(req *sip.Request, tx sip.ServerTransaction) {
		_ = tx.Respond(sip.NewResponseFromRequest(req, sip.StatusOK, "OK", nil))
	})

	srv.OnInvite(func(req *sip.Request, tx sip.ServerTransaction) {
		fmt.Printf("DIALOG STARTED!!!\n")
		dlg, err := dialogSrv.ReadInvite(req, tx)
		if err != nil {
			panic(err.Error())
		}
		sdpResp := generateSdpResponse(req.Body())
		_ = dlg.Respond(sip.StatusOK, "OK", sdpResp, sip.NewHeader("Content-Type", "application/sdp"))
		<-tx.Done()
		fmt.Printf("DIALOG DONE!!!\n")
	})

	srv.OnAck(func(req *sip.Request, tx sip.ServerTransaction) {
		_ = dialogSrv.ReadAck(req, tx)
	})

	srv.OnBye(func(req *sip.Request, tx sip.ServerTransaction) {
		_ = dialogSrv.ReadBye(req, tx)
	})

	ctx, _ := signal.NotifyContext(context.TODO(), os.Interrupt)
	go srv.ListenAndServe(ctx, "udp", "192.168.22.122:5060")
	<-ctx.Done()
}
@emiago
Copy link
Owner

emiago commented Nov 14, 2023

@half2me thanks for reporting.
Yes I am trying to keep dialog interface for now very minimal. It does not provide all cases.

Timeout you are facing is actually just transaction timeout and should have nothing with dialog.
Consider that even if you do not do this

<-tx.Done()
fmt.Printf("DIALOG DONE!!!\n")

dialog will be managed and have proper ACK and BYE handled.

So this just indicates that transaction handler is done but not dialog. Dialog is done when BYE is received, or this line specifically.

_ = dialogSrv.ReadBye(req, tx)

After you send 200 OK, your call should be still handled and managed by dialog, but you normally do not want to terminate transaction too early (State handling transaction, resending) so therefore it is recomended to keep transaction open with

<-tx.Done()

and let either dialog terminates or timeout (64 * T1 = 30 seconds).

I also see some issue of misuse, or maybe I am missing some docs here. What could help maybe that dialog wraps
this call with own Done but this will just block even more.

What are some features that maybe I am still in research is that you have dialog monitoring. This could make sense for you use case, but maybe I am wrong?

dialogSrv.OnDialog(d Dialog) {
     switch d.State() {
        case "established":
        case "terminated""
     }
}

@half2me
Copy link
Author

half2me commented Nov 14, 2023

Basically I need to clean up some resources when a call ends. This could happen when I receive BYE, but this message could also never arrive, such is the nature of UDP. How will I know the call is finished?

@emiago
Copy link
Owner

emiago commented Nov 14, 2023

@half2me Yes I see.
So you probably needs this dialog monitoring to be exposed.
What will allow you that outside of this transaction handlers, you deal only with dialog, but it will still be async.

This could happen when I receive BYE, but this message could also never arrive, such is the nature of UDP

True, this is now required some timeout handling + maybe keep alive over SIP.

So here I what I see that is missing

	srv.OnInvite(func(req *sip.Request, tx sip.ServerTransaction) {
		dlg, err := dialogSrv.ReadInvite(req, tx)
		
		...
		_ = dlg.Respond(sip.StatusOK, "OK", sdpResp, sip.NewHeader("Content-Type", "application/sdp"))
		
		
		<-tx.Done()
		fmt.Printf("DIALOG DONE!!!\n")
	})
	
      dialogSrv.OnDialog(func(d DialogServerSession) {
                // Dialog created on 200 OK
                select {
                    case <-d.Done():
                            // Bye Received from UAC
                    case <-time.After(3 *time.Second):
                           d.Bye()
                }
                
                // Do some after dialog cleanup
      })

@emiago
Copy link
Owner

emiago commented Nov 14, 2023

@half2me you can also checkout
https://github.com/emiago/sipgox/blob/c827447221daf40967212c605bc54db765a6d884/phone.go#L442

how this is handled. If you can ignore all other.

Basically I used seperate channel to draw out dialogServerSession and wrapped some done channel to signal when Bye is received. So there is some design missing currently

@emiago
Copy link
Owner

emiago commented Nov 18, 2023

@half2me I have added Done() for dialog as well

Check main branch
So now you can

dlg, err := dialogSrv.ReadInvite(req, tx)
...
<-dlg.Done()
fmt.Printf("DIALOG DONE!!!\n")

Also I noticed sometimes cleanup is hard to achieve due to many actions to take.
So for now there is also exposed
dlg.Close()

Which will trigger dlg.Done()

Pls provide some feedback after checking this

@emiago
Copy link
Owner

emiago commented Nov 22, 2023

For now dialog control should be enough with new calls. Clossing this issue

@emiago emiago closed this as completed Nov 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants