<commit_before>%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2008-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%
%%----------------------------------------------------------------------
%% Purpose: Handles an ssh connection, e.i. both the
%% setup SSH Transport Layer Protocol (RFC 4253), Authentication
%% Protocol (RFC 4252) and SSH connection Protocol (RFC 4255)
%% Details of the different protocols are
%% implemented in ssh_transport.erl, ssh_auth.erl and ssh_connection.erl
%% ----------------------------------------------------------------------

-module(ssh_connection_handler).

-behaviour(gen_statem).

-include("ssh.hrl").
-include("ssh_transport.hrl").
-include("ssh_auth.hrl").
-include("ssh_connect.hrl").

-include("ssh_fsm.hrl").

%%====================================================================
%%% Exports
%%====================================================================

%%% Start and stop
-export([start_link/4, start_link/5, start_link/6,
	 stop/1
	]).

%%% Internal application API
-export([available_hkey_algorithms/2,
	 open_channel/6,
         start_channel/5,
         handle_direct_tcpip/6,
	 request/6, request/7,
	 reply_request/3, 
         global_request/5,
         handle_ssh_msg_ext_info/2,
	 send/5,
         send_bytes/2,
         send_msg/2,
	 send_eof/2,
         send_disconnect/6,
         send_disconnect/7,
         store/3,
         retrieve/2,
	 info/1, info/2,
	 connection_info/2,
	 channel_info/3,
	 adjust_window/3, close/2,
	 disconnect/4,
	 get_print_info/1,
         set_sock_opts/2, get_sock_opts/2,
         prohibited_sock_option/1
	]).

%%% Behaviour callbacks
-export([init/1, callback_mode/0, handle_event/4, terminate/3,
	 format_status/2, code_change/4]).

%%% Exports not intended to be used :). They are used for spawning and tests
-export([init_ssh_record/3,		   % Export of this internal function
					   % intended for low-level protocol test suites
	 renegotiate/1, alg/1 % Export intended for test cases
	]).

-behaviour(ssh_dbg).
-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).


-define(call_disconnectfun_and_log_cond(LogMsg, DetailedText, StateName, D),
        call_disconnectfun_and_log_cond(LogMsg, DetailedText, ?MODULE, ?LINE, StateName, D)).

%%====================================================================
%% Start / stop
%%====================================================================

start_link(client, Host, Port, Options, NegotiationTimeout) ->
    {_, Callback, _} = ?GET_OPT(transport, Options),
    SocketOpts = [{active,false} | ?GET_OPT(socket_options,Options)],
    try Callback:connect(Host, Port, SocketOpts, ?GET_OPT(connect_timeout,Options)) of
        {ok, Socket} ->
            start_link(client, Socket, Options, NegotiationTimeout);
        {error, Reason} ->
            {error, Reason}
    catch
        _:badarg -> {error, {options,?GET_OPT(socket_options,Options)}};
        _:{error,Reason} -> {error,Reason};
        error:Error -> {error,Error};
        Class:Error -> {error, {Class,Error}}
    end.

start_link(Role, Socket, Options, NegotiationTimeout) ->
    {ok, {Host,Port}} = inet:sockname(Socket),
    start_link(Role, Host, Port, Socket, Options, NegotiationTimeout).

start_link(Role, Host, Port, Socket, Options0, NegotiationTimeout) ->
    try
        Options1 = ?PUT_INTERNAL_OPT([{user_pid, self()}
                                     ], Options0),
        Profile = ?GET_OPT(profile, Options1),
        {ok, {SystemSup, SubSysSup}} =
            case Role of
                client -> sshc_sup:start_system_subsystem(Host, Port, Profile, Options1);
                server -> sshd_sup:start_system_subsystem(Host, Port, Profile, Options1)
            end,
        ConnectionSup = ssh_system_sup:connection_supervisor(SystemSup),
        Options = ?PUT_INTERNAL_OPT([{supervisors, [{system_sup, SystemSup},
                                                    {subsystem_sup, SubSysSup},
                                                    {connection_sup, ConnectionSup}]}
                                    ], Options1),
        case ssh_connection_sup:start_child(ConnectionSup,
                                            [?MODULE, [Role, Socket, Options], [{spawn_opt, [{message_queue_data,off_heap}]}]]
                                           ) of
            {ok, Pid} ->
                case socket_control(Socket, Pid, Options) of
                    ok ->
                        handshake(Pid, erlang:monitor(process,Pid), NegotiationTimeout);
                    {error, Reason} ->
                        {error, Reason}
                end;
            {error, Reason} ->
                {error, Reason}
        end
    catch
        exit:{noproc,{gen_server,call,_}} -> {error, ssh_not_started};
        _:{error,Error} -> {error,Error};
        error:Error -> {error,Error};
        Class:Error -> {error, {Class,Error}}
    end.

%%--------------------------------------------------------------------
-spec stop(connection_ref()
	  ) -> ok | {error, term()}.
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
stop(ConnectionHandler)->
    case call(ConnectionHandler, stop) of
       {error, closed} ->
	    ok;
	Other ->
	    Other
    end.<commit_msg>ssh: Cosmetic changes + some comments<commit_after>%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2008-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%
