RFC 3261: Il DNA del VoIP – Capitolo 9
BYE e CANCEL: chiudere o interrompere una chiamata SIP

Dopo aver visto come nasce una sessione SIP e come viene confermata con ACK, possiamo affrontare un passaggio che nei tracciati pcap genera spesso qualche dubbio. Prima di entrare in CANCEL e BYE, conviene però fissare tre concetti che ci serviranno per leggere tutto il resto con più ordine.

Transaction, dialog e sessione avranno più avanti uno spazio tutto loro. Qui li teniamo volutamente semplici. Ci basta capire che cosa rappresentano e come riconoscerli quando abbiamo davanti un tracciato pcap.

Tre definizioni da fissare subito

Transaction, in modo semplice, è lo scambio tra una richiesta SIP e le risposte che appartengono a quella richiesta.

Dialog, sempre in modo semplice, è la relazione SIP che si crea tra due lati della comunicazione e che resta valida per un certo tempo, permettendo di scambiare richieste all’interno di quello stesso contesto.

Sessione è invece la comunicazione reale che il SIP sta cercando di instaurare, modificare o chiudere, per esempio una chiamata voce.

Quando le spiego in aula, cerco sempre di separarle subito. Sembrano vicine, ma descrivono tre livelli diversi della stessa comunicazione.

  • La transaction guarda il singolo scambio di segnalazione.
  • Il dialog guarda la relazione SIP che tiene insieme più messaggi coerenti tra loro.
  • La sessione guarda la comunicazione nel suo significato operativo, per esempio la chiamata tra due utenti.

Come distinguerli empiricamente in un tracciato pcap

Quando apro un tracciato pcap, per riconoscere una transaction parto da una richiesta precisa: INVITE, BYE, CANCEL o un altro metodo. Poi seguo le risposte che appartengono proprio a quella richiesta.

Per il dialog il ragionamento cambia. Qui seguo soprattutto Call-ID e tag di From e To. Se questi elementi restano coerenti nel tempo, sto osservando una relazione SIP che continua oltre la singola transaction.

La sessione la leggo invece dall’insieme: chi chiama chi, quando la chiamata viene accettata, quando parte il media e quando la comunicazione viene chiusa. È il livello che più assomiglia a ciò che, nella pratica, chiamiamo semplicemente chiamata.

Possiamo distinguerli anche così:

  • se guardi un singolo INVITE con le sue risposte, stai guardando soprattutto una transaction
  • se guardi la continuità tra INVITE, ACK, eventuale re-INVITE e BYE, stai guardando soprattutto un dialog
  • se guardi l’intera chiamata come evento comunicativo, stai guardando la sessione

Questa distinzione, qui presentata in modo volutamente semplice, ci basta per leggere bene il resto del capitolo. Nei capitoli dedicati a dialog e transaction layer torneremo su questi concetti con il livello di dettaglio completo previsto dalla RFC 3261.

CANCEL e BYE: due fasi diverse

Con queste tre definizioni in mente, possiamo finalmente entrare nel tema del capitolo.

CANCEL e BYE sono due metodi che servono a fermare una chiamata, ma in fasi diverse. CANCEL si usa quando il tentativo di chiamata è ancora pendente. BYE si usa quando la chiamata è già stata accettata e deve essere chiusa.

In termini più tecnici, CANCEL agisce su una richiesta ancora in corso, tipicamente un INVITE che non ha ancora ricevuto una risposta finale. BYE agisce invece all’interno di un dialog e termina la sessione associata.

Le sezioni di riferimento sono la Sezione 9, dedicata a CANCEL, e la Sezione 15, dedicata a BYE.

Quando leggo un tracciato pcap, la prima domanda che mi faccio è molto semplice: in quale fase della chiamata siamo? Siamo ancora prima della risposta finale? Abbiamo già un 200 OK? È arrivato l’ACK? Da questa risposta dipende la lettura corretta di CANCEL e BYE.

Che cosa dice la RFC sul CANCEL

