2017-07-16

zoiper その後・顛末記 -- まだ継続課題あり

ディープスリープで zoiper のレジストが外れる問題



    zoiper が切れる でトライした件


Tasker で1時間ごとに自動起動する、ではダメでした。

SIP ソフトフォンの zoiper のレジストが外れる件は、Tasker で1時間ごとに zoiper を起動するようにしたのですが、一晩経ってディープスリープ(Doze モード)に入っていると切れていることが多く、たまに切れていないときもあるので、


考え込んでしまいました。以下はその顛末記です。


Zoiper は、デフォルトアカウントはレジストが一旦失敗するとなぜかやり直してはくれなくて、外れたままになります。デフォルトアカウント以外はレジスト OK にみえますので、これがまた悩ましい点です。

デフォルトアカウントは、Connectivity を Save し直して(udp ポートの設定し直しと等価な処理)初めてレジストが復活します。


そもそも、SIP REGISTER はこれ自体、すでにレジストできていたのに、途中からいきなり失敗することは考えにくい。

ルーターで udp タイムアウトして NAPT が破棄されても、その後の REGISTER では新しく NAPT が張られるので、サーバーからの 200 OK は正しい UAC に戻るハズ。

考えられる原因は、以下のようなケースです。

 ① DNS がなんらかの原因で FQDN から正しく IPアドレス変換できなかったため、UAS は不当要求として registration failed を返した。
 ② うまくいった REGISTER 後、ルーターで udp タイムアウトが発生し、NAPT が破棄された後に registration keep alive で、戻り UAC を失ったので、UAC は応答タイムアウトでレジスト不可を認識した。
 ③ 発生状況からみると、可能性はかなり低いが、UAS 側に障害があった。
 ④ REGISTER 要求した後に、ルーターの DHCP のアドレス有効期限になり、UAC のアドレスが変わったため、NAPT で正しい UAC に戻せず、レジスト不可となった(NAPT が新たなアドレスで動的マスカレードテーブルを書き換えていなければ)。
 ⑤ zoiper 自体に何らかのバグがあり、これが原因で発生している。

などです。registration expiry time は contact ヘッダーに設定してレジストラに REGISTER 要求しますが、レジストラは独自の expiry time を返すことがあります。

① はネットワークの輻輳などで、DNS が詰まることはありえますが、8.8.8.8 なので考えにくい。
② はそもそも expiry time が 60秒の設定なので、udp タイムアウトにはなりません(ルーターの udp タイムアウト時間は 180秒)。レジストラが独自の長い expiry time を返して 180秒よりも大きい時間だと、次の REGISTER 要求は、タイムアウト後の可能性もありますが、例えタイムアウトで NAPT 破棄後であってもこの REGISTER 要求で新たな NAPT が張られるので問題は生じないことになる。
③ は lollipop 以前のスマホではうまくいっているので、これも考えにくい。
④ はあり得るシナリオです。現在のリースタイムは 4時間なので Doze から覚めたときのタイミングで変わっている可能性があります。しかし、レジストラからの keep alive 以外は、このシナリオも成り立ちません。UAC からの keep alive は NAPT は常に最新のハズです。逆にいうと、REGISTER の keep alive をレジストラ側から行っているとするとあり得るシナリオですが、通常サーバー側からは keep alive しません。そもそもレジストラの存在は INVITE 時のロケーション管理であって、UAC の生き死には気にもしません。
⑤ は、以上のことから一番あり得るシナリオとして、zoiper のサポートチームにメールで問い合わせすることにしたのです。

問題は REGISTER なので、非常に発生条件の絞り込みが難しいのです。

なぜ、こういう動作になるのか、zoiper の公式サイトの FAQ でも記述がないのです。

マニュアルはPC用はありますが、Android や iPhone 用はありません。
また、PC用マニュアルでもこのような事への記述はありませんし、PC用以外にマニュアルがない点も大いに不満なところです。

アプリケーション自体は相当にいい出来具合なので、大変残念なところです。

こういう動作も悩む点でした。Android の動きもそうですが、zoiper 自体の動きも物事を複雑にします。解決しなければならないパラメーターが一気に増えてしまいます。

----------◇----------◇----------◇----------

Doze で電池の消耗が減るのはありがたいのですが、SIP 着信などにとっては厄介です。
ネットではディープスリープで Mail や LINE の通知がこない、遅れる、などの相談もみられます。


プッシュ通知は Google Cloud Message(GCM)が受け持っています。
これがうまく働くときと、そうでないときがあるように思えます。

