# 機能設計書 71-ソケットペア作成

## 概要

uv_socketpair()により接続済みソケットのペアを作成する機能の設計書である。本機能はlibuvが提供するユーティリティ関数の一つであり、プロセス間通信（IPC）やストリーム転送のための双方向通信チャネルを確立する。

### 本機能の処理概要

uv_socketpair()は、AF_UNIXドメインのソケットペアを作成し、接続済みの2つのソケットディスクリプタを返す関数である。生成されるソケットペアはclose-on-execフラグが自動的に設定され、オプションとして各ソケットにノンブロッキングモードを個別に設定できる。

**業務上の目的・背景**：プロセス間通信（IPC）において、双方向のデータ転送チャネルが必要となる場面は多い。uv_socketpair()は、子プロセスの標準入出力をリダイレクトする際（uv_spawn()のstdio設定でUV_CREATE_PIPEを使用する場合）に内部的に使用される。また、アプリケーションが独自のIPC通信を構築する際にも利用される。socketpair()システムコールのクロスプラットフォームラッパーとして、Unix/Windows間の差異を吸収する役割を持つ。

**機能の利用シーン**：
- 子プロセス生成時のstdioリダイレクト（UV_CREATE_PIPEフラグ使用時に内部呼び出し）
- アプリケーション独自のプロセス間通信チャネルの構築
- テスト環境でのソケット通信シミュレーション
- TCPストリームの双方向通信テスト

**主要な処理内容**：
1. socketpair()システムコールによりAF_UNIXソケットペアを作成する
2. 作成された各ソケットにclose-on-exec（CLOEXEC）フラグを設定する
3. flags0/flags1パラメータに応じて各ソケットにノンブロッキングモードを設定する
4. エラー発生時はソケットを適切にクローズしてエラーコードを返す

**関連システム・外部連携**：OSのsocketpair()システムコールを直接使用する。Linuxではatomicなフラグ設定（SOCK_CLOEXEC/SOCK_NONBLOCK）をサポートし、他のプラットフォームではフォールバック処理を行う。Windowsではlisten/connect/acceptを用いたエミュレーション実装となる。

**権限による制御**：特段の権限制御はない。ソケット作成はユーザー権限で実行可能である。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 18 | TCP | 補助機能 | uv_socketpair()による接続済みソケットペア作成のAPI定義 |

## 機能種別

ユーティリティ関数（ソケット生成）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| type | int | Yes | ソケットタイプ（SOCK_STREAM, SOCK_DGRAM等） | socketpair()システムコールが受け付ける値 |
| protocol | int | Yes | プロトコル番号（通常0） | socketpair()システムコールが受け付ける値 |
| socket_vector | uv_os_sock_t[2] | Yes | 作成されたソケットペアを格納する配列 | NULLでないこと |
| flags0 | int | Yes | 最初のソケットに適用するフラグ | UV_NONBLOCK_PIPEが使用可能 |
| flags1 | int | Yes | 2番目のソケットに適用するフラグ | UV_NONBLOCK_PIPEが使用可能 |

### 入力データソース

関数呼び出し時の引数として直接指定する。子プロセス生成時（uv_spawn()のstdio設定）では内部的にtype=SOCK_STREAM, protocol=0, flags0=0, flags1=0で呼び出される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 成功時0、失敗時は負のエラーコード |
| socket_vector[0] | uv_os_sock_t | 作成された最初のソケットディスクリプタ |
| socket_vector[1] | uv_os_sock_t | 作成された2番目のソケットディスクリプタ |

### 出力先

呼び出し元の配列（socket_vector）にソケットディスクリプタが格納される。

## 処理フロー

### 処理シーケンス

```
1. プラットフォーム判定
   └─ SOCK_NONBLOCK/SOCK_CLOEXEC定義の有無を確認

2a. (SOCK_NONBLOCK/SOCK_CLOEXEC対応プラットフォーム) atomicなソケットペア作成
   ├─ typeにSOCK_CLOEXECを付加
   ├─ 両方のフラグがUV_NONBLOCK_PIPEの場合、SOCK_NONBLOCKも付加
   └─ socketpair(AF_UNIX, flags, protocol, temp)を呼び出し

2b. (非対応プラットフォーム) フォールバック処理
   ├─ socketpair(AF_UNIX, type, protocol, temp)を呼び出し
   ├─ uv__cloexec(temp[0], 1)でCLOEXEC設定
   └─ uv__cloexec(temp[1], 1)でCLOEXEC設定

3. 個別のノンブロッキング設定
   ├─ flags0にUV_NONBLOCK_PIPEが設定されている場合、temp[0]をノンブロッキングに
   └─ flags1にUV_NONBLOCK_PIPEが設定されている場合、temp[1]をノンブロッキングに

4. 結果の格納
   ├─ fds[0] = temp[0]
   └─ fds[1] = temp[1]

5. エラー処理（failラベル）
   ├─ uv__close(temp[0])
   ├─ uv__close(temp[1])
   └─ エラーコードを返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{SOCK_NONBLOCK/SOCK_CLOEXEC<br>定義あり?}
    B -->|Yes| C[type | SOCK_CLOEXECでフラグ構成]
    B -->|No| D[socketpair AF_UNIX, type, protocol]
    C --> E{両方UV_NONBLOCK_PIPE?}
    E -->|Yes| F[SOCK_NONBLOCK追加]
    E -->|No| G[socketpair AF_UNIX, flags, protocol]
    F --> G
    G --> H{成功?}
    H -->|No| ERR[UV__ERR errno返却]
    H -->|Yes| I{両方NONBLOCK?}
    I -->|Yes| J[fds格納して返却]
    I -->|No| K[個別NONBLOCK設定]
    D --> L{成功?}
    L -->|No| ERR
    L -->|Yes| M[CLOEXEC設定]
    M --> N{成功?}
    N -->|No| FAIL[close and エラー返却]
    N -->|Yes| K
    K --> O{成功?}
    O -->|No| FAIL
    O -->|Yes| J
    J --> P[終了 return 0]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-71-01 | ドメイン固定 | ソケットペアは常にAF_UNIX（UNIXドメイン）で作成される | 常時 |
| BR-71-02 | CLOEXEC自動設定 | 作成されたソケットには常にclose-on-execフラグが設定される | 常時 |
| BR-71-03 | NONBLOCK個別制御 | 各ソケットのノンブロッキングモードはflags0/flags1で個別に制御可能 | UV_NONBLOCK_PIPEフラグ指定時 |
| BR-71-04 | atomic最適化 | SOCK_NONBLOCK/SOCK_CLOEXECをサポートするプラットフォームではatomicにフラグを設定 | Linux等の対応プラットフォーム |

### 計算ロジック

特段の計算ロジックはない。

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

### 操作別データベース影響一覧

本機能はデータベース操作を行わない。OSのソケットAPIを直接使用する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EMFILE | リソース枯渇 | プロセスのファイルディスクリプタ上限に達した | 不要なFDをクローズするか、rlimitを引き上げる |
| UV_ENFILE | リソース枯渇 | システム全体のファイルディスクリプタ上限に達した | システム設定を見直す |
| UV_EACCES | 権限エラー | ソケット作成の権限がない | 実行ユーザーの権限を確認する |
| UV_ENOBUFS | メモリ不足 | カーネルバッファが不足 | システムリソースを確認する |

### リトライ仕様

リトライは行わない。エラー発生時は即座にエラーコードを返す。エラー発生時は作成途中のソケットを確実にクローズする。

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

トランザクション管理は不要。ソケットペア作成はatomic操作（socketpairシステムコール）であり、部分的な成功は発生しない。ただし、フラグ設定段階でエラーが発生した場合は作成済みソケットのクリーンアップが行われる。

## パフォーマンス要件

socketpair()システムコールの実行時間は通常マイクロ秒オーダーである。ノンブロッキング設定やCLOEXEC設定はカーネル内で完結する軽量な操作である。

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

- close-on-execフラグにより、exec()呼び出し時にソケットが子プロセスに漏洩しない
- AF_UNIXドメインのため、ネットワーク経由のアクセスは不可能
- Linuxではatomicなフラグ設定によりTOCTOU（Time of Check to Time of Use）脆弱性を回避

## 備考

- Windows版では、socketpair()が存在しないため、listen/connect/acceptを使用してエミュレーションを行う（src/win/tcp.c L1631以降）
- 子プロセス生成時（src/unix/process.c L207）で内部的に使用される

---

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

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

### 推奨読解順序

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

uv_socketpair()はハンドル型を使用しない独立したユーティリティ関数であるため、主要な型はuv_os_sock_tのみである。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | **L514-518**: uv_socketpair()のAPI宣言。type, protocol, socket_vector[2], flags0, flags1の5パラメータを確認 |

**読解のコツ**: uv_os_sock_tはUnixではintのtypedef、WindowsではSOCKET（UINT_PTR）のtypedefである。プラットフォームによりサイズが異なる点に注意。

#### Step 2: エントリーポイントを理解する（Unix実装）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | tcp.c | `src/unix/tcp.c` | **L632-675**: Unix版uv_socketpair()の実装全体。TCPモジュール内にあるが、AF_UNIXソケットペアを作成する |

**主要処理フロー**:
1. **632行目**: 関数定義。type, protocol, fds[2], flags0, flags1を受け取る
2. **635-649行目**: SOCK_NONBLOCK/SOCK_CLOEXEC対応プラットフォームのatomic処理パス
3. **651-657行目**: 非対応プラットフォームのフォールバックパス（手動CLOEXEC設定）
4. **660-665行目**: 各ソケットへの個別ノンブロッキング設定
5. **671-674行目**: エラー時のクリーンアップ（failラベル）

#### Step 3: Windows実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | tcp.c | `src/win/tcp.c` | **L1631以降**: Windows版uv_socketpair()。listen/connect/acceptによるエミュレーション実装 |

**主要処理フロー**:
- **1631行目**: Windows版はsocketpair()が存在しないため、ループバックアドレスでlisten→connect→acceptを行ってソケットペアを生成する

#### Step 4: 呼び出し元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | process.c | `src/unix/process.c` | **L202-212**: uv_spawn()のstdio設定でUV_CREATE_PIPE指定時にuv_socketpair(SOCK_STREAM, 0, fds, 0, 0)として呼び出される |

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

```
uv_socketpair()                         [src/unix/tcp.c L632]
    |
    +-- socketpair(AF_UNIX, ...)         [システムコール]
    |
    +-- uv__cloexec()                    [フォールバック時のCLOEXEC設定]
    |
    +-- uv__nonblock()                   [個別ノンブロッキング設定]
    |
    +-- uv__close()                      [エラー時クリーンアップ]

呼び出し元:
uv_spawn() --> uv__process_init_stdio() --> uv_socketpair()
                                            [src/unix/process.c L207]
```

### データフロー図

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

type (SOCK_STREAM等) ──────> socketpair()システムコール ──> socket_vector[0] (ソケットFD)
protocol (0等) ─────────────> AF_UNIXドメインで生成   ──> socket_vector[1] (ソケットFD)
flags0 (UV_NONBLOCK_PIPE) ─> ノンブロッキング設定     ──> 戻り値 (0 or エラーコード)
flags1 (UV_NONBLOCK_PIPE) ─> ノンブロッキング設定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | uv_socketpair()のAPI宣言（L514-518） |
| tcp.c | `src/unix/tcp.c` | ソース | Unix版uv_socketpair()実装（L632-675） |
| tcp.c | `src/win/tcp.c` | ソース | Windows版uv_socketpair()実装（L1631以降） |
| process.c | `src/unix/process.c` | ソース | 子プロセスstdio設定からの呼び出し元（L207） |
