[インデックス 13943] ファイルの概要
このコミットは、Go言語の標準ライブラリnet
パッケージにおいて、IPConn
とUDPConn
にIP補助データ(ancillary data)を扱うためのReadMsgIP
およびWriteMsgIP
メソッドを追加するものです。これにより、ソケット制御メッセージを介してIP補助データにアクセスできるようになります。
変更されたファイルは以下の通りです。
src/pkg/net/iprawsock_posix.go
: 33行追加src/pkg/net/udpsock_posix.go
: 37行追加
合計で70行が追加されました。
コミット
commit 4b9e8415dee1587933a2d175966737c429f85f27
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Tue Sep 25 06:57:32 2012 +0900
net: add read, write message methods to IPConn, UDPConn
Both methods allow to access the IP ancillary data through
socket control messages.
This CL is required for CL 6482044; go.net/ipv4: new package.
R=rsc, r, dave
CC=golang-dev
https://golang.org/cl/6426047
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/4b9e8415dee1587933a2d175966737c429f85f27
元コミット内容
net: add read, write message methods to IPConn, UDPConn
Both methods allow to access the IP ancillary data through
socket control messages.
This CL is required for CL 6482044; go.net/ipv4: new package.
R=rsc, r, dave
CC=golang-dev
https://golang.org/cl/6426047
変更の背景
このコミットの主な目的は、Go言語のnet
パッケージにおけるIPConn
(IPソケット接続)とUDPConn
(UDPソケット接続)が、IP補助データ(ancillary data)をソケット制御メッセージ(socket control messages)を介して送受信できるようにすることです。
特に、この変更はCL 6482044
、すなわちgo.net/ipv4
パッケージの新規導入に必要とされています。go.net/ipv4
パッケージは、IPv4のIPレベルソケットオプションをより詳細に制御するための機能を提供します。これには、Type-of-Service (TOS) や Time-to-Live (TTL) の設定、マルチキャストオプションの管理などが含まれます。これらの高度なネットワーク機能を実現するためには、通常のデータペイロードとは別に、IPヘッダ情報などの補助データを送受信するメカニズムが必要となります。
既存のReadFrom
やWriteTo
メソッドでは、データペイロードのみを扱っており、IP補助データへのアクセスができませんでした。このコミットで追加されるReadMsgIP
とWriteMsgIP
メソッドは、このギャップを埋め、go.net/ipv4
のような低レベルネットワーク操作を可能にするための基盤を提供します。
前提知識の解説
IP補助データ (Ancillary Data) とソケット制御メッセージ (Socket Control Messages)
通常のネットワーク通信では、アプリケーションデータ(ペイロード)が送受信されます。しかし、IP層やトランスポート層のプロトコルには、ペイロードとは別に、パケットのルーティング、エラー処理、QoS(Quality of Service)などに関する追加情報が付随することがあります。これを「補助データ(Ancillary Data)」と呼びます。
補助データは、ソケットAPIにおいては「ソケット制御メッセージ(Socket Control Messages)」として扱われます。これは、sendmsg
やrecvmsg
といったシステムコールを通じて、通常のデータとは別に送受信される特殊なメッセージです。例えば、IPヘッダのTTL(Time-to-Live)値、TOS(Type of Service)値、受信インターフェース情報、エラー情報などが補助データとしてやり取りされます。
IPConn
とUDPConn
IPConn
: Go言語のnet
パッケージにおけるIPソケット接続を表す型です。IP層での通信(例: ICMP、IGMP、または生のIPパケット)に使用されます。UDPConn
: Go言語のnet
パッケージにおけるUDPソケット接続を表す型です。UDP(User Datagram Protocol)はコネクションレスなプロトコルで、信頼性よりも速度が重視される場合に用いられます。
これらのコネクションタイプは、ネットワーク通信の基本的な構成要素であり、このコミットではこれらの型に補助データ送受信の機能が拡張されます。
syscall.ReadMsg
とsyscall.WriteMsg
Go言語のsyscall
パッケージは、オペレーティングシステムのシステムコールへの低レベルなインターフェースを提供します。
syscall.ReadMsg
:recvmsg
システムコールをラップしたもので、ソケットからデータと補助データを読み取ります。通常のデータペイロードだけでなく、制御メッセージバッファ(oob
)も引数として受け取り、補助データを格納します。syscall.WriteMsg
:sendmsg
システムコールをラップしたもので、ソケットにデータと補助データを書き込みます。通常のデータペイロードと制御メッセージバッファ(oob
)を引数として受け取り、補助データを送信します。
これらのシステムコールは、IP補助データのような高度なソケット操作を行うために不可欠です。
go.net/ipv4
パッケージ
go.net/ipv4
は、Go言語のgolang.org/x/net
サブリポジトリにあるパッケージで、IPv4のIPレベルソケットオプションをより詳細に制御するための機能を提供します。これには、以下のような機能が含まれます。
- IPヘッダの操作: IPヘッダのフィールド(TOS, TTLなど)を読み書きする機能。
- マルチキャストオプション: マルチキャストグループへの参加/脱退、マルチキャストTTLの設定など。
- Raw IPソケットアクセス: 生のIPパケットを直接送受信する機能。
このパッケージは、標準のnet
パッケージでは提供されていない低レベルなIP通信機能を提供し、ネットワークプログラミングのより高度なユースケースに対応します。今回のコミットは、このgo.net/ipv4
パッケージがnet
パッケージのIPConn
やUDPConn
を通じて補助データにアクセスするための前提条件となります。
技術的詳細
このコミットでは、IPConn
とUDPConn
のそれぞれにReadMsgIP
とWriteMsgIP
という2つの新しいメソッドが追加されています。これらのメソッドは、内部的にnetFD
(ファイルディスクリプタをラップする構造体)のReadMsg
およびWriteMsg
メソッドを呼び出すことで、ソケット制御メッセージを介したIP補助データの送受信を実現しています。
ReadMsgIP
メソッド
ReadMsgIP
メソッドは、ソケットからパケットを読み取り、ペイロードをb
に、関連する補助データ(out-of-band data)をoob
にコピーします。
- 引数:
b []byte
: 受信したペイロードを格納するバイトスライス。oob []byte
: 受信した補助データを格納するバイトスライス。
- 戻り値:
n int
:b
にコピーされたペイロードのバイト数。oobn int
:oob
にコピーされた補助データのバイト数。flags int
: パケットに設定されていたフラグ(例:MSG_OOB
、MSG_TRUNC
など)。addr *IPAddr
または*UDPAddr
: パケットの送信元アドレス。err error
: エラー情報。
内部では、c.fd.ReadMsg(b, oob)
が呼び出されます。このReadMsg
はsyscall.Recvmsg
システムコールをラップしており、ペイロード、補助データ、フラグ、そして送信元ソケットアドレス(syscall.Sockaddr
型)を返します。
返されたsyscall.Sockaddr
は、その型(*syscall.SockaddrInet4
または*syscall.SockaddrInet6
)に応じて、適切な*IPAddr
または*UDPAddr
に変換されます。これにより、呼び出し元はGoのnet
パッケージの型でアドレス情報を受け取ることができます。
WriteMsgIP
メソッド
WriteMsgIP
メソッドは、指定されたアドレスaddr
へパケットを書き込み、ペイロードをb
から、関連する補助データをoob
からコピーします。
- 引数:
b []byte
: 送信するペイロードを含むバイトスライス。oob []byte
: 送信する補助データを含むバイトスライス。addr *IPAddr
または*UDPAddr
: パケットの宛先アドレス。
- 戻り値:
n int
: 書き込まれたペイロードのバイト数。oobn int
: 書き込まれた補助データのバイト数。err error
: エラー情報。
内部では、まず宛先アドレスaddr
がc.fd.family
(ソケットのファミリー、例: AF_INET
、AF_INET6
)に対応するsyscall.Sockaddr
に変換されます。その後、c.fd.WriteMsg(b, oob, sa)
が呼び出されます。このWriteMsg
はsyscall.Sendmsg
システムコールをラップしており、ペイロードと補助データを指定されたソケットアドレスへ送信します。
UDPConn
のWriteMsgUDP
では、ソケットが既に接続済み(c.fd.isConnected
がtrue)の場合にErrWriteToConnected
エラーを返すチェックが追加されています。これは、接続済みUDPソケットではsendmsg
に宛先アドレスを指定する必要がないため、誤用を防ぐためのものです。
これらのメソッドの追加により、Goのnet
パッケージは、IP補助データを扱うための低レベルなソケット操作をサポートし、go.net/ipv4
のようなより高度なネットワーク機能の実装を可能にしています。
コアとなるコードの変更箇所
src/pkg/net/iprawsock_posix.go
--- a/src/pkg/net/iprawsock_posix.go
+++ b/src/pkg/net/iprawsock_posix.go
@@ -98,6 +98,25 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
return n, uaddr.toAddr(), err
}
+// 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) {
+ if !c.ok() {
+ return 0, 0, 0, nil, syscall.EINVAL
+ }
+ var sa syscall.Sockaddr
+ n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ addr = &IPAddr{sa.Addr[0:]}
+ case *syscall.SockaddrInet6:
+ addr = &IPAddr{sa.Addr[0:]}
+ }
+ return
+}
+
// WriteToIP writes an IP packet to addr via c, copying the payload from b.
//
// WriteToIP can be made to time out and return
@@ -127,6 +146,20 @@ func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
return c.WriteToIP(b, a)
}
+// 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) {
+ if !c.ok() {
+ return 0, 0, syscall.EINVAL
+ }
+ sa, err := addr.sockaddr(c.fd.family)
+ if err != nil {
+ return 0, 0, &OpError{"write", c.fd.net, addr, err}
+ }
+ return c.fd.WriteMsg(b, oob, sa)
+}
+
// DialIP connects to the remote address raddr on the network protocol netProto,
// which must be "ip", "ip4", or "ip6" followed by a colon and a protocol number or name.
func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
src/pkg/net/udpsock_posix.go
--- a/src/pkg/net/udpsock_posix.go
+++ b/src/pkg/net/udpsock_posix.go
@@ -87,6 +87,26 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
return n, uaddr.toAddr(), err
}
+// 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) {
+ if !c.ok() {
+ return 0, 0, 0, nil, syscall.EINVAL
+ }
+ var sa syscall.Sockaddr
+ n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ addr = &UDPAddr{sa.Addr[0:], sa.Port}
+ case *syscall.SockaddrInet6:
+ addr = &UDPAddr{sa.Addr[0:], sa.Port}
+ }
+ return
+}
+
// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
//
// WriteToUDP can be made to time out and return
@@ -119,6 +139,23 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
return c.WriteToUDP(b, a)
}
+// 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) {
+ if !c.ok() {
+ return 0, 0, syscall.EINVAL
+ }
+ if c.fd.isConnected {
+ return 0, 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
+ }
+ sa, err := addr.sockaddr(c.fd.family)
+ if err != nil {
+ return 0, 0, &OpError{"write", c.fd.net, addr, err}
+ }
+ return c.fd.WriteMsg(b, oob, sa)
+}
+
// DialUDP connects to the remote address raddr on the network net,\n // which must be "udp", "udp4", or "udp6". If laddr is not nil, it is used
// as the local address for the connection.
コアとなるコードの解説
このコミットで追加された主要な機能は、IPConn
とUDPConn
にそれぞれReadMsgIP
/ReadMsgUDP
とWriteMsgIP
/WriteMsgUDP
メソッドが追加されたことです。これらのメソッドは、IP補助データ(ancillary data)の送受信を可能にします。
IPConn.ReadMsgIP
および UDPConn.ReadMsgUDP
これらのメソッドは、ソケットからデータと補助データを読み取るためのものです。
if !c.ok() { return ... syscall.EINVAL }
: まず、コネクションが有効な状態であるかを確認します。無効な場合はsyscall.EINVAL
エラーを返します。var sa syscall.Sockaddr
: 送信元アドレスを格納するためのsyscall.Sockaddr
型の変数を宣言します。n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
: 内部のnetFD
(ファイルディスクリプタ)のReadMsg
メソッドを呼び出します。このメソッドは、システムコールのrecvmsg
をラップしており、以下の情報を返します。n
: 受信したペイロードのバイト数。oobn
: 受信した補助データのバイト数。flags
: 受信フラグ(例:MSG_OOB
、MSG_TRUNC
など)。sa
: 送信元ソケットアドレス。err
: エラー情報。
switch sa := sa.(type)
: 受信したsyscall.Sockaddr
の具体的な型をチェックします。case *syscall.SockaddrInet4
: IPv4アドレスの場合、sa.Addr[0:]
からIPAddr
またはUDPAddr
を構築します。case *syscall.SockaddrInet6
: IPv6アドレスの場合、sa.Addr[0:]
からIPAddr
またはUDPAddr
を構築します。UDPAddr
の場合はポート番号も含まれます。
return
: 読み取ったデータ、補助データ、フラグ、送信元アドレス、エラーを返します。
IPConn.WriteMsgIP
および UDPConn.WriteMsgUDP
これらのメソッドは、ソケットにデータと補助データを書き込むためのものです。
if !c.ok() { return ... syscall.EINVAL }
: コネクションが有効な状態であるかを確認します。if c.fd.isConnected { return ... ErrWriteToConnected }
(UDPConnのみ):UDPConn
の場合、ソケットが既に接続済みであるかを確認します。接続済みUDPソケットに対してsendmsg
で宛先アドレスを指定することは通常ないため、このチェックは誤用を防ぐためのものです。sa, err := addr.sockaddr(c.fd.family)
: 引数で渡された宛先アドレス(*IPAddr
または*UDPAddr
)を、ソケットのファミリー(IPv4またはIPv6)に対応するsyscall.Sockaddr
型に変換します。if err != nil { return ... &OpError{"write", ...} }
: アドレス変換中にエラーが発生した場合、OpError
を返します。return c.fd.WriteMsg(b, oob, sa)
: 内部のnetFD
のWriteMsg
メソッドを呼び出します。このメソッドは、システムコールのsendmsg
をラップしており、ペイロードb
と補助データoob
を指定されたソケットアドレスsa
へ送信します。書き込まれたペイロードと補助データのバイト数を返します。
これらの変更により、Goのnet
パッケージは、IP補助データという低レベルなネットワーク情報を扱う能力を獲得し、go.net/ipv4
のようなより高度なネットワークプログラミングを可能にするための重要な基盤が整備されました。
関連リンク
- Go CL 6426047: https://golang.org/cl/6426047
- Go CL 6482044 (go.net/ipv4: new package): https://golang.org/cl/6482044 (直接のリンクは提供されていませんが、コミットメッセージに記載されています)
golang.org/x/net/ipv4
パッケージ: https://pkg.go.dev/golang.org/x/net/ipv4
参考にした情報源リンク
- Web search results for "golang CL 6482044 go.net/ipv4":
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHDmQxS2THKxc8ymFTJTXnYxRqZ_UyDOdg6RK-yjOPAwes5bsWYAq8Qk6-XHPLvA2iJZfbh0Z-TxNvij_xoLVAdr5q-1ZOn5ZYzJttE4kaM7d7drbLEsa_G3GFVgCXMpEo=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEvVNOV40QoQ9yDyeI59qS1-0M01Ov3yB_8RgNLsXkQotPe0c813CaIJ5LIOf7QqFpCCWjyHKZ7yov-wQsQKAms8IM0zEFpSGR4TZfyxBk5tm1Mi4k3TH4ELqsjSGiSITAtx12Ye0Lx8Xb4pRHVeQ==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHwFr0KeMpiwa91SYyaMlRGDJjygu6eeLKIjRDLx0Zc3SIJBgqEhK3fgovRZTat_QBVmXjmpzW_plco1hb8bxc2RvarncD2_HwfTbbGHzIs8w4l5uMyhCLt_0OIjr4us_u7Iw==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEE3HbsfDJvYxyE_ErVONuqshZSTe05U8OHQCByipGHCzz_4_TwTvyKg26Z2omkvJNBMznihUpQs_nIgXRbslNJCtjkA34O2KgGQV6rsD1IGKiLwCkz6SrvI0O00wauEhz4AA==