# 通知設計書 10-DNS逆引き解決完了通知

## 概要

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

### 本通知の処理概要

uv_getnameinfo_cbは、IPアドレス（sockaddr）からホスト名およびサービス名への逆引きDNS解決を非同期に実行し、完了時にコールバックで結果を通知する仕組みである。正引き解決（No.9）と同様に、スレッドプールでブロッキングのgetnameinfo()を実行し、完了後にイベントループのメインスレッドでコールバックを呼び出す。

**業務上の目的・背景**：サーバーアプリケーションにおいて、接続元クライアントのIPアドレスからホスト名を取得する逆引きDNS解決は、ログ記録、アクセス制御、表示目的等で必要となる。POSIX getnameinfo()はブロッキング関数であるため、本通知はスレッドプールによる非同期実行を提供する。

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

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

**通知内容の概要**：コールバックにはuv_getnameinfo_tリクエスト、ステータス（int status）、ホスト名（const char* hostname）、サービス名（const char* service）が渡される。エラー時はhostnameとserviceがNULLとなる。

**期待されるアクション**：受信者はステータスを確認し、成功時はhostnameとservice文字列を使用する。これらの文字列はリクエスト構造体内のバッファに格納されているため、コールバック終了後も有効だが、リクエスト再利用時には上書きされる点に注意が必要。

## 通知種別

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

## 送信仕様

### 基本情報

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

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

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

## 通知テンプレート

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

| 項目 | 内容 |
|-----|------|
| 関数型 | `typedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req, int status, const char* hostname, const char* service)` |
| 定義場所 | `include/uv.h` |

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

```
req: uv_getnameinfo_t* - DNS逆引きリクエスト
status: int - ステータス（0=成功、UV_EAI_*=エラー）
hostname: const char* - 解決されたホスト名（エラー時NULL）
service: const char* - 解決されたサービス名（エラー時NULL）
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| req | DNS逆引きリクエスト | uv__work経由（container_of） | Yes |
| status | 解決結果ステータス | req->retcode（getnameinfo戻り値のエラー変換） | Yes |
| hostname | 解決されたホスト名 | req->host（NI_MAXHOST固定バッファ） | No（エラー時NULL） |
| service | 解決されたサービス名 | req->service（NI_MAXSERV固定バッファ） | No（エラー時NULL） |

## 送信トリガー・条件

### トリガー一覧

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

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| getnameinfo_cb == NULL（同期モード） | コールバックなしで同期実行（getnameinfo.c 116-121行目） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[uv_getnameinfo呼び出し] --> B[sockaddr検証]
    B --> C{アドレスファミリ}
    C -->|AF_INET| D[sockaddr_in コピー]
    C -->|AF_INET6| E[sockaddr_in6 コピー]
    C -->|その他| F[UV_EINVAL返却]
    D --> G{getnameinfo_cb != NULL?}
    E --> G
    G -->|Yes| H[uv__work_submit - スレッドプールに投入]
    G -->|No| I[同期実行]
    H --> J[ワーカースレッドでgetnameinfo実行]
    J --> K[uv_async_send - イベントループウェイクアップ]
    K --> L[uv__getnameinfo_done]
    L --> M{キャンセル?}
    M -->|Yes| N[retcode = UV_EAI_CANCELED]
    M -->|No| O{retcode == 0?}
    O -->|Yes| P[host/service設定]
    O -->|No| Q[host = service = NULL]
    N --> R[getnameinfo_cb呼び出し]
    P --> R
    Q --> R
    I --> S[結果返却]
```

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

### 内部データ構造

| データ構造 | 用途 | 備考 |
|-----------|------|------|
| req->storage | 入力sockaddr格納 | struct sockaddr_storage型 |
| req->host | ホスト名結果バッファ | NI_MAXHOST固定サイズ |
| req->service | サービス名結果バッファ | NI_MAXSERV固定サイズ |
| req->flags | getnameinfo()フラグ | NI_NAMEREQD, NI_NUMERICHOST等 |
| req->retcode | エラーコード | uv__getaddrinfo_translate_error()で変換 |
| req->work_req | スレッドプールワーク | uv__work構造体 |
| req->getnameinfo_cb | ユーザーコールバック | uv_getnameinfo_cb型 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| UV_EINVAL | req==NULLまたはaddr==NULL | エラーコード返却（getnameinfo.c 86-87行目） |
| UV_EINVAL | 未サポートアドレスファミリ | エラーコード返却（getnameinfo.c 97-98行目） |
| UV_EAI_* | getnameinfo()のエラー | uv__getaddrinfo_translate_error()で変換（getnameinfo.c 52行目） |
| UV_EAI_CANCELED | uv_cancel()で取り消し | キャンセルステータスでコールバック（getnameinfo.c 64-66行目） |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

