# 機能設計書 24-ハンドルタイプ推定

## 概要

本ドキュメントは、libuv の `uv_guess_handle()` 関数によるファイルディスクリプタからのハンドルタイプ推定機能の設計を記述する。

### 本機能の処理概要

本機能は、OSのファイルディスクリプタ（FD）を調査し、そのFDが表現するリソースの種類に基づいて、適切な`uv_handle_type`を推定・返却する。TTY、ソケット（TCP/UDP）、パイプ、通常ファイルなどの判定を行う。

**業務上の目的・背景**：標準入出力や外部から渡されたFDをlibuvハンドルとして扱う際、そのFDがどの種類のリソースを指しているかを事前に判定する必要がある。例えばNode.jsでは、プロセス起動時に標準入出力のFDがTTYなのかパイプなのかを判定し、適切なハンドル型でラップするために本機能が使用される。

**機能の利用シーン**：
- 標準入出力（stdin/stdout/stderr）のハンドル型を判定する場合
- 外部から継承したFDの種類を判定する場合
- uv_tty_init()内部でFDの種類を検証する場合
- uv_pipe_pending_type()で受信したFDの種類を判定する場合

**主要な処理内容**：
1. FDの有効性チェック（負値チェック）
2. isatty()によるTTY判定
3. fstat()によるファイル種別判定（通常ファイル、キャラクタデバイス、FIFO、ソケット）
4. getsockname()によるソケットファミリ判定
5. getsockopt(SO_TYPE)によるソケットタイプ判定（DGRAM→UDP、STREAM→TCP/PIPE）

**関連システム・外部連携**：OS固有のシステムコール（isatty, fstat, getsockname, getsockopt）を使用。プラットフォームごとに実装が異なる（Unix: src/unix/tty.c、Windows: src/win/handle.c）。

**権限による制御**：なし。ただしFDへのアクセス権が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 29 | その他ユーティリティ | 主画面 | uv_guess_handle()によるFDからのハンドルタイプ推定のAPI定義 |

## 機能種別

情報取得処理（FDのリソース種類に基づくハンドルタイプの推定）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| file | uv_file | Yes | 推定対象のファイルディスクリプタ | 0以上の有効なFD |

### 入力データソース

呼び出し元から直接引数として渡される。OSから取得したファイルディスクリプタ。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | uv_handle_type | 推定されたハンドルタイプ。判定不能の場合はUV_UNKNOWN_HANDLE |

返却される可能性がある型：UV_TTY, UV_FILE, UV_NAMED_PIPE, UV_TCP, UV_UDP, UV_UNKNOWN_HANDLE

### 出力先

関数の戻り値として呼び出し元に返却される。

## 処理フロー

### 処理シーケンス

```
1. FDの有効性チェック
   └─ file < 0 の場合、UV_UNKNOWN_HANDLE を返却
2. TTY判定
   └─ isatty(file) が真の場合、UV_TTY を返却
3. fstat()によるファイル種別判定
   ├─ S_ISREG: UV_FILE を返却（通常ファイル）
   ├─ S_ISCHR: UV_FILE を返却（キャラクタデバイス）
   ├─ S_ISFIFO: UV_NAMED_PIPE を返却
   └─ !S_ISSOCK: UV_UNKNOWN_HANDLE を返却
4. getsockname()によるソケットアドレス取得
   └─ 失敗時: UV_UNKNOWN_HANDLE を返却（プラットフォーム固有の例外あり）
5. getsockopt(SO_TYPE)によるソケットタイプ判定
   ├─ SOCK_DGRAM + AF_INET/AF_INET6: UV_UDP を返却
   ├─ SOCK_STREAM + AF_INET/AF_INET6: UV_TCP を返却
   ├─ SOCK_STREAM + AF_UNIX: UV_NAMED_PIPE を返却
   └─ その他: UV_UNKNOWN_HANDLE を返却
```

### フローチャート

```mermaid
flowchart TD
    A[uv_guess_handle] --> B{file < 0?}
    B -->|Yes| Z1[UV_UNKNOWN_HANDLE]
    B -->|No| C{isatty?}
    C -->|Yes| Z2[UV_TTY]
    C -->|No| D{fstat成功?}
    D -->|No| Z3[UV_UNKNOWN_HANDLE]
    D -->|Yes| E{ファイル種別}
    E -->|S_ISREG| Z4[UV_FILE]
    E -->|S_ISCHR| Z5[UV_FILE]
    E -->|S_ISFIFO| Z6[UV_NAMED_PIPE]
    E -->|S_ISSOCK| F{getsockname成功?}
    E -->|その他| Z7[UV_UNKNOWN_HANDLE]
    F -->|No| Z8[UV_UNKNOWN_HANDLE]
    F -->|Yes| G{getsockopt SO_TYPE}
    G -->|SOCK_DGRAM + INET| Z9[UV_UDP]
    G -->|SOCK_STREAM + INET| Z10[UV_TCP]
    G -->|SOCK_STREAM + AF_UNIX| Z11[UV_NAMED_PIPE]
    G -->|その他| Z12[UV_UNKNOWN_HANDLE]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-24-01 | 負値FD拒否 | 負のFDに対してはUV_UNKNOWN_HANDLEを返す | file < 0 |
| BR-24-02 | TTY優先判定 | isatty()チェックがfstat()より先に実行される | 常時 |
| BR-24-03 | プラットフォーム固有処理 | AIXではgetsockname失敗時にEINVALの場合UV_TCPを返す | AIXプラットフォーム |
| BR-24-04 | IBMi固有処理 | PASEではfstat失敗時にgetsockname/EINVAL判定でUV_TCPを返す | IBMi PASEプラットフォーム |

### 計算ロジック

特別な計算ロジックはない。OS APIの結果に基づく判定ロジック。

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

データベース操作は存在しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_UNKNOWN_HANDLE | 判定不能 | FDが不正、またはリソース種別が判定できない場合 | 呼び出し元で戻り値を確認し適切に処理 |

### リトライ仕様

リトライは不要。

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

トランザクションは存在しない。

## パフォーマンス要件

isatty()、fstat()、getsockname()、getsockopt()のシステムコールを使用するため、純粋な情報取得関数と比べると負荷は大きいが、通常は初期化時のみに呼ばれるため問題とならない。

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

- FDの有効性を確認する前にシステムコールが呼ばれるが、不正なFDに対してはエラーが返されるのみで危険はない。

## 備考

- Unix実装とWindows実装で判定ロジックが大きく異なる。Unix版は`src/unix/tty.c`に、Windows版は`src/win/handle.c`に実装されている。
- `uv_tty_init()`内部や`uv_pipe_pending_type()`の内部で呼び出される。
- キャラクタデバイス（/dev/randomなど）はUV_FILEとして返される。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | uv_handle_type列挙型（L198-205）。返却可能な全型の定義 |
| 1-2 | uv.h | `include/uv.h` | uv_guess_handle()の関数宣言（L856） |

**読解のコツ**: 返却されるuv_handle_typeの値は、実際にはUV_TTY、UV_FILE、UV_NAMED_PIPE、UV_TCP、UV_UDP、UV_UNKNOWN_HANDLEの6種類に限定される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | tty.c | `src/unix/tty.c` | uv_guess_handle()のUnix実装（L394-475）。FDの種別判定ロジック全体 |

**主要処理フロー**:
1. **400-401行目**: 負値FDチェック
2. **403-404行目**: isatty()によるTTY判定
3. **406-423行目**: fstat()によるファイル情報取得（IBMi PASE固有処理含む）
4. **425-435行目**: S_ISREG/S_ISCHR/S_ISFIFO/S_ISSOCKによるファイル種別判定
5. **437-452行目**: getsockname()によるソケットアドレス取得（AIX固有処理含む）
6. **454-475行目**: getsockopt(SO_TYPE)でSOCK_DGRAM/SOCK_STREAMを判定し、アドレスファミリと合わせてUDP/TCP/PIPEを返却

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | handle.c | `src/win/handle.c` | uv_guess_handle()のWindows実装（L31以降）。GetFileType()/GetConsoleMode()を使用 |

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

```
uv_guess_handle(file)   [Unix実装]
    │
    ├─ isatty(file)
    │
    ├─ uv__fstat(file, &s)
    │      └─ fstat(file, &s)
    │
    ├─ getsockname(file, ...)
    │
    └─ getsockopt(file, SOL_SOCKET, SO_TYPE, ...)
```

### データフロー図

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

uv_file (FD) ───▶ isatty() ───▶ TTY判定
                 ───▶ fstat()  ───▶ ファイル種別判定
                 ───▶ getsockname() ───▶ ソケット判定 ───▶ uv_handle_type
                 ───▶ getsockopt()  ───▶ TCP/UDP判定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | 関数宣言（L856） |
| tty.c | `src/unix/tty.c` | ソース | Unix実装（L394-475） |
| handle.c | `src/win/handle.c` | ソース | Windows実装（L31以降） |
| pipe.c | `src/unix/pipe.c` | ソース | uv_pipe_pending_type()からの呼び出し元（L444） |
