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

[インデックス 18831] ファイルの概要

このコミットは、Go言語の標準ライブラリにおけるSolarisオペレーティングシステム向けのネットワークソケットオプションとシステムコールに関する修正です。特に、マルチキャスト関連のソケットオプションの取り扱いと、SockaddrDatalink構造体の定義の正確性を改善することを目的としています。

コミット

commit ef6c21d0e9158e8dcb95543f684c01219f56b193
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Wed Mar 12 10:32:46 2014 +0900

    syscall, net: clean up socket stub for solaris
    
    Solaris doesn't have struct ip_mreqn, instead it uses struct ip_mreq
    and struct group_req with struct sockaddr_storage.
    
    Also fixes incorrect SockaddrDatalink.
    
    Update #7399
    
    LGTM=aram, iant
    R=golang-codereviews, aram, gobot, iant
    CC=golang-codereviews
    https://golang.org/cl/73920043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/ef6c21d0e9158e8dcb95543f684c01219f56b193

元コミット内容

このコミットの元のメッセージは以下の通りです。

syscall, net: clean up socket stub for solaris

Solaris doesn't have struct ip_mreqn, instead it uses struct ip_mreq
and struct group_req with struct sockaddr_storage.

Also fixes incorrect SockaddrDatalink.

Update #7399

変更の背景

この変更の背景には、Go言語のネットワークスタックがSolarisオペレーティングシステム上で正しく動作しない、あるいはSolarisのAPIとGoの抽象化が一致しないという問題がありました。具体的には、以下の点が挙げられます。

  1. struct ip_mreqn の非互換性: 多くのUnix系システム(Linuxや一部のBSD系)では、IPマルチキャストグループの参加・脱退やインターフェース指定にstruct ip_mreqnという構造体が使用されます。しかし、Solarisではこの構造体が存在せず、代わりにstruct ip_mreqstruct group_reqといった異なる構造体と、より汎用的なstruct sockaddr_storageを組み合わせて使用します。Goのnetパッケージがこれらの差異を吸収しきれていなかったため、Solaris上でのマルチキャスト関連のソケットオプション設定が機能していませんでした。
  2. SockaddrDatalink の定義の誤り: syscallパッケージ内のSockaddrDatalink構造体は、データリンク層のアドレス情報を表現するために使用されますが、Solarisにおける実際のカーネル構造体との間で定義の不一致がありました。これにより、データリンク層のソケットアドレスを扱う際に問題が発生していました。
  3. Issue #7399: このコミットメッセージに記載されているUpdate #7399は、GoのIssueトラッカーにおける「net: IPv4/IPv6 multicast on Solaris」というタイトルのバグ報告(https://github.com/golang/go/issues/7399)を指しています。このIssueでは、Solaris上でのIPv4およびIPv6マルチキャスト機能が動作しないことが報告されており、このコミットはその問題に対する対応の一環として行われました。

