1%% ``Licensed under the Apache License, Version 2.0 (the "License"); 2%% you may not use this file except in compliance with the License. 3%% You may obtain a copy of the License at 4%% 5%% http://www.apache.org/licenses/LICENSE-2.0 6%% 7%% Unless required by applicable law or agreed to in writing, software 8%% distributed under the License is distributed on an "AS IS" BASIS, 9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10%% See the License for the specific language governing permissions and 11%% limitations under the License. 12%% 13%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. 14%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings 15%% AB. All Rights Reserved.'' 16%% 17%% $Id$ 18%% 19-module(uds_dist). 20 21%% Handles the connection setup phase with other Erlang nodes. 22 23-export([childspecs/0, listen/1, accept/1, accept_connection/5, 24 setup/4, close/1, select/1, is_node_name/1]). 25 26%% internal exports 27 28-export([accept_loop/2,do_accept/6,do_setup/5, getstat/1,tick/1]). 29 30-import(error_logger,[error_msg/2]). 31 32-include("net_address.hrl"). 33 34 35 36-define(to_port(Socket, Data), 37 case uds:send(Socket, Data) of 38 {error, closed} -> 39 self() ! {uds_closed, Socket}, 40 {error, closed}; 41 R -> 42 R 43 end). 44 45 46-include("dist.hrl"). 47-include("dist_util.hrl"). 48-record(tick, {read = 0, 49 write = 0, 50 tick = 0, 51 ticked = 0 52 }). 53 54 55%% ------------------------------------------------------------- 56%% This function should return a valid childspec, so that 57%% the primitive ssl_server gets supervised 58%% ------------------------------------------------------------- 59childspecs() -> 60 {ok, [{uds_server,{uds_server, start_link, []}, 61 permanent, 2000, worker, [uds_server]}]}. 62 63 64%% ------------------------------------------------------------ 65%% Select this protocol based on node name 66%% select(Node) => Bool 67%% ------------------------------------------------------------ 68 69select(Node) -> 70 {ok, MyHost} = inet:gethostname(), 71 case split_node(atom_to_list(Node), $@, []) of 72 [_, MyHost] -> 73 true; 74 _ -> 75 false 76 end. 77 78%% ------------------------------------------------------------ 79%% Create the listen socket, i.e. the port that this erlang 80%% node is accessible through. 81%% ------------------------------------------------------------ 82 83listen(Name) -> 84 case uds:listen(atom_to_list(Name)) of 85 {ok, Socket} -> 86 {ok, {Socket, 87 #net_address{address = [], 88 host = inet:gethostname(), 89 protocol = uds, 90 family = uds}, 91 uds:get_creation(Socket)}}; 92 Error -> 93 Error 94 end. 95 96%% ------------------------------------------------------------ 97%% Accepts new connection attempts from other Erlang nodes. 98%% ------------------------------------------------------------ 99 100accept(Listen) -> 101 spawn_link(?MODULE, accept_loop, [self(), Listen]). 102 103accept_loop(Kernel, Listen) -> 104 process_flag(priority, max), 105 case uds:accept(Listen) of 106 {ok, Socket} -> 107 Kernel ! {accept,self(),Socket,uds,uds}, 108 controller(Kernel, Socket), 109 accept_loop(Kernel, Listen); 110 Error -> 111 exit(Error) 112 end. 113 114controller(Kernel, Socket) -> 115 receive 116 {Kernel, controller, Pid} -> 117 uds:controlling_process(Socket, Pid), 118 Pid ! {self(), controller}; 119 {Kernel, unsupported_protocol} -> 120 exit(unsupported_protocol) 121 end. 122 123%% ------------------------------------------------------------ 124%% Accepts a new connection attempt from another Erlang node. 125%% Performs the handshake with the other side. 126%% ------------------------------------------------------------ 127 128accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> 129 spawn_link(?MODULE, do_accept, 130 [self(), AcceptPid, Socket, MyNode, 131 Allowed, SetupTime]). 132 133do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> 134 process_flag(priority, max), 135 receive 136 {AcceptPid, controller} -> 137 Timer = dist_util:start_timer(SetupTime), 138 HSData = #hs_data{ 139 kernel_pid = Kernel, 140 this_node = MyNode, 141 socket = Socket, 142 timer = Timer, 143 this_flags = ?DFLAG_PUBLISHED bor 144 ?DFLAG_ATOM_CACHE bor 145 ?DFLAG_EXTENDED_REFERENCES bor 146 ?DFLAG_DIST_MONITOR bor 147 ?DFLAG_FUN_TAGS, 148 allowed = Allowed, 149 f_send = fun(S,D) -> uds:send(S,D) end, 150 f_recv = fun(S,N,T) -> uds:recv(S) 151 end, 152 f_setopts_pre_nodeup = 153 fun(S) -> 154 uds:set_mode(S, intermediate) 155 end, 156 f_setopts_post_nodeup = 157 fun(S) -> 158 uds:set_mode(S, data) 159 end, 160 f_getll = fun(S) -> 161 uds:get_port(S) 162 end, 163 f_address = fun get_remote_id/2, 164 mf_tick = {?MODULE, tick}, 165 mf_getstat = {?MODULE,getstat} 166 }, 167 dist_util:handshake_other_started(HSData) 168 end. 169 170%% ------------------------------------------------------------ 171%% Get remote information about a Socket. 172%% ------------------------------------------------------------ 173 174get_remote_id(Socket, Node) -> 175 [_, Host] = split_node(atom_to_list(Node), $@, []), 176 #net_address { 177 address = [], 178 host = Host, 179 protocol = uds, 180 family = uds }. 181 182%% ------------------------------------------------------------ 183%% Setup a new connection to another Erlang node. 184%% Performs the handshake with the other side. 185%% ------------------------------------------------------------ 186 187setup(Node, MyNode, LongOrShortNames,SetupTime) -> 188 spawn_link(?MODULE, do_setup, [self(), 189 Node, 190 MyNode, 191 LongOrShortNames, 192 SetupTime]). 193 194do_setup(Kernel, Node, MyNode, LongOrShortNames,SetupTime) -> 195 process_flag(priority, max), 196 ?trace("~p~n",[{uds_dist,self(),setup,Node}]), 197 [Name, Address] = splitnode(Node, LongOrShortNames), 198 {ok, MyName} = inet:gethostname(), 199 case Address of 200 MyName -> 201 Timer = dist_util:start_timer(SetupTime), 202 case uds:connect(Name) of 203 {ok, Socket} -> 204 HSData = #hs_data{ 205 kernel_pid = Kernel, 206 other_node = Node, 207 this_node = MyNode, 208 socket = Socket, 209 timer = Timer, 210 this_flags = ?DFLAG_PUBLISHED bor 211 ?DFLAG_ATOM_CACHE bor 212 ?DFLAG_EXTENDED_REFERENCES bor 213 ?DFLAG_DIST_MONITOR bor 214 ?DFLAG_FUN_TAGS, 215 other_version = 1, 216 f_send = fun(S,D) -> 217 uds:send(S,D) 218 end, 219 f_recv = fun(S,N,T) -> 220 uds:recv(S) 221 end, 222 f_setopts_pre_nodeup = 223 fun(S) -> 224 uds:set_mode(S, intermediate) 225 end, 226 f_setopts_post_nodeup = 227 fun(S) -> 228 uds:set_mode(S, data) 229 end, 230 f_getll = fun(S) -> 231 uds:get_port(S) 232 end, 233 f_address = 234 fun(_,_) -> 235 #net_address{ 236 address = [], 237 host = Address, 238 protocol = uds, 239 family = uds} 240 end, 241 mf_tick = {?MODULE, tick}, 242 mf_getstat = {?MODULE,getstat} 243 }, 244 dist_util:handshake_we_started(HSData); 245 _ -> 246 ?shutdown(Node) 247 end; 248 Other -> 249 ?shutdown(Node) 250 end. 251 252%% 253%% Close a socket. 254%% 255close(Socket) -> 256 uds:close(Socket). 257 258 259%% If Node is illegal terminate the connection setup!! 260splitnode(Node, LongOrShortNames) -> 261 case split_node(atom_to_list(Node), $@, []) of 262 [Name|Tail] when Tail /= [] -> 263 Host = lists:append(Tail), 264 case split_node(Host, $., []) of 265 [_] when LongOrShortNames == longnames -> 266 error_msg("** System running to use " 267 "fully qualified " 268 "hostnames **~n" 269 "** Hostname ~s is illegal **~n", 270 [Host]), 271 ?shutdown(Node); 272 L when length(L) > 1, LongOrShortNames == shortnames -> 273 error_msg("** System NOT running to use fully qualified " 274 "hostnames **~n" 275 "** Hostname ~s is illegal **~n", 276 [Host]), 277 ?shutdown(Node); 278 _ -> 279 [Name, Host] 280 end; 281 [_] -> 282 error_msg("** Nodename ~p illegal, no '@' character **~n", 283 [Node]), 284 ?shutdown(Node); 285 _ -> 286 error_msg("** Nodename ~p illegal **~n", [Node]), 287 ?shutdown(Node) 288 end. 289 290split_node([Chr|T], Chr, Ack) -> [lists:reverse(Ack)|split_node(T, Chr, [])]; 291split_node([H|T], Chr, Ack) -> split_node(T, Chr, [H|Ack]); 292split_node([], _, Ack) -> [lists:reverse(Ack)]. 293 294is_node_name(Node) when atom(Node) -> 295 case split_node(atom_to_list(Node), $@, []) of 296 [_, Host] -> true; 297 _ -> false 298 end; 299is_node_name(Node) -> 300 false. 301 302tick(Sock) -> 303 uds:tick(Sock). 304getstat(Socket) -> 305 uds:get_status_counters(Socket). 306