# 通知設計書 9-DNS正引き解決完了通知

## 概要

本ドキュメントは、libuvにおけるDNS正引き解決完了通知（uv_getaddrinfo_cb）の設計を記述する。ホスト名からIPアドレスへの非同期DNS解決が完了した際にコールバックで通知するメカニズムについて定義する。

### 本通知の処理概要

uv_getaddrinfo_cbは、ホスト名からIPアドレスへの名前解決（正引き）を非同期に実行し、完了時にコールバックで結果を通知する仕組みである。DNS解決はブロッキングI/Oであるため、スレッドプールでgetaddrinfo()を実行し、完了後にイベントループのメインスレッドでコールバックを呼び出す。

**業務上の目的・背景**：ネットワークアプリケーションでは、ホスト名からIPアドレスへの変換が必須である。しかし、POSIX getaddrinfo()はブロッキング関数であり、イベントループをブロックしてしまう。本通知は、スレッドプールによる非同期実行とイベントループへの結果通知を統合し、非ブロッキングなDNS解決を実現する。

**通知の送信タイミング**：uv_getaddrinfo()が呼び出されると、スレッドプールのワーカースレッドでgetaddrinfo()が実行される。完了後、uv_async_send()（loop->wq_async）を通じてイベントループにウェイクアップが送信され、uv__work_done()→uv__getaddrinfo_done()でコールバックが実行される。

**通知の受信者**：uv_getaddrinfo()で設定されたコールバック関数（uv_getaddrinfo_cb）が受信者となる。

**通知内容の概要**：コールバックにはuv_getaddrinfo_tリクエスト、ステータス（int status、0=成功、負の値=エラーコード）、解決結果（struct addrinfo* res）が渡される。

**期待されるアクション**：受信者はステータスを確認し、成功時はaddrinfo構造体のリンクリストからIPアドレスを取得して接続等に使用する。使用後はuv_freeaddrinfo()でメモリを解放する。

## 通知種別

コールバック通知（Cコールバック関数呼び出し）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（スレッドプール + uv_async経由でイベントループに通知） |
| 優先度 | 中（スレッドプールのUV__WORK_SLOW_IOキューで処理） |
| リトライ | なし |

### 送信先決定ロジック

uv_getaddrinfo()で設定されたコールバック（req->cb）がuv__getaddrinfo_done()内で呼び出される。同期モード（cb==NULL）の場合はuv_getaddrinfo()内で同期的に実行される。

## 通知テンプレート

### コールバック関数シグネチャ

| 項目 | 内容 |
|-----|------|
| 関数型 | `typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req, int status, struct addrinfo* res)` |
| 定義場所 | `include/uv.h` |

### コールバックパラメータ

```
req: uv_getaddrinfo_t* - DNS解決リクエスト
status: int - ステータス（0=成功、UV_EAI_*=エラー）
res: struct addrinfo* - 解決結果のリンクリスト（エラー時はNULL）
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| req | DNSリクエスト | uv__work経由（container_of） | Yes |
| status | 解決結果ステータス | req->retcode（getaddrinfo戻り値のエラー変換） | Yes |
| res | 解決結果addrinfo | req->addrinfo（getaddrinfo()で設定） | No（エラー時NULL） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| スレッドプール完了 | getaddrinfo()の完了 | uv_getaddrinfo()でcb!=NULLが設定済み | uv__getaddrinfo_done()でコールバック実行 |
| キャンセル | uv_cancel()の呼び出し | リクエストがキュー内（未実行） | UV_EAI_CANCELEDステータスでコールバック |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| cb == NULL（同期モード） | コールバックなしで同期実行（getaddrinfo.c 217-221行目） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[uv_getaddrinfo呼び出し] --> B{cb != NULL?}
    B -->|Yes| C[uv__work_submit - スレッドプールに投入]
    B -->|No| D[同期実行: getaddrinfo直接呼び出し]
    C --> E[ワーカースレッドでgetaddrinfo実行]
    E --> F[uv_async_send - イベントループウェイクアップ]
    F --> G[uv__work_done]
    G --> H[uv__getaddrinfo_done]
    H --> I[メモリ解放: hints/service/hostname]
    I --> J{キャンセルされた?}
    J -->|Yes| K[retcode = UV_EAI_CANCELED]
    J -->|No| L[retcodeはgetaddrinfo結果]
    K --> M[cb呼び出し]
    L --> M
    D --> N[結果返却]
```

## データベース参照・更新仕様

### 内部データ構造

