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

[インデックス 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)のリストに変換するために使用されます。従来のgethostbynamegetservbynameといった関数よりも柔軟で、IPv4とIPv6の両方をサポートし、非同期的な解決も可能です。

AI_ALL フラグ

getaddrinfo関数に渡されるヒント構造体(addrinfo)のai_flagsフィールドに設定できるフラグの一つです。AI_ALLが設定されると、getaddrinfoはホスト名に関連付けられたすべての利用可能なアドレスを返そうとします。これには、IPv4とIPv6のアドレス、および同じアドレスファミリー内で複数のネットワークインターフェースに関連付けられたアドレスが含まれる場合があります。

AI_CANONNAME フラグ

これもgetaddrinfoai_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つのファイルにあります。

  1. 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
    +}
    
  2. 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の挙動の違いを吸収し、それぞれのプラットフォームで最適なパフォーマンスと安定性を確保するための典型的なアプローチを示しています。

関連リンク

参考にした情報源リンク