[インデックス 11280] ファイルの概要
コミット
commit 7f4936a1c5d828b39efea48787bb266f4666d95c
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Fri Jan 20 08:33:37 2012 +0900
net: fix windows build
R=golang-dev, alex.brainman
CC=golang-dev
https://golang.org/cl/5532102
---
src/pkg/net/fd_windows.go | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 637510b732..6e37b4eb6f 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -230,7 +230,7 @@ type netFD struct {
// immutable until Close
sysfd syscall.Handle
family int
- proto int
+ sotype int
net string
laddr Addr
raddr Addr
@@ -244,11 +244,11 @@ type netFD struct {
wio sync.Mutex
}
-func allocFD(fd syscall.Handle, family, proto int, net string) (f *netFD) {
+func allocFD(fd syscall.Handle, family, sotype int, net string) (f *netFD) {
f = &netFD{
sysfd: fd,
family: family,
- proto: proto,
+ sotype: sotype,
net: net,
}
runtime.SetFinalizer(f, (*netFD).Close)
@@ -506,7 +506,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err
// Get new socket.
// See ../syscall/exec.go for description of ForkLock.
syscall.ForkLock.RLock()
- s, e := syscall.Socket(fd.family, fd.proto, 0)
+ s, e := syscall.Socket(fd.family, fd.sotype, 0)
if e != nil {
syscall.ForkLock.RUnlock()
return nil, e
@@ -546,7 +546,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err
lsa, _ := lrsa.Sockaddr()
rsa, _ := rrsa.Sockaddr()
- nfd = allocFD(s, fd.family, fd.proto, fd.net)
+ nfd = allocFD(s, fd.family, fd.sotype, fd.net)
nfd.setAddr(toAddr(lsa), toAddr(rsa))
return nfd, nil
}
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7f4936a1c5d828b39efea48787bb266f4666d95c
元コミット内容
このコミットは、Go言語のネットワークパッケージ (net
) におけるWindowsビルドの修正を目的としています。具体的には、netFD
構造体のフィールド名と、それに関連する allocFD
関数および accept
メソッド内の syscall.Socket
の引数を proto
から sotype
へと変更しています。
変更の背景
Go言語の syscall.Socket
関数は、オペレーティングシステムの低レベルなソケットAPIを呼び出すために使用されます。この関数は通常、アドレスファミリー (AF_INET
や AF_INET6
など)、ソケットタイプ (SOCK_STREAM
や SOCK_DGRAM
など)、およびプロトコル (IPPROTO_TCP
や IPPROTO_UDP
など) の3つの主要な引数を取ります。
元のコードでは、netFD
構造体内でソケットタイプを表すために proto
というフィールド名が使われており、syscall.Socket
関数に渡す際にもこの proto
フィールドがソケットタイプとして使用されていました。しかし、これは命名規則と実際の引数の意味合いにおいて混乱を招く可能性がありました。
Windows環境では、syscall.Socket
の第2引数はソケットタイプ (sotype) を表し、第3引数はプロトコル (protocol) を表します。このコミットは、このWindows固有の syscall.Socket
の引数と、Goの net
パッケージ内の内部表現との整合性を取ることを目的としています。proto
という名前がプロトコルを連想させるため、ソケットタイプを意味する sotype
に変更することで、コードの可読性と正確性を向上させています。これにより、Windows上でのビルドや実行時の潜在的な問題を修正し、より堅牢なネットワーク処理を実現します。
前提知識の解説
ソケットプログラミングの基本
ソケットは、ネットワーク通信のエンドポイントを抽象化したものです。アプリケーションはソケットを通じてデータを送受信します。ソケットを作成する際には、以下の3つの主要なパラメータを指定します。
-
アドレスファミリー (Address Family / Domain): どのネットワークプロトコルファミリーを使用するかを指定します。
AF_INET
(またはPF_INET
): IPv4インターネットプロトコル用。AF_INET6
(またはPF_INET6
): IPv6インターネットプロトコル用。AF_UNIX
(またはPF_UNIX
): 同一システム内のプロセス間通信用(Unixドメインソケット)。
-
ソケットタイプ (Socket Type): ソケットの通信特性を指定します。
SOCK_STREAM
: 信頼性のある、接続指向のバイトストリームを提供します。通常、TCP (Transmission Control Protocol) で使用されます。データの順序が保証され、欠損がありません。SOCK_DGRAM
: 信頼性のない、コネクションレスなデータグラムを提供します。通常、UDP (User Datagram Protocol) で使用されます。データの順序や到達は保証されません。SOCK_RAW
: 生のネットワークプロトコルに直接アクセスします。
-
プロトコル (Protocol): ソケットタイプ内で使用する特定のプロトコルを指定します。通常、ソケットタイプによってプロトコルは暗黙的に決定されるため、
0
を指定することが多いですが、明示的に指定することも可能です。IPPROTO_TCP
: TCPプロトコル。IPPROTO_UDP
: UDPプロトコル。IPPROTO_IP
: IPプロトコル(SOCK_RAW
と組み合わせて使用されることが多い)。
Go言語の syscall
パッケージ
Go言語の syscall
パッケージは、オペレーティングシステムが提供する低レベルなシステムコールに直接アクセスするための機能を提供します。これにより、GoプログラムからOS固有の機能(ファイル操作、プロセス管理、ネットワークソケットなど)を直接呼び出すことができます。
特にネットワーク関連では、syscall.Socket
関数がソケットの作成に使用されます。この関数はOSの socket()
システムコールをラップしており、OSごとに異なる引数の解釈や挙動を吸収する役割も担っています。
proto
と sotype
の違い
proto
(Protocol): ネットワークプロトコル層における特定のプロトコルを指します。例えば、TCPやUDPなどです。syscall.Socket
の第3引数に相当します。sotype
(Socket Type): ソケットの基本的な動作モードを指します。例えば、ストリームソケット(TCP)やデータグラムソケット(UDP)などです。syscall.Socket
の第2引数に相当します。
このコミットの背景にある問題は、Goの内部構造体でソケットタイプを proto
という名前で保持していたため、syscall.Socket
に渡す際に、本来ソケットタイプを期待される第2引数に proto
の値が渡され、それがWindowsのAPIの期待と一致しない場合に問題が発生する可能性があったということです。
技術的詳細
このコミットは、Go言語の src/pkg/net/fd_windows.go
ファイルに焦点を当てています。このファイルは、Windows環境におけるファイルディスクリプタ(Goの netFD
構造体で抽象化される)の管理と、ネットワーク操作の低レベルな実装を扱っています。
問題の核心は、netFD
構造体の定義と、ソケットを作成する allocFD
関数、および接続を受け入れる accept
メソッドにおける syscall.Socket
の呼び出しにありました。
-
netFD
構造体の変更:- 元のコードでは、
netFD
構造体内にproto int
というフィールドがありました。このフィールドは、ソケットの「タイプ」(SOCK_STREAM
やSOCK_DGRAM
など)を格納するために使用されていました。 - 変更後、このフィールドは
sotype int
にリネームされました。これにより、フィールド名がその役割(ソケットタイプ)をより正確に反映するようになりました。
- 元のコードでは、
-
allocFD
関数の変更:allocFD
関数は、新しいnetFD
オブジェクトを割り当て、初期化する役割を担っています。この関数は、syscall.Handle
型のファイルディスクリプタ、アドレスファミリー (family
)、ソケットタイプ (proto
またはsotype
)、およびネットワークタイプ (net
) を引数として受け取ります。- 変更前は
func allocFD(fd syscall.Handle, family, proto int, net string)
でしたが、変更後はfunc allocFD(fd syscall.Handle, family, sotype int, net string)
となり、引数名もproto
からsotype
に変更されました。 - 関数内部でも、
f.proto = proto
がf.sotype = sotype
に修正され、構造体フィールドへの代入も整合性が取られました。
-
accept
メソッド内のsyscall.Socket
呼び出しの変更:accept
メソッドは、新しい接続を受け入れる際に、新しいソケットを作成するためにsyscall.Socket
を呼び出します。- 元のコードでは、
syscall.Socket(fd.family, fd.proto, 0)
となっていました。ここでfd.proto
はnetFD
構造体のproto
フィールド(ソケットタイプを格納)を参照していました。 - 変更後、この呼び出しは
syscall.Socket(fd.family, fd.sotype, 0)
となりました。これにより、syscall.Socket
の第2引数に、netFD
構造体のsotype
フィールド(ソケットタイプを格納)が正しく渡されるようになりました。0
はプロトコル引数であり、この場合はソケットタイプから暗黙的に決定されるため、明示的に指定する必要がないことを示しています。
この変更は、Windowsの socket
APIの期待する引数の順序と意味論にGoの内部コードを合わせることで、Windows環境でのネットワークソケットの作成と管理における潜在的なバグを修正しています。特に、syscall.Socket
の第2引数がソケットタイプ、第3引数がプロトコルであるというWindowsの慣習に準拠することで、クロスプラットフォームな互換性を高めています。
コアとなるコードの変更箇所
src/pkg/net/fd_windows.go
ファイルにおいて、以下の変更が行われました。
-
netFD
構造体定義の変更:--- a/src/pkg/net/fd_windows.go +++ b/src/pkg/net/fd_windows.go @@ -230,7 +230,7 @@ type netFD struct { // immutable until Close sysfd syscall.Handle family int - proto int + sotype int net string laddr Addr raddr Addr
-
allocFD
関数のシグネチャと実装の変更:--- a/src/pkg/net/fd_windows.go +++ b/src/pkg/net/fd_windows.go @@ -244,11 +244,11 @@ type netFD struct { wio sync.Mutex } -func allocFD(fd syscall.Handle, family, proto int, net string) (f *netFD) { +func allocFD(fd syscall.Handle, family, sotype int, net string) (f *netFD) { f = &netFD{ sysfd: fd, family: family, - proto: proto, + sotype: sotype, net: net, } runtime.SetFinalizer(f, (*netFD).Close)
-
accept
メソッド内のsyscall.Socket
呼び出しの変更:--- a/src/pkg/net/fd_windows.go +++ b/src/pkg/net/fd_windows.go @@ -506,7 +506,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err // Get new socket. // See ../syscall/exec.go for description of ForkLock. syscall.ForkLock.RLock() - s, e := syscall.Socket(fd.family, fd.proto, 0) + s, e := syscall.Socket(fd.family, fd.sotype, 0) if e != nil { syscall.ForkLock.RUnlock() return nil, e @@ -546,7 +546,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err lsa, _ := lrsa.Sockaddr() rsa, _ := rrsa.Sockaddr() - nfd = allocFD(s, fd.family, fd.proto, fd.net) + nfd = allocFD(s, fd.family, fd.sotype, fd.net) nfd.setAddr(toAddr(lsa), toAddr(rsa)) return nfd, nil }
コアとなるコードの解説
このコミットの核心は、netFD
構造体内の proto
フィールドが、実際にはソケットタイプ(SOCK_STREAM
や SOCK_DGRAM
など)を格納していたにもかかわらず、その名前がプロトコル(IPPROTO_TCP
や IPPROTO_UDP
など)を連想させるという命名の不整合を解消することにあります。
Windowsの socket
APIでは、第2引数がソケットタイプ、第3引数がプロトコルです。Goの syscall.Socket
関数もこの慣習に従っています。
-
netFD
構造体のproto
からsotype
へのリネーム: これは単なる名前の変更以上の意味を持ちます。コードの意図を明確にし、ソケットの「タイプ」を保持するフィールドであることを明示することで、将来的な誤解やバグの発生を防ぎます。 -
allocFD
関数の引数と内部処理の変更:allocFD
関数は、新しいソケットディスクリプタをラップするnetFD
オブジェクトを生成します。この関数に渡される引数名もproto
からsotype
に変更され、内部でf.sotype = sotype
と代入されることで、netFD
構造体の新しいフィールド名と整合性が取られます。これにより、ソケットタイプが正しくnetFD
オブジェクトに格納されることが保証されます。 -
accept
メソッド内のsyscall.Socket
呼び出しの修正:accept
メソッドは、新しい接続を受け入れる際に、内部でsyscall.Socket
を呼び出して新しいソケットを作成します。この呼び出しにおいて、syscall.Socket(fd.family, fd.proto, 0)
がsyscall.Socket(fd.family, fd.sotype, 0)
に変更されました。 この修正は非常に重要です。fd.sotype
はnetFD
構造体から取得されるソケットタイプであり、これがsyscall.Socket
の第2引数に渡されることで、Windows APIが期待する正しいソケットタイプが指定されるようになります。第3引数の0
は、プロトコルがソケットタイプから暗黙的に決定されることを意味します。
この一連の変更により、Goの net
パッケージはWindows環境において、より正確かつ堅牢にソケットを操作できるようになりました。これは、Goがクロスプラットフォームな言語として、各OSのシステムコールAPIの微妙な違いを適切に吸収し、一貫したインターフェースを提供する上で重要な改善点です。
関連リンク
- Go言語の
syscall
パッケージに関する公式ドキュメント (当時のバージョンに基づく): https://pkg.go.dev/syscall (現在のドキュメントですが、当時のAPIの概念を理解するのに役立ちます) - Go言語の
net
パッケージに関する公式ドキュメント: https://pkg.go.dev/net
参考にした情報源リンク
- Go言語の
syscall.Socket
関数に関する情報 (Web検索結果より):- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG9HciXmNU8zcSxvveRXzOwpNir6SrfXLe6ONiWB5z2XDzrbBoMzDuRy07OeiredS3LJvb5X1Xc3FV-OZE8BDY0sL7Ts-aQW5iMCI0S_xKzNf_OmFw0eJNTE4WoaxZ3Q1d8ZgB_3JgO8w==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGgq08CoYGfCRs_Q9WnbWlNNb_7Fv8dPtGdBoJzTiaYxiUAVhmmIN6qm-P1pn0xTwTzwD_wIrlDXcv0zEYQsl8BMvncccmFvFWcPqj1i_69Wo9dO_tpaCnJ5D33D6XDhlE-aM85WoRyrJLD8lkB0kH3AOuOiPOlJcLD8tcR8ArAr-woiTXY0k=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEbCODx8wuTXHI7NVuFNL3u8NtIKmqUGf7ZHhQwCqfehIvGQQmJNenvrHAlz9Z86z6xTAfhtXOkZ0oJiynyFsDzX7ezLwHXGG_Hi7liNwKcPWXK6fSg3iVuj3fHjh-Y_4XzXo0nY6zNplD4OTJniyrO
- Go言語の
syscall
パッケージの歴史的経緯とgolang.org/x/sys/windows
への移行に関する情報 (Web検索結果より):- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFuuWXaoSSQD-xMdV_8f25NGUGoWoRh4FRzCB16Syd1CftbcRu9ZcPO0jwn25BlaPtI-_zQYmJH2XGSyUCeozSDrY8xqyqrW8TKDgt-K1TQXpf5IaC3YdgPbFOUqPAyJtL6OSulSe0RDeJKIvNBFvs76SC9JGf6
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHe71Ch1roSlimGUKwGvmYbpoDfJnyzoJtez1Fu85dLPey5EOhCoAZIz0Q5IKTg9iB0r4RjoG6z8t9UBCEPVOLItqG4NcKEIrBdIl5IjLgyYthNK7yw2HOQk09Dx9soYRBhQjR-jKGltcPEG7bM32yHuuIljIiPBsx03UVBXoJM9FamgMPTrIMleDFfFKqL4z6DRg==