私はssl認証サーバーへのインターフェースとして動作するgen_serverを練習として実装しています。受信したパケットが間違っている場合 (たとえば、ユーザー名とパスワードが間違っている場合)、ssl サーバーは接続を切断します。接続は持続的でなければなりません。
gen_server で、handle_cast/2 を使用してサーバーへの ssl 接続を開きます。
handle_cast(connect, State) ->
......
case ssl:connect(Address, Port, Options, Timeout) of
{ok, NewSocket} ->
{noreply, State#state{socket=NewSocket}};
{error, Reason} ->
gen_server:cast(?SERVER, connect),
{noreply, State#state{socket=undefined}};
そして、たとえば以下を使用して送信できる handle_cast/2 内の他のメッセージを待ちます。
gen_server:cast(Pid, {authenticate, User, Password}).
このようなキャスト メッセージを受け取るたびに、gen_server:call/3 を使用してサーバー状態から SSL ソケットを回復し、認証メッセージを SSL サーバーに送信する新しい関数を生成します。送信部分がエラーを返した場合、再接続を試みます。それ以外の場合は、ソケットをしばらく読み込んで、ソケットがダウンしていないことを確認し、ダウンしている場合は再接続します。
send_auth(_, _, 0) ->
{error, max_num_reached};
send_auth(User, Password, Num) ->
Socket = gen_server:call(?SERVER, socket),
%% also a check that socket is not 'undefined'
case ssl:send(Socket, AuthMessage) of
ok ->
case ssl:recv(Socket, 0, 2000) of
{error, timeout} ->
ok;
_ ->
gen_server:cast(?SERVER, connect),
send_auth(User, Password, Num-1)
end,
{error, closed} ->
gen_server:cast(?SERVER, connect),
send_auth(User, Password, Num-1)
end.
私は多くのテストを行いましたが、毎回、1 つのメッセージ (最後のメッセージではない) が間違っていると、次のメッセージはどれも実際には配信されません。
すべての有効な認証メッセージが認証サーバーに配信されることを許可するにはどうすればよいですか? さらに、サーバーがまだ接続しようとしていない場合にのみ、サーバーが接続することをどのように確認できますか? そうでなければ、それは DOS 攻撃のようなものです!