[インデックス 19677] ファイルの概要
このコミットは、Go言語のネットワークパッケージにおいて、AndroidプラットフォームでのgetaddrinfoシステムコールにおけるAI_ALLフラグの使用を停止することを目的としています。これにより、Android環境でのネットワークアドレス解決の安定性と予測可能性が向上します。
コミット
- コミットハッシュ:
9416fb8c81e25c0900d06f3f04a7508671ad4c09 - 作者: David Crawshaw david.crawshaw@zentus.com
- コミット日時: 2014年7月8日 火曜日 13:42:14 -0400
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/9416fb8c81e25c0900d06f3f04a7508671ad4c09
元コミット内容
net: no AI_ALL on android
LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/112800043
変更の背景
この変更の背景には、Android環境におけるgetaddrinfoシステムコールの挙動に関する潜在的な問題があります。AI_ALLフラグは、ホスト名に関連付けられたすべての利用可能なアドレス(IPv4とIPv6の両方、および同じアドレスファミリー内の複数のアドレス)を要求するために使用されます。しかし、Androidの特定のバージョンやデバイス構成では、AI_ALLフラグを使用すると、以下のような問題が発生する可能性がありました。
- パフォーマンスの低下: すべてのアドレスを解決しようとすると、特にモバイル環境では、DNS解決に時間がかかったり、リソースを多く消費したりする可能性があります。
- 予期せぬ挙動: Androidのネットワークスタックが
AI_ALLによって返される複数のアドレスを適切に処理しない場合、接続の失敗や誤ったアドレス選択につながる可能性があります。 - 互換性の問題: 特定のAndroidバージョンやカスタムROMにおいて、
AI_ALLの挙動が標準的なLinuxディストリビューションと異なる場合があり、これが不安定性の原因となることが考えられます。
このコミットは、これらの問題を回避し、Android上でのGoアプリケーションのネットワーク動作をより予測可能で安定したものにするために、AndroidではAI_ALLフラグを使用しないように変更しています。
前提知識の解説
getaddrinfo
getaddrinfoは、POSIX標準で定義されているネットワークアドレスおよびサービス変換のためのAPIです。これは、ホスト名とサービス名(ポート番号など)を、ソケット接続に使用できるソケットアドレス構造体(sockaddr)のリストに変換するために使用されます。従来のgethostbynameやgetservbynameといった関数よりも柔軟で、IPv4とIPv6の両方をサポートし、非同期的な解決も可能です。
AI_ALL フラグ
getaddrinfo関数に渡されるヒント構造体(addrinfo)のai_flagsフィールドに設定できるフラグの一つです。AI_ALLが設定されると、getaddrinfoはホスト名に関連付けられたすべての利用可能なアドレスを返そうとします。これには、IPv4とIPv6のアドレス、および同じアドレスファミリー内で複数のネットワークインターフェースに関連付けられたアドレスが含まれる場合があります。
AI_CANONNAME フラグ
これもgetaddrinfoのai_flagsに設定できるフラグの一つです。AI_CANONNAMEが設定されると、getaddrinfoは解決されたホストの「正規名」(canonical name)を返します。これは、エイリアスではなく、ホストの正式なDNS名です。
Cgo
Cgoは、Go言語がC言語のコードを呼び出すためのメカニズムです。Goプログラム内でCの関数やライブラリを使用することを可能にします。Goの標準ライブラリ、特にnetパッケージは、OSのシステムコール(getaddrinfoなど)を呼び出すためにCgoを内部的に使用することがあります。
Go net パッケージ
Go言語の標準ライブラリの一部であり、ネットワークプログラミングのための基本的な機能を提供します。TCP/IP、UDP、Unixドメインソケットなどのネットワークプロトコルをサポートし、DNS解決、接続の確立、データの送受信などの機能を提供します。
ビルドタグ (+build)
Go言語のコンパイラディレクティブで、特定のファイルが特定のビルド条件(OS、アーキテクチャ、タグなど)の下でのみコンパイルされるように指定するために使用されます。例えば、// +build androidはAndroid向けビルドでのみコンパイルされ、// +build !androidはAndroid以外のビルドでのみコンパイルされます。
技術的詳細
Goのnetパッケージは、ホスト名の解決にCgoを介してC標準ライブラリのgetaddrinfo関数を利用しています。このコミット以前は、Linuxシステム(Androidを含む)では、getaddrinfoに渡されるフラグが、AI_ALLを含む可能性のある一般的な設定になっていたと考えられます。
このコミットでは、Androidプラットフォームに特化したcgoAddrInfoFlags()関数を導入し、この関数がC.AI_CANONNAMEのみを返すように変更しました。これにより、Android上でのgetaddrinfo呼び出しは、ホストの正規名のみを要求し、AI_ALLによって引き起こされる可能性のある複雑なアドレス解決を回避します。
具体的には、src/pkg/net/cgo_android.goという新しいファイルが作成され、このファイルには// +build cgo,!netgoというビルドタグと、Android固有のcgoAddrInfoFlags()の実装が含まれています。一方、既存のsrc/pkg/net/cgo_linux.goファイルは、ビルドタグが// +build !android,cgo,!netgoに変更されました。この変更により、cgo_linux.goはAndroid向けビルドではコンパイルされなくなり、Android固有のcgo_android.goが代わりに利用されるようになります。
この分離により、GoランタイムはAndroid環境でのネットワークアドレス解決の挙動をより細かく制御できるようになり、AI_ALLが引き起こす可能性のある問題を回避し、より安定したネットワーク動作を実現します。
コアとなるコードの変更箇所
このコミットによる主要なコード変更は以下の2つのファイルにあります。
-
src/pkg/net/cgo_android.go:- このファイルは新規作成されました。
- Androidプラットフォームに特化した
cgoAddrInfoFlags()関数を定義しています。 - ビルドタグ
// +build cgo,!netgoが付与されています。
--- /dev/null +++ b/src/pkg/net/cgo_android.go @@ -0,0 +1,14 @@ +// Copyright 2014 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 cgo,!netgo + +package net + +//#include <netdb.h> +import "C" + +func cgoAddrInfoFlags() C.int { + return C.AI_CANONNAME +} -
src/pkg/net/cgo_linux.go:- 既存のファイルのビルドタグが変更されました。
- 変更前:
// +build cgo,!netgo - 変更後:
// +build !android,cgo,!netgo
--- a/src/pkg/net/cgo_linux.go +++ b/src/pkg/net/cgo_linux.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 cgo,!netgo +// +build !android,cgo,!netgo package net
コアとなるコードの解説
src/pkg/net/cgo_android.go
このファイルは、GoのnetパッケージがAndroid上でCgoを使用してアドレス情報を解決する際に、getaddrinfo関数に渡すフラグを定義しています。
func cgoAddrInfoFlags() C.int {
return C.AI_CANONNAME
}
cgoAddrInfoFlags()関数は、C.AI_CANONNAMEという整数値を返します。これは、getaddrinfoがホストの正規名のみを解決するように指示するフラグです。これにより、Android環境ではAI_ALLフラグが使用されなくなり、前述の潜在的な問題が回避されます。
// +build cgo,!netgoというビルドタグは、このファイルがCgoが有効で、かつGo独自のネットワーク実装(netgo)が使用されていない場合にのみコンパイルされることを意味します。これは、GoがCライブラリのgetaddrinfoを使用するシナリオに適用されます。
src/pkg/net/cgo_linux.go
このファイルは、Android以外のLinuxシステムにおけるgetaddrinfoのフラグ設定を扱います。
// +build !android,cgo,!netgo
ビルドタグが// +build !android,cgo,!netgoに変更されたことで、このファイルはAndroid向けにビルドされる際にはコンパイルされなくなります。これにより、Android固有のcgo_android.goが優先され、Linux(Android以外)とAndroidで異なるgetaddrinfoのフラグ設定が可能になります。
この変更は、Goのクロスプラットフォーム対応において、特定のOSの挙動の違いを吸収し、それぞれのプラットフォームで最適なパフォーマンスと安定性を確保するための典型的なアプローチを示しています。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/9416fb8c81e25c0900d06f3f04a7508671ad4c09
- Go Code Review (CL): https://golang.org/cl/112800043
参考にした情報源リンク
getaddrinfoに関する一般的な情報:- Androidにおける
getaddrinfoの挙動に関する一般的な問題(AI_ALLに直接言及はないが、背景情報として): - Go言語のビルドタグに関する情報:
- Cgoに関する情報: