sipgo icon indicating copy to clipboard operation
sipgo copied to clipboard

WriteResponse fails when called from a goroutine

Open andzsinszan opened this issue 1 year ago • 4 comments

This is a question, request for clarification.

  • when WriteResponse() is called from the same go routine as an OnInvite() -> all good.
  • when called from a different routine, it is never sent to the server
// OK
dialogServerSession.WriteResponse(resp)

// FAILS silently
go dialogServerSession.WriteResponse(resp)

// FAILS silently
go func(){
  time.Sleep(5 * time.Second)
  dialogServerSession.WriteResponse(resp)
}()

Is there a restriction that dialogues/sessions can only be used from the same goroutine? I am familiar with phone.go, I know how to re-organize my code so that dialogues/sessions do not cross goroutine boundaries if absolutely necessary.

Cf.: phone.go around #1141

err = func() error {
  // ...
  if err := dialog.WriteResponse(res); err != nil {
  // ...
}()   // <-- sic!

That err = func() error {}() is a bit suspicious... almost looks like a goroutine.

andzsinszan avatar Jul 28 '24 13:07 andzsinszan

If you are exiting Invite Server Transaction, then you are terminating Transaction. Normally you should do all responses in this goroutine. So after sending final response (>199) you are free to jump arround as much as you like.

emiago avatar Jul 28 '24 15:07 emiago

Thank you for the fast response. So it is a scope/lifetime issue - it isn't about goroutines. Indeed: if I keep OnInvite() alive, other go routines can also WriteResonse. Fine.

Could WriteResponse perhaps return an error upon trying to use a terminated transaction? Currently, tx.Err() WriteResponse just returns nil - as the previous/completed transaction(s) had no error.

// dialgog_server.go #297
select {
case req := <-tx.Cancels():
    tx.Respond(sip.NewResponseFromRequest(req, sip.StatusOK, "OK", nil))
    return ErrDialogCanceled
case <-tx.Done():
    // There must be some error         // [my comment] 'some error':  re-using a Done() transaction
    return tx.Err()
default:
}

andzsinszan avatar Jul 29 '24 00:07 andzsinszan

@andzsinszan ok I see your point. Maybe it makes sense to return error, similar as context.Context returns on cancelation

emiago avatar Jul 29 '24 08:07 emiago

Hi @emiago , thanks again for the fast response.

Maybe it makes sense to return error, similar as context.Context returns on cancelation

Thanks, I would really be going for it. As a returning nil error implies that the task was competed.

For reference, it is common to prevent the restart of a completed thread (or session), e.g.,

  • Java throws java.lang.IllegalThreadStateException
  • Python throws RuntimeError: threads can only be started once
  • C++ : no explicit thread start -> c'tor starts the thread -> cannot be re-used/re-started

andzsinszan avatar Jul 30 '24 01:07 andzsinszan

Hi @andzsinszan now when responding on server transaction you should recieve error. This last one I do not get. Adding more runtime checks could be sign of bad written library as well. sipgo must stay in some low level area and built on to, that is why I suggest that you now switch to https://github.com/emiago/diago project and give feedback there for better call control

emiago avatar Sep 28 '24 10:09 emiago