2007年05月18日

[仕事覚え書き]FD_SETの恐怖

まぁ、恐怖って程のもんでもないが。覚え書きなので、多少間違った記述があるかもしれないけど、ご愛敬ご愛敬。

WinSockがどうなっているかはともかくとして、unix系のFD_**関連の話。

よく、ディスクリプタに受信データがあるかどうかを確認するのに

fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
nRet = select (fd+1, &fds, NULL, NULL, &timeout);
if( nRet < 0)
 /*エラー*/
else if(nRet == 0)
 /*タイムアウト*/

if ( FD_ISSET(fd, &fds) != 0){
/*fdに読込み可能データあり*/
}

という具合な処理をするわけですが、このルーチンを通った後でクラスが破壊されるという変な症状が。変なっていうか、マルチスレッドプログラムなので

・他のスレッドが何らかの形で破壊している(排他がうまくいってない?)

・どっかでオーバーフロー

という2点が考えられたわけです。そんなわけで月曜から調査調査。これ修正しないとマジやばい。ていうか俺が作ったソースじゃないんだが……

※工数不足により、本来は業務推進が役目なのですが4月からOSXのプログラムの応援作業も(”も”ていうかこっちがメイン?)やるハメになっているわけなのですよ。

さて、そんなわけでクラス破壊とかの前にスレッドロックが発生していたりと楽しい事が火曜日までに判明してとりあえず修正。それでもクラス破壊が起こる。とりあえず、スレッド数減らして確認してみると頻度は低くなるけどやっぱりクラス破壊が起きる。意味ワカンネ。

スレッド処理が最初問題かと思ったがそうでもなさそう。色々デバッグプリントしてみる。XCodeは、ていうかマルチスレッドだからかもしれないが、ブレークかけてトレースすると色々不安定になって、どっちのエラーなのか判らなくなるので、デバッグプリントに頼らざるを得ない。なんて原始的な…

んで、まず今日判った事。とりあえず、

FD_SET

で呼び出し元のクラス破壊が発生している。ハテ、なんでだろう。ていうか、それなら先行で作っているWin版でも起きて良いはずなのだが。とりあえず、FD_SETが何やってるか見てみると、宣言とか覚えてないので直値で書くと

 hogehoge [FD_SETSIZE / 32 ]

こんな配列があって

 hogehoge[ fd / 32] |= (1<<(fd % 32));

こんな風にして、fdの値によってbitを立てている。んで、たぶんselectの中でひっかかったのbitでも立てているのかな?(そこまで内部見ていない)

とりあえず引数fdsにビット立てるとかして返して、そんでFD_ISSETで

 hogehoge [ fd /32] &= (1<<(fd % 32))

やってビット立ってれば受信データあるよ、となるわけだ。

色々追っていってFD_SETでオーバーフロー起こしたから、マクロの中覗いたら上記な感じ。キモはFD_SETSIZE。こいつは1024に設定されている。んで、このFD_SETSIZEから配列作るからint hogehoge [32]みたいな感じになる。

FD_SETSIZE/32の32ていうのは、4バイト(OSXではintは4バイト)のデータに対して、fdの値によってbitを一つ立てるから、配列一つに対して4*8で32個のデータがもてるから。んで1024/32=32になるからタマタマ配列も32個になっているだけで、FD_SETSIZEの値を変えれば配列の数は変わる。

さて、そこで初めて気付いたのがfdの値が1024を軽く越えているという事。

そりゃオーバーフロー起こすがな

とりあえず、FD_SETSIZEの値を大きくして最初に宣言してやれば、多少オーバーしても良い事になるわけだが…値大きくしたらそれよりさらに越える値がfdにセットされやがる、チクショウ。

そんなわけで、他を当たってみる。30分ほどで判明。ログ書き出しするルーチンの中で、ログ書き出しファイルがあるか無いかの条件式が逆になっていたから、ログをwriteするたびに毎回ファイルディスクリプタ作ってやがった。

定期的にログは吐き出すから、そりゃ使えば使うほどディスクリプタは大きくなっていくのも納得。そこ修正したら見事解決。したけど、またスレッドロック起きやがった。ま、これは回避策も既に調べたのでokok。明日やるか。

しかし、FD_SETも値チェックくらいしてくれれば良いのにと思うわけで。割とFD_SETのオーバーフローはgoogle先生の検索でも引っかかったから有名なのかな。今後FD_SET使う時は、fdの値チェックするのを忘れないようにしよう。ていうか、このソース作った人にもその辺教えておこう。

#define FD_SETEx(fd, fds) \
 if ( fd > FD_SETSIZE) \
  return false; \
 FD_SET(fd, fds) \
 return true;

みたいなマクロでも用意しておいて、

FD_SET(fd, &fds);

if ( FD_SETEx(fd, &fds) == false){
  /*ディスクリプタの値がでかすぎ*/
  printf("FD_SET Error: fd is over FD_SETSIZE ");
  return false;
}
nRet = select (fd+1, &fds, NULL, NULL, &timeout);

とでも置き換えて今後は使うようにしてもらえば良いのかね。

とりあえず、今週中にはこの辺の修正を終わらせるという目標は達成できそうだが、他の推進業務とか定型業務が滞っちまったなぁ…修正は明日の午前中で終わるけど、溜まった仕事捌けるのに丸1日はかかりそうな予感…

ちなみに、条件式間違いしたのは○○○トという名前の人なので

○○○トラップ

と名付けてあげました。俺の4日間を返せw

WinのFD_SETは前述とは違うやり方やってるみたいネ。

しかし、前プロジェクトとか前会社でも思ったのだがとりあえずWindowsで作ってできるだけ共通ソースにしたらMac(OSX)でもちょっと修正する程度で動くはず、みたいな作り方はそろそろやめてくれないかなぁ…

