Skip to content

Handler

Lyo Kato edited this page Jan 4, 2021 · 42 revisions

Callbacks

init/2

以下の例を確認してください

@impl Requiem
def init(conn, client) do

  Logger.debug("new connection is established, connection_id: #{conn.dcid}")

  if client.origin == "my-origin.example.com" && client.path == "/my_path" do

    my_state = %{path: client.path}
    {:ok, conn, state}

  else

    {:stop, 400, :forbidden}

  end
end

GenServerのinitに似ている役割を持っています。QUICのハンドシェイクに成功した後に呼ばれます。

引数

引数が2つあり、ConnectionStateと、ClientIndicationです。

必要ならClientIndicationのパラメータであるoriginとpathの値を確認し、任意の処理を行うことが出来ます。 上の例ではoriginが正しくなければここで切断し、originが期待通りであれば接続を維持するような処理になっています。

WebTransportモードをoffにした場合は、client indicationの部分はnilが渡されます。詳しくはWebTransportのページを参照してください。

originの扱いは、HTTPにおけるCORS と同じような話だと捉えてもらってよいです。

pathはこのサーバーにアクセスされるときに指定されたURLのパスの部分が入ります。

quic-transport://my-service.example.org/foobar というURLでアクセスされたとしたら、/foobarの部分が入ります。

必要によっては、この値を見て、サービスを分岐させて見ると良いでしょう。

Response

  @callback init(conn :: Requiem.ConnectionState.t(), client :: Requiem.ClientIndication.t()) ::
              {:ok, Requiem.ConnectionState.t(), any}
              | {:ok, Requiem.ConnectionState.t(), any, timeout | :hibernate}
              | {:stop, non_neg_integer, atom}

handle_info/3

  @callback handle_info(
              request :: term,
              conn :: Requiem.ConnectionState.t(),
              state :: any
            ) ::
              {:noreply, Requiem.ConnectionState.t(), any}
              | {:noreply, Requiem.ConnectionState.t(), any, timeout | :hibernate}
              | {:stop, non_neg_integer, atom}

handle_cast/3

  @callback handle_cast(
              request :: term,
              conn :: Requiem.ConnectionState.t(),
              state :: any
            ) ::
              {:noreply, Requiem.ConnectionState.t(), any}
              | {:noreply, Requiem.ConnectionState.t(), any, timeout | :hibernate}
              | {:stop, non_neg_integer, atom}

handle_call/4

  @callback handle_call(
              request :: term,
              from :: pid,
              conn :: Requiem.ConnectionState.t(),
              state :: any
            ) ::
              {:noreply, Requiem.ConnectionState.t(), any}
              | {:noreply, Requiem.ConnectionState.t(), any, timeout | :hibernate}
              | {:stop, non_neg_integer, atom}

terminate/3

  @type terminate_reason :: :normal | :shutdown | {:shutdown, term} | term

  @callback terminate(
              reason :: terminate_reason,
              conn :: Requiem.ConnectionState.t(),
              state :: any
            ) :: :ok

handle_stream/4


handle_dgram/3


Methods

close/0

close/2

stream_send/2

dgram_send/2

ConnectionState

各コールバックで渡されるconnの実態はRequiem.ConnectionStateモジュールで定義されている構造体です。

以下のようなフィールドを持っています

  • conn.scid
  • conn.dcid
  • conn.odcid

これらはQUICのフレームで利用される接続IDで、クライアントが接続開始の際に指定したものです。 (サーバー側がクライアントに対して指定したものではありません) odcidは、retryフレームを利用したトークンによるバリデーションを行う前に指定されたものです。

また、相手のAddressを持っています

  • conn.address

これはRequiem.Addressモジュールの構造体です。

  • conn.address.host
  • conn.address.port

のように相手の接続に関する情報にアクセスできます。

ClientIndication

ConnectionState以外にも知っておかなければならないものが一つあります。 init/2の第二引数として渡されるClientIndicationです。

@impl Requiem
def init(conn, client) do
  my_state = %{}
  {:ok, conn, my_state}
end

これは、WebTransportモードのときだけ利用されます。 WebTransportモードではない場合はここにはnilが渡されます。 (WebTransportモードについて詳しくは、ConfigurationWebTransportを参照してください。)

WebTransportモードの場合は、クライアントからstream_idが2のstreamを通して受け取ったデータを自動的にパースし、init/2に渡します。

ここで、originpathの値をチェックして、問題があれば切断することが出来ます。

@impl Requiem
def init(conn, client) do
  if client.origin == "example.org" && client.path == "/service" do
    my_state = %{}
    {:ok, conn, my_state}
  else
    {:stop, 400, :shutdown}
  end
end
Clone this wiki locally