[インデックス 15180] ファイルの概要
このコミットは、Go言語のnet
パッケージにおけるunixgram
(Unixドメインデータグラムソケット)の誤った挙動を修正するものです。具体的には、AF_UNIX
ドメインでSOCK_DGRAM
タイプのソケットがlisten
システムコールと連携できないというOSレベルの制約に対応し、ListenUnix
関数からunixgram
のサポートを削除しています。これにより、net
パッケージが提供するAPIと基盤となるOSのソケット挙動との整合性が保たれます。
コミット
commit a0430dae0482f2e9fc90255a568047be78129f13
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Sat Feb 9 08:18:32 2013 +0900
net: fix unixgram
The socket for AF_UNIX domain with SOCK_DGARM type isn't
allowed to work with syscall listen.
R=rsc
CC=golang-dev
https://golang.org/cl/7310068
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a0430dae0482f2e9fc90252a568047be78129f13
元コミット内容
net: fix unixgram
AF_UNIX
ドメインでSOCK_DGRAM
タイプのソケットは、listen
システムコールと連携することが許可されていません。
変更の背景
この変更の背景には、Unixドメインソケットの基本的な動作原理と、特定のソケットタイプがサポートする操作に関するOSレベルの制約があります。
Unixドメインソケットには主に2つのタイプがあります。
- ストリームソケット (SOCK_STREAM): TCPソケットに似ており、信頼性のある接続指向のデータ転送を提供します。サーバーは
listen
システムコールを使用して接続を待ち受け、クライアントからの接続を受け入れます。 - データグラムソケット (SOCK_DGRAM): UDPソケットに似ており、コネクションレスで信頼性のないデータグラム転送を提供します。データグラムソケットは通常、
sendto
やrecvfrom
といった関数で直接データを送受信し、接続を確立するためのlisten
操作は行いません。
コミットメッセージが示唆するように、AF_UNIX
ドメインのSOCK_DGRAM
ソケット(Goのnet
パッケージではunixgram
として扱われる)は、OSの設計上、listen
システムコールを呼び出すことができません。listen
は接続指向のソケット(SOCK_STREAM
)が接続要求をキューに入れるために使用されるものであり、データグラムソケットにはその概念がありません。
Goのnet
パッケージは、様々なネットワークプロトコルとソケットタイプを抽象化して統一的なAPIを提供していますが、その実装は基盤となるOSのシステムコールに依存しています。このコミット以前は、net
パッケージのListenUnix
関数が誤ってunixgram
ネットワークタイプをサポートしていると宣言しており、これによりユーザーがunixgram
ソケットでlisten
を試みると、OSレベルでエラーが発生する可能性がありました。この修正は、GoのAPIがOSの制約を正しく反映するようにするためのものです。
前提知識の解説
Unixドメインソケット (Unix Domain Sockets, UDS)
Unixドメインソケットは、同じホスト上のプロセス間通信 (IPC) のためのメカニズムです。ネットワークソケット(TCP/IPなど)とは異なり、UDSはファイルシステムパス(例: /tmp/mysocket
)に関連付けられ、ネットワークスタックを介さずに直接カーネル内で通信が行われるため、TCP/IPソケットよりも高速でオーバーヘッドが少ないという利点があります。
UDSには、ネットワークソケットと同様に、ストリーム型とデータグラム型の2種類があります。
- ストリーム型 (SOCK_STREAM): 信頼性があり、順序付けされた、接続指向のバイトストリームを提供します。TCPに似ています。
- データグラム型 (SOCK_DGRAM): コネクションレスで、信頼性のないデータグラムを提供します。UDPに似ています。各メッセージは独立したパケットとして送信されます。
listen
システムコール
listen
システムコールは、ソケットが着信接続を受け入れる準備ができていることをマークするために使用されます。これは通常、サーバーアプリケーションがクライアントからの接続を待ち受ける際に、bind
(ソケットにアドレスを割り当てる)とaccept
(接続を受け入れる)の間に呼び出されます。listen
は接続指向のソケット(SOCK_STREAM
)にのみ適用され、データグラムソケット(SOCK_DGRAM
)には適用されません。データグラムソケットは接続の概念を持たないため、listen
を呼び出すことはできません。
Go言語の net
パッケージ
Go言語の標準ライブラリnet
パッケージは、ネットワークI/Oのプリミティブを提供します。TCP/IP、UDP、Unixドメインソケットなど、様々なネットワークプロトコルを扱うためのインターフェースが含まれています。
net.Dial
: ネットワーク接続を確立します。net.Listen
: ネットワークアドレスで着信接続を待ち受けます。net.UnixConn
: Unixドメインソケット接続を表します。net.UnixListener
: Unixドメインソケットのリスナーを表します。
技術的詳細
このコミットの技術的詳細は、Unixドメインデータグラムソケット(unixgram
)がlisten
システムコールをサポートしないというOSの制約に起因します。
-
SOCK_DGRAM
とlisten
の非互換性: データグラムソケットは、メッセージの送受信に特化しており、接続の概念を持ちません。そのため、接続を待ち受けるためのlisten
システムコールは、データグラムソケットに対しては意味をなさず、通常はEOPNOTSUPP
(Operation not supported)のようなエラーを返します。 -
Goの
net
パッケージの抽象化とOSの制約: Goのnet
パッケージは、異なるOSやソケットタイプ間の差異を吸収し、統一されたAPIを提供しようとします。しかし、基盤となるOSの制約を完全に無視することはできません。この場合、net.ListenUnix
関数がunixgram
をサポートすると宣言していたことが問題でした。これは、GoのAPIがOSの実際の挙動と乖離していたことを意味します。 -
修正のロジック: コミットは、この乖離を修正するために、
ListenUnix
関数がunixgram
ネットワークタイプを受け入れないように変更しています。これにより、ユーザーがunixgram
でlisten
を試みることを防ぎ、実行時エラーを未然に防ぎます。src/pkg/net/dial.go
:resolveAddr
関数のコメントからunixgram
がListen
可能なネットワークタイプとして誤って記載されていた部分を削除。これはドキュメントの修正です。src/pkg/net/unixsock_plan9.go
およびsrc/pkg/net/unixsock_posix.go
:ListenUnix
関数の実装において、net
引数のswitch
文から"unixgram"
ケースを削除。これにより、ListenUnix
が"unixgram"
を受け取った場合にUnknownNetworkError
を返すようになります。
この修正により、Goのnet
パッケージは、Unixドメインデータグラムソケットの正しい使用法(listen
ではなく直接送受信)を強制し、開発者がOSの制約に起因する予期せぬエラーに遭遇するのを防ぎます。
コアとなるコードの変更箇所
このコミットでは、以下の3つのファイルが変更されています。
-
src/pkg/net/dial.go
resolveAddr
関数のコメントから、ListenUnix
がサポートするネットワークタイプとして"unixgram"
が削除されました。これはドキュメントの修正です。
--- a/src/pkg/net/dial.go +++ b/src/pkg/net/dial.go @@ -54,7 +54,8 @@ func resolveAddr(op, net, addr string, deadline time.Time) (Addr, error) { // // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), // "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4" -// (IPv4-only), "ip6" (IPv6-only), "unix" and "unixpacket". +// (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and +// "unixpacket". // // For TCP and UDP networks, addresses have the form host:port. // If host is a literal IPv6 address, it must be enclosed
注: 上記のdiffは、変更前のコードが
unixgram
を含んでいたことを示しており、変更によってunixgram
が削除されたことを意味します。元のコミットメッセージのdiff表示と実際の変更内容が逆になっているように見えますが、これはdial.go
のコメントがunixgram
をListen
可能なネットワークとして誤ってリストしていたのを修正したものです。つまり、unixgram
をリストから削除する変更です。 -
src/pkg/net/unixsock_plan9.go
ListenUnix
関数のコメントから、"unixgram"
がサポートされるネットワークタイプとして削除されました。ListenUnix
の実装自体は、Plan 9ではsyscall.EPLAN9
を返すため、具体的なswitch
文の変更はありませんが、コメントの修正が重要です。
--- a/src/pkg/net/unixsock_plan9.go +++ b/src/pkg/net/unixsock_plan9.go @@ -93,8 +93,7 @@ func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn type UnixListener struct{} // ListenUnix announces on the Unix domain socket laddr and returns a -// Unix listener. The network net must be "unix", "unixgram" or -// "unixpacket". +// Unix listener. The network net must be "unix" or "unixpacket". func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { return nil, syscall.EPLAN9 }
-
src/pkg/net/unixsock_posix.go
ListenUnix
関数のコメントから、"unixgram"
がサポートされるネットワークタイプとして削除されました。ListenUnix
の実装内のswitch net
文から"unixgram"
ケースが削除されました。これにより、"unixgram"
が渡された場合にUnknownNetworkError
が返されるようになります。
--- a/src/pkg/net/unixsock_posix.go +++ b/src/pkg/net/unixsock_posix.go @@ -251,11 +251,10 @@ type UnixListener struct { } // ListenUnix announces on the Unix domain socket laddr and returns a -// Unix listener. The network net must be "unix", "unixgram" or -// "unixpacket". +// Unix listener. The network net must be "unix" or "unixpacket". func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { switch net { -\tcase "unix", "unixgram", "unixpacket": +\tcase "unix", "unixpacket": default: return nil, UnknownNetworkError(net) }
コアとなるコードの解説
このコミットの核心は、net
パッケージのListenUnix
関数が、Unixドメインデータグラムソケット(unixgram
)に対してlisten
操作を許可しないように変更された点です。
ListenUnix
関数は、指定されたネットワークタイプ(net
引数)とローカルアドレス(laddr
引数)に基づいてUnixドメインソケットのリスナーを作成します。変更前は、この関数が"unixgram"
タイプも有効なネットワークとして受け入れていました。しかし、前述の通り、データグラムソケットはlisten
システムコールをサポートしません。
src/pkg/net/unixsock_posix.go
の変更が最も重要です。このファイルはPOSIX準拠システム(Linux, macOSなど)におけるUnixソケットの実装を含んでいます。
func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
switch net {
case "unix", "unixpacket": // 変更点: "unixgram" が削除された
default:
return nil, UnknownNetworkError(net)
}
// ... 以降のリスナー作成ロジック
}
このswitch
文は、ListenUnix
関数がサポートするネットワークタイプをチェックしています。変更前は"unix", "unixgram", "unixpacket"
の3つを許可していましたが、このコミットにより"unixgram"
が削除されました。
これにより、ユーザーがListenUnix("unixgram", ...)
を呼び出すと、default
ケースにフォールバックし、UnknownNetworkError
が返されるようになります。これは、unixgram
ソケットでlisten
を試みることがOSレベルで無効であるという事実を、GoのAPIレベルで強制するものです。
src/pkg/net/dial.go
とsrc/pkg/net/unixsock_plan9.go
におけるコメントの修正は、このAPIの変更をドキュメントに反映させるためのものです。特にdial.go
のコメントは、net
パッケージが認識するネットワークタイプの一覧を更新し、unixgram
がListen
操作には適さないことを明確にしています。
この修正は、Goのnet
パッケージの堅牢性を高め、開発者がOSのソケットプログラミングの基本的な制約を誤解することなく、正しい方法でUnixドメインソケットを扱えるようにするために不可欠です。
関連リンク
- Go CL 7310068: https://golang.org/cl/7310068
参考にした情報源リンク
- Unix Domain Sockets (man7.org): https://man7.org/linux/man-pages/man7/unix.7.html
- listen(2) - Linux man page: https://man7.org/linux/man-pages/man2/listen.2.html
- Go net package documentation: https://pkg.go.dev/net
- Stack Overflow: Why can't I listen on a UDP socket?: https://stackoverflow.com/questions/1074006/why-cant-i-listen-on-a-udp-socket (UDPソケットと
listen
の関係は、データグラムソケット全般に適用される概念です。)