# 機能設計書 7-dgram

## 概要

本ドキュメントは、Node.jsのdgramモジュール（UDP/データグラムソケット機能）の機能設計を記載する。dgramモジュールは、UDPデータグラムソケットを提供するコアモジュールである。

### 本機能の処理概要

dgramモジュールは、コネクションレスのUDP（User Datagram Protocol）通信を実現する。TCPと異なり、接続確立のオーバーヘッドがなく、低レイテンシでの通信が可能である。

**業務上の目的・背景**：UDPはリアルタイム性が求められるアプリケーション（DNS、ストリーミング、ゲーム、VoIP等）で広く使用される。信頼性よりも速度を優先する場合や、マルチキャスト/ブロードキャスト通信が必要な場合に適している。

**機能の利用シーン**：
- DNSクエリ/レスポンス
- リアルタイムゲームサーバー
- 音声/動画ストリーミング
- IoTデバイス間通信
- マルチキャスト配信
- ブロードキャスト送信
- サービスディスカバリ（mDNS等）

**主要な処理内容**：
1. UDPソケットの作成（createSocket, Socket）
2. ポートバインド（bind）
3. データ送受信（send, sendto）
4. 接続状態管理（connect, disconnect）
5. マルチキャスト設定（addMembership, dropMembership）
6. ブロードキャスト設定（setBroadcast）
7. TTL設定（setTTL, setMulticastTTL）
8. バッファサイズ設定

**関連システム・外部連携**：
- udp_wrapバインディング（C++レイヤー）
- dnsモジュール（名前解決）
- clusterモジュール（負荷分散）

**権限による制御**：ブロードキャストやマルチキャストにはネットワーク設定による制限がある場合がある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 直接関連する画面なし |

## 機能種別

ネットワーク通信 / データグラム / マルチキャスト

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| type | string | Yes | 'udp4' または 'udp6' | - |
| port | number | No | バインド/送信先ポート | validatePort |
| address | string | No | バインド/送信先アドレス | validateString |
| callback | Function | No | コールバック関数 | - |
| reuseAddr | boolean | No | アドレス再利用許可 | - |
| reusePort | boolean | No | ポート再利用許可 | - |
| ipv6Only | boolean | No | IPv6のみ | - |
| recvBufferSize | number | No | 受信バッファサイズ | validateUint32 |
| sendBufferSize | number | No | 送信バッファサイズ | validateUint32 |
| receiveBlockList | BlockList | No | 受信ブロックリスト | BlockList.isBlockList |
| sendBlockList | BlockList | No | 送信ブロックリスト | BlockList.isBlockList |
| signal | AbortSignal | No | 中断シグナル | validateAbortSignal |

### 入力データソース

- アプリケーションコード：ソケット設定、送信データ
- ネットワーク：受信データグラム

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| socket | Socket | UDPソケットインスタンス |
| address | object | アドレス情報（port, address, family） |
| buf | Buffer | 受信データ |
| rinfo | object | 送信元情報（address, port, family, size） |

### 出力先

- イベント：'message', 'listening', 'connect', 'close', 'error'
- コールバック：send完了通知

## 処理フロー

### 処理シーケンス（サーバー）

```
1. createSocket(type)でSocketインスタンス生成
   └─ EventEmitter継承
   └─ newHandle()でUDPハンドル作成
2. socket.bind(port, address)でバインド
   └─ handle.lookup()でアドレス解決
   └─ handle.bind()でポートバインド
   └─ startListening()で受信開始
3. 'listening'イベント発火
4. onMessage()でデータ受信
   └─ receiveBlockListチェック
   └─ 'message'イベント発火
5. socket.close()で終了
```

### 処理シーケンス（送信）

```
1. socket.send(buffer, port, address)
2. バインド済みチェック
   └─ 未バインド時は自動バインド
3. handle.lookup()でアドレス解決
4. doSend()で送信実行
   └─ sendBlockListチェック
   └─ SendWrap作成
   └─ handle.send()でデータ送信
5. afterSend()で完了コールバック
```

### フローチャート

