UTALI

書き溜めておいた技術記事や旅行記のバックアップです。

WebRTCの現状 - STUN/TURN・シグナリングサーバーについて - (7/8)

注:node-staticについてここで学ぶ必要はありません。サーバーを単純に書くためだと思ってください。 このアプリをlocalhostで動かすために,まずNode.js、socket.io、node-staticがインストールされていることを確認してください。Nodeは nodejs.org から簡単にインストールすことができます。socket.io、node-staticをインストールするにはコマンドラインから以下のコードを入力します。

npm install socket.io
npm install node-static

サーバーを起動するにはアプリを設置したディレクトリで以下のコマンドを入力します。

node server.js

Chrome,またはOperaのブラウザからlocalhost:2013にアクセスしてみましょう。新しいタブを開き、 localhost:2013を再び開きます。何が起こるかみてみてください。デベロッパーツールを開いて、コンソールをみてください。

どのようなシグナリング手法を使ったとしても、これに似た結果になるはずです。

シグナリングにRTCDataChannelを使用する。

シグナリングを行うにはWebRTCセッションを初期化する必要があります。

しかし、2つのピア間で一度接続が確立してしまえば、理屈の上ではRTCDataChannelはシグナリング経路としてtake overされます。これはシグナリングのレイテンシを損なう可能性があります。

なぜならメッセージを直接転送したとき、シグナリングサーバーの帯域と処理コストを低下させることになるからです。このデモはありませんが、このスペースを監視してください。

シグナリングのgotchas

  • RTCPeerConnectionはsetLocalDescription()が呼び出されるまでcandidatesを収集しない。これについては JSEP IETF draftを参照のこと

  • ICEの取り扱いの利便性のため、candidatesが到着したらaddIceCandidate() を呼び出す。

出来合いのシグナリングサーバー

すでにsocket.ioを利用したWebRTC用のシグナリングサーバーが用意されているので、手間をかけて構築する必要はない。そしてこれらはクライアント用のJavaScriptライブラリともうまく連携するように設計されている。

  • webRTC.io: 初期のWebRTC用の抽象ライブラリ

  • easyRTC: 古スタックのWebRTCライブラリ

  • Signalmaster: クライアントサイドライブラリのSimpleWebRTCと連携して使われるサーバーサイドライブラリ

もしコードを一切書きたくない場合は商用のWebRTCプラットフォームを使用するといいだろう。例としてvLineOpenTokAsteriskのような企業がパッケージを提供している。

レコードを取得したい場合は、エリクソン社が構築したApacheサーバー上で動作するPHPのシグナリングサーバー signaling server using PHP on Apache がある。これは少々時代遅れであるけれど、似たような物を作りたい時の参考になると思う。

セキュリティ

WebRTCで暗号化を行うかは任意である。

しかし、シグナリングの仕組み自体はWebRTCの基準に含まれていないので、シグナリングを安全に行うかはあなた次第である。もしシグナリングサーバーが攻撃者に乗っ取られてしまえば、セッションを停止したり、接続やレコードをリダイレクトしたり、あるいは通信の内容を改ざんされることになる。

シグナリングを安全に行うためにもっとも重要な要素は安全なプロトコルを利用することである。たとえば、HTTPSWSS(TLS)で、これらは暗号化されていないメッセージを盗聴されないように保障する。もうひとつ注意すべきなのはシグナリングメッセージを同じシグナリングサーバーを利用する別の利用者に盗聴されないようにすることである。

シグナリングのあとに - ICEを利用してNATとファイアーウォールに対応する。

メタデータのシグナリングについて、WebRTCは仲介サーバーを利用する。しかし実際のメディアとデータストリーミングでは、一度セッションが確立されたならば、RTCPeerConnectionはピアツーピアで、 クライアントを直接接続することを試みる。

これを単純化すると、すべてのWebRTCエンドポイントはユニークなアドレスをもっていて、ほかのピアと直接通信するためにそれを交換する。

しかし現実には、ほとんどのデバイスは1つないしは複数のNATを通過する。それは特定のポートやプロトコルを遮断するウイルス対策ソフトかもしれないし、プロキシやファイアーウォールを通してあるかもしれない。大抵の場合はファイアーウォールとNATは同じ機器で行われていることが多い。たとえば家庭用wifiルーターのように。

f:id:mochizuki_p:20160908114223p:plain

WebRTCのアプリはICEの枠組みを利用して現実世界のネットワークの複雑性を克服している。このためにアプリケーションはICEサーバーのURLを通過してRTCPeerConnectionに辿りつかないとならない。

ICEはpeer同士を接続するための最短経路を見つけることを試みる。それに並行してあらゆる可能性を試し、もっとも効率的な選択肢を見つけ出す。ICEはまずデバイスのOSとネットワークカードから取得したホストアドレスを使用して接続を試みる。もしこれが失敗したら(NATが利用されていることを意味する)STUNサーバーを利用して外部のアドレスを取得する。これも失敗してしまった場合はTURN中継サーバーを利用して情報を送信する。

つまり

  • STUNサーバーは外部のネットワークアドレスを取得するために使用される

  • TURNサーバーはピアツーピアの通信が失敗した場合に使用される中継サーバーのこと

すべてのTURNサーバーはSTUN機能を実装している。つまり、TURNサーバーは中継機能を実装したSTUNサーバーであるということだ。ICEはNATの複雑性に対応している。実際にNATの「ホールパンチング」はパブリックIPとポート番号だけでは不十分な場合がある。

STUN/TURNサーバーのURLはWebRTCアプリのICEサーバーの設定オブジェクトの第一引数で指定することができる。apprtc.appspot.com の場合は以下のようになる。

{
  'iceServers': [
    {
      'url': 'stun:stun.l.google.com:19302'
    },
    {
      'url': 'turn:192.158.29.39:3478?transport=udp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    },
    {
      'url': 'turn:192.158.29.39:3478?transport=tcp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    }
  ]
}

一度RTCPeerConnectionがその情報を取得したら,ICEの魔法が自動的に発動する。

つまり、PTCPeerConnectionは、STUNサーバーと連携しながら、ICEの仕組みを使ってピア間の最短経路を見つけ出す。もしこれで不十分ならば代わりにTURNサーバーが使用される。

7/8