2009年5月23日土曜日

RFC3261を読み解こう: 再送のまとめ

Timerについて前回まとめたので、今回は再送のロジックについてまとめます。再送の動作もRFC3261読んだだけでは全くイメージできませんからね。状態機械だけ見てイメージできる人がいるんでしょうか。うらやましい。

INVITEの再送動作(300~699応答の場合)

  • INVITEの再送はUDPでのみ行います。
  • INVITEを受信したUAは200ms以内に最終応答が返却できる保証がなければ100を返送しなければなりません(MUST)。普通そんな保証はないのでよほどの理由がない限り100を返送します。
  • INVITEを受信したUAはINVITEの再送を受信する度に直前の暫定応答を再送します。が、100は再送されません。なぜなら100はサーバトランザクションがProceeding状態のときに扱う暫定応答に含まれていないからです(RFC3261 17.2.1 Figure.2参照)。
  • INVITEを受信したUAはProceedingにいる間なら任意のタイミングで何度でも暫定応答を送信できます。
  • 暫定応答を受信したUAはINVITEEの再送を停止し、最終応答を待ちます。
  • 300~699の最終応答の再送はUDPでのみ行います。
  • 300~699の最終応答に対するACKは1つのINVITEトランザクションの中のものとして扱われます。
  • 300~699の最終応答を受信したUAはその度にACKを再送します。
  • ACKを受信したUAはConfirmedになり、再送されてくるACKを待ち受けて破棄します。
  • どのUAもTerminatedになったらトランザクションを直ちに解放します。
  • Terminatedになった後に受信した信号は全て新規のものとして扱います。

INVITEの再送動作(200応答の場合)

  • INVTEの最終応答が200の場合、UASは最終応答送信時に、UACは最終応答受信時にTerminatedに移行します。ただし、これだとINVITEがフォークされていた場合に後から来た応答に対応できないため、Timer LとTimer Mが新しく定義されています。がまだ正式な仕様になっていないため説明は割愛します。
  • 200は300~699と違い、UAS→UACのエンドエンドで流通するため、UASのみが生成できます(プロキシは200を生成してはいけません)。
  • 200は300~699と違い、トランザクションの外で再送されます。その再送のタイミングはTimer Gと同じなのですが、なぜか再送用のタイマや再送T.Oのタイマは定義されていません(RFC3261 13.3.1.4参照)。
  • UACのみがACKを生成でき、200を受信する度にACKを再送します。

非INVITEの動作

  • 非INVITEのサーバトランザクションもINVITEサーバトランザクションと同じような動作をしますが、非INVITEサーバトランザクションにはなぜかTryingステートがあります
  • 非INVITEサーバトランザクションはRFC3261上、暫定応答を送信してもいいことになっていますが、RFC4320(和訳)で色々な条件付きで禁止されています。この記事はRFC3261に関する説明と言うことで割愛します。
  • 非INVITEトランザクションでは200とそれ以外の応答とで動作の違いはありません。
  • 非INVITEクライアントトランザクションでは、暫定応答や最終応答を受信しても、リクエストの再送を継続します(UDPに限り)。
  • 最終応答の再送はリクエストの再送契機で行われます。だから暫定応答を受信してもリクエストの再送を止めないのです。

ゼロから学ぶSIP: 第04回 SIPメッセージの中身と通信方式

SIPはSIPメッセージと言うテキスト形式のデータをやりとりすることで、セッションを確立します。具体的に言うと、TCPやUDPの様なトランスポートプロトコルのデータ部(=ペイロード)にSIPメッセージを載せ、これを通信者同士で送受信し合うことで、必要な情報を共有していきます。

SIPメッセージはその内容によってリクエスト(要求)とレスポンス(応答)の2種類があります。リクエストはセッションを開始/変更/終了しようするときにUACから送出されるSIPメッセージです。レスポンスはUASからリクエストの成功または失敗を返却するためのSIPメッセージです。

SIPメッセージは大きく分けて以下の3つの部分で構成されています。

スタートライン
リクエストの場合はリクエストの種類(メソッド)、レスポンスの場合は成功または失敗を表すコード(ステータスコード)を記述。
ヘッダ部
SIP自身のプロトコルで必要となる情報(=発着の論理アドレス、ルーチングの為の情報等)を記述。
ボディ部
セッションを確立させる為の情報(=発着のIPアドレス/ポート番号、メディア情報等)を記述

