メインコンテンツまでスキップ

16. プロキシの動作 (Proxy Behavior)

16.1 概要 (Overview)​

SIP プロキシは、SIP リクエストをユーザーエージェントサーバ (UAS) に、SIP レスポンスをユーザーエージェントクライアント (UAC) にルーティングする要素である。リクエストは UAS に到達するまでの途中で複数のプロキシを経由することがある。各プロキシはルーティング決定を行い、次の要素に転送する前にリクエストを修正する。レスポンスは、リクエストが経由したのと同じ一連のプロキシを逆順に通ってルーティングされる。

プロキシであることは、SIP 要素にとっての論理的な役割である。リクエストが到着したとき、プロキシの役割を果たせる要素は、まず自分自身でそのリクエストに応答する必要があるかどうかを決定する。たとえば、リクエストが不正な形式であるか、プロキシとして動作する前にクライアントからのクレデンシャルが必要な場合がある。要素は任意の適切なエラーコードで応答してもよい (MAY)。リクエストに直接応答する場合、その要素は UAS の役割を果たしており、セクション 8.2 のとおりに振る舞わなければならない (MUST)。

プロキシは、各新規リクエストに対してステートフルまたはステートレスどちらかのモードで動作できる。ステートレスである場合、プロキシは単純な転送要素として動作する。リクエストに基づいてターゲティングおよびルーティング決定を行い、リクエストを単一の要素に下流へ転送する。受信したすべてのレスポンスは上流へ単に転送する。ステートレスプロキシは、メッセージを転送した後はそのメッセージに関する情報を破棄する。ステートフルプロキシは、受信した各リクエストおよびそのリクエストの処理結果として送信する任意のリクエストについて情報 (具体的にはトランザクション状態) を記憶する。この情報を使用して、そのリクエストに関連する将来のメッセージの処理に影響を与える。ステートフルプロキシはリクエストを「フォーク」(複数の送信先にルーティング) してもよい (MAY)。複数の場所に転送されるリクエストは、ステートフルに処理されなければならない (MUST)。

状況によっては、プロキシはトランザクション状態を持たずにステートフルなトランスポート (TCP など) を使用してリクエストを転送してもよい (MAY)。たとえば、プロキシはリクエストが到着したのと同じ接続を通じてレスポンスを転送できるだけの情報をメッセージに含めていれば、ある TCP 接続から別の TCP 接続へトランザクションステートレスにリクエストを転送してもよい (MAY)。プロキシの TU がいずれかのトランスポート上での確実な配送を保証するために主体的な役割を担う必要があるような、異なる種類のトランスポート間で転送されるリクエストは、トランザクションステートフルに転送されなければならない (MUST)。

ステートフルプロキシは、リクエストの処理中はいつでもステートレス動作へ移行してよい (MAY)。ただし、最初からステートレスにすることを妨げるようなことを行っていない (たとえばフォークや 100 レスポンスの生成) 場合に限る。このような移行を行うときは、すべての状態を単に破棄する。プロキシは CANCEL リクエストを開始すべきではない (SHOULD NOT)。

ステートレスまたはステートフルのいずれとして動作する場合も、リクエストの処理の大部分は同一である。以降の数サブセクションは、ステートフルプロキシの観点から記述されている。最後のセクションでは、ステートレスプロキシが異なるように振る舞う箇所を明記する。

16.2 ステートフルプロキシ (Stateful Proxy)​

ステートフルである場合、プロキシは純粋に SIP トランザクション処理エンジンである。その動作は、セクション 17 で定義されるサーバトランザクションおよびクライアントトランザクションの観点からここでモデル化される。ステートフルプロキシは、より上位層のプロキシ処理コンポーネント (図 3 参照、プロキシコアと呼ばれる) によって、1 つ以上のクライアントトランザクションと関連付けられたサーバトランザクションを持つ。着信リクエストはサーバトランザクションによって処理される。サーバトランザクションからのリクエストはプロキシコアに渡される。プロキシコアはリクエストのルーティング先 (1 つ以上のネクストホップの場所) を決定する。各ネクストホップの場所への送信リクエストは、それぞれに関連付けられたクライアントトランザクションによって処理される。プロキシコアはクライアントトランザクションからのレスポンスを収集し、それらを使用してサーバトランザクションへのレスポンスを送信する。

ステートフルプロキシは、受信した各新規リクエストに対して新しいサーバトランザクションを作成する。リクエストの再送はすべて、セクション 17 のとおりそのサーバトランザクションによって処理される。プロキシコアは、セクション 8.2.6 で説明されているように、そのサーバトランザクション上で即時の暫定レスポンス (100 Trying など) を送信する点において UAS として振る舞わなければならない (MUST)。したがって、ステートフルプロキシは非 INVITE リクエストに対して 100 (Trying) レスポンスを生成すべきではない (SHOULD NOT)。

これはプロキシの動作のモデルであって、ソフトウェアのモデルではない。実装は、このモデルが定義する外部的動作を再現する任意の手法を自由に採用してよい。

すべての新規リクエスト (未知のメソッドを含む) について、リクエストをプロキシしようとする要素は以下を行わなければならない (MUST):

  1. リクエストの検証 (セクション 16.3)

2. ルーティング情報の前処理 (セクション 16.4)

3. リクエストのターゲットの決定 (セクション 16.5)

+--------------------+
| | +---+
| | | C |
| | | T |
| | +---+
+---+ | Proxy | +---+ CT = Client Transaction
| S | | "Higher" Layer | | C |
| T | | | | T | ST = Server Transaction
+---+ | | +---+
| | +---+
| | | C |
| | | T |
| | +---+
+--------------------+

Figure 3: Stateful Proxy Model

4. 各ターゲットへのリクエストの転送 (セクション 16.6)

5. すべてのレスポンスの処理 (セクション 16.7)

16.3 リクエストの検証 (Request Validation)​

要素がリクエストをプロキシする前に、メッセージの妥当性を検証しなければならない (MUST)。妥当なメッセージは以下のチェックを通過しなければならない。

  1. 妥当な構文 (Reasonable Syntax)

2. URI スキーム (URI scheme)

3. Max-Forwards

4. (省略可能) ループ検出 (Loop Detection)

5. Proxy-Require

6. Proxy-Authorization

これらのチェックのいずれかが失敗した場合、要素はユーザーエージェントサーバとして振る舞わなければならず (MUST) (セクション 8.2 参照)、エラーコードで応答しなければならない。