“The CANCEL request, as the name implies, is used to cancel a previous request sent by a client. Specifically, it asks the UAS to cease processing the request and to generate an error response to that request.”
La richiesta CANCEL, come suggerisce il nome, viene usata per annullare una richiesta precedente inviata da un client. In modo specifico, chiede al lato UAS di interrompere l’elaborazione della richiesta e di generare una risposta di errore per quella richiesta.

Tradotto sul campo, CANCEL non chiude una sessione già attiva. Chiede al sistema remoto di interrompere l’elaborazione di una richiesta precedente. Se il telefono di Matteo sta ancora squillando e Daniele riaggancia, CANCEL è il messaggio con cui quel tentativo viene fermato prima della risposta finale.

La RFC aggiunge anche un altro punto decisivo: CANCEL non ha effetto se il lato UAS ha già generato una risposta finale. Questo significa che non esiste alcun potere retroattivo del metodo. Se la risposta finale è già partita, il CANCEL arriva troppo tardi per cambiare l’esito di quella transaction.

Per questo la RFC spiega che CANCEL è particolarmente utile per INVITE, cioè per richieste che possono restare aperte più a lungo delle altre. Un OPTIONS o un REGISTER, in condizioni normali, vengono gestiti molto più in fretta. Con un INVITE, invece, il terminale può squillare, l’utente può esitare, il proxy può fare forking, e la finestra temporale diventa molto più ampia.

Controllo del metodo

La RFC è molto chiara anche su un altro punto: un CANCEL non dovrebbe essere usato per annullare metodi diversi da INVITE. La ragione è pratica. Le richieste non-INVITE ricevono in genere una risposta immediata, quindi l’invio di un CANCEL creerebbe quasi sempre una corsa inutile tra messaggi.

Nel tracciato pcap la verifica è abbastanza immediata. Se la transaction originale è ancora in attesa di una risposta finale, CANCEL ha senso. Se invece la risposta finale è già arrivata, il CANCEL non può più cambiare quel risultato.

Un altro dettaglio importante è il modo in cui il CANCEL viene correlato alla richiesta originale. La RFC richiede che Request-URI, Call-ID, To, la parte numerica di CSeq e From siano identici a quelli della richiesta da annullare. Anche il Via deve corrispondere al top Via della richiesta originale. Cambia però il metodo nel CSeq, che diventa CANCEL.

Questo serve a un obiettivo molto concreto: il server deve poter capire con precisione quale richiesta precedente il CANCEL sta cercando di fermare, pur restando una transaction separata.

Quando può partire il CANCEL

La RFC aggiunge una regola che nel tracciato pcap è facile da trascurare: il client non deve inviare CANCEL prima di aver ricevuto almeno una risposta provvisoria alla richiesta originale.

Immaginiamo che Daniele invii l’INVITE e riagganci quasi subito. Se non è ancora arrivata neppure una risposta 1xx, il suo User Agent deve aspettare prima di trasmettere il CANCEL. Il motivo è molto pratico: senza questa regola, in alcune condizioni di rete il CANCEL potrebbe arrivare al server prima dello stesso INVITE che dovrebbe annullare.

Se invece nel frattempo è già arrivata una risposta finale all’INVITE, il CANCEL non va più inviato, perché non avrebbe alcun effetto sull’esito già prodotto.

Stesso percorso della richiesta originale

Anche la costruzione del CANCEL segue alcune regole precise. Se l’INVITE originale contiene un header Route, gli stessi valori devono essere riportati nel CANCEL. Inoltre destinazione, porta e protocollo di trasporto devono essere gli stessi usati per inviare la richiesta originale.

La RFC specifica anche che CANCEL non deve contenere gli header Require o Proxy-Require. Sono dettagli che riprenderemo quando parleremo in modo più completo di routing e proxy, ma vale la pena conoscerli già adesso perché aiutano a capire perché un CANCEL non viene costruito come una richiesta completamente indipendente.

Che cosa succede quando arriva il CANCEL

Se il lato UAS riceve un CANCEL valido per un INVITE ancora pendente, la RFC si aspetta un comportamento preciso. Il lato server risponde con un 200 OK al CANCEL per confermare la ricezione della richiesta di annullamento. Poi deve ancora chiudere correttamente l’INVITE originario, tipicamente con 487 Request Terminated.