スタートラインはリクエスト、レスポンスでそれぞれ以下の様な形式で記述します。

リクエスト
INVITE sip:bob@biloxi.com SIP/2.0
レスポンス
SIP/2.0 200 OK

ヘッダやSDPの詳細の説明はここでは割愛します(基本的すぎるので)。RFC3261に記述されているSIPメッセージの例を参考までに示しておきます。

リクエストの例(INVITE)

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

レスポンスの例

SIP/2.0 200 OK
Via: SIP/2.0/UDP server10.biloxi.com;branch=z9hG4bKnashds8;received=192.0.2.3
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds ;received=192.0.2.1
To: Bob <sip:bob@biloxi.com>;tag=a6c85cf
From: Alice <sip:alice@atlanta.com>;tag=1928301774
Call-ID: a84b4c76e66710@pc33.atlanta.com
CSeq: 314159 INVITE
Contact: <sip:bob@192.0.2.4>
Content-Type: application/sdp
Content-Length: 131

セッションを確立させるための情報はSession Description Protocol: SDPというプロトコルに従って記述するのが一般的です。SDPは現在はRFC4566で定義されています。

SIPでセッションを確立させるには、まず発信者がSIPメッセージにメディア情報を記述したリクエストを出し、着信者がその中から対応可能なメディアを選択したレスポンスを返却することで、通信に使用するメディア情報を共有します。このようにセッションを開始するためにSIPメッセージにメディア情報を載せることをオファーといい、それに対して対応可能なメディア情報を返却することをアンサーといいます。このオファーアンサーモデルについてはRFC3264で定義されています。

ボディ部にはSDPを記述しますが、SDPはオファーもしくはアンサーのときのみ必要なので、それ以外の場合はボディ部は空になります。

ここではリクエストでオファーし、レスポンスでアンサーする例をあげましたが、場合によってはレスポンスでオファーし別の何らかの方法を使ってアンサーを返却することもできます。詳しくはRFC3264を参照してください。

ボディ部にはセッションで利用されるメディア情報をSDPで記述しオファーアンサーで共有する、ということは上述しましたが、ヘッダ部に記述される情報はどのように利用されるのでしょうか。実はここからがSIPの真髄です。ルーティングやらダイアログやらターゲットやら、複雑な話がたくさん出てきます。それらについては次回以降で説明していきます。

2009年5月17日日曜日

RFC3261を読み解こう: Timerのまとめ

SIPのRFC3261にはたくさんのタイマ(Timer)が定義されていますが、本文内のあちこちに書かれていて、結局どのタイミングでどのタイマがいくつに設定されるのか、いまいちよくわかりません。本稿ではRFC3261に散りばめられたタイマについてまとめ、上記の問題を払拭します。

まずは「付録A タイマ値表(英語)」にちょっと補足したものを以下に示します。なお、これ以降RFC3261内の「信頼性のないトランスポート」を意味する箇所をUDP、「信頼性のあるトランスポート」を意味する箇所をTCPと表記することにします。また各タイマのn回目に更新された値を「An」のように表現していますが、これは本稿で便宜上定義するもので、RFC3261内に同様な記述はありません。