これらの問題を解決し、Solaris上でのGoのネットワーク機能の安定性と互換性を向上させることが、このコミットの主な動機となっています。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

  1. ソケットプログラミング: ネットワーク通信を行うためのAPI。特に、ソケットの作成、オプションの設定(setsockopt/getsockopt)、アドレスのバインド、データの送受信など。
  2. IPマルチキャスト: ネットワーク上で特定のグループに属する複数のホストに対してデータを一度に送信する通信方式。IPマルチキャストを使用するには、ソケットオプションを通じてマルチキャストグループへの参加や脱退、送信インターフェースの指定などを行う必要があります。
  3. setsockopt / getsockopt: ソケットの動作を設定・取得するためのシステムコール。level(プロトコルレベル、例: IPPROTO_IPIPPROTO_IPV6)とoptname(オプション名、例: IP_ADD_MEMBERSHIPIPV6_JOIN_GROUP)を指定して、ソケットの振る舞いを変更します。
  4. struct ip_mreq / struct ip_mreqn / struct group_req:
    • struct ip_mreq: IPv4マルチキャストグループに参加・脱退する際に使用される構造体。グループアドレスとインターフェースアドレス(通常はINADDR_ANY)を含みます。
    • struct ip_mreqn: struct ip_mreqに加えて、インターフェースをインデックスで指定できる拡張版。Linuxなどでよく使われます。
    • struct group_req: IPv6マルチキャストや、より汎用的なマルチキャストグループ管理に使用される構造体。グループアドレスとインターフェースインデックスを含みます。Solarisではこれらが使用されます。
  5. struct sockaddr_storage: 異なる種類のアドレス構造体(IPv4のsockaddr_in、IPv6のsockaddr_in6など)を格納できる汎用的なソケットアドレス構造体。これにより、APIが特定のアドレスファミリーに依存しないように設計できます。
  6. Goのビルドタグ (+build): Go言語のソースファイルに記述される特殊なコメント行で、特定の環境(OS、アーキテクチャなど)でのみそのファイルをコンパイルするように指定します。例えば、+build solarisはSolarisでのみコンパイルされることを意味します。これにより、OS固有のコードを分離して管理できます。
  7. syscallパッケージ: Go言語で低レベルなシステムコールを直接呼び出すためのパッケージ。OS固有の構造体や定数、関数が定義されています。
  8. netパッケージ: Go言語の標準ネットワークパッケージ。syscallパッケージの上に構築され、より高レベルなネットワーク抽象化を提供します。

技術的詳細

このコミットは、Solarisにおけるネットワークソケットオプションの取り扱いを、そのOSの特性に合わせて調整しています。

まず、Goのnetパッケージ内で、マルチキャスト関連のソケットオプションを設定する関数(setIPv4MulticastInterface, setIPv4MulticastLoopback, joinIPv4Group, setIPv6MulticastInterface, setIPv6MulticastLoopback, joinIPv6Group)について、Solaris固有の挙動を導入しています。

  • sockoptip_bsd.gosockoptip_posix.go からのSolarisの除外:

    • src/pkg/net/sockoptip_bsd.go は、Darwin, Dragonfly, FreeBSD, NetBSD, OpenBSDなどのBSD系OS向けのIPソケットオプションを定義していました。このファイルからsolarisビルドタグが削除されました。
    • src/pkg/net/sockoptip_posix.go は、Linuxを含むPOSIX互換OS向けのIPソケットオプションを定義していました。このファイルからもsolarisビルドタグが削除されました。
    • これにより、Solarisはこれらの汎用的なBSD/POSIX実装から切り離され、独自のソケットオプション実装を持つことになります。
  • sockoptip_stub.go の新規追加:

    • src/pkg/net/sockoptip_stub.go という新しいファイルが追加されました。このファイルは+build solarisタグを持つため、Solarisでのみコンパイルされます。
    • このファイルには、前述のマルチキャスト関連のソケットオプション設定関数がスタブとして実装されています。具体的には、これらの関数はすべてsyscall.EINVAL(Invalid argument: 不正な引数)エラーを返します。
    • これは、Solarisがstruct ip_mreqnを使用しないため、Goの汎用的なマルチキャストAPIをSolaris上で直接実装することが困難であるか、あるいはGoの設計思想とSolarisのAPIが大きく異なるため、現時点ではこれらの機能を提供しないという判断がなされたことを意味します。ユーザーがこれらの機能を使おうとすると、明示的に「サポートされていない」というエラーが返されるようになります。

次に、syscallパッケージにおけるSolaris固有の構造体定義が修正されています。

  • src/pkg/syscall/syscall_solaris.go の修正:
    • SockaddrDatalink構造体の定義が修正されました。
      • Len uint8フィールドが削除されました。これは、Solarisのsockaddr_dl構造体にはsdl_lenフィールドが存在しないか、あるいはGoの内部的な扱いとSolarisのカーネル定義との整合性を取るための変更と考えられます。
      • Family uint8Family uint16に変更されました。これにより、アドレスファミリーの表現がSolarisの実際の定義と一致するようになります。
      • Data [46]int8Data [244]int8に大幅に拡張されました。sockaddr_dl構造体は、データリンク層のアドレス(MACアドレスなど)やインターフェース名などを可変長で保持するため、DataフィールドのサイズはOSによって異なります。Solarisのsockaddr_dlがより大きな領域を必要とすることに対応した変更です。
    • IPMreqn構造体が削除されました。これは、Solarisがstruct ip_mreqnを使用しないため、Goのsyscallパッケージ内でこの構造体を定義する必要がなくなったためです。
    • GetsockoptInet4Addr, GetsockoptIPMreqn, SetsockoptIPMreqnといった、IPMreqnに関連するソケットオプション取得/設定関数も削除されました。これは、IPMreqn構造体自体がSolarisでは不要になったため、それらを扱う関数も不要になったためです。

これらの変更により、GoのネットワークスタックはSolarisの低レベルなネットワークAPIとより正確に連携できるようになり、同時に、Solarisでサポートされていないマルチキャスト機能については明示的にエラーを返すことで、予期せぬ動作を防ぐようになります。

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

このコミットにおけるコアとなるコードの変更箇所は以下のファイルに集中しています。

  1. src/pkg/net/sockoptip_bsd.go:
    --- a/src/pkg/net/sockoptip_bsd.go
    +++ b/src/pkg/net/sockoptip_bsd.go
    @@ -2,7 +2,7 @@
     // Use of this source code is governed by a BSD-style
     // license that can be found in the LICENSE file.
     
    -// +build darwin dragonfly freebsd nacl netbsd openbsd solaris
    +// +build darwin dragonfly freebsd nacl netbsd openbsd
     
     package net
    
  2. src/pkg/net/sockoptip_posix.go:
    --- a/src/pkg/net/sockoptip_posix.go
    +++ b/src/pkg/net/sockoptip_posix.go
    @@ -2,7 +2,7 @@
     // Use of this source code is governed by a BSD-style
     // license that can be found in the LICENSE file.\n
    -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
    +// +build darwin dragonfly freebsd linux nacl netbsd openbsd windows
     
     package net
    
  3. src/pkg/net/sockoptip_stub.go: (新規ファイル)
    // Copyright 2011 The Go Authors.  All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    // +build solaris
    
    package net
    
    import "syscall"
    
    func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
    	// See golang.org/issue/7399.
    	return syscall.EINVAL
    }
    
    func setIPv4MulticastLoopback(fd *netFD, v bool) error {
    	// See golang.org/issue/7399.
    	return syscall.EINVAL
    }
    
    func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
    	// See golang.org/issue/7399.
    	return syscall.EINVAL
    }
    
    func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
    	// See golang.org/issue/7399.
    	return syscall.EINVAL
    }
    
    func setIPv6MulticastLoopback(fd *netFD, v bool) error {
    	// See golang.org/issue/7399.
    	return syscall.EINVAL
    }
    
    func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
    	// See golang.org/issue/7399.
    	return syscall.EINVAL
    }
    
  4. src/pkg/syscall/syscall_solaris.go:
    --- a/src/pkg/syscall/syscall_solaris.go
    +++ b/src/pkg/syscall/syscall_solaris.go
    @@ -15,14 +15,13 @@ package syscall
     import "unsafe"
     
     type SockaddrDatalink struct {
    -	Len    uint8
    -	Family uint8
    +	Family uint16
     	Index  uint16
     	Type   uint8
     	Nlen   uint8
     	Alen   uint8
     	Slen   uint8
    -	Data   [46]int8
    +	Data   [244]int8
     	raw    RawSockaddrDatalink
     }
     
    @@ -77,12 +76,6 @@ func Pipe(p []int) (err error) {
     	return
     }
     
    -type IPMreqn struct {
    -	Multiaddr [4]byte /* in_addr */
    -	Address   [4]byte /* in_addr */
    -	Ifindex   int32
    -}
    -
     func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
     	if sa.Port < 0 || sa.Port > 0xFFFF {
     		return nil, 0, EINVAL
    @@ -145,21 +138,6 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
     	return anyToSockaddr(&rsa)
     }
     
    -func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
    -	vallen := _Socklen(4)
    -	err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
    -	return value, err
    -}
    -
    -func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
    -	// TODO(dfc)
    -	return nil, EINVAL
    -}
    -
    -func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
    -	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
    -}
    -
     // The const provides a compile-time constant so clients
     // can adjust to whether there is a working Getwd and avoid
     // even linking this function into the binary.  See ../os/getwd.go.
    

コアとなるコードの解説

src/pkg/net/sockoptip_bsd.go および src/pkg/net/sockoptip_posix.go の変更

これらのファイルからsolarisビルドタグが削除されたことにより、Solaris環境ではこれらのファイルで定義されている汎用的なソケットオプション設定ロジックがコンパイルされなくなりました。これは、SolarisのネットワークAPIが他のBSD系やPOSIX系OSと異なるため、共通のコードパスで処理することが適切ではないと判断されたためです。これにより、Solaris固有の挙動を新しいファイルで定義するための準備が整いました。

src/pkg/net/sockoptip_stub.go の新規追加

このファイルは、Solaris環境でのみコンパイルされるように+build solarisタグが付けられています。 ファイル内で定義されているsetIPv4MulticastInterfacesetIPv4MulticastLoopbackjoinIPv4GroupsetIPv6MulticastInterfacesetIPv6MulticastLoopbackjoinIPv6Groupといった関数は、いずれもsyscall.EINVALエラーを返します。 これは、Solarisがstruct ip_mreqnのようなGoのnetパッケージが期待する構造体やAPIをサポートしていないため、Goのマルチキャスト関連の機能がSolarisでは利用できないことを明示的に示しています。EINVALを返すことで、アプリケーション開発者はSolaris上でこれらの機能を使用しようとした際に、それがサポートされていないことを明確に認識できます。これは、未実装の機能を呼び出した際に予期せぬクラッシュや誤動作を防ぐための堅牢な設計パターンです。

src/pkg/syscall/syscall_solaris.go の変更

  1. SockaddrDatalink 構造体の修正:

    • Len uint8フィールドの削除: Solarisのsockaddr_dl構造体には、通常、構造体自体の長さを表すフィールドは含まれていません。Goの内部的な整合性や、SolarisのカーネルAPIとの正確なマッピングのために削除されました。
    • Family uint8からFamily uint16への変更: アドレスファミリー(例: AF_LINK)を表すFamilyフィールドの型がuint8からuint16に変更されました。これは、Solarisのシステムコールが期待する型に合わせるための修正であり、これにより正しい値が渡されるようになります。
    • Data [46]int8からData [244]int8への変更: SockaddrDatalink構造体は、データリンク層のアドレス情報(MACアドレス、インターフェース名など)を格納するための可変長データを保持します。Solarisのsockaddr_dl構造体が、他のOSと比較してより大きなデータ領域を必要とするため、Dataフィールドの配列サイズが大幅に拡張されました。これにより、Solarisのデータリンク層アドレスを正確に表現できるようになります。
  2. IPMreqn 構造体および関連関数の削除:

    • IPMreqn構造体は、Linuxなどで使用されるstruct ip_mreqnに対応するものでしたが、Solarisではこの構造体が存在しないため、syscall_solaris.goから削除されました。
    • これに伴い、GetsockoptInet4AddrGetsockoptIPMreqnSetsockoptIPMreqnといった、IPMreqn構造体を引数に取る、あるいは返す関数も削除されました。これらの関数はSolarisのAPIとは互換性がなく、存在しても機能しないため、コードベースから取り除かれました。

これらの変更は、GoのsyscallパッケージがSolarisの低レベルなネットワークAPIとより正確に一致するようにするための重要なステップです。これにより、Solaris上でのGoプログラムのネットワーク関連の安定性と互換性が向上します。

関連リンク

参考にした情報源リンク