```mermaid
flowchart TD
    A[createSocket] --> B[Socket生成]
    B --> C[newHandle]
    C --> D[bind]
    D --> E[lookup]
    E --> F[handle.bind]
    F --> G[startListening]
    G --> H[recvStart]
    H --> I{データ受信?}
    I -->|Yes| J[onMessage]
    J --> K{BlockList?}
    K -->|OK| L[messageイベント]
    K -->|Block| I
    L --> I
    I -->|close| M[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 自動バインド | send前に未バインドなら自動でポート0にバインド | send時 |
| BR-002 | 接続状態管理 | DISCONNECTED/CONNECTING/CONNECTEDの3状態 | connect使用時 |
| BR-003 | バインド状態管理 | UNBOUND/BINDING/BOUNDの3状態 | bind使用時 |
| BR-004 | デフォルトアドレス | udp4は'0.0.0.0'、udp6は'::'にバインド | address未指定時 |
| BR-005 | BlockList | receiveBlockListとsendBlockListで送受信制御 | オプション指定時 |
| BR-006 | reusePort指定時 | exclusive=trueに設定 | reusePort=true時 |

### 計算ロジック

- BIND_STATE: UNBOUND(0), BINDING(1), BOUND(2)
- CONNECT_STATE: DISCONNECTED(0), CONNECTING(1), CONNECTED(2)

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

本モジュールはデータベースを直接操作しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ERR_SOCKET_ALREADY_BOUND | 状態エラー | 既にバインド済み | 新規ソケット作成 |
| ERR_SOCKET_DGRAM_IS_CONNECTED | 状態エラー | 接続済みソケットで宛先指定 | disconnectまたは宛先省略 |
| ERR_SOCKET_DGRAM_NOT_CONNECTED | 状態エラー | 未接続で宛先省略 | connectまたは宛先指定 |
| ERR_SOCKET_DGRAM_NOT_RUNNING | 状態エラー | ソケットが動作していない | 新規ソケット作成 |
| ERR_SOCKET_BAD_BUFFER_SIZE | バリデーション | 無効なバッファサイズ | 正の整数を指定 |
| ERR_SOCKET_BUFFER_SIZE | システム | バッファサイズ設定失敗 | サイズ調整 |
| ERR_IP_BLOCKED | セキュリティ | BlockListでブロック | ブロックリスト確認 |
| ERR_BUFFER_OUT_OF_BOUNDS | バリデーション | バッファ範囲外 | offset/length確認 |
| ERR_INVALID_FD_TYPE | バリデーション | 無効なFDタイプ | UDPのFDを指定 |

### リトライ仕様

UDPはコネクションレスのため、アプリケーション層でのリトライ/確認応答が必要。

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

UDPはステートレスプロトコル。connect()で擬似接続状態を管理可能。

## パフォーマンス要件

- コネクションレスによる低レイテンシ
- バッファサイズ設定による最適化
- reusePortによる複数プロセスでのポート共有

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

- receiveBlockListによる受信フィルタリング
- sendBlockListによる送信制限
- AbortSignalによる処理中断
- UDPはなりすましが容易なため、上位プロトコルでの認証推奨

## 備考

- SocketはEventEmitterを継承
- udp_wrapのC++バインディングを使用
- diagnostics_channelでudp.socketチャネルを提供
- マルチキャストにはIGMPプロトコルを使用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dgram.js | `lib/dgram.js` | Socketクラスの継承関係と状態定義 |

**読解のコツ**: SocketはEventEmitterを継承（186-187行目）。kStateSymbolが内部状態管理の鍵で、BIND_STATE（87-89行目）とCONNECT_STATE（91-93行目）の定数が状態遷移を表す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dgram.js | `lib/dgram.js` | 公開API定義（1056-1059行目） |

**主要処理フロー**:
1. **190-192行目**: createSocket()関数
2. **108-185行目**: Socket関数（コンストラクタ）
3. **267-410行目**: Socket.prototype.bind()
4. **615-714行目**: Socket.prototype.send()

#### Step 3: バインド処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dgram.js | `lib/dgram.js` | バインド処理の実装 |

**主要処理フロー**:
- **195-211行目**: startListening() - 受信開始
- **244-265行目**: bindServerHandle() - クラスター環境でのハンドル取得
- **360-406行目**: アドレス解決とバインド実行

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | dgram.js | `lib/dgram.js` | 送受信処理の実装 |

**主要処理フロー**:
- **716-766行目**: doSend() - 送信実行
- **768-776行目**: afterSend() - 送信完了コールバック
- **981-992行目**: onMessage() - メッセージ受信

#### Step 5: マルチキャスト処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | dgram.js | `lib/dgram.js` | マルチキャスト関連処理 |

**主要処理フロー**:
- **843-848行目**: setBroadcast() - ブロードキャスト設定
- **863-872行目**: setMulticastTTL() - マルチキャストTTL設定
- **895-908行目**: addMembership() - マルチキャストグループ参加
- **911-924行目**: dropMembership() - マルチキャストグループ脱退
- **926-941行目**: addSourceSpecificMembership() - SSM参加

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

```
dgram.createSocket(type, listener)
    │
    └─ new Socket(type, listener)
           │
           ├─ EventEmitter.call(this)
           │
           ├─ newHandle(type, lookup)
           │      └─ new UDP()
           │
           └─ kStateSymbol初期化
                  └─ bindState, connectState等

socket.bind(port, address, callback)
    │
    ├─ healthCheck(this)
    │
    ├─ state.bindState = BINDING
    │
    └─ state.handle.lookup(address)
           │
           └─ コールバック
                  │
                  ├─ cluster.isWorker → bindServerHandle()
                  │      └─ cluster._getServer()
                  │             └─ replaceHandle()
                  │                    └─ startListening()
                  │
                  └─ プライマリ → state.handle.bind()
                         └─ startListening()
                                │
                                ├─ handle.onmessage = onMessage
                                ├─ handle.onerror = onError
                                ├─ handle.recvStart()
                                └─ emit('listening')

socket.send(buffer, port, address, callback)
    │
    ├─ バインドチェック
    │      └─ 未バインド → bind({ port: 0 })
    │
    ├─ state.handle.lookup(address)
    │
    └─ doSend(ip, list, address, port, callback)
           │
           ├─ sendBlockList?.check()
           │
           ├─ new SendWrap()
           │
           └─ state.handle.send(req, list, ...)
                  │
                  └─ afterSend() [コールバック]
```

### データフロー図

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

type, options    ───▶  new Socket           ───▶  Socketインスタンス
                           │
                      newHandle(UDP)
                           │
port, address   ───▶  bind                  ───▶  'listening'イベント
                           │
                      handle.bind()
                           │
                      startListening()
                           │
                      recvStart()

[受信]

UDPパケット     ───▶  onMessage             ───▶  'message'イベント
                           │                       (buf, rinfo)
                      receiveBlockList?.check()

[送信]

buffer, port,   ───▶  send                  ───▶  callback(err, bytes)
address               │
                      lookup(address)
                           │
                      doSend()
                           │
                      sendBlockList?.check()
                           │
                      handle.send()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dgram.js | `lib/dgram.js` | ソース | 公開API定義（メイン） |
| internal/dgram.js | `lib/internal/dgram.js` | ソース | 内部ユーティリティ（newHandle等） |
| internal/blocklist.js | `lib/internal/blocklist.js` | ソース | BlockList実装 |
| events.js | `lib/events.js` | ソース | EventEmitter基底 |