Nei corsi insisto spesso su questo passaggio: il 200 OK al CANCEL non dice che la chiamata è definitivamente chiusa. Dice soltanto che il CANCEL è stato ricevuto e accettato come transaction autonoma.

L’INVITE originario deve comunque avere la sua conclusione. E la conclusione più tipica, quando il CANCEL arriva in tempo, è proprio 487 Request Terminated.

Daniele                         Matteo
   |                                |
   |------ INVITE ----------------->|
   |<----- 180 Ringing -------------| |------ CANCEL ----------------->|
   |<----- 200 OK (CANCEL) ---------|
   |<----- 487 Request Terminated --| |------ ACK -------------------->|
   |                                |

In questo schema il significato dei messaggi è molto preciso.

  • l’INVITE è partito correttamente
  • il terminale remoto ha iniziato a squillare con 180 Ringing
  • il chiamante ha deciso di interrompere il tentativo con CANCEL
  • il lato remoto ha confermato il CANCEL con 200 OK
  • l’INVITE è stato chiuso con 487 Request Terminated
  • il chiamante ha mandato ACK alla risposta finale non-2xx dell’INVITE

Per leggerlo bene dobbiamo quindi tenere separati i due livelli: la transaction del CANCEL e la conclusione dell’INVITE originale.

Quando il CANCEL non trova la richiesta

Il server deve anche riuscire a collegare il CANCEL alla transaction che si vuole interrompere. Se non trova una transaction corrispondente, la risposta prevista è 481 Call/Transaction Does Not Exist.

Se invece la transaction originale esiste, il CANCEL viene gestito come una transaction propria. Quando l’INVITE è ancora pendente, il comportamento che ci aspettiamo è quello già visto: 200 OK al CANCEL e, normalmente, 487 Request Terminated all’INVITE.

C’è poi un limite temporale. Se dopo il CANCEL non arriva alcuna risposta finale alla richiesta originale entro 64*T1, il client può considerare cancellata la transaction originaria e rimuoverne lo stato. Qui non entriamo ancora nei valori dei timer: T1, 64*T1 e le relative macchine a stati verranno ripresi nel capitolo dedicato al transaction layer.

CANCEL e proxy

CANCEL ha anche una caratteristica importante: viene trattato come richiesta hop-by-hop. Uno stateful proxy che riceve un CANCEL risponde direttamente a quel CANCEL e, quando serve, genera a sua volta i CANCEL verso le transaction aperte a valle.

Questo significa che in un tracciato con più proxy non dobbiamo immaginare il CANCEL come un unico messaggio che attraversa la rete senza essere gestito dai nodi intermedi. Il dettaglio completo appartiene al capitolo sui proxy, ma questa distinzione aiuta già a leggere meglio i flussi con più hop.

⚠ I CONSIGLI DI VOIP.IT

Quando vedi un CANCEL, non fermarti mai al suo 200 OK. Controlla sempre anche come si chiude l’INVITE originale.

  • Se trovi 487 Request Terminated, il tentativo di chiamata è stato interrotto prima della sessione confermata.
  • Se trovi invece un 2xx all’INVITE, il CANCEL è arrivato troppo tardi per fermare l’accettazione. A quel punto la chiusura richiede un BYE.
  • In Wireshark conviene correlare sempre Call-ID, CSeq, tag e direzione dei messaggi prima di concludere che la chiamata sia davvero terminata.

Che cosa dice la RFC sul BYE

Con BYE cambia proprio il livello di lettura. Con CANCEL stavamo ancora cercando di fermare una richiesta pendente. Con BYE lavoriamo invece dentro un dialog che esiste già e dobbiamo terminare la sessione associata.

Per questo la regola RFC sul BYE richiama concetti come early dialog, confirmed dialog e, più avanti, anche il completamento corretto del setup con ACK. Li chiariremo subito dopo la citazione, così la sequenza resta lineare.

“A UA MUST NOT send a BYE outside of a dialog. The caller’s UA MAY send a BYE for either confirmed or early dialogs, and the callee’s UA MAY send a BYE on confirmed dialogs, but MUST NOT send a BYE on early dialogs.”
Un User Agent non deve inviare un BYE fuori da un dialog. Il lato chiamante può inviare un BYE sia per dialog confirmed sia per dialog early, mentre il lato chiamato può inviare un BYE sui dialog confirmed, ma non deve inviarlo sui dialog early.

