[インデックス 15319] ファイルの概要
このコミットは、Go言語のnet
パッケージにおけるPlan 9オペレーティングシステム向けのネットワーク処理に関する修正と改善を目的としています。具体的には、ネットワーク接続のデータファイルのオープンタイミング、接続クローズ時のリソース解放の堅牢性、およびAccept
コールにおけるリモートアドレスの設定の正確性に関する問題に対処しています。これにより、Plan 9環境下でのGoアプリケーションのネットワーク通信の信頼性と正確性が向上します。
コミット
commit 66b69a1719040e05f8ccef8110aaff192968c29a
Author: Akshat Kumar <seed@mail.nanosouffle.net>
Date: Tue Feb 19 17:11:17 2013 -0800
net: Plan 9: open data file and set remote-addr properly
The data file should be opened when a Conn is first
established, rather than waiting for the first Read or
Write.
Upon Close, we now make sure to try to close both, the
ctl as well as data files and set both to nil, even in
the face of errors, instead of returning early.
The Accept call was not setting the remote address
of the connection properly. Now, we read the correct
file.
Make functions that establish Conn use newTCPConn
or newUDPConn.
R=rsc, rminnich, ality, dave
CC=golang-dev
https://golang.org/cl/7228068
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/66b69a1719040e05f8ccef8110aaff192968c29a
元コミット内容
net: Plan 9: open data file and set remote-addr properly
The data file should be opened when a Conn is first
established, rather than waiting for the first Read or
Write.
Upon Close, we now make sure to try to close both, the
ctl as well as data files and set both to nil, even in
the face of errors, instead of returning early.
The Accept call was not setting the remote address
of the connection properly. Now, we read the correct
file.
Make functions that establish Conn use newTCPConn
or newUDPConn.
R=rsc, rminnich, ality, dave
CC=golang-dev
https://golang.org/cl/7228068
変更の背景
このコミットは、Go言語のnet
パッケージがPlan 9オペレーティングシステム上で動作する際の、いくつかの既存の不具合と非効率性を修正するために行われました。
- データファイルの遅延オープンによる非効率性: 以前の実装では、ネットワーク接続のデータファイル(実際のデータ送受信を行うファイルディスクリプタ)が、最初の
Read
またはWrite
操作が呼び出されるまで開かれませんでした。これは、接続が確立された直後にリソースが利用可能であるべきという期待に反し、最初のデータ操作時に余分なオーバーヘッドと潜在的なエラーを引き起こす可能性がありました。 - 接続クローズ時の不完全なリソース解放: 接続をクローズする際、制御ファイル(
ctl
)とデータファイル(data
)の両方が適切に閉じられ、nilに設定されるべきでした。しかし、以前の実装では、エラーが発生した場合に早期にリターンしてしまい、片方のファイルが閉じられないまま残る可能性がありました。これはリソースリークや後続の操作での問題につながります。 Accept
コールにおけるリモートアドレスの誤設定: サーバー側で新しい接続を受け入れるAccept
関数が、確立された接続のリモートアドレスを正しく設定していませんでした。これは、接続の相手を正確に識別できないという問題を引き起こし、ログ記録、セキュリティ、またはアプリケーションロジックに影響を与える可能性がありました。- 一貫性のない接続確立:
TCPConn
やUDPConn
といった具体的な接続タイプを確立する関数が、newTCPConn
やnewUDPConn
といったヘルパー関数を使用せず、直接構造体を初期化していました。これにより、コードの重複や将来的な変更の際に一貫性が失われるリスクがありました。
これらの問題に対処することで、Plan 9環境におけるGoのネットワークスタックの堅牢性、効率性、および正確性を向上させることが目的とされました。
前提知識の解説
このコミットを理解するためには、以下の概念が重要です。
-
Plan 9オペレーティングシステム:
- Plan 9は、ベル研究所で開発された分散オペレーティングシステムです。その最も特徴的な設計原則の一つは「Everything is a file(すべてはファイルである)」です。これは、プロセス、ネットワーク接続、デバイスなど、システム内のあらゆるリソースがファイルシステム上のファイルとして表現され、標準的なファイル操作(
open
,read
,write
,close
など)を通じてアクセスされることを意味します。 - ネットワーク接続も例外ではありません。Plan 9では、ネットワーク接続は通常、制御ファイル(
ctl
)とデータファイル(data
)のペアとして表現されます。ctl
ファイル: 接続の確立、設定、状態のクエリなど、接続の制御情報をやり取りするために使用されます。data
ファイル: 実際のデータ(ペイロード)の送受信に使用されます。
- Go言語は、その設計思想の一部にPlan 9の影響を受けており、特に初期のネットワーク実装ではPlan 9のファイルシステムベースのネットワークモデルを強く反映していました。
- Plan 9は、ベル研究所で開発された分散オペレーティングシステムです。その最も特徴的な設計原則の一つは「Everything is a file(すべてはファイルである)」です。これは、プロセス、ネットワーク接続、デバイスなど、システム内のあらゆるリソースがファイルシステム上のファイルとして表現され、標準的なファイル操作(
-
Go言語の
net
パッケージ:- Goの標準ライブラリである
net
パッケージは、TCP/IP、UDP、Unixドメインソケットなど、様々なネットワークプロトコルを扱うためのプラットフォーム非依存のインターフェースを提供します。 - しかし、内部的には各オペレーティングシステム(Linux, Windows, macOS, そしてPlan 9など)のネイティブなネットワークAPIを呼び出すためのOS固有の実装を持っています。このコミットで変更されているファイル(
fd_plan9.go
,ipsock_plan9.go
など)は、まさにPlan 9に特化した実装部分です。 netFD
構造体:net
パッケージ内部でネットワークファイルディスクリプタを抽象化するために使用される構造体です。Plan 9の場合、この構造体はctl
ファイルとdata
ファイルへの参照を保持します。
- Goの標準ライブラリである
-
ファイルディスクリプタとリソース管理:
- ファイルディスクリプタ(File Descriptor, FD)は、オペレーティングシステムがファイルやI/Oリソースを識別するために使用する抽象的なハンドルです。ネットワークソケットもファイルディスクリプタとして扱われることが一般的です。
- プログラムがファイルディスクリプタを開くと、対応するシステムリソースが消費されます。これらのリソースは、プログラムが終了するか、明示的にクローズされるまで解放されません。リソースリークを防ぐためには、不要になったファイルディスクリプタを確実にクローズすることが非常に重要です。
これらの背景知識を踏まえることで、コミットがなぜ特定のファイルを変更し、どのような挙動の改善を目指しているのかがより明確になります。
技術的詳細
このコミットは、Plan 9環境におけるGoのネットワーク処理のいくつかの側面を改善しています。
-
データファイルの即時オープン:
- 以前は、
netFD
のRead
またはWrite
メソッドが初めて呼び出されたときに、data
ファイルがos.OpenFile(fd.dir+"/data", os.O_RDWR, 0)
によって開かれていました。 - このコミットでは、
newFD
関数(netFD
構造体を初期化するヘルパー関数)のシグネチャが変更され、ctl
ファイルだけでなくdata
ファイルも引数として受け取るようになりました。 - これにより、
dialPlan9
やacceptPlan9
といった接続確立時に、data
ファイルが即座に開かれ、newFD
に渡されるようになりました。これにより、接続が確立された時点でデータ送受信の準備が整い、最初のRead
/Write
時の遅延やエラー処理の複雑さが解消されます。 Read
およびWrite
メソッド内のfd.data == nil
チェックとファイルオープンロジックは削除されました。
- 以前は、
-
Close
メソッドの堅牢化:- 以前の
Close
メソッドでは、fd.ctl.Close()
でエラーが発生した場合、すぐにリターンしていました。この場合、fd.data
がnil
でなければ、fd.data.Close()
が呼び出されず、データファイルが閉じられない可能性がありました。 - 新しい実装では、
fd.ctl.Close()
のエラーをerr
変数に保持しつつ、fd.data != nil
であれば必ずfd.data.Close()
を試みるようになりました。 fd.data.Close()
でエラーが発生した場合、それが最初のctl.Close()
のエラーがnil
であった場合にのみ、そのエラーをerr
に設定します。これにより、両方のクローズ操作を試み、最初のエラーを優先して報告しつつ、リソースの解放を最大化します。- 最後に、
fd.ctl = nil
とfd.data = nil
が必ず実行されるようになり、ファイルディスクリプタの参照が確実にクリアされるようになりました。
- 以前の
-
Accept
コールにおけるリモートアドレスの正確な設定:listenPlan9
のacceptPlan9
メソッドは、新しい接続を受け入れる際に、その接続のリモートアドレスを正しく取得していませんでした。以前は、リスナーのディレクトリ(l.dir
)からリモートアドレスを読み取ろうとしていましたが、これは新しい接続固有のアドレスではありませんでした。- 修正後、
acceptPlan9
は、新しく確立された接続の固有のディレクトリ(/net/
+l.proto
+/
+name
)からリモートアドレス(/remote
ファイル)を読み取るようになりました。これにより、Accept
によって返されるnetFD
オブジェクトが正しいリモートアドレスを持つことが保証されます。 - また、
acceptPlan9
内でもdata
ファイルが即座に開かれ、newFD
に渡されるようになりました。
-
newTCPConn
およびnewUDPConn
ヘルパー関数の利用:dialTCP
やdialUDP
といった関数が、TCPConn
やUDPConn
構造体を直接初期化する代わりに、それぞれnewTCPConn(fd)
やnewUDPConn(fd)
という新しいヘルパー関数を使用するように変更されました。newUDPConn
関数が追加され、*UDPConn
を返すようになりました。- これにより、接続オブジェクトの生成ロジックが一元化され、コードの可読性と保守性が向上します。
これらの変更は、Plan 9環境におけるGoのネットワークスタックの信頼性と正確性を大幅に向上させ、リソース管理のベストプラクティスに沿ったものとなっています。
コアとなるコードの変更箇所
このコミットによって変更された主要なファイルと、その変更の概要は以下の通りです。
-
src/pkg/net/fd_plan9.go
:newFD
関数のシグネチャが変更され、data *os.File
引数が追加されました。Read
およびWrite
メソッドから、fd.data == nil
の場合にデータファイルを開くロジックが削除されました。代わりに、fd.ok() || fd.data == nil
というチェックが追加され、data
ファイルが有効でない場合は即座にエラーを返すようになりました。Close
メソッドのロジックが変更され、ctl
とdata
の両方のファイルを確実に閉じ、エラーが発生しても両方をnil
に設定するようになりました。
-
src/pkg/net/ipsock_plan9.go
:dialPlan9
関数内で、ctl
ファイルを開いた直後にdata
ファイルも開くようになりました。そして、newFD
を呼び出す際にdata
ファイルを渡すようになりました。エラーハンドリングも、data
ファイルが開けなかった場合にctl
ファイルを閉じるように修正されました。listenPlan9
関数内で、newFD
を呼び出す際にdata
ファイルとしてnil
を渡すようになりました(リスナーはデータファイルを直接持たないため)。netFD
のnetFD()
メソッドが、newFD
を呼び出す際にdata
ファイルも渡すように変更されました。acceptPlan9
関数内で、新しく受け入れられた接続のdata
ファイルを開くようになりました。また、リモートアドレスを読み取るパスが、リスナーのディレクトリではなく、新しく確立された接続の固有のディレクトリを参照するように修正されました。newFD
を呼び出す際にdata
ファイルを渡すようになりました。
-
src/pkg/net/tcpsock_plan9.go
:dialTCP
関数が、&TCPConn{conn{fd}}
という直接的な構造体初期化の代わりに、newTCPConn(fd)
ヘルパー関数を使用するように変更されました。
-
src/pkg/net/udpsock_plan9.go
:newUDPConn
という新しいヘルパー関数が追加されました。ReadFromUDP
およびWriteToUDP
メソッドから、c.fd.data == nil
の場合にデータファイルを開くロジックが削除されました。代わりに、c.ok() || c.fd.data == nil
というチェックが追加され、data
ファイルが有効でない場合は即座にエラーを返すようになりました。dialUDP
関数が、&UDPConn{conn{fd}}
という直接的な構造体初期化の代わりに、newUDPConn(fd)
ヘルパー関数を使用するように変更されました。ListenUDP
関数内で、リスナーのdata
ファイルを開くようになりました。そして、newUDPConn(l.netFD())
を使用するように変更されました。
これらの変更は、Plan 9におけるネットワーク接続のライフサイクル管理とリソースハンドリングを改善し、より堅牢で予測可能な挙動を実現しています。
コアとなるコードの解説
ここでは、主要な変更点について、具体的なコードの差分を基に解説します。
src/pkg/net/fd_plan9.go
newFD
関数の変更
--- a/src/pkg/net/fd_plan9.go
+++ b/src/pkg/net/fd_plan9.go
@@ -29,22 +29,16 @@ func dialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
return dialTimeoutRace(net, addr, timeout)
}
-func newFD(proto, name string, ctl *os.File, laddr, raddr Addr) *netFD {
- return &netFD{proto, name, "/net/" + proto + "/" + name, ctl, nil, laddr, raddr}
+func newFD(proto, name string, ctl, data *os.File, laddr, raddr Addr) *netFD {
+ return &netFD{proto, name, "/net/" + proto + "/" + name, ctl, data, laddr, raddr}
}
- 変更点:
newFD
関数のシグネチャにdata *os.File
が追加されました。 - 解説: 以前は
netFD
構造体のdata
フィールドはnil
で初期化されていました。この変更により、接続が確立される際にdata
ファイルが外部から渡され、netFD
オブジェクトが生成された時点でdata
ファイルへの参照を持つことができるようになりました。これは、データファイルの遅延オープンをなくし、接続確立時に即座にデータ送受信の準備を整えるための基盤となります。
Read
およびWrite
メソッドの変更
--- a/src/pkg/net/fd_plan9.go
+++ b/src/pkg/net/fd_plan9.go
@@ -34,15 +28,9 @@ func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil }
func (fd *netFD) Read(b []byte) (n int, err error) {
- if !fd.ok() {
+ if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL
}
- if fd.data == nil {
- fd.data, err = os.OpenFile(fd.dir+"/data", os.O_RDWR, 0)
- if err != nil {
- return 0, err
- }
- }
n, err = fd.data.Read(b)
if fd.proto == "udp" && err == io.EOF {
n = 0
@@ -54,15 +48,9 @@ func (fd *netFD) Read(b []byte) (n int, err error) {
}
func (fd *netFD) Write(b []byte) (n int, err error) {
- if !fd.ok() {
+ if !fd.ok() || fd.data == nil {
return 0, syscall.EINVAL
}
- if fd.data == nil {
- fd.data, err = os.OpenFile(fd.dir+"/data", os.O_RDWR, 0)
- if err != nil {
- return 0, err
- }
- }
return fd.data.Write(b)
}
- 変更点:
Read
とWrite
メソッドから、fd.data == nil
の場合にdata
ファイルを開くロジックが削除されました。また、if !fd.ok()
の条件がif !fd.ok() || fd.data == nil
に変更されました。 - 解説:
newFD
の変更により、data
ファイルは接続確立時に既に開かれていることが期待されるため、これらのメソッド内で再度開く必要がなくなりました。fd.data == nil
のチェックが追加されたのは、data
ファイルが適切に設定されていない場合に備えて、早期に無効な引数エラー(syscall.EINVAL
)を返すためです。これにより、コードが簡潔になり、エラー処理のパスも明確になります。
Close
メソッドの変更
--- a/src/pkg/net/fd_plan9.go
+++ b/src/pkg/net/fd_plan9.go
@@ -85,11 +73,10 @@ func (fd *netFD) Close() error {
return syscall.EINVAL
}
err := fd.ctl.Close()
-\tif err != nil {\n-\t\treturn err\n-\t}\n \tif fd.data != nil {\n-\t\terr = fd.data.Close()\n+\t\tif err1 := fd.data.Close(); err1 != nil && err == nil {\n+\t\t\terr = err1\n+\t\t}\n \t}\n \tfd.ctl = nil
\tfd.data = nil
- 変更点:
fd.ctl.Close()
でエラーが発生してもすぐにリターンせず、fd.data.Close()
も試みるようになりました。エラーの伝播ロジックも変更されました。 - 解説:
err := fd.ctl.Close()
: まず制御ファイルを閉じます。エラーが発生しても、すぐにリターンしません。if fd.data != nil
: データファイルが存在する場合、そのクローズを試みます。if err1 := fd.data.Close(); err1 != nil && err == nil
: データファイルのクローズでエラー(err1
)が発生し、かつ制御ファイルのクローズでエラーがなかった場合(err == nil
)、err1
を最終的なエラーとしてerr
に設定します。これにより、両方のクローズ操作を試み、最初のエラーを優先して報告しつつ、リソースの解放を最大化します。fd.ctl = nil
とfd.data = nil
: 最後に、ファイルディスクリプタの参照を確実にnil
に設定します。これにより、リソースリークを防ぎ、オブジェクトが適切にクリーンアップされた状態を保証します。
src/pkg/net/ipsock_plan9.go
dialPlan9
関数の変更
--- a/src/pkg/net/ipsock_plan9.go
+++ b/src/pkg/net/ipsock_plan9.go
@@ -114,17 +114,24 @@ func dialPlan9(net string, laddr, raddr Addr) (*netFD, error) {
f.Close()
return nil, err
}
+ data, err := os.OpenFile("/net/"+proto+"/"+name+"/data", os.O_RDWR, 0)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
if err != nil {
+ data.Close()
f.Close()
return nil, err
}
raddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/remote")
if err != nil {
+ data.Close()
f.Close()
return nil, err
}
- return newFD(proto, name, f, laddr, raddr), nil
+ return newFD(proto, name, f, data, laddr, raddr), nil
}
- 変更点:
ctl
ファイル(f
)を開いた直後にdata
ファイルも開くようになりました。newFD
の呼び出しにdata
ファイルが追加されました。エラーハンドリングも、data
ファイルが開けなかった場合にctl
ファイルを閉じるように修正されました。 - 解説: これにより、
dialPlan9
(クライアント側での接続確立)が完了した時点で、netFD
オブジェクトがctl
とdata
の両方のファイルディスクリプタを保持するようになります。これは、fd_plan9.go
のRead
/Write
メソッドの変更と連携し、データファイルの即時オープンを実現します。
acceptPlan9
関数の変更
--- a/src/pkg/net/ipsock_plan9.go
+++ b/src/pkg/net/ipsock_plan9.go
@@ -161,15 +168,16 @@ func (l *netFD) acceptPlan9() (*netFD, error) {
return nil, err
}
name := string(buf[:n])
-\tladdr, err := readPlan9Addr(l.proto, l.dir+"/local")
+\tdata, err := os.OpenFile("/net/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
\tif err != nil {\n \t\tf.Close()\n \t\treturn nil, err\n \t}\n-\traddr, err := readPlan9Addr(l.proto, l.dir+"/remote")
+\traddr, err := readPlan9Addr(l.proto, "/net/"+l.proto+"/"+name+"/remote")
\tif err != nil {\n+\t\tdata.Close()\n \t\tf.Close()\n \t\treturn nil, err
\t}\n-\treturn newFD(l.proto, name, f, laddr, raddr), nil
+\treturn newFD(l.proto, name, f, data, l.laddr, raddr), nil
}
- 変更点: 新しく受け入れられた接続の
data
ファイルを開くようになりました。リモートアドレスを読み取るパスが、リスナーのディレクトリではなく、新しく確立された接続の固有のディレクトリを参照するように修正されました。newFD
を呼び出す際にdata
ファイルが追加されました。 - 解説:
data, err := os.OpenFile(...)
:dialPlan9
と同様に、acceptPlan9
でも新しい接続のdata
ファイルを即座に開きます。raddr, err := readPlan9Addr(l.proto, "/net/"+l.proto+"/"+name+"/remote")
: 最も重要な修正点の一つです。以前はリスナーのl.dir
からリモートアドレスを読み取ろうとしていましたが、これは誤りでした。新しいコードでは、name
変数(新しく受け入れられた接続の識別子)を使用して、その接続固有のリモートアドレスファイルから正確なリモートアドレスを読み取るようになりました。これにより、Accept
が返す接続オブジェクトが正しいリモートアドレスを持つことが保証されます。
src/pkg/net/tcpsock_plan9.go
dialTCP
関数の変更
--- a/src/pkg/net/tcpsock_plan9.go
+++ b/src/pkg/net/tcpsock_plan9.go
@@ -98,7 +98,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
if err != nil {
return nil, err
}
- return &TCPConn{conn{fd}}, nil
+ return newTCPConn(fd), nil
}
- 変更点:
&TCPConn{conn{fd}}
という直接的な構造体初期化の代わりに、newTCPConn(fd)
ヘルパー関数を使用するように変更されました。 - 解説: これは、接続オブジェクトの生成ロジックを一元化し、コードの可読性と保守性を向上させるためのリファクタリングです。
newTCPConn
は、TCPConn
オブジェクトを生成する際の標準的な方法を提供します。
src/pkg/net/udpsock_plan9.go
newUDPConn
関数の追加
--- a/src/pkg/net/udpsock_plan9.go
+++ b/src/pkg/net/udpsock_plan9.go
@@ -19,6 +19,10 @@ type UDPConn struct {
conn
}
+func newUDPConn(fd *netFD) *UDPConn {
+ return &UDPConn{conn{fd}}
+}
+
// ReadFromUDP reads a UDP packet from c, copying the payload into b.
// It returns the number of bytes copied into b and the return address
// that was on the packet.
- 変更点:
newUDPConn
という新しいヘルパー関数が追加されました。 - 解説:
TCPConn
と同様に、UDPConn
オブジェクトを生成するための標準的なヘルパー関数が提供されました。これにより、UDPConn
のインスタンス化が一貫した方法で行われるようになります。
ReadFromUDP
およびWriteToUDP
メソッドの変更
--- a/src/pkg/net/udpsock_plan9.go
+++ b/src/pkg/net/udpsock_plan9.go
@@ -27,15 +31,9 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
// Timeout() == true after a fixed time limit; see SetDeadline and
// SetReadDeadline.
func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
-\tif !c.ok() {\n+\tif !c.ok() || c.fd.data == nil {\n \t\treturn 0, nil, syscall.EINVAL\n \t}\n-\tif c.fd.data == nil {\n-\t\tc.fd.data, err = os.OpenFile(c.fd.dir+"/data", os.O_RDWR, 0)\n-\t\tif err != nil {\n-\t\t\treturn 0, nil, err
-\t\t}\n-\t}\n \tbuf := make([]byte, udpHeaderSize+len(b))\n \tm, err := c.fd.data.Read(buf)\n \tif err != nil {\
@@ -76,16 +74,9 @@ func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr,\
// SetWriteDeadline. On packet-oriented connections, write timeouts
// are rare.\n func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {\n-\tif !c.ok() {\n+\tif !c.ok() || c.fd.data == nil {\n \t\treturn 0, syscall.EINVAL\n \t}\n-\tif c.fd.data == nil {\n-\t\tf, err := os.OpenFile(c.fd.dir+"/data", os.O_RDWR, 0)\n-\t\tif err != nil {\n-\t\t\treturn 0, err\n-\t\t}\n-\t\tc.fd.data = f\n-\t}\n \th := new(udpHeader)\n \th.raddr = addr.IP.To16()\n \th.laddr = c.fd.laddr.(*UDPAddr).IP.To16()\
- 変更点:
ReadFromUDP
とWriteToUDP
メソッドから、c.fd.data == nil
の場合にdata
ファイルを開くロジックが削除されました。また、if !c.ok()
の条件がif !c.ok() || c.fd.data == nil
に変更されました。 - 解説:
fd_plan9.go
のRead
/Write
メソッドと同様に、UDPConn
のデータファイルも接続確立時に開かれるようになったため、これらのメソッド内で再度開く必要がなくなりました。
dialUDP
およびListenUDP
関数の変更
--- a/src/pkg/net/udpsock_plan9.go
+++ b/src/pkg/net/udpsock_plan9.go
@@ -141,7 +132,7 @@ func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, e
if err != nil {
return nil, err
}
- return &UDPConn{conn{fd}}, nil
+ return newUDPConn(fd), nil
}
const udpHeaderSize = 16*3 + 2*2
@@ -193,7 +184,11 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
if err != nil {
return nil, err
}
- return &UDPConn{conn{l.netFD()}}, nil
+ l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return nil, err
+ }
+ return newUDPConn(l.netFD()), nil
}
- 変更点:
dialUDP
はnewUDPConn(fd)
を使用するように変更されました。ListenUDP
は、リスナーのdata
ファイルを開くようになり、newUDPConn(l.netFD())
を使用するように変更されました。 - 解説:
dialUDP
の変更は、newUDPConn
ヘルパー関数の一貫した使用を促進します。ListenUDP
の変更は、UDPリスナーも関連するdata
ファイルを適切に管理し、newUDPConn
を通じて一貫したオブジェクト生成を行うことを保証します。
これらの変更は、Plan 9環境におけるGoのネットワークスタックの堅牢性、正確性、および保守性を向上させるための重要なステップです。
関連リンク
- Go CL 7228068: https://golang.org/cl/7228068
参考にした情報源リンク
- Go
net
package and Plan 9: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFtuU_OdVFXLXwa12cMId49NJuMGC7GUVyRMvJfZmAbGFOdPap69E9PHkUBJ-nX1u-z_UXNW1yxR0TGr71gYHb2k-VrLMHw_6IxidCU4ACUEnUEsOetcuKh6W_lpyj5XLONkepAnsDaitjWUTFxLWqLvBumEQnmN-LtvhWYjiX2gsRn03EyzGG8 - Go and Plan 9 principles: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEA6B8xYY-9LNNfdVhkGhVGI05uMA4_pNOH9F1bs0RypICGh5hYeCfcwZ7IqWJPQpnFyLE6ng52lXwCTv1ByjKZ4V8KLkV32cKg8vhgHo1AJKL_S4piu0lyNa2oDdC53NSYRRL3l-39