[インデックス 13956] ファイルの概要
このコミットは、Go言語の標準ライブラリである net
パッケージにおいて、Plan 9オペレーティングシステム上でのビルドに関する問題を修正することを目的としています。具体的には、net
パッケージ内のIP、TCP、UDP、Unixドメインソケットに関連するファイル (iprawsock_plan9.go
, ipsock_plan9.go
, tcpsock_plan9.go
, udpsock_plan9.go
, unixsock_plan9.go
) に対して、Plan 9環境でのネットワークインターフェースの整合性を保つための変更が加えられています。
コミット
commit d6665bc33818a5982e18f424bfe5d0e7ff961a89
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Wed Sep 26 16:11:49 2012 +0900
net: fix plan 9 build
R=golang-dev, lucio.dere, fshahriar
CC=golang-dev
https://golang.org/cl/6562046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d6665bc33818a5982e18f424bfe5d0e7ff961a89
元コミット内容
net: fix plan 9 build
R=golang-dev, lucio.dere, fshahriar
CC=golang-dev
https://golang.org/cl/6562046
変更の背景
Go言語はクロスプラットフォーム対応を重視しており、様々なオペレーティングシステムで動作するように設計されています。その中には、ベル研究所で開発された分散オペレーティングシステムであるPlan 9も含まれます。Goの net
パッケージは、ネットワーク通信のための基本的なインターフェースと実装を提供しますが、特定のOS環境ではそのインターフェースの実装が異なる場合があります。
このコミットが行われた2012年9月時点では、Goの net
パッケージのPlan 9向け実装において、一部のネットワーク関連のインターフェースメソッドが適切に実装されていなかったか、あるいはGoのAPI変更に伴って不足が生じていた可能性があります。これにより、Plan 9環境でGoのネットワーク機能を利用しようとすると、ビルドエラーや実行時エラーが発生する問題がありました。
このコミットの目的は、Plan 9環境でのGoの net
パッケージのビルドを修正し、GoのネットワークAPIがPlan 9上でも期待通りに動作するようにすることです。具体的には、Goの net
パッケージが提供する Conn
や PacketConn
などのインターフェースに定義されているメソッドが、Plan 9固有の制約や特性に合わせて適切にスタブ実装(syscall.EPLAN9
を返す)されるように変更されています。
前提知識の解説
Plan 9 from Bell Labs
Plan 9は、ベル研究所で開発された分散オペレーティングシステムです。Unixの設計思想をさらに推し進め、すべてのリソース(ファイル、デバイス、ネットワーク接続など)をファイルシステムとして表現するという特徴を持っています。これにより、ネットワーク透過性が高く、分散システムを構築しやすいという利点があります。Go言語の開発者の一部はPlan 9の開発にも携わっており、Go言語の設計思想にもPlan 9の影響が見られます。
Plan 9のネットワークスタックは、Unix系OSとは異なるアプローチを取っています。例えば、ソケットAPIの代わりにファイルシステムを通じてネットワークリソースにアクセスします。このため、Goの net
パッケージのような抽象化されたネットワークAPIをPlan 9に移植する際には、Plan 9固有のファイルシステムベースのネットワーク操作にマッピングする必要があります。
Go言語の net
パッケージ
Go言語の net
パッケージは、TCP/IP、UDP、Unixドメインソケットなどのネットワークプロトコルを扱うための基本的な機能を提供します。主要なインターフェースとして以下のようなものがあります。
net.Conn
: ネットワーク接続の一般的なインターフェースで、Read
、Write
、Close
、LocalAddr
、RemoteAddr
、SetDeadline
などのメソッドを定義します。net.PacketConn
: パケット指向のネットワーク接続のインターフェースで、ReadFrom
、WriteTo
などのメソッドを定義します。net.Listener
: ネットワーク接続をリッスンするためのインターフェースで、Accept
、Close
、Addr
などのメソッドを定義します。
これらのインターフェースは、具体的なプロトコル(TCP, UDPなど)やOSに依存しない形でネットワークプログラミングを可能にします。しかし、各OS固有の実装は、net
パッケージ内のOS固有のファイル(例: *_plan9.go
, *_linux.go
など)に記述されます。
syscall.EPLAN9
syscall.EPLAN9
は、Go言語の syscall
パッケージで定義されているエラーコードの一つです。これは、Plan 9オペレーティングシステム固有のエラーを示すために使用されます。このコミットでは、Plan 9環境でサポートされていない、または実装が複雑なネットワーク操作に対して、このエラーを返すことで、その機能がPlan 9では利用できないことを明示しています。これは、Goのクロスプラットフォーム戦略において、特定のOSで利用できない機能がある場合に、ビルドエラーではなく実行時エラーとしてその旨を伝える一般的なアプローチです。
技術的詳細
このコミットの技術的な詳細は、Goの net
パッケージが提供する標準的なネットワークインターフェースを、Plan 9のネットワークモデルに適合させるためのスタブ実装の追加と、既存のコメントの修正に集約されます。
Plan 9のネットワークはファイルシステムを通じて抽象化されており、一般的なUnix系OSのソケットAPIとは大きく異なります。Goの net
パッケージは、Read
や Write
といった汎用的なI/Oメソッドや、SetDeadline
、LocalAddr
、RemoteAddr
といった接続管理メソッドを net.Conn
インターフェースとして提供しています。これらのメソッドは、Plan 9環境では直接的なソケット操作にマッピングできない場合があります。
このコミットでは、IPConn
、plan9Conn
、UnixConn
、UnixListener
といったPlan 9固有のネットワーク接続型に対して、Goの net
パッケージのインターフェースが要求するメソッドの多くを実装しています。しかし、これらの実装のほとんどは、単に syscall.EPLAN9
エラーを返しています。これは、以下の理由によるものです。
- Plan 9のネットワークモデルとの不整合:
ReadMsgIP
やWriteMsgIP
のような、メッセージのフラグや帯域外データ(out-of-band data)を扱う高度なソケット操作は、Plan 9のファイルシステムベースのネットワークモデルでは直接的な対応が難しい場合があります。 - 機能の未サポート:
SetReadBuffer
やSetWriteBuffer
のようなバッファサイズ設定、あるいはFile()
メソッドのように基盤となるos.File
を返す機能は、Plan 9のネットワーク実装ではサポートされていないか、あるいはその必要がない場合があります。 - ビルドの成功: これらのメソッドがインターフェースに定義されている以上、Plan 9向けビルドを成功させるためには、何らかの形でこれらのメソッドを実装する必要があります。しかし、実際にその機能がPlan 9で利用可能である必要がない場合や、実装が複雑すぎる場合は、
syscall.EPLAN9
を返すことで、ビルドは成功させつつ、実行時にその機能が利用できないことを明示します。
また、コメントの修正も行われています。これは、GoDocの生成やコードの可読性を向上させるために、コメントのフォーマットや内容をより正確かつ簡潔にするためのものです。特に、行の折り返しや句読点の修正が見られます。
コアとなるコードの変更箇所
このコミットでは、以下の5つのファイルが変更されています。
src/pkg/net/iprawsock_plan9.go
src/pkg/net/ipsock_plan9.go
src/pkg/net/tcpsock_plan9.go
src/pkg/net/udpsock_plan9.go
src/pkg/net/unixsock_plan9.go
変更の概要は以下の通りです。
iprawsock_plan9.go
:IPConn
型にRead
,Write
,LocalAddr
,RemoteAddr
,SetReadBuffer
,SetWriteBuffer
,File
,ReadMsgIP
,WriteMsgIP
メソッドが追加され、すべてsyscall.EPLAN9
を返すスタブ実装となっています。既存のコメントも修正されています。ipsock_plan9.go
:plan9Conn
型にSetReadBuffer
,SetWriteBuffer
,File
メソッドが追加され、syscall.EPLAN9
を返すスタブ実装となっています。plan9Listener
型にもFile
メソッドが追加されています。既存のコメントも修正されています。tcpsock_plan9.go
: 主にコメントの修正が行われています。TCPConn
とTCPListener
の説明がより簡潔になっています。udpsock_plan9.go
:UDPConn
型にReadMsgUDP
,WriteMsgUDP
メソッドが追加され、syscall.EPLAN9
を返すスタブ実装となっています。既存のコメントも修正されています。unixsock_plan9.go
:UnixConn
型にRead
,Write
,LocalAddr
,RemoteAddr
,SetReadBuffer
,SetWriteBuffer
,File
,ReadFromUnix
,ReadMsgUnix
,WriteToUnix
,WriteMsgUnix
メソッドが追加され、syscall.EPLAN9
を返すスタブ実装となっています。UnixListener
型にもAcceptUnix
,SetDeadline
,File
メソッドが追加されています。既存のコメントも修正されています。
コアとなるコードの解説
各ファイルの主要な変更点と、その意図について解説します。
src/pkg/net/iprawsock_plan9.go
// IPConn is the implementation of the Conn and PacketConn interfaces
// for IP network connections.
type IPConn bool
// Implementation of the Conn interface - see Conn for documentation.
// Read implements the Conn Read method.
func (c *IPConn) Read(b []byte) (int, error) {
return 0, syscall.EPLAN9
}
// Write implements the Conn Write method.
func (c *IPConn) Write(b []byte) (int, error) {
return 0, syscall.EPLAN9
}
// LocalAddr returns the local network address.
func (c *IPConn) LocalAddr() Addr {
return nil
}
// RemoteAddr returns the remote network address.
func (c *IPConn) RemoteAddr() Addr {
return nil
}
// SetReadBuffer sets the size of the operating system's receive
// buffer associated with the connection.
func (c *IPConn) SetReadBuffer(bytes int) error {
return syscall.EPLAN9
}
// SetWriteBuffer sets the size of the operating system's transmit
// buffer associated with the connection.
func (c *IPConn) SetWriteBuffer(bytes int) error {
return syscall.EPLAN9
}
// File returns a copy of the underlying os.File, set to blocking
// mode. It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c.
func (c *IPConn) File() (f *os.File, err error) {
return nil, syscall.EPLAN9
}
// ReadMsgIP reads a packet from c, copying the payload into b and the
// associdated out-of-band data into oob. It returns the number of
// bytes copied into b, the number of bytes copied into oob, the flags
// that were set on the packet and the source address of the packet.
func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
return 0, 0, 0, nil, syscall.EPLAN9
}
// WriteMsgIP writes a packet to addr via c, copying the payload from
// b and the associated out-of-band data from oob. It returns the
// number of payload and out-of-band bytes written.
func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
return 0, 0, syscall.EPLAN9
}
このファイルでは、IPConn
型が net.Conn
および net.PacketConn
インターフェースを満たすために必要なメソッドが追加されています。しかし、これらのメソッドのほとんどは syscall.EPLAN9
を返しています。これは、Plan 9のネットワークモデルではこれらの機能が直接サポートされていないか、あるいは実装が非常に複雑であるため、GoのAPIとの整合性を保ちつつ、Plan 9でのビルドを可能にするための措置です。LocalAddr
と RemoteAddr
は nil
を返しており、これはPlan 9のIP接続ではこれらのアドレス情報が直接取得できないことを示唆しています。
src/pkg/net/ipsock_plan9.go
// SetReadBuffer sets the size of the operating system's receive
// buffer associated with the connection.
func (c *plan9Conn) SetReadBuffer(bytes int) error {
return syscall.EPLAN9
}
// SetWriteBuffer sets the size of the operating system's transmit
// buffer associated with the connection.
func (c *plan9Conn) SetWriteBuffer(bytes int) error {
return syscall.EPLAN9
}
// File returns a copy of the underlying os.File, set to blocking
// mode. It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c.
func (c *plan9Conn) File() (f *os.File, err error) {
return nil, syscall.EPLAN9
}
// File returns a copy of the underlying os.File, set to blocking
// mode. It is the caller's responsibility to close f when finished.
// Closing l does not affect f, and closing f does not affect l.
func (l *plan9Listener) File() (f *os.File, err error) {
return nil, syscall.EPLAN9
}
plan9Conn
は、Plan 9における一般的なネットワーク接続の基底となる型です。ここでも、バッファ設定や基盤となるファイルディスクリプタへのアクセスを提供する SetReadBuffer
, SetWriteBuffer
, File
メソッドが syscall.EPLAN9
を返すスタブとして追加されています。同様に、plan9Listener
にも File
メソッドが追加されています。これは、Plan 9のファイルシステムベースのネットワークモデルでは、これらの操作が直接的な意味を持たないか、あるいはサポートされていないためです。
src/pkg/net/tcpsock_plan9.go
このファイルでは、主にコメントの修正が行われています。例えば、TCPConn
や TCPListener
の説明文がより簡潔で正確な表現に修正されています。これは機能的な変更ではなく、コードのドキュメンテーションと可読性の向上を目的としています。
src/pkg/net/udpsock_plan9.go
// ReadMsgUDP reads a packet from c, copying the payload into b and
// the associdated out-of-band data into oob. It returns the number
// of bytes copied into b, the number of bytes copied into oob, the
// flags that were set on the packet and the source address of the
// packet.
func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
return 0, 0, 0, nil, syscall.EPLAN9
}
// WriteMsgUDP writes a packet to addr via c, copying the payload from
// b and the associated out-of-band data from oob. It returns the
// number of payload and out-of-band bytes written.
func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
return 0, 0, syscall.EPLAN9
}
UDPConn
型に対して、ReadMsgUDP
と WriteMsgUDP
メソッドが追加されています。これらは、UDPパケットのペイロードだけでなく、帯域外データ(out-of-band data)も扱うためのメソッドです。しかし、Plan 9環境ではこれらの高度なメッセージ操作が直接サポートされていないため、ここでも syscall.EPLAN9
を返すスタブ実装となっています。
src/pkg/net/unixsock_plan9.go
// Read implements the Conn Read method.
func (c *UnixConn) Read(b []byte) (int, error) {
return 0, syscall.EPLAN9
}
// Write implements the Conn Write method.
func (c *UnixConn) Write(b []byte) (int, error) {
return 0, syscall.EPLAN9
}
// LocalAddr returns the local network address.
func (c *UnixConn) LocalAddr() Addr {
return nil
}
// RemoteAddr returns the remote network address.
func (c *UnixConn) RemoteAddr() Addr {
return nil
}
// SetReadBuffer sets the size of the operating system's receive
// buffer associated with the connection.
func (c *UnixConn) SetReadBuffer(bytes int) error {
return syscall.EPLAN9
}
// SetWriteBuffer sets the size of the operating system's transmit
// buffer associated with the connection.
func (c *UnixConn) SetWriteBuffer(bytes int) error {
return syscall.EPLAN9
}
// File returns a copy of the underlying os.File, set to blocking
// mode. It is the caller's responsibility to close f when finished.
// Closing c does not affect f, and closing f does not affect c.
func (c *UnixConn) File() (f *os.File, err error) {
return nil, syscall.EPLAN9
}
// ReadFromUnix reads a packet from c, copying the payload into b. It
// returns the number of bytes copied into b and the source address of
// the packet.
func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
return 0, nil, syscall.EPLAN9
}
// ReadMsgUnix reads a packet from c, copying the payload into b and
// the associated out-of-band data into oob. It returns the number of
// bytes copied into b, the number of bytes copied into oob, the flags
// that were set on the packet, and the source address of the packet.
func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
return 0, 0, 0, nil, syscall.EPLAN9
}
// WriteToUnix writes a packet to addr via c, copying the payload from b.
func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
return 0, syscall.EPLAN9
}
// WriteMsgUnix writes a packet to addr via c, copying the payload
// from b and the associated out-of-band data from oob. It returns
// the number of payload and out-of-band bytes written.
func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
return 0, 0, syscall.EPLAN9
}
// AcceptUnix accepts the next incoming call and returns the new
// connection and the remote address.
func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
return nil, syscall.EPLAN9
}
// SetDeadline sets the deadline associated with the listener.
// A zero time value disables the deadline.
func (l *UnixListener) SetDeadline(t time.Time) error {
return syscall.EPLAN9
}
// File returns a copy of the underlying os.File, set to blocking
// mode. It is the caller's responsibility to close f when finished.
// Closing l does not affect f, and closing f does not affect l.
func (l *UnixListener) File() (*os.File, error) {
return nil, syscall.EPLAN9
}
UnixConn
と UnixListener
は、Unixドメインソケットを扱うための型です。このファイルでは、IPConn
や UDPConn
と同様に、Read
, Write
, LocalAddr
, RemoteAddr
, SetReadBuffer
, SetWriteBuffer
, File
といった net.Conn
インターフェースのメソッドや、ReadFromUnix
, ReadMsgUnix
, WriteToUnix
, WriteMsgUnix
といったUnixドメインソケット固有のメッセージ操作メソッドが追加されています。これらもすべて syscall.EPLAN9
を返すスタブ実装です。
UnixListener
にも AcceptUnix
, SetDeadline
, File
メソッドが追加されています。AcceptUnix
は、net.Listener
インターフェースの Accept
メソッドのUnixドメインソケット版ですが、ここでも syscall.EPLAN9
を返しています。これは、Plan 9のUnixドメインソケットの実装がGoのAPIと完全に一致しないため、あるいは特定の機能がサポートされていないためと考えられます。
全体として、このコミットは、Goの net
パッケージが提供する広範なネットワークAPIを、Plan 9の特定の制約や特性に合わせて調整し、ビルドエラーを解消しつつ、サポートされていない機能については明確に syscall.EPLAN9
エラーを返すようにすることで、クロスプラットフォーム互換性を維持しようとするものです。
関連リンク
- Go言語の
net
パッケージのドキュメント: https://pkg.go.dev/net - Plan 9 from Bell Labs: https://9p.io/plan9/
- Go言語の
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall
参考にした情報源リンク
- Go言語のソースコード (GitHub): https://github.com/golang/go
- Go Code Review Comments (CL 6562046): https://golang.org/cl/6562046 (コミットメッセージに記載されているChange Listへのリンク)
- Plan 9のネットワークに関する情報 (一般的なWeb検索)
- Go言語のクロスコンパイルとOS固有のコードに関する情報 (一般的なWeb検索)
- Go言語のインターフェースとスタブ実装に関する情報 (一般的なWeb検索)