[インデックス 17949] ファイルの概要
このコミットは、Go言語の標準ライブラリsrc/pkg/syscall/route_bsd.go
ファイルに対する変更です。このファイルは、BSD系のオペレーティングシステム(FreeBSD, OpenBSD, NetBSDなど)におけるネットワークルーティングメッセージの処理に関連するシステムコール(syscall
)を扱っています。具体的には、カーネルから受け取ったルーティングメッセージ(RoutingMessage
)をパース(解析)する機能を提供します。
コミット
commit 517e49eb290a454791034eb692b696c347f7d74e
Author: Joel Sing <jsing@google.com>
Date: Wed Dec 11 00:03:46 2013 +1100
syscall: skip routing messages with mismatched version
Skip routing messages with a mismatched version, rather than failing
and returning EINVAL. Only return EINVAL if we were unable to parse
any of the routing messages (presumably due to a version mismatch).
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/30340043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/517e49eb290a454791034eb692b696c347f7d74e
元コミット内容
このコミットの目的は、ルーティングメッセージをパースする際に、バージョンが一致しないメッセージを即座にEINVAL
エラーで失敗させるのではなく、スキップするように変更することです。EINVAL
エラーは、ルーティングメッセージのどれもパースできなかった場合(おそらくバージョン不一致が原因)にのみ返されるべきである、という方針転換が示されています。
変更の背景
以前の実装では、ParseRoutingMessage
関数が複数のルーティングメッセージを含むバイトスライスを受け取った際、その中の最初のメッセージのバージョンが期待されるRTM_VERSION
と一致しない場合、即座にEINVAL
(Invalid argument)エラーを返していました。これは、複数のルーティングメッセージが連結されて送られてくるシナリオにおいて、一部のメッセージが異なるバージョンを持つ場合に問題を引き起こす可能性がありました。
例えば、カーネルが異なるバージョンのルーティングメッセージを混在させて送信する、あるいは、アプリケーションが複数のルーティングメッセージを処理する際に、一部のメッセージが古い(または新しい)バージョンであるといった状況が考えられます。このような場合、以前の実装では、有効なメッセージが後続に存在しても、最初のバージョン不一致で処理が中断されてしまい、システムがルーティング情報を完全に取得できない、あるいは不必要にエラーを返すという非効率性や堅牢性の欠如がありました。
このコミットの背景には、より堅牢で柔軟なルーティングメッセージのパース処理を実現し、部分的なバージョン不一致があっても可能な限り多くの有効なメッセージを処理できるようにするという意図があります。これにより、Goアプリケーションがネットワークルーティング情報を扱う際の信頼性と互換性が向上します。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
-
システムコール (syscall): オペレーティングシステムが提供するサービスをプログラムから利用するためのインターフェースです。ファイル操作、ネットワーク通信、プロセス管理など、OSの低レベルな機能にアクセスするために使用されます。Go言語の
syscall
パッケージは、これらのOS固有の機能へのアクセスを提供します。 -
ルーティングメッセージ (Routing Messages): BSD系のUnixライクなシステム(FreeBSD, OpenBSD, NetBSDなど)では、カーネルがネットワークルーティングテーブルの変更やネットワークインターフェースの状態変化などの情報を、ユーザー空間のプロセスにルーティングメッセージとして通知します。これらのメッセージは特定の構造を持ち、ネットワークデーモン(例:
routed
,zebra
)がルーティング情報を管理するために利用します。 -
RTM_VERSION
: ルーティングメッセージのプロトコルバージョンを示す定数です。ルーティングメッセージのヘッダに含まれており、メッセージの構造や意味を解釈するために使用されます。バージョンが一致しない場合、メッセージのパース方法が異なる可能性があるため、通常は処理を中断するか、異なる方法で処理する必要があります。 -
EINVAL
: Unix系のシステムコールが返すエラーコードの一つで、「Invalid argument」(不正な引数)を意味します。関数に渡された引数が無効である場合に返されます。この文脈では、ルーティングメッセージのバージョンが不正である、あるいはメッセージ自体が破損しているといった状況で返されることが想定されます。 -
unsafe.Pointer
: Go言語のunsafe
パッケージに含まれる型で、任意の型のポインタを保持できる特殊なポインタです。Goの型安全性をバイパスして、メモリを直接操作することを可能にします。このコミットでは、バイトスライス[]byte
をルーティングメッセージの構造体anyMessage
にキャストするために使用されています。これは、バイト列を特定の構造体として解釈する際に一般的に用いられる手法ですが、Goの型システムを迂回するため、注意深く使用する必要があります。 -
バイトスライス (
[]byte
) と構造体 (struct
) の変換: ネットワークから受信したデータは通常バイト列として扱われます。これをGoのプログラムで意味のある情報として処理するためには、バイト列を定義された構造体(この場合はルーティングメッセージのヘッダやペイロードを表す構造体)に変換する必要があります。unsafe.Pointer
とunsafe.Sizeof
、unsafe.Offsetof
などの関数を組み合わせて、バイトスライスを構造体として解釈するテクニックが用いられます。
技術的詳細
変更はsrc/pkg/syscall/route_bsd.go
ファイルのParseRoutingMessage
関数に集中しています。この関数は、バイトスライスb
を受け取り、その中に含まれる複数のルーティングメッセージをパースして、[]RoutingMessage
の形で返します。
変更前は、for
ループ内で各メッセージを処理する際に、any.Version != RTM_VERSION
という条件でバージョンチェックを行い、バージョンが一致しない場合は即座にreturn nil, EINVAL
としていました。これは、メッセージストリームの途中でバージョン不一致のメッセージが見つかった場合でも、それ以降のメッセージの処理を完全に停止させてしまう挙動でした。
変更後は、この挙動が以下のように修正されました。
-
msgCount
変数の導入: パースを試みたメッセージの総数をカウントするために、msgCount
という新しい変数が導入されました。これは、ループが何回実行されたか(つまり、何個のメッセージの先頭を読み取ろうとしたか)を追跡します。 -
バージョン不一致時のスキップ:
if any.Version != RTM_VERSION
の条件が真(バージョン不一致)の場合、以前はreturn nil, EINVAL
でしたが、変更後はb = b[any.Msglen:]
とcontinue
が実行されます。b = b[any.Msglen:]
: 現在のメッセージの長さ(any.Msglen
)だけバイトスライスb
を進めます。これにより、バージョン不一致のメッセージをスキップし、次のメッセージの先頭にポインタを移動させます。continue
: ループの次のイテレーションに進み、次のメッセージのパースを試みます。 この変更により、バージョン不一致のメッセージは無視され、後続のメッセージのパースが継続されるようになります。
-
EINVAL
を返す条件の変更: ループが終了した後、つまりすべてのバイトスライスが処理された後に、EINVAL
を返す新しい条件が追加されました。// We failed to parse any of the messages - version mismatch? if msgCount > 0 && len(msgs) == 0 { return nil, EINVAL }
この条件は、以下の状況で
EINVAL
を返します。msgCount > 0
: 少なくとも1つ以上のメッセージのパースを試みた。len(msgs) == 0
: しかし、結果として有効なルーティングメッセージが1つもパースできなかった。 このロジックは、「メッセージのパースを試みたが、どれも成功しなかった(おそらく全体的なバージョン不一致やデータ破損のため)」という場合にのみEINVAL
を返すことを意味します。これにより、部分的なバージョン不一致で即座にエラーになるのではなく、本当に処理すべきメッセージが一つもなかった場合にのみエラーを返す、より堅牢な挙動が実現されます。
この変更は、ネットワークプロトコルやシステムメッセージのパースにおいて一般的な「フォールトトレランス」の考え方を導入しています。つまり、一部の不正なデータがあっても全体が失敗するのではなく、可能な限り有効なデータを抽出し、処理を継続しようとするアプローチです。
コアとなるコードの変更箇所
src/pkg/syscall/route_bsd.go
ファイルのParseRoutingMessage
関数内の以下の部分が変更されました。
--- a/src/pkg/syscall/route_bsd.go
+++ b/src/pkg/syscall/route_bsd.go
@@ -199,14 +199,21 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
// ParseRoutingMessage parses b as routing messages and returns the
// slice containing the RoutingMessage interfaces.
func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
+\tmsgCount := 0 // 追加
\tfor len(b) >= anyMessageLen {\
+\t\tmsgCount++ // 追加
\t\tany := (*anyMessage)(unsafe.Pointer(&b[0]))\
\t\tif any.Version != RTM_VERSION {\
-\t\t\treturn nil, EINVAL // 変更前: 即座にエラーを返す
+\t\t\tb = b[any.Msglen:] // 変更後: メッセージをスキップ
+\t\t\tcontinue // 変更後: 次のメッセージへ
\t\t}\
\t\tmsgs = append(msgs, any.toRoutingMessage(b))\
\t\tb = b[any.Msglen:]\
\t}\
+\t// We failed to parse any of the messages - version mismatch? // 追加
+\tif msgCount > 0 && len(msgs) == 0 { // 追加
+\t\treturn nil, EINVAL // 追加
+\t}
\treturn msgs, nil
}\
コアとなるコードの解説
ParseRoutingMessage
関数は、バイトスライスb
をルーティングメッセージのシーケンスとして解釈します。
-
msgCount := 0
: 関数冒頭でmsgCount
が0で初期化されます。これは、この関数が処理を試みたルーティングメッセージの数を追跡するためのカウンターです。 -
for len(b) >= anyMessageLen
: このループは、残りのバイトスライスb
が少なくとも1つのルーティングメッセージの最小長(anyMessageLen
)以上である限り続きます。これにより、バイトスライスが尽きるまで、または有効なメッセージの先頭が見つからなくなるまで処理が繰り返されます。 -
msgCount++
: ループの各イテレーションの開始時にmsgCount
がインクリメントされます。これは、現在処理しようとしているバイトスライスが、潜在的に新しいルーティングメッセージの開始点であることを示します。 -
any := (*anyMessage)(unsafe.Pointer(&b[0]))
:unsafe.Pointer
を使用して、現在のバイトスライスb
の先頭をanyMessage
構造体へのポインタとして解釈します。anyMessage
はルーティングメッセージの共通ヘッダ部分を表す構造体であり、バージョン情報(Version
フィールド)やメッセージ長(Msglen
フィールド)を含んでいます。 -
if any.Version != RTM_VERSION
: ここで、現在解釈しているメッセージのバージョンが、期待されるRTM_VERSION
と一致するかどうかをチェックします。- 変更前: バージョンが一致しない場合、即座に
nil
とEINVAL
エラーを返して関数を終了していました。 - 変更後: バージョンが一致しない場合でも、
b = b[any.Msglen:]
によって現在のメッセージの長さ分だけバイトスライスb
を進め、continue
によって次のメッセージのパースを試みます。これにより、不正なバージョンのメッセージをスキップし、後続のメッセージの処理を継続します。
- 変更前: バージョンが一致しない場合、即座に
-
msgs = append(msgs, any.toRoutingMessage(b))
: バージョンが一致した場合、any.toRoutingMessage(b)
を呼び出して、現在のメッセージをより具体的なRoutingMessage
インターフェースの型に変換し、結果のスライスmsgs
に追加します。 -
b = b[any.Msglen:]
: 現在のメッセージが正常にパースされた場合、そのメッセージの長さ分だけバイトスライスb
を進め、次のメッセージの先頭にポインタを移動させます。 -
新しいエラーチェック (
if msgCount > 0 && len(msgs) == 0
):for
ループが終了した後、この新しい条件が評価されます。msgCount > 0
: これは、関数が少なくとも1回はメッセージのパースを試みたことを意味します。つまり、入力バイトスライスb
が空ではなかったということです。len(msgs) == 0
: これは、パースを試みたにもかかわらず、最終的に有効なルーティングメッセージが1つもmsgs
スライスに追加されなかったことを意味します。 この両方の条件が真である場合、つまり「何かメッセージがあったが、どれも有効にパースできなかった」という状況で、初めてreturn nil, EINVAL
が実行されます。これにより、部分的なバージョン不一致ではなく、全体的なパースの失敗(例えば、すべてのメッセージが不正なバージョンであった場合など)に対してのみEINVAL
が返されるようになります。
この変更により、ParseRoutingMessage
関数は、ルーティングメッセージストリームの堅牢性が向上し、部分的なバージョン不一致があっても可能な限り多くの有効なメッセージを抽出できるようになりました。
関連リンク
- Go CL (Code Review) へのリンク: https://golang.org/cl/30340043
参考にした情報源リンク
- GitHub上のコミットページ: https://github.com/golang/go/commit/517e49eb290a454791034eb692b696c347f7d74e
- Go言語の
syscall
パッケージに関するドキュメント (一般的な情報): https://pkg.go.dev/syscall unsafe
パッケージに関するGo言語のドキュメント (一般的な情報): https://pkg.go.dev/unsafe- BSDルーティングソケットに関する一般的な情報 (例:
man 4 route
for FreeBSD/OpenBSD/NetBSD) - Web検索で関連情報を参照しました。# [インデックス 17949] ファイルの概要
このコミットは、Go言語の標準ライブラリsrc/pkg/syscall/route_bsd.go
ファイルに対する変更です。このファイルは、BSD系のオペレーティングシステム(FreeBSD, OpenBSD, NetBSDなど)におけるネットワークルーティングメッセージの処理に関連するシステムコール(syscall
)を扱っています。具体的には、カーネルから受け取ったルーティングメッセージ(RoutingMessage
)をパース(解析)する機能を提供します。
コミット
commit 517e49eb290a454791034eb692b696c347f7d74e
Author: Joel Sing <jsing@google.com>
Date: Wed Dec 11 00:03:46 2013 +1100
syscall: skip routing messages with mismatched version
Skip routing messages with a mismatched version, rather than failing
and returning EINVAL. Only return EINVAL if we were unable to parse
any of the routing messages (presumably due to a version mismatch).
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/30340043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/517e49eb290a454791034eb692b696c347f7d74e
元コミット内容
このコミットの目的は、ルーティングメッセージをパースする際に、バージョンが一致しないメッセージを即座にEINVAL
エラーで失敗させるのではなく、スキップするように変更することです。EINVAL
エラーは、ルーティングメッセージのどれもパースできなかった場合(おそらくバージョン不一致が原因)にのみ返されるべきである、という方針転換が示されています。
変更の背景
以前の実装では、ParseRoutingMessage
関数が複数のルーティングメッセージを含むバイトスライスを受け取った際、その中の最初のメッセージのバージョンが期待されるRTM_VERSION
と一致しない場合、即座にEINVAL
(Invalid argument)エラーを返していました。これは、複数のルーティングメッセージが連結されて送られてくるシナリオにおいて、一部のメッセージが異なるバージョンを持つ場合に問題を引き起こす可能性がありました。
例えば、カーネルが異なるバージョンのルーティングメッセージを混在させて送信する、あるいは、アプリケーションが複数のルーティングメッセージを処理する際に、一部のメッセージが古い(または新しい)バージョンであるといった状況が考えられます。このような場合、以前の実装では、有効なメッセージが後続に存在しても、最初のバージョン不一致で処理が中断されてしまい、システムがルーティング情報を完全に取得できない、あるいは不必要にエラーを返すという非効率性や堅牢性の欠如がありました。
このコミットの背景には、より堅牢で柔軟なルーティングメッセージのパース処理を実現し、部分的なバージョン不一致があっても可能な限り多くの有効なメッセージを処理できるようにするという意図があります。これにより、Goアプリケーションがネットワークルーティング情報を扱う際の信頼性と互換性が向上します。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
-
システムコール (syscall): オペレーティングシステムが提供するサービスをプログラムから利用するためのインターフェースです。ファイル操作、ネットワーク通信、プロセス管理など、OSの低レベルな機能にアクセスするために使用されます。Go言語の
syscall
パッケージは、これらのOS固有の機能へのアクセスを提供します。 -
ルーティングメッセージ (Routing Messages): BSD系のUnixライクなシステム(FreeBSD, OpenBSD, NetBSDなど)では、カーネルがネットワークルーティングテーブルの変更やネットワークインターフェースの状態変化などの情報を、ユーザー空間のプロセスにルーティングメッセージとして通知します。これらのメッセージは特定の構造を持ち、ネットワークデーモン(例:
routed
,zebra
)がルーティング情報を管理するために利用します。 -
RTM_VERSION
: ルーティングメッセージのプロトコルバージョンを示す定数です。ルーティングメッセージのヘッダに含まれており、メッセージの構造や意味を解釈するために使用されます。バージョンが一致しない場合、メッセージの構造や意味が異なる可能性があるため、通常は処理を中断するか、異なる方法で処理する必要があります。 -
EINVAL
: Unix系のシステムコールが返すエラーコードの一つで、「Invalid argument」(不正な引数)を意味します。関数に渡された引数が無効である場合に返されます。この文脈では、ルーティングメッセージのバージョンが不正である、あるいはメッセージ自体が破損しているといった状況で返されることが想定されます。 -
unsafe.Pointer
: Go言語のunsafe
パッケージに含まれる型で、任意の型のポインタを保持できる特殊なポインタです。Goの型安全性をバイパスして、メモリを直接操作することを可能にします。このコミットでは、バイトスライス[]byte
をルーティングメッセージの構造体anyMessage
にキャストするために使用されています。これは、バイト列を特定の構造体として解釈する際に一般的に用いられる手法ですが、Goの型システムを迂回するため、注意深く使用する必要があります。 -
バイトスライス (
[]byte
) と構造体 (struct
) の変換: ネットワークから受信したデータは通常バイト列として扱われます。これをGoのプログラムで意味のある情報として処理するためには、バイト列を定義された構造体(この場合はルーティングメッセージのヘッダやペイロードを表す構造体)に変換する必要があります。unsafe.Pointer
とunsafe.Sizeof
、unsafe.Offsetof
などの関数を組み合わせて、バイトスライスを構造体として解釈するテクニックが用いられます。
技術的詳細
変更はsrc/pkg/syscall/route_bsd.go
ファイルのParseRoutingMessage
関数に集中しています。この関数は、バイトスライスb
を受け取り、その中に含まれる複数のルーティングメッセージをパースして、[]RoutingMessage
の形で返します。
変更前は、for
ループ内で各メッセージを処理する際に、any.Version != RTM_VERSION
という条件でバージョンチェックを行い、バージョンが一致しない場合は即座にreturn nil, EINVAL
としていました。これは、メッセージストリームの途中でバージョン不一致のメッセージが見つかった場合でも、それ以降のメッセージの処理を完全に停止させてしまう挙動でした。
変更後は、この挙動が以下のように修正されました。
-
msgCount
変数の導入: パースを試みたメッセージの総数をカウントするために、msgCount
という新しい変数が導入されました。これは、ループが何回実行されたか(つまり、何個のメッセージの先頭を読み取ろうとしたか)を追跡します。 -
バージョン不一致時のスキップ:
if any.Version != RTM_VERSION
の条件が真(バージョン不一致)の場合、以前はreturn nil, EINVAL
でしたが、変更後はb = b[any.Msglen:]
とcontinue
が実行されます。b = b[any.Msglen:]
: 現在のメッセージの長さ(any.Msglen
)だけバイトスライスb
を進めます。これにより、バージョン不一致のメッセージをスキップし、次のメッセージの先頭にポインタを移動させます。continue
: ループの次のイテレーションに進み、次のメッセージのパースを試みます。 この変更により、バージョン不一致のメッセージは無視され、後続のメッセージのパースが継続されるようになります。
-
EINVAL
を返す条件の変更: ループが終了した後、つまりすべてのバイトスライスが処理された後に、EINVAL
を返す新しい条件が追加されました。// We failed to parse any of the messages - version mismatch? if msgCount > 0 && len(msgs) == 0 { return nil, EINVAL }
この条件は、以下の状況で
EINVAL
を返します。msgCount > 0
: 少なくとも1つ以上のメッセージのパースを試みた。len(msgs) == 0
: しかし、結果として有効なルーティングメッセージが1つもパースできなかった。 このロジックは、「メッセージのパースを試みたが、どれも成功しなかった(おそらく全体的なバージョン不一致やデータ破損のため)」という場合にのみEINVAL
を返すことを意味します。これにより、部分的なバージョン不一致で即座にエラーになるのではなく、本当に処理すべきメッセージが一つもなかった場合にのみエラーを返す、より堅牢な挙動が実現されます。
この変更は、ネットワークプロトコルやシステムメッセージのパースにおいて一般的な「フォールトトレランス」の考え方を導入しています。つまり、一部の不正なデータがあっても全体が失敗するのではなく、可能な限り有効なデータを抽出し、処理を継続しようとするアプローチです。
コアとなるコードの変更箇所
src/pkg/syscall/route_bsd.go
ファイルのParseRoutingMessage
関数内の以下の部分が変更されました。
--- a/src/pkg/syscall/route_bsd.go
+++ b/src/pkg/syscall/route_bsd.go
@@ -199,14 +199,21 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
// ParseRoutingMessage parses b as routing messages and returns the
// slice containing the RoutingMessage interfaces.
func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
+\tmsgCount := 0 // 追加
\tfor len(b) >= anyMessageLen {\
+\t\tmsgCount++ // 追加
\t\tany := (*anyMessage)(unsafe.Pointer(&b[0]))\
\t\tif any.Version != RTM_VERSION {\
-\t\t\treturn nil, EINVAL // 変更前: 即座にエラーを返す
+\t\t\tb = b[any.Msglen:] // 変更後: メッセージをスキップ
+\t\t\tcontinue // 変更後: 次のメッセージへ
\t\t}\
\t\tmsgs = append(msgs, any.toRoutingMessage(b))\
\t\tb = b[any.Msglen:]\
\t}\
+\t// We failed to parse any of the messages - version mismatch? // 追加
+\tif msgCount > 0 && len(msgs) == 0 { // 追加
+\t\treturn nil, EINVAL // 追加
+\t}
\treturn msgs, nil
}\
コアとなるコードの解説
ParseRoutingMessage
関数は、バイトスライスb
をルーティングメッセージのシーケンスとして解釈します。
-
msgCount := 0
: 関数冒頭でmsgCount
が0で初期化されます。これは、この関数が処理を試みたルーティングメッセージの数を追跡するためのカウンターです。 -
for len(b) >= anyMessageLen
: このループは、残りのバイトスライスb
が少なくとも1つのルーティングメッセージの最小長(anyMessageLen
)以上である限り続きます。これにより、バイトスライスが尽きるまで、または有効なメッセージの先頭が見つからなくなるまで処理が繰り返されます。 -
msgCount++
: ループの各イテレーションの開始時にmsgCount
がインクリメントされます。これは、現在処理しようとしているバイトスライスが、潜在的に新しいルーティングメッセージの開始点であることを示します。 -
any := (*anyMessage)(unsafe.Pointer(&b[0]))
:unsafe.Pointer
を使用して、現在のバイトスライスb
の先頭をanyMessage
構造体へのポインタとして解釈します。anyMessage
はルーティングメッセージの共通ヘッダ部分を表す構造体であり、バージョン情報(Version
フィールド)やメッセージ長(Msglen
フィールド)を含んでいます。 -
if any.Version != RTM_VERSION
: ここで、現在解釈しているメッセージのバージョンが、期待されるRTM_VERSION
と一致するかどうかをチェックします。- 変更前: バージョンが一致しない場合、即座に
nil
とEINVAL
エラーを返して関数を終了していました。 - 変更後: バージョンが一致しない場合でも、
b = b[any.Msglen:]
によって現在のメッセージの長さ分だけバイトスライスb
を進め、continue
によって次のメッセージのパースを試みます。これにより、不正なバージョンのメッセージをスキップし、後続のメッセージの処理を継続します。
- 変更前: バージョンが一致しない場合、即座に
-
msgs = append(msgs, any.toRoutingMessage(b))
: バージョンが一致した場合、any.toRoutingMessage(b)
を呼び出して、現在のメッセージをより具体的なRoutingMessage
インターフェースの型に変換し、結果のスライスmsgs
に追加します。 -
b = b[any.Msglen:]
: 現在のメッセージが正常にパースされた場合、そのメッセージの長さ分だけバイトスライスb
を進め、次のメッセージの先頭にポインタを移動させます。 -
新しいエラーチェック (
if msgCount > 0 && len(msgs) == 0
):for
ループが終了した後、この新しい条件が評価されます。msgCount > 0
: これは、関数が少なくとも1回はメッセージのパースを試みたことを意味します。つまり、入力バイトスライスb
が空ではなかったということです。len(msgs) == 0
: これは、パースを試みたにもかかわらず、最終的に有効なルーティングメッセージが1つもmsgs
スライスに追加されなかったことを意味します。 この両方の条件が真である場合、つまり「何かメッセージがあったが、どれも有効にパースできなかった」という状況で、初めてreturn nil, EINVAL
が実行されます。これにより、部分的なバージョン不一致ではなく、全体的なパースの失敗(例えば、すべてのメッセージが不正なバージョンであった場合など)に対してのみEINVAL
が返されるようになります。
この変更により、ParseRoutingMessage
関数は、ルーティングメッセージストリームの堅牢性が向上し、部分的なバージョン不一致があっても可能な限り多くの有効なメッセージを抽出できるようになりました。
関連リンク
- Go CL (Code Review) へのリンク: https://golang.org/cl/30340043
参考にした情報源リンク
- GitHub上のコミットページ: https://github.com/golang/go/commit/517e49eb290a454791034eb692b696c347f7d74e
- Go言語の
syscall
パッケージに関するドキュメント (一般的な情報): https://pkg.go.dev/syscall unsafe
パッケージに関するGo言語のドキュメント (一般的な情報): https://pkg.go.dev/unsafe- BSDルーティングソケットに関する一般的な情報 (例:
man 4 route
for FreeBSD/OpenBSD/NetBSD) - Web検索で関連情報を参照しました。