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

[インデックス 18005] ファイルの概要

このコミットは、Go言語のネットワークパッケージ(net)におけるPlan 9オペレーティングシステム向けのプロトコルルックアップとホストルックアップの挙動を修正するものです。具体的には、プロトコル名の検索時に小文字を使用するように変更し、lookupHost関数でより汎用的なネットワークプロトコルを使用するように更新しています。

コミット

commit 20dee338c322bb3beb805f837ab780f98cfe8d59
Author: David du Colombier <0intro@gmail.com>
Date:   Mon Dec 16 12:00:23 2013 -0800

    net: lookup protocol in lower-case on Plan 9
    
    Protocol keywords are case-insensitive,
    but the Ndb database is case-sensitive.
    
    Also use the generic net protocol instead
    of tcp in lookupHost.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/40600047

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/20dee338c322bb3beb805f837ab780f98cfe8d59

元コミット内容

このコミットは、src/pkg/net/lookup_plan9.go ファイルに対して以下の変更を加えています。

  1. strings パッケージのインポートを追加。
  2. lookupProtocol 関数内で、プロトコル名をクエリする際に strings.ToLower() を使用して小文字に変換するように変更。
    • 変更前: lines, err := query("/net/cs", "!protocol="+name, 128)
    • 変更後: lines, err := query("/net/cs", "!protocol="+strings.ToLower(name), 128)
  3. lookupHost 関数内で、queryCS を呼び出す際のプロトコル指定を "tcp" から "net" に変更。
    • 変更前: lines, err := queryCS("tcp", host, "1")
    • 変更後: lines, err := queryCS("net", host, "1")

変更の背景

この変更の背景には、Plan 9オペレーティングシステムのネットワーク設定とデータベースの特性があります。

  1. Ndbデータベースのケースセンシティブ性: Plan 9のネットワーク設定は、主にNdb (Name database) と呼ばれるデータベースによって管理されています。このNdbデータベースは、その内部でキーと値のペアを格納する際にケースセンシティブ(大文字と小文字を区別する)な挙動を示します。しかし、一般的なネットワークプロトコルのキーワード(例: "TCP", "tcp")は、通常ケースインセンシティブに扱われるべきです。この不一致が問題を引き起こしていました。Goのnetパッケージがプロトコル名をNdbに問い合わせる際、ユーザーが指定したプロトコル名(例: "TCP")がNdbに登録されている小文字のプロトコル名(例: "tcp")と一致しない場合、正しい情報が取得できない可能性がありました。このコミットは、Ndbに問い合わせる前にプロトコル名を小文字に統一することで、この問題を解決しようとしています。

  2. lookupHostにおける汎用プロトコルの使用: lookupHost関数は、ホスト名からIPアドレスを解決する役割を担っています。以前は、この関数が内部でqueryCSを呼び出す際に、特定のプロトコルとして"tcp"を指定していました。しかし、ホスト名の解決はTCPプロトコルに限定されるものではなく、より汎用的なネットワークサービスに関連する情報であるべきです。"net"という汎用的なプロトコル指定を使用することで、TCPに限定されず、より広範なネットワーク設定(例えば、ローカルネットワーク内のホスト名解決など)に対応できるようになります。これは、/net/cs(connection server)がローカルのホスト名解決情報(/lib/ndb/localなどから)も知っているというコメントからも裏付けられます。

これらの変更は、GoのnetパッケージがPlan 9環境でより堅牢かつ正確に動作するようにするためのものです。

前提知識の解説