Questo passaggio è importante perché mostra quanto BYE sia legato alla nozione di dialog. Diversamente da CANCEL, che agisce su una richiesta ancora in corso, BYE è un messaggio che vive dentro una relazione SIP già identificata dai suoi elementi di dialog.

La prima regola è netta: BYE non si invia fuori da un dialog. Quindi non è il metodo giusto per provare a fermare un INVITE iniziale che non ha ancora generato il contesto corretto. La RFC ha voluto esplicitamente separare questo caso, affidandolo a CANCEL.

La seconda regola richiede ancora più attenzione. Il lato chiamante può inviare BYE anche su un early dialog. Il lato chiamato, invece, non può farlo. Può inviare BYE solo su un dialog confirmed.

Questa differenza non è casuale. Dipende dal modo in cui il protocollo fa nascere e consolidare il dialogo tra le due parti.

Early dialog e confirmed dialog, spiegati in modo semplice

Qui ci basta una lettura pratica. Il capitolo dedicato ai dialoghi entrerà molto più in profondità; per ora ci interessa capire quando un dialog è ancora early e quando diventa confirmed.

Un dialog è la relazione SIP che si forma tra due lati della comunicazione e che viene identificata da elementi come Call-ID, tag locale e tag remoto. Questa relazione non nasce tutta in un colpo solo. Ha una fase iniziale e una fase confermata.

Un early dialog è un dialog che ha già iniziato a prendere forma, ma che non è ancora arrivato alla risposta finale di successo che conferma davvero la sessione.

Un confirmed dialog è invece un dialog che ha già ricevuto una risposta finale 2xx all’INVITE ed è quindi entrato nella fase confermata della comunicazione.

Detto in modo semplice:

  • early dialog, la chiamata è avviata ma non ancora accettata in modo definitivo
  • confirmed dialog, la chiamata è stata accettata con risposta finale di successo

Esempio pratico di early dialog

Immaginiamo che Daniele chiami Matteo.

Daniele                         Matteo
   |                                |
   |------ INVITE ----------------->|
   |<----- 180 Ringing -------------|
   |                                |

Matteo non ha ancora accettato la chiamata. Il suo terminale sta semplicemente dicendo che sta squillando. Se in questa fase si è già formato il dialog, siamo davanti a un early dialog: la relazione SIP esiste, ma la sessione non è ancora stata accettata in modo definitivo.

Che cosa significa operativamente? Significa che la chiamata è in corso di instaurazione, ma non è ancora arrivata al punto in cui possiamo dire che la sessione sia davvero confermata.

È proprio per questo che la RFC separa bene i comportamenti dei due lati. Il chiamante, in alcune condizioni, può ancora decidere di chiudere quel ramo con BYE. Il chiamato, invece, non deve usare BYE su un early dialog. Prima della conferma, il protocollo vuole mantenere separato il piano del tentativo di chiamata da quello della sessione ormai accettata.

Esempio pratico di confirmed dialog

Adesso prendiamo lo stesso caso e portiamolo un passo avanti.

Daniele                         Matteo
   |                                |
   |------ INVITE ----------------->|
   |<----- 180 Ringing -------------|
   |<----- 200 OK ------------------| |------ ACK -------------------->|
   |                                |

Con il 200 OK il quadro cambia. L’INVITE è stato accettato e il dialog diventa confirmed. Quando arriva anche l’ACK, il setup della segnalazione è completato. Da quel momento siamo nel caso più comune di chiamata attiva che, quando deve terminare, viene chiusa con BYE.

Questo è il contesto tipico del BYE. Quando la chiamata è arrivata qui, se una delle due parti vuole terminarla, la richiesta corretta è BYE, seguita da 200 OK.

Se è il chiamato a rifiutare

Fin qui abbiamo guardato soprattutto il comportamento del chiamante che decide di rinunciare al tentativo. Dal lato chiamato la logica è diversa.

