# 機能設計書 75-asyncnet

## 概要

本ドキュメントは、Nim標準ライブラリのasyncnetモジュールの機能設計について記載する。本モジュールはasyncdispatchモジュールをベースとした高レベルの非同期ソケットAPIを提供し、ノンブロッキングなネットワーク通信を実現する。

### 本機能の処理概要

asyncnetモジュールは、シングルスレッドで完全にノンブロッキングな非同期ネットワーク通信を提供する。async/await構文を使用して、同期的なコードスタイルで非同期処理を記述できる。バッファリング機能とSSL/TLS暗号化通信もサポートする。

**業務上の目的・背景**：高パフォーマンスなネットワークアプリケーション（チャットサーバー、Webサーバーなど）の開発において、マルチスレッドを使用せずに多数の同時接続を効率的に処理する必要がある。本モジュールは、Nimのasync/await機能と統合された使いやすいAPIを提供する。

**機能の利用シーン**：
- 非同期TCPクライアント/サーバーの開発
- 非同期UDPアプリケーション
- HTTPサーバー/クライアントの基盤
- チャットサーバーなどのリアルタイム通信
- 大量同時接続が必要なネットワークサービス

**主要な処理内容**：
1. 非同期ソケットの作成（newAsyncSocket）
2. 非同期接続（connect、dial）
3. 非同期データ送受信（send、recv、recvLine）
4. 非同期接続受け入れ（accept、acceptAddr）
5. SSL/TLSラッピング（wrapSocket、wrapConnectedSocket）
6. Unixドメインソケット（connectUnix、bindUnix）

**関連システム・外部連携**：asyncdispatch、nativesockets、net、selectorsモジュールと連携する。

**権限による制御**：OSレベルのソケット権限に依存。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本モジュールはGUI/画面を持たないライブラリ機能 |

## 機能種別

ネットワーク通信 / 非同期ソケット操作 / 暗号化通信

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| domain | Domain | No | アドレスファミリー | デフォルト: AF_INET |
| sockType | SockType | No | ソケットタイプ | デフォルト: SOCK_STREAM |
| protocol | Protocol | No | プロトコル | デフォルト: IPPROTO_TCP |
| buffered | bool | No | バッファリング有効化 | デフォルト: true |
| inheritable | bool | No | 子プロセスへの継承可否 | デフォルト: defined(nimInheritHandles) |
| address | string | Yes | 接続先アドレス | 有効なホスト名またはIPアドレス |
| port | Port | Yes | ポート番号 | 0-65535 |
| flags | set[SocketFlag] | No | ソケットフラグ | デフォルト: {SafeDisconn} |
| maxLength | int | No | 最大行長 | デフォルト: MaxLineLength |

### 入力データソース

- ホスト名/IPアドレス文字列
- ポート番号
- SSL証明書ファイル（SSL使用時）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| AsyncSocket | ref AsyncSocketDesc | 非同期ソケットオブジェクト |
| Future[T] | ref object | 非同期操作の結果を表すFuture |

### 出力先

- Future経由での非同期結果取得
- ネットワーク経由でのデータ送信

## 処理フロー

### 処理シーケンス

