Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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 パッケージが提供する ConnPacketConn などのインターフェースに定義されているメソッドが、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: ネットワーク接続の一般的なインターフェースで、ReadWriteCloseLocalAddrRemoteAddrSetDeadline などのメソッドを定義します。
  • net.PacketConn: パケット指向のネットワーク接続のインターフェースで、ReadFromWriteTo などのメソッドを定義します。
  • net.Listener: ネットワーク接続をリッスンするためのインターフェースで、AcceptCloseAddr などのメソッドを定義します。

これらのインターフェースは、具体的なプロトコル(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 パッケージは、ReadWrite といった汎用的なI/Oメソッドや、SetDeadlineLocalAddrRemoteAddr といった接続管理メソッドを net.Conn インターフェースとして提供しています。これらのメソッドは、Plan 9環境では直接的なソケット操作にマッピングできない場合があります。

このコミットでは、IPConnplan9ConnUnixConnUnixListener といったPlan 9固有のネットワーク接続型に対して、Goの net パッケージのインターフェースが要求するメソッドの多くを実装しています。しかし、これらの実装のほとんどは、単に syscall.EPLAN9 エラーを返しています。これは、以下の理由によるものです。

  1. Plan 9のネットワークモデルとの不整合: ReadMsgIPWriteMsgIP のような、メッセージのフラグや帯域外データ(out-of-band data)を扱う高度なソケット操作は、Plan 9のファイルシステムベースのネットワークモデルでは直接的な対応が難しい場合があります。
  2. 機能の未サポート: SetReadBufferSetWriteBuffer のようなバッファサイズ設定、あるいは File() メソッドのように基盤となる os.File を返す機能は、Plan 9のネットワーク実装ではサポートされていないか、あるいはその必要がない場合があります。
  3. ビルドの成功: これらのメソッドがインターフェースに定義されている以上、Plan 9向けビルドを成功させるためには、何らかの形でこれらのメソッドを実装する必要があります。しかし、実際にその機能がPlan 9で利用可能である必要がない場合や、実装が複雑すぎる場合は、syscall.EPLAN9 を返すことで、ビルドは成功させつつ、実行時にその機能が利用できないことを明示します。

また、コメントの修正も行われています。これは、GoDocの生成やコードの可読性を向上させるために、コメントのフォーマットや内容をより正確かつ簡潔にするためのものです。特に、行の折り返しや句読点の修正が見られます。

コアとなるコードの変更箇所

このコミットでは、以下の5つのファイルが変更されています。

  1. src/pkg/net/iprawsock_plan9.go
  2. src/pkg/net/ipsock_plan9.go
  3. src/pkg/net/tcpsock_plan9.go
  4. src/pkg/net/udpsock_plan9.go
  5. 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: 主にコメントの修正が行われています。TCPConnTCPListener の説明がより簡潔になっています。
  • 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でのビルドを可能にするための措置です。LocalAddrRemoteAddrnil を返しており、これは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

このファイルでは、主にコメントの修正が行われています。例えば、TCPConnTCPListener の説明文がより簡潔で正確な表現に修正されています。これは機能的な変更ではなく、コードのドキュメンテーションと可読性の向上を目的としています。

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 型に対して、ReadMsgUDPWriteMsgUDP メソッドが追加されています。これらは、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
}

UnixConnUnixListener は、Unixドメインソケットを扱うための型です。このファイルでは、IPConnUDPConn と同様に、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言語のソースコード (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検索)