プロキシはマージされたリクエストを検出することを要求されず、マージされたリクエストをエラー状態として扱ってはならない (MUST NOT)。リクエストを受信するエンドポイントが、セクション 8.2.2.2 のとおりにマージを解決する。

  1. 妥当な構文チェック (Reasonable syntax check)

    リクエストは、サーバトランザクションで処理できる程度に十分に整った形式でなければならない (MUST)。これ以降のリクエスト検証ステップやリクエスト転送セクションに関与するコンポーネントは、すべて十分な形式でなければならない (MUST)。その他のコンポーネントは、形式が整っていてもいなくても、無視され、メッセージの転送時に変更されないままであるべきである (SHOULD)。たとえば、要素は Date ヘッダフィールドが不正な形式であるからといってリクエストを拒否しない。同様に、プロキシはリクエストを転送する前に不正な形式の Date ヘッダフィールドを削除しない。

    このプロトコルは拡張されるように設計されている。将来の拡張により、新しいメソッドやヘッダフィールドがいつでも定義される可能性がある。要素は、知らないメソッドやヘッダフィールドを含むことを理由にリクエストのプロキシを拒否してはならない (MUST NOT)。

  2. URI スキームチェック (URI scheme check)

    Request-URI が、プロキシが理解できないスキームを持つ URI である場合、プロキシは 416 (Unsupported URI Scheme) レスポンスでリクエストを拒否すべきである (SHOULD)。

  3. Max-Forwards チェック

    Max-Forwards ヘッダフィールド (セクション 20.22) は、SIP リクエストが経由できる要素の数を制限するために使用される。

    リクエストに Max-Forwards ヘッダフィールドが含まれていない場合、このチェックは通過する。

    リクエストに、フィールド値がゼロより大きい Max-Forwards ヘッダフィールドが含まれている場合、チェックは通過する。

    リクエストに、フィールド値がゼロ (0) の Max-Forwards ヘッダフィールドが含まれている場合、要素はリクエストを転送してはならない (MUST NOT)。リクエストが OPTIONS 宛てであった場合、要素は最終受信者として動作し、セクション 11 のとおりに応答してもよい (MAY)。それ以外の場合、要素は 483 (Too many hops) レスポンスを返さなければならない (MUST)。

  4. 省略可能なループ検出チェック (Optional Loop Detection check)

    要素は、リクエストを転送する前に転送ループをチェックしてもよい (MAY)。リクエストに、プロキシが以前のリクエストに設定した値と等しい sent-by 値を持つ Via ヘッダフィールドが含まれている場合、そのリクエストはこの要素によって以前に転送されたものである。リクエストはループしたか、あるいは正当に要素を通ってスパイラル (spiral) している。リクエストがループしたかどうかを決定するため、要素はセクション 16.6 のステップ 8 で説明される branch パラメータ計算をこのメッセージに対して実行し、その Via ヘッダフィールドで受信したパラメータと比較してもよい (MAY)。パラメータが一致すれば、リクエストはループした。異なっていれば、リクエストはスパイラルしており、処理を続行する。ループが検出された場合、要素は 482 (Loop Detected) レスポンスを返してもよい (MAY)。

  5. Proxy-Require チェック

    このプロトコルの将来の拡張により、プロキシによる特別な処理を必要とする機能が導入される可能性がある。エンドポイントは、これらの機能を使用するリクエストに Proxy-Require ヘッダフィールドを含め、その機能が理解されない限りリクエストを処理しないようプロキシに指示する。

    リクエストに、この要素が理解できない 1 つ以上の option-tag を持つ Proxy-Require ヘッダフィールド (セクション 20.29) が含まれている場合、要素は 420 (Bad Extension) レスポンスを返さなければならない (MUST)。レスポンスには、要素が理解できなかった option-tag を列挙する Unsupported (セクション 20.40) ヘッダフィールドを含めなければならない (MUST)。

  6. Proxy-Authorization チェック

    要素がリクエストを転送する前にクレデンシャルを必要とする場合、セクション 22.3 のとおりにリクエストを検査しなければならない (MUST)。そのセクションは、検査が失敗した場合に要素が行うべきことも定義している。

16.4 ルーティング情報の前処理 (Preparing the Request for Routing)​

リクエストをフォワードする前に、要素はルーティングに影響を与えるヘッダフィールドを検査・修正しなければならない (MUST)。Record-Route ヘッダフィールド (セクション 20.30) はリクエストにそのまま残す。追加で、要素は以下の手順を実行しなければならない (MUST):

  1. リクエストに Route ヘッダフィールド (セクション 20.34) が含まれており、その最初の値 (最上位) が要素を指していない場合、要素はリクエストを変更せずにセクション 16.6 に進む。要素はリクエストに Record-Route ヘッダフィールド値を挿入しない。要素はリクエストをそのまま次の要素へ転送する。

注: 最上位の Route ヘッダフィールド値が要素を指していないということは、要素がルーズルーティング (loose routing) を実装していない以前の要素によって挿入された Route ヘッダフィールドを処理しているということである。

2. リクエストに Route ヘッダフィールド (セクション 20.34) が含まれ、その最初の値が要素を指している場合:

要素がルーズルーティングをサポートしている場合、要素は Route ヘッダフィールドの最初の値を削除しなければならない (MUST)。ルーズルーティング手順が適用されることになる。

要素がルーズルーティングを実装していない場合、要素は RFC 2543 の strict routing 手順を実行しなければならない (MUST)。

3. 最後に、要素は自身を示す Record-Route ヘッダフィールド値をリクエストに追加してもよい (MAY)。

16.5 リクエストのターゲットの決定 (Determining Request Targets)​

要素がダイアログを作成するリクエスト (たとえば INVITE) を処理する場合、要素はダイアログのルートセットを初期化しなければならない (MUST)。ルートセットは要素が Record-Route ヘッダフィールドをリクエストに挿入するときに初期化される。

要素がダイアログを作成するリクエストを処理する場合、要素はリクエストを 1 つ以上の場所に転送しなければならない (MUST)。これは宛先セット (target set) と呼ばれる。

要素がターゲットを決定する方法は、リクエストの種類 (ダイアログを作成するか、ダイアログ内か) と、Request-URI が要素が管理するドメインを示しているかどうかに依存する。

  1. リクエストに Route ヘッダフィールドが含まれていない場合、要素は Request-URI の URI が指すリソースを所有しているかどうかをチェックしなければならない (MUST)。URI が要素が管理するドメイン内のリソースを示している場合、要素は Request-URI の値を、そのリソースの場所を表すセット (たとえば、登録された Contacts やリソースのホームエージェント) に置き換えなければならない (MUST)。これは通常、要素の位置情報サービス (location service) を実行することで行われる。場所は、登録 (セクション 10)、リダイレクト、またはその他の手段によって得られるかもしれない。

Request-URI が管理対象ドメインのリソースを示していない場合、要素は Request-URI を宛先セットに配置する。

2. リクエストに Route ヘッダフィールドが含まれている場合、要素は宛先セットを Route ヘッダフィールドの最初の値 (最上位) が指す場所に設定しなければならない (MUST)。要素がルーズルーティングを実装している場合、Route ヘッダフィールドの最初の値はすでに (セクション 16.4 のステップ 2 で) 削除されているため、Route ヘッダフィールドの次の値 (存在する場合) が宛先セットになる。Request-URI の URI は宛先セットの計算に使用されない。

ダイアログ内のリクエスト (たとえば BYE) の場合、要素は宛先セットをダイアログのルートセットの最初の値に設定しなければならない (MUST)。ダイアログのリモートターゲット URI は宛先セットの計算に使用されない。

要素がフォワードする前に宛先セットに対してローカルポリシー検査を実行してもよい (MAY)。要素は 3xx レスポンスを受信したときに再帰するために宛先セットを修正してもよい (MAY)。

16.6 リクエストの転送 (Forwarding the Request)​

