Raspberry PiとRTL2832Uドングルを受信サーバとして使うためにrtl_tcpを修正した
前回Raspberry PiをRTL2832Uドングル用受信サーバとして使う方法を紹介しました。しかしながら実際に使用しようとした場合、安定して使用することができていませんでした。gqrxやgnuradioで構成したクライアントを使用して、rtl_tcpに接続したのち、一度切断、そして再接続しようとした時に、rtl_tcpが不正終了してしまい、いちいちコマンドを起動しなおす必要がありました。せっかく便利そうなリモート受信サーバなのですが、このままではちょっと残念な感じでした。そこで不具合の原因調査と修正を行いました。結果うまく安定して動作させることができるようになりました。また、受信サーバとして運用するには、マシンを起動したときに自動的にサービスが起動して欲しいものです。そのための起動スクリプトを作成しましたので、こちらもあわせて紹介します。
まずは不具合の状況ですが、Linuxマシン(Raspberry Piを使っています)にRTLドングルを接続、rtl_tcpコマンドを起動し、gqrxで接続を行いました。そうするとrtl_tcpコマンド側は以下のように動作していました。
$ rtl_tcp -a 0.0.0.0 Found 1 device(s). Found Rafael Micro R820T tuner Using ezcap USB 2.0 DVB-T/DAB/FM dongle Tuned to 100000000 Hz. listening... Use the device argument 'rtl_tcp=0.0.0.0:1234' in OsmoSDR (gr-osmosdr) source to receive samples in GRC and control rtl_tcp parameters (frequency, gain, ...). client accepted! set gain mode 1 set sample rate 1024000 set freq 82500000 set gain mode 0 set gain 490 ll+, now 1 ll+, now 2 ll+, now 3 ll+, now 4 ....
このように一度目は正常です。その後、gqrxの動作を止めると以下のようにrtl_tcpも停止し、接続の待ち受け状態に戻ります。
worker socket error Signal caught, exiting! comm recv socket error Signal caught, exiting! all threads dead.. listening...
この状態で再度gqrxで接続を行います。そうするとrtl_tcpコマンドは以下のように動作開始しようとするのですが、すぐに落ちてしまいます。
Use the device argument 'rtl_tcp=0.0.0.0:1234' in OsmoSDR (gr-osmosdr) source to receive samples in GRC and control rtl_tcp parameters (frequency, gain, ...). comm recv socket error Signal caught, exiting! Segmentation fault
このように再接続で落ちてしまうようでは受信サーバとして使うことは困難です。何度接続しても大丈夫なように安定していることが望まれます。
というわけで調べてみたところ、TCP接続が切断された時の処理に不完全なところがあるようでした。TCP切断でシグナルが発生したとき、複数のスレッドが存在していることが原因で、本来一度だけ呼ぶべきrtlsdr_cancel_asyncが、複数回呼ばれていることが原因のようです。とりあえず最小限の修正をしてみたところ、とりあえず落ちることがなくなりました。
修正したソースは、githubに上げておきます。本家osmocomにパッチの取り込みを依頼する予定です。
以下ビルド方法のメモです。
$ wget https://github.com/edy555/rtl-sdr/archive/rtltcpFixSegv.zip $ unzip rtltcpFixSegv.zip $ cd rtltcpFixSegv $ libtoolize --force $ autoreconf -i $ ./configure $ make $ sudo make install $ sudo make install-udev-rules $ sudo ldconfig
依存ライブラリのインストールなどについては前の記事を参照してください。
rtl_tcpを安定して動作させることがようになったら、今度はマシン起動時に自動的にサービス起動するようにしたいものです。Linuxのディストリビューションとしてdebian(実際にはその派生であるraspbian)を使っています。debianでは/etc/init.dに起動スクリプトを配置したうえで、update-rc.dコマンドにより設定することで、自動起動を行うことができます。
作成したスクリプトrtl_tcp.rcは、こちらになります。
上記のスクリプトをダウンロードし、/etc/init.dにrtl_tcpというファイル名でコピー、update-rc.dコマンドで起動設定を行います。
$ sudo cp rtl_tcp.rc /etc/init.d/rtl_tcp $ sudo update-rc.d -n rtl_tcp start 99 5
スクリプトをインストールしたら、下記のコマンドで手動でサービスの起動、再起動、停止、動作確認を行うことができます。
$ sudo /etc/init.d/rtl_tcp start $ sudo /etc/init.d/rtl_tcp restart $ sudo /etc/init.d/rtl_tcp stop $ sudo /etc/init.d/rtl_tcp status
このスクリプトは、コマンドをサービスとして動作させるために、debian標準のstart-stop-daemonコマンドを使っています。また、rtl_tcpコマンドは、uidとしてnobodyで動作させています。
以上rtl_tcpを安定動作させられるようになり、またサービスとして自動起動することができるようになりました。おかげさまでリビングのコタツでぬくぬくとワイヤレスのオペレーションが可能です。ご参考になれば幸いです。
メモと謝辞とリファレンス
サービスとして利用できるとはいえセキュリティ的脆弱性が存在する可能性が多分にありますので、外部のインターネットから接続可能な場所での運用は避けた方が良いと思われます。
SDR#からの使用に際しての不具合報告とWindows環境でのビルド確認に、@sdrfunさんのご協力をいただきました。ありがとうございました。
電源をいきなり切断しても大丈夫なように、AUFSなどを使ってファイルシステムをread onlyマウントすることもやってみたいと考えています。
オリジナルのrtl-sdrの配布元osmocom-rtl http://sdr.osmocom.org/trac/wiki/rtl-sdr
keenerdさんのリポジトリ。精力的にアップデートされています。興味深いのはrtl_adsbというコマンドが追加されたことです。gr-air-modes, rtl1090に続くRTLドングルを使った第3のmode-b受信方法となりそうです。このリポジトリはosmocomに取り込まれるとrebaseされてしまうようですのでfork/cloneの際には注意が必要です。https://github.com/keenerd/rtl-sdr
修正したソースはこちら https://github.com/edy555/rtl-sdr/tree/rtltcpFixSegv
起動スクリプトrtl_tcp.rc https://github.com/edy555/rtl-sdr/blob/rtltcpFixSegv/rtl_tcp.rc