って所で夜中の2時経過。まぁ、おかげで明日午前中に修正するために必要な情報とかは調べ上げられたので、あとは溜まった仕事を午後から初めて何時までに終わらせられるかって所かなぁ…

あー ねみぃ ねみぃ。今週こんだけ頑張ったんだから、きっと来週は………

とりあえず、この問題が解決したことでもしかしたら休日出勤もあるかも、という自体は免れたし、来週は今週よりも娘との時間を作ることができる可能性が出来たから良しとするか。

チマチマ間違い記述修正してたら3時だよ

・寝る

・徹夜

・泣く

どうする?俺!?

posted by gigabeat360 at 02:03| Comment(1) | TrackBack(0) | 仕事覚え書き | このブログの読者になる | 更新情報をチェックする

2007年04月17日

[仕事覚え書き]OpenSSL

いずれ仕事で使う事があるかもしれないので、OpenSSLについての覚え書き

http://www.openssl.org/

上記サイトからソースを落として来てビルドする。バージョン0.9.6はAESをサポートしていないので注意。OSX 10.2.xはOpenSSL0.9.6までしかソフトアップデートでは入らないので注意。

【ビルド方法】

Windows版はINSTALL.W32を参照しながらやれば割と簡単。Perlがいるとか多少準備はあるが基本的にはすぐできる。OpenSSL 0.9.8 の Win32 環境用ライブラリを自力でビルドする方法を参照しても良い

OSX版は以下のコマンドで可能

>./config

>make

>make test

>make install

ただし、この方法ではStatic Libraryが作成される。Shared Libraryが欲しければ最初の./configにオプションをつけて

>./config shared

としてから残りのコマンドを実行する。LinuxとかBSDとかも基本的には上記でいけるはず。

【暗号化スイーツ】

opensslでサポートしている暗号化スイーツを調べる時にはbinフォルダ内にあるopensslコマンドを以下のオプションつけて実行

>openssl ciphers

他にもオプションがあるので色々見てみると良い。ちなみに、暗号化処理速度を測定したい場合は

>openssl speed

である程度の速度は計測できる。

【暗号化アルゴリズム】

☆共通鍵暗号方式

DES、3DES、RC2、RC4、RC5、IDEA、AES、blowfish、Camellia辺りをサポートしている。

RC2とRC4という名称はRSA Security社の登録商標なので注意。

RC4は実際にはArcfour。RC4自体はRSA Security社は仕様などを一切公表していない。昔、ニュースグループにアルゴリズムが配信されたが、それがRC4だとはRSA Security社は認めていない。

IDEAとRC5は特許が絡むので注意。Camelliaはロイヤリティフリーだったはず。

AESもロイヤリティフリー。AESはNISTが特許権と著作権などを一切放棄する事を条件に公募した暗号アルゴリズム。

強度については、鍵長にも影響してくる部分があるのでなんとも言えないが、少なくともDESは56bit鍵なので強度は強くない。RC2も破られる方法があるっぽい。

電子政府推奨暗号リストによれば、ブロック暗号は「AES」、ストリーム暗号は「128bit RC4」を使用するのが望ましい?Camelliaでも良いが、OpenSSLでCamelliaはデフォルトではサポート外。また0.9.7ではそもそも含まれていないかも。blowfishも欧州では割とメジャーっぽいが、疑問の残る所もあるらしい。無理に使う必要は無さそう。

ちなみに、OpenSSLの共通鍵暗号アルゴリズムでは、ストリーム暗号はRC4のみで、それ以外は全てブロック暗号。

ブロック暗号使用時、CBCモードやECBモードを使用するとブロック長に満たない平文ブロックがあるとパディングを行うので、平文と暗号文でデータ長が異なる事がある。これがイヤならCFBかOFBを使用する。

ただし、ECBとOFBは仕様的にかなり強度は弱い、というかECBに至っては使う意味が無いかもしれないので、CBCかCFBを使用するのがベター。

パディング方法はいくつかあるが、PKCS#5が一般的?ただし、OpenSSLでパディング方式を色々設定できるのかはまだ不明。まぁ、無理なら自力で作れば良さそうだが。

PKCS#5は残りバイト数で埋めていくもの。ブロック長8バイトで0x0A0B0C0Dという4バイトしか無かったら、0x04で残りのバイトを埋めて0x0A0B0C0D04040404となる。

ちなみに、AES-CBCではIVを入れていたような気がする。data[n]=IV[n]て感じ。

☆公開鍵暗号方式

RSA、DH、DSSをサポートしている。

RSAはRSA Security社の登録商法。特許については2000年9月に放棄してパブリックドメインになっている。

DSS(正確にはDSSで指定さているDSA)は、アメリカ政府がパテント持ってるとかなんとか。個人使用や非商用目的はロイヤリティフリーだが、商用目的は??

☆ハッシュ・ダイジェスト

MD2、MD5、SHA-1、SHA-192、SHA-256、SHA-384、SHA-512、MDC2、HMACあたりをサポート。

MDC2は特許が絡むので注意。

【SSL通信】

まだ調べ中………

ただ、色々検索してみるとOSI層のトランスポート層に位置するとかソケット層に位置するとか書かれているが、動きを見る限り、トランスポート層とソケット層の間で動いている(またはそれぞれの半分ずつを担っている)みたいな感じが一番しっくりくる。

とりあえず、使用する暗号化スイーツについては、Cipher Listをクライアント/サーバ間で交換してその中で一番強いものを使用する仕組み。

とりあえず殴り書き。

posted by gigabeat360 at 23:15| Comment(0) | TrackBack(0) | 仕事覚え書き | このブログの読者になる | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。