Comprendre
les échanges SIP par l’expérimentation
Emin Gabrielyan
Christian Lathion (traduction)
2007-04-10
Switzernet Sàrl
Nous allons analyser
quelques scénarios simples d’échange de messages SIP, pour un appel entre deux
téléphones SIP. Nous utilisons SIP Express Router (SER) comme proxy, ainsi que
pour analyser les messages SIP. Nous illustrons et analysons les requêtes
INVITE, CANCEL, ACK, BYE ainsi que leur réponses. Nous discuterons les
transactions et dialogues SIP. Nous examinerons le cas où le serveur proxy
intermédiaire ne participe qu’à l’établissement de l’appel, ainsi que le cas où
il modifie l’adresse des messages de signalisation pour participer à la
signalisation de toute la session SIP. Nous n’examinerons pas le chemin du
média. Lors de nos expérimentations, les paquets RTP sont directement transmis
entre les deux téléphones SIP, sans intermédiaire.
Comprendre les échanges SIP par
l’expérimentation
2.2. A quoi ressemblent les messages SIP ?
2.3. Configuration des
appareils SIP
2.4. Configuration du
serveur proxy SIP
2.5. Messages d’établissement
d’appel
2.7. Configuration de SER sans mémoire (stateless)
3. Le proxy SIP traite l’établissement de l’appel et tous les messages de
signalisation suivants
4. Autres expérimentations pour comprendre le protocole SIP
Dans nos expérimentations,
nous utiliserons deux téléphones SIP (Grandstream Budge Tone-100) [308, bmp, htm], [309, bmp, htm], ainsi qu’un serveur proxy SIP OpenSER, une
déclinaison de SIP Express Router (SER).
Ce scénario (le proxy SIP
ne prend en charge la signalisation que lors de l’établissement de l’appel, le
reste de la signalisation passe directement entre les deux téléphones SIP en
contournant le proxy) est le premier exemple décrit dans le RFC3261 [txt], [htm]. Voir le schéma
ci-dessous [rfc3261,
p.10-11].
atlanta.com . . . biloxi.com
. proxy proxy .
. .
softphone SIP Phone
| | | |
| INVITE F1 | | |
|--------------->| INVITE F2 | |
| 100 Trying F3 |--------------->| INVITE F4 |
|<---------------| 100 Trying F5 |--------------->|
| |<-------------- | 180 Ringing F6 |
| | 180 Ringing F7 |<---------------|
| 180 Ringing F8 |<---------------| 200 OK F9 |
|<---------------| 200 OK F10 |<---------------|
| 200 OK F11 |<---------------| |
|<---------------| | |
| ACK F12 |
|------------------------------------------------->|
| Media Session |
|<================================================>|
| BYE F13 |
|<-------------------------------------------------|
| 200 OK F14 |
|------------------------------------------------->|
| |
Figure 1: SIP session setup example with SIP trapezoid
Dans l’exemple du
RFC3261, il y deux proxys intermédiaires. Les messages de signalisation SIP
pendant l’établissement de l’appel sont échangés entre les téléphones SIP via
les deux proxys intermédiaires. Les messages d’établissement d’appel sont INVITE,
100 (Trying), 180 (Ringing), et 200 (OK). L’échange de ces quatre messages
constitue une transaction SIP. Il
s’agit d’un court échange de messages SIP. Dans le contexte d’une transaction,
les messages SIP utilisent le même chemin, donc si le message INVITE initial de
cet exemple passe par deux proxys intermédiaires, tous les autres messages de
la transaction vont aussi passer par les deux mêmes proxys [rfc3261, p.13-14]. Dans une même transaction, le chemin est
conservé en utilisant une pile de champs "Via" ajoutés à l’en-tête
des messages SIP [rfc3261, p.12].
De plus, dans le même
exemple, on peut voir que d’une fois l’établissement de l’appel (initiée par un
message INVITE) accomplie, les messages de signalisation suivants sont échangés
directement entre les téléphones SIP. Le message ACK (informant du début de la
session média) est transmis directement de l’appareil appelant à l’appareil
appelé. La transaction de déconnexion, comprenant la requête BYE, est aussi
acheminée directement sans passer par les deux serveurs proxy.
Dans ce document, nous
analysons les transactions SIP en utilisant un modèle plus simple, comprenant
un seul proxy intermédiaire.
Le chemin des paquets média
n’est pas décrit dans ce document. Dans tous les exemples discutés, le flux
média est transmis directement entre les deux téléphones, que la signalisation
passe au travers d’un serveur proxy ou non.
Les messages SIP sont des
lignes de texte. On peut les imprimer. Un message SIP est habituellement
transporté dans un paquet UDP. On peut répéter une courte expérience
transmettant des messages texte dans des paquets UDP [htm]. Le protocole SIP est basé sur un modèle de
transactions requête/réponse, ressemblant à du HTTP. Chaque transaction
consiste en une requête et au moins une réponse. L’exemple du message INVITE,
correspondant à la première figure du RFC3261 est illustré ci-dessous [rfc3261, p.10-11].
INVITE sip:bob@biloxi.com SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds
Max-Forwards: 70
To: Bob <sip:bob@biloxi.com>
From: Alice <sip:alice@atlanta.com>;tag=1928301774
Call-ID: a84b4c76e66710@pc33.atlanta.com
CSeq: 314159 INVITE
Contact: <sip:alice@pc33.atlanta.com>
Content-Type: application/sdp
Content-Length: 142
(
La première ligne du
message contient le nom de la méthode (INVITE) Les lignes suivantes sont une
liste d’en-têtes [rfc3261, p.10-11]. Beaucoup de messages SIP sont limités par la
première ligne et les en-têtes la suivant. Dans l’exemple, le message contient
aussi un corps (qui n’est pas illustré). Le corps est transmis par un message
SIP, similairement à un document attaché à un email, ou une page web transmise
dans un message HTTP [rfc3261,
p.12-13].
Le corps du message
INVITE contient les détails de la session, comme les informations sur le codec,
l’adresse IP du serveur de média ou les ports utilisés par les appareils. Ces
informations n’utilisent pas le format SIP. Le corps de l’INVITE utilise un
autre protocole, à savoir le Session Description Protocol (SDP), décrit dans
RFC 2327 [txt], [htm].
Notre configuration de test utilise deux
appareils SIP Grandstream Budge Tone-100. Ils sont configurés en IP statique : 192.168.10 et 192.168.1.11, pour plus
de clarté dans les explications (une configuration IP dynamique, au moyen d’un
serveur DHCP, fonctionnerait aussi). Les deux appareils sont connectés au même
serveur SIP, à l’adresse 192.168.1.15.
Le téléphone SIP à l’IP 192.168.1.10
utilise le numéro de téléphone 308 :
[htm]
Le téléphone SIP à l’IP 192.168.1.11
utilise le numéro de téléphone 309 :
[htm]
Nous utilisons un proxy OpenSER à l’adresse IP
192.168.1.15. C’est une déclinaison de SIP Express Router (SER). La configuration
de SER s’effectue dans un unique fichier texte. Dans sa configuration basique, SER
gère les requêtes d’enregistrement (sans authentification) et permet les appels
entre téléphones SIP. Le fichier de configuration fait typiquement 100-200
lignes [ser.cfg], [openser.cfg], et consiste en un script avec uns syntaxe
proche du C. Le fichier de configuration définit les opérations à effectuer à
la réception des requêtes SIP individuelles. Les réponses peuvent aussi
utiliser un fonctionnement "avec mémoire" (voir sections 2.7 et 3). Les scripts de SER et OpenSER sont quasiment compatibles. Avec de
petites modifications, un fichier de configuration de SER peut être utilisé
dans OpenSER et vice-versa.
Pour mieux visualiser les
échanges SIP, le serveur OpenSER est lance en mode debug depuis un terminal. A
la réception d’une requête SIP, son contenu entier est affiché, et nous
attendons toutes les réponses à ce message [cfg]. Le traitement appliqué au paquet SIP est celui
du script de configuration par défaut. Les détails du fichier de configuration
sortent du cadre de ce document. Le langage utilisé dans le script est décrit dans
“SER Getting Started”.
Le tampon de messages est
affiché en entier par la commande suivante :
xlog("L_INFO","\n\n$Cbg[ Method $rm from $si ]$Cxx\n$mb$Cbg[ End of Request ]$Cxx\n");
Ici, $mb représente la
totalité du tampon du message SIP, incluant le corps du message (en
attachement). Le corps seul d’une requête ou réponse peut être affiché avec la
pseudo variable $rb. La méthode d’affichage xlog est définie dans le module
xlog.so [xlog ser], [xlog openser], [readme] (la seule différence d’usage de xlog dans SER et
OpenSER est que l’un utilise le symbole ‘%’ pour indiquer les pseudo variables,
alors que l’autre utilise ‘$’). La variable $si représente l’adresse IP de
l’expéditeur du message, et la variable $rm la méthode de requête.
Les réponses aux requêtes
SIP peuvent aussi être traitées par le script SER. Dans la méthode principale
de routage, on doit spécifier quelle fonction traite les réponses :
t_on_reply("1");
On doit aussi fournir le
corps de la méthode qui traite les réponses :
onreply_route[1]
{
xlog("L_INFO","\n\n$Cbc[ Reply $rs ($rr) from $si concerning $rm ]$Cxx\n$mb$Cbc[ End of Reply ]$Cxx\n");
}
Les réponses seront
traitées uniquement si les requêtes ont été précédemment relayées avec une
fonction à mémoire :
route[1]
{
if(!t_relay())
sl_reply_error();
xlog("L_INFO","$CbxMessage is relayed; now exiting$Cxx\n");
exit;
}
Dans le corps de
onreply_route[1], on affiche le contenu du message de réponse ($mb), le statut
de la réponse ($rs), la raison de la réponse ($rr), l’adresse IP de
l’expéditeur ($si) et la méthode de requête initiale associée à laquelle la
réponse est associée ($rr). Cette association est possible grâce au traitement
"à mémoire" des transactions par SER. Les réponses SIP sont corrélées
aux requêtes initiales grâce aux paramètres d’identification fournis par les
champs Via présents dans les en-têtes des messages SIP [rfc3261, p.13].
Dans cet exemple un appel
est effectué du téléphone SIP 308 (à l’adresse IP 192.168.1.10) au téléphone
SIP 309 (à l’adresse IP 192.168.1.11). Ici le téléphone SIP destinataire (309)
répond et l’appel est établi. Le serveur OpenSER – qui joue le rôle de proxy
pour les deux téléphones – logue à l’écran les messages reçus (selon le fichier
de configuration décrit précédemment [cfg]). En dessous se trouve la sortie du serveur pour
notre appel de 308 à 309. Le message encadré par les barres vertes représente
la requête INVITE ; les massages encadrés par les barres bleues sont les
réponses. La requête INVITE est envoyée depuis le téléphone à l’adresse 192.168.1.10.
On voit ensuite la réponse 100 (Trying) envoyée par le destinataire
192.168.1.11. Cette réponse est immédiatement suivie de 180 (Ringing),
également envoyée par le destinataire. Quand l’appelant reçoit en retour 180
(Ringing), il génère la tonalité de sonnerie pour l’utilisateur. Le décrochage
de l’appareil appelé est confirmé par la réponse 200 (OK) envoyée par le
destinataire. Ces trois messages constituent une transaction SIP, qui contient une requête INVITE avec ses trois
réponses 100 (Trying) [rfc3261,
p.13], 180 (Ringing), et
200 (OK).
[ Method INVITE from 192.168.1.10 ]
INVITE sip:309@192.168.1.15 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bK533110eb792e9593
From: <sip:308@192.168.1.15>;tag=839d16b92cebf0ae
To: <sip:309@192.168.1.15>
Contact: <sip:308@192.168.1.10>
Supported: replaces
Call-ID: 278956deb55db668@192.168.1.10
CSeq: 23290 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Type: application/sdp
Content-Length: 225
v=0
o=308 8000 8000 IN IP4 192.168.1.10
s=SIP Call
c=IN IP4 192.168.1.10
t=0 0
m=audio 5004 RTP/AVP 4 18 97
a=sendrecv
a=rtpmap:4 G723/8000
a=rtpmap:18 G729/8000
a=rtpmap:97 iLBC/8000
a=fmtp:97 mode=20
a=ptime:60
[ End of Request ]
[ Reply 100 (Trying) from 192.168.1.11 concerning INVITE ]
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bK4599.12d426e3.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bK533110eb792e9593
From: <sip:308@192.168.1.15>;tag=839d16b92cebf0ae
To: <sip:309@192.168.1.15>
Call-ID: 278956deb55db668@192.168.1.10
CSeq: 23290 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Content-Length: 0
[ End of Reply ]
[ Reply 180 (Ringing) from 192.168.1.11 concerning INVITE ]
SIP/2.0 180 Ringing
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bK4599.12d426e3.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bK533110eb792e9593
From: <sip:308@192.168.1.15>;tag=839d16b92cebf0ae
To: <sip:309@192.168.1.15>;tag=e821cb882a12d201
Call-ID: 278956deb55db668@192.168.1.10
CSeq: 23290 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Content-Length: 0
[ End of Reply ]
[ Reply 200 (OK) from 192.168.1.11 concerning INVITE ]
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bK4599.12d426e3.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bK533110eb792e9593
From: <sip:308@192.168.1.15>;tag=839d16b92cebf0ae
To: <sip:309@192.168.1.15>;tag=e821cb882a12d201
Call-ID: 278956deb55db668@192.168.1.10
CSeq: 23290 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Contact: <sip:309@192.168.1.11>
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Type: application/sdp
Supported: replaces
Content-Length: 154
v=0
o=309 8000 8000 IN IP4 192.168.1.11
s=SIP Call
c=IN IP4 192.168.1.11
t=0 0
m=audio 5004 RTP/AVP 4
a=sendrecv
a=rtpmap:4 G723/8000
a=ptime:60
[ End of Reply ]
Tous les messages de la
transaction sont transmis via le serveur proxy, et donc nous pouvons tous les
voir. Dans le contexte d’une transaction SIP, les messages suivent toujours le
même chemin. Le champ Via du header
SIP est responsable de l’identification des transactions et de conserver le
chemin des messages appartenant à la même transaction. La transaction est
identifiée par un paramètre branch
incorporé au champ Via [rfc3261, p.12]. Les réponses sont liées aux requêtes grâce au
champ branch [rfc3261, p.13]. Dans la sortie suivante, les paramètres branch
sont en gras. On peut voir qu’ils sont identiques pour les trois messages.
Le chemin des messages
est conservé grâce à la pile de champs Via ajoutés par les proxys
intermédiaires à l’en-tête des requêtes, lorsqu’elles traversent la chaîne de
proxys (un seul est présent dans notre exemple). Le téléphone SIP s’assure que
la réponse à une requête SIP contient la même pile de champs Via. Quand les
réponses sont renvoyées, chaque proxy intermédiaire enlève son adresse du
sommet de la pile et utilise le champ Via suivant pour déterminer ou envoyer la
réponse. Ainsi, chaque proxy qui voit une requête verra aussi toutes les
réponses associées à cette requête [rfc3261, p.13-14].
La transaction illustrée
plus haut initie un appel téléphonique. Plusieurs autres transactions peuvent
arriver pendant et à la fin de la conversation. Même si (comme expliqué) dans
le cadre d’une transaction tous les messages SIP suivent le même chemin, les
autres transactions liées au même appel ne vont pas nécessairement suivre le
même chemin que celle qui initie l’appel. Au lieu de passer par les proxys
intermédiaires, les transactions suivantes sont souvent directement transmises
entre les deux téléphones SIP (voir le premier exemple de RFC3261 [rfc3261, p.15]). Cela arrive car pendant la première
transaction INVITE/200 (OK), les nœuds finaux apprennent leurs adresses
respectives depuis les champs Contact des en-têtes [rfc3261,
p.12].
L’exemple de cette
section correspond aussi à un scénario similaire au premier exemple de RFC3261
[rfc3261, p.10-11]. Dès que 100 (OK) est transmis pour le premier
INVITE (c-à-d que l’appel est établi), plus aucun message de signalisation ne
passe par le proxy [rfc3261, p.15]. Toutes
les transactions SIP suivantes passent directement entre les téléphones SIP,
contournant le proxy. Ainsi on ne voit plus les autres messages de l’appel (qui
contiennent au moins ACK, BYE et la réponse 200 (OK) du BYE).
Dans la requête INVITE et
la réponse 200 (OK) de la sortie imprimée, on voit aussi le corps des messages
SDP attachés [rfc3261, p.12-13]. Par l’échange de ces messages SDP, les téléphones
SIP négocient les paramètres de la future session média. En particulier, chaque
appareil informe l’autre sur les adresses et ports disponibles pour le flux de
média (ici 192.168.1.10:5004 et 192.168.1.11:5004) et négocient le codec G723
pour le média.
L’appelant peut raccrocher avant que
l’appelé ne réponde. Cela ajoute des
messages supplémentaires dans la transaction d’établissement de l’appel. La
sortie suivante correspond à ce scénario. D’abord le téléphone 308 (à l’IP
192.168.1.10) compose le numéro 309, et raccroche sans attendre la réponse de
309.
[ Method INVITE from 192.168.1.10 ]
INVITE sip:309@192.168.1.15 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKdfda7b9079412bd5
From: <sip:308@192.168.1.15>;tag=8b2723dc35649705
To: <sip:309@192.168.1.15>
Contact: <sip:308@192.168.1.10>
Supported: replaces
Call-ID: 64f567bcc5d8f80c@192.168.1.10
CSeq: 14107 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Type: application/sdp
Content-Length: 225
v=0
o=308 8000 8000 IN IP4 192.168.1.10
s=SIP Call
c=IN IP4 192.168.1.10
t=0 0
m=audio 5004 RTP/AVP 4 18 97
a=sendrecv
a=rtpmap:4 G723/8000
a=rtpmap:18 G729/8000
a=rtpmap:97 iLBC/8000
a=fmtp:97 mode=20
a=ptime:60
[ End of Request ]
[ Reply 100 (Trying) from 192.168.1.11 concerning INVITE ]
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bK5647.03eb25b7.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKdfda7b9079412bd5
From: <sip:308@192.168.1.15>;tag=8b2723dc35649705
To: <sip:309@192.168.1.15>
Call-ID: 64f567bcc5d8f80c@192.168.1.10
CSeq: 14107 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Content-Length: 0
[ End of Reply ]
[ Reply 180 (Ringing) from 192.168.1.11 concerning INVITE ]
SIP/2.0 180 Ringing
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bK5647.03eb25b7.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKdfda7b9079412bd5
From: <sip:308@192.168.1.15>;tag=8b2723dc35649705
To: <sip:309@192.168.1.15>;tag=76adf65f887d5f3f
Call-ID: 64f567bcc5d8f80c@192.168.1.10
CSeq: 14107 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Content-Length: 0
[ End of Reply ]
[ Method CANCEL from 192.168.1.10 ]
CANCEL sip:309@192.168.1.15 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKdfda7b9079412bd5
From: <sip:308@192.168.1.15>;tag=8b2723dc35649705
To: <sip:309@192.168.1.15>
Supported: replaces
Call-ID: 64f567bcc5d8f80c@192.168.1.10
CSeq: 14107 CANCEL
User-Agent: Grandstream BT110 1.0.8.33
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Length: 0
[ End of Request ]
[ Reply 200 (OK) from 192.168.1.11 concerning CANCEL ]
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bK5647.03eb25b7.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKdfda7b9079412bd5
From: <sip:308@192.168.1.15>;tag=8b2723dc35649705
To: <sip:309@192.168.1.15>;tag=76adf65f887d5f3f
Call-ID: 64f567bcc5d8f80c@192.168.1.10
CSeq: 14107 CANCEL
User-Agent: Grandstream BT110 1.0.8.33
Contact: <sip:309@192.168.1.11>
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Supported: replaces
Content-Length: 0
[ End of Reply ]
0(22535)
[ Reply 487 (Request Cancelled) from 192.168.1.11 concerning INVITE ]
SIP/2.0 487 Request Cancelled
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bK5647.03eb25b7.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKdfda7b9079412bd5
From: <sip:308@192.168.1.15>;tag=8b2723dc35649705
To: <sip:309@192.168.1.15>;tag=76adf65f887d5f3f
Call-ID: 64f567bcc5d8f80c@192.168.1.10
CSeq: 14107 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Content-Length: 0
[ End of Reply ]
0(22535)
[ Method ACK from 192.168.1.10 ]
ACK sip:309@192.168.1.15 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKdfda7b9079412bd5
From: <sip:308@192.168.1.15>;tag=8b2723dc35649705
To: <sip:309@192.168.1.15>;tag=76adf65f887d5f3f
Contact: <sip:308@192.168.1.10>
Call-ID: 64f567bcc5d8f80c@192.168.1.10
CSeq: 14107 ACK
User-Agent: Grandstream BT110 1.0.8.33
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Length: 0
[ End of Request ]
Les sept messages
correspondent à la même transaction, Cette transaction essaie d’établir
l’appel, mais ensuite annule la tentative. Voici le diagramme des messages
échangés :
Les en-têtes affichés
dans la sortie contiennent deux paramètres branch. Le premier (branch=z9hG4bKdfda7b9079412bd5)
se trouve dans le champ Via ajouté par le téléphone SIP appelé 192.168.1.10. Le
second (branch=z9hG4bK5647.03eb25b7.0) se trouve dans le champ Via ajouté par
le proxy SIP. La transaction peut être identifiée par n’importe lequel de ces
deux paramètres branch. Notons que dans ce scénario – où l’appel est annulé avant
d’être établi – le message ACK est transmis dans le cadre de la même
transaction (il a le même paramètre branch), alors que dans le cas où l’appel
est répondu (voir la sortie de la section 2.5), le message ACK est envoyé avec un paramètre branch différent et
n’appartient donc pas à la transaction de la requête INVITE.
Quand le proxy SIP
192.168.1.15 reçoit une requête INVITE et voit "branch=z9hG4bKdfda7b9079412bd5"
pour la première fois (le paramètre branch étant ajouté par le téléphone SIP
appelant 192.168.1.10), le proxy crée un numéro de transaction interne z9hG4bK5647.03eb25b7.0
associé à tous les messages attendus suivants de la transaction. Le numéro de
transaction interne crée par le proxy et le paramètre branch sont synonymes et
identifient la même transaction. Quand le proxy SIP reçoit de nouvelles
requêtes provenant de 192.168.1.10 avec le même paramètre branch (fourni par le
téléphone appelant), le proxy peut identifier la transaction sortante et va
associer la transaction interne déjà crée avec ces messages. De plus, le proxy
ajoute son numéro de transaction interne dans le champ Via ajouté aux en-têtes
de messages.
La sortie de cet exemple
montre le contenu des messages SIP à leur arrivée, avant que le champ Via ne
soit inclus dans les requêtes. Les réponses SIP sont transférées en retour du
téléphone SIP 192.168.1.11 au proxy 192.168.1.15, et elles contiennent les
en-têtes Via tu téléphone appelant et du proxy lui-même (insérés dans la
requête SIP pendant son transfert vers le téléphone appelant). Le proxy à
mémoire associe le message de réponse à la transaction en cours en utilisant
soit son propre paramètre branch ou celui du téléphone appelant. Par exemple,
il est possible d’accéder à la méthode de requête (par la pseudo variable $rm)
pendant le traitement des messages de réponse, grâce à l’association entre la
réponse et la transaction correspondante. Avant de relayer la réponse au
téléphone source, le proxy enlève son propre champ Via de l’en-tête de la réponse
[rfc3261, p.13-14]. La sortie affichée montre les messages de
réponse à leur arrivée sur le proxy, donc le champ Via du header n’est pas
encore enlevé.
Le téléphone d’origine
apprend l’information de contact direct vers le téléphone SIP de destination
depuis l’en-tête Contact de la réponse 200 (OK) au message CANCEL (en gras dans
la sortie). Toutefois, le message ACK n’est pas envoyé directement. Le ACK
contient le même numéro de branche, et est donc dans le contexte de la même
transaction. Ainsi, le ACK suit le même chemin via le serveur proxy.
Comme la tentative
d’appel est annulée, dans la transaction présentée seul le message INVITE
contient un attachement SDP. Il n’y a pas besoin d’attachement SDP dans la
réponse 487 (Request Cancelled).
En utilisant les fonctions
sans mémoire de SER, le proxy transmet simplement les messages sans garder en
mémoire les informations de transaction. Pour du forwarding sans mémoire, on
utilise la méthode forward() (t_relay() pour un forwarding avec mémoire) :
route[1]
{
if(!forward())
sl_reply_error();
xlog("L_INFO","$CbxMessage is relayed; now exiting$Cxx\n");
exit;
}
Avec le traitement sans
mémoire, les messages sont traités sans contexte et les réponses ne peuvent
être associées aux requêtes [SER
Getting Started, p.9].
Cela signifie qu’avant de relayer une requête SIP, le proxy ne stocke pas en
mémoire les paramètres de branch de la requête SIP pour traiter les réponses
correspondantes.
Toujours avec les methodes
stateless[cfg], pendant l’essai d’appel annulé, seuls les
messages INVITE et CANCEL seront vus et logués par le script SER (voir la
sortie ci-dessous). Tous les autres messages associés à la transaction ne
seront pas traités :
[ Method INVITE from 192.168.1.10 ]
INVITE sip:309@192.168.1.15 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKef1e1f8da5c0298d
From: <sip:308@192.168.1.15>;tag=0434481ac70e589b
To: <sip:309@192.168.1.15>
Contact: <sip:308@192.168.1.10>
Supported: replaces
Call-ID: f146448b7830985b@192.168.1.10
CSeq: 24573 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Type: application/sdp
Content-Length: 225
v=0
o=308 8000 8000 IN IP4 192.168.1.10
s=SIP Call
c=IN IP4 192.168.1.10
t=0 0
m=audio 5004 RTP/AVP 4 18 97
a=sendrecv
a=rtpmap:4 G723/8000
a=rtpmap:18 G729/8000
a=rtpmap:97 iLBC/8000
a=fmtp:97 mode=20
a=ptime:60
[ End of Request ]
[ Method CANCEL from 192.168.1.10 ]
CANCEL sip:309@192.168.1.15 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKef1e1f8da5c0298d
From: <sip:308@192.168.1.15>;tag=0434481ac70e589b
To: <sip:309@192.168.1.15>
Supported: replaces
Call-ID: f146448b7830985b@192.168.1.10
CSeq: 24573 CANCEL
User-Agent: Grandstream BT110 1.0.8.33
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Length: 0
[ End of Request ]
Dans la section 2.5, nous avons vu l’établissement d’un appel entre deux téléphones SIP. Dans
l’exemple correspondant, le proxy SIP participe à l’établissement de l’appel
mais ne voit aucun des messages SIP après cette transaction. Les en-têtes SIP
donnent aux proxys intermédiaires la possibilité de rester dans le chemin de la
signalisation pour la suite de l’appel. Les messages de signalisation entre les
destinataires finaux peuvent être entendus durant toute la durée de la session
SIP. Si le proxy veut rester dans le chemin des messages SIP après la
transaction d’établissement de l’appel (i.e. l’INVITE et les messages
associés), il devrait ajouter à l’INVITE un en-tête de routage, appelé Record-Route, qui contient le nom
d’hôte ou l’adresse IP du proxy. Cette information est reçue par les téléphones
SIP appelé et appelant grâce au header Record-Route, qui est transmis dans les
réponses 180 (Ringing) et 200 (OK). Ils sont indiqués en gras dans l’exemple de
sortie suivant. L’information Record-Route est stockée pour toute la durée du
dialogue. Le serveur proxy va ensuite recevoir aussi les messages ACK et BYE /
200 (OK). Chaque proxy peut décider indépendamment de recevoir les messages
suivants, et ces messages vont passer par tous les proxys qui demandent à les
recevoir [rfc3261, p.16].
Le champ Record-Route est
ajouté au message par les lignes suivantes du fichier de configuration [cfg] :
if(method!="REGISTER") {
xlog("L_INFO","$CbxAdding the Route header$Cxx\n");
record_route();
}
if(loose_route()) {
xlog("L_INFO","$
route(1);
}
La sortie ci-dessous
montre que notre proxy a bien reçu tous les messages de signalisation, de
l’établissement de l’appel à le fin de la communication.
Quand un téléphone SIP
reçoit la pile de headers Record-Route
(ajoutés par chaque proxy intermédiaire désirant rester dans le dialogue), il
copie cette pile dans une nouvelle pile de champs Route. Ces champs Route indiquent le chemin à suivre pour les
messages sortants envoyés par le téléphone. L’appareil va ajouter les en-têtes
Route à toutes les requêtes transmises dans le cadre de la session SIP courante
(les champs Route sont indiqués en gras dans la sortie suivante).
Quand le téléphone appelé
reçoit une requête avec une pile de headers Record-Route, il copie les mêmes
champs Record-Route dans le message de réponse. Ainsi, le téléphone SIP
appelant va aussi recevoir cette pile de champs Record-Route. Le téléphone
appelant crée aussi une pile de headers Route, mais cette pile est inversée
(comme la séquence de proxys va être traversée dans l’ordre inverse).
Le serveur SER ne
mémorise pas l’état du dialogue SIP (il ne voit pas les appels sortants). C’est
au téléphone SIP de s’assurer que dans le carde d’un appel, la pile de headers
Route soit ajoutée dans chaque message transmis (assurant ainsi que les
serveurs SIP intermédiaires reçoivent bien tous les messages se rapportant à
l’appel en cours).
[ Method INVITE from 192.168.1.10 ]
INVITE sip:309@192.168.1.15 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKf3c60221ce03445c
From: <sip:308@192.168.1.15>;tag=fce371520693b722
To: <sip:309@192.168.1.15>
Contact: <sip:308@192.168.1.10>
Supported: replaces
Call-ID: 8c80d06175b1eb80@192.168.1.10
CSeq: 28826 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Type: application/sdp
Content-Length: 225
v=0
o=308 8000 8000 IN IP4 192.168.1.10
s=SIP Call
c=IN IP4 192.168.1.10
t=0 0
m=audio 5004 RTP/AVP 4 18 97
a=sendrecv
a=rtpmap:4 G723/8000
a=rtpmap:18 G729/8000
a=rtpmap:97 iLBC/8000
a=fmtp:97 mode=20
a=ptime:60
{end}
[ End of Request ]
[ Reply 100 (Trying) from 192.168.1.11 concerning INVITE ]
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bKb992.ec6bce33.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKf3c60221ce03445c
From: <sip:308@192.168.1.15>;tag=fce371520693b722
To: <sip:309@192.168.1.15>
Call-ID: 8c80d06175b1eb80@192.168.1.10
CSeq: 28826 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Content-Length: 0
[ End of Reply ]
[ Reply 180 (Ringing) from 192.168.1.11 concerning INVITE ]
SIP/2.0 180 Ringing
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bKb992.ec6bce33.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKf3c60221ce03445c
Record-Route: <sip:192.168.1.15;lr=on;ftag=fce371520693b722>
From: <sip:308@192.168.1.15>;tag=fce371520693b722
To: <sip:309@192.168.1.15>;tag=352ec99f5ffd23cf
Call-ID: 8c80d06175b1eb80@192.168.1.10
CSeq: 28826 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Content-Length: 0
[ End of Reply ]
[ Reply 200 (OK) from 192.168.1.11 concerning INVITE ]
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bKb992.ec6bce33.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bKf3c60221ce03445c
Record-Route: <sip:192.168.1.15;lr=on;ftag=fce371520693b722>
From: <sip:308@192.168.1.15>;tag=fce371520693b722
To: <sip:309@192.168.1.15>;tag=352ec99f5ffd23cf
Call-ID: 8c80d06175b1eb80@192.168.1.10
CSeq: 28826 INVITE
User-Agent: Grandstream BT110 1.0.8.33
Contact: <sip:309@192.168.1.11>
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Type: application/sdp
Supported: replaces
Content-Length: 154
v=0
o=309 8000 8000 IN IP4 192.168.1.11
s=SIP Call
c=IN IP4 192.168.1.11
t=0 0
m=audio 5004 RTP/AVP 4
a=sendrecv
a=rtpmap:4 G723/8000
a=ptime:60
{end}
[ End of Reply ]
[ Method ACK from 192.168.1.10 ]
ACK sip:309@192.168.1.11 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bK9678e44f4ea235df
Route: <sip:192.168.1.15;lr=on;ftag=fce371520693b722>
From: <sip:308@192.168.1.15>;tag=fce371520693b722
To: <sip:309@192.168.1.15>;tag=352ec99f5ffd23cf
Contact: <sip:308@192.168.1.10>
Call-ID: 8c80d06175b1eb80@192.168.1.10
CSeq: 28826 ACK
User-Agent: Grandstream BT110 1.0.8.33
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Length: 0
[ End of Request ]
[ Method INFO from 192.168.1.10 ]
INFO sip:309@192.168.1.11 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bK93bc61c18d96eb8b
Route: <sip:192.168.1.15;lr=on;ftag=fce371520693b722>
From: <sip:308@192.168.1.15>;tag=fce371520693b722
To: <sip:309@192.168.1.15>;tag=352ec99f5ffd23cf
Contact: <sip:308@192.168.1.10>
Supported: replaces
Call-ID: 8c80d06175b1eb80@192.168.1.10
CSeq: 28827 INFO
User-Agent: Grandstream BT110 1.0.8.33
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Type: application/dtmf-relay
Content-Length: 23
Signal=2
Duration=4800{end}
[ End of Request ]
[ Reply 200 (OK) from 192.168.1.11 concerning INFO ]
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bKc992.e100efc6.0
Via: SIP/2.0/UDP 192.168.1.10;branch=z9hG4bK93bc61c18d96eb8b
Record-Route: <sip:192.168.1.15;lr=on;ftag=fce371520693b722>
From: <sip:308@192.168.1.15>;tag=fce371520693b722
To: <sip:309@192.168.1.15>;tag=352ec99f5ffd23cf
Call-ID: 8c80d06175b1eb80@192.168.1.10
CSeq: 28827 INFO
User-Agent: Grandstream BT110 1.0.8.33
Contact: <sip:309@192.168.1.11>
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Supported: replaces
Content-Length: 0
[ End of Reply ]
[ Method INFO from 192.168.1.11 ]
INFO sip:308@192.168.1.10 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.11;branch=z9hG4bKd51a30c261b5691e
Route: <sip:192.168.1.15;lr=on;ftag=fce371520693b722>
From: <sip:309@192.168.1.15>;tag=352ec99f5ffd23cf
To: <sip:308@192.168.1.15>;tag=fce371520693b722
Contact: <sip:309@192.168.1.11>
Supported: replaces
Call-ID: 8c80d06175b1eb80@192.168.1.10
CSeq: 52519 INFO
User-Agent: Grandstream BT110 1.0.8.33
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Type: application/dtmf-relay
Content-Length: 22
Signal=3
Duration=480{end}
[ End of Request ]
[ Reply 200 (OK) from 192.168.1.10 concerning INFO ]
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bKb593.5d620aa5.0
Via: SIP/2.0/UDP 192.168.1.11;branch=z9hG4bKd51a30c261b5691e
Record-Route: <sip:192.168.1.15;lr=on;ftag=352ec99f5ffd23cf>
From: <sip:309@192.168.1.15>;tag=352ec99f5ffd23cf
To: <sip:308@192.168.1.15>;tag=fce371520693b722
Call-ID: 8c80d06175b1eb80@192.168.1.10
CSeq: 52519 INFO
User-Agent: Grandstream BT110 1.0.8.33
Contact: <sip:308@192.168.1.10>
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Supported: replaces
Content-Length: 0
[ End of Reply ]
[ Method BYE from 192.168.1.11 ]
BYE sip:308@192.168.1.10 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.11;branch=z9hG4bKd0b04fbb081eb9ab
Route: <sip:192.168.1.15;lr=on;ftag=352ec99f5ffd23cf>
From: <sip:309@192.168.1.15>;tag=352ec99f5ffd23cf
To: <sip:308@192.168.1.15>;tag=fce371520693b722
Supported: replaces
Call-ID: 8c80d06175b1eb80@192.168.1.10
CSeq: 52520 BYE
User-Agent: Grandstream BT110 1.0.8.33
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Content-Length: 0
[ End of Request ]
[ Reply 200 (OK) from 192.168.1.10 concerning BYE ]
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.1.15;branch=z9hG4bK0593.583e3506.0
Via: SIP/2.0/UDP 192.168.1.11;branch=z9hG4bKd0b04fbb081eb9ab
Record-Route: <sip:192.168.1.15;lr=on;ftag=352ec99f5ffd23cf>
From: <sip:309@192.168.1.15>;tag=352ec99f5ffd23cf
To: <sip:308@192.168.1.15>;tag=fce371520693b722
Call-ID: 8c80d06175b1eb80@192.168.1.10
CSeq: 52520 BYE
User-Agent: Grandstream BT110 1.0.8.33
Contact: <sip:308@192.168.1.10>
Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE
Supported: replaces
Content-Length: 0
[ End of Reply ]
Même si le serveur SIP
n’identifie pas les conversations téléphoniques, il peut enregistrer chaque
message reçu dans une base de données. Une application externe peut donc réunir
les messages faisant partie d’une même conversation. Une conversation peut être
identifiée par le tag du téléphone appelant (tag=fce371520693b722) [rfc3261, p.12], celui
du téléphone appelé (tag=352ec99f5ffd23cf) [rfc3261,
p.14-15], et par le champ
Call-Id (8c80d06175b1eb80@192.168.1.10). Ces tags ainsi que le champ Call-Id
sont générés par les téléphones SIP en bout de chaîne, et sont gardés constants
durant la conversation téléphonique. Les tags sont des chaînes de caractères
aléatoires, et le Call-Id est généré en combinant une chaîne aléatoire et
l’adresse IP (ou nom d’hôte) de l’appareil appelant. La combinaison des tags To
et From, et du champ Call-Id identifie une relation de pair à pair entre deux
téléphones SIP, et est appelée dialogue
[rfc3261, p.12].
Comme un appel
téléphonique (p. ex. un dialogue SIP) consiste en plusieurs transactions, et
étant donné que SER ne conserve pas d’informations sur les transactions au
cours du même appel, SER ne peut pas savoir si l’appel est entrant ou sortant, ni
connaître la durée d’un appel (en cours ou terminé) ou le terminer. Toutefois,
SER peut loguer les messages à la réception (INVITE, ACK et BYE sont stockés
avec le Call-Id correspondant). Une application de facturation peut donc réunir
les messages INVITE et BYE, et ainsi calculer la durée de l’appel [SER Getting Started, p.9].
Le dialogue affiché en
exemple peut être illustré par le diagramme suivant :
Pendant la conversation,
on voit deux transactions comportant un message INFO. Elles correspondent à la
transmission de signaux DTMF via les messages SIP. La première indique que la
touche "2" a été pressée sur le téléphone appelant pendant 4800
millisecondes. Pour s’assurer que les messages SIP INFO soient transmis, on
doit spécifier dans la configuration que les informations DTMF doivent être
transmises dans le messages SIP :
[bmp]
D’après l’affichage de
sortie, on peut conclure que l’appel a été établi avec succès, comme le message
ACK (branch=z9hG4bK9678e44f4ea235df ) n’appartient plus à la transaction du
message INVITE (branch=z9hG4bKf3c60221ce03445c). C’est la raison pour laquelle
dans la section 2.5 – sans utiliser les champs Record-Route – le message ACK ne passait pas
par le serveur proxy.
Il est important de
rappeler que le header Record-Route ne donne d’informations qu’aux téléphones
SIP en bout de chaîne, pour ajouter les champs Route aux requêtes durant toute
la durée de l’appel. Ainsi, ce sont les téléphones (destinataires finaux) qui
sont chargés de vérifier que les champs Route soient ajoutés à tous les
messages associés à l’appel en cours. Ils sont donc au courant de l’appel en
cours, ce qui n’est pas le cas du proxy.
Paramètres STUN des appareils SIP
Créer
et envoyer des messages SIP INVITE et CANCEL
Appels
directs entre deux téléphones SIP sans passer par un proxy SIP
Comprendre
les échanges SIP par l’expérimenation
Ce document [htm], [pdf], [doc], la page web entière [zip]
FQDN Fully Qualified Domain Name
SDP Session Description Protocol
HTTP Hyper Text Transfer Protocol
RFC Request for Comments
SIP Session Initiation Protocol
SER SIP Express Router
RTP Real-time Transport Protocol
UA User Agent
ACK Acknowledgement
DTMF Dual Tone Multi Frequency
URI Universal Resource Identifier
DHCP Dynamic Host Configuration Protocol
http://openser.org/docs/pseudo-variables-1.1.x.html, pseudo variables (openser)
http://www.iptel.org/ser/doc/modules/xlog, pseudo variables pour xlog (ser)
http://www.iptel.org/ser/doc/gettingstarted, documentation de démarrage (ser)
ftp://siprouter.onsip.org/pub/gettingstarted/configs/, fichiers de configuration simples
http://www.faqs.org/rfcs/rfc3261.html, SIP: Session Initiation Protocol
http://www.faqs.org/rfcs/rfc2327.html, SDP: Session Description Protocol
http://www.iptel.org/ser/, page web de Sip Express Router
http://www.openser.org/, page web de OpenSER
http://www.openser.org/dokuwiki/doku.php/core-cookbook:1.1.x, mots clés, valeurs et paramètres principaux de
la configuration de SER
http://www.openser.org/docs/modules/1.2.x/textops.html,
expressions régulières avec SER
http://mit.edu/sip/sip.edu/ser.shtml, quelques exemples utilisant SER
http://www.iptel.org/how_can_i_dynamically_change_the_invite_timer_fr_invite,
modifier (dynamiquement) le délai de timeout