```
1. 非同期ソケット作成（newAsyncSocket）
   └─ createAsyncNativeSocket → AsyncSocketオブジェクト初期化
2. 非同期接続（connect/dial）
   └─ asyncdispatch.connect → SSLハンドシェイク（オプション）
3. サーバー構築
   ├─ bindAddr: アドレスをバインド
   ├─ listen: 接続待機開始
   └─ accept/acceptAddr: クライアント接続受け入れ
4. 非同期データ送受信
   ├─ send: データ送信（Future返却）
   ├─ recv: データ受信（バッファリング対応）
   └─ recvLine: 行単位受信
5. SSL/TLS（オプション）
   ├─ wrapSocket: SSLでラップ
   └─ sslLoopでSSL読み書き
6. ソケットクローズ（close）
   └─ SSLシャットダウン → closeSocket
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[newAsyncSocket]
    B --> C{用途}
    C -->|クライアント| D[connect/dial]
    C -->|サーバー| E[bindAddr]
    D --> F{SSL?}
    E --> G[listen]
    G --> H[await accept]
    F -->|Yes| I[wrapSocket]
    F -->|No| J[await send/recv]
    I --> K[SSLハンドシェイク]
    K --> J
    H --> L[クライアントAsyncSocket取得]
    L --> J
    J --> M{継続?}
    M -->|Yes| J
    M -->|No| N[close]
    N --> O[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-75-01 | バッファサイズ | デフォルトバッファサイズはBufferSize定数 | buffered=true時 |
| BR-75-02 | 最大行長 | recvLineはMaxLineLengthで切り捨て（DOS対策） | recvLine使用時 |
| BR-75-03 | SafeDisconn | 切断エラーを安全に処理するフラグ | flagsに指定時 |
| BR-75-04 | 非継承デフォルト | 子プロセスへのソケット継承を防止 | デフォルト動作 |

### 計算ロジック

行読み取り（recvLine）:
- `\r\L`を検出するまでバッファから読み取り
- 行末の`\r\L`は結果に含めない
- `\r\L`のみの行は`\r\L`を返す

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | 本モジュールはデータベース操作を行わない |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| OSError | システムエラー | ソケット操作失敗 | osLastError()で詳細取得 |
| SslError | SSL/TLSエラー | SSLハンドシェイク失敗 | ERR_error_string()で詳細取得 |
| ValueError | 値エラー | 不明なソケットファミリー | ドメイン指定を確認 |
| IOError | 入出力エラー | アドレス解決失敗 | ホスト名を確認 |

### リトライ仕様

- SSL_ERROR_WANT_READ/WANT_WRITEで自動リトライ（sslLoop）
- SafeDisconnフラグで切断時にエラーではなく0を返す

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

本モジュールはネットワーク通信を行うものであり、データベーストランザクション管理は行わない。

## パフォーマンス要件

- シングルスレッドで完全にノンブロッキング
- バッファリングによる効率的なデータ読み取り
- イベントループ（asyncdispatch）による効率的なI/O多重化
- epoll/kqueue/IOCP対応（プラットフォーム依存）

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

- SSL/TLS暗号化通信のサポート（-d:ssl）
- SNI（Server Name Indication）サポート
- 最大行長制限によるDOS攻撃対策（#3847）
- 子プロセスへのソケットリーク防止（デフォルト非継承）

## 備考

- ブロッキングソケットにはnetモジュールを使用
- Windows環境ではIOCPベースの実装
- Unix環境ではepoll/kqueueベースの実装
- SSLハンドシェイク前のシャットダウンは安全にスキップ

---

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

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

### 推奨読解順序

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

まず、AsyncSocket型の内部構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | asyncnet.nim | `lib/pure/asyncnet.nim` | AsyncSocketDesc型（118-135行目）: 非同期ソケットの内部構造 |
| 1-2 | asyncnet.nim | `lib/pure/asyncnet.nim` | defineSsl定数（108行目）: SSL条件コンパイル |

**読解のコツ**: AsyncSocketDescはfd、closed、isBuffered、buffer、isSsl等のフィールドを持つ。SSLフィールドはwhen defineSslで条件コンパイルされる。

#### Step 2: ソケット作成を理解する

非同期ソケットの生成処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | asyncnet.nim | `lib/pure/asyncnet.nim` | newAsyncSocket（137-163行目）: AsyncFD版 |
| 2-2 | asyncnet.nim | `lib/pure/asyncnet.nim` | newAsyncSocket（165-178行目）: 新規作成版 |

**主要処理フロー**:
1. **152行目**: fdをSocketHandleとして保存
2. **155行目**: setBlockingでノンブロッキングモードに設定
3. **156-157行目**: setInheritableで継承制御

#### Step 3: 非同期接続を理解する

接続処理とSSLハンドシェイクを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | asyncnet.nim | `lib/pure/asyncnet.nim` | dial関数（298-308行目）: IPv4/IPv6自動選択 |
| 3-2 | asyncnet.nim | `lib/pure/asyncnet.nim` | connect関数（310-327行目）: 接続とSSLハンドシェイク |

**主要処理フロー**:
- **315行目**: asyncdispatch.connectを呼び出し
- **320-323行目**: IPアドレスでない場合はSNIを設定
- **326-327行目**: sslSetConnectState → sslDoHandshake

#### Step 4: データ送受信を理解する

非同期データ送受信の処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | asyncnet.nim | `lib/pure/asyncnet.nim` | readIntoテンプレート（329-344行目）: 読み取りの基本処理 |
| 4-2 | asyncnet.nim | `lib/pure/asyncnet.nim` | recvInto関数（353-399行目）: バッファ対応受信 |
| 4-3 | asyncnet.nim | `lib/pure/asyncnet.nim` | recv関数（401-452行目）: 文字列受信 |
| 4-4 | asyncnet.nim | `lib/pure/asyncnet.nim` | send関数（454-480行目）: 送信処理 |
| 4-5 | asyncnet.nim | `lib/pure/asyncnet.nim` | recvLine関数（615-643行目）: 行単位受信 |

**主要処理フロー**:
- **370-397行目**: バッファからチャンク単位で読み取り
- **462-464行目**: SSL使用時はsslLoop経由でsslWrite
- **589-590行目**: maxLength超過でループ終了（DOS対策）

#### Step 5: SSL処理を理解する

SSL/TLS暗号化の処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | asyncnet.nim | `lib/pure/asyncnet.nim` | sslLoopテンプレート（268-296行目）: SSL読み書きループ |
| 5-2 | asyncnet.nim | `lib/pure/asyncnet.nim` | wrapSocket関数（767-783行目）: SSLラッピング |
| 5-3 | asyncnet.nim | `lib/pure/asyncnet.nim` | wrapConnectedSocket関数（785-808行目）: 接続済みソケットのラッピング |

**主要処理フロー**:
- **775行目**: SSL_newでハンドル作成
- **779-781行目**: BIOをメモリバッファとして設定
- **800-808行目**: クライアント/サーバーに応じてconnect/acceptステートを設定

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

```
newAsyncSocket(domain, sockType, protocol)
    │
    ├─ createAsyncNativeSocket() [asyncdispatch]
    │
    ├─ setBlocking(false) [nativesockets]
    │
    └─ setInheritable(inheritable) [nativesockets]

