%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
%%
-module(dtls_connection).
%% %%====================================================================
%% %% Internal application API
%% %%====================================================================
%% %%====================================================================
%% %% State functions
%% %%====================================================================
%% -spec hello(start | #hello_request{} | #client_hello{} | #server_hello{} | term(),
%% #state{}) -> gen_fsm_state_return().
%% %%--------------------------------------------------------------------
%% hello(start, #state{host = Host, port = Port, role = client,
%% ssl_options = SslOpts,
%% session = #session{own_certificate = Cert} = Session0,
%% session_cache = Cache, session_cache_cb = CacheCb,
%% connection_states = ConnectionStates0,
%% renegotiation = {Renegotiation, _},
%% client_cookie = Cookie} = State0) ->
%% Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, SslOpts,
%% Cache, CacheCb, Renegotiation, Cert),
%% Version = Hello#client_hello.client_version,
%% State1 = State0#state{negotiated_version = Version, %% Requested version
%% session =
%% Session0#session{session_id = Hello#client_hello.session_id},
%% dtls_handshake_history = ssl_handshake:init_handshake_history()},
%% State2 = send_flight(Hello, waiting, State1),
%% {Record, State} = next_record(State2),
%% next_state(hello, hello, Record, State);
%% hello(start, #state{role = server} = State0) ->
%% {Record, State} = next_record(State0),
%% next_state(hello, hello, Record, State);
%% hello(#hello_request{}, #state{role = client} = State0) ->
%% {Record, State} = next_record(State0),
%% next_state(hello, hello, Record, State);
%% hello(#server_hello{cipher_suite = CipherSuite,
%% compression_method = Compression} = Hello,
%% #state{session = #session{session_id = OldId},
%% connection_states = ConnectionStates0,
%% role = client,
%% negotiated_version = ReqVersion,
%% renegotiation = {Renegotiation, _},
%% ssl_options = SslOptions} = State1) ->
%% State0 = flight_done(State1),
%% case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
%% #alert{} = Alert ->
%% handle_own_alert(Alert, ReqVersion, hello, State0);
%% {Version, NewId, ConnectionStates, NextProtocol} ->
%% {KeyAlgorithm, _, _, _} =
%% ssl_cipher:suite_definition(CipherSuite),
%% PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
%% NewNextProtocol = case NextProtocol of
%% undefined ->
%% State0#state.next_protocol;
%% _ ->
%% NextProtocol
%% end,
%% State = State0#state{key_algorithm = KeyAlgorithm,
%% hashsign_algorithm = default_hashsign(Version, KeyAlgorithm),
%% negotiated_version = Version,
%% connection_states = ConnectionStates,
%% premaster_secret = PremasterSecret,
%% expecting_next_protocol_negotiation = NextProtocol =/= undefined,
%% next_protocol = NewNextProtocol},
%% case ssl_session:is_new(OldId, NewId) of
%% true ->
%% handle_new_session(NewId, CipherSuite, Compression,
%% State#state{connection_states = ConnectionStates});
%% false ->
%% handle_resumed_session(NewId, State#state{connection_states = ConnectionStates})
%% end
%% end;
%% hello(#hello_verify_request{cookie = Cookie},
%% #state{host = Host, port = Port,
%% session = #session{own_certificate = Cert},
%% session_cache = Cache, session_cache_cb = CacheCb,
%% ssl_options = SslOpts,
%% connection_states = ConnectionStates0,
%% renegotiation = {Renegotiation, _}} = State0) ->
%% Hello = ssl_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, SslOpts,
%% Cache, CacheCb, Renegotiation, Cert),
%% State1 = State0#state{
%% tls_handshake_history = ssl_handshake:init_handshake_history(),
%% client_cookie = Cookie},
%% State2 = send_flight(Hello, waiting, State1),
%% {Record, State} = next_record(State2),
%% next_state(hello, hello, Record, State);
%% %%--------------------------------------------------------------------
%% -spec abbreviated(#hello_request{} | #finished{} | term(),
%% #state{}) -> gen_fsm_state_return().
%% %%--------------------------------------------------------------------
%% abbreviated(timeout, State) ->
%% { next_state, abbreviated, State, hibernate };
%% abbreviated(Msg, State) ->
%% handle_unexpected_message(Msg, abbreviated, State).
%% %%--------------------------------------------------------------------
%% -spec certify(#hello_request{} | #certificate{} | #server_key_exchange{} |
%% #certificate_request{} | #server_hello_done{} | #client_key_exchange{} | term(),
%% #state{}) -> gen_fsm_state_return().
%% %%--------------------------------------------------------------------
%% certify(timeout, State) ->
%% { next_state, certify, State, hibernate };
%% certify(Msg, State) ->
%% handle_unexpected_message(Msg, certify, State).
%% %%--------------------------------------------------------------------
%% -spec cipher(#hello_request{} | #certificate_verify{} | #finished{} | term(),
%% #state{}) -> gen_fsm_state_return().
%% %%--------------------------------------------------------------------
%% cipher(timeout, State) ->
%% { next_state, cipher, State, hibernate };
%% cipher(Msg, State) ->
%% handle_unexpected_message(Msg, cipher, State).
%% %%--------------------------------------------------------------------
%% -spec connection(#hello_request{} | #client_hello{} | term(),
%% #state{}) -> gen_fsm_state_return().
%% %%--------------------------------------------------------------------
%% connection(timeout, State) ->
%% {next_state, connection, State, hibernate};
%% connection(Msg, State) ->
%% handle_unexpected_message(Msg, connection, State).
%% %%--------------------------------------------------------------------
%% %%% Internal functions
%% %%--------------------------------------------------------------------
%% handle_unexpected_message(Msg, Info, #state{negotiated_version = Version} = State) ->
%% Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE),
%% handle_own_alert(Alert, Version, {Info, Msg}, State).
%% send_flight(HandshakeRec, FlightState, State) ->
%% send_flight(FlightState, buffer_flight(HandshakeRec, State)).
%% send_flight(FlightState, State = #state{negotiated_version = Version,
%% flight_buffer = Buffer}) ->
%% State1 = do_send_flight(queue:to_list(Buffer), [], State),
%% finish_send_flight(Version, FlightState, State1).
%% resend_flight(State = #state{negotiated_version = Version,
%% flight_state = FlightState,
%% flight_buffer = Buffer})
%% when FlightState == finished; FlightState == waiting ->
%% State1 = do_send_flight(queue:to_list(Buffer), [], State),
%% finish_send_flight(Version, FlightState, State1);
%% resend_flight(State) ->
%% State.
%% flight_done(State) ->
%% cancel_dtls_retransmit_timer(State#state{flight_state = done,
%% flight_buffer = undefined}).
%% do_send_flight([], BinMsgs, State = #state{transport_cb = Transport, socket = Socket}) ->
%% Transport:send(Socket, lists:reverse(BinMsgs)),
%% State;
%% do_send_flight([{Epoch, MsgSeq, HandshakeRec}|T], BinMsgs0,
%% State = #state{negotiated_version = Version,
%% connection_states = ConnectionStates0}) ->
%% CS0 = ssl_record:connection_state_by_epoch(ConnectionStates0, Epoch, write),
%% {BinMsgs, CS1} = encode_handshake_rec(HandshakeRec, Version, MsgSeq, BinMsgs0, CS0),
%% ConnectionStates1 = ssl_record:set_connection_state_by_epoch(ConnectionStates0, CS1, write),
%% do_send_flight(T, BinMsgs, State#state{connection_states = ConnectionStates1}).
%% cancel_dtls_retransmit_timer(State = #state{dtls_retransmit_timer = TimerRef}) ->
%% cancel_timer(TimerRef),
%% State#state{dtls_retransmit_timer = undefined}.
%% rearm_dtls_retransmit_timer(State = #state{dtls_retransmit_timer = undefined}) ->
%% TimerRef = erlang:start_timer(1000, self(), dtls_retransmit),
%% State#state{dtls_retransmit_timer = TimerRef};
%% rearm_dtls_retransmit_timer(State) ->
%% State.
%% finish_send_flight({254, _}, waiting, State) ->
%% TimerRef = erlang:start_timer(1000, self(), dtls_retransmit),
%% State#state{
%% dtls_retransmit_timer = TimerRef,
%% last_retransmit = timestamp(),
%% flight_state = waiting};
%% finish_send_flight(_, FlightState, State) ->
%% State#state{flight_state = FlightState}.
%% timestamp() ->
%% {Mega, Sec, Micro} = erlang:now(),
%% Mega * 1000000 * 1000 + Sec * 1000 + (Micro div 1000).
%% encode_handshake_rec(HandshakeRec, Version, MsgSeq, BinMsgs0, CS0) ->
%% {_, Fragments} = ssl_handshake:encode_handshake(HandshakeRec, Version, MsgSeq, 1400),
%% lists:foldl(fun(F, {Bin, C0}) ->
%% {B, C1} = ssl_record:encode_handshake(F, Version, C0),
%% {[B|Bin], C1} end, {BinMsgs0, CS0}, Fragments).