# 機能設計書 52-UDP送信

## 概要

本ドキュメントは、libuvにおけるUDP非同期送信機能（`uv_udp_send()`）の設計仕様を記述する。UDPデータグラムを非同期で送信し、完了時にコールバック関数を呼び出す。

### 本機能の処理概要

**業務上の目的・背景**：UDPプロトコルによるネットワーク通信において、ノンブロッキングな送信を実現する。イベントループと統合された非同期送信により、送信処理がブロックすることなく他のI/O処理と並行して実行できる。接続済み（connected）UDPソケットと非接続UDPソケットの両方に対応する。

**機能の利用シーン**：
- UDPベースのプロトコル（DNS、DHCP、mDNS等）の実装
- リアルタイム通信（ゲーム、VoIP等）でのデータ送信
- センサーデータやログの非同期送信
- マルチキャストグループへのデータ配信

**主要な処理内容**：
1. 送信先アドレスと接続状態の整合性チェック
2. 必要に応じた遅延バインド（deferred bind）の実行
3. 送信リクエスト構造体の初期化とバッファコピー
4. 送信キューへのリクエスト追加
5. キューが空の場合は即座に送信を試行
6. 送信できない場合はI/Oウォッチャーによる非同期送信をスケジュール
7. 完了時にコールバック関数を呼び出し

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

**権限による制御**：特になし。ただし、ブロードキャストやマルチキャスト送信にはSO_BROADCAST等の事前設定が必要。

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| req | uv_udp_send_t* | Yes | 送信リクエスト構造体 | NULLでないこと |
| handle | uv_udp_t* | Yes | UDPハンドル | handle->typeがUV_UDPであること |
| bufs | const uv_buf_t[] | Yes | 送信データバッファ配列 | nbufs > 0 |
| nbufs | unsigned int | Yes | バッファ数 | 1以上 |
| addr | const struct sockaddr* | 条件付き | 送信先アドレス | 接続済みの場合はNULL、非接続の場合は必須 |
| send_cb | uv_udp_send_cb | No | 完了コールバック | NULLでも可 |

### 入力データソース

アプリケーションから直接渡される送信データバッファと送信先アドレス。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 成功時は0、失敗時は負のエラーコード |
| send_cb status | int | コールバック引数：成功時は0、失敗時は負のエラーコード |

### 出力先

送信データはOSのソケットを通じてネットワークに送出される。送信完了はコールバック関数で通知される。

## 処理フロー

### 処理シーケンス

