[インデックス 18748] ファイルの概要
このコミットは、Go言語のnet
パッケージにおけるDragonFly BSD上での非ブロッキングコネクト処理のバグ修正に関するものです。具体的には、net/fd_unix.go
ファイルが変更され、非ブロッキングソケットでのconnect
システムコールが複数回実行された際の挙動が改善されています。
コミット
commit 734d4637c5925826904ffe7406cd411568928cb4
Author: Joel Sing <jsing@google.com>
Date: Thu Mar 6 00:07:16 2014 +1100
net: fix non-blocking connect handling on dragonfly
Performing multiple connect system calls on a non-blocking socket
under DragonFly BSD does not necessarily result in errors from earlier
connect calls being returned, particularly if we are connecting to
localhost. Instead, once netpoll tells us that the socket is ready,
get the SO_ERROR socket option to see if the connection succeeded
or failed.
Fixes #7474
LGTM=mikioh.mikioh
R=mikioh.mikioh
CC=golang-codereviews
https://golang.org/cl/69340044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/734d4637c5925826904ffe7406cd411568928cb4
元コミット内容
このコミットの元の内容は、DragonFly BSD環境において、非ブロッキングソケットに対する複数回のconnect
システムコールが、以前のconnect
コールからのエラーを適切に返さないという問題に対処するものです。特にlocalhost
への接続時にこの問題が顕著でした。修正は、netpoll
がソケットの準備ができたことを通知した後、SO_ERROR
ソケットオプションを取得して接続の成否を確認するというアプローチを取っています。
変更の背景
この変更の背景には、Go言語のネットワークスタックが様々なOSで一貫して動作するようにするための努力があります。特に、非ブロッキングI/Oは高性能なネットワークアプリケーションを構築する上で不可欠な要素ですが、OSごとにその挙動には微妙な違いが存在します。
DragonFly BSDは、FreeBSDからフォークしたUNIX系OSであり、独自のカーネル設計やシステムコール実装を持つことがあります。このコミットで修正された問題は、DragonFly BSDのconnect
システムコールが、非ブロッキングモードで複数回呼び出された際に、期待されるエラーコード(例えばEINPROGRESS
やEALREADY
)を常に返さないというOS固有の挙動に起因しています。
Goのnet
パッケージは、内部的にnetpoll
というメカニズムを使用して、非ブロッキングI/Oの準備ができたことを効率的に検出します。しかし、connect
が完了したとnetpoll
が通知した後でも、実際の接続結果(成功または失敗)を正確に把握するためには、追加のチェックが必要となるケースがありました。特に、localhost
への接続は非常に高速に完了するため、OSがエラーを返す前に接続が確立されてしまうことがあり、これが問題を引き起こしていました。
この問題は、GoのIssue #7474として報告されており、このコミットはその解決策として実装されました。
前提知識の解説
1. 非ブロッキングI/Oとconnect
システムコール
- ブロッキングI/O: 通常のソケット操作はブロッキングモードで動作します。これは、
connect
やread
、write
などのシステムコールが、操作が完了するまで(またはエラーが発生するまで)プログラムの実行を停止(ブロック)することを意味します。 - 非ブロッキングI/O: 非ブロッキングモードでは、システムコールはすぐに制御を呼び出し元に返します。操作がすぐに完了しない場合、通常は
EINPROGRESS
(操作が進行中)やEWOULDBLOCK
(操作がブロックされるだろう)といったエラーコードを返します。これにより、アプリケーションはI/O操作の完了を待つ間に他の処理を実行できます。 connect
システムコール: クライアントがサーバーへの接続を確立するために使用するシステムコールです。TCP接続の場合、3ウェイハンドシェイクが完了すると接続が確立されます。非ブロッキングモードでは、connect
はすぐに戻り、接続がバックグラウンドで進行します。
2. netpoll
Go言語のランタイムは、効率的なネットワークI/Oのためにnetpoll
という抽象化レイヤーを使用しています。これは、OSが提供するI/O多重化メカニズム(Linuxのepoll
、macOS/FreeBSDのkqueue
、WindowsのI/O Completion Portsなど)をラップしたものです。netpoll
は、ソケットが読み書き可能になったり、接続が完了したりした際に、Goのゴルーチンをスケジュールするために使用されます。
3. SO_ERROR
ソケットオプション
ソケットには様々なオプションがあり、getsockopt
システムコールを使って取得したり、setsockopt
システムコールを使って設定したりできます。SO_ERROR
は、ソケットに関連付けられた保留中のエラーを取得するために使用されるソケットオプションです。非ブロッキングconnect
が完了した後、このオプションをチェックすることで、接続が成功したのか、それとも非同期的にエラーが発生したのかを判断できます。SO_ERROR
が0であればエラーはなく、それ以外の値であれば対応するエラーコード(例: ECONNREFUSED
、ETIMEDOUT
など)を示します。
4. DragonFly BSDの特性
DragonFly BSDは、FreeBSD 4.xからフォークしたOSであり、独自の設計思想を持っています。特に、カーネルの同期メカニズムやVFS(Virtual File System)の設計に違いがあります。このコミットが示唆するように、ネットワークスタックの特定の挙動、特に非ブロッキングconnect
のセマンティクスが他のUNIX系OS(LinuxやFreeBSD)と異なる場合がありました。
技術的詳細
このコミットの技術的詳細を掘り下げると、Goのnet
パッケージがどのように非ブロッキングconnect
を処理しているか、そしてDragonFly BSDの特定の挙動にどのように対応しているかが明らかになります。
Goのnet
パッケージでは、fd_unix.go
ファイルがUNIX系OSにおけるファイルディスクリプタ(ソケットも含む)の低レベルな操作を扱っています。netFD
構造体は、ネットワークファイルディスクリプタを表し、connect
メソッドはそのソケットでの接続処理を担当します。
通常の非ブロッキングconnect
のフローは以下のようになります。
- ソケットを非ブロッキングモードに設定する。
connect
システムコールを呼び出す。connect
がEINPROGRESS
を返した場合(接続がすぐに完了しない場合)、netpoll
にソケットが書き込み可能になるのを待つように登録する。netpoll
がソケットが書き込み可能になったことを通知したら、接続が完了したと判断する。
しかし、DragonFly BSDでは、この「接続が完了したと判断する」部分に問題がありました。コミットメッセージによると、「非ブロッキングソケットで複数回のconnect
システムコールを実行しても、以前のconnect
コールからのエラーが必ずしも返されない」という問題がありました。これは、connect
がEINPROGRESS
を返さずに、内部的に接続を試行し続けるか、あるいはlocalhost
のような非常に高速な接続の場合に、netpoll
が準備完了を通知する前に、OSがエラー状態を適切に設定しない可能性を示唆しています。
この修正では、netpoll
がソケットの準備ができたと通知した後、追加のステップとしてsyscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
を呼び出してSO_ERROR
ソケットオプションの値を取得しています。
fd.sysfd
: ソケットのファイルディスクリプタ。syscall.SOL_SOCKET
: ソケットレベルのオプションを指定する。syscall.SO_ERROR
: 取得したいオプションが保留中のエラーコードであることを示す。
GetsockoptInt
は、指定されたソケットオプションの整数値を取得します。取得したnerr
が0
であれば、エラーは発生しておらず、接続は成功したと判断されます。nerr
が0
以外の場合、その値はエラーコードを表すため、syscall.Errno(nerr)
を使ってGoのエラー型に変換し、それを返します。
このチェックは、syscall.EINPROGRESS
、syscall.EALREADY
、syscall.EINTR
といった、非ブロッキングconnect
で通常期待される一時的なエラーコードではない場合にのみ、エラーとして返されます。これにより、OS固有の挙動によってconnect
が直接エラーを返さなかった場合でも、SO_ERROR
を通じて真の接続状態を正確に把握できるようになります。
この修正は、GoのネットワークスタックがOSの差異を吸収し、一貫した動作を提供するための重要な一例です。
コアとなるコードの変更箇所
変更はsrc/pkg/net/fd_unix.go
ファイル内のfunc (fd *netFD) connect(la, ra syscall.Sockaddr) error
メソッドにあります。
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/net/fd_unix.go
@@ -96,6 +96,28 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
if err = fd.pd.WaitWrite(); err != nil {
return err
}
+
+ // Performing multiple connect system calls on a non-blocking
+ // socket under DragonFly BSD does not necessarily result in
+ // earlier errors being returned, particularly if we are
+ // connecting to localhost. Instead, once netpoll tells us that
+ // the socket is ready, get the SO_ERROR socket option to see
+ // if the connection succeeded or failed. See issue 7474 for
+ // further details. At some point we may want to consider
+ // doing the same on other Unixes.
+ if runtime.GOOS == "dragonfly" {
+ nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+ if err != nil {
+ return err
+ }
+ if nerr == 0 {
+ return nil
+ }
+ err = syscall.Errno(nerr)
+ if err != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR {
+ return err
+ }
+ }
}
return nil
}
コアとなるコードの解説
追加されたコードブロックは、runtime.GOOS == "dragonfly"
という条件分岐の中にあります。これは、この修正がDragonFly BSDに特化したものであることを示しています。
-
if runtime.GOOS == "dragonfly" { ... }
: Goのビルド時に設定される環境変数GOOS
がdragonfly
である場合にのみ、このコードブロックが実行されます。これにより、他のOSでは既存の挙動が維持され、DragonFly BSD特有の問題にのみ対処します。 -
nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
:syscall.GetsockoptInt
関数を呼び出し、ソケットのファイルディスクリプタfd.sysfd
に対して、SOL_SOCKET
レベルのSO_ERROR
オプションの整数値を取得します。nerr
: 取得されたエラーコードの整数値。エラーがない場合は0
。err
:GetsockoptInt
自体の呼び出しで発生したエラー。
-
if err != nil { return err }
:GetsockoptInt
の呼び出し自体が失敗した場合、そのエラーを即座に返します。 -
if nerr == 0 { return nil }
:SO_ERROR
が0
である場合、ソケットには保留中のエラーがないことを意味します。これは接続が成功したことを示唆するため、nil
(エラーなし)を返してconnect
メソッドを終了します。 -
err = syscall.Errno(nerr)
:nerr
が0
でない場合、それは実際のエラーコードを表します。syscall.Errno(nerr)
を使って、その整数値をGoのsyscall.Errno
型(エラーインターフェースを実装)に変換します。 -
if err != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR { return err }
: 最後に、変換されたエラーが、非ブロッキングconnect
で通常発生しうる一時的なエラー(EINPROGRESS
、EALREADY
、EINTR
)ではないことを確認します。EINPROGRESS
: 接続がまだ進行中である。EALREADY
: 接続が既に進行中である(以前のconnect
呼び出しがまだ完了していない)。EINTR
: システムコールがシグナルによって中断された。 これらのエラーは、接続がまだ完了していないか、一時的な状態であることを示すため、この場合はエラーとして返さずに、connect
メソッドのループが継続することを期待します(元のコードのfd.pd.WaitWrite()
が再度呼び出される)。 上記以外のエラー(例:ECONNREFUSED
、ETIMEDOUT
など)は、接続が実際に失敗したことを意味するため、そのエラーを返してconnect
メソッドを終了します。
このコードは、DragonFly BSDの非ブロッキングconnect
の挙動の特殊性を考慮し、SO_ERROR
を明示的にチェックすることで、接続の最終的な状態を正確に判断し、Goのネットワークスタックが期待通りに動作するようにしています。
関連リンク
- Go Issue #7474: https://github.com/golang/go/issues/7474
- Go CL 69340044: https://golang.org/cl/69340044 (Gerrit Code Review)
参考にした情報源リンク
connect(2)
man page (Linux): https://man7.org/linux/man-pages/man2/connect.2.htmlgetsockopt(2)
man page (Linux): https://man7.org/linux/man-pages/man2/getsockopt.2.html- DragonFly BSD Documentation (General): https://www.dragonflybsd.org/docs/
- Go
net
package documentation: https://pkg.go.dev/net - Go
syscall
package documentation: https://pkg.go.dev/syscall - Go
runtime
package documentation: https://pkg.go.dev/runtime - 非ブロッキングソケットと
SO_ERROR
に関する一般的な情報 (例: Stack Overflow, 技術ブログなど)
[インデックス 18748] ファイルの概要
このコミットは、Go言語のnet
パッケージにおけるDragonFly BSD上での非ブロッキングコネクト処理のバグ修正に関するものです。具体的には、net/fd_unix.go
ファイルが変更され、非ブロッキングソケットでのconnect
システムコールが複数回実行された際の挙動が改善されています。
コミット
commit 734d4637c5925826904ffe7406cd411568928cb4
Author: Joel Sing <jsing@google.com>
Date: Thu Mar 6 00:07:16 2014 +1100
net: fix non-blocking connect handling on dragonfly
Performing multiple connect system calls on a non-blocking socket
under DragonFly BSD does not necessarily result in errors from earlier
connect calls being returned, particularly if we are connecting to
localhost. Instead, once netpoll tells us that the socket is ready,
get the SO_ERROR socket option to see if the connection succeeded
or failed.
Fixes #7474
LGTM=mikioh.mikioh
R=mikioh.mikioh
CC=golang-codereviews
https://golang.org/cl/69340044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/734d4637c5925826904ffe7406cd411568928cb4
元コミット内容
このコミットの元の内容は、DragonFly BSD環境において、非ブロッキングソケットに対する複数回のconnect
システムコールが、以前のconnect
コールからのエラーを適切に返さないという問題に対処するものです。特にlocalhost
への接続時にこの問題が顕著でした。修正は、netpoll
がソケットの準備ができたことを通知した後、SO_ERROR
ソケットオプションを取得して接続の成否を確認するというアプローチを取っています。
変更の背景
この変更の背景には、Go言語のネットワークスタックが様々なOSで一貫して動作するようにするための努力があります。特に、非ブロッキングI/Oは高性能なネットワークアプリケーションを構築する上で不可欠な要素ですが、OSごとにその挙動には微妙な違いが存在します。
DragonFly BSDは、FreeBSDからフォークしたUNIX系OSであり、独自のカーネル設計やシステムコール実装を持つことがあります。このコミットで修正された問題は、DragonFly BSDのconnect
システムコールが、非ブロッキングモードで複数回呼び出された際に、期待されるエラーコード(例えばEINPROGRESS
やEALREADY
)を常に返さないというOS固有の挙動に起因しています。
Goのnet
パッケージは、内部的にnetpoll
というメカニズムを使用して、非ブロッキングI/Oの準備ができたことを効率的に検出します。しかし、connect
が完了したとnetpoll
が通知した後でも、実際の接続結果(成功または失敗)を正確に把握するためには、追加のチェックが必要となるケースがありました。特に、localhost
への接続は非常に高速に完了するため、OSがエラーを返す前に接続が確立されてしまうことがあり、これが問題を引き起こしていました。
この問題は、GoのIssue #7474として報告されており、このコミットはその解決策として実装されました。
前提知識の解説
1. 非ブロッキングI/Oとconnect
システムコール
- ブロッキングI/O: 通常のソケット操作はブロッキングモードで動作します。これは、
connect
やread
、write
などのシステムコールが、操作が完了するまで(またはエラーが発生するまで)プログラムの実行を停止(ブロック)することを意味します。 - 非ブロッキングI/O: 非ブロッキングモードでは、システムコールはすぐに制御を呼び出し元に返します。操作がすぐに完了しない場合、通常は
EINPROGRESS
(操作が進行中)やEWOULDBLOCK
(操作がブロックされるだろう)といったエラーコードを返します。これにより、アプリケーションはI/O操作の完了を待つ間に他の処理を実行できます。 connect
システムコール: クライアントがサーバーへの接続を確立するために使用するシステムコールです。TCP接続の場合、3ウェイハンドシェイクが完了すると接続が確立されます。非ブロッキングモードでは、connect
はすぐに戻り、接続がバックグラウンドで進行します。
2. netpoll
Go言語のランタイムは、効率的なネットワークI/Oのためにnetpoll
という抽象化レイヤーを使用しています。これは、OSが提供するI/O多重化メカニズム(Linuxのepoll
、macOS/FreeBSDのkqueue
、WindowsのI/O Completion Portsなど)をラップしたものです。netpoll
は、ソケットが読み書き可能になったり、接続が完了したりした際に、Goのゴルーチンをスケジュールするために使用されます。
3. SO_ERROR
ソケットオプション
ソケットには様々なオプションがあり、getsockopt
システムコールを使って取得したり、setsockopt
システムコールを使って設定したりできます。SO_ERROR
は、ソケットに関連付けられた保留中のエラーを取得するために使用されるソケットオプションです。非ブロッキングconnect
が完了した後、このオプションをチェックすることで、接続が成功したのか、それとも非同期的にエラーが発生したのかを判断できます。SO_ERROR
が0であればエラーはなく、それ以外の値であれば対応するエラーコード(例: ECONNREFUSED
、ETIMEDOUT
など)を示します。
4. DragonFly BSDの特性
DragonFly BSDは、FreeBSD 4.xからフォークしたOSであり、独自の設計思想を持っています。特に、カーネルの同期メカニズムやVFS(Virtual File System)の設計に違いがあります。このコミットが示唆するように、ネットワークスタックの特定の挙動、特に非ブロッキングconnect
のセマンティクスが他のUNIX系OS(LinuxやFreeBSD)と異なる場合がありました。Web検索の結果からも、DragonFly BSDにおける非ブロッキングconnect
とSO_ERROR
の挙動は、他のBSD系OSと同様に標準的なものであることが確認できます。つまり、connect
がEINPROGRESS
を返した後、select()
やpoll()
でソケットが書き込み可能になったことを待ち、その後getsockopt()
でSO_ERROR
をチェックするという流れが一般的です。このコミットは、Goのnet
パッケージがこの標準的な挙動を正しく解釈できていなかった、あるいは特定の条件下で問題が発生していたことを示唆しています。
技術的詳細
このコミットの技術的詳細を掘り下げると、Goのnet
パッケージがどのように非ブロッキングconnect
を処理しているか、そしてDragonFly BSDの特定の挙動にどのように対応しているかが明らかになります。
Goのnet
パッケージでは、fd_unix.go
ファイルがUNIX系OSにおけるファイルディスクリプタ(ソケットも含む)の低レベルな操作を扱っています。netFD
構造体は、ネットワークファイルディスクリプタを表し、connect
メソッドはそのソケットでの接続処理を担当します。
通常の非ブロッキングconnect
のフローは以下のようになります。
- ソケットを非ブロッキングモードに設定する。
connect
システムコールを呼び出す。connect
がEINPROGRESS
を返した場合(接続がすぐに完了しない場合)、netpoll
にソケットが書き込み可能になるのを待つように登録する。netpoll
がソケットが書き込み可能になったことを通知したら、接続が完了したと判断する。
しかし、DragonFly BSDでは、この「接続が完了したと判断する」部分に問題がありました。コミットメッセージによると、「非ブロッキングソケットで複数回のconnect
システムコールを実行しても、以前のconnect
コールからのエラーが必ずしも返されない」という問題がありました。これは、connect
がEINPROGRESS
を返さずに、内部的に接続を試行し続けるか、あるいはlocalhost
のような非常に高速な接続の場合に、OSがエラー状態を適切に設定しない可能性を示唆しています。
この修正では、netpoll
がソケットの準備ができたと通知した後、追加のステップとしてsyscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
を呼び出してSO_ERROR
ソケットオプションの値を取得しています。
fd.sysfd
: ソケットのファイルディスクリプタ。syscall.SOL_SOCKET
: ソケットレベルのオプションを指定する。syscall.SO_ERROR
: 取得したいオプションが保留中のエラーコードであることを示す。
GetsockoptInt
は、指定されたソケットオプションの整数値を取得します。取得したnerr
が0
であれば、エラーは発生しておらず、接続は成功したと判断されます。nerr
が0
以外の場合、その値はエラーコードを表すため、syscall.Errno(nerr)
を使ってGoのエラー型に変換し、それを返します。
このチェックは、syscall.EINPROGRESS
、syscall.EALREADY
、syscall.EINTR
といった、非ブロッキングconnect
で通常期待される一時的なエラーコードではない場合にのみ、エラーとして返されます。これにより、OS固有の挙動によってconnect
が直接エラーを返さなかった場合でも、SO_ERROR
を通じて真の接続状態を正確に把握できるようになります。
この修正は、GoのネットワークスタックがOSの差異を吸収し、一貫した動作を提供するための重要な一例です。
コアとなるコードの変更箇所
変更はsrc/pkg/net/fd_unix.go
ファイル内のfunc (fd *netFD) connect(la, ra syscall.Sockaddr) error
メソッドにあります。
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/net/fd_unix.go
@@ -96,6 +96,28 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
if err = fd.pd.WaitWrite(); err != nil {
return err
}
+
+ // Performing multiple connect system calls on a non-blocking
+ // socket under DragonFly BSD does not necessarily result in
+ // earlier errors being returned, particularly if we are
+ // connecting to localhost. Instead, once netpoll tells us that
+ // the socket is ready, get the SO_ERROR socket option to see
+ // if the connection succeeded or failed. See issue 7474 for
+ // further details. At some point we may want to consider
+ // doing the same on other Unixes.
+ if runtime.GOOS == "dragonfly" {
+ nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+ if err != nil {
+ return err
+ }
+ if nerr == 0 {
+ return nil
+ }
+ err = syscall.Errno(nerr)
+ if err != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR {
+ return err
+ }
+ }
}
return nil
}
コアとなるコードの解説
追加されたコードブロックは、runtime.GOOS == "dragonfly"
という条件分岐の中にあります。これは、この修正がDragonFly BSDに特化したものであることを示しています。
-
if runtime.GOOS == "dragonfly" { ... }
: Goのビルド時に設定される環境変数GOOS
がdragonfly
である場合にのみ、このコードブロックが実行されます。これにより、他のOSでは既存の挙動が維持され、DragonFly BSD特有の問題にのみ対処します。 -
nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
:syscall.GetsockoptInt
関数を呼び出し、ソケットのファイルディスクリプタfd.sysfd
に対して、SOL_SOCKET
レベルのSO_ERROR
オプションの整数値を取得します。nerr
: 取得されたエラーコードの整数値。エラーがない場合は0
。err
:GetsockoptInt
自体の呼び出しで発生したエラー。
-
if err != nil { return err }
:GetsockoptInt
の呼び出し自体が失敗した場合、そのエラーを即座に返します。 -
if nerr == 0 { return nil }
:SO_ERROR
が0
である場合、ソケットには保留中のエラーがないことを意味します。これは接続が成功したことを示唆するため、nil
(エラーなし)を返してconnect
メソッドを終了します。 -
err = syscall.Errno(nerr)
:nerr
が0
でない場合、それは実際のエラーコードを表します。syscall.Errno(nerr)
を使って、その整数値をGoのsyscall.Errno
型(エラーインターフェースを実装)に変換します。 -
if err != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR { return err }
: 最後に、変換されたエラーが、非ブロッキングconnect
で通常発生しうる一時的なエラー(EINPROGRESS
、EALREADY
、EINTR
)ではないことを確認します。EINPROGRESS
: 接続がまだ進行中である。EALREADY
: 接続が既に進行中である(以前のconnect
呼び出しがまだ完了していない)。EINTR
: システムコールがシグナルによって中断された。 これらのエラーは、接続がまだ完了していないか、一時的な状態であることを示すため、この場合はエラーとして返さずに、connect
メソッドのループが継続することを期待します(元のコードのfd.pd.WaitWrite()
が再度呼び出される)。 上記以外のエラー(例:ECONNREFUSED
、ETIMEDOUT
など)は、接続が実際に失敗したことを意味するため、そのエラーを返してconnect
メソッドを終了します。
このコードは、DragonFly BSDの非ブロッキングconnect
の挙動の特殊性を考慮し、SO_ERROR
を明示的にチェックすることで、接続の最終的な状態を正確に判断し、Goのネットワークスタックが期待通りに動作するようにしています。
関連リンク
- Go Issue #7474: コミットメッセージに記載されていますが、現在のGitHubリポジトリでは直接この番号のIssueは見つかりませんでした。これは、GoのIssueトラッカーが過去に移行したため、古いIssueが異なるシステムに存在するか、アーカイブされている可能性があります。
- Go CL 69340044: https://golang.org/cl/69340044 (Gerrit Code Review)
参考にした情報源リンク
connect(2)
man page (Linux): https://man7.org/linux/man-pages/man2/connect.2.htmlgetsockopt(2)
man page (Linux): https://man7.org/linux/man-pages/man2/getsockopt.2.html- DragonFly BSD Documentation (General): https://www.dragonflybsd.org/docs/
- Go
net
package documentation: https://pkg.go.dev/net - Go
syscall
package documentation: https://pkg.go.dev/syscall - Go
runtime
package documentation: https://pkg.go.dev/runtime - 非ブロッキングソケットと
SO_ERROR
に関する一般的な情報 (例: Stack Overflow, 技術ブログなど)