GCM のタイムアウト値はデフォルトでは、

 WiFi       : 15分
 モバイル : 29分(なんか中途半端な時間です)

このタイムアウト時間はスマホ側の設定値で、モバイルに関しては MVNO によってはこれよりも短い時間(数分程度)でセッションを切られるケースもあるそうです。

三大キャリアは 53分だそうです(端末側の設定値の方が小さいのでキャリア側は切らなくても GCM は 29分でタイムアウトすることになります)。

タイムアウトは、この時間内に一度も tcp パケットが流れないときに起こります。


タイムアウト値を三大キャリア並みにして欲しいとのMVNOへの相談には、まじめに設定値を見直ししてくれた事例と、不まじめなところとがあるようで、こういったところは「いいMVNO」「悪いMVNO」の差となって表れます。MVNOを選ぶ際の一つの指標でしょう。

同様のことは、端末メーカーも然りです。


ともあれ、いまはまず WiFi での動作をちゃんとしてモバイルはその後で考えることにしました。


GCM のタイムアウトを防止するために tcp パケットを流すタイミング、つまり「ハートビート時間の設定」をしてくれるアプリ(Push Notification Fixer - no root [以降 PNF]、または Heartbeat Fixer for GCM をインストールして、

 WiFi       : 4 分ごと
 モバイル : 10分ごと

に設定し試したのですが、一晩放置でレジストが OK のときもあれば NG の時もありますので、状況的には変わりません。



これが Push Notification Fixer -- no root の画面です。ハートビート間隔を設定した後に Apply settings をクリックすると GCM のテーブルを書き換えてくれます。
テーブル書き換えだけですので、このアプリが何かほかの動作をするわけではありませんから、設定後はアンインストールしても構いません。ただ、スマホの再起動をするとデフォルトに戻るようです。

Heartbeat Fixer for GCM の場合は再起動でも設定を書き戻してくれるようです。



先に挙げた Mail や LINE のケースはこれで解決したという報告もありますが、zoiper の場合はそういう事例もなく、Connectivity の Save で OK ならそれでいいと諦めているケースが多いと思われます。

PNF -- root 版は、ルートとらないと本来は有効ではありませんが、これには Google play 開発者サービスの動作状況を見られる機能があるので、これもインストールして状況を見てみました。

下記は PNF -- root 版による Google Play開発者サービスの Status画面です。



こちらは同じく Google Play開発者サービスの Event 画面です。





これを見ると、Doze は入ったり出たり(Entering doze/Exiting doze)しているようです。


zoiper はレジスト OK なら、着信はプッシュ通知されるはずです。
着信のプッシュ通知は、zoiper の場合も GCM に依存しています。


さらに調べてみると GCM はタイムアウト期限までに tcp パケットが流れないでセッションタイムアウトすると、NAT を破棄する(NAT テーブルのクリア)らしいことがわかりました。
この NAT 破棄はどのように影響するのでしょうか。

NAT を必要とするのは端末がモバイルルーターの場合です。

普通のスマホは、プラーベートであれ、グローバルであれ IP アドレスは、モバイルキャリアから割り当てられています。

WiFi では、ルーターの DHCP から動的に割り当て、またはスマホの WiFi 設定時に静的に割り当て、のどちらかです。

プライベート IP アドレスの場合は WiFi ルーターまたは、キャリア側で NAT 変換しています。
グローバル IP アドレスの場合は VPN の場合を除けば NAT を必要としないはずです。

したがって、GCM の NAT 破棄は影響しないことになります。
この部分でも余計な情報を得たためにいろいろと遠回りをしてしまいました。


しかし、ここで重要なヒントを得、思いだしました。それはルーターの NAT テーブルはどうか、ということです。

しかも、いまのルーターは NAPT になっていてポート変換までしています。これはローカル網内のどのノードから発信されたパケットかを、同じ宛先への違う発信元を区別するために、発信元ポートも変換して一意に定めるためです。

ところが、この変換テーブルがタイムアウトでクリアされてしまうと、正しく発信元にパケットを返せなくなってしまいます。発信元(スマホ)からみると応答タイムアウトで通信失敗という結果になります。これがレジストエラーの原因だろうと疑いましたが、冒頭のシナリオではあり得ません。

zoiper がなぜ、ローカル網からグローバル網に変わってもレジストを維持できるのか、おそらく zoiper 自身でも NAPT 相当(NATトラバーサル?)を行っているのではないかと想定されます。そう考えると、デフォルトアカウントのレジストエラーが回復しない理由も納得できます。Connectivity を Save によってやり直すと、zoiper 自身の NAT-T がリフレッシュされて、再び通信が復活するのではないかと考えられます。


我が家のルーターの SPI (ステートフル・パケット・インスペクション)のタイムアウト値は tcp ではデフォルトが 3600秒でしたが、あまり深くは考えないで 300秒の設定で使っていました。udp は 180秒(デフォルト値)のままです。

SPI の動作を考えると、短めの方がより安全にフィルタリングできると漠然と考えていました。

300秒(=5分)ですから GCM のタイムアウト云々以前に、パケットが流れない状況、つまり網内のどのノードもスリープ状態のときに、ルーターでタイムアウトしてしまいます。

このときにルーターのダイナミック NAPT はテーブルクリアされます。

そもそも、ウチの Mac は 7:00〜19:00 はスリープタイムではありません。画面オフでも1時間はスリープに入りません。この間は Gmail はほぼリアルタイムにメール着信をチェックしています。したがって、tcp が流れなくなる時間はほぼありません。NAPT テーブルも保持されています。

スマホから見ると、たとえスマホが放置されていても Mac によって、スリープタイム以外は結果的にルーターの NAPT テーブルが保持されていたことになります。

19時以降は Mac はスリープタイム設定してあります。ですから夜間は tcp が流れない時間があるわけです。タイムアウトもするわけです。



そこで、tcp/udp タイムアウト値をそれぞれ、1800秒/900秒に変えました。これにより、少なくともルーターが GCM より先にタイムアウトすることはなくなります。

思うに、スマホの NAT がディープスリープによってタイムアウトして、それが原因で zoiper の 定期的な(Registration expiry time ごとの)レジストが失敗、もしくは keep alive が失敗、その結果レジストが外れるのではないか、と考えたのでした。


ハートビートの方は、PNF no root で WiFi 14分間隔、モバイル 20分間隔で設定し直しました。


ログを見ると、実際のハートビート間隔は最長がこの値で、概ねこの値よりも短い間隔で行われているようです。

この設定見直しにより、ルーターの NAPT テーブルは少なくとも 30分間は保持されます。夜間は、GCM のハートビートも相まってタイムアウトはなくなり、ルーターの NAPT 破棄も起こらないことになるはずです。そうすれば、zoiper のレジストが失敗しないですむはずです。

一晩放置して Doze に入ってもレジストが外れないか様子をみました。


外れ、だったようです。


なお、zoiper は当然「最適化しない」設定に最初からしています。
その後、解決に至ったことは、ここに記述しています。



ところで、

zoiper はバックグラウンドで動いていますから、レジストさえ維持されれば、待受けの問題はなくなるのですが、レジストが外れていると当然ですが着信しません。

このとき、かけた側には「おかけになった電話番号は現在使われておりません」というメッセージが流れてしまいます。

このメッセージは気に入りません。
電話番号を使っていないのではなく、着信しないだけなのですから。

携帯電話への発信だと、「おかけになった電話番号は現在電波の届かないところにあるか、電源が切れているのでかかりません」というメッセージになります。

このあたりは、ブラステルになんとかしてもらいたいところではあります。
電話番号はブラステルが発行しているのですから、着信しない場合は、携帯電話への発信と同様に扱うべきだろうと思います。

いきなり切断状態なので、かけた側は「電話番号が使われていない」と判断してしまいます。


スマホに関していえば、レジストが外れているかどうかは通知領域を見て、初めてわかりますが、いつから外れていたかはわかりません。この間の着信をのがしているかも知れないのです。




上部通知領域の左に、緑色ののマークが見えると思いますが、これが zoiper がレジストOKのときの通知です。レジストが外れると、この表示自体がされません。



イエデンの場合は、Asteriskで 30秒間呼び出しに応答しなかったら留守電メール通知するようにしているので、とくに問題はありませんが、それ以外の持ち歩き用に確保したカミさん用のブラステル番号は、レジストが外れてしまうと、「おかけになった電話番号は現在使われておりません」となってしまいます。

また、娘一家が帰国したときに使う番号も同じ扱いになってしまいます。


携帯電話では、不在着信(圏外または電源オフ)は sms で通知されます。


まったく同じにはできないのですが、持ち歩き用も Asteriskに収容して、擬似的(一定時間呼び出しのあと)に携帯電話と同じメッセージを流すようにし、メールで不在通知しようかと考えています。


このときに、発信側には携帯電話と同じメッセージが流れるようにするのです。

「おかけになった電話番号は現在電波の届かないところにあるか、電源が切れているのでかかりません」



またまた、Asterisk でやることもできました。

というわけで本件は一件落着ですが、新たな課題は継続です。









0 件のコメント: