[インデックス 18225] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおけるOpenBSD向けのgetsockname
システムコールに関するワークアラウンド(回避策)を削除するものです。具体的には、Unixドメインソケットにおいてgetsockname
がAF_UNSPEC
(未指定)ファミリーを返す問題に対する修正が、OpenBSD 5.2で導入されたため、Goの最小要件がOpenBSD 5.4-currentに引き上げられたことに伴い、不要になったコードを削除しています。
コミット
commit 3233a12f614723317f5d2e127b87b69aa236cd58
Author: Joel Sing <jsing@google.com>
Date: Mon Jan 13 11:24:56 2014 +1100
syscall: remove getsockname workaround for openbsd
Remove the getsockname workaround for unix domain sockets on OpenBSD.
This was fixed in OpenBSD 5.2 and we now have a minimum requirement
for OpenBSD 5.4-current.
R=golang-codereviews, minux.ma
CC=golang-codereviews
https://golang.org/cl/50960043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3233a12f614723317f5d2e127b87b69aa236cd58
元コミット内容
syscall: remove getsockname workaround for openbsd
このコミットは、OpenBSDにおけるgetsockname
システムコールに対するワークアラウンドを削除します。
OpenBSD 5.2でこの問題が修正され、GoのOpenBSDに対する最小要件がOpenBSD 5.4-currentになったため、このワークアラウンドは不要になりました。
変更の背景
Go言語のsyscall
パッケージは、オペレーティングシステムのシステムコールをGoプログラムから呼び出すためのインターフェースを提供します。getsockname
は、指定されたソケットのローカルアドレスを取得するためのシステムコールです。
過去のOpenBSDのバージョン(5.2より前)では、Unixドメインソケットに対してgetsockname
を呼び出した際に、ソケットアドレス構造体(sockaddr
)のsa_family
フィールドがAF_UNSPEC
(アドレスファミリーが未指定)として返され、sa_len
フィールドが0になるという問題がありました。これは、Unixドメインソケットが実際にはAF_UNIX
ファミリーに属しているにもかかわらず、正しく識別されないというバグでした。
Goのランタイムは、このOpenBSDのバグに対応するため、syscall_bsd.go
ファイル内で特定のワークアラウンドを実装していました。このワークアラウンドは、getsockname
がAF_UNSPEC
と0の長さのアドレスを返した場合に、それがUnixドメインソケットであると仮定して、AF_UNIX
ファミリーと適切な長さに手動で修正するというものでした。
しかし、OpenBSD 5.2でこのgetsockname
のバグが修正され、Unixドメインソケットに対して正しいAF_UNIX
ファミリーが返されるようになりました。GoのOpenBSDサポートの最小バージョンがOpenBSD 5.4-currentに引き上げられたため、この古いバグに対するワークアラウンドはもはや必要なくなりました。このコミットは、その不要になったコードを削除し、コードベースをクリーンアップすることを目的としています。
また、コミットメッセージにはDragonFly BSDに関するコメントも含まれており、同様の「バグ」がDragonFly BSDにも存在し、上流に報告されるべきであると指摘されています。これは、異なるBSD系OS間でのシステムコール実装の差異と、それに対するGoランタイムの対応の複雑さを示唆しています。
前提知識の解説
1. システムコール (System Call)
システムコールは、オペレーティングシステム(OS)のカーネルが提供するサービスを、ユーザー空間のプログラムが利用するためのインターフェースです。ファイル操作、メモリ管理、プロセス制御、ネットワーク通信など、OSの基本的な機能にアクセスするために使用されます。Go言語のsyscall
パッケージは、これらのシステムコールをGoの関数として抽象化し、クロスプラットフォームで利用できるようにしています。
2. ソケット (Socket)
ソケットは、ネットワーク通信のエンドポイントを抽象化したものです。プロセス間通信(IPC)やネットワーク通信において、データの送受信を行うためのインターフェースとして機能します。ソケットには、TCPソケット、UDPソケット、そしてこのコミットで関連するUnixドメインソケットなど、いくつかの種類があります。
3. Unixドメインソケット (Unix Domain Socket)
Unixドメインソケット(UDS)は、同じホストマシン上のプロセス間で通信を行うためのソケットです。TCP/IPソケットがネットワークインターフェースを介して通信するのに対し、UDSはファイルシステム上のパス名(または抽象的な名前空間)を介して通信します。ネットワークスタックを介さないため、TCP/IPソケットよりも高速で効率的なプロセス間通信が可能です。
4. getsockname
システムコール
getsockname
は、ソケットディスクリプタ(fd
)で指定されたソケットのローカルアドレス(つまり、ソケットがバインドされているアドレス)を取得するために使用されるシステムコールです。このシステムコールは、sockaddr
構造体と呼ばれる汎用的なソケットアドレス構造体にアドレス情報を格納して返します。
5. sockaddr
構造体とアドレスファミリー
sockaddr
構造体は、ソケットアドレスを表現するための汎用的な構造体です。この構造体には、アドレスファミリー(sa_family
)と、そのファミリーに固有のアドレス情報が含まれます。
-
sa_family
: ソケットが属するアドレスファミリーを示すフィールドです。AF_UNSPEC
(Address Family Unspecified): アドレスファミリーが未指定であることを示します。これは通常、ソケットがまだ特定のアドレスファミリーにバインドされていない場合や、エラー状態の場合に返されることがあります。AF_UNIX
(Address Family Unix): Unixドメインソケットのアドレスファミリーを示します。AF_INET
(Address Family Internet): IPv4ソケットのアドレスファミリーを示します。AF_INET6
(Address Family Internet Version 6): IPv6ソケットのアドレスファミリーを示します。
-
sa_len
:sockaddr
構造体全体の長さをバイト単位で示すフィールドです。
6. OpenBSD と DragonFly BSD
OpenBSDとDragonFly BSDは、BSD(Berkeley Software Distribution)系のオープンソースUNIXライクなオペレーティングシステムです。これらはFreeBSDから派生しており、それぞれ異なる開発目標と哲学を持っています。OSのバージョンやパッチレベルによって、システムコールの挙動やバグの有無が異なることがあります。
技術的詳細
このコミットの核心は、Go言語のsyscall
パッケージが、特定のOS(OpenBSD)の過去のシステムコール実装のバグをどのように扱っていたか、そしてそのバグが修正された後にどのようにコードベースを更新したかという点にあります。
Goのsyscall_bsd.go
ファイルには、Getsockname
というGoの関数が定義されており、これは内部的にC言語のgetsockname
システムコールを呼び出しています。
元のコードでは、getsockname
が返したSockaddr
構造体のAddr.Family
がAF_UNSPEC
であり、かつAddr.Len
が0である場合に、それがOpenBSDまたはDragonFly BSD上のUnixドメインソケットであると判断し、Addr.Family
をAF_UNIX
に、Addr.Len
をSizeofSockaddrUnix
(Unixドメインソケットアドレスの正しいサイズ)に手動で修正していました。これは、OpenBSDの古いバージョンにおけるgetsockname
のバグに対する直接的なワークアラウンドでした。
// 修正前のコードの関連部分(コミット差分から推測)
if (runtime.GOOS == "dragonfly" || runtime.GOOS == "openbsd") && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
rsa.Addr.Family = AF_UNIX
rsa.Addr.Len = SizeofSockaddrUnix
}
このワークアラウンドは、OpenBSD 5.2でgetsockname
のバグが修正されたことで不要になりました。GoのOpenBSDサポートの最小バージョンがOpenBSD 5.4-currentに引き上げられたため、Goランタイムはもはやこの古いバグを考慮する必要がなくなりました。
コミットは、この条件分岐からruntime.GOOS == "openbsd"
の部分を削除し、OpenBSD向けのワークアラウンドを完全に廃止しました。
// 修正後のコードの関連部分
if runtime.GOOS == "dragonfly" && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
rsa.Addr.Family = AF_UNIX
rsa.Addr.Len = SizeofSockaddrUnix
}
これにより、コードはよりシンプルになり、OpenBSDの最新の挙動に合致するようになりました。ただし、DragonFly BSDについては同様のバグがまだ存在すると考えられているため、DragonFly BSD向けのワークアラウンドは残されています。これは、異なるOS間での互換性を維持しつつ、各OSの特性に合わせた調整を行うGoランタイムの設計思想を反映しています。
この変更は、GoがサポートするOSのバージョンアップに伴い、過去のOSのバグに対する特定の回避策が不要になった場合に、積極的にコードをクリーンアップしていくという開発プロセスの一環です。これにより、コードの複雑性が軽減され、将来的なメンテナンスが容易になります。
コアとなるコードの変更箇所
変更はsrc/pkg/syscall/syscall_bsd.go
ファイルにあります。
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -296,10 +296,9 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
if err = getsockname(fd, &rsa, &len); err != nil {
return
}
- // TODO(jsing): Remove after OpenBSD 5.4 is released (see issue 3349).
- // TODO(jsing): Apparently dragonfly has the same "bug", which should
- // be reported upstream.
- if (runtime.GOOS == "dragonfly" || runtime.GOOS == "openbsd") && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
+ // TODO(jsing): DragonFly has a "bug" (see issue 3349), which should be
+ // reported upstream.
+ if runtime.GOOS == "dragonfly" && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
rsa.Addr.Family = AF_UNIX
rsa.Addr.Len = SizeofSockaddrUnix
}
コアとなるコードの解説
変更されたコードブロックは、Getsockname
関数内にあります。この関数は、ソケットディスクリプタfd
を受け取り、そのソケットのローカルアドレスをSockaddr
インターフェースとして返します。
-
if err = getsockname(fd, &rsa, &len); err != nil { return }
- ここで実際のシステムコール
getsockname
が呼び出され、ソケットアドレス情報がrsa
(RawSockaddrAny
型、汎用的なsockaddr
構造体)に格納されます。エラーが発生した場合は、すぐに処理を終了します。
- ここで実際のシステムコール
-
// TODO(jsing): DragonFly has a "bug" (see issue 3349), which should be // reported upstream.
- これは、DragonFly BSDにおける同様のバグに関するコメントです。このコメントは、このワークアラウンドがDragonFly BSD向けにはまだ必要であることを示唆しています。また、このバグはGoのコードベースで修正するのではなく、OSの上流プロジェクトに報告して修正されるべきであるという方針も示しています。
-
if runtime.GOOS == "dragonfly" && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 { ... }
- これが変更された条件分岐です。
- 変更前は
(runtime.GOOS == "dragonfly" || runtime.GOOS == "openbsd")
でした。 - 変更後は
runtime.GOOS == "dragonfly"
のみになりました。 - この条件は、現在のGoの実行環境がDragonFly BSDであり、かつ
getsockname
が返したソケットアドレスのファミリーがAF_UNSPEC
で、長さが0である場合に真となります。 - この条件が真の場合、以下の2行が実行されます。
rsa.Addr.Family = AF_UNIX
: ソケットアドレスのファミリーをAF_UNIX
に強制的に設定します。これは、getsockname
が誤ってAF_UNSPEC
を返した場合に、それがUnixドメインソケットであることをGoランタイムが「推測」して修正するものです。rsa.Addr.Len = SizeofSockaddrUnix
: ソケットアドレスの長さをSizeofSockaddrUnix
(Unixドメインソケットアドレスの正しいサイズ)に強制的に設定します。これも同様に、getsockname
が誤って0を返した場合の修正です。
この変更により、OpenBSD向けの不要なワークアラウンドが削除され、コードがより簡潔になりました。DragonFly BSD向けのワークアラウンドは、そのOSのバグが修正されるまで維持されます。
関連リンク
- Go issue 3349: https://github.com/golang/go/issues/3349 (このコミットで言及されているDragonFly BSDのバグに関連する可能性のあるGoのIssue)
- OpenBSD
getsockname
man page: https://man.openbsd.org/getsockname.2 (OpenBSDにおけるgetsockname
のドキュメント) - Unix Domain Sockets (Wikipedia): https://en.wikipedia.org/wiki/Unix_domain_socket
参考にした情報源リンク
- コミットメッセージと差分
- Go言語の
syscall
パッケージのドキュメント getsockname
システムコールに関する一般的な情報(Linux man pagesなど)- OpenBSDおよびDragonFly BSDのリリースノートやバグトラッカー(具体的な修正内容の確認のため)
- Go issue 3349 (直接的な情報源ではないが、関連する議論の可能性)
- Stack Overflowや技術ブログでの
AF_UNSPEC
とUnixドメインソケットに関する議論