aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh/src/ssh.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssh/src/ssh.erl')
-rw-r--r--lib/ssh/src/ssh.erl215
1 files changed, 89 insertions, 126 deletions
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index c1be9f732d..c139556791 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -132,13 +132,12 @@ connect(Host, Port, UserOptions, Timeout) when is_integer(Port),
SocketOpts = [{active,false} | ?GET_OPT(socket_options,Options)],
try Transport:connect(Host, Port, SocketOpts, ConnectionTimeout) of
{ok, Socket} ->
- Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,Host}], Options),
+ Opts = ?PUT_INTERNAL_OPT([{user_pid,self()}, {host,fmt_host(Host)}], Options),
ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
{error, Reason} ->
{error, Reason}
catch
exit:{function_clause, _F} ->
- io:format('function_clause ~p~n',[_F]),
{error, {options, {transport, TransportOpts}}};
exit:badarg ->
{error, {options, {socket_options, SocketOpts}}}
@@ -311,16 +310,15 @@ handle_daemon_args(Host, UserOptions0) ->
%%%----------------------------------------------------------------
valid_socket_to_use(Socket, {tcp,_,_}) ->
%% Is this tcp-socket a valid socket?
- case {is_tcp_socket(Socket),
- {ok,[{active,false}]} == inet:getopts(Socket, [active])
- }
+ try {is_tcp_socket(Socket),
+ {ok,[{active,false}]} == inet:getopts(Socket, [active])
+ }
of
- {true, true} ->
- ok;
- {true, false} ->
- {error, not_passive_mode};
- _ ->
- {error, not_tcp_socket}
+ {true, true} -> ok;
+ {true, false} -> {error, not_passive_mode};
+ _ -> {error, not_tcp_socket}
+ catch
+ _:_ -> {error, bad_socket}
end;
valid_socket_to_use(_, {L4,_,_}) ->
@@ -340,13 +338,7 @@ start_daemon(_, _, {error,Error}) ->
start_daemon(socket, Socket, Options) ->
case valid_socket_to_use(Socket, ?GET_OPT(transport,Options)) of
ok ->
- try
- do_start_daemon(Socket, Options)
- catch
- throw:bad_fd -> {error,bad_fd};
- throw:bad_socket -> {error,bad_socket};
- _C:_E -> {error,{cannot_start_daemon,_C,_E}}
- end;
+ start_daemon(inet:sockname(Socket), Socket, Options);
{error,SockError} ->
{error,SockError}
end;
@@ -355,136 +347,107 @@ start_daemon(Host, Port, Options) ->
try
do_start_daemon(Host, Port, Options)
catch
- throw:bad_fd -> {error,bad_fd};
- throw:bad_socket -> {error,bad_socket};
- _C:_E -> {error,{cannot_start_daemon,_C,_E}}
+ throw:bad_fd ->
+ {error,bad_fd};
+ throw:bad_socket ->
+ {error,bad_socket};
+ error:{badmatch,{error,Error}} ->
+ {error,Error};
+ _C:_E ->
+ {error,{cannot_start_daemon,_C,_E}}
end.
+%%%----------------------------------------------------------------
+do_start_daemon({error,Error}, _, _) ->
+ {error,Error};
-do_start_daemon(Socket, Options) ->
- {ok, {IP,Port}} =
- try {ok,_} = inet:sockname(Socket)
- catch
- _:_ -> throw(bad_socket)
- end,
- Host = fmt_host(IP),
- Opts = ?PUT_INTERNAL_OPT([{connected_socket, Socket},
- {address, Host},
- {port, Port},
- {role, server}], Options),
-
- Profile = ?GET_OPT(profile, Options),
- case ssh_system_sup:system_supervisor(Host, Port, Profile) of
- undefined ->
- try sshd_sup:start_child(Opts) of
- {error, {already_started, _}} ->
- {error, eaddrinuse};
- Result = {ok,_} ->
- call_ssh_acceptor_handle_connection(Host, Port, Opts, Socket, Result);
- Result = {error, _} ->
- Result
- catch
- exit:{noproc, _} ->
- {error, ssh_not_started}
- end;
- Sup ->
- AccPid = ssh_system_sup:acceptor_supervisor(Sup),
- case ssh_acceptor_sup:start_child(AccPid, Opts) of
- {error, {already_started, _}} ->
- {error, eaddrinuse};
- {ok, _} ->
- call_ssh_acceptor_handle_connection(Host, Port, Opts, Socket, {ok,Sup});
- Other ->
- Other
- end
- end.
+do_start_daemon({ok, {IP,Port}}, Socket, Options0) ->
+ finalize_start(fmt_host(IP),
+ Port,
+ ?PUT_INTERNAL_OPT({connected_socket, Socket}, Options0),
+ fun(Opts, DefaultResult) ->
+ try ssh_acceptor:handle_established_connection(
+ ?GET_INTERNAL_OPT(address, Opts),
+ ?GET_INTERNAL_OPT(port, Opts),
+ Opts,
+ Socket)
+ of
+ {error,Error} ->
+ {error,Error};
+ _ ->
+ DefaultResult
+ catch
+ C:R ->
+ {error,{could_not_start_connection,{C,R}}}
+ end
+ end);
do_start_daemon(Host0, Port0, Options0) ->
- {Host,Port1} =
- try
- case ?GET_SOCKET_OPT(fd, Options0) of
- undefined ->
- {Host0,Port0};
- Fd when Port0==0 ->
- find_hostport(Fd)
- end
- catch
- _:_ -> throw(bad_fd)
- end,
- {Port, WaitRequestControl, Options1} =
- case Port1 of
- 0 -> %% Allocate the socket here to get the port number...
- {ok,LSock} = ssh_acceptor:callback_listen(0, Options0),
- {ok,{_,LPort}} = inet:sockname(LSock),
- {LPort,
- LSock,
- ?PUT_INTERNAL_OPT({lsocket,{LSock,self()}}, Options0)
- };
- _ ->
- {Port1, false, Options0}
- end,
+ {{Host,Port}, ListenSocket} =
+ open_listen_socket(Host0, Port0, Options0),
+
+ %% Now Host,Port is what to use for the supervisor to register its name,
+ %% and ListenSocket is for listening on connections. But it is still owned
+ %% by self()...
+
+ finalize_start(Host, Port,
+ ?PUT_INTERNAL_OPT({lsocket,{ListenSocket,self()}}, Options0),
+ fun(Opts, Result) ->
+ {_, Callback, _} = ?GET_OPT(transport, Opts),
+ receive
+ {request_control, ListenSocket, ReqPid} ->
+ ok = Callback:controlling_process(ListenSocket, ReqPid),
+ ReqPid ! {its_yours,ListenSocket},
+ Result
+ end
+ end).
+
+
+open_listen_socket(Host0, Port0, Options0) ->
+ case ?GET_SOCKET_OPT(fd, Options0) of
+ undefined ->
+ {ok,LSock} = ssh_acceptor:listen(Port0, Options0),
+ {ok,{_,LPort}} = inet:sockname(LSock),
+ {{fmt_host(Host0),LPort}, LSock};
+
+ Fd when is_integer(Fd) ->
+ %% Do gen_tcp:listen with the option {fd,Fd}:
+ {ok,LSock} = ssh_acceptor:listen(0, Options0),
+ {ok,{LHost,LPort}} = inet:sockname(LSock),
+ {{fmt_host(LHost),LPort}, LSock}
+ end.
+
+%%%----------------------------------------------------------------
+finalize_start(Host, Port, Options0, F) ->
Options = ?PUT_INTERNAL_OPT([{address, Host},
{port, Port},
- {role, server}], Options1),
- Profile = ?GET_OPT(profile, Options0),
+ {role, server}], Options0),
+ Profile = ?GET_OPT(profile, Options),
case ssh_system_sup:system_supervisor(Host, Port, Profile) of
undefined ->
try sshd_sup:start_child(Options) of
{error, {already_started, _}} ->
{error, eaddrinuse};
+ {error, Error} ->
+ {error, Error};
Result = {ok,_} ->
- sync_request_control(WaitRequestControl, Options),
- Result;
- Result = {error, _} ->
- Result
+ F(Options, Result)
catch
exit:{noproc, _} ->
{error, ssh_not_started}
end;
- Sup ->
+ Sup ->
AccPid = ssh_system_sup:acceptor_supervisor(Sup),
case ssh_acceptor_sup:start_child(AccPid, Options) of
{error, {already_started, _}} ->
{error, eaddrinuse};
+ {error, Error} ->
+ {error, Error};
{ok, _} ->
- sync_request_control(WaitRequestControl, Options),
- {ok, Sup};
- Other ->
- Other
+ F(Options, {ok,Sup})
end
end.
-call_ssh_acceptor_handle_connection(Host, Port, Options, Socket, DefaultResult) ->
- {_, Callback, _} = ?GET_OPT(transport, Options),
- try ssh_acceptor:handle_connection(Callback, Host, Port, Options, Socket)
- of
- {error,Error} -> {error,Error};
- _ -> DefaultResult
- catch
- C:R -> {error,{could_not_start_connection,{C,R}}}
- end.
-
-
-sync_request_control(false, _Options) ->
- ok;
-sync_request_control(LSock, Options) ->
- {_, Callback, _} = ?GET_OPT(transport, Options),
- receive
- {request_control,LSock,ReqPid} ->
- ok = Callback:controlling_process(LSock, ReqPid),
- ReqPid ! {its_yours,LSock},
- ok
- end.
-
-find_hostport(Fd) ->
- %% Using internal functions inet:open/8 and inet:close/0.
- %% Don't try this at home unless you know what you are doing!
- {ok,S} = inet:open(Fd, {0,0,0,0}, 0, [], tcp, inet, stream, inet_tcp),
- {ok, HostPort} = inet:sockname(S),
- ok = inet:close(S),
- HostPort.
-
-fmt_host({A,B,C,D}) ->
- lists:concat([A,".",B,".",C,".",D]);
-fmt_host(T={_,_,_,_,_,_,_,_}) ->
- lists:flatten(string:join([io_lib:format("~.16B",[A]) || A <- tuple_to_list(T)], ":")).
+%%%----------------------------------------------------------------
+fmt_host(IP) when is_tuple(IP) -> inet:ntoa(IP);
+fmt_host(Str) when is_list(Str) -> Str.