| データ構造 | 用途 | 備考 |
|-----------|------|------|
| req->hostname | 解決対象ホスト名 | uv__malloc()で単一バッファに格納 |
| req->service | サービス名 | hostname/service/hintsは連続バッファ |
| req->hints | addrinfo hints | フィルタ条件（AF_INET等） |
| req->addrinfo | 解決結果 | getaddrinfo()で設定されるリンクリスト |
| req->retcode | エラーコード | uv__getaddrinfo_translate_error()で変換 |
| req->work_req | スレッドプールワーク | uv__work構造体 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| UV_EINVAL | req==NULLまたはhostname/service両方NULL | エラーコード返却（getaddrinfo.c 152-155行目） |
| UV_ENOMEM | バッファ割当失敗 | エラーコード返却（getaddrinfo.c 179-180行目） |
| UV_EAI_* | getaddrinfo()のエラー | uv__getaddrinfo_translate_error()で変換（getaddrinfo.c 39-93行目） |
| UV_EAI_CANCELED | uv_cancel()で取り消し | キャンセルステータスでコールバック（getaddrinfo.c 128-131行目） |
| IDNA変換失敗 | 国際化ドメイン名の変換エラー | エラーコード返却（getaddrinfo.c 168-169行目） |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | なし |
| リトライ対象エラー | なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | スレッドプールサイズに依存（デフォルト4スレッド、最大1024） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし。ただし、UV__WORK_SLOW_IOとしてスレッドプールの半数以上を占有しないよう制限される。

## セキュリティ考慮事項

- IDNAによる国際化ドメイン名の正規化処理あり（uv__idna_toascii）
- getaddrinfo()はOSのDNSリゾルバに依存するため、DNS応答の信頼性はOS設定に依存

## 備考

- UV__WORK_SLOW_IOカテゴリでスレッドプールに投入される（getaddrinfo.c 212行目）
- hostname/service/hintsは単一のuv__malloc()で連続バッファに格納される（メモリ効率の最適化）
- メモリ解放順序がhintsの有無で変わる点に注意（getaddrinfo.c 115-122行目）
- 同期モード（cb==NULL）ではスレッドプールを使用せず直接実行

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | uv_getaddrinfo_cb型定義、uv_getaddrinfo_t構造体 |

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | getaddrinfo.c | `src/unix/getaddrinfo.c` | 138-222行目: uv_getaddrinfo() - メインAPI |

**主要処理フロー**:
1. **152-155行目**: 引数バリデーション
2. **163-171行目**: IDNA正規化（hostname_ascii）
3. **177行目**: バッファ割当（hostname+service+hints連続）
4. **194-208行目**: hints/service/hostname設定
5. **210-216行目**: uv__work_submit()でスレッドプールに投入

#### Step 3: ワーカースレッド実行を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | getaddrinfo.c | `src/unix/getaddrinfo.c` | 96-103行目: uv__getaddrinfo_work() - スレッドプール内での実行 |

#### Step 4: 完了通知を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | getaddrinfo.c | `src/unix/getaddrinfo.c` | 106-135行目: uv__getaddrinfo_done() - コールバック実行 |
| 4-2 | threadpool.c | `src/threadpool.c` | 319-356行目: uv__work_done() - スレッドプール完了時のディスパッチ |

**主要処理フロー**:
- **111-112行目**: リクエストのループからの登録解除
- **115-122行目**: メモリ解放（hints/service/hostname）
- **128-131行目**: キャンセル時のエラーコード設定
- **133-134行目**: req->cb(req, req->retcode, req->addrinfo)呼び出し

### プログラム呼び出し階層図

```
uv_getaddrinfo(loop, req, cb, hostname, service, hints)
    +-- uv__idna_toascii()       ← IDNA正規化
    +-- uv__malloc()             ← バッファ確保
    +-- uv__work_submit()
            +-- [ワーカースレッド]
            |   uv__getaddrinfo_work()
            |       +-- getaddrinfo()   ← ブロッキングDNS解決
            |
            +-- [完了通知]
                uv__work_done()
                    +-- uv__getaddrinfo_done()
                            +-- メモリ解放
                            +-- req->cb(req, retcode, addrinfo)
```

### データフロー図

```
[入力]                    [処理]                          [出力]

hostname, service    uv_getaddrinfo()
hints (optional)  ──▶  IDNA正規化 → バッファ確保
                         │
                  [スレッドプール]
                         │
                         ▼
                  getaddrinfo()  ← ブロッキング実行
                         │
                  [イベントループ]
                         │
                         ▼
                  uv__getaddrinfo_done()
                  メモリ解放
                         │
                         ▼
                  cb(req, status, addrinfo) ──▶ ユーザーコールバック
                                                    │
                                                    ▼
                                              uv_freeaddrinfo(res)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | uv_getaddrinfo_cb型定義、uv_getaddrinfo_t構造体、公開API宣言 |
| getaddrinfo.c | `src/unix/getaddrinfo.c` | ソース | DNS正引き解決の全実装 |
| threadpool.c | `src/threadpool.c` | ソース | スレッドプール基盤（work_submit, work_done） |
| idna.c | `src/idna.c` | ソース | 国際化ドメイン名のASCII変換 |
| idna.h | `src/idna.h` | ヘッダ | IDNA関数宣言 |
