RFC1459 Internet Relay Chat Protocolを読んでみた。（8.Current Implementations Details）

# はじめに
どうも。こんにちは。
[42tokyo](https://42tokyo.jp/)といったところで、簡単なIRCサーバの実装を行なっています。
前回は、[RFC2812 Internet Relay Chat: Client Protocolを読んでみた。](https://qiita.com/gu-chi/items/e293020428e6c839673d)を書き、
クライアントとサーバ間の通信について学びました。

今回は、[RFC1459 Internet Relay Chat Protocol 8.Current implementations](https://datatracker.ietf.org/doc/html/rfc1459#section-8)を読み、
実装について学んで行きたいと思います。
クライアントとサーバ間の通信に関連する箇所を重点的に見ていきます。
サーバ間の通信に関連する箇所は、飛ばしていることもあります。

間違い等があれば、ご指摘ください。
# 8.Current Implementations Details
* この文書は、IRCプロトコルの標準化を行うにあたり、バージョン2.8のIRCサーバソフトウェアを参考にした
* そのため、2.8以前のソフトウェアでは、この文書とは異なる実装の場合がある
* 例えば、バージョン2.8以前のIRCサーバーの実装では、メッセージ中にある任意のLFまたはCRが終端を表す
* また、2.8以後でも後方互換性を保つために、この文書とは異なる実装の場合もある
* この章は、サーバを実装する際の重要な問題に焦点を当てている（一部はクライアントにも直接適用される可能性がある）

## 8.1 Network protocol: TCP
* IRCは、ネットワークプロトコルにTCPを採用している

### 8.1.1 Support of Unix sockets
* Unixドメインソケットを使用して、クライアントとサーバの接続を受け付けることができる

## 8.2 Command Parsing
* ソケット毎にメッセージを格納するバッファを用意する
* このバッファサイズは、512bytesで、これはメッセージの最大長
* １クライアントの１回の通信で、複数のメッセージ（命令？）が来た場合、注意が必要
* 複数メッセージの中に、クライアントの状態を変更するものがあるとき、それに応じた処理をする必要がある

## 8.3 Message delivery
* １回の通信で複数のメッセージが来たとき、１つのメッセージ毎にレスポンスを返す（write()システムコールを発行する）ことは、効率的とは言えない
* そのため、レスポンスを一時的に保存する「送信キュー（FIFO）」を用意し、そこにレスポンスを貯めていく
* 各メッセージに対する処理を終えたところで「送信キュー」に貯まったレスポンスをクライアントに返送する
* こうすることで、write()システムコールの呼び出し回数を減らすことができる
* IRCプロトコルにおけるメッセージの最大長は、512バイトなので、レスポンスの最大長も512バイトとなる

## 8.4 Connection 'Liveness'
* 一定期間通信のないクライアントに対して、確認応答のためpingを送信しなければならない **[MUST]**
* そして時間内に応答がなければ、適切な手順を踏んで、クライアントとの接続を切断する
* また「送信キュー」が、許容する容量を超えて大きくなった場合も、そのクライアントとの接続を切断すること

## 8.5 Establishing a server-client connection
* クライアントがサーバに接続すると、サーバは以下の情報をクライアントに送信する
  * MOTD(Message of the Day)
  存在する場合のみ送信する。MOTDとは、管理者が設定したメッセージのこと。
  通常はユーザに表示される。
  * LUSERコマンド
  接続時現在のサーバ数とユーザ数を送信する。
  * サーバ名
  * サーバのバージョン
  * その他のメッセージ
* クライアントは、これらのメッセージを受け取ることで、接続が成功したことを確認する
* その後、サーバは、登録されたユーザ情報をクライアントに返送する
  * NICKコマンド
  * USERコマンド

## 8.6 Establishing a server-server connection
省略します。
参考：[8.6 Establishing a server-server connection.](https://datatracker.ietf.org/doc/html/rfc1459#section-8.6)

### 8.6.1 State information exchange when connecting
省略します。
参考：[8.6.1 State information exchange when connecting](https://datatracker.ietf.org/doc/html/rfc1459#section-8.6.1)

## 8.7 Terminating server-client connections
* クライアントとの接続が終了すると、クライアントが接続していたサーバが、QUITメッセージを作成する
* QUITメッセージ以外の生成、使用はない

## 8.8 Terminating server-server connections
省略します。
参考：[8.8 Terminating server-server connections](https://datatracker.ietf.org/doc/html/rfc1459#section-8.8)

## 8.9 Tracking nickname changes
* サーバは、ニックネームの変更履歴を保存する必要がある
* これによって、ニックネームの変更に伴う競合状態を減少させることができる
* ニックネームのチェックが必要なコマンドは、以下の通り（これ以外は必要ない）
  * KILL
  * MODE(+/-o,v)
  * KICK
* 保存するニックネームの履歴範囲は、よく検討すること

## 8.10 Flood control of clients
* ネットワークの負荷を軽減する仕組み
  * クライアントが最後に送信したメッセージの時刻を保存する（メッセージタイマ）
  * 次のメッセージを受け取るとき、現在時刻とメッセージタイマを比較し、１０秒以内であればペナルティを課す
  * ペナルティとは、すぐにメッセージを受け取らず、２秒待ってから処理すること
  * こうすることで、クライアントが送るメッセージの送信速度を制限することができる

## 8.11 Non-blocking lookups
* より多くのクライアントを処理するために、サーバプロセスの待機時間は短い方が良い
* よってネットワーク操作は、ノンブロッキングI/Oで行われるべきだ
* ディスク読み込みなど、サーバプロセスをブロックする可能性のある処理は、
短いタイムアウトで実行されることが望ましい

### 8.11.1 Hostname (DNS) lookups
* 標準的なリゾルバ・ライブラリを使用すると、タイムアウトによって返信が大きく遅延することがある
* これを回避するために、ノンブロッキングIOで動作するDNSルーチンが作成された
* DNSルーチンは、メインサーバのIOループ内から定期的にポーリングされ、
ネットワークの遅延やタイムアウトによる問題に対応する

### 8.11.2 Username (Ident) lookups
* ユーザ名の検索で用いられるライブラリの多くは、同期的に動作するので、頻繁に遅延が発生する問題を抱えている
* これに対応するため、前項と同様ノンブロッキングIOで動作するルーチンを作成された

## 8.12 Configuration file
* 柔軟なサーバの設定と実行を行うために、設定ファイルの使用を推奨する
* 以下は、設定ファイルの内容
  * クライアント接続を受け入れるホスト
  * サーバ接続を許可するホスト
  * 接続するホスト（both actively and passively）
  * サーバの情報（大学、市町村、会社など）
  * サーバの責任者と連絡先のメールアドレス
  * 制限されたオペレーターコマンドへアクセスするためにクライアントへ与えられるホスト名とパスワード

* ホスト名の指定では、ドメイン名とドット表記(127.0.0.1)の両方が受け入れられるべき **[SHOULD]**
* 全ての送受信接続で使用されるパスワードを指定できる必要がある（ただし、発信接続は他のサーバへの接続に限る）
このパスワードはサーバ間の接続で使用される
定期的にパスワードを変更することを推奨

ここまでは、他サーバとの接続を行うのに最低限必要な情報
以下、その他設定
* 他のサーバが紹介できるサーバの指定
* 許容できるサーバブランチの深さ
* クライアントが接続できる時間帯

### 8.12.1 Allowing clients to connect
* サーバは、クライアントの接続管理を行うために「アクセス制御リスト」を使用する
* 「アクセス制御リスト」とは、クライアントのホストによる接続可否について書かれている
* 「アクセス制御リスト」は、サーバ起動時に読み込まれる
* 「アクセス制御リスト」は、Configuration fileか別のファイルで管理する
* アクセス制御の柔軟性を上げるために「deny（拒否）」と「allow（許可）」の両方を実装すべき **[SHOULD]**

### 8.12.2 Operators
* オペレータは強い権限を持つため、権限の付与には注意が必要
* 権限取得には、２つのパスワードが必要（うち１つは、比較的推測の簡単なものが使用される）
* パスワードの管理は、Configuration fileで行われることが一般的に多い（そして安全）
* Configuration fileで管理する際は、暗号化された形式で管理すること

### 8.12.3 Allowing servers to connect
省略します。
参考：[8.12.3 Allowing servers to connect](https://datatracker.ietf.org/doc/html/rfc1459#section-8.12.3)

### 8.12.4 Administrivia
* サーバはADMINコマンドへの応答で、正確な管理者情報を提供するために、Configuration fileから関連情報を取得する

## 8.13 Channel membership
* ローカルユーザ（サーバに接続しているユーザ）は、最大１０チャンネルに参加できる
* 非ローカルユーザへの設定は行わない（これによって他サーバと一貫性を保ちつつメンバーシップを管理できる）

# さいごに
具体的な実装について、少しずつ見えてきた気がします。
次回は、[RFC1459 Internet Relay Chat Protocol 4.1 Connection Registration](https://datatracker.ietf.org/doc/html/rfc1459#section-4.1)あたりを読んでいきたいと思います。
ありがとうございました。

# 参考

https://e-words.jp/w/%E3%83%95%E3%83%A9%E3%83%83%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0.html#:~:text=%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%95%E3%82%8C%E3%81%9F,%E3%80%8D%EF%BC%88flooding%20attack%EF%BC%89%E3%81%A8%E3%81%84%E3%81%86%E3%80%82

https://datatracker.ietf.org/doc/html/rfc1459