# 機能設計書 51-UDP既存ソケットオープン

## 概要

本ドキュメントは、libuv の `uv_udp_open()` および `uv_udp_open_ex()` APIによる、既存のOSソケットをUDPハンドルに関連付ける機能の設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：アプリケーションがOS APIやサードパーティライブラリを通じて直接作成済みのUDPソケットをlibuvのイベントループに統合する必要がある場面が存在する。例えば、特殊なソケットオプションを設定した後にlibuvで非同期I/Oを行いたい場合や、外部から渡されたソケットFDをlibuvで管理したい場合である。本機能はこの要求に応えるため、既存ソケットをUDPハンドルに関連付けるAPIを提供する。

**機能の利用シーン**：外部で作成されたUDPソケットをlibuvのイベントループで使用したい場合に利用する。具体的には、`socket()` システムコールで直接作成したソケットや、他のライブラリから受け取ったソケットFDをlibuvのUDPハンドルに割り当てる際に使用される。`uv_udp_open()` は後方互換性のためSO_REUSEADDRを自動設定し、`uv_udp_open_ex()` はフラグで動作を細かく制御できる拡張版である。

**主要な処理内容**：
1. フラグの妥当性を検証する（UV_UDP_REUSEADDR, UV_UDP_REUSEPORTのみ許可）
2. ハンドルが既にソケットを保持していないか確認する
3. ソケットFDがイベントループで既に使用されていないか確認する
4. ソケットをノンブロッキングモードに設定する
5. フラグに応じてSO_REUSEADDRまたはSO_REUSEPORTを設定する
6. ソケットFDをI/Oウォッチャーに関連付ける
7. ソケットが既に接続済みの場合は接続フラグを設定する

**関連システム・外部連携**：OSのソケットAPI（socket(), setsockopt()等）との連携。外部ライブラリから受け取ったソケットFDの統合。

**権限による制御**：特になし。ただし、SO_REUSEPORTオプションはLinux 3.9+等の特定プラットフォームでのみ利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 21 | UDP | 主機能 | uv_udp_open()/uv_udp_open_ex()による既存OSソケット関連付けのAPI定義 |

## 機能種別

リソース管理 / ソケット操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| handle | uv_udp_t* | Yes | 初期化済みのUDPハンドル | NULLでないこと |
| sock | uv_os_sock_t | Yes | 既存のOSソケット | 有効なファイルディスクリプタであること |
| flags | unsigned int | No (open_exのみ) | ソケットオプションフラグ | UV_UDP_REUSEADDR, UV_UDP_REUSEPORTのみ許可 |

### 入力データソース

アプリケーションから直接渡されるOSソケットファイルディスクリプタ。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 成功時0、失敗時負のエラーコード |

### 出力先

呼び出し元へ戻り値として返却。ハンドル内部のio_watcher.fdが更新される。

## 処理フロー

### 処理シーケンス

```
1. フラグ検証
   └─ UV_UDP_REUSEADDR・UV_UDP_REUSEPORT以外のフラグがある場合はUV_EINVALを返す
2. ハンドル状態確認
   └─ io_watcher.fdが-1でない（既にソケットが割り当てられている）場合はUV_EBUSYを返す
3. FD重複確認
   └─ 渡されたsockがループ内で既に使用されている場合はUV_EEXISTを返す
4. ノンブロッキング設定
   └─ uv__nonblock(sock, 1)でソケットをノンブロッキングモードに設定
5. ソケットオプション設定
   └─ フラグに応じてSO_REUSEADDR/SO_REUSEPORTを設定
6. FD割り当て
   └─ handle->io_watcher.fd = sockで関連付け
7. 接続状態確認
   └─ uv__udp_is_connected()で接続済みならUV_HANDLE_UDP_CONNECTEDフラグを設定
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{flagsは有効か?}
    B -->|No| C[UV_EINVAL返却]
    B -->|Yes| D{ハンドルにFDが既存?}
    D -->|Yes| E[UV_EBUSY返却]
    D -->|No| F{FDがループ内で使用済み?}
    F -->|Yes| G[UV_EEXIST返却]
    F -->|No| H[ノンブロッキング設定]
    H --> I{設定成功?}
    I -->|No| J[エラー返却]
    I -->|Yes| K{REUSEADDR?}
    K -->|Yes| L[SO_REUSEADDR設定]
    K -->|No| M{REUSEPORT?}
    L --> M
    M -->|Yes| N[SO_REUSEPORT設定]
    M -->|No| O[FD割り当て]
    N --> O
    O --> P{接続済み?}
    P -->|Yes| Q[CONNECTEDフラグ設定]
    P -->|No| R[0を返却]
    Q --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-51-1 | 後方互換性 | uv_udp_open()は常にUV_UDP_REUSEADDRフラグ付きでuv_udp_open_ex()を呼び出す | uv_udp_open()使用時 |
| BR-51-2 | フラグ制限 | UV_UDP_REUSEADDRとUV_UDP_REUSEPORTのみが有効なフラグ | uv_udp_open_ex()使用時 |
| BR-51-3 | 排他制御 | 同一ハンドルに複数のソケットを関連付けることはできない | 常時 |
| BR-51-4 | FD一意性 | 同一ループ内で同じFDを複数のハンドルに関連付けることはできない | 常時 |

### 計算ロジック

該当なし。

## データベース操作仕様

該当なし（インメモリ操作のみ）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータエラー | 無効なフラグが指定された場合 | 有効なフラグのみ指定する |
| UV_EBUSY | 状態エラー | ハンドルに既にソケットが関連付けられている | 新しいハンドルを使用するかクローズ後に再利用 |
| UV_EEXIST | 重複エラー | ソケットFDがループ内で既に使用されている | 別のソケットFDを使用する |
| UV_ENOTSUP | 非サポート | SO_REUSEPORTが非対応プラットフォーム | UV_UDP_REUSEPORTフラグを使用しない |

### リトライ仕様

リトライは不要。エラーの原因を解消した上で再度呼び出す。

## トランザクション仕様

該当なし。

## パフォーマンス要件

同期的な処理のため、即時完了する。OS APIの呼び出し（setsockopt, fcntl）に依存する。

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

- 渡されるソケットFDの妥当性は呼び出し側の責任であり、不正なFDは未定義動作を引き起こす可能性がある
- SO_REUSEPORTの使用は、同一ポートでの受信データが複数プロセス間で分散されるため、セキュリティポリシーに応じた使用判断が必要

## 備考

- `uv_udp_open()` は後方互換性のため、常にSO_REUSEADDRを設定する。GitHub Issue #4551を参照。
- `uv_udp_open_ex()` はlibuv 1.46以降で利用可能な拡張API。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | **L721-734行目**: uv_udp_s構造体の定義。send_queue_size, send_queue_countフィールドとUV_UDP_PRIVATE_FIELDSを確認 |
| 1-2 | uv.h | `include/uv.h` | **L678-711行目**: uv_udp_flags列挙型。UV_UDP_REUSEADDR, UV_UDP_REUSEPORT等のフラグ定義 |

**読解のコツ**: `UV_HANDLE_FIELDS` と `UV_UDP_PRIVATE_FIELDS` はマクロで定義され、プラットフォームごとに異なるフィールドが展開される。Unix系では `io_watcher` がI/O監視に使用される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | udp.c (unix) | `src/unix/udp.c` | **L1011-1017行目**: uv_udp_open()の実装。UV_UDP_REUSEADDRフラグ付きでuv_udp_open_ex()を呼び出す |
| 2-2 | udp.c (unix) | `src/unix/udp.c` | **L973-1008行目**: uv_udp_open_ex()の実装。フラグ検証、重複チェック、ノンブロッキング設定、ソケットオプション設定、FD割り当て |

**主要処理フロー**:
1. **973-978行目**: フラグの妥当性検証（UV_UDP_REUSEADDRとUV_UDP_REUSEPORTのみ許可）
2. **981-982行目**: ハンドルに既にFDが割り当てられていないか確認
3. **984-985行目**: ループ内でのFD重複確認
4. **987-989行目**: ノンブロッキングモードへの設定
5. **991-1001行目**: REUSEADDR/REUSEPORTオプション設定
6. **1003行目**: io_watcher.fdへのソケットFD割り当て
7. **1004-1005行目**: 接続済みソケットの検出とフラグ設定

#### Step 3: ソケットオプション設定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | udp.c (unix) | `src/unix/udp.c` | **L379-415行目**: uv__sock_reuseaddr()。プラットフォーム別のSO_REUSEADDR/SO_REUSEPORT設定 |

**主要処理フロー**:
- **383-394行目**: z/OS: AF_UNIX以外ではSO_REUSEPORTを使用
- **395-403行目**: Solaris 11.4: SO_REUSEPORTを優先し、ENOPROTOOPT時にSO_REUSEADDRへフォールバック
- **404-408行目**: BSD系: SO_REUSEPORTを使用
- **410-411行目**: Linux等: SO_REUSEADDRを使用

#### Step 4: 接続状態確認を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | uv-common.c | `src/uv-common.c` | **L442-453行目**: uv__udp_is_connected()。getpeername()で接続状態を判定 |

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

```
uv_udp_open(handle, sock)
    │
    └─ uv_udp_open_ex(handle, sock, UV_UDP_REUSEADDR)
           │
           ├─ uv__nonblock(sock, 1)
           │
           ├─ uv__sock_reuseaddr(sock)      [flags & UV_UDP_REUSEADDR時]
           │      └─ setsockopt(SO_REUSEADDR / SO_REUSEPORT)
           │
           ├─ uv__sock_reuseport(sock)       [flags & UV_UDP_REUSEPORT時]
           │      └─ setsockopt(SO_REUSEPORT)
           │
           └─ uv__udp_is_connected(handle)
                  └─ uv_udp_getpeername()
                         └─ uv__getsockpeername()
                                └─ getpeername()
```

### データフロー図

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

OSソケットFD ───────▶ uv_udp_open_ex() ───────▶ uv_udp_t.io_watcher.fd
                          │                               (ソケットFDが設定済み)
flags ─────────────▶      │
                          ├─ fcntl(O_NONBLOCK)
                          ├─ setsockopt()
                          └─ getpeername()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | UDP API宣言とuv_udp_s構造体定義 |
| udp.c (unix) | `src/unix/udp.c` | ソース | Unix系プラットフォームのUDP実装 |
| udp.c (win) | `src/win/udp.c` | ソース | Windows向けUDP実装 |
| uv-common.c | `src/uv-common.c` | ソース | プラットフォーム共通のUDP処理 |
| uv-data-getter-setters.c | `src/uv-data-getter-setters.c` | ソース | データアクセサ関数 |
