[インデックス 12456] ファイルの概要
このコミットは、Go言語の標準ライブラリnet
パッケージ内のTestDialTimeout
テストがWindows環境のビルドサーバーで失敗する問題を修正するものです。具体的には、テストが意図しない成功を収めてしまう原因となっていたポート番号の変更と、ダイヤルが失敗したことを明示的に確認するチェックの追加が行われました。
コミット
commit c804efb5de2f73a7ce12b4b09a2947b164c3aa43
Author: Russ Cox <rsc@golang.org>
Date: Wed Mar 7 00:41:24 2012 -0500
net: fix TestDialTimeout on windows builder
I don't know what's out there, but something
is answering to 127.0.71.111:80 on our builder,
so use a different port.
Also insert a check that the dial fails, which
would have diagnosed this problem.
Fixes #3016.
R=golang-dev, mikioh.mikioh, r
CC=golang-dev
https://golang.org/cl/5754062
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c804efb5de2f73a7ce12b4b09a2947b164c3aa43
元コミット内容
net: fix TestDialTimeout on windows builder
このコミットは、Windowsビルドサーバー上でTestDialTimeout
テストが失敗する問題を修正します。
問題の原因は、ビルドサーバー上で127.0.71.111:80
に対してダイヤルを試みた際に、何らかのサービスが応答してしまい、テストが意図せず成功してしまうことでした。
このため、テストで使用するポートを別のものに変更し、さらにダイヤルが失敗したことを明示的に確認するチェックを追加しました。これにより、将来同様の問題が発生した場合に診断が容易になります。
この修正は、Issue #3016に対応するものです。
変更の背景
TestDialTimeout
は、指定されたタイムアウト時間内に接続が確立できない場合に、DialTimeout
関数がエラーを返すことを検証するためのテストです。このテストでは、通常、存在しないIPアドレスやポートに対して接続を試みることで、意図的に接続失敗を発生させます。
しかし、Go言語のWindowsビルドサーバーにおいて、127.0.71.111:80
というアドレスとポートの組み合わせに対してDialTimeout
を呼び出した際に、予期せず接続が成功してしまうという問題が発生しました。コミットメッセージによると、「何らかのサービスが応答している」とのことです。これは、ビルド環境のネットワーク設定、仮想マシンの構成、ファイアウォール、あるいはデータセンターのインフラストラクチャが、特定のローカルIPアドレスとポート(特にHTTPの標準ポートである80番)への接続を傍受し、応答を返してしまう状況を示唆しています。
この予期せぬ接続成功は、テストの目的(タイムアウトによる接続失敗の検証)を妨げ、テストが誤ってパスしてしまう原因となっていました。そのため、テストの信頼性を確保し、DialTimeout
関数の正しい動作を検証するために、この修正が必要となりました。また、将来的に同様の問題が発生した場合に、その原因を特定しやすくするための診断メカニズムの追加も行われました。
前提知識の解説
DialTimeout
関数: Go言語のnet
パッケージに存在する関数で、指定されたネットワークアドレス(例:tcp
,127.0.0.1:8080
)に対して接続を試み、指定されたタイムアウト時間内に接続が確立できない場合にエラーを返します。ネットワーク接続のタイムアウト処理をテストする際などに利用されます。127.0.0.1
(localhost): ループバックアドレスとして知られ、自身のコンピュータを指します。127.0.0.1
から127.255.255.255
までの範囲はループバックアドレスとして予約されており、通常は外部ネットワークには到達しません。テスト目的で、存在しないサービスへの接続をシミュレートするためによく使用されます。- ポート80: HTTPプロトコルの標準ポートです。Webサーバーが通常このポートでリクエストを待ち受けます。
- ビルドサーバー (Builder): ソフトウェア開発において、ソースコードをコンパイルし、実行可能なバイナリやパッケージを生成するための専用サーバーです。継続的インテグレーション (CI) システムの一部として機能し、コードの変更がコミットされるたびに自動的にビルドとテストを実行します。ビルドサーバーの環境は、開発者のローカル環境とは異なる場合があり、それが今回のような問題を引き起こすことがあります。
- TCP/IP: インターネットを含む多くのネットワークで利用される通信プロトコル群です。TCP (Transmission Control Protocol) は信頼性の高いデータ転送を提供し、IP (Internet Protocol) はデータのルーティングを担当します。
DialTimeout
はTCP接続の確立を試みます。 - IIS (Internet Information Services): Microsoftが提供するWebサーバーソフトウェアです。Windows環境でWebサイトをホストする際によく利用されます。コミットメッセージで「IIS web server」に接続された可能性が示唆されているのは、ポート80番がHTTPの標準ポートであり、Windows環境でIISが稼働している場合にそのポートをリッパしている可能性があるためです。
技術的詳細
このコミットの技術的な核心は、TestDialTimeout
テストの堅牢性を高めることにあります。
-
ポート番号の変更:
- 元のテストでは、
127.0.71.111:80
というアドレスとポートの組み合わせを使用していました。ポート80はHTTPの標準ポートであり、多くのシステムでWebサーバー(IISなど)が稼働している可能性があります。 - Windowsビルドサーバーでこのポート80への接続が予期せず成功してしまったため、テストの意図(接続失敗)が達成されませんでした。
- 修正では、ポート番号を
80
から44444
に変更しました。44444
は一般的に使用されない非特権ポートであり、このポートでサービスが稼働している可能性は非常に低いため、接続が失敗する確率が高まります。これにより、テストが意図した通りにDialTimeout
がエラーを返すことを検証できるようになります。
- 元のテストでは、
-
明示的な接続失敗チェックの追加:
- 以前のテストでは、
DialTimeout
がエラーを返さない場合に、その原因を特定するのが困難でした。 - 修正では、
DialTimeout
の呼び出し結果としてerr == nil
(エラーがない、つまり接続が成功した)の場合に、明示的にエラーを生成するロジックが追加されました。 - 具体的には、
fmt.Errorf("unexpected: connected to %s!", c.RemoteAddr())
というエラーメッセージを生成し、接続が成功したことを示すリモートアドレスを含めることで、デバッグ時の情報量を増やしています。 - さらに、予期せず接続が成功してしまった場合には、確立された接続
c
をc.Close()
で即座に閉じ、リソースリークを防いでいます。 - このチェックの追加により、テストが誤って成功した場合でも、その原因(予期せぬ接続成功)が明確に診断されるようになり、テストの信頼性とデバッグの容易性が向上しました。
- 以前のテストでは、
-
Windows環境への適用:
- 元々
darwin
(macOS)環境でのみ適用されていた「希望的に死んでいる127/8
アドレスに接続する」というロジックが、今回の修正でwindows
環境にも適用されるようになりました。これは、macOSと同様にWindowsでも特定のローカルアドレスへの接続が予期せぬ挙動を示す可能性があるためです。
- 元々
これらの変更により、TestDialTimeout
は、様々な環境下でDialTimeout
関数のタイムアウト挙動をより正確かつ確実に検証できるようになりました。
コアとなるコードの変更箇所
--- a/src/pkg/net/dial_test.go
+++ b/src/pkg/net/dial_test.go
@@ -6,6 +6,7 @@ package net
import (
"flag"
+ "fmt"
"regexp"
"runtime"
"testing"
@@ -44,13 +45,22 @@ func TestDialTimeout(t *testing.T) {
errc <- err
}()
}
- case "darwin":
+ case "darwin", "windows":
// At least OS X 10.7 seems to accept any number of
// connections, ignoring listen's backlog, so resort
// to connecting to a hopefully-dead 127/8 address.
// Same for windows.
+ //
+ // Use a bogus port (44444) instead of 80, because
+ // on our 386 builder, this Dial succeeds, connecting
+ // to an IIS web server somewhere. The data center
+ // or VM or firewall must be stealing the TCP connection.
go func() {
-\t\t\t_, err := DialTimeout("tcp", "127.0.71.111:80", 200*time.Millisecond)
+\t\t\tc, err := DialTimeout("tcp", "127.0.71.111:44444", 200*time.Millisecond)
+\t\t\tif err == nil {
+\t\t\t\terr = fmt.Errorf("unexpected: connected to %s!", c.RemoteAddr())
+\t\t\t\tc.Close()
+\t\t\t}
errc <- err
}()
default:
コアとなるコードの解説
このコミットによるsrc/pkg/net/dial_test.go
への変更は以下の通りです。
-
fmt
パッケージのインポート追加:import ("fmt")
が追加されました。これは、新しく追加されるエラーメッセージ生成のためにfmt.Errorf
関数を使用するためです。
-
case "darwin"
からcase "darwin", "windows"
への変更:TestDialTimeout
関数内のswitch runtime.GOOS
文において、以前はdarwin
(macOS)環境のみに適用されていたテストロジックが、windows
環境にも適用されるようになりました。これにより、Windowsビルドサーバーでの問題に対応します。
-
ポート番号の変更とコメントの追加:
DialTimeout
の呼び出しで指定されるアドレスが、"127.0.71.111:80"
から"127.0.71.111:44444"
に変更されました。ポート80番がWindowsビルドサーバー上で予期せず応答してしまう問題があったため、使用される可能性が低いポート44444番に変更されました。- 新しいコメントが追加され、ポート80番がIISウェブサーバーなどに接続されてしまう可能性があり、データセンター、VM、またはファイアウォールがTCP接続を「盗んでいる」可能性があることが説明されています。これは、問題の背景を明確にするための重要な情報です。
-
接続成功時のエラーチェックの追加:
DialTimeout
の戻り値である接続オブジェクトc
とエラーerr
を受け取るようになりました。if err == nil
という条件が追加されました。これは、DialTimeout
がエラーを返さずに接続が成功してしまった場合に実行されます。- この条件が真の場合、
fmt.Errorf("unexpected: connected to %s!", c.RemoteAddr())
を使って新しいエラーが生成されます。このエラーメッセージには、予期せず接続されたリモートアドレスが含まれており、デバッグに役立ちます。 - エラー生成後、
c.Close()
が呼び出され、予期せず確立された接続が閉じられます。これにより、リソースリークを防ぎます。 - 最終的に、この生成されたエラーが
errc
チャネルに送信され、テストフレームワークによって捕捉されます。
これらの変更により、TestDialTimeout
はWindows環境においても、意図した通りに接続がタイムアウトし、エラーを返すことを確実に検証できるようになりました。また、万が一予期せぬ接続が成功した場合でも、その事実が明確に報告され、問題の診断が容易になります。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/c804efb5de2f73a7ce12b4b09a2947b164c3aa43
- コミットメッセージに記載されているGo CL (Change List) リンク
https://golang.org/cl/5754062
は、現在の公開されているGoのコードレビューシステムでは見つかりませんでした。これは、古い内部的なCL番号であるか、リンクが変更された可能性があります。 - コミットメッセージに記載されているIssue
#3016
は、現在のGoの公開Issueトラッカーや一般的なWeb検索では、このコミットの内容に直接関連するものは特定できませんでした。これは、当時のGoの内部Issueトラッカーの番号である可能性が高いです。
参考にした情報源リンク
- Go言語の
net
パッケージに関する一般的な知識 - TCP/IPおよびネットワークプロトコルに関する一般的な知識
- ソフトウェア開発におけるビルドサーバーおよび継続的インテグレーションの概念
- Web検索による
golang.org/cl/5754062
およびGo issue 3016
の調査結果(ただし、直接的な関連は確認できず)