要素がリクエストをフォワードする (またはプロキシする) 前に、要素はその宛先セットの各宛先に対して以下の手順を実行しなければならない (MUST):

  1. コピーの作成 (Make a copy)

     要素は受信したリクエストのコピーを作成し、そのコピーを次のステップで修正する。要素は受信したリクエストを直接修正してはならない (MUST NOT)。これにより、エラーや異常が発生した場合に要素が元のリクエストをフォワードできるようになる。

  2. マルチホームホストの URI のスワップ (Swap multicast address for a multicast-capable host)

     Request-URI のホスト部分が IP マルチキャストグループのアドレスである場合、要素はホスト部分を、そのマルチキャストグループをリッスンし、リクエストを処理できるマルチホームホストのユニキャストアドレスに置き換えてもよい (MAY)。これにより、マルチキャストグループ内の他のホストがリクエストのコピーを受信して処理しようとするのを防ぐ。

  3. Record-Route の追加 (Add a Record-Route value if necessary)

     要素が Record-Route ヘッダフィールド値を挿入する場合、要素は次の URI に等しい新しい Record-Route ヘッダフィールド値をコピーの先頭に挿入しなければならない (MUST):

        o 要素が UDP 経由でリクエストを受信したが TCP 経由で送信する場合、その URI は SIP URI でなければならず (MUST)、要素のホスト名または IP アドレス (およびオプションのポート) と、リッスンするトランスポートを示す transport パラメータを含まなければならない (MUST)。要素が当初 UDP で受信し、TCP 経由で送信する場合、URI は sip: スキームを使用しなければならない (MUST)。

        o 要素が TCP 経由でリクエストを受信し、UDP 経由で送信する場合、その URI は SIP URI でなければならず (MUST)、要素のホスト名または IP アドレス (およびオプションのポート) と、transport=udp パラメータを含まなければならない (MUST)。

        o 要素が TLS 経由で受信し、TLS 以外の接続を介して送信する (またはその逆) 場合、その URI は、リクエストを受信したトランスポートが TLS であったかどうかに対応して、SIPS URI または SIP URI でなければならない (MUST)。

        o それ以外の場合、要素は自身のホスト名または IP アドレス (およびオプションのポート) を含む SIP または SIPS URI を使用してもよい (MAY)。要素は、その URI を含むリクエストが到着したポートとは異なるポートでリッスンしていてもよい (MAY)。要素は自身の能力を示すために transport パラメータを含めてもよい (MAY)。

     要素は Record-Route ヘッダフィールドに挿入するURIに lr パラメータを含めなければならない (MUST) (セクション 19.1.1 を参照)。

  4. Route 情報の処理 (Process routing information)

     要素がルーズルーティングを実装している場合、Request-URI を変更しない。それ以外の場合、要素が strict ルーターである場合、要素は Route ヘッダフィールドの最初の値を Request-URI にコピーし、その値を Route ヘッダフィールドから削除しなければならない (MUST)。要素はその URI を Request-URI に入れる前に、その URI 内のパラメータをあらゆる方法でも修正してはならない (MUST NOT)。

     要素は Route ヘッダフィールドのいずれかの値が自身を指しているかどうかをチェックしてもよい (MAY)。自身を指している場合、要素はその値を削除してもよい (MAY)。

  5. Request-URI の追加 (Add the Request-URI to the copy)

     要素が strict ルーターであり、コピーの Request-URI が Route ヘッダフィールドの最初の値から取得された場合、その値を Route ヘッダフィールドから削除しなければならない (MUST)。

  6. Max-Forwards の減算 (Decrement Max-Forwards)

     コピーに Max-Forwards ヘッダフィールドが含まれていない場合、要素はそれを 70 に設定しなければならない (MUST)。それ以外の場合、要素はフィールド値を 1 減らさなければならない (MUST)。

  7. ネクストホップのアドレス、ポート、トランスポートの決定 (Determine the next-hop address, port, and transport)

     要素は、セクション 16.5 の宛先セットの 1 つのメンバーに対応するアドレス、ポート、トランスポートを決定する。

     宛先セットが Route ヘッダフィールド値であった場合、アドレス、ポート、トランスポートは、RFC 2543 の付録 C で説明されるプロシージャを使用してその URI を解決することで決定される。

     宛先セットが Request-URI であった場合、そのメソッドと Request-URI を使用して RFC 3263 のプロシージャが適用される。

  8. コピーに自身の Via を追加 (Add own Via to the copy)

     要素は、コピーの Via ヘッダフィールドの先頭に、自身の sent-by アドレスを含む新しい Via ヘッダフィールド値を追加しなければならない (MUST)。

     アドレスは要素がそのトランスポート接続をリッスンしている場所でなければならず (MUST)、要素がその接続を介してレスポンスを確実に受信できることを保証しなければならない (MUST)。

     Via ヘッダフィールド値は、要素がそのトランスポート上でその宛先にリクエストを送信するときに選択した branch パラメータを含まなければならない (MUST)。

     branch パラメータは、要素が送信するすべてのリクエスト (CANCEL および非 2xx ACK を除く) に対して一意でなければならない (MUST)。この要件は、空間および時間の両方で一意であることを要求する。要素はリクエストをフォワードするとき、図 3 に示されたクライアントトランザクションと関連付けられたそのリクエストに branch パラメータを割り当てる。この branch パラメータを計算するため、要素はリクエストの特別な部分 (RFC 3261 のマジッククッキー "z9hG4bK" で始まる文字列) をハッシュしなければならない (MUST)。

     プロキシがリクエストをフォワードするとき、それは受信したリクエストのすべての値 (Request-URI を含む) を含むコピーを作成し、それに自身の Via を追加する。リクエストの構文、およびリクエストのルーティングまたは受け入れに影響する任意のヘッダフィールドを構成するすべての値は、ハッシュ計算に含まれなければならない (MUST)。これは、ループしたリクエストと、このサーバーに戻る前にルーティングパラメータが変更されたリクエストを区別するために必要である。

     branch パラメータの計算にリクエストメソッドを含んではならない (MUST NOT)。特に、CANCEL および ACK リクエスト (非 2xx レスポンス用) は、それらがキャンセルまたは確認する対応するリクエストと同じ branch 値を持たなければならない (MUST)。branch パラメータは、それらを処理するサーバーでこれらのリクエストを相関させるために使用される (セクション 17.2.3 および 9.2 を参照)。

  9. 必要に応じて Content-Length ヘッダフィールドを追加 (Add a Content-Length header field if necessary)

     リクエストがストリームベースのトランスポートを使用してネクストホップに送信され、そのコピーに Content-Length ヘッダフィールドが含まれていない場合、プロキシはリクエストのボディの正しい値を持つものを挿入しなければならない (MUST) (セクション 20.14 を参照)。

  10. リクエストの転送 (Forward Request)

     ステートフルプロキシは、セクション 17.1 で説明されるようにこのリクエストに対する新しいクライアントトランザクションを作成し、ステップ 7 で決定されたアドレス、ポート、トランスポートを使用してリクエストを送信するようトランザクションに指示しなければならない (MUST)。

  11. タイマー C の設定 (Set timer C)

     INVITE リクエストが最終レスポンスを生成しない場合に対処するため、TU はタイマー C と呼ばれるタイマーを使用する。INVITE リクエストがプロキシされるとき、タイマー C は各クライアントトランザクションに対して設定されなければならない (MUST)。タイマーは 3 分以上でなければならない (MUST)。セクション 16.7 箇条書き 2 はこのタイマーが暫定レスポンスでどのように更新されるかを説明し、セクション 16.8 はそれが発火したときの処理を説明する。

