# 機能設計書 53-ポート確認

## 概要

本ドキュメントは、Nushellにおけるポート確認機能の設計仕様を記載する。この機能は、システム上で利用可能な空きTCPポートを取得するportコマンドを提供する。

### 本機能の処理概要

ポート確認機能は、ネットワークプログラミングやサービス起動時に必要となる空きポートを自動的に検出する。

**業務上の目的・背景**：ローカル開発環境でのサービス起動、テスト環境構築、動的なポート割り当てが必要な場面で、手動でポート番号を確認・指定する手間を省き、ポート競合を回避する。特にマイクロサービス開発やDockerコンテナの動的ポートマッピングで有用。

**機能の利用シーン**：
- ローカル開発サーバーの起動ポート決定
- テスト実行時の一時的なサーバー用ポート取得
- 複数サービスの並行起動時のポート競合回避
- CI/CDパイプラインでの動的ポート割り当て

**主要な処理内容**：
1. 範囲指定なしの場合、システムが自動で空きポートを割り当て
2. 範囲指定ありの場合、指定範囲内で空きポートを検索
3. Windowsの場合はTCPテーブルを参照して使用中ポートを除外

**関連システム・外部連携**：
- オペレーティングシステムのTCPスタック
- Windows: GetTcpTable2 API

**権限による制御**：特になし（一般ユーザーでも実行可能）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLI専用コマンド |

## 機能種別

システム情報取得

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| start | Int | No | 検索開始ポート番号（含む） | 0-65535の範囲、u16に変換可能 |
| end | Int | No | 検索終了ポート番号（含む） | 0-65535の範囲、start以上 |

### 入力データソース

コマンドライン引数

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (出力) | Int | 利用可能な空きポート番号 |

### 出力先

パイプライン出力

## 処理フロー

### 処理シーケンス

```
1. 引数解析
   └─ 開始ポート・終了ポートの取得
2. 範囲判定
   ├─ 範囲指定なし: システム提供ポート取得
   └─ 範囲指定あり: 指定範囲内検索
3. 空きポート検索
   ├─ Unix: TcpListener::bind()で確認
   └─ Windows: TCPテーブル参照
4. 結果返却
   └─ 空きポート番号をIntとして返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{範囲指定あり?}
    B -->|No| C[system_provided_port]
    B -->|Yes| D[範囲バリデーション]
    D --> E{start <= end?}
    E -->|No| F[InvalidRangeエラー]
    E -->|Yes| G{プラットフォーム}
    G -->|Unix| H[TcpListener::bindで検索]
    G -->|Windows| I[GetTcpTable2でTCPテーブル取得]
    H --> J[空きポート発見?]
    I --> K[使用中ポート除外]
    K --> J
    J -->|No| L[エラー: 空きポートなし]
    J -->|Yes| M[ポート番号返却]
    C --> N[ポート番号取得]
    N --> M
    M --> O[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルト範囲 | start未指定時は1024、end未指定時は65535 | 片方のみ指定時 |
| BR-02 | localhost限定 | 127.0.0.1でバインドを試行 | 全ての検索 |
| BR-03 | 範囲昇順制約 | start > endの場合はエラー | 範囲指定時 |
| BR-04 | Windows特別処理 | TCPテーブル参照（二重バインド対策） | Windows環境 |

### 計算ロジック

特になし

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| CantConvert | 型変換エラー | ポート番号がu16範囲外 | 0-65535の値を指定 |
| InvalidRange | 範囲エラー | start > end | 正しい範囲を指定 |
| IoError | I/Oエラー | 全ポートが使用中 | 範囲を広げるか時間を置く |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

特になし（ポート検索は高速）

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

- ポートスキャンとして悪用可能なため、本番環境での使用は限定的にすべき
- 1024未満のポートは管理者権限が必要な場合がある

## 備考

- Windowsでは`SO_REUSEADDR`によりポートの重複バインドが可能なため、TCPテーブル参照方式を採用
- Unix系ではTcpListener::bind()の成否で空きを判定

---

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

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

### 推奨読解順序

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

ポート確認機能は単純な整数を扱うため、特別なデータ構造はない。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | port.rs | `crates/nu-command/src/network/port.rs` | Portコマンドのシグネチャ確認 |

**読解のコツ**:
- **14-24行目**: シグネチャでオプショナルなstart/endパラメータを定義

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | port.rs | `crates/nu-command/src/network/port.rs` | run()メソッドとget_free_port() |

**主要処理フロー**:
- **34-42行目**: run()でget_free_port()を呼び出し
- **60-127行目**: get_free_port()で引数解析と処理分岐

#### Step 3: プラットフォーム別実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | port.rs | `crates/nu-command/src/network/port.rs` | Unix/Windows別の検索ロジック |

**主要処理フロー（Unix）**:
- **129-133行目**: system_provided_port()で`127.0.0.1:0`にバインド
- **137-165行目**: search_port_in_range()で範囲内検索

**主要処理フロー（Windows）**:
- **168-316行目**: windowsモジュール内のTCPテーブル参照
- **191-248行目**: TcpTable::new()でGetTcpTable2 API呼び出し
- **263-315行目**: search_port_in_range()でTCPテーブルから使用中ポートを除外

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

```
port コマンド
    │
    ├─ get_free_port()
    │      │
    │      ├─ 範囲指定なし
    │      │      └─ system_provided_port()
    │      │             └─ TcpListener::bind("127.0.0.1:0")
    │      │
    │      └─ 範囲指定あり
    │             ├─ [Unix] search_port_in_range()
    │             │         └─ TcpListener::bind() (各ポート試行)
    │             │
    │             └─ [Windows] windows::search_port_in_range()
    │                       ├─ TcpTable::new()
    │                       │     └─ GetTcpTable2() (Win32 API)
    │                       └─ HashSet<u16> で使用中ポート管理
    │
    └─ Value::int() で結果返却
```

### データフロー図

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

(なし) ─────────────────▶ system_provided_port() ───────▶ Int (ポート番号)

start, end ─────────────▶ 範囲バリデーション
     │                            │
     └─ 有効な範囲 ───────────────▶ search_port_in_range()
                                  │
                                  ├─ [Unix] TcpListener試行 ─▶ Int
                                  └─ [Windows] TCPテーブル参照 ─▶ Int
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| port.rs | `crates/nu-command/src/network/port.rs` | ソース | portコマンドの実装 |