Se Matteo non ha ancora accettato l’INVITE e decide di rifiutare la chiamata, non deve inviare CANCEL, perché non è lui ad aver generato la richiesta originale. E non può usare BYE su un early dialog. Deve invece chiudere l’INVITE con una risposta finale non-2xx adatta al motivo del rifiuto.

La Sezione 15 cita, come esempio legato all’interfaccia utente, anche 403 Forbidden per esprimere il rifiuto prima della risposta. Il codice concreto dipende dal motivo e dal comportamento del sistema, ma la regola da ricordare è semplice: prima dell’accettazione, il chiamato rifiuta l’INVITE con una risposta finale; non termina la chiamata con BYE.

Il lato UAC

Dal punto di vista del lato che invia il BYE, la RFC tratta il metodo come una normale richiesta in-dialog. Una volta costruito il messaggio, il lato UAC crea una nuova non-INVITE client transaction e lo invia.

C’è però una regola operativa molto forte: il lato che invia BYE deve considerare la sessione terminata immediatamente, cioè dal momento in cui passa il BYE alla client transaction. In pratica, deve smettere di inviare e ricevere media subito, senza aspettare il 200 OK finale.

Questo è un dettaglio utile anche in diagnostica. Se un terminale continua a tenere attivo il media molto oltre l’invio del BYE, il comportamento va guardato con attenzione, perché la logica RFC è diversa.

La RFC chiarisce anche un caso che sul campo può creare dubbi. Se il BYE riceve un 481 Call/Transaction Does Not Exist, un 408 Request Timeout oppure non riceve alcuna risposta, il lato UAC deve comunque considerare terminati sia la sessione sia il dialog.

Quindi l’assenza del classico 200 OK al BYE non significa che il terminale debba mantenere attiva la chiamata. Dal punto di vista del lato che ha inviato il BYE, la sessione è già terminata.

Il lato UAS

Quando il lato UAS riceve un BYE, deve prima verificare che il messaggio corrisponda a un dialog esistente. Se non trova un dialog valido, la risposta corretta è normalmente 481 Call/Transaction Does Not Exist.

Se invece il dialog esiste, il lato UAS deve elaborare il BYE e poi rispondere con una risposta 2xx, in pratica quasi sempre 200 OK. Dopo questo passaggio la sessione viene considerata terminata e il media si ferma.

Nel tracciato pcap, una chiusura pulita della chiamata si presenta quindi in modo molto lineare.

Matteo                          Daniele
   |                                |
   |------ BYE -------------------->|
   |<----- 200 OK ------------------|
   |                                |

Qui il tracciato è leggibile senza ambiguità. Il dialog esiste già. Uno dei due lati decide di chiudere la sessione. L’altro conferma con 200 OK. Non serve alcun ACK, perché ACK ha una logica speciale legata all’INVITE, non ai metodi non-INVITE.

Dopo il BYE

La ricezione di un BYE valido non fa sparire automaticamente le altre richieste che erano già pendenti sullo stesso dialog. Il UAS deve ancora rispondere a quelle richieste e la RFC raccomanda, in questi casi, una risposta 487 Request Terminated.

È un dettaglio utile nei tracciati più complessi, dove un BYE può incrociarsi con una richiesta già in corso. Vedere un 487 dopo il BYE non significa necessariamente che il BYE sia fallito: può appartenere a un’altra transaction che era ancora aperta sul dialog.

La RFC contempla anche un caso particolare per le sessioni multicast. In quel contesto un UAS può scegliere di continuare la propria partecipazione al media anche dopo il BYE dell’altro lato, pur dovendo comunque rispondere 2xx al BYE. È uno scenario poco comune nel VoIP Business e non lo approfondiamo qui.

Il vincolo sul lato chiamato

Ora che la differenza tra early dialog e confirmed dialog è chiara, possiamo leggere meglio la regola più delicata del BYE.

Il lato chiamato non deve inviare BYE su un dialog confirmed finché non ha ricevuto l’ACK al proprio 2xx, oppure finché non termina la server transaction.

La ragione è semplice: con il 200 OK il dialog è già confirmed, ma il passaggio INVITE–200 OK–ACK non è ancora completo. Il chiamato deve quindi lasciare al protocollo il tempo di ricevere l’ACK. Se l’ACK non arriva, entreranno in gioco i timer previsti dalla RFC.