16.7 レスポンスの処理 (Response Processing)​

要素がレスポンスを受信したとき、まずクライアントトランザクション (セクション 17.1.3) を検索してレスポンスと一致するものを見つけようとする。一致するものが見つからない場合、要素はレスポンスを (それが情報レスポンスであっても) ステートレスプロキシとして処理しなければならない (MUST) (以下参照)。一致が見つかった場合、レスポンスはクライアントトランザクションに渡される。

  クライアントトランザクション (より一般的には、関連するリクエストを送信したといういかなる知識も) が見つからないレスポンスをフォワードすることは、堅牢性を向上させる。特に、INVITE リクエストに対する「遅れた」2xx レスポンスが適切にフォワードされることを保証する。

クライアントトランザクションがレスポンスをプロキシ層に渡すとき、以下の処理が行われなければならない (MUST):

  1. 適切なレスポンスコンテキストの検索

2. 暫定レスポンスに対するタイマー C の更新

3. 最上位の Via の削除

4. レスポンスをレスポンスコンテキストへの追加

5. このレスポンスを直ちにフォワードすべきかどうかのチェック

6. 必要に応じて、レスポンスコンテキストから最適な最終レスポンスの選択

レスポンスコンテキストに関連付けられたすべてのクライアントトランザクションが終了した後も最終レスポンスがフォワードされていなければ、プロキシはそれまでに見たものの中から「最良の」レスポンスを選択してフォワードしなければならない (MUST)。

フォワードされる各レスポンスに対して以下の処理が行われなければならない (MUST)。各リクエストに対して複数のレスポンスがフォワードされる可能性が高い (少なくとも各暫定レスポンスと 1 つの最終レスポンス)。

  7. 必要に応じて Authorization ヘッダフィールド値の集約

8. 任意で Record-Route ヘッダフィールド値の書き換え

9. レスポンスのフォワード

10. 必要な CANCEL リクエストの生成

