[mew-dist 26717] ちょっぴり敗北宣言
Kazu Yamamoto ( 山本和彦 )
kazu at example.com
2005年 12月 9日 (金) 17:46:54 JST
山本です。
後で思い出すための技術的なメモです。技術に興味がある人のみお読み下さい。
フォールバック大作戦から学んだことの一つに、投稿ポートから SMTP ポート
へフォールバックする際は、それぞれで IPv6 から IPv4 へフォールバックし
なければならないというのがあります。
ややこしいので図に描くと、
投稿ポート/IPv6
↓
投稿ポート/IPv4
↓
SMTPポート/IPv6
↓
SMTPポート/IPv4
とフォールバックしていかなければなりません。
ELisp ではサーバ名とポート名を指定しますので、ポートレベルのフォールバッ
クができます。
名前から IPv6/IPv4 へ変換するのは C レベルなので、IPv6 => IPv4 のフォー
ルバックをするのは、C レベルになります。
blocking な場合を図に描くとこんな感じ:
-----------------------------------------------------------------------
Elisp: open-network-stream(サーバ名、ポート名)
-----------------------------------------------------------------------
C: make_network_process {
getaddrinfo();
for (それぞれのアドレス) {
connect();
/* blocking なら IPv6 => IPv4 できるよーん */
}
}
-----------------------------------------------------------------------
さて、IPv6 => IPv4 のフォールバックを忘れ、non-blocking connect() の仕
組みを描くとこんな感じ:
-----------------------------------------------------------------------
Elisp: make-network-process(サーバ名、ポート名) sentinel(イベント)
-----------------------------------------------------------------------
C: make_network_process { 別の C の関数 {
getaddrinfo(); select();
non-blocking connect(最初のアドレス) 接続できたら、
sentinel へ
} }
-----------------------------------------------------------------------
というわけで、getaddrinfo() している関数と select() している関数が別な
ので、non-blocking connect() では IPv6 => IPv4 へのフォールバックができ
ません! (受け入れられる方法で C レベルを改造するのは無理!)
まとめ:
1) non-blocking connect() では、IPv6=>IPv4 フォールバックができない
2) blocing connect() では、IPv6=>IPv4 フォールバックができる
よって、いろいろ考えてた結果、
a) 投稿ポートへは IPv4 を指定して non-blocking connect()
b) SMTP ポートへは connect()
という風に Mew を改造します。
これにより、以下のようなフォールバックが実現できます。
投稿ポート/IPv4
↓
SMTPポート/IPv6
↓
SMTPポート/IPv4
IPv6 普及委員会副会長としては、敗北感に打ちのめされていますが、それ以上
に迷惑メールを退治する方が大切です。
なお、「IPv4 を指定して non-blocking connect()」するには、
make-network-process() の引数 :family に AF_INET の値を指定しないといけ
ません。
BSD では AF_INET は 2 と #define されていますが、他の OS ではどうなって
いるでしょうか?
P.S.
remote サーバだと non-blocking connect() できるが、
local サーバだとできない問題ですが、分かりました。
remote サーバだと、non-blocking connect() した瞬間に「仕様通り」
EINPROGRESS が返ります。
FreeBSD/NetBSD で、local サーバに non-blocking connect() すると、
すぐに TCP RST が返るため、ECONNREFUSED が返ります。(このため、
この場合に限り、なんと IPv6 => IPv4 へフォールバックできます。)
make-network-process() は仕様にない ECONNREFUSED なんて知らないので、接
続できない場合、nil を返すのでした。
挙動さえ理解してしまえば、これはこれでいいかなと思っています。Mew では
対応済みだし。
--かず
Mew-dist メーリングリストの案内