タイマ値表
タイマ設定値説明
T1 500ms RTTの推定値です。限定的なネットワークでない限り500ms以下は推奨されません(NOT RECOMMENDED)。一方、応答に時間がかかることが分かっている場合は500msより大きくすることが推奨されています(RECOMMENDED)。UACとUASそれぞれのT1値が異なる場合がありえますが、UAC、UAS共に相手のT1値を知ることはできません(≒知る仕組みがありません)。
T24sINVITEリクエスト以外の全ての再送処理における、最大再送間隔を表します。初期値は4sと規定されていますが、他の値にしていいのかどうかはRFC3261には規定されていません。
T4 5s 既に処理が終わったメッセージの再送を受け取るための時間です。このタイマが有効な間は該当の再送メッセージを再送として受け取り、タイマが満了すると新規レスポンスとして処理します。初期値は5sと規定されていますが、他の値にしていいのかどうかはRFC3261には規定されていません。
Timer A A0 = T1
An = An-1×2
INVITEの再送の為のタイマ。このタイマが満了するたびにINVITEを再送し、値を更新します。UDPでのみ左記の設定値が適用され、TCPでは常に0(=再送しない)となります。理屈上無限に大きくなりそうですが、Timer B(=64s×T1)が満了するとその時点でトランザクション終了となるため、実際はA5までしかないのが普通です。
Timer B 64s×T1 (UDP/TCP) INVITEクライアントトランザクションがCalling状態でいられる最大時間。満了するとトランザクション状態がTerminatedへ遷移します。いかなるトランスポートでも64s×T1となります。
Timer C Timer C > 180s プロキシがINVITEを転送するときにクライアントトランザクションに設定するタイマ。180s(3分)より大きい値でなければならず(MUST)、暫定応答を受信するたびに180sより大きい値で更新されます。満了した場合は、暫定応答をもらっていればCANCEL送出、暫定応答がなければ408応答を受信したかのように動作しなければなりません(MUST)。なお、プロキシのみに設定される値で、UACには設定しません。これは、UACは任意にCANCELでINVITEトランザクションを終了できますが、プロキシは(Timer Cがなければ)自発的にCANCELを送出する契機を持っていないからです。
Timer D > 32s (UDP)
= 0s (TCP)
INVITEトランザクションで300~699を受信したときに、ACKを返却する期間。
Timer E E0 = T1
En = min(En-1×2, T2)
非INVITEトランザクションにおいて、UACがリクエストを再送するためのタイマです。最大でT2にしかならない、という点を除いて、Timer Aと同じです。
Timer F 64s×T1 (UDP/TCP) 非INVITEトランザクションにおいて、UACが暫定応答をもらうまでのタイマです。Timer Bと同じです。
Timer G G0 = T1
Gn = min(Gn-1×2, T2)
INVITEサーバトランザクションにおいて、UASが300~699までの最終応答を再送するためのタイマです。Timer Eと同じ更新の仕方をします。
Timer H 64s×T1 (UDP/TCP) INVITEサーバトランザクションにおいて、UASが300~699までの最終応答に対するACKを受信するまでの時間です。UDP、TCPともに左記の値にします。満了した場合はTerminatedに遷移してトランザクションを破棄します。
Timer I = T4 (UDP)
= 0s (TCP)
INVITEサーバトランザクションにおいて、UASがACKの再送に備える時間です。満了する以外に消滅契機はありません。満了した場合はTerminatedに遷移してトランザクションを破棄します。
Timer J = 64s×T1 (UDP)
= 0s (TCP)
非INVITEサーバトランザクションがCompleted状態にいられる時間。Timer Hと同じ役割。
Timer K = T4 (UDP)
= 0s (TCP)
非INVITEクライアントトランザクションがCompleted状態にいられる時間。Timer Dと同じ役割。
Timer L 64s×T1 RFC3261非掲載。トランザクション状態がAcceptedのときに受理済みのINVITEの再送を受け付けるタイマ。詳しくはdraft-sparks-sip-invfixを参照。
Timer M 64s×T1 RFC3261非掲載。200の再送またはフォークされた先からの200の再送を受け付けるタイマ。詳しくはdraft-sparks-sip-invfixを参照。

2009年5月7日木曜日

ゼロから学ぶSIP: 第03回 SIPの登場人物、UAとSIPサーバ

SIPを使った通信をするときに登場する登場人物(装置)は以下の通りです。

  • 通信者(UA: User Agent)
    • 通信元(UAC: User Agent Client)
    • 通信先(UAS: User Agent Server)
  • SIPサーバ(またはプロキシサーバ)

通信をするユーザのことをUAと呼びます。電話の場合は加入者(の端末)のことです。チャットの場合はサービスに入っているメンバのことです。

UAが通信を開始しようとするとき、そのUAをUACと呼び、通信に招待されるUAをUASと呼びます。つまりUACとUASの間のセッションを成立させることがSIPの目的であると言えます。UACとUASがお互いのIPアドレス/ポート番号とメディアの情報をSIPメッセージをやり取りすることで共有できれば、目的達成ができるというわけです。なお、UACとUASは論理的な立場のようなもので、1回のトランザクション(リクエストとレスポンスのセット)が終了するとなくなります。そして次にリクエストを出すときに改めてUAC、UASが定義されます。そのため、リクエストを出す方向が逆になればUAC、UASも逆転します

