Skip to content

Invite transaction terminated when received Prack for 100rel #229

@k3nopa

Description

@k3nopa

Description

For every request received, it seems library will terminate the server transaction after passing it to registered handler. In my case, this caused an issue during INVITE's mid-dialog handling when PRACK request is received in response to a provisional response. When attempting to send final response, in this case 487 through tx, somehow it repeatedly it for a few times and stop.

Below is pcap snapshot where "TAS_IP" is the app encountering this issue.
Image

To confirm this, I've printed backtrace in tx.OnTerminate() of registered invite handler.

=== BACKTRACE ===
#0: func1()
at /mnt/tas/src/handlers.go:65
#1: func1()
at /go/pkg/mod/github.com/emiago/sipgo@v0.31.0/sip/transaction.go:210
#2: delete()
at /go/pkg/mod/github.com/emiago/sipgo@v0.31.0/sip/transaction_server_tx.go:259
#3: Terminate()
at /go/pkg/mod/github.com/emiago/sipgo@v0.31.0/sip/transaction_server_tx.go:152
#4: TerminateGracefully()
at /go/pkg/mod/github.com/emiago/sipgo@v0.31.0/sip/transaction_server_tx.go:173
#5: handleRequest()
at /go/pkg/mod/github.com/emiago/sipgo@v0.31.0/server.go:271
#6: serverTxRequest()
at /go/pkg/mod/github.com/emiago/sipgo@v0.31.0/sip/transaction_layer.go:155
#7: handleRequest()
at /go/pkg/mod/github.com/emiago/sipgo@v0.31.0/sip/transaction_layer.go:129
#8: handleRequestBackground()
at /go/pkg/mod/github.com/emiago/sipgo@v0.31.0/sip/transaction_layer.go:89

Attempting digging the source code, I do see it's applicable for all received request

// server.go
// handleRequest is handling transaction layer
func (srv *Server) handleRequest(req *sip.Request, tx *sip.ServerTx) {
	for _, mid := range srv.requestMiddlewares {
		mid(req)
	}

	handler := srv.getHandler(req.Method)
	handler(req, tx)
	if tx != nil {
		// Must be called to prevent any transaction leaks
		tx.TerminateGracefully()
	}
}
// transaction_server_tx.go
// TerminateGracefully allows retransmission to happen before shuting down transaction
func (tx *ServerTx) TerminateGracefully() {
	if tx.reliable {
		// reliable transports have no retransmission, so it is better just to terminate
		tx.Terminate()
		return
	}

	// Check did we receive final response
	tx.fsmMu.Lock()
	finalized := tx.fsmResp != nil && !tx.fsmResp.IsProvisional()
	tx.fsmMu.Unlock()
	if !finalized {
		tx.Terminate()
		return
	}
	tx.log.Debug("Server transaction waiting termination")
	<-tx.Done()
}

Question/Request

Please let me know if my approach is not as the library intended or this is an issue.

Note

For now, I'm able to achieve sending 487 with server.WriteResponse(res).

Thanks for the awesome library. It help me a lot on learning and understanding how SIP works.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions