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

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

このコミットは、Go言語の syscall パッケージにおけるソケットオプション関連の関数を、Unix系システム全体で統合し、簡素化することを目的としています。具体的には、プラットフォーム固有のファイル(syscall_bsd.gosyscall_linux.go)に分散していた Getsockopt* 関数群を syscall_unix.go に集約し、APIの統一とコードの重複排除を図っています。また、Getsockopt* および Setsockopt* 関数の戻り値の型をGoの慣習に沿って簡素化し、Solarisを含むUnix系システムでの共通ソケットオプション関数の利用を促進しています。

コミット

syscall: consolidate, simplify socket options for Unix-like systems

Also exposes common socket option functions on Solaris.

Update #7174
Update #7175

LGTM=aram
R=golang-codereviews, aram
CC=golang-codereviews
https://golang.org/cl/107280044

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

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

元コミット内容

commit e3e48cd075091d8f0e1265ae6a18e69ac83d2af4
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Mon Jun 23 18:46:01 2014 +0900

    syscall: consolidate, simplify socket options for Unix-like systems
    
    Also exposes common socket option functions on Solaris.
    
    Update #7174
    Update #7175
    
    LGTM=aram
    R=golang-codereviews, aram
    CC=golang-codereviews
    https://golang.org/cl/107280044
---
 src/pkg/syscall/syscall_bsd.go   | 42 -----------------------
 src/pkg/syscall/syscall_linux.go | 34 ------------------
 src/pkg/syscall/syscall_unix.go  | 74 +++++++++++++++++++++++++++++++---------
 3 files changed, 58 insertions(+), 92 deletions(-)

diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index af563910b1..c569b1900b 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -309,48 +309,6 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
 }\n \n //sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)\n-\n-func GetsockoptByte(fd, level, opt int) (value byte, err error) {\n-\tvar n byte\n-\tvallen := _Socklen(1)\n-\terr = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)\n-\treturn n, err\n-}\n-\n-func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {\n-\tvallen := _Socklen(4)\n-\terr = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)\n-\treturn value, err\n-}\n-\n-func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {\n-\tvar value IPMreq\n-\tvallen := _Socklen(SizeofIPMreq)\n-\terr := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)\n-\treturn &value, err\n-}\n-\n-func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {\n-\tvar value IPv6Mreq\n-\tvallen := _Socklen(SizeofIPv6Mreq)\n-\terr = getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)\n-\treturn &value, err\n-}\n-\n-func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {\n-\tvar value IPv6MTUInfo\n-\tvallen := _Socklen(SizeofIPv6MTUInfo)\n-\terr = getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)\n-\treturn &value, err\n-}\n-\n-func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {\n-\tvar value ICMPv6Filter\n-\tvallen := _Socklen(SizeofICMPv6Filter)\n-\terr = getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)\n-\treturn &value, err\n-}\n-\n //sys   recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)\n //sys   sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)\n //sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error)\ndiff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index fa0d7ea3c7..cdba97d2e7 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -440,19 +440,6 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
 	return anyToSockaddr(&rsa)\n }\n \n-func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {\n-\tvallen := _Socklen(4)\n-\terr = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)\n-\treturn value, err\n-}\n-\n-func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {\n-\tvar value IPMreq\n-\tvallen := _Socklen(SizeofIPMreq)\n-\terr = getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)\n-\treturn &value, err\n-}\n-\n func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {\n \tvar value IPMreqn\n \tvallen := _Socklen(SizeofIPMreqn)\n@@ -460,27 +447,6 @@ func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {\n \treturn &value, err\n }\n \n-func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {\n-\tvar value IPv6Mreq\n-\tvallen := _Socklen(SizeofIPv6Mreq)\n-\terr = getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)\n-\treturn &value, err\n-}\n-\n-func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {\n-\tvar value IPv6MTUInfo\n-\tvallen := _Socklen(SizeofIPv6MTUInfo)\n-\terr = getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)\n-\treturn &value, err\n-}\n-\n-func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {\n-\tvar value ICMPv6Filter\n-\tvallen := _Socklen(SizeofICMPv6Filter)\n-\terr = getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)\n-\treturn &value, err\n-}\n-\n func GetsockoptUcred(fd, level, opt int) (*Ucred, error) {\n \tvar value Ucred\n \tvallen := _Socklen(SizeofUcred)\ndiff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go
index b28891568d..699a8fd120 100644
--- a/src/pkg/syscall/syscall_unix.go
+++ b/src/pkg/syscall/syscall_unix.go
@@ -207,13 +207,6 @@ func Getpeername(fd int) (sa Sockaddr, err error) {\n \treturn anyToSockaddr(&rsa)\n }\n \n-func GetsockoptInt(fd, level, opt int) (value int, err error) {\n-\tvar n int32\n-\tvallen := _Socklen(4)\n-\terr = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)\n-\treturn int(n), err\n-}\n-\n func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {\n \tvar rsa RawSockaddrAny\n \tvar len _Socklen = SizeofSockaddrAny\n@@ -234,24 +227,73 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {\n \treturn sendto(fd, p, flags, ptr, n)\n }\n \n-func SetsockoptByte(fd, level, opt int, value byte) (err error) {\n+func GetsockoptByte(fd, level, opt int) (byte, error) {\n+\tvar v byte\n+\tl := _Socklen(1)\n+\terr := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)\n+\treturn v, err\n+}\n+\n+func GetsockoptInt(fd, level, opt int) (int, error) {\n+\tvar v int32\n+\tl := _Socklen(4)\n+\terr := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)\n+\treturn int(v), err\n+}\n+\n+func GetsockoptInet4Addr(fd, level, opt int) ([4]byte, error) {\n+\tvar v [4]byte\n+\tl := _Socklen(4)\n+\terr := getsockopt(fd, level, opt, unsafe.Pointer(&v[0]), &l)\n+\treturn v, err\n+}\n+\n+func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {\n+\tvar v IPMreq\n+\tl := _Socklen(SizeofIPMreq)\n+\terr := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)\n+\treturn &v, err\n+}\n+\n+func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {\n+\tvar v IPv6Mreq\n+\tl := _Socklen(SizeofIPv6Mreq)\n+\terr := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)\n+\treturn &v, err\n+}\n+\n+func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {\n+\tvar v IPv6MTUInfo\n+\tl := _Socklen(SizeofIPv6MTUInfo)\n+\terr := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)\n+\treturn &v, err\n+}\n+\n+func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {\n+\tvar v ICMPv6Filter\n+\tl := _Socklen(SizeofICMPv6Filter)\n+\terr := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)\n+\treturn &v, err\n+}\n+\n+func SetsockoptByte(fd, level, opt int, value byte) error {\n \treturn setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)\n }\n \n-func SetsockoptInt(fd, level, opt int, value int) (err error) {\n-\tvar n = int32(value)\n+func SetsockoptInt(fd, level, opt int, value int) error {\n+\tn := int32(value)\n \treturn setsockopt(fd, level, opt, unsafe.Pointer(&n), 4)\n }\n \n-func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (err error) {\n+func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) error {\n \treturn setsockopt(fd, level, opt, unsafe.Pointer(&value[0]), 4)\n }\n \n-func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {\n+func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) error {\n \treturn setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPMreq)\n }\n \n-func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {\n+func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) error {\n \treturn setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPv6Mreq)\n }\n \n@@ -259,15 +301,15 @@ func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error {\n \treturn setsockopt(fd, level, opt, unsafe.Pointer(filter), SizeofICMPv6Filter)\n }\n \n-func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {\n+func SetsockoptLinger(fd, level, opt int, l *Linger) error {\n \treturn setsockopt(fd, level, opt, unsafe.Pointer(l), SizeofLinger)\n }\n \n-func SetsockoptString(fd, level, opt int, s string) (err error) {\n+func SetsockoptString(fd, level, opt int, s string) error {\n \treturn setsockopt(fd, level, opt, unsafe.Pointer(&[]byte(s)[0]), uintptr(len(s)))\n }\n \n-func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {\n+func SetsockoptTimeval(fd, level, opt int, tv *Timeval) error {\n \treturn setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv))\n }\n \n```

## 変更の背景

このコミットの主な背景は、Go言語の `syscall` パッケージにおけるソケットオプション関連のコードの重複を解消し、APIの一貫性と保守性を向上させることにあります。

Goの `syscall` パッケージは、OSのシステムコールをGoプログラムから直接呼び出すための低レベルなインターフェースを提供します。ソケットオプションの取得(`getsockopt`)と設定(`setsockopt`)は、ネットワークプログラミングにおいて非常に頻繁に利用される機能ですが、Goの初期の実装では、これらの関数が各Unix系OS(BSD、Linuxなど)のプラットフォーム固有のファイルに個別に定義されていました。

これにより、以下のような問題が生じていました。

1.  **コードの重複**: 多くの `Getsockopt*` 関数が、異なるプラットフォーム間でほぼ同じロジックを持ちながら、それぞれのファイルにコピーされていました。これはコードの肥大化と保守の複雑化を招きます。
2.  **APIの不統一**: 各プラットフォームで同じ機能を提供する関数であっても、定義されているファイルが異なるため、開発者が一貫した方法でソケットオプションを扱うことが困難になる可能性がありました。
3.  **Solarisサポートの不足**: コミットメッセージに「Also exposes common socket option functions on Solaris」とあるように、Solaris環境ではこれらの共通ソケットオプション関数が十分に利用できていなかった可能性があります。

このコミットは、これらの問題を解決するために、共通のソケットオプション関数を `syscall_unix.go` という共通のファイルに集約し、プラットフォーム固有のファイルからはそれらを削除することで、コードベースを整理し、より簡潔で一貫性のあるAPIを提供することを目指しました。また、`Getsockopt*` および `Setsockopt*` 関数の戻り値の型をGoの慣習に合わせた形に簡素化することで、APIの使いやすさも向上させています。

コミットメッセージに記載されている `#7174` と `#7175` というIssueは、この変更に関連する具体的な課題や改善要求を示唆していますが、GoのIssueトラッカーのシステム変更などにより、直接的な参照は困難でした。しかし、コードレビューのタイトルから、ソケットオプションの統合と簡素化が主要な目的であったことが確認できます。

## 前提知識の解説

このコミットの変更内容を理解するためには、以下の前提知識が役立ちます。

### 1. Go言語の `syscall` パッケージ

`syscall` パッケージは、Goプログラムからオペレーティングシステム(OS)のシステムコールを直接呼び出すための低レベルなインターフェースを提供します。これにより、ファイル操作、ネットワーク通信、プロセス管理など、OSが提供する基本的な機能にアクセスできます。通常、Goの標準ライブラリはより高レベルな抽象化を提供しますが、`syscall` パッケージは、OS固有の機能やパフォーマンスが重要な場面で利用されます。

### 2. ソケットオプション (`getsockopt`, `setsockopt`)

ネットワークプログラミングにおいて、ソケットはネットワーク通信のエンドポイントです。ソケットの挙動は、様々な「ソケットオプション」によって制御されます。
*   **`getsockopt`**: ソケットの現在のオプション設定を取得するためのシステムコールです。例えば、ソケットの送受信バッファサイズ、タイムアウト設定、再利用設定などを取得できます。
*   **`setsockopt`**: ソケットのオプション設定を変更するためのシステムコールです。例えば、ソケットをブロードキャストモードにする、キープアライブを有効にする、TCP_NODELAYを設定するなど、ソケットの動作を細かく調整するために使用されます。

これらのシステムコールは、通常、ファイルディスクリプタ(ソケットを識別する整数値)、オプションのレベル(例: `SOL_SOCKET` はソケットレベルのオプション、`IPPROTO_TCP` はTCPプロトコルレベルのオプション)、オプション名(例: `SO_REUSEADDR` はアドレス再利用を許可するオプション)、そしてオプションの値へのポインタとそのサイズを引数に取ります。

### 3. Unix系システム

Unix系システムとは、Unixオペレーティングシステムの設計思想や機能セットを共有するOSの総称です。これには、Linux、BSD(FreeBSD、OpenBSD、NetBSDなど)、Solaris、macOSなどが含まれます。これらのシステムは、多くの場合、共通のシステムコールインターフェース(POSIX標準など)を共有しており、`getsockopt` や `setsockopt` のような基本的なネットワークシステムコールも同様の振る舞いをします。しかし、細部の実装や利用可能なオプション、構造体の定義などが異なる場合があります。

### 4. `unsafe.Pointer`

Go言語は通常、厳格な型安全性を提供しますが、`unsafe` パッケージは、その型安全性をバイパスする機能を提供します。`unsafe.Pointer` は、任意の型のポインタを保持できる特殊なポインタ型です。これは、Goのメモリモデルを直接操作したり、C言語のライブラリやシステムコールと連携したりする際に必要となることがあります。`getsockopt` や `setsockopt` のようなシステムコールは、C言語のインターフェースを模倣しているため、Goの構造体や変数のアドレスを `unsafe.Pointer` を介して渡すことで、OSのAPIが期待する形式に合わせます。

### 5. `_Socklen`

`_Socklen` は、ソケットオプションのサイズやアドレス構造体の長さを表すために使用される型です。これは、`getsockopt` や `setsockopt` システムコールに渡される引数の一つで、オプションの値が格納されるバッファのサイズを示します。

### 6. ネットワーク関連の構造体

コミットで変更されている関数名や削除されているコードから、以下のようなネットワーク関連の構造体がソケットオプションとして扱われていることがわかります。

*   **`IPMreq` (IP Multicast Request)**: IPマルチキャストグループに参加または脱退するための構造体。
*   **`IPv6Mreq` (IPv6 Multicast Request)**: IPv6マルチキャストグループに参加または脱退するための構造体。
*   **`IPv6MTUInfo` (IPv6 Maximum Transmission Unit Information)**: IPv6のパスMTU(最大転送単位)に関する情報を含む構造体。
*   **`ICMPv6Filter` (ICMPv6 Filter)**: ICMPv6メッセージのフィルタリングルールを設定するための構造体。
*   **`Linger`**: ソケットのクローズ時の挙動(未送信データの扱いなど)を制御するための構造体。
*   **`Timeval`**: 時間値を表す構造体で、ソケットのタイムアウト設定などに使用されます。

これらの構造体は、特定のソケットオプションの値を表現するために使用され、`getsockopt` や `setsockopt` を通じてOSとやり取りされます。

## 技術的詳細

このコミットにおける技術的な変更は、主に以下の3つの側面に集約されます。

### 1. ソケットオプション関数の統合とコードの重複排除

最も顕著な変更は、`Getsockopt*` 関数群の定義場所の変更です。変更前は、`GetsockoptByte`, `GetsockoptInet4Addr`, `GetsockoptIPMreq` など、様々な型のソケットオプションを取得する関数が、`src/pkg/syscall/syscall_bsd.go` と `src/pkg/syscall/syscall_linux.go` の両方に個別に存在していました。これらの関数は、内部的にはほとんど同じ `getsockopt` システムコールを呼び出し、戻り値の型と `unsafe.Pointer` を介して渡すデータのサイズが異なるだけでした。

このコミットでは、これらの重複する定義を削除し、`src/pkg/syscall/syscall_unix.go` に一元化しました。`syscall_unix.go` は、Unix系OS全般に共通するシステムコールやユーティリティ関数を定義するファイルであり、ここに集約することで、コードの重複を大幅に削減し、保守性を向上させています。これにより、将来的に新しいUnix系OSをサポートする際や、既存のソケットオプション関数に修正を加える際に、複数のファイルを変更する必要がなくなります。

### 2. APIの簡素化とGoの慣習への適合

`Getsockopt*` および `Setsockopt*` 関数の戻り値の型が簡素化されました。

**変更前(例: `GetsockoptByte`):**
```go
func GetsockoptByte(fd, level, opt int) (value byte, err error) {
	var n byte
	vallen := _Socklen(1)
	err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
	return n, err
}

この形式では、戻り値として value byteerr error を明示的に名前付きで宣言し、関数内で n に値を代入してから return n, err としています。

変更後(例: GetsockoptByte):

func GetsockoptByte(fd, level, opt int) (byte, error) {
	var v byte
	l := _Socklen(1)
	err := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)
	return v, err
}

変更後では、戻り値の型を (byte, error) のように直接指定し、関数内で v に値を代入した後、return v, err としています。これはGo言語における一般的な関数の戻り値の書き方であり、コードの可読性を向上させ、よりGoらしい(idiomatic Go)コードになっています。

同様に、Setsockopt* 関数も (err error) から error へと戻り値の型が簡素化されています。

変更前(例: SetsockoptByte):

func SetsockoptByte(fd, level, opt int, value byte) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)
}

変更後(例: SetsockoptByte):

func SetsockoptByte(fd, level, opt int, value byte) error {
	return setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)
}

これもまた、Goの慣習に沿った簡潔な記述です。

3. Solaris環境での共通ソケットオプション関数の公開

コミットメッセージに「Also exposes common socket option functions on Solaris.」とあるように、この変更はSolaris環境においても、統合された共通のソケットオプション関数が利用可能になることを意味します。syscall_unix.go に関数が集約されたことで、Solarisを含むすべてのUnix系システムが、これらの共通APIを利用できるようになり、プラットフォーム間の互換性が向上します。これは、Goがより多くのプラットフォームで一貫した動作を提供するための重要なステップです。

unsafe.Pointer の継続的な利用

これらの変更後も、getsockopt および setsockopt システムコールを呼び出す際には、引き続き unsafe.Pointer が使用されています。これは、Goの型システムとC言語ベースのシステムコールインターフェースとの間の橋渡しをするために不可欠です。unsafe.Pointer を使用することで、Goの変数や構造体のアドレスを、システムコールが期待する汎用ポインタとして渡すことが可能になります。このコミットは unsafe.Pointer の利用方法を変更するものではなく、その利用を前提としたAPIの整理と簡素化を行っています。

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

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

  1. src/pkg/syscall/syscall_bsd.go:

    • GetsockoptByte
    • GetsockoptInet4Addr
    • GetsockoptIPMreq
    • GetsockoptIPv6Mreq
    • GetsockoptIPv6MTUInfo
    • GetsockoptICMPv6Filter 上記の Getsockopt* 関数がすべて削除されています。
  2. src/pkg/syscall/syscall_linux.go:

    • GetsockoptInet4Addr
    • GetsockoptIPMreq
    • GetsockoptIPv6Mreq
    • GetsockoptIPv6MTUInfo
    • GetsockoptICMPv6Filter 上記の Getsockopt* 関数がすべて削除されています。
  3. src/pkg/syscall/syscall_unix.go:

    • 既存の GetsockoptInt 関数が削除され、新しい形式で再追加されています。
    • syscall_bsd.gosyscall_linux.go から削除されたすべての Getsockopt* 関数(GetsockoptByte, GetsockoptInet4Addr, GetsockoptIPMreq, GetsockoptIPv6Mreq, GetsockoptIPv6MTUInfo, GetsockoptICMPv6Filter)が、新しい簡素化された戻り値の型で追加されています。
    • 既存の Setsockopt* 関数群(SetsockoptByte, SetsockoptInt, SetsockoptInet4Addr, SetsockoptIPMreq, SetsockoptIPv6Mreq, SetsockoptICMPv6Filter, SetsockoptLinger, SetsockoptString, SetsockoptTimeval)の戻り値の型が (err error) から error へと変更されています。

コアとなるコードの解説

ここでは、変更されたコードの具体的な例を挙げて、その意味を解説します。

Getsockopt* 関数の統合と戻り値の簡素化

syscall_bsd.go および syscall_linux.go から削除され、syscall_unix.go に統合された GetsockoptByte 関数を例に取ります。

変更前(syscall_bsd.go または syscall_linux.go に存在):

func GetsockoptByte(fd, level, opt int) (value byte, err error) {
	var n byte
	vallen := _Socklen(1)
	err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
	return n, err
}

このコードでは、value byte, err error という名前付き戻り値が宣言されており、関数内で n という変数に結果を格納し、最後に return n, err で返しています。

変更後(syscall_unix.go に存在):

func GetsockoptByte(fd, level, opt int) (byte, error) {
	var v byte
	l := _Socklen(1)
	err := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)
	return v, err
}

変更後では、戻り値の型が (byte, error) と直接指定されています。関数内で v という変数を宣言し、そこに結果を格納した後、return v, err で返します。この形式は、Go言語の関数で複数の戻り値を返す際の一般的な慣習であり、コードがより簡潔で読みやすくなります。valuen といった一時的な変数名を明示的に戻り値として宣言する必要がなくなります。

同様に、GetsockoptInt も変更されています。

変更前(syscall_unix.go に存在):

func GetsockoptInt(fd, level, opt int) (value int, err error) {
	var n int32
	vallen := _Socklen(4)
	err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
	return int(n), err
}

変更後(syscall_unix.go に存在):

func GetsockoptInt(fd, level, opt int) (int, error) {
	var v int32
	l := _Socklen(4)
	err := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)
	return int(v), err
}

ここでも、value int, err error から (int, error) への変更と、内部変数名の変更が行われています。

Setsockopt* 関数の戻り値の簡素化

Setsockopt* 関数も同様に、戻り値の型が簡素化されています。

変更前(例: SetsockoptByte):

func SetsockoptByte(fd, level, opt int, value byte) (err error) {
	return setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)
}

この関数は、err error という名前付き戻り値を宣言していますが、関数本体では直接 setsockopt の結果を返しています。

変更後(例: SetsockoptByte):

func SetsockoptByte(fd, level, opt int, value byte) error {
	return setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)
}

変更後では、戻り値の型が error と直接指定されています。これにより、関数シグネチャがより簡潔になり、Goの慣習に沿った記述となります。

これらの変更は、機能的な振る舞いを変更するものではなく、主にコードの構造とAPIの表現を改善することを目的としています。これにより、syscall パッケージのソケットオプション関連コードがより整理され、Go言語のスタイルガイドラインに沿ったものになっています。

関連リンク

  • Go Code Review (Gerrit) リンク: このコミットの元のコードレビューページです。変更の議論や承認プロセスに関する詳細が含まれています。 https://golang.org/cl/107280044

  • Go Issue #7174: このコミットで更新されたとされるIssueの一つですが、現在のGoのIssueトラッカーでは直接参照できませんでした。

  • Go Issue #7175: このコミットで更新されたとされるIssueの一つですが、現在のGoのIssueトラッカーでは直接参照できませんでした。

参考にした情報源リンク

  • Go言語公式ドキュメント: Go言語の基本的な構文や標準ライブラリに関する公式情報源です。 https://go.dev/

  • Go syscall パッケージ ドキュメント: syscall パッケージのAPIリファレンスです。 https://pkg.go.dev/syscall

  • getsockopt および setsockopt man ページ: Unix系システムにおける getsockopt および setsockopt システムコールの詳細な説明です。 例: man 2 getsockopt (Linuxの場合)

  • Goの unsafe パッケージ ドキュメント: unsafe パッケージの利用に関する公式ドキュメントです。 https://pkg.go.dev/unsafe