# 機能設計書 50-UDP接続

## 概要

本ドキュメントは、libuv の `uv_udp_connect()` APIによりUDPソケットをリモートアドレスに接続（関連付け）する機能の設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：UDPはコネクションレスプロトコルだが、connect()を呼び出すことで特定のリモートアドレスに関連付けることができる。これにより、送信時にアドレスを毎回指定する必要がなくなり、かつ指定アドレス以外からのパケットはカーネルレベルでフィルタリングされる。また、ICMPエラーの受信も可能になる。切断（アドレスの関連付け解除）もサポートする。

**機能の利用シーン**：特定のサーバーとのみ通信するUDPクライアント、DNSクエリ、STUNプロトコル、VPN接続、ゲームクライアントなど、固定の相手先と通信する場合に使用される。切断はサーバー切り替え時などに使用される。

**主要な処理内容**：
1. ハンドル型チェック（UV_UDP）
2. 切断処理（addr == NULL時）
   - 接続状態チェック（未接続時はUV_ENOTCONN）
   - uv__udp_disconnect()呼び出し
3. 接続処理（addr != NULL時）
   - アドレスファミリ検証とaddrlen算出
   - 二重接続チェック（既接続時はUV_EISCONN）
   - 遅延バインド（必要時）
   - connect()システムコール発行
   - UV_HANDLE_UDP_CONNECTEDフラグ設定

**関連システム・外部連携**：OSのconnect()システムコールを使用する。

**権限による制御**：特別な権限制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 21 | UDP | 主機能 | uv_udp_connect()によるUDPリモートアドレス接続のAPI定義 |

## 機能種別

ネットワーク設定（ソケット接続/切断）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| handle | uv_udp_t* | Yes | 初期化済みUDPハンドル | handle->type == UV_UDP |
| addr | const struct sockaddr* | No | 接続先アドレス。NULLの場合は切断 | NULL or sa_family == AF_INET/AF_INET6 |

### 入力データソース

アプリケーションから直接呼び出される。

## 出力仕様

### 出力データ

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

### 出力先

戻り値として直接返却。

## 処理フロー

### 処理シーケンス

```
1. 型チェック（uv-common.c）
   └─ handle->type != UV_UDP → UV_EINVAL
2. addr == NULLの場合（切断）
   ├─ 未接続チェック → UV_ENOTCONN
   └─ uv__udp_disconnect()呼び出し
3. addr != NULLの場合（接続）
   ├─ アドレスファミリチェック・addrlen算出
   ├─ 既接続チェック → UV_EISCONN
   └─ uv__udp_connect()呼び出し
      ├─ 遅延バインド（uv__udp_maybe_deferred_bind）
      ├─ connect()システムコール
      └─ UV_HANDLE_UDP_CONNECTEDフラグ設定
```

### フローチャート