このコミットを理解するためには、以下の概念について基本的な知識が必要です。

  • Plan 9 from Bell Labs: ベル研究所で開発された分散オペレーティングシステム。Unixの後継として設計され、"Everything is a file"(すべてはファイルである)という哲学を徹底しています。ネットワークリソースもファイルシステムを通じてアクセスされます。
  • Ndb (Name database): Plan 9におけるネットワーク設定情報(ホスト名、IPアドレス、プロトコルなど)を管理するためのデータベースシステム。/lib/ndbディレクトリ以下のファイル群で構成され、ndb/cs(connection server)などのサービスがこのデータベースを利用して名前解決やプロトコル情報のルックアップを行います。Ndbは、その設計上、キーの検索においてケースセンシティブな挙動を示すことがあります。
  • /net/cs (Connection Server): Plan 9のネットワークサービスの一つで、接続に関する情報を提供します。これには、プロトコル番号のルックアップや、ホスト名からIPアドレスへの解決などが含まれます。ファイルシステム上の/net/csというパスを通じてアクセスされます。
  • /net/dns: Plan 9におけるDNS(Domain Name System)クライアントサービス。外部のDNSサーバーに問い合わせてホスト名を解決する際に使用されます。
  • query および queryCS 関数: Goのnetパッケージ(特にPlan 9向けの実装)内で、Plan 9のファイルシステムを通じてネットワークサービスに問い合わせを行うための内部関数です。
    • query(filename, query string, bufSize int): 指定されたfilename(例: /net/cs)に対してquery文字列を送信し、結果を読み取ります。
    • queryCS(proto, name, typ string): /net/csに対して特定のプロトコル、名前、タイプで問い合わせを行います。
  • ケースセンシティブとケースインセンシティブ:
    • ケースセンシティブ (Case-sensitive): 大文字と小文字を区別すること。例えば、"TCP"と"tcp"は異なるものとして扱われます。
    • ケースインセンシティブ (Case-insensitive): 大文字と小文字を区別しないこと。例えば、"TCP"と"tcp"は同じものとして扱われます。

技術的詳細

このコミットの技術的詳細は、Plan 9のネットワークスタックとGoのnetパッケージの連携に深く関わっています。

1. lookupProtocolにおける小文字化の必要性

lookupProtocol関数は、与えられたプロトコル名(例: "tcp", "udp")に対応するプロトコル番号(例: TCPなら6, UDPなら17)を取得するために使用されます。Plan 9では、この情報は/net/csを通じてNdbデータベースから取得されます。

Ndbデータベースは、プロトコル名をキーとしてプロトコル番号を格納していますが、その内部的なキーの比較はケースセンシティブです。しかし、Goのnetパッケージを使用するアプリケーションや、一般的なネットワークプロトコルの慣習では、プロトコル名はケースインセンシティブに扱われることが期待されます。

例えば、ユーザーが"TCP"という文字列をプロトコル名として指定した場合、GoのnetパッケージはこれをlookupProtocolに渡します。もしNdbに"tcp"というエントリしか登録されていない場合、ケースセンシティブな検索では"TCP""tcp"は一致しないため、正しいプロトコル番号が取得できませんでした。

このコミットでは、query関数を呼び出す前にstrings.ToLower(name)を使用することで、入力されたプロトコル名を強制的に小文字に変換しています。これにより、Ndbデータベースが内部的に小文字のプロトコル名(例: "tcp")でエントリを保持している場合でも、ユーザーがどのような大文字・小文字の組み合わせでプロトコル名を指定しても、常に正しいエントリにヒットするようになります。これは、堅牢性と互換性を向上させるための重要な変更です。

2. lookupHostにおけるプロトコル指定の変更

lookupHost関数は、ホスト名(例: "google.com")に対応するIPアドレスを解決するために使用されます。Plan 9では、この解決は/net/csを通じて行われます。

以前の実装では、queryCS関数を呼び出す際に、プロトコルとして"tcp"がハードコードされていました。これは、ホスト名の解決が主にTCP接続の確立に関連しているという一般的な認識に基づいていた可能性があります。しかし、ホスト名の解決はTCPに限定されるものではなく、より広範なネットワークサービスや設定(例えば、ローカルネットワーク内のホスト名解決や、他のプロトコルに関連する名前解決)にも適用されるべきです。

