■ISCPという謎のプロトコルで制御できるようになったAVセンターですが、IPアドレスはDHCPなので、もしかしたらIPアドレスが変わってしまうかもしれない。変わるたびに調べるのは面倒だし、AndroidアプリにはAVセンターのアドレスを設定せずにつかえているので、何らかの方法でサーチしているはず。SSDPのSEARCHコマンドあたりではないだろうか。
そう思ってSEARCHパケットを流してみると、AVセンターの電源が入っているときは応答を拾えたのですが、電源が落ちている(待機状態になっている)と応答が出てこない。別の方法でサーチしているわけで、もういちどパケットキャプチャで調べてみました。
解ったことはブロードキャストパケットでISCPの'ENQSTN'コマンドが流れていて、AVセンターがそれに応答していることでした。応答パケットにはデバイス名、ポート番号、MACアドレスがASCIIの可読文字列で格納されています。
さっそくLinuxサーバーから同じパケットを作ってUDPのブロードキャストで流してみました。
PHPでは次のような流れになります。
1) $soc=socket_create (AF_INET, SOCK_DGRAM, SOL_UDL)
2) socket_set_option ($soc, SOL_SOCKET , SO_BROADCAST, 1)
3) socket_sendto ($soc, [パケット], [長さ], 0, "255.255.255.255", 60128)
4) socket_recvfrom($soc, $buff, [受信長], MSG_WAITALL, $wip, $port);
※(4)の$wipは"0.0.0.0"、$portは0を設定します。
UDPの送受信はこれでいいはずなんですが、なぜか受信できません。socket_recvfromでブロックされてしまいます。AVセンターからの応答が出ていないのかと、パケットキャプチャすると、AVセンターからの応答は出ているのですが、それに対してLinuxサーバーからICMPのコード10 ('Destination host administratively prohibited')が応答されています。
ICMPのコード10が返される理由がよくわからなかったのですが、ユニキャストのやり取りでは問題なかったことと、ユニキャストをSO_REUSEADDRで行った直後のブロードキャストのやりとりでは成功すること、しかし時間がたつとブロードキャストからユニキャストの受信ができなくなること、などの現象からファイアウォールがそれらしく思えてきました。
結論からするとファイアウォールの設定でした。ブロードキャスト送信とユニキャスト応答が別のセッションで扱われるらしく、ユニキャスト応答がファイアウォールで撥ねられていたのでした。
AVセンターからの応答はあくまでもブロードキャスト時のクライアント側のポートに対して行われるので、ブロードキャスト前にbindして特定のポートを使うようにして、ファイアウォールでそのポートをudp受信可にしてやることで使えるようになりました。
先の手順で言えば、(1)と(2)の間にsocket_bindが入ります。
socket_bind($soc, "0.0.0.0.0", [ポート番号])
これで、コマンド側にAVセンターのIPアドレスを埋め込む必要がなくなりました。一旦ブロードキャストでアドレスを確認してから、TCPでAVセンターのIPアドレスに対してコマンドを送信するようにできます。