- getnameinfo()はOSのDNSリゾルバに依存するため、逆引き結果の信頼性はDNS設定に依存
- 逆引き結果をアクセス制御に使用する場合はDNSスプーフィングのリスクに注意

## 備考

- エラーコードの変換にはuv__getaddrinfo_translate_error()を共用（getnameinfo.c 52行目）
- host/serviceバッファはreq構造体内の固定サイズバッファであり、動的メモリ確保は不要
- AF_INETとAF_INET6のみサポート、他のアドレスファミリはUV_EINVAL
- 同期モード（getnameinfo_cb==NULL）ではスレッドプールを使用せず直接実行

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | uv_getnameinfo_cb型定義、uv_getnameinfo_t構造体（host/serviceバッファ、storage、flags） |

**読解のコツ**: uv_getnameinfo_tのhost/serviceフィールドは固定サイズバッファ（NI_MAXHOST/NI_MAXSERV）であり、getaddrinfo_tとは異なりリンクリストではない。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | getnameinfo.c | `src/unix/getnameinfo.c` | 81-121行目: uv_getnameinfo() - メインAPI |

**主要処理フロー**:
1. **86-87行目**: 引数バリデーション（req, addr）
2. **89-98行目**: アドレスファミリ判定とsockaddrコピー
3. **101-107行目**: リクエスト初期化
4. **109-114行目**: uv__work_submit()でスレッドプールに投入
5. **116-120行目**: 同期モード処理

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

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

**主要処理フロー**:
- **38-43行目**: アドレスファミリに応じたsockaddr長の計算
- **45-51行目**: getnameinfo()呼び出し（req->host, req->serviceに結果格納）
- **52行目**: エラーコード変換

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | getnameinfo.c | `src/unix/getnameinfo.c` | 55-74行目: uv__getnameinfo_done() - コールバック実行 |

**主要処理フロー**:
- **61行目**: リクエストのループからの登録解除
- **62行目**: host/serviceをNULL初期化
- **64-66行目**: キャンセル時のエラーコード設定
- **67-70行目**: 成功時のhost/service設定
- **72-73行目**: getnameinfo_cb呼び出し

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

```
uv_getnameinfo(loop, req, cb, addr, flags)
    +-- sockaddrコピー（AF_INET/AF_INET6）
    +-- uv__req_init()
    +-- uv__work_submit()
            +-- [ワーカースレッド]
            |   uv__getnameinfo_work()
            |       +-- getnameinfo()   ← ブロッキングDNS逆引き
            |
            +-- [完了通知]
                uv__work_done()
                    +-- uv__getnameinfo_done()
                            +-- uv__req_unregister()
                            +-- req->getnameinfo_cb(req, retcode, host, service)
```

### データフロー図

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

struct sockaddr      uv_getnameinfo()
(IP:port)     ──▶  sockaddrコピー → リクエスト初期化
                         │
                  [スレッドプール]
                         │
                         ▼
                  getnameinfo()  ← ブロッキング実行
                  → req->host, req->service
                         │
                  [イベントループ]
                         │
                         ▼
                  uv__getnameinfo_done()
                         │
                         ▼
                  cb(req, status, hostname, service) ──▶ ユーザーコールバック
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | uv_getnameinfo_cb型定義、uv_getnameinfo_t構造体、公開API宣言 |
| getnameinfo.c | `src/unix/getnameinfo.c` | ソース | DNS逆引き解決の全実装 |
| getaddrinfo.c | `src/unix/getaddrinfo.c` | ソース | uv__getaddrinfo_translate_error()の共用 |
| threadpool.c | `src/threadpool.c` | ソース | スレッドプール基盤（work_submit, work_done） |