%%----------------------------------------------------------------------
%% Purpose: Handles an ssh connection, e.i. both the
%% setup SSH Transport Layer Protocol (RFC 4253), Authentication
%% Protocol (RFC 4252) and SSH connection Protocol (RFC 4255)
%% Details of the different protocols are
%% implemented in ssh_transport.erl, ssh_auth.erl and ssh_connection.erl
%% ----------------------------------------------------------------------

-module(ssh_connection_handler).

-behaviour(gen_statem).

-include("ssh.hrl").
-include("ssh_transport.hrl").
-include("ssh_auth.hrl").
-include("ssh_connect.hrl").

-include("ssh_fsm.hrl").

%%====================================================================
%%% Exports
%%====================================================================

%%% Start and stop
-export([start_link/4, start_link/5, start_link/6,
	 stop/1
	]).

%%% Internal application API
-export([available_hkey_algorithms/2,
	 open_channel/6,
         start_channel/5,
         handle_direct_tcpip/6,
	 request/6, request/7,
	 reply_request/3, 
         global_request/5,
         handle_ssh_msg_ext_info/2,
	 send/5,
         send_bytes/2,
         send_msg/2,
	 send_eof/2,
         send_disconnect/6,
         send_disconnect/7,
         store/3,
         retrieve/2,
	 info/1, info/2,
	 connection_info/2,
	 channel_info/3,
	 adjust_window/3, close/2,
	 disconnect/4,
	 get_print_info/1,
         set_sock_opts/2, get_sock_opts/2,
         prohibited_sock_option/1
	]).

%%% Behaviour callbacks
-export([init/1, callback_mode/0, handle_event/4, terminate/3,
	 format_status/2, code_change/4]).

%%% Exports not intended to be used :). They are used for spawning and tests
-export([init_ssh_record/3,		   % Export of this internal function
					   % intended for low-level protocol test suites
	 renegotiate/1, alg/1 % Export intended for test cases
	]).

-behaviour(ssh_dbg).
-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).


-define(call_disconnectfun_and_log_cond(LogMsg, DetailedText, StateName, D),
        call_disconnectfun_and_log_cond(LogMsg, DetailedText, ?MODULE, ?LINE, StateName, D)).

%%====================================================================
%% Start / stop
%%====================================================================

start_link(client, Host, Port, Options, NegotiationTimeout) ->
    {_, Callback, _} = ?GET_OPT(transport, Options),
    SocketOpts = [{active,false} | ?GET_OPT(socket_options,Options)],
    try Callback:connect(Host, Port, SocketOpts, ?GET_OPT(connect_timeout,Options)) of
        {ok, Socket} ->
            start_link(client, Socket, Options, NegotiationTimeout);
        {error, Reason} ->
            {error, Reason}
    catch
        _:badarg -> {error, {options,?GET_OPT(socket_options,Options)}};
        _:{error,Reason} -> {error,Reason};
        error:Error -> {error,Error};
        Class:Error -> {error, {Class,Error}}
    end.

start_link(Role, Socket, Options, NegotiationTimeout) ->
    {ok, {Host,Port}} = inet:sockname(Socket),
    start_link(Role, Host, Port, Socket, Options, NegotiationTimeout).

start_link(Role, Host, Port, Socket, Options0, NegotiationTimeout) ->
    try
        Options1 = ?PUT_INTERNAL_OPT([{user_pid, self()}
                                     ], Options0),
        Profile = ?GET_OPT(profile, Options1),
        Sup = case Role of
                client -> sshc_sup;
                server -> sshd_sup
            end,
        {ok, {SystemSup, SubSysSup}} =
            Sup:start_system_subsystem(Host, Port, Profile, Options1),
        ConnectionSup = ssh_system_sup:connection_supervisor(SystemSup),
        Options = ?PUT_INTERNAL_OPT([{supervisors, [{system_sup, SystemSup},
                                                    {subsystem_sup, SubSysSup},
                                                    {connection_sup, ConnectionSup}]}
                                    ], Options1),

        %% This is essentially gen_statem:start_link/3 :
        case ssh_connection_sup:start_child(ConnectionSup,
                                            [?MODULE,
                                             [Role, Socket, Options],
                                             [{spawn_opt, [{message_queue_data,off_heap}]}]]
                                           ) of
            {ok, Pid} ->
                %% Now the connection_handler process is started, but no message handling
                %% begins until the socket_control is called
                case socket_control(Socket, Pid, Options) of
                    ok ->
                        %% handshake returns {ok,Pid} after a successful connection setup.
                        %% or {error,Reason} after an unsuccesful one:
                        handshake(Pid, erlang:monitor(process,Pid), NegotiationTimeout);
                    {error, Reason} ->
                        {error, Reason}
                end;
            {error, Reason} ->
                {error, Reason}
        end
    catch
        exit:{noproc,{gen_server,call,_}} -> {error, ssh_not_started};
        _:{error,Error} -> {error,Error};
        error:Error -> {error,Error};
        Class:Error -> {error, {Class,Error}}
    end.

%%--------------------------------------------------------------------
-spec stop(connection_ref()
	  ) -> ok | {error, term()}.
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
stop(ConnectionHandler)->
    case call(ConnectionHandler, stop) of
       {error, closed} ->
	    ok;
	Other ->
	    Other
    end.
{'fraction_non_alphanumeric': 0.1948734801183043, 'fraction_numerical': 0.012651988169569504, 'mean_word_length': 2.2383612662942274, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 32, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '657137', 'n_tokens_mistral': 3605, 'n_tokens_neox': 3363, 'n_words': 798}