バックグラウンド
Linux カーネル 2.6.35 を実行する小さなヘッドレス ボックスと、ARM ハードウェア上の Open Embedded ディストリビューションのいくつかのバリアントがあります。
私たちが知る限り、glibc 2.10.1 を使用しています。
ボックスには、接続されていないイーサネットと、シリアル接続された GSM/3G モデムがあります。インターネットへの接続を継続できるように PPP を構成しました。この部分は問題なく動作します。
ソケットを使用して何らかの接続を行う c (実際には c++) でコーディングされたプログラムがあります。このプログラムは、pthreads を使用して高度にマルチスレッド化されています。
接続先の IP アドレスを検索するには、gethostbyname() を使用します。
インターネットへの接続がない場合、たとえば初期ブート中または SIM カードがモデムから取り外された場合、gethostbyname() は本来あるべき NULL を返します。
症状
しかし、インターネット接続が稼働しているにもかかわらず、時折 gethostbyname() が NULL を返し続けます。
getaddrinfo() を使用した場合のエラー コードは EAI_NONAME ~ "名前またはサービスが不明です" です。gethostbyname() からのエラー コードは手元にありませんが、同等でした。
私たちの分析
(シリアルコンソール経由で)インターネット接続が正常であることを確認しました
- リスト項目
- /var/log/messages を確認し、pppd がすべて OK であることを確認しました
- ホスト名を ping します (IP に変換され、OK と応答します)
- パブリック IP 経由で ssh 経由でボックスに接続します
プロセスには、同じホストに対して gethostbyname() を使用する 2 つのスレッドがあります。コードパスと関数はわずかに異なりますが、gethostbyname() を呼び出す部分を含め、ソケット関数に共通のコードを使用します。
gethostbyname() が NULL を返し続ける状況では、これは通常、スレッドの 1 つにのみ当てはまり、毎回同じスレッドではありません。もう1つはルックアップを完全に行います。
さらに、失敗した gethostbyname() を持つスレッドは、そのスレッドを簡単に制御して停止し、関数を再起動することで簡単に機能させることができます。これにより、新しいスレッドが pthread 単位で生成されます。
全体として、DNS 変換とインターネット接続が OS レベルで正常に機能していると確信しています。
スレッド化の問題を排除するために、マニュアル ページに従って再入可能である getaddrinfo() を使用してルックアップ コードを再実装しました。そして、まったく同じ結果が得られます。
スレッドを終了すると、gethostbyname()/getaddrinfo() のルックアップ機能に影響を与えるある種のクリーンアップが発生するようです。
回避策は、失敗したスレッドを強制的に終了させることですが、これはアプリケーション構造の大幅な変更を意味し、実際にはオプションではありません。
質問
質問は次のとおりです。解決策を探す場所や、実際の問題がどこにあるのか、何かヒントはありますか?