上記の各ステップを以下に詳述する:

  1. コンテキストの検索 (Find Context)

     プロキシは、セクション 16.6 で説明されたキーを使用して、元のリクエストをフォワードする前に作成した「レスポンスコンテキスト」を検索する。残りの処理ステップはこのコンテキスト内で行われる。

  2. 暫定レスポンスに対するタイマー C の更新 (Update timer C for provisional responses)

     INVITE トランザクションの場合、レスポンスが 101 から 199 までの状態コードを含む暫定レスポンス (つまり 100 以外) であれば、プロキシはそのクライアントトランザクションのタイマー C をリセットしなければならない (MUST)。タイマーは別の値にリセットしてもよい (MAY) が、この値は 3 分以上でなければならない (MUST)。

  3. Via

     プロキシはレスポンスから最上位の Via ヘッダフィールド値を削除する。

     レスポンスに Via ヘッダフィールド値が残っていない場合、そのレスポンスはこの要素宛てであり、フォワードしてはならない (MUST NOT)。このセクションで説明される残りの処理はこのメッセージに対して実行されず、代わりにセクション 8.1.3 で説明される UAC 処理規則に従う (トランスポート層処理はすでに発生している)。

     これは、たとえば要素がセクション 10 で説明される CANCEL リクエストを生成するときに発生する。

  4. レスポンスをコンテキストに追加 (Add response to context)

     受信した最終レスポンスは、このコンテキストに関連付けられたサーバトランザクションで最終レスポンスが生成されるまで、レスポンスコンテキストに格納される。そのレスポンスは、そのサーバトランザクションで返される最良の最終レスポンスの候補となり得る。このレスポンスが選択されなくても、最良のレスポンスを形成する際にこのレスポンスからの情報が必要になる場合がある。

     プロキシが 3xx レスポンス内の任意の Contact に対して再帰 (recurse) し、それらを宛先セットに追加することを選択した場合、レスポンスをレスポンスコンテキストに追加する前に、それらをレスポンスから削除しなければならない (MUST)。ただし、元のリクエストの Request-URI が SIPS URI であった場合、プロキシは非 SIPS URI に対して再帰すべきではない (SHOULD NOT)。プロキシが 3xx レスポンス内のすべての Contact に対して再帰する場合、プロキシは結果の Contact なしレスポンスをレスポンスコンテキストに追加すべきではない (SHOULD NOT)。

     Contact をレスポンスコンテキストに追加する前に削除することで、上流の次の要素がこのプロキシがすでに試した場所を再試行するのを防ぐ。

     3xx レスポンスには SIP、SIPS、および非 SIP URI が混在する場合がある。プロキシは SIP および SIPS URI に対して再帰し、残りを返される可能性のある最終レスポンスに入れてレスポンスコンテキストに配置してもよい (MAY)。

     プロキシが、Request-URI スキームが SIP ではなかったリクエストに対して 416 (Unsupported URI Scheme) レスポンスを受信したが、元々受信したリクエストのスキームが SIP または SIPS であった場合 (つまり、プロキシがリクエストをプロキシするときにスキームを SIP または SIPS から別のものに変更した場合)、プロキシは宛先セットに新しい URI を追加すべきである (SHOULD)。この URI は、試したばかりの非 SIP URI の SIP URI 版であるべきである (SHOULD)。tel URL の場合、tel URL の telephone-subscriber 部分を SIP URI の user 部分に入れ、hostpart を以前のリクエストが送信されたドメインに設定することで達成される。tel URL から SIP URI を形成する詳細についてはセクション 19.1.6 を参照。

     3xx レスポンスと同様に、プロキシが 416 に対して「再帰」し、代わりに SIP または SIPS URI を試す場合、416 レスポンスをレスポンスコンテキストに追加すべきではない (SHOULD NOT)。

  5. フォワードのためのレスポンスのチェック (Check response for forwarding)

     サーバトランザクションで最終レスポンスが送信されるまで、以下のレスポンスは直ちにフォワードされなければならない (MUST):

     - 100 (Trying) 以外の任意の暫定レスポンス

     - 任意の 2xx レスポンス

     6xx レスポンスを受信した場合、それは直ちにフォワードされないが、ステートフルプロキシはセクション 10 で説明されるようにすべての保留中クライアントトランザクションをキャンセルすべきであり (SHOULD)、このコンテキストで新しいブランチを作成してはならない (MUST NOT)。

     これは RFC 2543 からの変更であり、RFC 2543 はプロキシが 6xx レスポンスを直ちにフォワードすることを義務付けていた。INVITE トランザクションの場合、このアプローチには、別のブランチで 2xx レスポンスが到着する可能性があり、その場合プロキシは 2xx をフォワードしなければならないという問題があった。その結果、UAC が 6xx レスポンスに続いて 2xx レスポンスを受信する可能性があり、それは決して許されてはならない。新しい規則の下では、6xx を受信するとプロキシは CANCEL リクエストを発行し、通常はすべての未処理クライアントトランザクションから 487 レスポンスが得られ、その時点で 6xx が上流へフォワードされる。

     サーバトランザクションで最終レスポンスが送信された後、以下のレスポンスは直ちにフォワードされなければならない (MUST):

     - INVITE リクエストに対する任意の 2xx レスポンス

     ステートフルプロキシは他の任意のレスポンスを直ちにフォワードしてはならない (MUST NOT)。特に、ステートフルプロキシは任意の 100 (Trying) レスポンスをフォワードしてはならない (MUST NOT)。後で「最良の」レスポンスとしてフォワードされる候補となるレスポンスは、「レスポンスをコンテキストに追加」ステップで収集されている。

     直ちにフォワードするために選択された任意のレスポンスは、「Authorization ヘッダフィールド値の集約」から「Record-Route」までのステップで説明されるとおりに処理されなければならない (MUST)。

     このステップと次のステップを組み合わせることで、ステートフルプロキシは、非 INVITE リクエストに対して正確に 1 つの最終レスポンスを、INVITE リクエストに対しては正確に 1 つの非 2xx レスポンスまたは 1 つ以上の 2xx レスポンスをフォワードすることが保証される。

  6. 最良のレスポンスの選択 (Choosing the best response)

     上記の規則によって最終レスポンスが直ちにフォワードされておらず、かつこのレスポンスコンテキスト内のすべてのクライアントトランザクションが終了している場合、ステートフルプロキシはレスポンスコンテキストのサーバトランザクションに対して最終レスポンスを送信しなければならない (MUST)。

     ステートフルプロキシは、レスポンスコンテキスト内で受信され格納されたものの中から「最良の」最終レスポンスを選択しなければならない (MUST)。

     コンテキストに最終レスポンスがない場合、プロキシは 408 (Request Timeout) レスポンスをサーバトランザクションに送信しなければならない (MUST)。

     それ以外の場合、プロキシはレスポンスコンテキストに格納されたレスポンスからレスポンスをフォワードしなければならない (MUST)。コンテキストに存在する場合は、6xx クラスのレスポンスから選択しなければならない (MUST)。6xx クラスのレスポンスが存在しない場合、プロキシはレスポンスコンテキストに格納された最も低いレスポンスクラスから選択すべきである (SHOULD)。プロキシはその選択したクラス内の任意のレスポンスを選択してもよい (MAY)。プロキシは、このリクエストの再送信に影響を与える情報 (401、407、415、420、484 など) を提供するレスポンスを優先すべきである (SHOULD)。

     503 (Service Unavailable) レスポンスを受信したプロキシは、それがプロキシがプロキシする可能性のある後続のリクエストもすべて 503 を生成することを判断できない限り、それを上流へフォワードすべきではない (SHOULD NOT)。言い換えれば、503 をフォワードすることは、プロキシがその 1 つの Request-URI に対するリクエストだけでなく、いかなるリクエストも処理できないことを知っていることを意味する。受信した唯一のレスポンスが 503 である場合、プロキシは 500 レスポンスを生成して上流へフォワードすべきである (SHOULD)。

     フォワードされるレスポンスは、「Authorization ヘッダフィールド値の集約」から「Record-Route」までのステップで説明されるとおりに処理されなければならない (MUST)。

     たとえば、プロキシがリクエストを 4 か所にフォワードし、503、407、501、404 のレスポンスを受信した場合、407 (Proxy Authentication Required) レスポンスをフォワードすることを選択してもよい (MAY)。

     1xx および 2xx レスポンスはダイアログの確立に関与する可能性がある。リクエストに To tag が含まれていない場合、レスポンス内の To tag は、ダイアログ作成リクエストへの複数のレスポンスを UAC が区別するために使用される。リクエストに To tag が含まれていない場合、プロキシは 1xx または 2xx レスポンスの To ヘッダフィールドに tag を挿入してはならない (MUST NOT)。プロキシは 1xx または 2xx レスポンスの To ヘッダフィールド内の tag を変更してはならない (MUST NOT)。

     プロキシは、To tag を含まないリクエストに対する 1xx レスポンスに tag を挿入できないため、自身で非 100 暫定レスポンスを発行できない。しかし、プロキシと同じ要素を共有する UAS へリクエストをブランチさせることはできる。この UAS は自身の暫定レスポンスを返し、リクエストの開始者との早期ダイアログに入ることができる。UAS はプロキシと別個のプロセスである必要はない。プロキシと同じコード空間に実装された仮想 UAS であってもよい。

     3-6xx レスポンスはホップバイホップで配信される。3-6xx レスポンスを発行するとき、要素は事実上 UAS として動作し、通常は下流要素から受信したレスポンスに基づいて自身のレスポンスを発行する。要素は、To tag を含まないリクエストへの 3-6xx レスポンスを単にフォワードするとき、To tag を保持すべきである (SHOULD)。

     プロキシは、To tag を含むリクエストに対するフォワードされた任意のレスポンス内の To tag を変更してはならない (MUST NOT)。

     プロキシがフォワードされた 3-6xx レスポンス内の To tag を置き換えても上流要素に違いは生じないが、元の tag を保持することはデバッグに役立つ可能性がある。

     プロキシが複数のレスポンスから情報を集約するとき、それらの間から To tag を選択することは任意であり、新しい To tag を生成するとデバッグが容易になる場合がある。これは、たとえば 401 (Unauthorized) と 407 (Proxy Authentication Required) のチャレンジを組み合わせる場合、または暗号化されておらず認証されていない 3xx レスポンスから Contact 値を組み合わせる場合に発生する。

  7. Authorization ヘッダフィールド値の集約 (Aggregate Authorization Header Field Values)

     選択されたレスポンスが 401 (Unauthorized) または 407 (Proxy Authentication Required) である場合、プロキシは、このレスポンスコンテキスト内でこれまでに受信した他のすべての 401 (Unauthorized) および 407 (Proxy Authentication Required) レスポンスからの任意の WWW-Authenticate および Proxy-Authenticate ヘッダフィールド値を収集し、フォワードする前に変更せずにこのレスポンスに追加しなければならない (MUST)。結果の 401 (Unauthorized) または 407 (Proxy Authentication Required) レスポンスには、複数の WWW-Authenticate および Proxy-Authenticate ヘッダフィールド値が含まれる可能性がある。

     これは、リクエストがフォワードされた送信先のすべてまたはいずれかがクレデンシャルを要求した可能性があるため必要である。クライアントはそれらのチャレンジのすべてを受信し、リクエストを再試行するときにそれぞれのクレデンシャルを提供する必要がある。この動作の動機はセクション 26 で提供される。

  8. Record-Route

     選択されたレスポンスに、このプロキシが元々提供した Record-Route ヘッダフィールド値が含まれている場合、プロキシはフォワードする前にその値を書き換えることを選択してもよい (MAY)。これによりプロキシは、次の上流要素および下流要素に対して自身の異なる URI を提供できる。プロキシは任意の理由でこのメカニズムを選択してよい。たとえば、マルチホームホストに有用である。

     プロキシがリクエストを TLS 経由で受信し、非 TLS 接続で送信した場合、プロキシは Record-Route ヘッダフィールド内の URI を SIPS URI に書き換えなければならない (MUST)。プロキシがリクエストを非 TLS 接続で受信し、TLS 経由で送信した場合、プロキシは Record-Route ヘッダフィールド内の URI を SIP URI に書き換えなければならない (MUST)。

     プロキシが提供する新しい URI は、リクエスト内の Record-Route ヘッダフィールドに配置される URI に対する制約 (セクション 16.6 のステップ 4 参照) を、以下の修正を伴って満たさなければならない (MUST):

     プロキシが、後続のリクエストの経路に存在する次の上流 (下流ではなく) 要素がそのトランスポートをサポートするという知識を持っていない限り、URI に transport パラメータを含んではならない (SHOULD NOT)。

     プロキシがレスポンス内の Record-Route ヘッダフィールドを変更することを決定したとき、それが実行する操作の 1 つは、自身が挿入した Record-Route 値の検索である。リクエストがスパイラルした場合、プロキシがスパイラルの各反復で Record-Route 値を挿入したなら、レスポンス内 (逆方向の適切な反復でなければならない) の正しい値を見つけるのは困難である。上記の規則は、Record-Route ヘッダフィールド値の書き換えを望むプロキシに対し、書き換えのために正しいものが選択できるよう、十分に異なる URI を Record-Route ヘッダフィールドに挿入することを推奨している。これを達成するための推奨されるメカニズムは、プロキシがプロキシインスタンスの一意の識別子を URI の user 部分に付加することである。

     レスポンスが到着したとき、プロキシは識別子がプロキシインスタンスと一致する最初の Record-Route を変更する。変更の結果、URI の user 部分に付加されたこのデータ片を含まない URI となる。次の反復では、同じアルゴリズム (パラメータを持つ最上位の Record-Route ヘッダフィールド値を検索) が、そのプロキシによって挿入された次の Record-Route ヘッダフィールド値を正しく抽出する。

     プロキシが Record-Route ヘッダフィールド値を追加したリクエストに対するすべてのレスポンスに Record-Route ヘッダフィールドが含まれるわけではない。レスポンスに Record-Route ヘッダフィールドが含まれる場合、それにはプロキシが追加した値が含まれる。

  9. レスポンスのフォワード (Forward response)

     「Authorization ヘッダフィールド値の集約」から「Record-Route」までのステップで説明される処理を実行した後、プロキシは選択されたレスポンスに対して機能固有の操作を実行してもよい (MAY)。プロキシはメッセージボディを追加、変更、削除してはならない (MUST NOT)。別途指定がない限り、プロキシはセクション 16.7 項目 3 で説明される Via ヘッダフィールド値以外の任意のヘッダフィールド値を削除してはならない (MUST NOT)。特に、プロキシは、このレスポンスに関連するリクエストを処理中に次の Via ヘッダフィールド値に追加した可能性のある任意の "received" パラメータを削除してはならない (MUST NOT)。プロキシはレスポンスをレスポンスコンテキストに関連付けられたサーバトランザクションに渡さなければならない (MUST)。これにより、レスポンスは現在最上位の Via ヘッダフィールド値で示される場所に送信される。サーバトランザクションが送信を処理するために利用できなくなった場合、要素はレスポンスをサーバートランスポートに送信することでステートレスにフォワードしなければならない (MUST)。サーバトランザクションはレスポンスの送信失敗を示したり、状態マシンでタイムアウトを通知したりする場合がある。これらのエラーは診断目的で適切にログに記録されるが、プロキシに必要な救済措置はプロトコル上要求されない。

     プロキシは、最終レスポンスをフォワードした後でも、関連するすべてのトランザクションが終了するまでレスポンスコンテキストを維持しなければならない (MUST)。

  10. CANCEL の生成 (Generate CANCELs)

     フォワードされたレスポンスが最終レスポンスであった場合、プロキシはこのレスポンスコンテキストに関連付けられたすべての保留中クライアントトランザクションに対して CANCEL リクエストを生成しなければならない (MUST)。プロキシは 6xx レスポンスを受信したときにも、このレスポンスコンテキストに関連付けられたすべての保留中クライアントトランザクションに対して CANCEL リクエストを生成すべきである (SHOULD)。保留中クライアントトランザクションとは、暫定レスポンスを受信したが最終レスポンスを受信していない (進行中状態にある) ものであり、かつ関連する CANCEL が生成されていないものである。CANCEL リクエストの生成はセクション 9.1 で説明される。

     最終レスポンスをフォワードするときに保留中クライアントトランザクションを CANCEL する要件は、エンドポイントが INVITE に対する複数の 200 (OK) レスポンスを受信しないことを保証するものではない。CANCEL リクエストが送信および処理される前に、複数のブランチで 200 (OK) レスポンスが生成される可能性がある。さらに、将来の拡張がこの CANCEL リクエスト発行の要件を上書きすることが合理的に予想される。

