[インデックス 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.goresolveAddr関数のコメントから、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.goListenUnix関数のコメントから、"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.goListenUnix関数のコメントから、"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の関係は、データグラムソケット全般に適用される概念です。)