```
1. 事前チェック (uv__udp_check_before_send)
   ├─ handle->typeがUV_UDPであることを確認
   ├─ addr指定ありかつ接続済みの場合 → UV_EISCONN
   ├─ addr指定なしかつ未接続の場合 → UV_EDESTADDRREQ
   └─ addrのアドレスファミリからアドレス長を計算
2. プラットフォーム固有実装呼び出し (uv__udp_send)
   ├─ addr指定時は遅延バインドを実行
   ├─ 送信リクエストを初期化
   ├─ バッファをリクエストにコピー（小さい場合はbufsml使用、大きい場合はmalloc）
   ├─ send_queue_sizeとsend_queue_countを更新
   └─ 送信キューに追加
3. 即座送信試行
   ├─ キューが空で処理中でない場合、uv__udp_sendmsg()を呼び出し
   └─ 送信完了しない場合はPOLLOUT I/Oウォッチャーを開始
4. 非同期送信完了
   ├─ I/Oウォッチャーがwritable通知を受け取り
   ├─ uv__udp_sendmsg()でバッチ送信
   └─ uv__udp_run_completed()で完了コールバック呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[uv_udp_send呼び出し] --> B[uv__udp_check_before_send]
    B -->|エラー| Z1[エラーコード返却]
    B -->|OK| C[uv__udp_send]
    C --> D{addr指定あり?}
    D -->|Yes| E[uv__udp_maybe_deferred_bind]
    D -->|No| F[リクエスト初期化]
    E --> F
    F --> G{nbufs > bufsml配列サイズ?}
    G -->|Yes| H[バッファをmalloc]
    G -->|No| I[bufsmlを使用]
    H --> J[キューに追加]
    I --> J
    J --> K{キュー空 かつ 非処理中?}
    K -->|Yes| L[即座にsendmsg試行]
    K -->|No| M[POLLOUTウォッチャー開始]
    L --> N{全て送信完了?}
    N -->|Yes| O[完了]
    N -->|No| M
    M --> P[イベントループでwritable通知]
    P --> Q[uv__udp_sendmsg バッチ送信]
    Q --> R[uv__udp_run_completed]
    R --> S[send_cb呼び出し]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-52-01 | 接続済みソケット制約 | 接続済みUDPソケットではaddrにNULLを指定する | handle->flags & UV_HANDLE_UDP_CONNECTED |
| BR-52-02 | 未接続ソケット制約 | 未接続UDPソケットではaddrを指定する | !(handle->flags & UV_HANDLE_UDP_CONNECTED) |
| BR-52-03 | 遅延バインド | ソケットが未バインドの場合、送信前に自動バインドされる | handle->io_watcher.fd == -1 |
| BR-52-04 | バッチ送信 | sendmmsg()対応プラットフォームでは最大20個をバッチ送信 | Linux, FreeBSD, macOS |
| BR-52-05 | 小バッファ最適化 | nbufsが小さい場合、ヒープ割り当て不要のbufsml配列を使用 | nbufs <= ARRAY_SIZE(req->bufsml) |

### 計算ロジック

送信キューサイズ計算: `handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs)`

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

該当なし（インメモリ操作のみ）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータ不正 | handle->typeがUV_UDPでない / addrのファミリが不正 | 正しいパラメータを渡す |
| UV_EISCONN | 接続済み | 接続済みソケットにaddr指定 | addrにNULLを渡す |
| UV_EDESTADDRREQ | 宛先必須 | 未接続ソケットにaddr未指定 | addrを指定するかuv_udp_connect()する |
| UV_ENOMEM | メモリ不足 | バッファコピー用メモリ割り当て失敗 | メモリ解放後に再試行 |

### リトライ仕様

送信がEAGAINで失敗した場合、自動的にI/Oウォッチャーで再送信が試行される。

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

該当なし。UDPはコネクションレスプロトコルであり各データグラムは独立。

## パフォーマンス要件

- sendmmsg()対応プラットフォームでは最大20メッセージのバッチ送信
- bufsml最適化によるヒープ割り当て回避
- キュー空時の即座送信でI/Oウォッチャーオーバーヘッド回避

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

- 送信先アドレスの妥当性はアプリケーション側で検証が必要
- バッファデータの内容バリデーションは行わない

## 備考

- send_cbがNULLの場合でもリソース解放は自動的に行われる
- AF_UNIXアドレスファミリも非Windows環境でサポート
- 送信キューサイズはhandle->send_queue_sizeで確認可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | **L721-734行目**: uv_udp_s構造体 - send_queue_size, send_queue_countフィールド |
| 1-2 | uv.h | `include/uv.h` | **L736-742行目**: uv_udp_send_s構造体 - handle, cbフィールドとUV_UDP_SEND_PRIVATE_FIELDS |
| 1-3 | uv.h | `include/uv.h` | **L713行目**: uv_udp_send_cb型定義 |

**読解のコツ**: UV_UDP_SEND_PRIVATE_FIELDSにはbufs, bufsml, nbufs, queue, u(addr/storage)が含まれる。bufsmlは小バッファ最適化用の固定配列。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | uv-common.c | `src/uv-common.c` | **L456-484行目**: uv__udp_check_before_send() - 接続状態とアドレスの整合性チェック |
| 2-2 | uv-common.c | `src/uv-common.c` | **L487-500行目**: uv_udp_send() - 公開API |

**主要処理フロー**:
1. **L459-460行目**: handle->typeがUV_UDPか検証
2. **L462-463行目**: 接続済みソケットにaddr指定 → UV_EISCONN
3. **L465-466行目**: 未接続ソケットにaddr未指定 → UV_EDESTADDRREQ
4. **L468-483行目**: アドレスファミリからアドレス長計算

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | udp.c (unix) | `src/unix/udp.c` | **L647-710行目**: uv__udp_send() - 遅延バインド、リクエスト初期化、キュー追加、即座送信 |
| 3-2 | udp.c (unix) | `src/unix/udp.c` | **L1458-1512行目**: uv__udp_sendmsg() - 送信キューからのバッチ送信 |
| 3-3 | udp.c (unix) | `src/unix/udp.c` | **L1395-1455行目**: uv__udp_sendmsgv() - sendmmsg()を使用したバッチ送信 |
| 3-4 | udp.c (unix) | `src/unix/udp.c` | **L1367-1392行目**: uv__udp_sendmsg1() - 単一sendmsg()呼び出し |

#### Step 4: 送信完了処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | udp.c (unix) | `src/unix/udp.c` | **L98-139行目**: uv__udp_run_completed() - 完了キュー処理とコールバック呼び出し |
| 4-2 | udp.c (unix) | `src/unix/udp.c` | **L175-194行目**: uv__udp_io() - I/OウォッチャーコールバックでPOLLOUT処理 |

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

```
uv_udp_send(req, handle, bufs, nbufs, addr, send_cb)
    ├─ uv__udp_check_before_send(handle, addr)
    └─ uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb)
           ├─ uv__udp_maybe_deferred_bind(handle, domain, 0)
           ├─ uv__req_init(loop, req, UV_UDP_SEND)
           ├─ memcpy(req->bufs, bufs, ...)
           ├─ uv__queue_insert_tail(&handle->write_queue)
           └─ uv__udp_sendmsg(handle)  [キュー空時]
                  └─ uv__udp_sendmsgv(fd, count, bufs, nbufs, addrs)
                         ├─ sendmmsg()  [Linux/FreeBSD/macOS]
                         └─ uv__udp_sendmsg1()  [フォールバック]
                                └─ sendmsg()
```

### データフロー図

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

bufs[] ──────────────▶ uv__udp_send() ─────────▶ write_queue
addr                      │                          │
send_cb                   │                          ▼
                          │                    uv__udp_sendmsg()
                          │                          │
                          │                    sendmsg()/sendmmsg()
                          │                          │
                          │                          ▼
                          │                    write_completed_queue
                          │                          │
                          └──────────────────▶ uv__udp_run_completed()
                                                     │
                                                     ▼
                                               send_cb(req, status)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| 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版の送信実装 |
