ユニバーサル プラグ アンド プレイ (UPnP) クライアント サポート
発行 : 2001 年 8 月
トピック
UPnP クライアント サポートの概要
UPnP クライアント サポート アーキテクチャ
UPnP クライアント サポートの初期化と動作
UPnP クライアント サポートのトラブルシューティング
まとめ
参考資料
UPnP クライアント サポートの概要
ネットワークの構築、構成、トラブルシューティングは、日々確実に簡略化されています。このことは、IT 専門グループがない場合や中小企業や家庭に小規模なネットワークを構築する場合など、ネットワーキングをサポートするうえで不可欠の技術発展と言えます。
また、ここ数年、携帯電話、PDA デバイス、タブレット デバイス、テレビなど、デジタル情報交換を可能にするデバイスの数が増加しています。これまでコンピューティング デバイスではなかったデバイスにも、一般的になったデジタル データ形式を処理するなどの目的でコンピュータ技術が取り入れられるようになりました。コンピューティング技術が導入されているデバイスは、サーモスタットからステレオ システムまで多岐にわたります。コンピューティングおよびネットワーキング技術の実装コストが低下したことで、そうした技術の普及が進み、既存のデバイスにコンピューティング機能や、場合によっては信頼性の高いネットワーキングを組み込むことが可能になりました。
この進歩の第 2 段階は、これらのデバイスを人間には見えない形で互いに接続することです (この段階はすでに始まっています) 。これによって、リモート コントロールやリモート監視、デジタル データの共有、複数のデバイスや場所から送られてくるデータの統合など、さまざまな新技術が実現されます。ただし、このような技術には通信に関する規格とプロトコルが必要です。これこそ UPnP が果たす役割です。
Windows は必ずしも必要ありませんが、UPnP サポートを搭載した Windows システムは、この新たなデバイス ネットワークにおいて、中央コントローラやゲートウェイなど、さまざまな役割を果たすことができます。
UPnP のプロトコルと要件については、UPnP フォーラムの Web サイトに掲載された文書や仕様書に詳しい説明があります。ここでは、Windows プラットフォームでの UPnP の実装について説明します。
UPnP は、既存のプロトコルおよび技術に対応しています。たとえば、UPnP ではベース プロトコルとして TCP/IP、UDP/IP、HTTP を使用しています。これらのベース プロトコルに加え、それらを基礎とするプロトコルがいくつかあり、UPnP のさまざまな "ステップ" つまりフェーズを実装しています。
UPnP ネットワークでは、図 1 に示すようにいくつかのコンポーネント タイプと責任が定義されています。コンポーネントには、コントロール ポイント、デバイス、サービスなどが含まれます。コントロール ポイントとは、UPnP ネットワークに属するクライアントのことで、デバイスとサービスを制御します。Windows プラットフォームでは、通常、特定のタイプのデバイスまたはサービスを制御するアプリケーションがコントロール ポイントとなります。
デバイスは、1 つまたは複数のサービスが属する論理コンテナで、他のデバイスを含むこともできます。デバイスとサービスは、その最低機能を表すタイプによって識別されます。
Windows は UPnP ネットワークに参加し、Windows システムのユーザーが使用できるネットワークに接続されたデバイスやサービスを UPnP 対応にすることができます。Windows は、UPnP によって接続されたデバイスやサービスを制御するコントロール ポイント アプリケーションの構築および実行用プラットフォームとしても利用できます。インターネット接続の共有 (ICS) サービスは、UPnP を使用して、そのサービス自体が使用可能であることをネットワーク上の UPnP クライアント コンピュータに知らせます。
Windows が同時に複数のコントロール ポイント アプリケーションのホストとなることもあります。多くのさまざまな個人や企業がこうしたアプリケーションを作成することも考えられます。コントロール ポイント アプリケーションの Windows サポート アーキテクチャによって、どの UPnP にも共通するコードを書く必要性が小さくなります。そうした共通コードが Windows に多数含まれているため、システムの安定性を実装および改善するための努力が少なくてすみます。
UPnP ネットワーキングのステップ
Windows に UPnP サポート アーキテクチャを実装するためには、UPnP ネットワーキングのステップのサポートが必要です。
-
アドレス指定
UPnP ネットワーキングのステップ "0" と呼ばれることもあります。ネットワーク内のデバイスが自己のネットワーク レイヤ アドレスを取得するために必要なステップです。Windows ネットワーキング スタックのコンポーネントである TCP/IP (および UDP) と DHCP がアドレス指定のサポートを提供します。アドレス指定には、DHCP が割り当てるアドレスが使用されます。ネットワークに DHCP サポートがない場合は、自動的に割り当てられる IP アドレス、つまり AutoIP が使用されます。
-
検出
コントロール ポイントは、UPnP の検出によってネットワーク上で目的のデバイスを見つけることができます。デバイスは存在することを定期的にアナウンスし、要求されたときには UPnP で定義されたデバイス タイプとサービス タイプをアナウンスします。コントロール ポイントがデバイスとサービスのアナウンスを要求することもできます。これらの機能は、UPnP にはユニキャスト形式とマルチキャスト形式の HTTP プロトコルを使用すると定義されています。検出ステップは、SSDP (Simple Service Discovery Protocol) と GENA (Generic Event Notification Architecture) という 2 つのプロトコルに定義されたメソッドとヘッダーも利用します。GENA はその一部分のみ使用され、UPnP の将来のバージョンでは使用されない可能性があります。
検出ステップにおいて UPnP コントロール ポイントをサポートするために、Windows はコントロール ポイントがデバイス タイプとサービス タイプに基づいてデバイスまたはサービスを検索するためのインターフェイスを提供する必要があります。デバイスはいつでもネットワークに追加できます (自らアナウンスします)。追加されたデバイスは定期的にアナウンスを更新します。デバイスがネットワークから削除されることもあり、そのとき通知する場合と通知しない場合があります。Windows の検出インターフェイスでは、デバイスの存在の変化を知らせる通知と新しいデバイスの追加を知らせる通知も可能です。
つまり、Windows は、検出をサポートするために、複数の動的コントロール ポイントおよびデバイスに対してインターフェイスを提供するとともに、これらのインスタンスを管理し、GENA と SSDP を実装する必要があります。
-
記述
検出によって、ネットワーク上のデバイスに関する情報が収集されます。この情報をもとに、検出されたデバイスが使用可能かどうかを確認し、同種のデバイスの中から使用するデバイスを選択することができます。この決定を行った後で、デバイスとそのサービスにアクセスし、制御するために、さらに情報が必要となります。デバイスの詳細な記述が必要です。UPnP では、このようなデバイスの記述を UPnP フォーラムが定義した形式の XML (Extensible Markup Language) ドキュメントとして提供します。この記述には、デバイスとそのサービスに関する情報が豊富に含まれており (デバイスの記述にサービスの記述への参照が組み込まれています)、以降の UPnP ネットワーキング ステップで説明する、デバイスの実行に必要な情報もあります。
Windows はコントロール ポイント (クライアント) アプリケーションの説明もサポートする必要があります。コントロール ポイント アプリケーションは、実装されたアーキテクチャにおいて説明の XML ドキュメントを要求、受信、解析する機能を備えていなければなりません。このドキュメント管理の処理は、すべて標準の HTTP メソッドを使用して実装できます。
-
制御
デバイスとそのサービスの記述を取得すると、コントロール ポイントはアクションと呼ばれる公開されたメソッドを呼び出して、サービスに対して実行するアクションを要求できます。サービスの記述には、要求できるアクションとそれに関連するパラメータの情報があります。これらのアクションを呼び出すと、UPnP サービスに対する一種のリモート プロシージャ コール インターフェイスとなります。アクションの要求および応答は SOAP (Simple Object Access Protocol) でフォーマットされます。アクションと同じように、UPnP の制御ステップはサービスが公開する状態変数をコントロール ポイントが照会する方法も定義します。ただし、この機能より状態変数を取得する汎用サービス アクションの方が好まれています。この目的には SOAP も使用されます。
Windows に実装された UPnP は、コントロール ポイント アプリケーションが使用するネットワーク デバイスの制御をサポートしなければなりません。コントロール ポイント アプリケーションはアクション リクエスタです。実装された UPnP は、アプリケーションからのメソッド要求をネットワーク上のデバイスへの SOAP 要求に変換する必要があります。戻りパラメータと結果を解析し、アプリケーションに渡します。
-
イベント生成
UPnP サービスは、サービスの実行時の状態を表す変数を含むことがあります。UPnP サービスは、これらの変数の値が変更されたときには新しい値を公開でき、コントロール ポイントはサービスにサブスクライブすることによって変数値の変更通知を要求できます。通知は GENA メソッドによって送信されます。
コントロール ポイントがネットワーク上の特定のサービスへのサブスクライブを要求し、コールバックを登録するためのインターフェイスを提供する必要があります。実装された UPnP は、サブスクライブ要求をサブスクライブするサービスへのプロトコル要求に変換します。実装された UPnP に GENA 通知として送信された状態変数の変更を、登録されたコールバックに渡す必要があります。
-
プレゼンテーション
これが UPnP ネットワークの最終ステップであり、デバイスに HTML ベースのユーザー インターフェイスを提供します。このインターフェイスは、デバイス ステータスの制御や表示に使用できます。そのために、デバイスの記述にはプレゼンテーション URL が含まれています。
コントロール ポイント サポートでは、「記述」のところで述べたとおり、記述ドキュメントの要素を提供します。標準 HTTP インターフェイスおよびメソッドを使用して、デバイス プレゼンテーション ページを取得できます。
UPnP の動作
UPnP は、ネットワーキングを単純化することを目的としており、ネットワークに追加されたデバイスを簡単に検索できるという利点もあります。Windows ME や Windows XP などの UPnP 対応のオペレーティング システムを使用している場合は、新たに追加された UPnP デバイスが自動的に [マイ ネットワーク] に表示されます。
メモ : Windows XP (および Windows Me) では、この機能は既定で有効になりません。不要なネットワーク トラフィックが発生し、UPnP の利点が損なわれるからです。また、検出されたデバイスを簡単に検索できるようにデバイスの表示方法を改良することもできます。
Windows XP では、UPnP デバイスを [マイ ネットワーク] に表示する UI コンポーネントをオプションのネットワーキング コンポーネントとしてインストールできます (Windows ME では、UPnP 自体がオプションのコンポーネントです)。この UI コンポーネントをインストールする手順は次のとおりです。
-
[スタート] ボタンをクリックし、[コントロール パネル] をクリックします。次に [ネットワーク接続] を選択します。
-
[ネットワーク接続] で、メニュー バーから [詳細設定]、[オプション ネットワーク コンポーネント] を選択します。
-
[ネットワーク サービス] を選択し、[詳細] をクリックします。
-
[ユニバーサル プラグ アンド プレイ] チェック ボックスをオンにします。
-
[OK] をクリックし、[Windows コンポーネント] ダイアログ ボックスで [次へ] をクリックします。UPnP UI のインストールが完了します。
これで、デスクトップから [マイ ネットワーク] を開くと、UPnP 対応のデバイスがネットワーク上に存在するかどうか確認できます。ローカル ネットワーク上に UPnP デバイスがある場合は、デバイス タイプに基づく汎用アイコンで [マイ ネットワーク] に表示されます。[マイ ネットワーク] からデバイスを呼び出すと、そのプレゼンテーション ページが表示されます。
この動作を確認するためには、ネットワーク上に UPnP デバイスが存在していなければなりません。この場合の対応策は 2 つあります。1 つ目は、UPnP Device Development Kit のサンプル デバイスを使用する方法です。このサンプル デバイスは Windows 2000 に IIS をインストールした環境と Windows XP のどちらでも動作します。ただし、SSDP サービスを停止することが必要です。これは、サンプル デバイスと SSDP サービスが同じポートを使用するため、競合が発生するからです。サンプル デバイスには、Windows 2000 または Windows XP のコンピュータがもう 1 台必要となります。UPnP Device Development Kit は次のサイトからダウンロードできます。
http://msdn.microsoft.com/en-us/library/aa382303 (英語版)
もう 1 つの方法は、UPnP 対応のデバイスを購入することです。UPnP 対応のデバイスは近々発売される予定です。Windows XP の ICS (Internet Connection Sharing) などのインターネット ゲートウェイ デバイスは UPnP を使用した NAT Traversal and Firewall 構成をサポートする場合もありますが、このようなデバイスは [マイ ネットワーク] には表示されません。
UPnP クライアント サポート アーキテクチャ
Windows に UPnP を実装するために必要な要素の大部分は、TCP/IP や HTTP などの標準のプロトコル スタックおよびコンポーネントから得られます。これらのコンポーネントに加え、UPnP が使用する SSDP や GENA などのプロトコルのサポートを追加する必要があります。これらのプロトコルのインターフェイスをコントロール ポイント アプリケーション用に定義します。アーキテクチャは、同時に実行される複数のコントロール ポイント アプリケーションをサポートおよび管理するように設計されている必要があります。
Windows に実装された UPnP は、2 つのアーキテクチャで説明できます。1 つ目のアーキテクチャはコンポーネント アーキテクチャで、UPnP の実装を構成するソフトウェア コンポーネントと、それらのコンポーネントとオペレーティング システムとのインターフェイス方法を規定します。もう 1 つのアーキテクチャは、それらのコンポーネントの COM アーキテクチャで、コンポーネントとそれに基づくアプリケーションの対話を理解するのに役立ちます。コンポーネント アーキテクチャ、COM アーキテクチャの順に説明します。
コンポーネント アーキテクチャ
図 2 は、Windows XP の UPnP に対するクライアント サイド (コントロール ポイント) のサポートを実装するコンポーネントを示しています。それらのコンポーネントと対話するほかのネットワーキング コンポーネントも含まれています。UPnP 固有のコンポーネントとその責任について以下で説明します。
図 2 に示すコンポーネントは次のような働きをします。
upnp.dll コントロール ポイント アプリケーション用の Windows UPnP API と COM オブジェクトを公開する DLL です。UPnP Development Kit とプラットフォーム SDK の説明を参照してください。検出を必要とする要求は SSDP プロトコルを呼び出し、それによって ssdpapi.dll に渡されます。制御要求とその応答は SOAP メッセージであるため、別の経路をたどり、msxml.dll が提供する XMLDOM (XML Document Object Model) インターフェイスと WinInet インターフェイスを経由します。XML DOM インターフェイスは、XML ドキュメントの管理において必要になった場合にも使用されます。XML DOM は、ネットワーク アクセスが必要な場合に WinInet API を使用するように実装されます。upnp.dll は、CoInternetCombineUrl など、urlmon.dll が提供するいくつかのユーティリティ インターフェイスも使用します。upnp.dll は、すべての UPnP アプリケーションにロードされます。
ssdpapi.dll SSDP API を公開する DLL で、upnp.dll がクライアントの検出要求を処理するために使用します。アプリケーションは Device Finder COM オブジェクトを使用して、検索メッセージをネットワークに送信します。Device Finder が upnp.dll を呼び出すと ssdpapi.dll が呼び出され、最終的に Windows ソケットへと到達し、ネットワークに検索メッセージを送信します。ssdpapi.dll は検索タイマも実装し、すべての UPnP アプリケーションにロードされます。ssdpapi.dll は ssdpsrv.dll と連携し、デバイス キャッシュ、デバイス アナウンスの通知、イベント通知などの処理を実行します。
ssdpsrv.dll この DLL (Windows ME では ssdpsrv.exe という名前) は、SSDP Discovery サービスを Windows サービスの 1 つとして実装します。検出キャッシュがここに作成されます。このキャッシュにアクセスするには (クエリと更新のいずれの場合も) RPC を使用します。ssdpsrv はデバイスの存在アナウンスの受信を管理します。キャッシュを更新し、それらの通知を検索要求が未処理であるクライアントに渡します。このコンポーネントは、サービスを開くクライアントのイベント サブスクリプションも処理します。SSDP Discovery サービスは、クライアントからイベント コールバックの登録を受け取り、それらをサブスクリプション要求に変換して、イベント通知の発生を監視します。イベント通知が発生した場合は、それを登録されたコールバックに渡します。ssdpsrv.dll は Windows ソケットと WinInet インターフェイスを介してネットワークと通信します。
upnpui.dll ( 図には示されていません ) UPnP のシェル インターフェイスの役割を果たす DLL です。upnpui.dll は既定でインストールされないため、オプションのネットワーキング コンポーネントとしてインストールする必要があります。upnpui.dll はシェル拡張であり、ログオン時にエクスプローラによってロードされます (インストールされている場合)。upnpui.dll は UPnP アプリケーションでもあるため、upnp.dll と ssdpapi.dll をロードします。upnpui.dll によって、UPnP デバイスが [マイ ネットワーク] に表示されます。そのために、upnpui.dll は Windows エクスプローラに登録され、エクスプローラによって呼び出されます。この DLL はタスクバーの通知領域も管理します。
UPnP COM アーキテクチャ
図 3 に、コントロール ポイント アプリケーションをサポートする COM オブジェクト アーキテクチャを示します。
図 3 にはコールバック インターフェイスが示されていませんが、非同期検索または記述ドキュメントのロードを使用する場合や、サービスからイベント通知を受け取る場合は、このインターフェイスも実装する必要があります。この図に示されたインターフェイスは、Windows に実装されているものです。
UPnP を活用するためには、コントロール ポイント アプリケーションがまず Device Finder のインスタンスを作成しなければなりません。この Device Finder オブジェクトを使用すると、デバイスの同期検索または非同期検索を実行できます。結果の形式は検索方法によって異なり、デバイス コレクションまたは単一のデバイス オブジェクトとして返されます。デバイス コレクションから個々のデバイス オブジェクトを取り出すことができます。デバイス オブジェクトも Description Document インターフェイスによって公開されるメソッドを使って取得できます。
デバイス オブジェクトを取得すると、コントロール ポイントはそのオブジェクトのメソッドを使用して特定のデバイスのプロパティを取得できます。さらに、サービス コレクションを取得し、そこから個々のサービス オブジェクトを取得することも可能です。サービス オブジェクトを取得すると、そのメソッドを使用して、イベント通知を要求したりコントロール アクションを実行することができます。
これらのオブジェクトに対してメソッドを呼び出すことによって、「コンポーネント アーキテクチャ」の節で説明したコンポーネントに対する要求が発生することがあります。図を見るとわかるとおり、COM アーキテクチャは upnp.dll に実装されます。
UPnP クライアント サポートの初期化と動作
この節では、前述したコンポーネントの動作に焦点を当てます。UPnP コントロール ポイント アプリケーションまたはホストされるデバイスによって実行される各種操作において、それらのコンポーネントがいつどのように呼び出されるかを説明します。まず各コンポーネントがいつどのように初期化されるのかを明らかにし、次にそれらのコンポーネントが UPnP 操作において果たす役割について説明します。
UPnP クライアント サポートの初期化
この節では、UPnP コンポーネントの初期化について説明します。
SSDP Discovery サービス (SSDPSRV) の初期化
SSDP Discovery サービスは、Windows XP のデマンド スタート サービスとして実行されます。つまり、このサービスは初期化関数 SSDPAPI が呼び出されると自動的に起動します。このコンポーネントの役割には次のようなものがあります。
-
ネットワーク上の使用可能なデバイスのキャッシュを作成し、その管理作業として、アナウンスをリッスンし、クライアント検索の結果に基づいてキャッシュの内容を更新する。
-
サブスクライブ要求および再サブスクライブ要求を定期的に送信し、受信したイベント通知を転送することによって、クライアントのイベント サブスクリプションを管理する。
その他の UPnP コンポーネントは、これらのサービスで SSDPSRV を利用します。たとえば、SSDP クライアント API は、RPC を使用してデバイス キャッシュをチェックしてから検索要求を送信し、検索の結果に基づいてキャッシュを更新します。
Windows XP を既定でインストールすると、UPnP がインストールされ、SSDP Discovery サービス (SSDPSRV) はオンデマンド スタート サービスとして設定されます。SSDPSRV が起動時に行う最初の操作は、サービス コントロール マネージャにサービス コントロール ハンドラを登録することです。これは、サービスが行う通常の操作で、サービスの停止や開始などのサービス制御要求を処理するために必要なものです。
次に、SSDP Discovery サービスが以下の手順で初期化を進めます。
SSDP Discovery サービスが自ら使用するタイマ キューを作成します (CreateTimerQueue() を使用)。このキューには、次のようなさまざまな目的に使用するタイマが作成されます。
-
ホストされるデバイスのデバイス アナウンスを送信する。
-
デバイス削除通知 (SSDP 終了メッセージ) を再送信する。
-
SSDP Cache Control に基づいてキャッシュの内容を期限切れにする。
-
クライアントのイベント サブスクリプションの更新。
-
クライアント検索の応答を送信する。
次に、SSDP Discovery サービスはシステム上で使用可能なネットワーク インターフェイスのリストを初期化します。このリストは、ICF (Internet Connection Firewall) とインターネット接続の共有 (ICS) が UPnP を利用してポート マッピングや NAT トラバースなどのサービスを提供するときに使用するインターフェイスのリストです。セキュリティ上の理由から、ICS は外部 (インターネット) インターフェイスでは UPnP を使用しません。
リスト内のインターフェイスに変更が生じたときには、それを知らせるイベントが発生します。スレッド プール内の待ちスレッドがこのイベントを受け取り、コールバックによってインターフェイス リスト内の IP アドレスが再構築されます。このイベントは IPHelper (Internet Protocol Helper) API の NotifyAddrChange で使用されるもので、インターフェイスと IP アドレスのマッピングに変更が生じたときに発生し、IP アドレス リストを更新するコールバックをトリガします。このリストの初期の作成と変更時の更新においては、IPHelper API の GetAdaptersInfo も使用されます。
SSDP Discovery サービスは、次に 2 つのリンクされたリストを初期化します。このコンピュータの有効なネットワークのリストと、ピア システムとの間で確立されている接続のリストです。これらのリストは後でデータが追加され、使用されます。
SSDP Discovery サービスは次に Windows ソケット インターフェイスを初期化します。そのために、WSAStartup を呼び出します。推奨バージョンは 2.0 で、最低でもバージョン 1.1 が必要です。バージョン ネゴシエーションが成功すると、SSDP Discovery サービスは SSDP 検出要求の標準宛先アドレス 239.255.255.250:1900 を含むソケット アドレス構造を初期化します。このアドレスは、検出メッセージを送信する必要がある場合にリモート アドレスとして使用されます。ワイルドカード ローカル アドレスとイベント ポート (5000) を宛先とするイベント通知を受信するためのソケットがオープンされます。このソケットがリッスンされ、イベント生成のために TCP 接続を受け入れるテンプレートとして使用されます。
SSDP Discovery サービスは RPC によってクライアントにインターフェイスを公開します。そのため、RPC サーバー サイドを初期化する必要があります。次に、この初期化が行われます。
このサービスの停止を同期化する際に使用される手動リセット イベントが作成されます。SSDP Discovery サービスが停止されると、このイベントが発生し、それをメイン スレッドが受け取ります。
RPC のサーバー サイドが RPC に登録します。このとき、RpcServerUseProtSeqEp を呼び出してローカル プロシージャ コールをプロトコル シーケンスとして指定します。これは、ローカル アプリケーションとローカル サービスは SSDP Discovery サービスにアクセスできるが、リモート システムはこのサービスを使用できないことを意味します。次に、RPC サーバーが RpcServerRegisterIf を呼び出してインターフェイスを登録します。SSDP Discovery サービスは、デバイスの公開、イベントおよびデバイスの通知、デバイス キャッシュの管理、およびホストされるデバイスとしての ICS のサポートを実行するメソッドを RPC によって提供します。
次に、SSDP Discovery サービスは、ネットワークのリンク リストにデータを追加します。この処理では、Windows Sockets Ioctl コール SIO_ADDRESS_LIST_QUERY を使用して、コンピュータ上の有効な IP アドレスのリストを取得します。このリストを解析し、NULL、0、非 IP アドレスなどの無効なアドレスを削除します。残ったアドレスがプロトコル固有のソケット アドレス構造に取り込まれ、SSDP ネットワーク構造に追加されます。SSDP ネットワーク構造には、ネットワーク状態とそのネットワークに対してオープンしているソケットも含まれます。この構造に含まれるソケットは、次にオープンされると、送受信用の SSDP マルチキャスト グループに加わります。 このリストに有効なネットワークがない場合でも、ループバック アドレスだけは追加されます。これらの "ネットワーク" は、このコンピュータの有効なネットワーク リンク リストに追加されます。このリストは、どのネットワークで受信または送信するかを決定するときに使用されます。
このとき、RPC のサーバー サイドは RpcServerListen を呼び出して RPC を受信します。これで、サーバー側ではクライアントからの接続要求を受け入れる準備が整いました。
次に、SSDP Discovery サービスはネットワークから受け取ったデータを処理するオブジェクトを作成します。このオブジェクトには、処理の開始を知らせるイベント、サービスの停止を知らせるイベント、および 1 つのスレッドが含まれます。このスレッドは、作成された後、受け取ったデータを処理するルーチンを実行するように設定されます。このスレッドは両方のイベントを待ち、処理の開始を知らせるイベントが発生した場合は、受け取ったデータを処理します。サービスの停止を知らせるイベントが発生した場合は、このスレッドが完了します。
SSDP Discovery サービスは隠しウィンドウを作成し、そこからウィンドウ メッセージを受信して転送します。このウィンドウは、主として受け取った Windows ソケット メッセージの処理に使用されます。このウィンドウ ハンドルは、WSAAsyncSelect の呼び出しで使用されます。WSAAsyncSelect では、作成済みのネットワーク リストに属す各ネットワークに対応するイベントとして FD_READ が指定されます。出力先が SSDP Discovery サービスのウィンドウに指定されたメッセージは、SSDP メッセージを受信したことを示します。その結果、このサービスはすべてのネットワークでリッスンし、SSDP メッセージを受信します。
次に、イベント通知用に作成されたソケットが初期化されます。このソケットにリッスン メソッドが登録され、その後に TCP データ (または接続) を受信したことを示すメッセージが指定された WSAAsyncSelect が登録されます。このソケットでの選択に関係する登録済みイベントは、FD_ACCEPT、FD_CONNECT、FD_READ、および FD_CLOSE です。
SSDP Discovery サービスは、インターフェイス リスト内のインターフェイスまたはその IP アドレスの変更を検出できなければなりません。このような変更が発生したときには、ネットワーク リストを再計算し、ソケットを再作成し、選択メソッドを呼び出す必要があります。そのために SSDP Discovery サービスは、もう 1 つイベントを作成し、スレッド プール内のスレッドでこのイベントとコールバック ルーチンを待ち、そのイベントを指定して NotifyAddrChange (IPHelper API) を呼び出します。このイベントが発生すると、コールバックがネットワーク リストを再構築し、ソケットを再作成して、リッスン メソッドと選択メソッドを再登録します。
最後に、サービス コントロール マネージャにおいて、SetServiceStatus の呼び出しによって SSDP Discovery サービスのステータスが "running" に更新され、メイン スレッドでこのサービス プロセスのメッセージ ループが実行されます。
この時点で、SSDP Discovery サービスが稼働し、いくつかのスレッドが作成され、さまざまなタスクを実行しています。メイン スレッドがメッセージ ループを実行し、2 つのスレッドがアドレス変更通知を待ち、別のスレッドがデータを処理するために Receive Data Manager で Work イベントを待ち、RPC スレッドがクライアント API コールを待っています。
SSDP クライアント (UPNP.DLL 、 SSDPAPI.DLL) の初期化
アプリケーションが UPnP クライアント API を使用すると、UPNP.DLL と SSDPAPI.DLL がそのアプリケーションのアドレス空間にロードされます。これらの DLL は UPnP クライアント (コントロール ポイント) DLL です。すでに説明したように、UPNP.DLL は COM インターフェイスを実装し、SSDPAPI.DLL によって公開される SSDP クライアント API を利用して、SSDP ネットワークの利用状況を監視します。UPNP.DLL は、上図のアーキテクチャに示す URLMON.DLL と MSXML.DLL によって公開される API とインターフェイスも使用します。それらの API とインターフェイスがどのように使用されるかについては、以降の節で詳しく説明します。
アプリケーションが UPNP.DLL によって実装された COM オブジェクトをインスタンス化すると (通常は最初に Device Finder オブジェクトがインスタンス化されます)、UPNP.DLL の初期化が開始されます。この初期化は UPnP クライアント操作の中で行われるため、その操作に関する節で (この初期化を開始させるアクションとともに) 詳しく説明します。
SSDPAPI.DLL (SSDP クライアント) は、API がそのクライアントから呼び出されるのに備え、準備作業を行います。そのようなクライアントの 1 つに UPNP.DLL があります。SSDP クライアント API の初期化は、公開された SsdpStartup の呼び出し (同時に SsdpCleanup も呼び出される) によって開始されます。SsdpStartup は SSDP クライアントのグローバル状態を初期化するもので、どの API より先に呼び出されます。この初期化には、特定のクライアントにのみ有益な処理も含まれます。SsdpStartup が呼び出されると、以下の処理が実行されます。
RPC クライアント (SSDPSRV の RPC サーバー インターフェイスを使用する) を初期化する内部ルーチンが呼び出されます。このルーチンでは、RPC プロトコル シーケンスが LRPC に設定され、エンドポイントが SSDPSRV に設定されます。実際にサーバーに接続する前に、さらにいくつかの処理が実行されます。
クライアント通知の登録を保存するためのリンク リストが作成され、このリストへのアクセスを保護するためのミューテックスも作成されます。このリストには後でクライアント通知の登録が追加され、要求と一致する実際の追加がクライアントに送信されます。次に、CreateTimerQueue によってタイマ キューが作成されます。このキューには、SSDP 検索要求のタイムアウトに使用されるタイマが格納されます。
SSDP クライアント API は、検索要求を送信し、応答を受信するときに、Windows ソケットからネットワークへの直接接続を使用します。その準備のために、WSAStartup を呼び出し、SSDP 要求の宛先アドレスとポート (239.255.255.250/1900) が収められたアドレス構造を割り当てます。
SSDP クライアント API は、内部スレッド同期のために 2 つの同期化オブジェクトを作成します。1 つ目の Event オブジェクトは、そのクライアントの通知ループ スレッドが作成されたときに発生します。他の通知スレッドは、このイベントが発生するのを待ちます。これによって、それらの通知を検索するスレッドが起動するまで、通知を受け取るための呼び出しは行われません。これについては、通知の登録に関する項で詳しく説明します。もう 1 つの同期化オブジェクトは、共有アクセスまたは排他アクセスで取得でき、このオブジェクトによって、通知用に登録されたコールバックは登録が完了するまで呼び出されなくなります。そのために、登録プロセスはこのオブジェクトを共有アクセスで取得します。コールバックは排他アクセスを取得しようとしますが、共有アクセスが解放されるまで待たなければなりません。
最後に、SSDP クライアントが RpcStringBindingCompose と RpcBindingFromStringBinding を呼び出し、SSDPSRV の RPC コールを実行するためのバインドを取得します。
この時点で、SSDP クライアント API は以下の作業を完了しています。
-
SSDP Discovery サービスへの RPC バインド ハンドルを作成する。
-
未処理の通知コールバックのリストを初期化する。
-
検索要求をタイムアウトにするタイマのキューを作成する。
-
2 つのスレッド同期化オブジェクトを初期化する。
UPnP クライアント サポートの動作
さまざまな UPnP コンポーネントがどのように対話するのかを明確にするために、各種 UPnP 操作における処理の内容を全体的に捉えてみます。Windows XP (または Windows ME) に実装された UPnP クライアントは、UPnP デバイスの検索および制御に必要な COM オブジェクトとインターフェイスをすべて持っています。アプリケーションの形式には、HTML に埋め込まれたスクリプト、Visual Basic プログラム、C++ プログラムがあります。
この節では、クライアントのデバイス検索要求、デバイスの記述の取得要求、サービス イベントへのサブスクライブ要求、サービスの制御要求を UPnP がどのように処理するのかについて説明します。これらの操作を Visual Basic と C++ で実行する例は Windows XP SDK に含まれているので、ここでは説明しません。ここでは、UPnP の実装に対する影響について説明します。
デバイスの検索
クライアント アプリケーションが使用可能なデバイスを見つけるときには、まず Device Finder COM オブジェクトを作成しなければなりません。この Device Finder オブジェクトを使用して、同期検索または非同期検索を実行します。Device Finder を割り当てたときには、予想される検索要求に応じた初期化の処理がいくつか実行されます。
ファインダとその関連順序を保存するためのリンク リストが作成されます。このリストが実際に使用されるのは、検索要求を処理するときです。ファインダ オブジェクトは upnp.dll に実装されますが、SSDP コンポーネントのサービスを必要とします。新たに割り当てられたファインダは SsdpStartup で SSDPAPI クライアント DLL を呼び出し、初期化に関する節で説明したように、この DLL を初期化します。
クライアントが使用するデバイス ファインダ インターフェイスが用意されたので、検索を同期または非同期で実行できます。非同期検索の場合は、Device Finder Callback オブジェクトが提供され、検索結果は即時にクライアントに返されます。このオブジェクトは、IUPnPDeviceFinderCallback インターフェイスまたは IDispatch インターフェイスを実装しなければなりません。このコールバック オブジェクトのメソッドが結果をクライアントに送り、最後に検索が完了したことを知らせます。最初の検索が完了した後もコールバックは存続し、デバイスの追加や削除を知らせるアナウンスが発生した場合には再び呼び出されます。この状態は非同期検索が取り消されるまで維持されます。
同期検索要求の場合、クライアントから提供されるコールバックは必要ありませんが、UPnP は固有のコールバック オブジェクトを割り当て、同期検索を非同期検索に変えます。同期検索要求において検索の完了が UPnP に通知されると、非同期検索が取り消され、結果が返されます。どちらの検索も結果的に非同期検索となるため、ここでは UPnP による非同期検索の実装について説明します。
CreateAsyncFind が呼び出されると、UPnP が使用する "プライベート" デバイス ファインダ コールバック オブジェクトが割り当てられ、デバイス ファインダ リストに置かれます。このオブジェクトが初期化され、検索に関連する機能が追加されます。検索の対象となるリソースの識別子、検索要求に関連するタイマを格納するタイマ キュー、検索結果を返すときに呼び出すインターフェイス (クライアント提供のコールバック オブジェクト) へのポインタなどです。
プライベート コールバック オブジェクトは、プライベート コールバック ヘルパをグローバル インターフェイス テーブルに登録します。検索状態が "initialized" に設定され、検索を識別するクッキーがクライアントに返されます。
検索を実行するためには、クライアントが StartAsyncSearch メソッドを使用する必要があります。CreateAsyncFind が返したクッキーは、StartAsyncSearch メソッドにパラメータとして渡され、デバイス ファインダ リストでコールバック オブジェクトを見つける手段として使用されます。初期化が完了して、検索が開始されていないことが確認されます。
この時点で検索状態は "started" に設定され、SSDPAPI の呼び出しによって検索が開始されます。この SSDPAPI は、検索の種類を表すパラメータ、検索の強制実行 (ネットワークに接続する) を示すブール値、コールバック ルーチン (UPnP.DLL に対してグローバル)、コンテキストとしてのプライベート コールバック オブジェクトへのポインタを含んでいます。このメソッドからハンドルが返され、プライベート コールバック オブジェクトとともに保存されます。
SSDPAPI は、検索結果を表すオブジェクト、このクライアントからの複数の検索要求を管理するオブジェクト、現在アクティブな検索結果を保存するリスト (検索要求が保存される) を割り当てます。検索要求の完了を知らせるイベントが生成されます。SSDP 検索要求は、渡された情報に基づいて作成されます。次に、Windows ソケットと IPHelper によって、システム上で使用可能なインターフェイスのリストが作成され、検索要求を送信するために各インターフェイスでソケットがオープンされ、そのソケットがインターフェイスに関する情報とともにリストに保存されます。このリストにはループバック インターフェイスも含まれています。
検索状態が "discovering" に設定され、検索が開始されます。SSDP クライアント API は、まず SSDP Discovery サービスが管理しているアナウンス キャッシュをチェックする RPC を送信します。このキャッシュ チェックは RPC によって SSDP Discovery サービスに渡されます。このサービスは、SSDP アライブ通知または終了通知の受信またはクライアントの検索要求による更新によって SSDP アナウンスを受け取ったデバイスのリストを作成します。ネットワーク インターフェイスが変更されると、このリストも調整されます。
ローカル キャッシュに検索要求と一致するエントリがないかどうかがチェックされ、一致するデバイスが検出されたデバイスのリストに追加されます。次に、Windows ソケットへの直接アクセス (初期化において作成されたソケットに対して sendto が実行される) によって検索要求がすべてのインターフェイスから送信され、ネットワークがチェックされます。タイマが 3 秒 (既定) に設定されます。3 秒が経過すると、タイムアウトとなり、検索が再試行されます (3 回)。
次に、ソケット選択メソッドが呼び出され、各ソケットに FD_READ 機能があるかどうかチェックします。読み取り可能なソケットであることが判明すると、ioctl によって読み取りデータの量がチェックされます。さらに、そのソケットに対して適切なサイズのバッファを持った recvfrom が呼び出され、SSDP 応答を取得します。この応答が解析され、検出されたデバイスのリストの内容と比較されます。重複するデバイスがなければ、この応答がリストに追加されます。この応答は SSDP Discovery サービスにも転送され、このサービスのキャッシュを更新するよう要求します。
応答が受信されてからも、いくつかの操作が実行されます。デバイス ファインダがそのプライベート コールバック (UPNP.DLL 内) で新しいデバイスが検出されたことを示すコールを受け取ります。MSXML (XML DOM) と WinInet によって、受信した応答に指定された場所に基づき、このデバイスの記述ドキュメントが非同期でロードされます。このロードは非同期で行われ、ドキュメントが完全にロードされると、クライアントの DeviceAdded コールバック メソッドが呼び出されます。このメソッドには、見つかったデバイスを表す新しいデバイス オブジェクトが指定されます。
このロード プロセスでは、見つかったデバイスを表すために作成されるデバイス オブジェクトを管理する記述ドキュメント オブジェクトが作成されます。この記述ドキュメントはルート デバイス オブジェクトへのポインタを含んでおり、このオブジェクトには子デバイス オブジェクトまたはサービス オブジェクトへのポインタが含まれています。この記述ドキュメントから XML データが取り出され、ネストされたデバイス オブジェクトおよびサービス オブジェクトに保存されます。このデータには配列形式のプロパティが含まれており、クライアントがデバイス オブジェクトに対してメソッドを呼び出すことにより、簡単にアクセスできます。
再試行がすべて完了し、受信した応答のリストが作成されると、検索が終了したことが示され、内部プライベート コールバックが再び呼び出されます。このコールバックには、検索が完了した場合に果たす役割が 2 つあります。
元の要求が非同期要求 (前述のとおり、同期メソッドを呼び出した場合でも非同期要求になります) であった場合、アクティブな検索フェーズが終了します。CancelAsyncFind で要求を取り消すまでは、デバイスの追加と削除の通知を受け取る必要があります。デバイスがネットワーク上で追加または削除されたときに、アナウンスに基づいてコールバックが呼び出されるようにするために、デバイス ファインダは通知の受信を登録します。通知については、この後、サービス イベントにサブスクライブするためにコールバックを登録した場合の動作について説明するときに触れます。デバイス ファインダによって非同期要求に変換された同期検索要求は、内部的に同期呼び出しの終了後まで存続することはありません。検索が内部的に完了すると、同期呼び出しは取り消されます。
最後に、内部コールバックが非同期コールバック オブジェクトの SearchComplete メソッドを呼び出します。非同期検索はアクティブな検索モードではなくなりますが、SSDP 通知によってデバイスの追加および削除の通知を受け取るコールバックが登録されます。
デバイスの記述の取得と解析
検索が完了すると、クライアントは検索条件と一致するデバイスを表す個々のデバイス オブジェクトへのアクセスを取得します。UDN による検索の場合、アクセスできるのは単一のデバイス オブジェクトです。タイプによる検索の場合は、デバイスのコレクションがアクセスの対象となり、このコレクションを解析して個々のオブジェクトを取得する必要があります。デバイス コレクションに対して、UDN を指定して Item メソッドを呼び出します。Item メソッドは、デバイス オブジェクト コレクションをチェックし、保存されたプロパティから UDN を取り出して (クライアント アプリケーションと同じように UniqueDeviceName メソッドを使用する)、それを指定された UDN と比較します。一致する UDN があった場合は、そのデバイス オブジェクトが返されます。
クライアント アプリケーションは、デバイス オブジェクトのメソッドを使用して、デバイスの記述のプロパティにアクセスすることができます。これらのプロパティは、前述のとおり、アクセスが容易な配列としてオブジェクトにロードされます。クライアント アプリケーションが子デバイスを要求した場合は、親デバイス オブジェクトからデバイス コレクションを取得できます。これは反復的なプロセスになります。
サービス オブジェクトの取得
実装された UPnP クライアントがデバイス ツリーを解析、保存するときに、サービスも列挙され、そのデバイスに付属のリストに追加されます。クライアント アプリケーションは、デバイス オブジェクトに対して Services メソッドを実行して、このサービス リストを取得できます。このサービス コレクションを解析することにより、特定のサービスを見つけだし、サービス オブジェクトを取得することができます。
UPnP は、サービス オブジェクトの検索要求を受け取ると、サービス リストを検索し、一致するサービス ID を探します。一致するサービスが見つかった場合は、追加の操作を実行します。まず、このサービスの URL (記述ドキュメント、制御、イベント生成の URL) が有効であるかどうかをチェックします。WinInet インターフェイスと XML DOM インターフェイスを使用して、サービスの記述を同期モードでロードします。次に、このサービスを表すサービス オブジェクトを作成します。
サービス オブジェクトの作成中に、サービスの記述から状態変数が取得され、それらの変数に関する情報を保存するテーブルが作成されます。このテーブルには、変数名、データ型、既定値、変数を照会するためにリモート クエリの使用が必要かどうかを示す情報 (この変数に対してイベントが送信されるかどうかに基づく) が含まれます。アクション テーブルも作成されます。このテーブルには、入力/出力引数や戻り値など、サービスがサポートするアクションを表す構造体の配列が入っています。これらのテーブルとその他の情報 (制御 URL、イベント生成 URL など) が、返されるサービス オブジェクトにコピーされます。
サービス オブジェクトをクライアントに返す前に、最後の操作が実行されます。このサービスは、UPnP によってイベント生成用に初期化されます。UPnP によって、このサービス オブジェクトを参照するプライベート コールバック インターフェイスが作成されます。このプライベート インターフェイスは、サービス オブジェクトのグローバル インターフェイス テーブルに保存されます。そのサービスにイベント生成された変数がある場合は、イベント生成 URL を使用して、サービスのプロパティ変更通知を受け取るための登録をします。この通知によって、UPnP はサービス状態テーブルを最新に保ち、クライアントが登録したコールバックを実行できます。このサービス オブジェクトに対してコールバックがいくつ登録されていても、UPnP クライアントはそのうちの 1 つだけをリモート サービスに登録します。この登録は、既に説明したデバイスの通知および削除の登録と同じように、SSDP Discovery サービスへと伝達されます。次に、これらの登録について説明します。
コールバックの登録
サービス オブジェクトを取得すると、クライアント アプリケーションはそのオブジェクトが公開するメソッドをさまざまな目的に使用できます。こうしたメソッドで実行できる操作には、状態変数の照会またはアクションの実行 (後の項を参照)、サービスの状態またはサービス状態変数の変更を通知するコールバックの登録などがあります。
このコールバック登録は、サービス オブジェクトの AddCallback メソッドによって実行されます。クライアントは、このメソッドを使用して、サービス状態の変更通知を受信するサービス コールバックを登録します。これ以前に、サービス オブジェクトを取得したときに、UPnP クライアント DLL はこのサービスからの通知を受け取るための登録をしています。クライアントのコールバックが、他の登録された状態変更コールバックと共に、そのオブジェクトのグローバル インターフェイス テーブルに追加されます。UPnP クライアント DLL によって登録されたコールバックが実行されると、グローバル インターフェイス テーブル内のコールバック インターフェイスが呼び出され、変更通知を受け取ります。
登録されたコールバックがデバイス ファインダによって実行された場合 (デバイス通知) でも、サービス オブジェクトによって実行された場合 (イベント) でも、結果として SSDP クライアント API が呼び出され、最終的には SSDP Discovery サービスが呼び出されます。要求には、通知のタイプとして、"Alive" (デバイス通知の場合) または "Property Change" (サービス状態の変更) が指定されています。また、非同期デバイス検索でのデバイス タイプまたは UDN、イベント通知でのイベント URL、デバイス ファインダまたはサービスのコールバック、要求 (検索要求またはサービス オブジェクト) の送信元を示すコンテキストも指定されます。
SSDP クライアント API は、RPC を使用して、この要求を SSDP Discovery サービスに転送します。この操作の前に、いくつかの作業が行われます。登録に関する情報を保存する構造体が割り当てられます。この構造体には、解除する登録を認識する手段としてサービスが返すハンドルも保存されます。この構造体のハンドルは、登録のハンドルとして最終的に SSDP API の呼び出し元 (UPnP クライアント DLL) に渡されます。
次に、この通知登録が初めて行われたものかどうかがチェックされます。そうである場合は、通知メッセージ ループ スレッドを作成する必要があります。このメッセージ ループを開始するために、まずセマフォが作成されます。次に、SSDP Discovery サービスを呼び出して (RPC を使用) 通知を取得するスレッドが作成されます。このスレッドはセマフォが発生するのを待ちます。通知を受け取るたびにセマフォが発生し、それによってこのスレッドが起動し、メッセージを処理します。
この通知ループ スレッドが作成されると、それ以降は通知登録が存続します。SSDP Discovery サービスによる要求の処理方法は、通知のタイプ (Alive または Property Change) によって異なります。要求がどちらのタイプでも、セマフォは SSDP Discovery サービスに渡され、要求オブジェクトに保存されます。要求と一致する通知を受け取ると、セマフォは解放され、それによって通知ループ スレッドが起動し、要求を処理できるようになります。
デバイス通知 (Alive) 要求の場合は、通知に関する情報 (コールバック インターフェイスを含む) がアクティブな Alive コールバックのリストに保存されます。デバイス通知リストに含まれるこの構造体へのポインタは、サーバーのハンドルとしてクライアント API に返されます。このポインタはほかの情報と共に登録を表す構造体に保存され、この構造体のハンドルは SSDP API の呼び出し元 (UPnP DLL) に返されます。UPnP DLL は、非同期検索が取り消されるか、アプリケーションが終了する場合に通知の登録を解除する際、このハンドルを使用します。
プロパティ変更通知の登録がたどる経路は少し異なります。この場合、新しいデバイスが追加され、アナウンスされるのを待つのではなく、ネットワーク上のサービスにサブスクライブする必要があります。
そのために、SSDP Discovery サービスは WinInet API を使用して、サービスのイベント URL に接続し、サブスクリプション要求を送信します。リモート サービスはリターン フォームにサブスクリプション ID とタイムアウトを追加します。これらは、登録に関する残りの情報と共に構造体に保存されます。サービスのタイマ キューに属するタイマによって通知要求のタイムアウトが設定されます (サブスクリプションのタイムアウト時間の 65% を基準とします)。タイムアウトになると、返されたサブスクリプション ID を使用して再サブスクリプション要求がサービスに送信されます。この再サブスクリプション要求に対する応答には、同じサブスクリプション ID とタイムアウト時間が含まれています。このタイムアウト時間は、サブスクリプション応答に含まれる時間と同じ場合もあれば異なる場合もあります。タイマは、返されたタイムアウト時間の 65% に設定され、再開されます。
デバイス通知の登録と同じように、イベント通知の登録もサービスのリストに保存され、クライアントには登録のハンドルが返されます。このハンドルは、登録を解除するときに使用します。デバイスが通知を送信するときには、初期化中に作成されたイベント通知用のソケットで TCP 接続を確立します。
イベント通知が到着した場合
初期化中に、SSDP Discovery サービスは通知の受信用に作成したソケットに WSAAsyncSelect を登録しました。このメソッドには、このサービスの隠しウィンドウのハンドルと TCP データの受信を示すメッセージが指定されています。このようなメッセージが到着すると、SSDP Discovery サービスの Window プロセスがメッセージ生成の理由を突き止めます。つまり、接続が確立可能、解放可能、データ受信可能のうち、どの原因によって選択メソッドが呼び出されたのかを判定します。この判定によって、次に実行する操作が決まります。
クローズ メッセージを受信した場合は、closesocket が呼び出され、接続がサービスのオープン接続リストから削除されます。新たな接続要求が届いた場合は、accept が呼び出され、新しい接続を管理する新しい接続が割り当てられます。SSDP Discovery サービスのイベント サーバー部分は、オープンしている接続のリンク リストを作成し、ピア ソケット ハンドルや接続の作成済み SSDP メッセージなどの情報を保存します。
ソケットに読み取りデータがあることをメッセージが示している場合は、データの量 (ioctlsocket で調べる) に応じたサイズの受信バッファが割り当てられ、recvfrom によってデータがバッファに格納されます。受信データに関する情報は、受信したソケット、リモート ソケット アドレス、データそのものなど、すべて構造体にコピーされ、作業項目のコンテキストとしてワーカー スレッドに渡されます。
この作業項目が処理されると、オープンしている接続のリストにオープンしている接続が存在するかどうかチェックされ、受信データが処理されます。メッセージが適切な形式であり、ヘッダーが完全で有効であるかどうかが検証されます。要求に指定された情報がデータ処理用の構造体にコピーされ、追加処理のために渡されます (まだサービスの内部にある)。
この処理には、このイベントに関連するクライアント アプリケーションがあるかどうかのチェックも含まれます。このチェックでは、サブスクリプション ID とその他のヘッダー値を照合します。このイベントに関連するクライアント アプリケーションがある場合は、通知要求オブジェクトが取得され、そのオブジェクトに保留中の通知リストが追加されます。次に、この通知要求に関連するセマフォが解放されます。実際には検出通知を受信し、そのサービスにサブスクライブしているクライアントがある場合は、検出キャッシュが更新されます。
セマフォが解放されることによって、通知ループ スレッドも解放されます (前の項を参照)。このループはクライアント要求を見つけるコンテキストとしてセマフォを使用し、受信したメッセージを返して RPC コールから復帰します。
未処理の各イベントごとに、クライアントへのコールバックの準備として、コールバック情報をコールバック構造にコピーし、コールバック数を増やします。さらに、各コールバックについて、クライアントが登録したコールバックが呼び出されます。これは UPnP クライアント DLL が登録したコールバックです。
UPnP クライアント DLL が登録したコールバックは、イベント通知のシーケンス番号が有効かどうか確認し、無効であれば、サービスに再サブスクライブします。そうでない場合は、メッセージが XML DOM ドキュメントに変換され、その解析を基に、サービスの状態テーブルが更新され、クライアント アプリケーションが登録した実際のコールバックが呼び出されます。クライアント コールバックは、登録に関する節で説明したように、サービス オブジェクト グローバル インターフェイス テーブルで検索されます。
アクション ( 制御 ) 要求
クライアント アプリケーションは、サービス オブジェクトの InvokeAction メソッドを使用して、サービスに対して制御要求を実行します。制御要求は、状態変数クエリと同じように SOAP を使用します。そのため、制御要求と状態変数クエリは実装方法がよく似ており、同じコードを共用します。
InvokeAction メソッドは、まず渡された値をチェックし、入力変数の数が正しいかどうかを確認します。出力変数と戻り値の出力パラメータが正しく、書き込み可能であるかどうかもチェックします。これらのチェックを行い、アクション要求を実行するために、サービス オブジェクトのアクション テーブルを解析し、アクション要求に関連する構造体を取得する必要があります。
SOAP 要求が作成、構築され、アクション要求に対して実行されます。この要求の処理に必要なネットワーク通信には WinInet が使用されます。サービス オブジェクトから取得した制御 URL を使用して、要求が非同期で送信されます。要求の処理が完了すると、応答から結果が取り出されます。要求の処理が成功した場合は、出力パラメータと戻り値がクライアント アプリケーションに返されます。
UPnP クライアント サポートのトラブルシューティング
UPnP の動作はユーザーにはほとんど見えません。ネットワークに接続されたデバイスとサービスは、コントロール ポイント アプリケーションにとって使用可能な場合と、そうでない場合があります。ファイルとプリンタの共有など、ネットワーク接続が使用可能な場合は、UPnP デバイスも存在する可能性があります。UPnP デバイスやコントロール ポイント アプリケーションの設計およびテストの段階では、ネットワーク接続や通常のネットワーク トラブルシューティング以外の問題が検討の対象となります。
したがって、次に示す 2 種類の問題があります。
-
デバイスまたはコントロール ポイントの開発に関する問題
-
デバイスおよびサービスの検出と利用に関する問題
デバイスやコントロール ポイントの開発に関する問題は、開発する製品が UPnP デバイスとコントロール ポイント アプリケーションのいずれであっても、ほとんどは出荷前に解決されます。開発段階では、消費者が実際に使用する中で現れる問題の多くが発生します。デバイスの検出に関する問題が発生した場合の解決法はいくつかあります。ここで説明する方法は Windows XP を前提としています。デバイス クライアントとして Windows ME コンピュータを使用する場合は、異なる手順となることがあります。
-
まず、接続を検証します。
ネットワーキングの問題で最も可能性の高い原因は物理的な接続です。接続を検証するには、いくつかの方法があります。まず、ネットワークとの物理的な接続を調べます。家庭のネットワーク環境では、デバイスを接続しているネットワーク メディアがクライアントと同じ場合と異なる場合があります。
デバイスとクライアントを、イーサネットと無線など、異なるネットワーク メディアに接続している場合は、2 つのネットワークが互いに接続されていることを確認します。この確認では、Windows XP の ネットワーク ブリッジ または他のブリッジ デバイスを使用します。このテストの方法は、対象となるネットワークの構成とメディアによって異なります。このレベルの接続をチェックする方法の 1 つとして、クライアントからターゲット デバイスと同じメディア上のデバイスが見えるかどうかを確認することがあります。
デバイスとクライアントを同じ物理メディアに接続している場合は、ネットワーク ブリッジは必要ありません。メディアには、接続を視覚的に表示するものがあり、それによって接続をチェックできます。たとえば、ツイスト ペア ケーブル上のイーサネットには、ケーブルが接続され、使用可能であることを示す緑色のランプがついています。この場合も、同じメディア上のほかのデバイスにアクセスできれば、接続に問題がないことを確認できます。
物理的な接続に問題がないと思われる場合は、ネットワーク プロトコルの接続をチェックする必要があります。このチェックにもいくつかの方法があります。ただ、UPnP には TCP/IP が必要であるため、"ping" ユーティリティを使用するのが最も簡単な方法です。ping は Windows XP から実行します。このとき、IP アドレスでターゲット デバイスを指定します。デバイスの IP アドレスを調べる方法はデバイスによって異なります (IP アドレスを表示できるデバイスもあります)。
UPnP を使用するネットワークでは、アドレスも動的ホスト構成プロトコル (DHCP) で設定される場合があります。たとえば、ICS を使用してインターネット接続を共有している場合、ICS 内の DHCP サーバーは 192.168.0.x の予約されたプライベート IP アドレス範囲でアドレスを割り当てます。この範囲のアドレスを 1 つずつ試し、応答がないかどうか確認することもできます。
SSDP Discovery は TTL 4 のマルチキャスト フレームを使用するため、ping コマンド (この目的には tracert も使用できます) が返す TTL にも注意を払う必要があります。ping の実行が成功し、TTL が 255 である場合は (このサブネット内に宛先があったことを意味します)、ネットワーク接続が存在すると考えられます。デバイスとクライアントの間に複数のホップが存在すると判明した場合は、デバイスとクライアントを同じハブ内に移し、テストを再実行してください。
-
SSDP Discovery サービスが Windows XP クライアントで実行され、その異常を知らせるイベントがシステム ログに記録されていないことを確認します。
前に説明したように、デバイスの検出や検索には SSDP Discovery サービスが必要です。サービスが動作しているかどうかを確認するには、コマンド プロンプトに次のように入力します。
net start <enter>
表示された情報の中に "SSDP Discovery Service" があるかどうか調べます。このサービス名がない場合は、次のように入力します。
net start "SSDP Discovery Service"
<enter>これで SSDP Discovery サービスが起動します。
イベント ビューアでシステム イベント ログをチェックするには、[コントロール パネル] から[管理ツール] を選択し、[イベント ビューア] を選択します。
-
デバイス サービスがどのポートを使用するかわかっている場合は、telnet でそのポートに接続し、HTTP の機能を確認することができます。
次のようなメッセージが表示された場合は、デバイスが記述の XML ドキュメントへのアクセスを提供していません (または別のポートでアクセスを提供しています)。
Connecting To <computername or IP>...Could not open connection to the host, on port XXX.
No connection could be made because the target machine actively refused it.
メモ: ICS のような UPnP 対応のインターネット ゲートウェイ デバイスでトラブルシューティングを行う場合、この方法は使用できないことがあります。
telnet で接続できない場合は、デバイスに問題があるか、デバイスの構成が誤っているか、デバイスがテストしたポートとは異なるポートを使用している可能性があります。デバイスの構成をチェックして、こうした問題がないかどうか確認してください。
デバイスが動作しているかどうかを確認するには、[マイ ネットワーク] のアイコンをチェックするという方法もあります (UI コンポーネントをインストールすることが必要です)。アイコンがある場合は、検出と記述の機能が動作しています。アイコンがない場合は、問題が存在する可能性がありますが、デバイスがプレゼンテーション ページ (任意) を提供していないことが原因とも考えられます。
-
この時点で詳細なトラブルシューティングが必要となる場合もあります。
その場合は、ネットワーク モニタまたは netcap.exe ユーティリティを使用して、UPnP 要求によって生成されるネットワーク トラフィックをキャプチャします。キャプチャされたネットワーク トラフィックを調べ、SSDP フレームが正しく作成されており、適切な UPnP トラフィックが交換されていることを検証します。
netcap.exe ユーティリティは、Windows XP の CD の \support\tools ディレクトリにあります。キャプチャされたネットワーク トラフィックを表示するには、ネットワーク モニタが必要です。ネットワーク モニタは、Windows Server 製品または Microsoft Systems Management Server に付属しています。ネットワーク モニタのテンポラリ バージョンを Microsoft PSS (Product Support Services) から入手することもできます。サポート サービスのスタッフは、ネットワーク トレースの解析方法についての問い合わせにも応じています。
この場合、SSDP Response フレームに注目し、Description URL (このフレームの Location フィールドにあります) をチェックします。Description Request (フレームは XML 記述ドキュメントの HTTP GET) と Description Response (その XML ドキュメントをクライアントに渡す HTTP Response) もチェックしてください。記述要求が送信されていないか、正しく送信されなかった場合は、クライアント コンピュータの SSDP Discovery サービスまたは SSDP 交換のフォーマットに問題があると考えられます。
以上のチェックによって、検出および記述のトラフィックがクライアント コンピュータまで届いていることを確認できました。次に、データが到着した後、ローカル コンピュータでどのようなことが起きているかを確認します。次のような問題が発生する可能性があります。
-
破損した XML ドキュメントがクライアント コンピュータに問題を発生させる。
-
SSDP Discovery サービスが列挙中に誤動作する。
-
デバイスの UUID が以前に検出された別のデバイスと競合する。
問題を解決できない場合は、Microsoft PSS に問い合わせることもできます。
-
まとめ
Windows XP のユニバーサル プラグ アンド プレイ サポートによって、各種のデバイスを簡単にネットワーク化することができます。この規格が開発され、そこで使用されている標準プロトコルをサポートするデバイスが増加するのに伴い、デバイスをネットワーク上から制御または監視することが当たり前になるでしょう。Microsoft Windows プラットフォームの発展に伴って、デバイス、サービス、およびアプリケーションのサポートも拡張されていきます。
参考資料
UPnP フォーラムと UPnP の仕様および規格については、UPnP フォーラムの Web サイト http://www.upnp.org/ (英語) を参照してください。
XML DOM、URLMON、WinInet、IP Helper API に関する情報は、MSDN ライブラリの Platform SDK にあります。MSDN ライブラリの詳細については、http://msdn.microsoft.com/ja-jp/library/default.aspx を参照してください。