しかしSIPメッセージをやり取りするためには、SIPメッセージをやり取りするためのIPアドレス/ポート番号が必要になります(ややこしい。。)。例えば電話の場合、通信先(着信先)の電話番号は知っているかもしれませんが、IPアドレスなんて知らないことが多いです。つまり、UACがUASのIPアドレスを知らなくても、電話番号やメールアドレス(チャットの場合)さえあれば相手にSIPメッセージが届く仕組みが必要になります。そこで登場するのがSIPサーバ(プロキシサーバ)と呼ばれるSIPメッセージを中継するサーバです。

SIPサーバは、UACからのSIPメッセージ(正確にはリクエスト)に記述されている電話番号やメールアドレスのような論理的なアドレスを基に、適切なUASや別のSIPサーバへとSIPメッセージを中継します。具体的にはリクエストのSIPメッセージ内に記述されているRequest-URIToヘッダを見て経路選択を行います。この経路選択のことをルーティングと言います。SIPサーバはリクエストだけでなく、レスポンスも中継します。

SIPサーバは、どんなリクエストをどこにルーティングすればいいかを知っています(そう設定されています)。電話の場合、それは電話番号と接続先(UAS or 他のSIPサーバ)を関連付けた単純なリスト(あるいはデータベース)のようなものですが、どんなリクエストをどこにルーティングするのかはSIPでは規定されていない為、どこへどうつなぐかはSIPサーバの胸三寸です。また時と場合によって接続する先を変えてもかまいません。これは例えば、同じ電話番号へかけても、接続先が輻輳している場合にガイダンスサーバへつないだり、着信先が収容変え(番号ポータビリティ)で他の事業会社に収容されているかもしれないからです。いづれにしても、(リクエストがエラーにならない限り、)SIPサーバが中継動作を繰り返すことで、必ずどこかのUASへと辿りつくことができます

上記のSIPサーバの動作によって、UACは通信先の論理的なアドレスをSIPメッセージに記述し、それをSIPサーバに渡すだけで、ルーティングをSIPサーバに任せることができます。UACはリクエストを書くことだけに専念すればいいわけです。

SIPサーバの動作はとてもたくさんあり、全てを説明することはできませんが、基本的には上述の通り、受信したリクエストの論理的なアドレスを見て適切にルーティングすることです。

まとめると、SIPを使って通信をするときには、発信者(UAC)、着信者(UAS)という2つのUA以外に、SIPサーバ(プロキシサーバ)という中継サーバがあり、これがルーティング機能を全て賄ってくれるので、UAはSIPサーバからのリクエスト、レスポンスだけを処理すればいいことになります。

2009年5月6日水曜日

H.248(Megaco): 第01回 MegacoとMGCPとH.248

MGを操作するプロトコルには、Megaco、MGCP、H.248があります。ややこしいので最初に整理しておきます。下図はMegaco、MGCP、H.248の発生と変遷を表したものです。

上記の中のMegacoとMGCPは、RFC2805で定義されている「Media Gateway Control Protocol Architecture」という要求事項を実装したプロトコルです。先にMGCPができて、あとからMegacoができました。そのため、Megacoの方をより正式なものにしようという動きが強いです(MGCPは標準ではなく情報文書(Informational)です。IP電話用語集参照)。

MGを操作するプロトコルとしてMegacoを標準化させようとする一方で、Megacoの管轄が、もともと音頭を取っていたIETFから(なぜか)ITU-Tに移されます。これにより、IETFはMegacoからは手を引き、ITU-Tが音頭を取ってITU-TのHシリーズの仕様としてH.248が誕生しました。

結論から言えば、このH.248という言葉だけ覚えておけばいいわけですが、H.248ができたのが2005年頃(Megacoを廃止したRFC5125が2008年)のため、未だにMegacoという呼び方が生き残っています。

こうしてできたMegaco改めH.248ですが、基本的な仕様はH.248.1で規定され、その他の細々した仕様はH.248.xxと言ったサブ番号で定義されています。例として、NAPTトラバース機能はH.248.37で定義されています。

今後は基本的にH.248という言葉に統一するようにしますが、この連載名は親しみやすいように(!?)Megacoというタイトルを付けています。

なお、今後はもうMGCPは出てきません。標準でも何でもないものを扱うつもりはありません。

AAAプロトコルの目的は何処。。。役に立たないRFCを読んでしまった悲劇

勉強のためにRFC3588の翻訳をやっていますが、翻訳って大変ですね。読んで意味が分かることと、それを日本語で表現するのとは、雲泥の差があることが分かりました。

ところで、このRFCを翻訳している理由は、IMSで使われているGq'インターフェイスを理解するための前段として「そもそもDiameterとは何か?」ということを知らなくては、という重い突きからなのですが、1章を訳し終わって気づきました。

ここには大した情報が書いてない!!

1章の途中で気づいていましたが、ほとんど役に立たないものを訳してしまいました。。。

欲しかった情報は、「Diameterが具体的に何をするプロトコルなのか」をやり取りするデータの実体名で知りたかったのですが、全く書いてありませんね。

そもそもこのRFCはどんな構成しているんですかね。1章には「1.2. Approach to Extensibility(拡張性へのアプローチ)」という箇所がありますが、そんなものはずっと後でしょう。まずAAAのそれぞれの機能は具体的に何をすることなのかを書いておいてくださいよ。このRFC内では一貫して「認証を行うアプリケーションは」とか書いてありますが、それが何をすることなのか、さっぱり分かりません。

SIPのRFC3261もそうですが、汎用性を持たせるためか、そのプロトコルが何の情報を伝えるものなのかがはっきり書いていないんですよね。SIPであれば「発着のIPアドレスとポート、そしてメディア情報(≒SDP)」という通信を開始するために必要な情報を共有する、というのが目下の目的です。ダイアログを作るとかルート情報を確立させるとかは二の次です。まずはIPアドレスとポートとメディアです。それを概要か1章の最初に書いておいてほしいですよね。

まーRFCも技術仕様とは言いながら、テキスト形式で展開している時点で、参考情報程度の効力しかないんでしょうかね。今のご時世に全くそぐわないやり方で、ものごとをまとめようとする姿勢が大変残念です。

2009年5月5日火曜日

ゼロから学ぶSIP: 第02回 SIPが扱う「セッション」とは?

SIPとはセッションを開始するときに使うプロトコルです。ここでいうセッションとは、端的に言えば、通信元と通信先とその間を流れる情報(メディア)のセットのことです。RTP[RFC3350]でのセッションの定義に似ていますね。例えば、電話は発信者(通信元)と着信者(通信先)が音声というメディアを交換し合うセッションです。テレビは配信元(通信元)から視聴者(のテレビ)(通信先)へ映像と音声というメディアを流すセッションです。チャットは2人以上の通信者がテキスト(メディア)のやりとりをするセッションです。要は何か情報があってそれを送信する人、受信する人がいればそれがセッションなのです。何となくイメージできるでしょうか。なお、便宜上通信元と通信先という言い方をしていますが、メディアの流通は片方向とは限りませんので、通信元というのは最初に「通信を始めよう」と提案する人、通信先というのはその提案を受け取った人で、メディアを流す方向とは関係ない、という点に注意してください。

SIPが開始/操作するセッションと、RTPで定義されているセッションはちょっと違います。RTPでいうセッションは明確に、1つの通信元、1つの通信先、そしてその間に流れる単一のメディアと決まっています。つまり、映像と音声を流す場合は、それぞれが別のセッションになります。そして3者通話のように通信先が2つになる場合には、各々の通信先に対してセッションを張ります。一方、SIPが扱うセッションは、メディアが映像+音声のように複数ある場合でも、3者通話や複数地点から参加する電話会議のような2つ以上の通信先がある場合でも、1つのセッションとしてまとめて扱います。こうすることで、複数の接続先を関連付けて操作ができます。

SIPとは、上記のような通信者とメディアのセットを「セッション」という単位で識別できるようにし、それを操作するためのプロトコルだと言えます。

もう少し具体的な動作の中身を説明します。SIPはIPネットワ―ク上で動作するので、通信元、通信先はIPアドレスとポート番号が分かれば特定できます。またその間を流れるメディアは、メディアの種類(音声、映像、テキスト等)、コーデック名(G.711、H.246等)、転送レートなどを決定すればメディアを流せます。つまり、通信元と通信先が、お互いのIPアドレスとポート番号とその間に流すメディアに関する情報を共有できれば、通信を開始できます。RTPで通信をするときに必要な情報と同じですね。

つまり、SIPを使ってセッションを開始することとは、上記のような通信を開始するための情報を通信元と通信先とで共有することだと言えます。SIPはそれらの情報を伝達するルールを規定しているプロトコルです。