[インデックス 11537] ファイルの概要
このコミットは、Go言語の標準ライブラリにおいて、Windows環境でのIPv4マルチキャスト機能のサポートを強化するものです。具体的には、net
パッケージとsyscall
パッケージにIPv4マルチキャスト関連のヘルパー関数を追加し、それに伴いWindows上でのシンプルなIPv4マルチキャストテストを再度有効にしています。
コミット
commit 804f1882c582f05d55db812964ebe41a986b5eb1
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Wed Feb 1 14:14:04 2012 +0900
net, syscall: add IPv4 multicast helpers for windows
Also re-enable simple IPv4 multicast testing on windows.
R=alex.brainman, rsc
CC=golang-dev
https://golang.org/cl/5605048
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/804f1882c582f05d55db812964ebe41a986b5eb1
元コミット内容
net, syscall: add IPv4 multicast helpers for windows
Also re-enable simple IPv4 multicast testing on windows.
R=alex.brainman, rsc
CC=golang-dev
https://golang.org/cl/5605048
変更の背景
Go言語のネットワークライブラリは、クロスプラットフォームでの動作を目指していますが、特定のOS固有の機能や挙動に対応するためには、OS固有の実装が必要となる場合があります。このコミット以前のGoのWindows環境では、IPv4マルチキャストに関する一部の機能が未実装(TODO
コメントで示されていた)であり、関連するテストも無効化されていました。
この変更の背景には、Windows環境でのIPv4マルチキャスト通信をGoプログラムからより適切に制御できるようにするという目的があります。具体的には、マルチキャストパケットの送信インターフェースの指定、TTL(Time To Live)値の設定、ループバックの有効/無効化といった、マルチキャスト通信において重要なソケットオプションを設定するためのヘルパー関数が不足していました。これらの機能が実装されることで、Goで書かれたネットワークアプリケーションがWindows上でより高度なマルチキャスト通信を行えるようになります。また、テストの再有効化は、これらの新機能が正しく動作することを保証するために不可欠です。
前提知識の解説
IPv4マルチキャスト
IPv4マルチキャストは、単一の送信元から特定のグループに属する複数の受信者に対して、効率的にデータを送信するための通信方式です。ユニキャスト(1対1)やブロードキャスト(1対全員)とは異なり、マルチキャストでは「マルチキャストグループ」という概念が導入されます。データはマルチキャストグループアドレス宛に送信され、そのグループに参加しているすべてのホストがデータを受信できます。これにより、帯域幅の節約やネットワーク負荷の軽減が実現されます。
ソケットオプション
ソケットオプションは、ネットワークソケットの動作を制御するための設定項目です。setsockopt
(設定)やgetsockopt
(取得)といったシステムコールを通じて、アプリケーションはソケットの挙動を細かく調整できます。マルチキャスト通信においては、以下のようなソケットオプションが重要になります。
IP_MULTICAST_IF
: マルチキャストパケットを送信する際に使用するローカルインターフェースを指定します。複数のネットワークインターフェースを持つホストで、どのインターフェースからマルチキャストパケットを送信するかを制御するために使用されます。IP_MULTICAST_TTL
: マルチキャストパケットのTTL(Time To Live)値を設定します。TTLはパケットが通過できるルーターのホップ数を制限し、ネットワーク上でのパケットの到達範囲を制御します。IP_MULTICAST_LOOP
: マルチキャストパケットのループバックを制御します。このオプションが有効な場合、送信元ホスト自身も送信したマルチキャストパケットを受信します。無効な場合、送信元ホストは自身の送信したパケットを受信しません。
Windows APIとシステムコール
Windowsオペレーティングシステムでは、アプリケーションがカーネルの機能にアクセスするためにWin32 APIが提供されています。ネットワーク関連の機能はWinsock(Windows Sockets)APIを通じて提供され、ソケットオプションの設定にはsetsockopt
関数が使用されます。Go言語のsyscall
パッケージは、これらのOS固有のシステムコールやAPIをGoプログラムから呼び出すためのインターフェースを提供します。
unsafe.Pointer
とSizeof
Go言語のunsafe
パッケージは、型安全性をバイパスして低レベルのメモリ操作を可能にするための機能を提供します。
unsafe.Pointer
: 任意の型のポインタを保持できる汎用ポインタです。異なる型のポインタ間で変換を行う際に使用されます。unsafe.Sizeof
: 指定された式のメモリ上のサイズ(バイト単位)を返します。構造体や配列のサイズを動的に取得する際に使用されます。 これらの機能は、C言語の構造体をGoの構造体として扱い、システムコールに渡す際に、メモリレイアウトを正確に合わせるために必要となることがあります。
技術的詳細
このコミットは、Go言語のnet
パッケージとsyscall
パッケージにまたがる変更で、Windows環境でのIPv4マルチキャスト機能の不足を解消しています。
-
net/multicast_test.go
の変更:TestSimpleListenMulticastUDP
関数内で、これまでWindows環境ではテストをスキップしていたcase "windows": return
の行が削除されました。これにより、Windows上でもシンプルなIPv4マルチキャストのテストが実行されるようになります。これは、後述するヘルパー関数の実装によって、Windowsでのマルチキャスト機能が利用可能になったためです。
-
net/sockoptip_windows.go
の変更:setIPv4MulticastInterface(fd *netFD, ifi *Interface) error
関数が実装されました。この関数は、指定されたネットワークインターフェース(ifi
)をマルチキャスト送信インターフェースとして設定します。interfaceToIPv4Addr(ifi)
でインターフェースのIPv4アドレスを取得します。- 取得したIPv4アドレスを4バイトの配列
x
にコピーします。 syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
を呼び出して、ソケットオプションIP_MULTICAST_IF
を設定します。SetsockoptInet4Addr
は、後述するsyscall
パッケージで新しく追加されたヘルパー関数です。
setIPv4MulticastTTL(fd *netFD, v int) error
関数が実装されました。この関数は、マルチキャストパケットのTTL値を設定します。syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
を呼び出して、ソケットオプションIP_MULTICAST_TTL
を設定します。
setIPv4MulticastLoopback(fd *netFD, v bool) error
関数が実装されました。この関数は、マルチキャストループバックの有効/無効を設定します。syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
を呼び出して、ソケットオプションIP_MULTICAST_LOOP
を設定します。boolint(v)
はbool
値をint
に変換するヘルパー関数です。
- これらの関数は、以前は
// TODO: Implement this
とコメントされ、syscall.EWINDOWS
(Windowsでの未実装エラー)を返していました。今回の変更で、実際のソケットオプション設定ロジックが追加されました。 os
パッケージがインポートされています。これはos.NewSyscallError
を使用するためです。
-
syscall/syscall_windows.go
の変更:SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error)
関数が新しく追加されました。- この関数は、IPv4アドレス(4バイト配列)をソケットオプションとして設定するための汎用ヘルパーです。
- 内部で
Setsockopt
関数を呼び出しており、value
(4バイト配列)の先頭アドレスをunsafe.Pointer
で*byte
にキャストし、サイズを4
(バイト)として渡しています。これは、C言語のsetsockopt
関数がポインタとサイズを引数として取ることに対応するためです。
-
syscall/ztypes_windows.go
の変更:- Windowsのソケットオプション定数として、以下の3つが追加されました。
IP_MULTICAST_IF = 0x9
IP_MULTICAST_TTL = 0xa
IP_MULTICAST_LOOP = 0xb
- これらの定数は、Microsoftのサポート技術情報(KB257460)に記載されている値と一致しており、WindowsのWinsock APIにおけるIPv4マルチキャスト関連のソケットオプションに対応します。
- Windowsのソケットオプション定数として、以下の3つが追加されました。
これらの変更により、Go言語のnet
パッケージはWindows環境においても、IPv4マルチキャスト通信のより詳細な制御が可能となり、クロスプラットフォームでのマルチキャストアプリケーション開発が容易になります。
コアとなるコードの変更箇所
src/pkg/net/multicast_test.go
--- a/src/pkg/net/multicast_test.go
+++ b/src/pkg/net/multicast_test.go
@@ -86,7 +86,7 @@ func TestListenMulticastUDP(t *testing.T) {
func TestSimpleListenMulticastUDP(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "windows":
+ case "plan9":
return
}
src/pkg/net/sockoptip_windows.go
--- a/src/pkg/net/sockoptip_windows.go
+++ b/src/pkg/net/sockoptip_windows.go
@@ -7,6 +7,7 @@
package net
import (
+ "os"
"syscall"
)
@@ -16,8 +17,19 @@ func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
}
func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
- // TODO: Implement this
- return syscall.EWINDOWS
+ ip, err := interfaceToIPv4Addr(ifi)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ var x [4]byte
+ copy(x[:], ip.To4())
+ fd.incref()
+ defer fd.decref()
+ err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
}
func ipv4MulticastTTL(fd *netFD) (int, error) {
@@ -26,8 +38,14 @@ func ipv4MulticastTTL(fd *netFD) (int, error) {
}
func setIPv4MulticastTTL(fd *netFD, v int) error {
- // TODO: Implement this
- return syscall.EWINDOWS
+ fd.incref()
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+
}
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
@@ -36,8 +54,14 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
}
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
- // TODO: Implement this
- return syscall.EWINDOWS
+ fd.incref()
+ defer fd.decref()
+ err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
+ if err != nil {
+ return os.NewSyscallError("setsockopt", err)
+ }
+ return nil
+
}
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
src/pkg/syscall/syscall_windows.go
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -657,6 +657,9 @@ type IPv6Mreq struct {
func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, EWINDOWS }
func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) { return EWINDOWS }
+func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) {
+ return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4)
+}
func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) {
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq)))
}
src/pkg/syscall/ztypes_windows.go
--- a/src/pkg/syscall/ztypes_windows.go
+++ b/src/pkg/syscall/ztypes_windows.go
@@ -389,8 +389,13 @@ const (
SO_SNDBUF = 0x1001
SO_UPDATE_ACCEPT_CONTEXT = 0x700b
+ // cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460
+
IP_TOS = 0x3
IP_TTL = 0x4
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_TTL = 0xa
+ IP_MULTICAST_LOOP = 0xb
IP_ADD_MEMBERSHIP = 0xc
IP_DROP_MEMBERSHIP = 0xd
コアとなるコードの解説
src/pkg/net/sockoptip_windows.go
このファイルは、Windows固有のIPソケットオプション設定に関するロジックをカプセル化しています。
-
setIPv4MulticastInterface
:interfaceToIPv4Addr(ifi)
: ネットワークインターフェースオブジェクトifi
から、そのインターフェースに割り当てられたIPv4アドレスを取得します。var x [4]byte; copy(x[:], ip.To4())
: 取得したnet.IP
型のアドレスを、syscall.SetsockoptInet4Addr
が期待する4バイトのバイト配列x
に変換してコピーします。syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
: 実際にソケットオプションを設定する部分です。fd.sysfd
: ソケットのファイルディスクリプタ(Windowsではハンドル)。syscall.IPPROTO_IP
: IPプロトコルレベルのオプションであることを示します。syscall.IP_MULTICAST_IF
: マルチキャスト送信インターフェースを指定するためのソケットオプション定数。x
: 設定するIPv4アドレス(4バイト配列)。
fd.incref()
とfd.decref()
:netFD
の参照カウントを管理し、ソケットが適切にクローズされるようにします。os.NewSyscallError("setsockopt", err)
: システムコールエラーが発生した場合に、より詳細なエラー情報を含むos.SyscallError
を生成します。
-
setIPv4MulticastTTL
:syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
: マルチキャストTTL値を設定します。SetsockoptInt
は整数値を設定するためのヘルパー関数です。
-
setIPv4MulticastLoopback
:syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
: マルチキャストループバックの有効/無効を設定します。boolint(v)
はtrue
を1、false
を0に変換します。
src/pkg/syscall/syscall_windows.go
このファイルは、Windows固有のシステムコールをGoから呼び出すためのラッパー関数を提供します。
SetsockoptInet4Addr
:Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4)
: この関数が、実際のWindows APIのsetsockopt
に相当する低レベルのSetsockopt
関数を呼び出します。(*byte)(unsafe.Pointer(&value[0]))
: 4バイト配列value
の先頭要素のアドレスをunsafe.Pointer
を介して*byte
型にキャストしています。これは、Setsockopt
関数がオプション値のポインタを*byte
として受け取るためです。4
: オプション値のサイズ(IPv4アドレスは4バイト)を指定します。
src/pkg/syscall/ztypes_windows.go
このファイルは、Windows APIで使用される定数や構造体のGo言語での定義を含んでいます。
IP_MULTICAST_IF
,IP_MULTICAST_TTL
,IP_MULTICAST_LOOP
:- これらの定数は、WindowsのWinsock APIで定義されているソケットオプションの識別子です。Goの
syscall
パッケージがこれらの定数を定義することで、GoプログラムからWindows固有のソケットオプションを直接参照できるようになります。コメントにあるMicrosoftのKB記事は、これらの定数の由来と意味を裏付けています。
- これらの定数は、WindowsのWinsock APIで定義されているソケットオプションの識別子です。Goの
これらの変更により、Goのnet
パッケージは、Windows環境でのIPv4マルチキャスト通信において、よりきめ細やかな制御を可能にし、他のOSと同様の機能を提供できるようになりました。
関連リンク
- Go言語の
net
パッケージドキュメント: https://pkg.go.dev/net - Go言語の
syscall
パッケージドキュメント: https://pkg.go.dev/syscall - Winsock
setsockopt
function (Microsoft Learn): https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt - IP Multicast Programming (Microsoft Learn): https://learn.microsoft.com/en-us/windows/win32/winsock/ip-multicast-programming
参考にした情報源リンク
- https://github.com/golang/go/commit/804f1882c582f05d55db812964ebe41a986b5eb1
- Microsoft Support KB257460 (Internet Archive): https://web.archive.org/web/20150315000000*/http://support.microsoft.com/default.aspx?scid=kb;en-us;257460 (元のリンクは古いため、Internet Archiveのリンクを使用)
- Go言語の
unsafe
パッケージに関するドキュメント: https://pkg.go.dev/unsafe - Go言語の
os
パッケージに関するドキュメント: https://pkg.go.dev/os - 一般的なIPv4マルチキャストに関する情報源 (例: Wikipedia, RFCなど)