Tra 200 OK e ACK

C’è una fase molto breve ma importante da distinguere. Matteo ha già accettato l’INVITE con 200 OK, quindi il dialog è confirmed, ma non ha ancora ricevuto l’ACK.

Daniele                         Matteo
   |                                |
   |------ INVITE ----------------->|
   |<----- 180 Ringing -------------|
   |<----- 200 OK ------------------|
   |                                |

In questa finestra il lato chiamato non deve ancora inviare BYE. Deve prima attendere l’ACK oppure la scadenza prevista dal protocollo. Questo passaggio spiega perché un dialog può essere già confirmed mentre il setup dell’INVITE non è ancora completato dal punto di vista della segnalazione.

Che cosa significa timeout in questo contesto

Il timeout, in questo passaggio, va letto in modo molto concreto: il lato chiamato non può aspettare per sempre un ACK che potrebbe non arrivare.

Se dopo il 200 OK il chiamato non riceve l’ACK entro il tempo previsto dal protocollo, la server transaction conclude che il completamento del setup non è avvenuto come atteso. A quel punto non ha più senso restare sospesi in quella fase intermedia.

Nel capitolo dedicato al transaction layer vedremo in dettaglio timer, stati e macchine a stati della RFC 3261. Qui basta fissare l’idea pratica: il timeout è il limite oltre il quale il protocollo smette di aspettare l’ACK come evento ancora plausibile.

Nel tracciato pcap questo scenario si riconosce abbastanza bene: il 200 OK all’INVITE viene ritrasmesso più volte, ma l’ACK non compare. In quel caso non sto cercando un problema di chiusura della chiamata. Sto ancora cercando perché il setup non si è completato correttamente.

Come leggere questa regola in pratica

Possiamo quindi tradurre la regola RFC così:

  • prima del 200 OK, siamo ancora nella fase di instaurazione
  • dopo il 200 OK, il dialog entra nella fase confermata, ma il lato chiamato deve ancora attendere l’ACK
  • solo dopo l’ACK, oppure dopo il timeout previsto se l’ACK non arriva, il lato chiamato può chiudere con BYE senza creare incoerenze nel setup

Questa lettura è molto utile perché evita due errori frequenti:

  • pensare che il 200 OK da solo basti sempre a considerare il setup completamente chiuso
  • pensare che il BYE sia un metodo generico da usare in qualsiasi punto della chiamata

Cosa succede se il CANCEL arriva troppo tardi

Questo è uno di quei casi che in Wireshark vale la pena leggere con calma. Daniele invia CANCEL mentre l’INVITE è ancora pendente, ma quasi nello stesso momento Matteo accetta la chiamata con 200 OK.

Se il 200 OK all’INVITE è già stato generato, il CANCEL non può annullarlo retroattivamente. Daniele deve riconoscere quella risposta con ACK e, se non vuole proseguire la chiamata, chiudere poi la sessione con BYE.

Daniele                         Matteo
   |                                |
   |------ INVITE ----------------->|
   |<----- 180 Ringing -------------| |------ CANCEL ----------------->|
   |<----- 200 OK (CANCEL) ---------|
   |<----- 200 OK (INVITE) ---------| |------ ACK -------------------->|
   |------ BYE -------------------->|
   |<----- 200 OK ------------------|
   |                                |

La lettura corretta è quindi questa: il CANCEL è stato ricevuto, ma è arrivato troppo tardi per impedire l’accettazione dell’INVITE. Il 200 OK al CANCEL conferma soltanto la ricezione del CANCEL; il 200 OK all’INVITE crea invece un esito diverso, che richiede ACK e, se la chiamata va chiusa, BYE.

Quando lo vediamo in un tracciato pcap non dobbiamo quindi pensare subito a un errore. È una conseguenza possibile della temporizzazione dei messaggi SIP.

Consigli pratici per Wireshark

Quando analizzi una chiusura o un’interruzione di chiamata, evita di partire dal singolo pacchetto. Ricostruisci prima il flusso completo e poi verifica a quale transaction appartiene ogni risposta.