Plan 9の/net/csは、単にDNSクエリを転送するだけでなく、/lib/ndb/localのようなローカルのNdbファイルに定義されたホスト名情報も利用して名前解決を行います。これらのローカルなエントリは、必ずしも特定のトランスポートプロトコル(TCPやUDP)に厳密に結びついているわけではありません。

"net"というプロトコル指定は、TCPやUDPのような特定のトランスポートプロトコルではなく、より抽象的で汎用的な「ネットワーク」サービス全般を指します。この変更により、lookupHostはTCPに限定されず、/net/csが提供するあらゆる種類のホスト名解決情報(ローカルなNdbエントリを含む)をより適切に利用できるようになります。これにより、Plan 9環境におけるホスト名解決の柔軟性と正確性が向上します。

コアとなるコードの変更箇所

変更は src/pkg/net/lookup_plan9.go ファイルに集中しています。

--- a/src/pkg/net/lookup_plan9.go
+++ b/src/pkg/net/lookup_plan9.go
@@ -7,6 +7,7 @@ package net
 import (
 	"errors"
 	"os"
+	"strings" // 追加
 )
 
 func query(filename, query string, bufSize int) (res []string, err error) {
@@ -72,7 +73,7 @@ func queryDNS(addr string, typ string) (res []string, err error) {
 // lookupProtocol looks up IP protocol name and returns
 // the corresponding protocol number.
 func lookupProtocol(name string) (proto int, err error) {
-	lines, err := query("/net/cs", "!protocol="+name, 128) // 変更前
+	lines, err := query("/net/cs", "!protocol="+strings.ToLower(name), 128) // 変更後
 	if err != nil {
 		return 0, err
 	}
@@ -94,7 +95,7 @@ func lookupProtocol(name string) (proto int, err error) {
 func lookupHost(host string) (addrs []string, err error) {
 	// Use /net/cs instead of /net/dns because cs knows about
 	// host names in local network (e.g. from /lib/ndb/local)
-	lines, err := queryCS("tcp", host, "1") // 変更前
+	lines, err := queryCS("net", host, "1") // 変更後
 	if err != nil {
 		return
 	}

コアとなるコードの解説

import "strings" の追加

strings.ToLower() 関数を使用するために、Goの標準ライブラリであるstringsパッケージがインポートされました。

lookupProtocol 関数の変更

func lookupProtocol(name string) (proto int, err error) {
	lines, err := query("/net/cs", "!protocol="+strings.ToLower(name), 128)
	if err != nil {
		return 0, err
	}
	// ... (後続の処理は変更なし)
}

この変更の核心は、query関数に渡すクエリ文字列の構築部分です。

  • 変更前は、引数として受け取ったname(プロトコル名)をそのままクエリ文字列に連結していました。
  • 変更後は、strings.ToLower(name) を使用して、nameを小文字に変換してからクエリ文字列に連結しています。

これにより、例えばlookupProtocol("TCP")が呼び出された場合でも、/net/csへのクエリは!protocol=tcpとなり、Ndbデータベースがtcpという小文字のキーでプロトコル情報を保持している場合に正しくマッチするようになります。

lookupHost 関数の変更

func lookupHost(host string) (addrs []string, err error) {
	// Use /net/cs instead of /net/dns because cs knows about
	// host names in local network (e.g. from /lib/ndb/local)
	lines, err := queryCS("net", host, "1")
	if err != nil {
		return
	}
	// ... (後続の処理は変更なし)
}

この変更は、queryCS関数の最初の引数(プロトコル指定)を"tcp"から"net"に変更した点です。

  • 変更前は、ホスト名解決のためにTCPプロトコルに特化した問い合わせを行っていました。
  • 変更後は、より汎用的な"net"プロトコルを指定することで、/net/csが提供する広範な名前解決サービス(ローカルのNdbエントリを含む)を利用できるようになりました。これにより、ホスト名解決の範囲がTCPに限定されず、Plan 9のネットワーク環境により適した挙動となります。コメントにもあるように、/net/cs/lib/ndb/localからのホスト名も認識しているため、この変更は理にかなっています。

関連リンク

参考にした情報源リンク