16.8 タイマー C の処理 (Processing Timer C)​

タイマー C が発火した場合、プロキシはタイマーを任意の選択した値でリセットするか、クライアントトランザクションを終了しなければならない (MUST)。クライアントトランザクションが暫定レスポンスを受信していた場合、プロキシはそのトランザクションに一致する CANCEL リクエストを生成しなければならない (MUST)。クライアントトランザクションが暫定レスポンスを受信していない場合、プロキシはトランザクションが 408 (Request Timeout) レスポンスを受信したかのように振る舞わなければならない (MUST)。

プロキシがタイマーをリセットできるようにすることで、タイマーが発火したときに、現在の状況 (利用状況など) に基づいてトランザクションの寿命を動的に延長できる。

16.9 トランスポートエラーの処理 (Handling Transport Errors)​

トランスポート層がプロキシに、リクエストのフォワード時のエラーを通知した場合 (セクション 18.4 参照)、プロキシはフォワードされたリクエストが 503 (Service Unavailable) レスポンスを受信したかのように振る舞わなければならない (MUST)。

プロキシがレスポンスのフォワード時にエラーを通知された場合、プロキシはそのレスポンスを破棄する。プロキシは、この通知によりこのレスポンスコンテキストに関連付けられた未処理のクライアントトランザクションをキャンセルすべきではない (SHOULD NOT)。

  単一の悪意のある、または誤動作するクライアントが、自身の Via ヘッダフィールドを通じてすべてのトランザクションを失敗させる可能性がある。

16.10 CANCEL の処理 (CANCEL Processing)​

ステートフルプロキシは、それが生成した任意の他のリクエストに対して、任意の時点で CANCEL を生成してもよい (MAY) (セクション 9.1 で説明されるとおり、そのリクエストに対する暫定レスポンスを受信することが条件)。プロキシは、一致する CANCEL リクエストを受信したとき、レスポンスコンテキストに関連付けられたすべての保留中クライアントトランザクションをキャンセルしなければならない (MUST)。

ステートフルプロキシは、保留中の INVITE クライアントトランザクションに対して、INVITE の Expires ヘッダフィールドで指定された期間が経過したことに基づいて CANCEL リクエストを生成してもよい (MAY)。しかし、これは一般に不要である。なぜなら、関与するエンドポイントがトランザクションの終了を通知するからである。

