aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/examples/uds_dist/src/uds_dist.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/kernel/examples/uds_dist/src/uds_dist.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/kernel/examples/uds_dist/src/uds_dist.erl')
-rw-r--r--lib/kernel/examples/uds_dist/src/uds_dist.erl304
1 files changed, 304 insertions, 0 deletions
diff --git a/lib/kernel/examples/uds_dist/src/uds_dist.erl b/lib/kernel/examples/uds_dist/src/uds_dist.erl
new file mode 100644
index 0000000000..7a9c15a3c8
--- /dev/null
+++ b/lib/kernel/examples/uds_dist/src/uds_dist.erl
@@ -0,0 +1,304 @@
+%% ``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 via the world wide web 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.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(uds_dist).
+
+%% Handles the connection setup phase with other Erlang nodes.
+
+-export([childspecs/0, listen/1, accept/1, accept_connection/5,
+ setup/4, close/1, select/1, is_node_name/1]).
+
+%% internal exports
+
+-export([accept_loop/2,do_accept/6,do_setup/5, getstat/1,tick/1]).
+
+-import(error_logger,[error_msg/2]).
+
+-include("net_address.hrl").
+
+
+
+-define(to_port(Socket, Data),
+ case uds:send(Socket, Data) of
+ {error, closed} ->
+ self() ! {uds_closed, Socket},
+ {error, closed};
+ R ->
+ R
+ end).
+
+
+-include("dist.hrl").
+-include("dist_util.hrl").
+-record(tick, {read = 0,
+ write = 0,
+ tick = 0,
+ ticked = 0
+ }).
+
+
+%% -------------------------------------------------------------
+%% This function should return a valid childspec, so that
+%% the primitive ssl_server gets supervised
+%% -------------------------------------------------------------
+childspecs() ->
+ {ok, [{uds_server,{uds_server, start_link, []},
+ permanent, 2000, worker, [uds_server]}]}.
+
+
+%% ------------------------------------------------------------
+%% Select this protocol based on node name
+%% select(Node) => Bool
+%% ------------------------------------------------------------
+
+select(Node) ->
+ {ok, MyHost} = inet:gethostname(),
+ case split_node(atom_to_list(Node), $@, []) of
+ [_, MyHost] ->
+ true;
+ _ ->
+ false
+ end.
+
+%% ------------------------------------------------------------
+%% Create the listen socket, i.e. the port that this erlang
+%% node is accessible through.
+%% ------------------------------------------------------------
+
+listen(Name) ->
+ case uds:listen(atom_to_list(Name)) of
+ {ok, Socket} ->
+ {ok, {Socket,
+ #net_address{address = [],
+ host = inet:gethostname(),
+ protocol = uds,
+ family = uds},
+ uds:get_creation(Socket)}};
+ Error ->
+ Error
+ end.
+
+%% ------------------------------------------------------------
+%% Accepts new connection attempts from other Erlang nodes.
+%% ------------------------------------------------------------
+
+accept(Listen) ->
+ spawn_link(?MODULE, accept_loop, [self(), Listen]).
+
+accept_loop(Kernel, Listen) ->
+ process_flag(priority, max),
+ case uds:accept(Listen) of
+ {ok, Socket} ->
+ Kernel ! {accept,self(),Socket,uds,uds},
+ controller(Kernel, Socket),
+ accept_loop(Kernel, Listen);
+ Error ->
+ exit(Error)
+ end.
+
+controller(Kernel, Socket) ->
+ receive
+ {Kernel, controller, Pid} ->
+ uds:controlling_process(Socket, Pid),
+ Pid ! {self(), controller};
+ {Kernel, unsupported_protocol} ->
+ exit(unsupported_protocol)
+ end.
+
+%% ------------------------------------------------------------
+%% Accepts a new connection attempt from another Erlang node.
+%% Performs the handshake with the other side.
+%% ------------------------------------------------------------
+
+accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
+ spawn_link(?MODULE, do_accept,
+ [self(), AcceptPid, Socket, MyNode,
+ Allowed, SetupTime]).
+
+do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
+ process_flag(priority, max),
+ receive
+ {AcceptPid, controller} ->
+ Timer = dist_util:start_timer(SetupTime),
+ HSData = #hs_data{
+ kernel_pid = Kernel,
+ this_node = MyNode,
+ socket = Socket,
+ timer = Timer,
+ this_flags = ?DFLAG_PUBLISHED bor
+ ?DFLAG_ATOM_CACHE bor
+ ?DFLAG_EXTENDED_REFERENCES bor
+ ?DFLAG_DIST_MONITOR bor
+ ?DFLAG_FUN_TAGS,
+ allowed = Allowed,
+ f_send = fun(S,D) -> uds:send(S,D) end,
+ f_recv = fun(S,N,T) -> uds:recv(S)
+ end,
+ f_setopts_pre_nodeup =
+ fun(S) ->
+ uds:set_mode(S, intermediate)
+ end,
+ f_setopts_post_nodeup =
+ fun(S) ->
+ uds:set_mode(S, data)
+ end,
+ f_getll = fun(S) ->
+ uds:get_port(S)
+ end,
+ f_address = fun get_remote_id/2,
+ mf_tick = {?MODULE, tick},
+ mf_getstat = {?MODULE,getstat}
+ },
+ dist_util:handshake_other_started(HSData)
+ end.
+
+%% ------------------------------------------------------------
+%% Get remote information about a Socket.
+%% ------------------------------------------------------------
+
+get_remote_id(Socket, Node) ->
+ [_, Host] = split_node(atom_to_list(Node), $@, []),
+ #net_address {
+ address = [],
+ host = Host,
+ protocol = uds,
+ family = uds }.
+
+%% ------------------------------------------------------------
+%% Setup a new connection to another Erlang node.
+%% Performs the handshake with the other side.
+%% ------------------------------------------------------------
+
+setup(Node, MyNode, LongOrShortNames,SetupTime) ->
+ spawn_link(?MODULE, do_setup, [self(),
+ Node,
+ MyNode,
+ LongOrShortNames,
+ SetupTime]).
+
+do_setup(Kernel, Node, MyNode, LongOrShortNames,SetupTime) ->
+ process_flag(priority, max),
+ ?trace("~p~n",[{uds_dist,self(),setup,Node}]),
+ [Name, Address] = splitnode(Node, LongOrShortNames),
+ {ok, MyName} = inet:gethostname(),
+ case Address of
+ MyName ->
+ Timer = dist_util:start_timer(SetupTime),
+ case uds:connect(Name) of
+ {ok, Socket} ->
+ HSData = #hs_data{
+ kernel_pid = Kernel,
+ other_node = Node,
+ this_node = MyNode,
+ socket = Socket,
+ timer = Timer,
+ this_flags = ?DFLAG_PUBLISHED bor
+ ?DFLAG_ATOM_CACHE bor
+ ?DFLAG_EXTENDED_REFERENCES bor
+ ?DFLAG_DIST_MONITOR bor
+ ?DFLAG_FUN_TAGS,
+ other_version = 1,
+ f_send = fun(S,D) ->
+ uds:send(S,D)
+ end,
+ f_recv = fun(S,N,T) ->
+ uds:recv(S)
+ end,
+ f_setopts_pre_nodeup =
+ fun(S) ->
+ uds:set_mode(S, intermediate)
+ end,
+ f_setopts_post_nodeup =
+ fun(S) ->
+ uds:set_mode(S, data)
+ end,
+ f_getll = fun(S) ->
+ uds:get_port(S)
+ end,
+ f_address =
+ fun(_,_) ->
+ #net_address{
+ address = [],
+ host = Address,
+ protocol = uds,
+ family = uds}
+ end,
+ mf_tick = {?MODULE, tick},
+ mf_getstat = {?MODULE,getstat}
+ },
+ dist_util:handshake_we_started(HSData);
+ _ ->
+ ?shutdown(Node)
+ end;
+ Other ->
+ ?shutdown(Node)
+ end.
+
+%%
+%% Close a socket.
+%%
+close(Socket) ->
+ uds:close(Socket).
+
+
+%% If Node is illegal terminate the connection setup!!
+splitnode(Node, LongOrShortNames) ->
+ case split_node(atom_to_list(Node), $@, []) of
+ [Name|Tail] when Tail /= [] ->
+ Host = lists:append(Tail),
+ case split_node(Host, $., []) of
+ [_] when LongOrShortNames == longnames ->
+ error_msg("** System running to use "
+ "fully qualified "
+ "hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown(Node);
+ L when length(L) > 1, LongOrShortNames == shortnames ->
+ error_msg("** System NOT running to use fully qualified "
+ "hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown(Node);
+ _ ->
+ [Name, Host]
+ end;
+ [_] ->
+ error_msg("** Nodename ~p illegal, no '@' character **~n",
+ [Node]),
+ ?shutdown(Node);
+ _ ->
+ error_msg("** Nodename ~p illegal **~n", [Node]),
+ ?shutdown(Node)
+ end.
+
+split_node([Chr|T], Chr, Ack) -> [lists:reverse(Ack)|split_node(T, Chr, [])];
+split_node([H|T], Chr, Ack) -> split_node(T, Chr, [H|Ack]);
+split_node([], _, Ack) -> [lists:reverse(Ack)].
+
+is_node_name(Node) when atom(Node) ->
+ case split_node(atom_to_list(Node), $@, []) of
+ [_, Host] -> true;
+ _ -> false
+ end;
+is_node_name(Node) ->
+ false.
+
+tick(Sock) ->
+ uds:tick(Sock).
+getstat(Socket) ->
+ uds:get_status_counters(Socket).