photonとの通信で接続が切れたことを検知する

photonとの接続が切断されたことを検知する方法を調べたのでメモ

公式のドキュメントはこちら
https://doc.photonengine.com/ja-jp/realtime/current/reference/analyzing-disconnects

photonのサーバとクライアントはheartbeatのメッセージを投げあって、接続されているか常に確認しあっている模様

Photon接続の両側(クライアントとサーバ)は送信したリライアブルコマンドが相手側に届いたことをを監視します。即時に (現在の往復時間に基づいて)ACKがない場合、リライアブルコマンドを再送します。

よって、このメッセージの応答がサーバから返らないことを検知できれば切断を検知したことになる。

photonのc++sdkを見ると、Listenerとして以下のようなinterfaceが定義されている。 http://doc-api.photonengine.com/en/cpp/current/

これらを呼び出すの部分をc++ sdk(v4.1.9.0)内で探すとLoadBalancing::Client::onStatusChanged()
にある。その中でstatusに応じて対応するlistenerが呼ばれている。statusは以下のファイルで定義されており、それぞれコメントが書いてあったのでgistに貼った。 ExitGames::Photon::StatusCode https://gist.github.com/y-kamiya/eb3d2dfdf05952bfa4d8cef1ef643940

onStateChangeのロジックと対応させて見ると、切断に関するlistenerは以下のような感じだった。

  • clientErrorReturn
    • クライアントからパケットを送出できなかった場合
    • 対応するstatusCode
      • SEND_ERROR
  • connectionErrorReturn
    • タイムアウトやサーバ側からの切断要求、なんらかの例外発生
    • 対応するstatusCode
      • EXCEPTION
      • EXCEPTION_ON_CONNECT
      • INTERNAL_RECEIVE_EXCEPTION
      • TIMEOUT_DISCONNECT
      • DISCONNECT_BY_SERVER
      • DISCONNECT_BY_SERVER_USER_LIMIT
      • DISCONNECT_BY_SERVER_LOGIC

実際にlistenerが呼ばれる場合を試してみたところ少なくとも以下は確認できた

  • 自分の端末を機内モードwifi OFFなどした場合
    • 自端末でclientErrorReturnが呼ばれる
  • 通信相手の端末を機内モードwifi OFFなどした場合
    • 自端末でconnectionErrorReturnが呼ばれる

ちなみに、connectionErrorReturnの場合はその中でdisconnet()も呼んでいるため、その後disconnetReturnも呼ばれる

c+11でメンバ変数初期化のされ方

c+11で書いていてクラス内のメンバの中に、コンストラクタで初期化子が定義されてないものがあったのでどのような挙動になるのか調べてみた。

これらを見るとわかりやすい
C++11: Syntax and Feature
C++の初期化は分かりにくい - ぷろみん

まず、staticが付いたものなどglobalスコープの変数はゼロ初期化されてことが保証されている (不定にはならない)

それ以外だと、デフォルト初期化と値初期化の場合で挙動が異なる

デフォルト初期化の場合

以下のSのように初期化子のカッコを付けずにオブジェクトを生成した場合のこと クラスのメンバ変数に対し、コンストラクタでのメンバー初期化子が指定されてない場合もこれになる

int main() {
    S s;
    ...
}
  • メンバがクラス型である場合
    • デフォルトコンストラクタが呼ばれる
  • メンバが配列型である場合
    • 各要素がそれぞれデフォルト初期化
  • それ以外の場合

値初期化の場合

以下のSのように初期化子のカッコを付けて定義したもの 他にもnewをつけた場合やコンストラクタでのメンバー初期化子などもこれ

int main() {
    S s();
    ...
}
  • メンバがクラス型である場合
    • デフォルトコンストラクタが呼ばれる
  • メンバが配列型である場合
    • 各要素がそれぞれデフォルト初期化
  • それ以外の場合、
    • ユーザ定義コンストラクタを持つ場合
    • ユーザ定義コンストラクタを持たない場合
      • ゼロ初期化

daedalus walletがネットワーク接続中のまま進まない

ADAを保持するためdaedalus walletをinstallしたが、起動してすぐにネットワーク接続中のまま動かなくなってしまった。何の設定もしてない状態なのでとりあえず再インストールもためしてみたが効果なし。

なのでググってみるとそういう事例はたくさんあるようこんなのを見つけた。
IOHK statement: connecting to network issue - Announcements - Cardano Forum

ただ、どれも自分の状況とは一致しておらず解決せず。
ということで自分で調べてみることに。

ログの場所は以下のFAQの下部に書いてあった。
Daedalus - Cryptocurrency wallet

macならここ
~/Library/Application Support/Daedalus/Logs

以下のコマンド実行後、walletを起動するとcardano-node.logにエラーが見つかった

$ tail -f ~/Library/Application Support/Daedalus/Logs/*
...
[node.worker.subscription:ERROR:ThreadId 563] [2017-12-23 08:04:43 JST] dnsSubscriptionWorker: no relays found for index 1
[node.worker.subscription:ERROR:ThreadId 563] [2017-12-23 08:04:43 JST] dnsSubscriptionWorker: DNS failure for index 1: [OperationRefused]
...

というわけで名前解決に失敗していることがわかった。

ps aux | grep cardanoでプロセスを確認するとcardano-nodeの起動時に多くのパラメータが設定されていることがわかる。その中の一つに以下のようなものがあった。

--report-server -n http://report-server.cardano-mainnet.iohk.io:8080

ネットワーク接続中となるのは、report serverに情報を送信しますか?という画面の直後だったので、おそらく↑への接続時にdnsが引けないのではと考えられる。

digしてみると、やはりIPアドレスを引けていない。

$ dig report-server.cardano-mainnet.iohk.io 
; <<>> DiG 9.8.3-P1 <<>> report-server.cardano-mainnet.iohk.io
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 381
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;report-server.cardano-mainnet.iohk.io. IN A

;; Query time: 3 msec
;; SERVER: 2404:1a8:7f01:b::3#53(2404:1a8:7f01:b::3)
;; WHEN: Sat Dec 23 08:24:12 2017
;; MSG SIZE  rcvd: 55

ちなみにネームサーバとしてgoogleのを使うと引ける。

$ dig report-server.cardano-mainnet.iohk.io @8.8.8.8
; <<>> DiG 9.8.3-P1 <<>> report-server.cardano-mainnet.iohk.io @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 9757
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;report-server.cardano-mainnet.iohk.io. IN A

;; ANSWER SECTION:
report-server.cardano-mainnet.iohk.io. 299 IN A 18.194.141.68

;; Query time: 95 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sat Dec 23 08:25:01 2017
;; MSG SIZE  rcvd: 71

よく見ると、デフォルトの設定ではネームサーバとしてipv6のものが使われている。試しにプロバイダのdns(ipv4)に向けてdigをすると正しく解決できた。

ちなみに、2404:1a8:7f01:bでググってみるとこれはNTT 東日本が設置しているデフォルトの DNS サーバーの模様(今回試した環境ではフレッツ光を使っている)。

よくある質問と回答 - OPEN IPv6 ダイナミック DNS for フレッツ・光ネクスト

というわけで、ネットワークの設定を見てみるとdnsの項目にipv6のものが設定されてることが判明。そこをipv4のものに変更してやってみると無事ネットワーク接続中から先に進むことができた。