[インデックス 19245] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおいて、Native Client (NaCl) 環境向けにSendmsgN
関数を追加し、既存のSendmsg
関数を更新するものです。これにより、ソケットへのメッセージ送信時に送信バイト数を正確に取得できるようになります。
コミット
commit d873e642cd78cd4943157bcef7cc27f8f4e9d3cc
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Mon Apr 28 11:34:52 2014 +0900
syscall: add missing SendmsgN for NaCl
Update #7645
LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/98790044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d873e642cd78cd4943157bcef7cc27f8f4e9d3cc
元コミット内容
syscall: add missing SendmsgN for NaCl
Update #7645
LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/98790044
変更の背景
このコミットは、Go言語のsyscall
パッケージがGoogle Native Client (NaCl) 環境で動作する際の不足を補うものです。具体的には、ソケットにデータを送信する際に、送信されたバイト数を正確に返すSendmsgN
関数がNaCl環境向けに欠落していたため、これを追加することが目的です。コミットメッセージにある「Update #7645」は、この機能追加が特定の内部課題(おそらくバグ報告や機能要望)に対応するものであることを示唆しています。
従来のSendmsg
関数はエラーのみを返していましたが、ネットワークプログラミングにおいては、実際に何バイトのデータが送信されたかを知ることが重要です。特に、部分的な送信が発生した場合や、送信バッファの管理を行う場合には、この情報が不可欠となります。NaCl環境におけるGoプログラムのネットワーク機能の完全性と堅牢性を向上させるために、この変更が導入されました。
前提知識の解説
Go言語のsyscall
パッケージ
syscall
パッケージは、Goプログラムからオペレーティングシステム(OS)のシステムコールを直接呼び出すための低レベルなインターフェースを提供します。システムコールは、ファイル操作、ネットワーク通信、プロセス管理など、OSカーネルが提供する基本的なサービスを利用するための手段です。Go言語の標準ライブラリの多くは、このsyscall
パッケージを介してOSの機能を利用しています。
Native Client (NaCl)
Native Client (NaCl) は、Googleが開発したサンドボックス技術で、Webブラウザ内でネイティブコード(C/C++など)を安全かつポータブルに実行することを可能にします。NaClは、セキュリティモデルを強化し、悪意のあるコードがシステムにアクセスするのを防ぎながら、ネイティブアプリケーションに近いパフォーマンスを提供することを目指していました。Go言語もNaCl環境をターゲットプラットフォームの一つとしてサポートしており、GoプログラムをNaClモジュールとしてコンパイルし、Webアプリケーション内で実行することができました。ただし、NaClは現在では非推奨(deprecated)となっており、WebAssembly (Wasm) などの新しい技術に置き換えられています。
sendmsg
システムコール
sendmsg
は、Unix系OSで利用される汎用的なソケット通信のためのシステムコールです。このシステムコールは、通常のデータだけでなく、補助データ(例: ファイルディスクリプタ、ソケット認証情報など)も同時に送信できる柔軟性を持っています。ネットワークプログラミングにおいて、複雑なメッセージ構造や特殊な制御情報を送る際に利用されます。
SOCK_STREAM
とSOCK_DGRAM
ソケットプログラミングにおいて、ソケットの種類は通信の特性を決定します。
SOCK_STREAM
: ストリームソケットは、TCP (Transmission Control Protocol) のように、信頼性があり、コネクション指向で、バイトストリームを提供するソケットです。データの順序が保証され、欠損や重複がありません。SOCK_DGRAM
: データグラムソケットは、UDP (User Datagram Protocol) のように、コネクションレスで、信頼性のないデータグラムを提供するソケットです。データの順序は保証されず、欠損や重複が発生する可能性がありますが、オーバーヘッドが少なく高速です。
技術的詳細
このコミットの主要な目的は、NaCl環境におけるsyscall.Sendmsg
の動作を改善し、送信バイト数を返すSendmsgN
関数を導入することです。
Go言語のsyscall
パッケージにおけるネットワーク関連の関数は、OSのシステムコールをラップしています。sendmsg
システムコールは通常、送信されたバイト数を返しますが、Goのsyscall.Sendmsg
は歴史的にエラーのみを返す設計になっていました。これは、多くのケースで送信が成功したかどうかが重要であり、送信バイト数はアプリケーションレベルで別途管理されることが多かったためと考えられます。
しかし、特定のシナリオ、特にNaClのようなサンドボックス環境では、より詳細な情報(送信バイト数)が必要となる場合があります。このコミットでは、SendmsgN
という新しい関数を導入し、この関数が送信バイト数とエラーの両方を返すように設計されています。既存のSendmsg
関数は、この新しいSendmsgN
を内部的に呼び出し、その戻り値のうちエラーのみを返すように変更されています。これにより、既存のAPIの互換性を保ちつつ、より詳細な情報を提供する新しいAPIが追加されました。
また、SendmsgN
の実装では、ソケットのタイプ(SOCK_STREAM
かSOCK_DGRAM
か)に応じて異なる内部関数(f.write
またはf.sendto
)を呼び分けています。これは、ストリームソケットとデータグラムソケットでデータの送信方法が異なるためです。ストリームソケットではバイトストリームとしてデータを書き込み、データグラムソケットではデータグラムとしてデータを送信します。
コアとなるコードの変更箇所
変更はsrc/pkg/syscall/net_nacl.go
ファイルに集中しています。
--- a/src/pkg/syscall/net_nacl.go
+++ b/src/pkg/syscall/net_nacl.go
@@ -808,11 +808,26 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn, recvflags int, from Soc
}
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) error {
+ _, err := SendmsgN(fd, p, oob, to, flags)
+ return err
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
f, err := fdToNetFile(fd)
if err != nil {
- return err
+ return 0, err
}
- return f.sendto(p, flags, to)
+ switch f.sotype {
+ case SOCK_STREAM:
+ n, err = f.write(p)
+ case SOCK_DGRAM:
+ n = len(p)
+ err = f.sendto(p, flags, to)
+ }
+ if err != nil {
+ return 0, err
+ }
+ return n, nil
}
func GetsockoptInt(fd, level, opt int) (value int, err error) {
コアとなるコードの解説
Sendmsg
関数の変更
既存のSendmsg
関数は、以下のように変更されました。
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) error {
_, err := SendmsgN(fd, p, oob, to, flags)
return err
}
この変更により、Sendmsg
は新しく追加されたSendmsgN
関数を呼び出し、その戻り値のうちエラーのみを返すようになりました。これは、既存のAPIのシグネチャ(引数と戻り値の型)を変更せずに、内部実装を新しいSendmsgN
に委譲するための一般的なパターンです。
SendmsgN
関数の追加
新しく追加されたSendmsgN
関数は以下のようになっています。
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return 0, err
}
switch f.sotype {
case SOCK_STREAM:
n, err = f.write(p)
case SOCK_DGRAM:
n = len(p)
err = f.sendto(p, flags, to)
}
if err != nil {
return 0, err
}
return n, nil
}
fdToNetFile(fd)
: まず、与えられたファイルディスクリプタfd
から、内部的なnetFile
構造体を取得します。このnetFile
は、ソケットに関する詳細な情報(ソケットタイプなど)を保持しています。エラーが発生した場合は、直ちに0
バイトとエラーを返します。- ソケットタイプの判定:
f.sotype
(ソケットタイプ)に基づいて、処理を分岐します。SOCK_STREAM
(TCP): ストリームソケットの場合、f.write(p)
を呼び出します。write
メソッドは、バイトストリームとしてデータをソケットに書き込み、書き込まれたバイト数とエラーを返します。SOCK_DGRAM
(UDP): データグラムソケットの場合、n = len(p)
で送信バイト数をペイロードの長さとして設定し、f.sendto(p, flags, to)
を呼び出します。sendto
メソッドは、指定されたアドレスにデータグラムを送信します。データグラム通信では、通常、送信されるデータの長さは事前に分かっているため、len(p)
がそのまま送信バイト数となります。
- エラーハンドリング:
f.write
またはf.sendto
の呼び出し後にエラーが発生した場合、0
バイトとエラーを返します。 - 戻り値: すべての処理が成功した場合、実際に送信されたバイト数
n
とnil
エラーを返します。
この変更により、NaCl環境においても、Goプログラムがソケット通信の際に送信バイト数を正確に把握できるようになり、より堅牢なネットワークアプリケーションの開発が可能になります。
関連リンク
- Go CL 98790044: https://golang.org/cl/98790044
参考にした情報源リンク
- Go言語の
syscall
パッケージに関する公式ドキュメント - Native Client (NaCl) に関するGoogle Developersのドキュメント(現在は非推奨に関する情報を含む)
- Unix系OSにおける
sendmsg
システムコールに関するmanページや関連ドキュメント - TCP/UDPソケットプログラミングに関する一般的な情報源