2006年05月17日

Heimdallrのバグ対策

5/16の記事の続きです。

不具合の原因は恐らく以下の通りです。残念ながら、断言できるところまで解析はできませんでしたが。

Heimdallrは、MFCのCInternetSession/CHttpConnection/CHttpFileクラス(以下、CInternetSession関連クラス)をマルチスレッドで使用してインターネットアクセスを行っておりますが、
残念ながらこれらのクラスはスレッドセーフではないことが原因のようです。
特に、Heimdallrでは、サーバに接続した後、一定時間が経過した場合、別スレッドからCHttpFile::Closeを呼んで切断しているのですが、このやり方に問題があったようです。

さて不具合の原因が大体明らかになったところで、対策を考えてみます。
スレッドセーフじゃないならスレッドセーフにすれば良いだけのようですが、残念ながらそう簡単にスレッドセーフにはできないようです。

まず最初に、Heimdallrのインターネットアクセスに関する要件をまとめてみます。
(1) HTTPに対応していること。
(2) HTTPSに対応していること。
(3) 同時に複数の接続が張れること。
(4) 指定した時間が経過した場合は強制的に接続を切断できること。

従来は、(1)(2)を満たすためにCInternetSession関連クラスを使い、(3)(4)を満たすためにマルチスレッドを使っていたわけです。

不具合の対策を行った後も、これらの要件を全て満たす必要があります。
といっても(1)(3)は別にどうということはありません。厄介なのは(2)(4)です。

とりあえず対策を適当に挙げてみます。
(a) CInternetSession関連クラスのラッパを作成してスレッドセーフにする。
(b) (4)を実行するときに別スレッドからCHttpFile::Closeを呼ぶ方法以外の方法を使う。
(c) 自分でsocketを使ってスレッドセーフなHTTPライブラリを作る。
(d) スレッドセーフなWinINetライブラリのラッパクラスを作成する。
(e) 他のHTTPライブラリを使用する。

対策(a)について。残念ながら(4)を満たしつつスレッドセーフにする方法が分かりませんでした。WinINetの非同期モードを使えればなんとかなりそうなのですが、CInternetSession関連クラスは同期モードにしか対応していないようなので無理そうです。
対策(b)について。CInternetSessionクラスは受信タイムアウトを設定できるのでなんとなく行けそうだったのですが、残念ながらこの受信タイムアウトは受信パケット間のタイムアウトを指定するパラメータでした。つまり、タイムアウトを2秒に設定しておいても、1秒毎に1バイト受信し続けることができれば何秒経ってもタイムアウトしないのです。これでは(4)を満たせません。残念。
対策(c)について。これは(2)が無理。勘弁して下さい。
対策(d)について。これは対策(a)(b)を同時に実施するのに近いものがあります。WinINetの非同期モードが使えるラッパクラスにすれば全ての要件を満たせそうです。
対策(e)について。(2)(4)を同時に満たせるライブラリが見つかってみません。まあ(d)で行けそうだからあまり探してもいないんですけど。

というわけで現状は対策(d)を進める予定です。

投稿者 MASATO : 2006年05月17日 22:56 | トラックバック
コメント

> このあたりが関連するかな?という気がします。
> http://support.microsoft.com/default.aspx?scid=kb%3Bja%3B263754
まさしくこれですね。教えて頂きありがとうございます。

原因はInternetReadFile API のバグとのことですので、最初にWinINetのバグについてしっかり調べておけば良かったですね。

Posted by: MASATO : 2006年05月18日 08:13

このあたりが関連するかな?という気がします。
インターネットオプションの設定変更で Wininet も改善できるかもしれませんね。
http://support.microsoft.com/default.aspx?scid=kb%3Bja%3B263754

この現象はうちのRSSリーダーでも希に報告されます。
特に Thread を使用しない Headline-Deskbar でも報告が
ありますので Thread が(頻発の要因であっても)原因とはいえません。

Posted by: t.o : 2006年05月18日 00:27
コメントする









名前、アドレスを登録しますか?