1%%-------------------------------------------------------------------- 2%% 3%% %CopyrightBegin% 4%% 5%% Copyright Ericsson AB 1999-2016. All Rights Reserved. 6%% 7%% Licensed under the Apache License, Version 2.0 (the "License"); 8%% you may not use this file except in compliance with the License. 9%% You may obtain a copy of the License at 10%% 11%% http://www.apache.org/licenses/LICENSE-2.0 12%% 13%% Unless required by applicable law or agreed to in writing, software 14%% distributed under the License is distributed on an "AS IS" BASIS, 15%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16%% See the License for the specific language governing permissions and 17%% limitations under the License. 18%% 19%% %CopyrightEnd% 20%% 21%% 22%%----------------------------------------------------------------- 23%% File: orber_iiop_pm.erl 24%% Description: 25%% This file contains the mapping of addresses on the format {Host, Port} 26%% to a proxy pid. 27%% 28%%----------------------------------------------------------------- 29-module(orber_iiop_pm). 30 31-behaviour(gen_server). 32 33-include_lib("orber/src/orber_iiop.hrl"). 34-include_lib("orber/include/corba.hrl"). 35-include_lib("kernel/include/inet.hrl"). 36 37%%----------------------------------------------------------------- 38%% External exports 39%%----------------------------------------------------------------- 40-export([start/0, start/1]). 41 42%%----------------------------------------------------------------- 43%% Internal exports 44%%----------------------------------------------------------------- 45-export([connect/7, 46 close_connection/1, close_connection/2, 47 list_existing_connections/0, 48 list_setup_connections/0, 49 list_all_connections/0, 50 init/1, handle_call/3, handle_cast/2, handle_info/2, 51 code_change/3, terminate/2, stop/0, setup_connection/8, 52 reconfigure/1, reconfigure/3, reconfigure/4, add_connection/3, 53 sockname2peername/2, peername2sockname/2]). 54 55%%----------------------------------------------------------------- 56%% Macros/Defines 57%%----------------------------------------------------------------- 58-define(DEBUG_LEVEL, 7). 59 60-define(PM_CONNECTION_DB, orber_iiop_pm_db). 61 62-record(state, {connections, queue}). 63 64-record(connection, {hp, child, interceptors, slave, 65 flags = 0, alias = 0, socketdata = {"Unavailable", 0}}). 66 67%%----------------------------------------------------------------- 68%% External interface functions 69%%----------------------------------------------------------------- 70start() -> 71 ignore. 72start(Opts) -> 73 gen_server:start_link({local, 'orber_iiop_pm'}, ?MODULE, Opts, []). 74 75 76connect(Host, Port, SocketType, Timeout, Chars, Wchars, Ctx) 77 when SocketType == normal -> 78 Key = create_key(Host, Port, Ctx), 79 case ets:lookup(?PM_CONNECTION_DB, Key) of 80 [#connection{child = connecting}] -> 81 gen_server:call(orber_iiop_pm, {connect, Host, Port, SocketType, 82 [], Chars, Wchars, Key}, Timeout); 83 [] -> 84 gen_server:call(orber_iiop_pm, {connect, Host, Port, SocketType, 85 [], Chars, Wchars, Key}, Timeout); 86 [#connection{hp = {_, _, 0}, child = P, interceptors = I}] -> 87 {ok, P, [], I, 0}; 88 [#connection{hp = {_, _, Interface}, child = P, interceptors = I}] -> 89 {ok, P, [], I, [Interface]} 90 end; 91connect(Host, Port, SocketType, Timeout, Chars, Wchars, Ctx) 92 when SocketType == ssl -> 93 Key = create_key(Host, Port, Ctx), 94 case ets:lookup(?PM_CONNECTION_DB, Key) of 95 [#connection{child = connecting}] -> 96 SocketOptions = get_ssl_socket_options(Ctx), 97 gen_server:call(orber_iiop_pm, {connect, Host, Port, SocketType, 98 SocketOptions, Chars, Wchars, Key}, 99 Timeout); 100 [] -> 101 SocketOptions = get_ssl_socket_options(Ctx), 102 gen_server:call(orber_iiop_pm, {connect, Host, Port, SocketType, 103 SocketOptions, Chars, Wchars, Key}, 104 Timeout); 105 [#connection{hp = {_, _, 0}, child = P, interceptors = I}] -> 106 {ok, P, [], I, 0}; 107 [#connection{hp = {_, _, Interface}, child = P, interceptors = I}] -> 108 {ok, P, [], I, [Interface]} 109 end. 110 111get_ssl_socket_options([]) -> 112 SSLOpts = 113 case orber_env:ssl_client_options() of 114 [] -> 115 [{verify, orber_env:ssl_client_verify()}, 116 {depth, orber_env:ssl_client_depth()}, 117 {certfile, orber_env:ssl_client_certfile()}, 118 {cacertfile, orber_env:ssl_client_cacertfile()}, 119 {password, orber_env:ssl_client_password()}, 120 {keyfile, orber_env:ssl_client_keyfile()}, 121 {ciphers, orber_env:ssl_client_ciphers()}, 122 {cachetimeout, orber_env:ssl_client_cachetimeout()}, 123 {keepalive, orber_env:iiop_ssl_out_keepalive()}]; 124 Opts -> 125 case orber_tb:check_illegal_tcp_options(Opts) of 126 ok -> 127 check_old_ssl_client_options([]), 128 Opts; 129 {error, IllegalOpts} -> 130 error_logger:error_report([{application, orber}, 131 "TCP options not allowed to set on a connection", 132 IllegalOpts]), 133 error("Illegal TCP option") 134 end 135 end, 136 ssl_client_extra_options(SSLOpts, []); 137get_ssl_socket_options([#'IOP_ServiceContext' 138 {context_id=?ORBER_GENERIC_CTX_ID, 139 context_data = {configuration, Options}}|_]) -> 140 SSLOpts = 141 case orber_tb:keysearch(ssl_client_options, Options, 142 orber_env:ssl_client_options()) of 143 [] -> 144 Verify = orber_tb:keysearch(ssl_client_verify, Options, 145 orber_env:ssl_client_verify()), 146 Depth = orber_tb:keysearch(ssl_client_depth, Options, 147 orber_env:ssl_client_depth()), 148 Cert = orber_tb:keysearch(ssl_client_certfile, Options, 149 orber_env:ssl_client_certfile()), 150 CaCert = orber_tb:keysearch(ssl_client_cacertfile, Options, 151 orber_env:ssl_client_cacertfile()), 152 Pwd = orber_tb:keysearch(ssl_client_password, Options, 153 orber_env:ssl_client_password()), 154 Key = orber_tb:keysearch(ssl_client_keyfile, Options, 155 orber_env:ssl_client_keyfile()), 156 Ciphers = orber_tb:keysearch(ssl_client_ciphers, Options, 157 orber_env:ssl_client_ciphers()), 158 Timeout = orber_tb:keysearch(ssl_client_cachetimeout, Options, 159 orber_env:ssl_client_cachetimeout()), 160 KeepAlive = orber_tb:keysearch(ssl_server_cachetimeout, Options, 161 orber_env:iiop_ssl_out_keepalive()), 162 [{verify, Verify}, 163 {depth, Depth}, 164 {certfile, Cert}, 165 {cacertfile, CaCert}, 166 {password, Pwd}, 167 {keyfile, Key}, 168 {ciphers, Ciphers}, 169 {cachetimeout, Timeout}, 170 {keepalive, KeepAlive}]; 171 Opts -> 172 case orber_tb:check_illegal_tcp_options(Opts) of 173 ok -> 174 check_old_ssl_client_options(Options), 175 Opts; 176 {error, IllegalOpts} -> 177 error_logger:error_report([{application, orber}, 178 "TCP options not allowed to set on a connection", 179 IllegalOpts]), 180 error("Illegal TCP option") 181 end 182 end, 183 ssl_client_extra_options(SSLOpts, []); 184get_ssl_socket_options([_|T]) -> 185 get_ssl_socket_options(T). 186 187 188ssl_client_extra_options([], Acc) -> 189 Acc; 190ssl_client_extra_options([{_Type, []}|T], Acc) -> 191 ssl_client_extra_options(T, Acc); 192ssl_client_extra_options([{_Type, infinity}|T], Acc) -> 193 ssl_client_extra_options(T, Acc); 194ssl_client_extra_options([{Type, Value}|T], Acc) -> 195 ssl_client_extra_options(T, [{Type, Value}|Acc]). 196 197add_connection(Key, Key, SockData) -> 198 case ets:lookup(?PM_CONNECTION_DB, Key) of 199 [Connection] -> 200 ets:insert(?PM_CONNECTION_DB, 201 Connection#connection{socketdata = SockData}); 202 [] -> 203 ets:insert(?PM_CONNECTION_DB, 204 #connection{hp= Key, child = connecting, 205 socketdata = SockData}) 206 end; 207add_connection(Key, NewKey, SockData) -> 208 add_connection(Key, Key, SockData), 209 add_connection(NewKey, NewKey, SockData). 210 211get_socket_data(Key) -> 212 case ets:lookup(?PM_CONNECTION_DB, Key) of 213 [#connection{socketdata = SockData}] -> 214 SockData; 215 _ -> 216 {"Unable to extract socket information", 0} 217 end. 218 219sockname2peername(SockHost, SockPort) -> 220 orber_tb:unique( 221 do_select([{#connection{hp = {'$1', '$2', '_'}, 222 socketdata = {match_type(SockHost), 223 match_type(SockPort)}, 224 _='_'}, [], [{{'$1', '$2'}}]}])). 225 226 227peername2sockname(PeerHost, PeerPort) -> 228 orber_tb:unique( 229 do_select([{#connection{hp = {match_type(PeerHost), 230 match_type(PeerPort), 231 '_'}, 232 socketdata = '$1', 233 _='_'}, [], ['$1']}])). 234 235match_type(0) -> 236 %% Wildcard port number 237 '_'; 238match_type("") -> 239 %% Wildcard host 240 '_'; 241match_type(Key) -> 242 %% Wildcard not used. 243 Key. 244 245create_key(Host, Port, []) -> 246 {Host, Port, 0}; 247create_key(Host, Port, 248 [#'IOP_ServiceContext' 249 {context_id=?ORBER_GENERIC_CTX_ID, 250 context_data = {interface, Interface}}|_]) when is_list(Interface) -> 251 {Host, Port, Interface}; 252create_key(Host, Port, 253 [#'IOP_ServiceContext' 254 {context_id=?ORBER_GENERIC_CTX_ID, 255 context_data = {interface, Interface}}|_]) -> 256 orber:dbg("[~p] orber_iiop_pm:create_key(~p, ~p);~n" 257 "The supplied interface must be a string.", 258 [?LINE, Host, Port, Interface], ?DEBUG_LEVEL), 259 corba:raise(#'BAD_CONTEXT'{completion_status=?COMPLETED_NO}); 260create_key(Host, Port, [_|T]) -> 261 create_key(Host, Port, T). 262 263reconfigure(Options) -> 264 {Local, Proxy} = check_options(Options, [], []), 265 reconfigure_local(Local), 266 reconfigure_proxy(Proxy). 267 268 269reconfigure(Options, Host, Port) -> 270 reconfigure(Options, Host, Port, 0). 271reconfigure(Options, Host, Port, Interface) -> 272 case ets:lookup(?PM_CONNECTION_DB, {Host, Port, Interface}) of 273 [#connection{child = P}] when is_pid(P) -> 274 case check_options(Options, [], []) of 275 {[], Proxy} -> 276 reconfigure_proxy(Proxy, [P]); 277 {Local, Proxy} -> 278 reconfigure_proxy(Proxy, [P]), 279 gen_server:call(orber_iiop_pm, {reconfigure, Local, 280 Host, Port, Interface}, infinity) 281 end; 282 _ -> 283 {error, "No proxy matched the supplied reference"} 284 end. 285 286reconfigure_local([]) -> 287 ok; 288reconfigure_local(Options) -> 289 gen_server:call(orber_iiop_pm, {reconfigure, Options}, infinity). 290 291reconfigure_proxy([]) -> 292 ok; 293reconfigure_proxy(Options) -> 294 reconfigure_proxy(Options, do_select([{#connection{child = '$1', _='_'}, 295 [], ['$1']}])). 296 297reconfigure_proxy(Options, [Pid|T]) -> 298 Pid ! {reconfigure, Options}, 299 reconfigure_proxy(Options, T); 300reconfigure_proxy(_Options, []) -> 301 ok. 302 303 304check_options([{interceptors, false}|Options], Local, Proxy) -> 305 check_options(Options, [{interceptors, false}|Local], Proxy); 306check_options([{interceptors, {native, LPIs}}|Options], Local, Proxy) -> 307 check_options(Options, [{interceptors, {native, LPIs}}|Local], Proxy); 308check_options([{fake, option}|Options], Local, Proxy) -> 309 check_options(Options, Local, [{fake, option}|Proxy]); 310check_options([_|Options], Local, Proxy) -> 311 check_options(Options, Local, Proxy); 312check_options([], Local, Proxy) -> 313 {Local, Proxy}. 314 315 316close_connection(PeerData) -> 317 close_connection(PeerData, 0). 318 319close_connection(PeerData, Interface) -> 320 gen_server:call(orber_iiop_pm, {disconnect, PeerData, Interface}, infinity). 321 322 323list_existing_connections() -> 324 transform( 325 lists:sort( 326 do_select([{#connection{hp = {'$2','$3','$4'}, child = '$1', _='_'}, 327 [{is_pid, '$1'}], [{{'$1', '$2','$3','$4'}}]}])), []). 328 329list_setup_connections() -> 330 transform( 331 lists:sort( 332 do_select([{#connection{hp = {'$1','$2','$3'}, child = connecting, _='_'}, [], 333 [{{'$1','$2','$3'}}]}])), []). 334 335list_all_connections() -> 336 transform( 337 lists:sort( 338 do_select([{#connection{hp = {'$2','$3','$4'}, child = '$1', _='_'}, [], 339 [{{'$1','$2','$3', '$4'}}]}])), []). 340 341%% Since the connections interface can be 0 or an ip-address we want to 342%% transform those containing 0. 343transform([{C, H, P, 0}, {C, H, P, I}|T], Acc) -> 344 %% ACL defined interface. Drop the anonymous one. 345 transform(T, [{H, P, I}|Acc]); 346transform([{_C, H, P, 0}|T], Acc) -> 347 %% No interface supplied. Drop the 0. 348 transform(T, [{H, P}|Acc]); 349transform([{_C, H, P, I}|T], Acc) -> 350 %% Interface supplied. Keep it. 351 transform(T, [{H, P, I}|Acc]); 352transform([{H,P,0}|T], Acc) -> 353 transform(T, [{H,P}|Acc]); 354transform([{H,P,I}|T], Acc) -> 355 transform(T, [{H,P,I}|Acc]); 356transform([H|T], Acc) -> 357 transform(T, [H|Acc]); 358transform([], Acc) -> 359 Acc. 360 361do_select(Pattern) -> 362 case catch ets:select(?PM_CONNECTION_DB, Pattern) of 363 {'EXIT', _What} -> 364 []; 365 Result -> 366 Result 367 end. 368 369%%----------------------------------------------------------------- 370%% Internal interface functions 371%%----------------------------------------------------------------- 372%%----------------------------------------------------------------- 373%% Func: stop/0 (Only used for test purpose !!!!!!) 374%%----------------------------------------------------------------- 375stop() -> 376 gen_server:call(orber_iiop_pm, stop). 377 378%%----------------------------------------------------------------- 379%% Server functions 380%%----------------------------------------------------------------- 381%%----------------------------------------------------------------- 382%% Func: init/1 383%%----------------------------------------------------------------- 384init(_Opts) -> 385 process_flag(trap_exit, true), 386 {ok, #state{connections = ets:new(orber_iiop_pm_db, 387 [{keypos, 2}, set, public, named_table]), 388 queue = ets:new(orber_iiop_pm_queue, [bag])}}. 389 390%%----------------------------------------------------------------- 391%% Func: terminate/2 392%%----------------------------------------------------------------- 393terminate(_Reason, #state{queue = Q}) -> 394 %% Kill all proxies and close table before terminating 395 stop_all_proxies(ets:first(?PM_CONNECTION_DB)), 396 ets:delete(?PM_CONNECTION_DB), 397 ets:delete(Q), 398 ok. 399 400stop_all_proxies('$end_of_table') -> 401 ok; 402stop_all_proxies(Key) -> 403 case ets:lookup(?PM_CONNECTION_DB, Key) of 404 [] -> 405 ok; 406 [#connection{child = connecting, interceptors = I}] -> 407 invoke_connection_closed(I); 408 [#connection{child = P, interceptors = I}] -> 409 invoke_connection_closed(I), 410 catch orber_iiop_outproxy:stop(P) 411 end, 412 stop_all_proxies(ets:next(?PM_CONNECTION_DB, Key)). 413 414%%----------------------------------------------------------------- 415%% Func: handle_call/3 416%%----------------------------------------------------------------- 417handle_call({connect, Host, Port, SocketType, SocketOptions, Chars, Wchars, Key}, 418 From, State) -> 419 case ets:lookup(?PM_CONNECTION_DB, Key) of 420 [#connection{child = connecting}] -> 421 %% Another client already requested a connection to the given host/port. 422 %% Just add this client to the queue. 423 ets:insert(State#state.queue, {Key, From}), 424 {noreply, State}; 425 [#connection{hp = {_,_,0}, child = P, interceptors = I}] -> 426 %% This case will occur if the PortMapper completed a connection 427 %% between the client's ets:lookup and receiving this request. 428 {reply, {ok, P, [], I, 0}, State}; 429 [#connection{hp = {_,_,Intf}, child = P, interceptors = I}] -> 430 %% This case will occur if the PortMapper completed a connection 431 %% between the client's ets:lookup and receiving this request. 432 {reply, {ok, P, [], I, [Intf]}, State}; 433 [] -> 434 %% The first time a connection is requested to the given host/port. 435 case catch spawn_link(?MODULE, setup_connection, 436 [self(), Host, Port, SocketType, 437 SocketOptions, Chars, Wchars, Key]) of 438 Slave when is_pid(Slave) -> 439 ets:insert(?PM_CONNECTION_DB, 440 #connection{hp = Key, child = connecting, 441 interceptors = false, slave = Slave}), 442 ets:insert(State#state.queue, {Key, From}), 443 {noreply, State}; 444 What -> 445 orber:dbg("[~p] orber_iiop_pm:handle_call(connect);~n" 446 "Unable to invoke setup_connection due to: ~n~p~n", 447 [?LINE, What], ?DEBUG_LEVEL), 448 {reply, 449 {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}}, 450 State} 451 end 452 end; 453handle_call({disconnect, PeerData, Interface}, _From, State) -> 454 {reply, do_disconnect(PeerData, Interface, State), State}; 455handle_call({reconfigure, Options, Host, Port, Interface}, 456 _From, State) -> 457 case ets:lookup(?PM_CONNECTION_DB, {Host, Port, Interface}) of 458 [] -> 459 {reply, {error, "No proxy matched the supplied reference"}, State}; 460 [Connection] -> 461 NewConnection = update_connection(Connection, Options), 462 ets:insert(?PM_CONNECTION_DB, NewConnection), 463 {reply, ok, State} 464 end; 465handle_call({reconfigure, Options}, _From, State) -> 466 case catch update_db(ets:first(?PM_CONNECTION_DB), Options) of 467 ok -> 468 {reply, ok, State}; 469 _What -> 470 {reply, {error, "Unable to change configuration"}, State} 471 end; 472handle_call(stop, _From, State) -> 473 {stop, normal, ok, State}; 474handle_call(_, _, State) -> 475 {noreply, State}. 476 477update_db('$end_of_table', _) -> 478 ok; 479update_db(Key, Options) -> 480 [Connection] = ets:lookup(?PM_CONNECTION_DB, Key), 481 NewConnection = update_connection(Connection, Options), 482 ets:insert(?PM_CONNECTION_DB, NewConnection), 483 update_db(ets:next(?PM_CONNECTION_DB, Key), Options). 484 485 486update_connection(Connection, [{interceptors, false}|Options]) -> 487 update_connection(Connection#connection{interceptors = false}, Options); 488update_connection(#connection{interceptors = false, 489 hp = {PH, PP, _}, 490 socketdata = {SH, SP}} = Connection, 491 [{interceptors, {native, LPIs}}|Options]) -> 492 %% No Interceptor(s). Add the same Ref used by the built in interceptors. 493 update_connection(Connection#connection{interceptors = 494 {native, {PH, PP, SH, SP}, LPIs}}, 495 Options); 496update_connection(#connection{interceptors = {native, Ref, _}} = Connection, 497 [{interceptors, {native, LPIs}}|Options]) -> 498 %% Interceptor(s) already in use. We must use the same Ref as before. 499 update_connection(Connection#connection{interceptors = 500 {native, Ref, LPIs}}, 501 Options); 502update_connection(Connection, [H|T]) -> 503 orber:dbg("[~p] orber_iiop_pm:update_connection(~p, ~p)~n" 504 "Unable to update the connection.~n", 505 [?LINE, Connection, H], ?DEBUG_LEVEL), 506 update_connection(Connection, T); 507update_connection(Connection, []) -> 508 Connection. 509 510do_disconnect([], _Interface, _State) -> 511 ok; 512do_disconnect([{Host, Port}|T], Interface, State) -> 513 case ets:lookup(?PM_CONNECTION_DB, {Host, Port, Interface}) of 514 [] -> 515 ok; 516 [#connection{child = connecting, interceptors = I}] -> 517 ets:delete(?PM_CONNECTION_DB, {Host, Port, Interface}), 518 Exc = {'EXCEPTION',#'INTERNAL'{completion_status = ?COMPLETED_NO}}, 519 send_reply_to_queue(ets:lookup(State#state.queue, 520 {Host, Port, Interface}), Exc), 521 ets:delete(State#state.queue, {Host, Port, Interface}), 522 invoke_connection_closed(I); 523 [#connection{child = P, interceptors = I}] -> 524 unlink(P), 525 catch orber_iiop_outproxy:stop(P), 526 ets:delete(?PM_CONNECTION_DB, {Host, Port, Interface}), 527 invoke_connection_closed(I) 528 end, 529 do_disconnect(T, Interface, State). 530 531%%----------------------------------------------------------------- 532%% Func: handle_cast/2 533%%----------------------------------------------------------------- 534handle_cast(stop, State) -> 535 {stop, normal, State}; 536handle_cast(_, State) -> 537 {noreply, State}. 538 539%%----------------------------------------------------------------- 540%% Func: handle_info/2 541%%----------------------------------------------------------------- 542%% Trapping exits 543handle_info({'EXIT', Pid, Reason}, State) -> 544 %% Check the most common scenario first, i.e., a proxy terminates. 545 case ets:match_object(?PM_CONNECTION_DB, #connection{child = Pid, _='_'}) of 546 [#connection{hp = K, interceptors = I}] -> 547 ets:delete(?PM_CONNECTION_DB, K), 548 invoke_connection_closed(I), 549 {noreply, State}; 550 [#connection{hp = K, interceptors = I}, #connection{hp = K2}] -> 551 ets:delete(?PM_CONNECTION_DB, K), 552 ets:delete(?PM_CONNECTION_DB, K2), 553 invoke_connection_closed(I), 554 {noreply, State}; 555 [] when Reason == normal -> 556 %% This might have been a spawned 'setup_connection' which terminated 557 %% after sucessfully setting up a new connection. 558 {noreply, State}; 559 [] -> 560 %% Wasn't a proxy. Hence, we must test if it was a spawned 561 %% 'setup_connection' that failed. 562 case ets:match_object(?PM_CONNECTION_DB, #connection{slave = Pid, _='_'}) of 563 [#connection{hp = K, child = connecting, interceptors = I}] -> 564 ets:delete(?PM_CONNECTION_DB, K), 565 invoke_connection_closed(I), 566 Exc = {'EXCEPTION',#'INTERNAL'{completion_status = ?COMPLETED_NO}}, 567 send_reply_to_queue(ets:lookup(State#state.queue, K), Exc), 568 ets:delete(State#state.queue, K), 569 orber:dbg("[~p] orber_iiop_pm:handle_info(setup_failed ~p);~n" 570 "It was not possible to create a connection to the" 571 " given host/port.", 572 [?LINE, K], ?DEBUG_LEVEL), 573 {noreply, State}; 574 [#connection{hp = K, child = connecting, interceptors = I}, 575 #connection{hp = K2}] -> 576 ets:delete(?PM_CONNECTION_DB, K), 577 ets:delete(?PM_CONNECTION_DB, K2), 578 invoke_connection_closed(I), 579 Exc = {'EXCEPTION',#'INTERNAL'{completion_status = ?COMPLETED_NO}}, 580 send_reply_to_queue(ets:lookup(State#state.queue, K), Exc), 581 ets:delete(State#state.queue, K), 582 orber:dbg("[~p] orber_iiop_pm:handle_info(setup_failed ~p);~n" 583 "It was not possible to create a connection to the" 584 " given host/port.", 585 [?LINE, K], ?DEBUG_LEVEL), 586 {noreply, State}; 587 _ -> 588 {noreply, State} 589 end 590 end; 591handle_info({setup_failed, {Host, Port, _} = Key, Key, Exc}, State) -> 592 %% Deletet the data from the connection DB first to avoid clients from 593 %% trying to access it again. 594 ets:delete(?PM_CONNECTION_DB, Key), 595 %% Now we can send whatever exception received. 596 send_reply_to_queue(ets:lookup(State#state.queue, Key), Exc), 597 ets:delete(State#state.queue, Key), 598 orber:dbg("[~p] orber_iiop_pm:handle_info(setup_failed ~p ~p);~n" 599 "It was not possible to create a connection to the given host/port.", 600 [?LINE, Host, Port], ?DEBUG_LEVEL), 601 {noreply, State}; 602handle_info({setup_failed, {Host, Port, _} = Key, NewKey, Exc}, State) -> 603 %% Deletet the data from the connection DB first to avoid clients from 604 %% trying to access it again. 605 ets:delete(?PM_CONNECTION_DB, Key), 606 ets:delete(?PM_CONNECTION_DB, NewKey), 607 %% Now we can send whatever exception received. 608 send_reply_to_queue(ets:lookup(State#state.queue, Key), Exc), 609 ets:delete(State#state.queue, Key), 610 orber:dbg("[~p] orber_iiop_pm:handle_info(setup_failed ~p ~p);~n" 611 "It was not possible to create a connection to the given host/port.", 612 [?LINE, Host, Port], ?DEBUG_LEVEL), 613 {noreply, State}; 614handle_info({setup_successfull, Key, Key, {Child, Ctx, Int}}, State) -> 615 %% Create a link to the proxy and store it in the connection DB. 616 link(Child), 617 case ets:lookup(?PM_CONNECTION_DB, Key) of 618 [Connection] -> 619 ets:insert(?PM_CONNECTION_DB, 620 Connection#connection{hp = Key, child = Child, 621 interceptors = Int, 622 slave = undefined}); 623 [] -> 624 ets:insert(?PM_CONNECTION_DB, 625 #connection{hp = Key, child = Child, 626 interceptors = Int, 627 slave = undefined}) 628 end, 629 %% Send the Proxy reference to all waiting clients. 630 case Key of 631 {_, _, 0} -> 632 send_reply_to_queue(ets:lookup(State#state.queue, Key), 633 {ok, Child, Ctx, Int, 0}); 634 {_, _, Interface} -> 635 send_reply_to_queue(ets:lookup(State#state.queue, Key), 636 {ok, Child, Ctx, Int, [Interface]}) 637 end, 638 %% Reset the queue. 639 ets:delete(State#state.queue, Key), 640 {noreply, State}; 641handle_info({setup_successfull, Key, NewKey, {Child, Ctx, Int}}, State) -> 642 %% Create a link to the proxy and store it in the connection DB. 643 link(Child), 644 case ets:lookup(?PM_CONNECTION_DB, NewKey) of 645 [Connection] -> 646 ets:insert(?PM_CONNECTION_DB, 647 Connection#connection{hp = NewKey, child = Child, 648 interceptors = Int, 649 slave = undefined}); 650 [] -> 651 ets:insert(?PM_CONNECTION_DB, 652 #connection{hp = NewKey, child = Child, 653 interceptors = Int, 654 slave = undefined}) 655 end, 656 case ets:lookup(?PM_CONNECTION_DB, Key) of 657 [Connection2] -> 658 ets:insert(?PM_CONNECTION_DB, 659 Connection2#connection{hp = Key, child = Child, 660 interceptors = Int, 661 slave = undefined}); 662 [] -> 663 ets:insert(?PM_CONNECTION_DB, 664 #connection{hp = Key, child = Child, 665 interceptors = Int, 666 slave = undefined}) 667 end, 668 %% Send the Proxy reference to all waiting clients. 669 case NewKey of 670 {_, _, 0} -> 671 send_reply_to_queue(ets:lookup(State#state.queue, Key), 672 {ok, Child, Ctx, Int, 0}); 673 {_, _, Interface} -> 674 send_reply_to_queue(ets:lookup(State#state.queue, Key), 675 {ok, Child, Ctx, Int, [Interface]}) 676 end, 677 %% Reset the queue. 678 ets:delete(State#state.queue, Key), 679 {noreply, State}; 680handle_info(_, State) -> 681 {noreply, State}. 682 683 684send_reply_to_queue([], _) -> 685 ok; 686send_reply_to_queue([{_, Client}|T], Reply) -> 687 gen_server:reply(Client, Reply), 688 send_reply_to_queue(T, Reply). 689 690%%----------------------------------------------------------------- 691%% Func: code_change/3 692%%----------------------------------------------------------------- 693code_change(_OldVsn, State, _Extra) -> 694 {ok, State}. 695 696%%----------------------------------------------------------------- 697%% Internal functions 698%%----------------------------------------------------------------- 699setup_connection(PMPid, Host, Port, SocketType, SocketOptions, Chars, Wchars, Key) -> 700 case catch access_allowed(Host, Port, SocketType, Key) of 701 ok -> 702 do_setup_connection(PMPid, Host, Port, SocketType, SocketOptions, 703 Chars, Wchars, Key, Key); 704 {ok, Interface} -> 705 do_setup_connection(PMPid, Host, Port, SocketType, 706 [{ip, Interface}|SocketOptions], 707 Chars, Wchars, Key, Key); 708 {ok, Interface, NewKey} -> 709 do_setup_connection(PMPid, Host, Port, SocketType, 710 [{ip, Interface}|SocketOptions], 711 Chars, Wchars, Key, NewKey); 712 false -> 713 orber_tb:info("Blocked connect attempt to ~s - ~p", [Host, Port]), 714 PMPid ! {setup_failed, Key, Key, 715 {'EXCEPTION', #'NO_PERMISSION'{completion_status=?COMPLETED_NO}}}, 716 ok; 717 Reason -> 718 orber:dbg("[~p] orber_iiop_pm:handle_call(connect ~p ~p); failed~n" 719 "Reason: ~p", 720 [?LINE, Host, Port, Reason], ?DEBUG_LEVEL), 721 PMPid ! {setup_failed, Key, Key, 722 {'EXCEPTION', #'COMM_FAILURE'{completion_status=?COMPLETED_NO}}}, 723 ok 724 end. 725 726 727do_setup_connection(PMPid, Host, Port, SocketType, SocketOptions, Chars, 728 Wchars, Key, NewKey) -> 729 case catch orber_iiop_outsup:connect(Host, Port, SocketType, 730 SocketOptions, PMPid, Key, NewKey) of 731 {error, {'EXCEPTION', E}} -> 732 orber:dbg("[~p] orber_iiop_pm:handle_call(connect ~p ~p);~n" 733 "Raised Exc: ~p", 734 [?LINE, Host, Port, E], ?DEBUG_LEVEL), 735 PMPid ! {setup_failed, Key, NewKey, {'EXCEPTION', E}}, 736 ok; 737 {error, Reason} -> 738 orber:dbg("[~p] orber_iiop_pm:handle_call(connect ~p ~p);~n" 739 "Got EXIT: ~p", 740 [?LINE, Host, Port, Reason], ?DEBUG_LEVEL), 741 PMPid ! {setup_failed, Key, NewKey, 742 {'EXCEPTION', #'INTERNAL'{completion_status=?COMPLETED_NO}}}, 743 ok; 744 {ok, undefined} -> 745 orber:dbg("[~p] orber_iiop_pm:handle_call(connect ~p ~p);~n" 746 "Probably no listener on the given Node/Port or timedout.", 747 [?LINE, Host, Port], ?DEBUG_LEVEL), 748 PMPid ! {setup_failed, Key, NewKey, 749 {'EXCEPTION', #'COMM_FAILURE'{minor=(?ORBER_VMCID bor 1), 750 completion_status=?COMPLETED_NO}}}, 751 ok; 752 {ok, Child} -> 753 case init_interceptors(Host, Port, get_socket_data(Key)) of 754 {'EXCEPTION', E} -> 755 PMPid ! {setup_failed, Key, NewKey, {'EXCEPTION', E}}, 756 ok; 757 Interceptors -> 758 BiDirCtx = orber:bidir_context(), 759 Ctx = case orber:exclude_codeset_ctx() of 760 true -> 761 BiDirCtx; 762 _ -> 763 CodeSetCtx = 764 #'CONV_FRAME_CodeSetContext' 765 {char_data = Chars, 766 wchar_data = Wchars}, 767 [#'IOP_ServiceContext' 768 {context_id=?IOP_CodeSets, 769 context_data = CodeSetCtx} | BiDirCtx] 770 end, 771 PMPid ! {setup_successfull, Key, NewKey, 772 {Child, Ctx, Interceptors}}, 773 ok 774 end 775 end. 776 777access_allowed(Host, Port, Type, {_,_,UserInterface}) -> 778 Flags = orber:get_flags(), 779 case ?ORB_FLAG_TEST(Flags, ?ORB_ENV_USE_ACL_OUTGOING) of 780 false when UserInterface == 0 -> 781 get_local_interface(Type); 782 false -> 783 inet:getaddr(UserInterface, get_ip_family(UserInterface)); 784 true -> 785 SearchFor = 786 case Type of 787 normal -> 788 tcp_out; 789 ssl -> 790 ssl_out 791 end, 792 {ok, Ip} = inet:getaddr(Host, get_ip_family(Host)), 793 case orber_acl:match(Ip, SearchFor, true) of 794 {true, [], 0} -> 795 get_local_interface(Type); 796 {true, [], Port} -> 797 get_local_interface(Type); 798 {true, [], {Min, Max}} when Port >= Min, Port =< Max -> 799 get_local_interface(Type); 800 {true, [Interface], 0} -> 801 {ok, NewIp} = inet:getaddr(Interface, get_ip_family(Interface)), 802 {ok, NewIp, {Host, Port, 0}}; 803 {true, [Interface], Port} -> 804 805 {ok, NewIp} = inet:getaddr(Interface, get_ip_family(Interface)), 806 {ok, NewIp, {Host, Port, 0}}; 807 {true, [Interface], {Min, Max}} when Port >= Min, Port =< Max -> 808 809 {ok, NewIp} = inet:getaddr(Interface, get_ip_family(Interface)), 810 {ok, NewIp, {Host, Port, 0}}; 811 _ -> 812 false 813 end 814 end. 815 816get_local_interface(normal) -> 817 case orber_env:ip_address_local() of 818 [] -> 819 ok; 820 [Interface] -> 821 inet:getaddr(Interface, get_ip_family(Interface)) 822 end; 823get_local_interface(ssl) -> 824 case orber_env:iiop_ssl_ip_address_local() of 825 [] -> 826 ok; 827 [Interface] -> 828 inet:getaddr(Interface, get_ip_family(Interface)) 829 end. 830 831get_ip_family(Addr) -> 832 [Family] = orber_socket:get_ip_family_opts(Addr), 833 Family. 834 835invoke_connection_closed(false) -> 836 ok; 837invoke_connection_closed({native, Ref, PIs}) -> 838 (catch orber_pi:closed_out_connection(PIs, Ref)); 839invoke_connection_closed({_Type, _PIs}) -> 840 ok. 841 842 843init_interceptors(Host, Port, {SHost, SPort}) -> 844 case orber:get_interceptors() of 845 {native, PIs} -> 846 case catch orber_pi:new_out_connection(PIs, Host, Port, SHost, SPort) of 847 {'EXIT', R} -> 848 orber:dbg("[~p] orber_iiop_pm:init_interceptors(~p); Got Exit: ~p.~n" 849 "One or more Interceptor incorrect or undefined?", 850 [?LINE, PIs, R], ?DEBUG_LEVEL), 851 {'EXCEPTION', #'COMM_FAILURE'{minor=(?ORBER_VMCID bor 2), 852 completion_status=?COMPLETED_NO}}; 853 IntRef -> 854 {native, IntRef, PIs} 855 end; 856 Other -> 857 %% Either 'false' or {Type, PIs}. 858 Other 859 end. 860 861 862check_old_ssl_client_options(Options) -> 863 try 864 0 = orber_tb:keysearch(ssl_client_verify, Options, 865 orber_env:ssl_client_verify()), 866 1 = orber_tb:keysearch(ssl_client_depth, Options, 867 orber_env:ssl_client_depth()), 868 [] = orber_tb:keysearch(ssl_client_certfile, Options, 869 orber_env:ssl_client_certfile()), 870 [] = orber_tb:keysearch(ssl_client_cacertfile, Options, 871 orber_env:ssl_client_cacertfile()), 872 [] = orber_tb:keysearch(ssl_client_password, Options, 873 orber_env:ssl_client_password()), 874 [] = orber_tb:keysearch(ssl_client_keyfile, Options, 875 orber_env:ssl_client_keyfile()), 876 [] = orber_tb:keysearch(ssl_client_ciphers, Options, 877 orber_env:ssl_client_ciphers()), 878 infinity = orber_tb:keysearch(ssl_client_cachetimeout, Options, 879 orber_env:ssl_client_cachetimeout()), 880 false = orber_tb:keysearch(iiop_ssl_out_keepalive, Options, 881 orber_env:iiop_ssl_out_keepalive()) 882 883 catch 884 _:_ -> 885 error_logger:warning_report([{application, orber}, 886 "Ignoring deprecated ssl client options used together with the ssl_client_options"]) 887 end. 888 889 890 891 892%%----------------------------------------------------------------- 893%% END OF MODULE 894%%----------------------------------------------------------------- 895