CANCEL リクエストはステートフルプロキシ内で自身のサーバトランザクションによって処理されるが、それに対する新しいレスポンスコンテキストは作成されない。代わりに、プロキシ層は既存のレスポンスコンテキストを検索し、この CANCEL に関連付けられたリクエストを処理しているサーバトランザクションを見つける。一致するレスポンスコンテキストが見つかった場合、要素は直ちに CANCEL リクエストに対して 200 (OK) レスポンスを返さなければならない (MUST)。この場合、要素はセクション 8.2 で定義されるユーザーエージェントサーバとして動作している。さらに、要素はセクション 16.7 ステップ 10 で説明されるとおり、コンテキスト内のすべての保留中クライアントトランザクションに対して CANCEL リクエストを生成しなければならない (MUST)。

レスポンスコンテキストが見つからない場合、要素は CANCEL を適用する対象のリクエストに関する知識を持っていない。要素は CANCEL リクエストをステートレスにフォワードしなければならない (MUST) (関連するリクエストを以前にステートレスにフォワードした可能性がある)。

16.11 ステートレスプロキシ (Stateless Proxy)​

ステートレスに動作する場合、プロキシは単純なメッセージフォワーダである。ステートレスに動作するときに実行される処理の多くは、ステートフルに振る舞うときと同じである。相違点をここに詳述する。

ステートレスプロキシは、トランザクションや、ステートフルプロキシの動作を記述するために使用されるレスポンスコンテキストという概念を持たない。代わりに、ステートレスプロキシはメッセージ (リクエストとレスポンスの両方) をトランスポート層から直接取得する (セクション 18 参照)。その結果、ステートレスプロキシは自身でメッセージを再送しない。ただし、受信したすべての再送をフォワードする (元のメッセージと再送を区別する能力がない)。さらに、リクエストをステートレスに処理するとき、要素は自身の 100 (Trying) または他の任意の暫定レスポンスを生成してはならない (MUST NOT)。

ステートレスプロキシはセクション 16.3 で説明されるとおりにリクエストを検証しなければならない (MUST)。

ステートレスプロキシはセクション 16.4 から 16.5 のリクエスト処理ステップに従わなければならない (MUST) が、以下の例外がある:

  o ステートレスプロキシは宛先セットから 1 つだけを選択しなければならない (MUST)。この選択はメッセージ内のフィールドとサーバーの時間不変プロパティのみに依存しなければならない (MUST)。特に、再送されたリクエストは処理されるたびに同じ宛先へフォワードされなければならない (MUST)。さらに、CANCEL および非ルーティング ACK リクエストは、それらに関連付けられた INVITE と同じ選択を生成しなければならない (MUST)。

ステートレスプロキシはセクション 16.6 のリクエスト処理ステップに従わなければならない (MUST) が、以下の例外がある:

  o 空間および時間を通じて一意の branch ID の要件はステートレスプロキシにも適用される。しかし、ステートレスプロキシはセクション 16.6 箇条書き 8 で説明されるように、乱数生成器を使用して branch ID の第 1 成分を計算することはできない。これは、リクエストの再送には同じ値が必要であり、ステートレスプロキシは元のリクエストと再送を区別できないためである。したがって、branch パラメータを一意にする成分は、再送されたリクエストがフォワードされるたびに同じでなければならない。したがって、ステートレスプロキシの場合、branch パラメータは、再送で不変であるメッセージパラメータの組み合わせ関数として計算されなければならない (MUST)。

ステートレスプロキシは、トランザクション間で branch ID の一意性を保証するために好きな手法を使用してもよい (MAY)。ただし、以下の手順が推奨される。プロキシは受信したリクエストの最上位 Via ヘッダフィールド内の branch ID を調べる。それがマジッククッキーで始まる場合、送信リクエストの branch ID の第 1 成分は、受信した branch ID のハッシュとして計算される。それ以外の場合、branch ID の第 1 成分は、受信したリクエストの最上位 Via、To ヘッダフィールドの tag、From ヘッダフィールドの tag、Call-ID ヘッダフィールド、CSeq 番号 (メソッドを除く)、および Request-URI のハッシュとして計算される。これらのフィールドのいずれかは、2 つの異なるトランザクション間で常に変化する。

o セクション 16.6 で指定された他のすべてのメッセージ変換は、再送されたリクエストの同じ変換になる結果をもたらさなければならない (MUST)。特に、プロキシが Record-Route 値を挿入するか Route ヘッダフィールドに URI をプッシュする場合、リクエストの再送に同じ値を配置しなければならない (MUST)。Via branch パラメータと同様に、これは変換が時間不変の設定または再送不変のリクエストのプロパティに基づいていなければならないことを意味する。

o ステートレスプロキシは、セクション 16.6 項目 10 でステートフルプロキシ向けに説明されるとおりに、リクエストをフォワードする場所を決定する。リクエストはクライアントトランザクションを介さずにトランスポート層に直接送信される。

ステートレスプロキシは再送されたリクエストを同じ宛先へフォワードし、それぞれに同じ branch パラメータを追加しなければならないため、それらの計算にはメッセージ自体からの情報と時間不変の設定データのみを使用できる。設定状態が時間不変でない場合 (たとえばルーティングテーブルが更新された場合)、変更の影響を受ける可能性のあるリクエストは、変更の前または後のトランザクションタイムアウトウィンドウに等しい間隔の間、ステートレスにフォワードされない可能性がある。その間に影響を受けるリクエストを処理する方法は実装の決定である。一般的な解決策は、それらをトランザクションステートフルにフォワードすることである。

ステートレスプロキシは CANCEL リクエストに対する特別な処理を実行してはならない (MUST NOT)。それらは上記の規則で他のリクエストと同様に処理される。特に、ステートレスプロキシは CANCEL リクエストに対して、他のリクエストに適用するのと同じ Route ヘッダフィールド処理を適用する。

セクション 16.7 で説明されるレスポンス処理は、ステートレスに動作するプロキシには適用されない。レスポンスがステートレスプロキシに到着したとき、プロキシは最初の (最上位) Via ヘッダフィールド値内の sent-by 値を検査しなければならない (MUST)。そのアドレスがプロキシと一致する場合 (このプロキシが以前のリクエストに挿入した値に等しい)、プロキシはそのヘッダフィールド値をレスポンスから削除し、次の Via ヘッダフィールド値で示される場所へ結果をフォワードしなければならない (MUST)。プロキシはメッセージボディを追加、変更、削除してはならない (MUST NOT)。別途指定がない限り、プロキシは他の任意のヘッダフィールド値を削除してはならない (MUST NOT)。アドレスがプロキシと一致しない場合、メッセージは黙って破棄されなければならない (MUST)。

16.12 プロキシルート処理の要約 (Summary of Proxy Route Processing)​

これに反するローカルポリシーがない限り、Route ヘッダフィールドを含むリクエストに対してプロキシが実行する処理は、以下のステップに要約できる。

  1. プロキシは Request-URI を検査する。それがこのプロキシが所有するリソースを示している場合、プロキシはそれを位置情報サービスを実行した結果に置き換える。それ以外の場合、プロキシは Request-URI を変更しない。

2. プロキシは最上位の Route ヘッダフィールド値内の URI を検査する。それがこのプロキシを示している場合、プロキシはそれを Route ヘッダフィールドから削除する (このルートノードに到達した)。

3. プロキシは、最上位の Route ヘッダフィールド値内の URI、または Route ヘッダフィールドが存在しない場合は Request-URI で示されるリソースへリクエストをフォワードする。プロキシは、リクエストのフォワード時に使用するアドレス、ポート、トランスポートを、[4] のプロシージャをその URI に適用して決定する。

