# 機能設計書 54-UDP受信開始・停止

## 概要

本ドキュメントは、libuvにおけるUDP受信制御機能（`uv_udp_recv_start()` / `uv_udp_recv_stop()`）の設計仕様を記述する。UDPデータグラムの非同期受信を開始・停止する。

### 本機能の処理概要

**業務上の目的・背景**：UDPプロトコルでネットワークからデータグラムを受信するために、非同期のイベント駆動型受信メカニズムが必要である。受信開始時にアロケーションコールバックと受信コールバックを登録し、データグラム到着時にイベントループから通知を受ける。不要になった受信を停止する機能も提供する。

**機能の利用シーン**：
- UDPサーバーでのクライアントからのデータ受信
- DNS応答の受信
- マルチキャストデータの受信
- リアルタイム通信でのデータ受信ループ

**主要な処理内容**：
1. recv_start: コールバック登録、I/Oウォッチャー開始、ハンドルアクティブ化
2. recv_stop: I/Oウォッチャー停止、コールバック解除
3. データ到着時: alloc_cbでバッファ取得 → recvmsg/recvmmsg → recv_cb呼び出し
4. recvmmsg対応プラットフォームではバッチ受信

**関連システム・外部連携**：OSのソケットAPI（recvmsg/recvmmsg）、イベントループのI/Oウォッチャー。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 21 | UDP | 主機能 | uv_udp_recv_start()/uv_udp_recv_stop()によるUDP受信制御のAPI定義 |
| 35 | ネットワーク | 補助機能 | UDPデータグラム受信の使用例 |

## 機能種別

データ受信 / 非同期I/O

## 入力仕様

### 入力パラメータ

#### uv_udp_recv_start()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| handle | uv_udp_t* | Yes | UDPハンドル | handle->typeがUV_UDPであること |
| alloc_cb | uv_alloc_cb | Yes | バッファ確保コールバック | NULLでないこと |
| recv_cb | uv_udp_recv_cb | Yes | 受信コールバック | NULLでないこと |

#### uv_udp_recv_stop()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| handle | uv_udp_t* | Yes | UDPハンドル | handle->typeがUV_UDPであること |

### 入力データソース

ネットワークから到着するUDPデータグラム。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 成功時は0、失敗時は負のエラーコード |
| recv_cb nread | ssize_t | 受信バイト数（0はデータなし、負はエラー） |
| recv_cb buf | const uv_buf_t* | alloc_cbで確保されたバッファ |
| recv_cb addr | const struct sockaddr* | 送信元アドレス |
| recv_cb flags | unsigned | UV_UDP_PARTIAL, UV_UDP_MMSG_CHUNK等 |

### 出力先

受信データはrecv_cbコールバックを通じてアプリケーションに通知される。

## 処理フロー

### 処理シーケンス

```
[recv_start]
1. パラメータ検証
   ├─ handle->typeがUV_UDPか確認
   ├─ alloc_cbがNULLでないか確認
   └─ recv_cbがNULLでないか確認
2. 既に受信中でないか確認（POLLINアクティブ → UV_EALREADY）
3. 遅延バインド（AF_INET、フラグなし）
4. コールバック登録（handle->alloc_cb, handle->recv_cb）
5. POLLINのI/Oウォッチャー開始
6. ハンドルをアクティブ化

[recv_stop]
1. handle->typeがUV_UDPか確認
2. POLLINのI/Oウォッチャー停止
3. POLLOUTもアクティブでなければハンドルを非アクティブ化
4. コールバックをNULLに設定

[データ到着時]
1. alloc_cbでバッファ確保
2. recvmmsg使用判定 → バッチ受信 or 単一受信
3. recvmsg()でデータ受信
4. MSG_TRUNCフラグチェック → UV_UDP_PARTIAL設定
5. recv_cbでアプリケーションに通知
6. 最大32回まで繰り返し（ループ飢餓防止）
```

### フローチャート