```mermaid
flowchart TD
    A[uv_udp_connect 呼び出し] --> B{handle->type == UV_UDP?}
    B -->|No| C[UV_EINVAL返却]
    B -->|Yes| D{addr == NULL?}
    D -->|Yes| E{UV_HANDLE_UDP_CONNECTED?}
    E -->|No| F[UV_ENOTCONN返却]
    E -->|Yes| G[uv__udp_disconnect呼び出し]
    D -->|No| H{addr->sa_family有効?}
    H -->|No| C
    H -->|Yes| I{既に接続済み?}
    I -->|Yes| J[UV_EISCONN返却]
    I -->|No| K[uv__udp_connect呼び出し]
    K --> L[遅延バインド]
    L --> M[connect システムコール]
    M --> N{成功?}
    N -->|No| O[エラー返却]
    N -->|Yes| P[UV_HANDLE_UDP_CONNECTED設定]
    P --> Q[0 を返す]
    G --> Q
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-50-1 | NULL切断 | addr==NULLで切断（アドレス関連付け解除）を行う | addr == NULL |
| BR-50-2 | 未接続切断禁止 | 未接続状態で切断を試みるとUV_ENOTCONNを返す | addr == NULL && !(flags & UV_HANDLE_UDP_CONNECTED) |
| BR-50-3 | 二重接続禁止 | 既に接続済みの場合はUV_EISCONNを返す | addr != NULL && (flags & UV_HANDLE_UDP_CONNECTED) |
| BR-50-4 | 遅延バインド | ソケット未作成時はアドレスファミリに基づいて自動バインドする | handle->io_watcher.fd == -1 |
| BR-50-5 | BSD切断特殊処理 | BSDではAF_UNSPECでの切断時にEAFNOSUPPORT/EINVALが返される場合があるが、成功として扱う | BSD系プラットフォーム |

### 計算ロジック

特になし。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | バリデーションエラー | ハンドル型不正、アドレスファミリ不正 | 正しいパラメータを指定する |
| UV_ENOTCONN | 状態エラー | 未接続状態で切断を試みた | 接続後に切断する |
| UV_EISCONN | 状態エラー | 既に接続済みの状態で接続を試みた | まず切断してから再接続する |
| UV__ERR(errno) | システムエラー | connect()が失敗 | ネットワーク状態を確認する |

### リトライ仕様

connect()システムコールがEINTRを返した場合は自動的にリトライする。

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

該当なし。

## パフォーマンス要件

同期的に即座に完了する操作。

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

接続（関連付け）によりカーネルレベルでのパケットフィルタリングが有効になるため、予期しないアドレスからのパケットを受信しなくなる。セキュリティの向上に寄与する。

## 備考

- UDPのconnect()は実際にネットワーク上で接続を確立するものではなく、カーネル内部でアドレスの関連付けを行うだけである。
- 切断処理のプラットフォーム差異が大きい（BSD: AF_UNSPECで再connect、AIX: NULLで再connect、zOS: AF_UNSPECで再connect等）。コード内のコメント（573-603行目）に各プラットフォームの挙動が詳細に記述されている。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | uv_udp_connect()のAPI宣言（753行目） |
| 1-2 | uv.h | `include/uv.h` | uv_udp_s構造体（721-734行目） |

**読解のコツ**: UDPのconnect()はTCPのconnect()とは性質が異なり、アドレスの関連付けを行うだけで、addr=NULLで切断もできる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | uv-common.c | `src/uv-common.c` | uv_udp_connect()の共通実装（414-439行目） |

**主要処理フロー**:
1. **417-418行目**: handle->type != UV_UDP チェック
2. **421-426行目**: addr == NULL 時の切断処理（未接続チェック + uv__udp_disconnect()）
3. **428-433行目**: アドレスファミリチェックとaddrlen算出
4. **435-436行目**: 既接続チェック（UV_EISCONN）
5. **438行目**: uv__udp_connect()へ委譲

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | udp.c | `src/unix/udp.c` | uv__udp_connect()の実装（551-571行目） |
| 3-2 | udp.c | `src/unix/udp.c` | uv__udp_disconnect()の実装（604-645行目）。プラットフォーム別の切断ロジック |
| 3-3 | udp.c | `src/unix/udp.c` | uv__udp_maybe_deferred_bind()の実装（514-548行目）。遅延バインド処理 |

**主要処理フロー**:

uv__udp_connect():
- **556-558行目**: 遅延バインド（uv__udp_maybe_deferred_bind）
- **560-563行目**: connect()システムコール（EINTRリトライ）
- **565-566行目**: エラー時はUV__ERR(errno)返却
- **568行目**: UV_HANDLE_UDP_CONNECTEDフラグ設定

uv__udp_disconnect():
- **612行目**: memset(&addr, 0, sizeof(addr))
- **617行目**: addr.sa_family = AF_UNSPEC
- **620-632行目**: connect()呼び出し（IBMi/PASEではNULLアドレスを使用）
- **634-641行目**: BSDでのEAFNOSUPPORT/EINVALの特殊処理
- **643行目**: UV_HANDLE_UDP_CONNECTEDフラグクリア

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

```
uv_udp_connect() [src/uv-common.c:414]
    │
    ├─ [addr == NULL] uv__udp_disconnect() [src/unix/udp.c:604]
    │      │
    │      └─ connect(fd, AF_UNSPEC addr) [OS system call]
    │
    └─ [addr != NULL] uv__udp_connect() [src/unix/udp.c:551]
           │
           ├─ uv__udp_maybe_deferred_bind() [src/unix/udp.c:514]
           │      │
           │      └─ uv__udp_bind() [src/unix/udp.c:440]
           │
           └─ connect() [OS system call]
```

### データフロー図

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

uv_udp_t* handle           ──▶  uv_udp_connect()         ──▶  戻り値(0/エラー)
const sockaddr* addr       ──▶  ├ 型チェック
  (NULL = 切断)                 ├ [NULL] 切断処理
  (非NULL = 接続)               │  └ AF_UNSPEC connect
                                └ [非NULL] 接続処理
                                   ├ 遅延バインド
                                   └ connect()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | API宣言 |
| uv-common.c | `src/uv-common.c` | ソース | uv_udp_connect()共通実装、uv__udp_is_connected() |
| udp.c (unix) | `src/unix/udp.c` | ソース | uv__udp_connect(), uv__udp_disconnect(), uv__udp_maybe_deferred_bind()の実装 |
| udp.c (win) | `src/win/udp.c` | ソース | Windows固有の実装 |
| core.c | `src/unix/core.c` | ソース | uv__socket()の実装 |