リクエストの経路に strict-routing 要素が存在しない場合、Request-URI は常にリクエストのターゲットを示す。

16.12.1 例 (Examples)​

16.12.1.1 基本的な SIP 台形 (Basic SIP Trapezoid)​

このシナリオは基本的な SIP 台形、U1 -> P1 -> P2 -> U2 であり、両方のプロキシが record-routing を行う。フローは以下のとおり。

U1 は以下を送信する:

  INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]

P1 へ。P1 はアウトバウンドプロキシである。P1 は domain.com を管理していないので、DNS で検索してそこへ送信する。また、Record-Route ヘッダフィールド値を追加する:

  INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]
      Record-Route: `<sip:p1.example.com;lr>`

P2 はこれを受信する。P2 は domain.com を管理しているので位置情報サービスを実行し、Request-URI を書き換える。また、Record-Route ヘッダフィールド値を追加する。Route ヘッダフィールドはないので、新しい Request-URI を解決してリクエストの送信先を決定する:

  INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route: `<sip:p2.domain.com;lr>`
Record-Route: `<sip:p1.example.com;lr>`

u2.domain.com の呼び出し先はこれを受信し、200 OK で応答する:

  SIP/2.0 200 OK
Contact: sip:[email protected]
Record-Route: `<sip:p2.domain.com;lr>`
Record-Route: `<sip:p1.example.com;lr>`

u2 の呼び出し先は、ダイアログ状態のリモートターゲット URI を sip:[email protected] に、ルートセットを以下に設定する:

  (`<sip:p2.domain.com;lr>`,`<sip:p1.example.com;lr>`)

これは通常どおり P2 から P1 へ U1 へフォワードされる。ここで、U1 はダイアログ状態のリモートターゲット URI を sip:[email protected] に、ルートセットを以下に設定する:

  (`<sip:p1.example.com;lr>`,`<sip:p2.domain.com;lr>`)

すべてのルートセット要素に lr パラメータが含まれているため、U1 は以下の BYE リクエストを構成する:

  BYE sip:[email protected] SIP/2.0
Route: `<sip:p1.example.com;lr>`,`<sip:p2.domain.com;lr>`

他の任意の要素 (プロキシを含む) と同様に、最上位の Route ヘッダフィールド値内の URI を DNS で解決してリクエストの送信先を決定する。これは P1 へ向かう。P1 は Request-URI で示されるリソースを管理していないことに気付くので変更しない。Route ヘッダフィールドの最初の値が自身であることも見て取るので、その値を削除し、リクエストを P2 へフォワードする:

  BYE sip:[email protected] SIP/2.0
Route: `<sip:p2.domain.com;lr>`

P2 も Request-URI で示されるリソースを管理していないことに気付く (domain.com を管理しているが u2.domain.com ではない) ので変更しない。Route ヘッダフィールドの最初の値に自身がいることを見て取るので、それを削除し、Request-URI に対する DNS ルックアップに基づいて u2.domain.com へ以下をフォワードする:

  BYE sip:[email protected] SIP/2.0

16.12.1.2 strict-routing プロキシの通過 (Traversing a Strict-Routing Proxy)​

このシナリオでは、ダイアログが 4 つのプロキシを経て確立され、それぞれが Record-Route ヘッダフィールド値を追加する。3 番目のプロキシは RFC 2543 および多くの works in progress で指定される strict-routing 手順を実装している。

  U1->P1->P2->P3->P4->U2

U2 に到着する INVITE は以下を含む:

  INVITE sip:[email protected] SIP/2.0
Contact: sip:[email protected]
Record-Route: `<sip:p4.domain.com;lr>`
Record-Route: `<sip:p3.middle.com>`
Record-Route: `<sip:p2.example.com;lr>`
Record-Route: `<sip:p1.example.com;lr>`

U2 はこれに 200 OK で応答する。その後、U2 は最初の Route ヘッダフィールド値に基づいて以下の BYE リクエストを P4 へ送信する。

  BYE sip:[email protected] SIP/2.0
Route: `<sip:p4.domain.com;lr>`
Route: `<sip:p3.middle.com>`
Route: `<sip:p2.example.com;lr>`
Route: `<sip:p1.example.com;lr>`

P4 は Request-URI で示されるリソースを管理していないのでそのままにする。Route ヘッダフィールドの最初の値にある要素が自身であることに気付くので削除する。次に、現在最初の Route ヘッダフィールド値である sip:p3.middle.com に基づいてリクエストを送信する準備をするが、この URI に lr パラメータが含まれていないことに気付くので、送信前にリクエストを以下のように再フォーマットする:

  BYE sip:p3.middle.com SIP/2.0
Route: `<sip:p2.example.com;lr>`
Route: `<sip:p1.example.com;lr>`
Route: `<sip:[email protected]>`

P3 は strict ルーターなので、以下を P2 へフォワードする:

  BYE sip:p2.example.com;lr SIP/2.0
Route: `<sip:p1.example.com;lr>`
Route: `<sip:[email protected]>`

P2 は request-URI が自身が Record-Route ヘッダフィールドに配置した値であることに気付くので、さらに処理する前にリクエストを以下のように書き換える:

  BYE sip:[email protected] SIP/2.0
Route: `<sip:p1.example.com;lr>`

P2 は u1.example.com を管理していないので、Route ヘッダフィールド値の解決に基づいてリクエストを P1 へ送信する。

P1 は最上位の Route ヘッダフィールド値に自身がいることに気付くので削除し、以下の結果となる:

  BYE sip:[email protected] SIP/2.0

P1 は u1.example.com を管理しておらず、Route ヘッダフィールドもないので、Request-URI に基づいてリクエストを u1.example.com へフォワードする。

16.12.1.3 Record-Route ヘッダフィールド値の書き換え (Rewriting Record-Route Header Field Values)​

このシナリオでは、U1 と U2 は異なるプライベート名前空間にあり、プロキシ P1 を介してダイアログを開始する。P1 は名前空間間のゲートウェイとして動作する。

  U1->P1->U2

U1 は以下を送信する:

  INVITE sip:[email protected] SIP/2.0
Contact: `<sip:[email protected]>`

P1 は位置情報サービスを使用し、以下を U2 へ送信する:

  INVITE sip:[email protected] SIP/2.0
Contact: `<sip:[email protected]>`
Record-Route: `<sip:gateway.rightprivatespace.com;lr>`

U2 はこの 200 (OK) を P1 へ返す:

  SIP/2.0 200 OK
Contact: `<sip:[email protected]>`
Record-Route: `<sip:gateway.rightprivatespace.com;lr>`

P1 は、U1 にとって有用な値を提供するために Record-Route ヘッダパラメータを書き換え、以下を U1 へ送信する:

  SIP/2.0 200 OK
Contact: `<sip:[email protected]>`
Record-Route: `<sip:gateway.leftprivatespace.com;lr>`

その後、U1 は以下の BYE リクエストを P1 へ送信する:

  BYE sip:[email protected] SIP/2.0
Route: `<sip:gateway.leftprivatespace.com;lr>`

これを P1 は以下のように U2 へフォワードする:

  BYE sip:[email protected] SIP/2.0