```mermaid
flowchart TD
    A[uv_udp_recv_start] --> B{パラメータ有効?}
    B -->|No| Z1[UV_EINVAL]
    B -->|Yes| C{既に受信中?}
    C -->|Yes| Z2[UV_EALREADY]
    C -->|No| D[遅延バインド]
    D --> E[コールバック登録]
    E --> F[POLLIN開始]
    F --> G[ハンドルアクティブ化]
    G --> H[0を返却]

    I[データ到着] --> J[alloc_cb呼び出し]
    J --> K{バッファ取得成功?}
    K -->|No| L[recv_cb UV_ENOBUFS]
    K -->|Yes| M{recvmmsg使用?}
    M -->|Yes| N[recvmmsg バッチ受信]
    M -->|No| O[recvmsg 単一受信]
    N --> P[recv_cb呼び出し]
    O --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-54-01 | ループ飢餓防止 | 1回のイベントで最大32回まで受信を繰り返す | 常時 |
| BR-54-02 | alloc_cb必須 | バッファ確保はアプリケーション責任 | recv_start時 |
| BR-54-03 | recvmmsg最適化 | UV_UDP_RECVMMSGフラグ設定時にバッチ受信 | Linux/FreeBSD/macOS |
| BR-54-04 | 部分受信通知 | MSG_TRUNCの場合はUV_UDP_PARTIALフラグを設定 | データ受信時 |
| BR-54-05 | MMSGチャンク通知 | recvmmsg使用時はUV_UDP_MMSG_CHUNKフラグで個別通知 | recvmmsg時 |

### 計算ロジック

特になし。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータ不正 | handle->typeがUV_UDPでない / alloc_cbかrecv_cbがNULL | パラメータを修正 |
| UV_EALREADY | 既に実行中 | 受信が既に開始されている | 先にrecv_stopを呼ぶ |
| UV_ENOBUFS | バッファ不足 | alloc_cbがNULLバッファを返した場合 | alloc_cbで有効なバッファを返す |

### リトライ仕様

recv_start自体のリトライは不要。受信エラーはrecv_cbを通じて通知され、受信は自動的に継続される。

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

該当なし。

## パフォーマンス要件

- recvmmsg対応プラットフォームでは最大20メッセージのバッチ受信
- ループ飢餓防止のため1イベントあたり最大32回の受信制限
- alloc_cbで適切なバッファサイズ（UV__UDP_DGRAM_MAXSIZE推奨）を返すことが重要

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

- 受信データの内容バリデーションはアプリケーション側の責任
- 送信元アドレスの検証もアプリケーション側で行う必要がある

## 備考

- recv_cbのnread=0, addr=NULLは受信データなしを示す（エラーではない）
- Linuxのみ: IP_RECVERR/IPV6_RECVERRが有効な場合、ICMPエラーメッセージもrecv_cbで通知される（UV_UDP_LINUX_RECVERRフラグ）
- recvmmsg使用時は最後にUV_UDP_MMSG_FREEフラグ付きコールバックが呼ばれ、元バッファの解放タイミングを通知する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | **L714-718行目**: uv_udp_recv_cb型定義。nread, buf, addr, flagsパラメータ |
| 1-2 | uv.h | `include/uv.h` | **L660-670行目**: UV_UDP_PARTIAL等のrecvフラグ定義 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | uv-common.c | `src/uv-common.c` | **L536-543行目**: uv_udp_recv_start() - 型チェック後にuv__udp_recv_start呼び出し |
| 2-2 | uv-common.c | `src/uv-common.c` | **L546-551行目**: uv_udp_recv_stop() - 型チェック後にuv__udp_recv_stop呼び出し |

#### Step 3: プラットフォーム固有の受信制御を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | udp.c (unix) | `src/unix/udp.c` | **L1301-1323行目**: uv__udp_recv_start() - 遅延バインド、コールバック設定、POLLIN開始 |
| 3-2 | udp.c (unix) | `src/unix/udp.c` | **L1326-1336行目**: uv__udp_recv_stop() - POLLIN停止、コールバッククリア |
| 3-3 | udp.c (unix) | `src/unix/udp.c` | **L281-359行目**: uv__udp_recvmsg() - 単一メッセージ受信ループ |
| 3-4 | udp.c (unix) | `src/unix/udp.c` | **L196-279行目**: uv__udp_recvmmsg() - バッチ受信実装 |

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

```
uv_udp_recv_start(handle, alloc_cb, recv_cb)
    └─ uv__udp_recv_start(handle, alloc_cb, recv_cb)
           ├─ uv__udp_maybe_deferred_bind(handle, AF_INET, 0)
           ├─ handle->alloc_cb = alloc_cb
           ├─ handle->recv_cb = recv_cb
           ├─ uv__io_start(loop, &io_watcher, POLLIN)
           └─ uv__handle_start(handle)

[データ到着時]
uv__udp_io(loop, w, revents)  [POLLIN]
    └─ uv__udp_recvmsg(handle, 0)
           ├─ alloc_cb(handle, UV__UDP_DGRAM_MAXSIZE, &buf)
           ├─ [recvmmsg有効時] uv__udp_recvmmsg(handle, &buf, flag)
           │      └─ recvmmsg() / recvmsg_x()
           └─ [通常時] recvmsg(fd, &h, flag)
                  └─ recv_cb(handle, nread, &buf, &peer, flags)

uv_udp_recv_stop(handle)
    └─ uv__udp_recv_stop(handle)
           ├─ uv__io_stop(loop, &io_watcher, POLLIN)
           └─ handle->recv_cb = NULL
```

### データフロー図

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

ネットワーク ──────▶ recvmsg()/recvmmsg() ──────▶ recv_cb(handle, nread, buf, addr, flags)
                          │
                    alloc_cb ──▶ バッファ確保
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | API宣言、コールバック型定義 |
| uv-common.c | `src/uv-common.c` | ソース | 共通エントリーポイント |
| udp.c (unix) | `src/unix/udp.c` | ソース | Unix系の受信実装 |
| udp.c (win) | `src/win/udp.c` | ソース | Windows版の受信実装 |