Un metodo pratico è questo:

  • parti dal Call-ID per isolare i messaggi della chiamata
  • controlla il CSeq per capire a quale metodo appartiene una risposta, soprattutto quando nello stesso flusso compaiono più 200 OK
  • verifica la direzione dei messaggi e i tag di From e To quando devi seguire il dialog
  • se trovi un CANCEL, cerca sempre anche la risposta finale all’INVITE
  • se trovi 487 Request Terminated, verifica che sia seguito dall’ACK previsto per la risposta finale non-2xx all’INVITE
  • se trovi un 200 OK all’INVITE dopo il CANCEL, cerca l’ACK e l’eventuale BYE successivo
  • se trovi un CANCEL, verifica che prima sia arrivata almeno una risposta provvisoria all’INVITE originale
  • un 481 in risposta al CANCEL indica che il server non ha trovato la transaction da cancellare
  • con più proxy, ricorda che CANCEL è hop-by-hop e può essere gestito e rigenerato dagli stateful proxy
  • se un BYE riceve 481, 408 o va in timeout, il lato che lo ha inviato considera comunque sessione e dialog terminati

Wireshark mette a disposizione anche filtri utili per restringere rapidamente l’analisi:

sip.Method == "CANCEL"
sip.Method == "BYE"
sip.Status-Code == 487
sip.CSeq.method == "INVITE"
sip.CSeq.method == "CANCEL"
sip.Call-ID == "valore-del-call-id"

Il filtro sul CSeq è particolarmente utile quando compaiono due risposte 200 OK vicine: una può riferirsi al CANCEL e l’altra all’INVITE. Guardare solo il codice di risposta non basta; bisogna leggere il metodo indicato nel CSeq.

Se invece vedi più 200 OK all’INVITE e nessun ACK, concentra l’analisi sul percorso dell’ACK e sulla raggiungibilità del lato che ha generato il 200 OK. Le ritrasmissioni, da sole, non dicono ancora dove sia il problema, ma indicano che il completamento del setup non è avvenuto come previsto.

Per una vista d’insieme può essere utile anche il flusso VoIP di Wireshark, così da verificare rapidamente ordine, direzione e tempi dei messaggi prima di entrare nel dettaglio dei singoli pacchetti.

Per i nomi aggiornati dei campi puoi fare riferimento alla Display Filter Reference SIP di Wireshark.

Perché la RFC separa così nettamente i due metodi

La separazione tra i due metodi serve a mantenere ordinati i diversi livelli del protocollo. CANCEL lavora su una richiesta ancora in corso. BYE lavora su una sessione che vive già dentro un dialog. Tenere distinti questi due casi rende più semplice anche il troubleshooting.

Per questo la RFC 3261 chiarisce anche che, rispetto a RFC 2543, CANCEL e BYE non devono più essere mescolati. L’INVITE originario va sempre chiuso correttamente. Se il chiamante vuole fermarsi prima della risposta finale usa CANCEL. Se invece un dialog è stato già accettato, la chiusura corretta passa da BYE.

È una distinzione che, una volta interiorizzata, rende molto più naturale la lettura dei flussi SIP reali.

Conclusione

In questo capitolo abbiamo chiarito una distinzione fondamentale della RFC 3261. CANCEL non chiude una sessione già accettata. Ferma una richiesta ancora pendente e prova a far chiudere l’INVITE con una risposta finale non-2xx, in genere 487 Request Terminated. BYE, invece, vive dentro un dialog e termina la sessione associata.

Quando analizziamo un tracciato pcap, quindi, non fermiamoci mai al 200 OK del CANCEL. Seguiamo sempre anche l’INVITE originale e verifichiamo come si chiude. Se nel frattempo è arrivato un 2xx, potrebbe essere nato un dialog che richiede poi un BYE.

Dopo aver chiarito come una chiamata SIP può essere interrotta o terminata, nel prossimo capitolo vedremo OPTIONS. Sarà il passaggio giusto per capire come il protocollo usa una richiesta diversa da INVITE per interrogare capacità e disponibilità, senza entrare ancora nei capitoli più avanzati su dialoghi, transaction layer e proxy.

Tags: