# 機能設計書 40-TCPバインド

## 概要

本ドキュメントは、libuvにおけるTCPバインド機能（uv_tcp_bind()）の設計仕様を記述する。TCPソケットを指定アドレスにバインドし、IPv6only、REUSEPORTオプションに対応する。

### 本機能の処理概要

**業務上の目的・背景**：TCPサーバーがクライアントからの接続を受け付けるためには、まずソケットを特定のIPアドレスとポート番号にバインドする必要がある。uv_tcp_bind()はこのバインド操作を行い、IPV6ONLYやSO_REUSEPORTなどのソケットオプションも同時に設定する。SO_REUSEPORTは複数のプロセスが同一ポートをリッスンし、カーネルによる接続の負荷分散を実現する機能である。

**機能の利用シーン**：TCPサーバーの構築時にuv_tcp_init()の後、uv_listen()の前に呼び出す。ポート番号0を指定することでOSにポートを自動選択させることも可能。

**主要な処理内容**：
1. ハンドル型チェック（UV_TCPであること）
2. クローズ中チェック
3. アドレスファミリに応じたaddrlen計算
4. uv__tcp_bind()の呼び出し
5. SO_REUSEADDRオプションの設定
6. UV_TCP_REUSEPORTフラグ処理
7. IPv6の場合のIPV6_V6ONLYオプション設定
8. bind()システムコールの実行
9. UV_HANDLE_BOUNDフラグとUV_HANDLE_IPV6フラグの設定

**関連システム・外部連携**：OSのbind()、setsockopt()システムコール。

**権限による制御**：特権ポート（1024未満）にバインドするにはroot権限が必要な場合がある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 18 | TCP | 主機能 | uv_tcp_bind()によるTCPソケットバインドのAPI定義（IPv6only・REUSEPORT対応） |
| 35 | ネットワーク | 参照画面 | TCPサーバーのアドレスバインド処理の使用例 |

## 機能種別

ソケット設定処理（アドレスバインド）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| handle | uv_tcp_t* | Yes | TCPハンドル | type == UV_TCPであること |
| addr | const struct sockaddr* | Yes | バインド先アドレス | AF_INETまたはAF_INET6 |
| flags | unsigned int | Yes | オプションフラグ | UV_TCP_IPV6ONLY, UV_TCP_REUSEPORT, または0 |

### 入力データソース

アプリケーションコードからの直接呼び出し。アドレス構造体はuv_ip4_addr()/uv_ip6_addr()で作成可能。

## 出力仕様

### 出力データ

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

### 出力先

TCPソケットが指定アドレスにバインドされる。

## 処理フロー

### 処理シーケンス

```
1. uv_tcp_bind()（uv-common.c内）
   ├─ handle->type != UV_TCP → UV_EINVAL
   ├─ クローズ中チェック → UV_EINVAL
   ├─ sa_familyに応じたaddrlen計算
   │     ├─ AF_INET → sizeof(struct sockaddr_in)
   │     └─ AF_INET6 → sizeof(struct sockaddr_in6)
   │     └─ その他 → UV_EINVAL
   └─ uv__tcp_bind()呼び出し

2. uv__tcp_bind()（unix/tcp.c内）
   ├─ IPv6only制約チェック（非IPv6でIPV6ONLYフラグ→UV_EINVAL）
   ├─ maybe_new_socket()でソケット作成（必要な場合）
   ├─ SO_REUSEADDRの設定
   ├─ UV_TCP_REUSEPORTの処理
   ├─ IPV6_V6ONLYの設定（IPv6の場合）
   ├─ bind()システムコール
   ├─ UV_HANDLE_BOUNDフラグ設定
   └─ IPv6の場合UV_HANDLE_IPV6フラグ設定
```

### フローチャート

```mermaid
flowchart TD
    A[uv_tcp_bind 呼び出し] --> B{型チェック}
    B -->|非TCP| C[UV_EINVAL]
    B -->|OK| D{クローズ中?}
    D -->|Yes| C
    D -->|No| E{sa_family}
    E -->|AF_INET| F[addrlen = sizeof sockaddr_in]
    E -->|AF_INET6| G[addrlen = sizeof sockaddr_in6]
    E -->|その他| C
    F --> H[uv__tcp_bind]
    G --> H
    H --> I{IPv6only & 非IPv6?}
    I -->|Yes| C
    I -->|No| J[maybe_new_socket]
    J --> K[SO_REUSEADDR 設定]
    K --> L{REUSEPORT?}
    L -->|Yes| M[SO_REUSEPORT 設定]
    L -->|No| N[skip]
    M --> O{IPv6?}
    N --> O
    O -->|Yes| P[IPV6_V6ONLY 設定]
    O -->|No| Q[skip]
    P --> R[bind syscall]
    Q --> R
    R --> S{成功?}
    S -->|Yes| T[BOUND/IPV6 フラグ設定]
    S -->|No| U[エラー返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-40-01 | SO_REUSEADDR | 常にSO_REUSEADDRが設定される | 常時 |
| BR-40-02 | IPV6ONLY制約 | UV_TCP_IPV6ONLYフラグはIPv6アドレスでのバインド時のみ有効 | IPv6使用時 |
| BR-40-03 | REUSEPORT | UV_TCP_REUSEPORTフラグでSO_REUSEPORTを設定（Linux 3.9+等のみ対応） | プラットフォーム依存 |
| BR-40-04 | delayed_error | bind()がEADDRINUSEを返した場合、即座にエラーを返さずdelayed_errorに保存する | EADDRINUSE発生時 |
| BR-40-05 | 遅延ソケット作成 | バインド時にソケットが未作成の場合、maybe_new_socket()で自動作成される | ソケット未作成時 |

### 計算ロジック

特になし。

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

該当なし。

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

該当なし。

### テーブル別操作詳細

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | 入力エラー | 非TCPハンドル、クローズ中、不正アドレスファミリ、非IPv6でIPV6ONLY | パラメータを修正 |
| UV_EADDRINUSE | アドレスエラー | アドレスが既に使用中（delayed_errorに保存） | SO_REUSEPORTの使用や別ポートの選択 |
| UV_EAFNOSUPPORT | アドレスエラー | BSDs/SunOSでAF_INETソケットにIPv6アドレスを使用 | 正しいアドレスファミリを使用 |
| errno系エラー | システムエラー | setsockopt()やbind()の失敗 | OS設定を確認 |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

- maybe_new_socket()による遅延ソケット作成でバインド時のオーバーヘッドが発生する場合がある
- SO_REUSEPORTを使用することで複数プロセス/スレッドでの負荷分散が可能

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

- 特権ポート（1024未満）へのバインドにはroot権限が必要
- SO_REUSEPORTの使用は意図したプロセスのみがバインドしていることを確認すること
- SO_REUSEADDRが常に設定されるため、TIME_WAIT状態のソケットを再利用できる

## 備考

- uv_tcp_bind()のバリデーション部分はuv-common.cに、実際のバインドロジックはunix/tcp.c（またはwin/tcp.c）に分離されている
- bind()がEADDRINUSEを返した場合、即座にエラーを返さずdelayed_errorに保存する設計により、connect()やlisten()時にエラーが検出される
- OpenBSD環境ではIPV6_V6ONLYの設定をスキップする（#ifndef __OpenBSD__）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | **612-626行目**: uv_tcp_flags列挙型（UV_TCP_IPV6ONLY=1, UV_TCP_REUSEPORT=2） |
| 1-2 | uv.h | `include/uv.h` | **628-630行目**: uv_tcp_bind()のAPI宣言 |

**読解のコツ**: flagsはビットフラグとして使用され、UV_TCP_IPV6ONLYとUV_TCP_REUSEPORTを組み合わせて指定可能。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | uv-common.c | `src/uv-common.c` | **324-342行目**: uv_tcp_bind()のプラットフォーム共通バリデーション |

**主要処理フロー**:
1. **329-330行目**: handle->type != UV_TCPチェック
2. **331-333行目**: uv__is_closing()チェック
3. **334-339行目**: sa_familyに応じたaddrlen計算
4. **341行目**: uv__tcp_bind()に委譲

#### Step 3: プラットフォーム固有のバインド処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | tcp.c | `src/unix/tcp.c` | **151-211行目**: uv__tcp_bind()のUnix実装 |

**主要処理フロー**:
- **159-160行目**: IPv6onlyの制約チェック
- **162-164行目**: maybe_new_socket()でソケット遅延作成
- **166-168行目**: SO_REUSEADDR設定
- **170-174行目**: UV_TCP_REUSEPORT処理
- **178-193行目**: IPV6_V6ONLY設定（IPv6時、OpenBSD除外）
- **196行目**: bind()システムコール
- **204行目**: delayed_error設定（EADDRINUSE時）
- **206-208行目**: UV_HANDLE_BOUND/UV_HANDLE_IPV6フラグ設定

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

```
uv_tcp_bind(handle, addr, flags)  [uv-common.c]
    ├─ バリデーション（型、クローズ中、アドレスファミリ）
    └─ uv__tcp_bind(tcp, addr, addrlen, flags)  [unix/tcp.c]
           ├─ IPv6only制約チェック
           ├─ maybe_new_socket(tcp, addr->sa_family, 0)
           │      └─ new_socket(handle, domain, flags)
           │             ├─ uv__socket(domain, SOCK_STREAM, 0)
           │             └─ uv__stream_open(stream, sockfd, flags)
           ├─ setsockopt(SO_REUSEADDR)
           ├─ uv__sock_reuseport() [REUSEPORT時]
           ├─ setsockopt(IPV6_V6ONLY) [IPv6時]
           └─ bind(fd, addr, addrlen)
```

### データフロー図

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

handle, addr, flags  ───▶ uv_tcp_bind()                ───▶ 0 or エラー
                           │
                           ├─ バリデーション
                           ├─ maybe_new_socket()
                           ├─ setsockopt(SO_REUSEADDR)
                           ├─ setsockopt(SO_REUSEPORT) [opt]
                           ├─ setsockopt(IPV6_V6ONLY) [opt]
                           └─ bind() syscall ───▶ ソケットがアドレスにバインド
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | uv_tcp_bind()のAPI宣言とuv_tcp_flags定義 |
| uv-common.c | `src/uv-common.c` | ソース | プラットフォーム共通のバリデーション |
| tcp.c | `src/unix/tcp.c` | ソース | Unix版uv__tcp_bind()の実装 |
| tcp.c | `src/win/tcp.c` | ソース | Windows版uv__tcp_bind()の実装 |