connect(socket, address, port)
    │
    ├─ asyncdispatch.connect() [Future返却]
    │
    └─ [SSL有効時]
          ├─ SSL_set_tlsext_host_name() [SNI設定]
          │
          ├─ sslSetConnectState()
          │
          └─ sslLoop(sslDoHandshake)
                │
                ├─ sendPendingSslData()
                │
                └─ appeaseSsl() [WANT_READ/WRITE処理]

recv(socket, size, flags)
    │
    ├─ [バッファあり]
    │     ├─ readIntoBuf() [バッファ補充]
    │     │     └─ readInto() → sslRead or asyncdispatch.recvInto
    │     │
    │     └─ copyMem() [バッファからコピー]
    │
    └─ [バッファなし]
          └─ readInto() → sslRead or asyncdispatch.recvInto
```

### データフロー図

```
[アプリケーション]         [asyncnet]              [asyncdispatch]         [OS]

await connect() ──────▶ connect() ──────────────▶ connect() ──────────▶ connect()
                              │                                              │
                              ▼                                              ▼
                       [SSL有効]                                        [接続完了]
                              │
                              ├──▶ sslLoop(sslDoHandshake)
                              │         │
                              │         ├──▶ sendPendingSslData()
                              │         │         └──▶ send() ──────────▶ send()
                              │         │
                              │         └──▶ appeaseSsl()
                              │                   └──▶ recv() ──────────▶ recv()
                              │
await send(data) ──────▶ send()
                              │
                              ├──▶ [SSL] sslLoop(sslWrite)
                              │              └──▶ sendPendingSslData()
                              │
                              └──▶ [非SSL] send() ──────────────────────▶ send()

await recv(size) ──────▶ recv()
                              │
                              ├──▶ [バッファあり] readIntoBuf()
                              │         │
                              │         └──▶ readInto()
                              │                   │
                              │                   ├──▶ [SSL] sslRead
                              │                   │
                              │                   └──▶ [非SSL] recvInto() ──▶ recv()
                              │
                              └──▶ [バッファなし] readInto()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| asyncnet.nim | `lib/pure/asyncnet.nim` | ソース | 高レベル非同期ソケット |
| asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | ソース | イベントループ・Future |
| nativesockets.nim | `lib/pure/nativesockets.nim` | ソース | 低レベルソケット操作 |
| net.nim | `lib/pure/net.nim` | ソース | SSL Context定義 |
| selectors.nim | `lib/pure/selectors.nim` | ソース | select/epoll/kqueue抽象化 |
| openssl.nim | `lib/wrappers/openssl.nim` | ソース | OpenSSLラッパー |
