1%%--------------------------------------------------------------------
2%%
3%% %CopyrightBegin%
4%%
5%% Copyright Ericsson AB 1997-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.erl
24%% Description:
25%%    This file contains the interface to the iiop operations
26%%
27%%-----------------------------------------------------------------
28-module(orber_iiop).
29
30-include_lib("orber/include/corba.hrl").
31-include_lib("orber/src/orber_iiop.hrl").
32
33-behaviour(supervisor).
34%%-----------------------------------------------------------------
35%% External exports
36%%-----------------------------------------------------------------
37-export([start_sup/1, request/8, locate/4]).
38
39%%-----------------------------------------------------------------
40%% Internal exports
41%%-----------------------------------------------------------------
42-export([init/1, terminate/2, handle_call/3]).
43
44%%-----------------------------------------------------------------
45%% Internal defines
46%%-----------------------------------------------------------------
47-define(DEBUG_LEVEL, 7).
48
49
50%%-----------------------------------------------------------------
51%% External interface functions
52%%-----------------------------------------------------------------
53%%-----------------------------------------------------------------
54%% Func: start_sup/1
55%%-----------------------------------------------------------------
56start_sup(Opts) ->
57    supervisor:start_link({local, orber_iiop_sup}, ?MODULE,
58			  {orber_iiop_sup, Opts}).
59
60%%%-----------------------------------------------------------------
61%%% Func: connect/1
62%%%-----------------------------------------------------------------
63%connect(OrbName) ->
64%    orber_iiop_net:connect(OrbName).
65
66%%%-----------------------------------------------------------------
67%%% Func: request/5
68%%%-----------------------------------------------------------------
69request({Host, Port, InitObjkey, Index, TaggedProfile, HostData},
70	Op, Parameters, TypeCodes, ResponseExpected, Timeout, IOR, UserCtx) ->
71    {{Proxy, SysCtx, Interceptors, LocalInterface}, ObjKey, Version} =
72	connect(Host, Port, InitObjkey, Timeout, [Index], HostData,
73		TaggedProfile, IOR, UserCtx),
74    Ctx = add_user_context(SysCtx, UserCtx),
75    RequestId = orber_request_number:get(),
76    Env = #giop_env{interceptors = Interceptors, type = out,
77		    flags = orber_env:get_flags(), host = LocalInterface,
78		    version = Version, ctx = Ctx, request_id = RequestId, op = Op,
79		    parameters = Parameters, tc = TypeCodes, objkey = ObjKey,
80		    response_expected = ResponseExpected},
81    Message = encode_request(Env),
82    case catch orber_iiop_outproxy:request(Proxy, ResponseExpected, Timeout,
83					   Message, RequestId) of
84	{'EXCEPTION', MsgExc} ->
85	    corba:raise(MsgExc);
86	_ when ResponseExpected == false ->
87	    ok;
88	{reply, ReplyHeader, Rest, Len, ByteOrder, Bytes} ->
89	    case catch decode_reply_body(Interceptors, ObjKey, Op, ReplyHeader,
90					 Version, TypeCodes, Rest, Len, ByteOrder,
91					 Bytes) of
92		{'EXCEPTION', DecodeException} ->
93		    %% We cannot log this exception since it may be a correct exception.
94		    corba:raise(DecodeException);
95		{'EXIT', message_error} ->
96		    orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
97			      "Got exit(message_error)",
98			      [?LINE, Rest, Version, TypeCodes], ?DEBUG_LEVEL),
99		    corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
100		{'EXIT', Why} ->
101		    orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
102			      "Got exit(~p)",
103			      [?LINE, Rest, Version, TypeCodes, Why], ?DEBUG_LEVEL),
104		    corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
105		'message_error' ->
106		    orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p);~n"
107			      "Got message_error",
108			      [?LINE, Rest, Version, TypeCodes], ?DEBUG_LEVEL),
109                    %% Perhaps a resend should be done when a message error occurs
110		    corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
111		{Result, Par} ->
112                    %% Check request id
113		    case ReplyHeader#reply_header.reply_status of
114			'no_exception' ->
115			    case Par of
116				[] ->
117				    Result;
118				_ ->
119				    list_to_tuple([Result | Par])
120			    end;
121			'system_exception' ->
122			    corba:raise(Result);
123			'user_exception' ->
124			    corba:raise(Result);
125			'location_forward' ->
126			    case get(orber_forward_notify) of
127				true ->
128				   {location_forward, Result};
129				_ ->
130				    case catch corba:call(Result, Op, Parameters,
131							  TypeCodes,
132							  [{timeout, Timeout},
133							   {context, UserCtx}]) of
134					{'EXCEPTION', E} ->
135					    corba:raise(E);
136					{'EXIT', Reason} ->
137					    orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
138						      "location_forward resulted in exit(~p)",
139						      [?LINE, Rest, Version, TypeCodes, Reason], ?DEBUG_LEVEL),
140					    corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO});
141					NewResult ->
142					    NewResult
143				    end
144			    end;
145			'location_forward_perm' ->
146                            %% We should notify the client in this case.
147			    case get(orber_forward_notify) of
148				true ->
149				   {location_forward, Result};
150				_ ->
151				    case catch corba:call(Result, Op, Parameters,
152                                                          TypeCodes,
153							  [{timeout, Timeout},
154							   {context, UserCtx}]) of
155					{'EXCEPTION', E} ->
156					    corba:raise(E);
157					{'EXIT', Reason} ->
158					    orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
159						      "location_forward_perm resulted in exit(~p)",
160						      [?LINE, Rest, Version, TypeCodes, Reason], ?DEBUG_LEVEL),
161					    corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO});
162					NewResult ->
163					    NewResult
164				    end
165			    end;
166			'needs_addressing_mode' ->
167			    orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
168				      "needs_addressing_mode not supported.",
169				      [?LINE, Rest, Version, TypeCodes], ?DEBUG_LEVEL),
170			    corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
171		    end
172	    end;
173        What ->
174            orber:dbg("[~p] orber_iiop:request(reply, ~p, ~p, ~p)~n"
175		      "outproxy-request: ~p", [?LINE, Message, Version, TypeCodes, What], ?DEBUG_LEVEL),
176            corba:raise(#'COMM_FAILURE'{completion_status=?COMPLETED_NO})
177    end.
178
179-dialyzer({no_improper_lists, encode_request/1}).
180encode_request(#giop_env{interceptors = false} = Env) ->
181    case catch cdr_encode:enc_request(Env) of
182	{'EXCEPTION', Exc} ->
183	    orber:dbg("[~p] orber_iiop:request(~p)~n"
184		      "Got exception(~p)",
185		      [?LINE, Env, Exc], ?DEBUG_LEVEL),
186	    corba:raise(Exc);
187	{'EXIT', R} ->
188	    orber:dbg("[~p] orber_iiop:request:( ~p )~n"
189		      "Got exit(~p)",
190		      [?LINE, Env, R], ?DEBUG_LEVEL),
191	    corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
192	Msg ->
193	    Msg
194    end;
195encode_request(#giop_env{interceptors = {native, Ref, PIs},
196			 objkey = ObjKey, ctx = Ctx, op = Op,
197			 parameters = Params} = Env) ->
198    Parameters = orber_pi:out_request(PIs, ObjKey, Ctx, Op, Ref, Params),
199    case catch cdr_encode:enc_request_split(Env) of
200	{'EXCEPTION', Exc} ->
201	    orber:dbg("[~p] orber_iiop:request( ~p, ~p); exception(~p)",
202		      [?LINE, Env, Parameters, Exc], ?DEBUG_LEVEL),
203	    corba:raise(Exc);
204	{'EXIT', R} ->
205	    orber:dbg("[~p] orber_iiop:request:( ~p, ~p); got exit(~p)",
206		      [?LINE, Env, Parameters, R], ?DEBUG_LEVEL),
207	    corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
208	{Hdr, Body, HdrLen, _, Flags} ->
209	    NewBody = orber_pi:out_request_enc(PIs, ObjKey, Ctx, Op, Ref, Body),
210	    cdr_encode:enc_giop_message_header(Env, 'request', Flags,
211					       HdrLen+size(NewBody),
212					       [Hdr|NewBody])
213    end;
214encode_request(Env) ->
215    case catch cdr_encode:enc_request(Env) of
216	{'EXCEPTION', Exc} ->
217	    orber:dbg("[~p] orber_iiop:request( ~p ); exception(~p)",
218		      [?LINE, Env, Exc], ?DEBUG_LEVEL),
219	    corba:raise(Exc);
220	{'EXIT', R} ->
221	    orber:dbg("[~p] orber_iiop:request:( ~p ); got exit(~p)",
222		      [?LINE, Env, R], ?DEBUG_LEVEL),
223	    corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
224	Msg ->
225	    Msg
226    end.
227
228%%-----------------------------------------------------------------
229%% Func: locate/1
230%%-----------------------------------------------------------------
231locate({Host, Port, InitObjkey, Index, TaggedProfile, HostData},
232       Timeout, IOR, UserCtx) ->
233    {{Proxy, _Ctx, _Interceptors, LocalInterface}, ObjKey, Version} =
234	connect(Host, Port, InitObjkey, Timeout, [Index], HostData,
235		TaggedProfile, IOR, UserCtx),
236    RequestId = orber_request_number:get(),
237    Env = #giop_env{version = Version, objkey = ObjKey, request_id = RequestId,
238		    flags = orber_env:get_flags(), host = LocalInterface},
239    Result =
240	case catch cdr_encode:enc_locate_request(Env) of
241	    {'EXCEPTION', EncE} ->
242		orber:dbg("[~p] orber_iiop:locate(~p); exception(~p)",
243			  [?LINE, ObjKey, EncE], ?DEBUG_LEVEL),
244		corba:raise(EncE);
245	    {'EXIT', EncR} ->
246		orber:dbg("[~p] orber_iiop:locate(~p); exit(~p)",
247			  [?LINE, ObjKey, EncR], ?DEBUG_LEVEL),
248		corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO});
249	    Request ->
250		(catch orber_iiop_outproxy:request(Proxy, true, Timeout,
251						   Request, RequestId))
252	end,
253    case Result of
254	{'EXCEPTION', MsgExc} ->
255	    corba:raise(MsgExc);
256	{locate_reply, ReplyHeader, Rest, Len, ByteOrder} ->
257	    case catch cdr_decode:dec_locate_reply_body(Version,
258							ReplyHeader#locate_reply_header.locate_status,
259							Rest, Len, ByteOrder) of
260		{'EXCEPTION', DecodeException} ->
261		    orber:dbg("[~p] orber_iiop:locate(locate_reply, ~p, ~p); exception(~p)",
262			      [?LINE, Rest, Version, DecodeException], ?DEBUG_LEVEL),
263		    corba:raise(DecodeException);
264		{'EXIT', message_error} ->
265		    orber:dbg("[~p] orber_iiop:locate(locate_reply, ~p, ~p); exit(message_error)",
266					    [?LINE, Rest, Version], ?DEBUG_LEVEL),
267		    corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
268		{'EXIT', R} ->
269		    orber:dbg("[~p] orber_iiop:locate(locate_reply, ~p, ~p); exit(~p)",
270			      [?LINE, Rest, Version, R], ?DEBUG_LEVEL),
271		    corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE});
272		[] ->
273		    ReplyHeader#locate_reply_header.locate_status;
274		ObjRef ->
275		    {ReplyHeader#locate_reply_header.locate_status, ObjRef}
276	    end;
277	Other ->
278	    orber:dbg("[~p] orber_iiop:locate(~p); exit(~p)",
279		      [?LINE, ObjKey, Other], ?DEBUG_LEVEL),
280	    corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO})
281    end.
282
283%%%-----------------------------------------------------------------
284%%% Func: cancel/1
285%%%-----------------------------------------------------------------
286%cancel(X) ->
287%	ok.
288
289%%%-----------------------------------------------------------------
290%%% Func: message_error/1
291%%%-----------------------------------------------------------------
292%message_error(X) ->
293%	ok.
294
295%%-----------------------------------------------------------------
296%% Server functions
297%%-----------------------------------------------------------------
298%%-----------------------------------------------------------------
299%% Func: init/1
300%%-----------------------------------------------------------------
301init({orber_iiop_sup, Opts}) ->
302    IIOP_port      =  orber:iiop_port(),
303    SSL_port       =  orber:iiop_ssl_port(),
304    SupFlags       = {one_for_one, 5, 1000},	%Max 5 restarts in 1 second
305    PortList = if
306		   SSL_port > -1 ->
307		       [{port, ssl, SSL_port}];
308		   true ->
309		       []
310		 end,
311    ChildSpec =
312	case orber:is_lightweight() of
313	    true ->
314		[
315		 {orber_iiop_outsup, {orber_iiop_outsup, start,
316				      [sup, Opts]},
317		  permanent, 10000, supervisor, [orber_iiop_outsup]},
318		 {orber_iiop_pm, {orber_iiop_pm, start,
319				  [Opts]},
320		  permanent, 10000, worker, [orber_iiop_pm]}
321		];
322	    false ->
323		[{orber_iiop_outsup, {orber_iiop_outsup, start,
324				      [sup, Opts]},
325		  permanent, 10000, supervisor, [orber_iiop_outsup]},
326		 {orber_iiop_pm, {orber_iiop_pm, start,
327				  [Opts]},
328		  permanent, 10000, worker, [orber_iiop_pm]},
329		 {orber_iiop_insup, {orber_iiop_insup, start,
330				     [sup, Opts]},
331		  permanent, 10000, supervisor, [orber_iiop_insup]},
332		 {orber_iiop_socketsup, {orber_iiop_socketsup, start,
333					 [sup, Opts]},
334		  permanent, 10000, supervisor, [orber_iiop_socketsup]},
335		 {orber_iiop_net, {orber_iiop_net, start,
336				   [[{port, normal, IIOP_port} | PortList]]},
337		  permanent, 10000, worker, [orber_iiop_net]}]
338	end,
339    {ok, {SupFlags, ChildSpec}}.
340
341
342
343
344
345%%-----------------------------------------------------------------
346%% Func: terminate/2
347%%-----------------------------------------------------------------
348terminate(_Reason, _State) ->
349    ok.
350
351%%-----------------------------------------------------------------
352%% Func: handle_call/3
353%%-----------------------------------------------------------------
354handle_call(_Req, _From, State) ->
355    {reply, ok, State}.
356
357
358%%-----------------------------------------------------------------
359%% Internal functions
360%%-----------------------------------------------------------------
361add_user_context([], UserCtx) -> UserCtx;
362add_user_context(SysCtx, []) -> SysCtx;
363add_user_context(SysCtx, UserCtx) -> SysCtx ++ UserCtx.
364
365decode_reply_body(false, _ObjKey, _Op, ReplyHeader, Version, TypeCodes,
366		  Rest, Len, ByteOrder, Bytes) ->
367    case ReplyHeader#reply_header.reply_status of
368	'no_exception' ->
369	    {R, P, _} = cdr_decode:dec_reply_body(Version, TypeCodes, Rest, Len, ByteOrder, Bytes),
370	    {R, P};
371	'system_exception' ->
372	    {R, _} = cdr_decode:dec_system_exception(Version, Rest, Len, ByteOrder),
373	    {R, []};
374	'user_exception' ->
375	    {R, _} = cdr_decode:dec_user_exception(Version, Rest, Len, ByteOrder),
376	    {R, []};
377	'location_forward' ->
378	    {R, _, _} = cdr_decode:dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]},
379						  Rest, Len, ByteOrder, Bytes),
380	    {R, []};
381	'location_forward_perm' ->
382	    {R, _, _} = cdr_decode:dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]},
383						  Rest, Len, ByteOrder, Bytes),
384	    {R, []};
385	'needs_addressing_mode' ->
386	    {R, _, _} = cdr_decode:dec_reply_body(Version, {'tk_short', [],[]},
387						  Rest, Len, ByteOrder, Bytes),
388	    {R, []}
389    end;
390decode_reply_body(Interceptors, ObjKey, Op, ReplyHeader, Version, TypeCodes,
391		  RestIn, Len, ByteOrder, Bytes) ->
392    Rest =
393        case Interceptors of
394            {portable, _PIs} ->
395                RestIn;
396            {native, Ref, PIs} ->
397                orber_pi:in_reply_enc(PIs, ObjKey,
398				      ReplyHeader#reply_header.service_context,
399				      Op, Ref, RestIn)
400        end,
401    Reply =
402	case ReplyHeader#reply_header.reply_status of
403	    'no_exception' ->
404		{R, P, _} = cdr_decode:dec_reply_body(Version, TypeCodes, Rest, Len, ByteOrder, Bytes),
405		{R, P};
406	    'system_exception' ->
407		{R, _} = cdr_decode:dec_system_exception(Version, Rest, Len, ByteOrder),
408		{R, []};
409	    'user_exception' ->
410		{R, _} = cdr_decode:dec_user_exception(Version, Rest, Len, ByteOrder),
411		{R, []};
412	    'location_forward' ->
413		{R, _, _} = cdr_decode:dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]},
414						      Rest, Len, ByteOrder, Bytes),
415		{R, []};
416	    'location_forward_perm' ->
417		{R, _, _} = cdr_decode:dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]},
418						      Rest, Len, ByteOrder, Bytes),
419		{R, []};
420	    'needs_addressing_mode' ->
421		{R, _, _} = cdr_decode:dec_reply_body(Version, {'tk_short', [],[]},
422						      Rest, Len, ByteOrder, Bytes),
423		{R, []}
424	end,
425        case Interceptors of
426            {portable, _PI} ->
427                Reply;
428            {native, Refs, PI} ->
429                orber_pi:in_reply(PI, ObjKey,
430				  ReplyHeader#reply_header.service_context,
431				  Op, Refs, Reply)
432        end.
433
434%% "Plain" TCP/IP.
435connect(Host, Port, Objkey, Timeout, Index,
436	#host_data{protocol = normal, csiv2_mech = undefined} = HostData,
437	TaggedProfile, IOR, Ctx) ->
438    connect2([{Host, Port}], Objkey, Timeout, Index, HostData,
439	     TaggedProfile, IOR, Ctx);
440%% "Plain" SSL
441connect(Host, _, Objkey, Timeout, Index,
442	#host_data{protocol = ssl,
443		   ssl_data = #'SSLIOP_SSL'{port = Port},
444		   csiv2_mech = undefined} = HostData,
445	TaggedProfile, IOR, Ctx) ->
446    connect2([{Host, Port}], Objkey, Timeout, Index, HostData,
447	     TaggedProfile, IOR, Ctx);
448%% TEMPORARY FIX TO AVOID RUNNING CSIv2.
449connect(Host, _, Objkey, Timeout, Index,
450	#host_data{protocol = ssl,
451		   ssl_data = #'SSLIOP_SSL'{port = Port}} = HostData,
452	TaggedProfile, IOR, Ctx) ->
453    connect2([{Host, Port}], Objkey, Timeout, Index, HostData,
454	     TaggedProfile, IOR, Ctx);
455%% CSIv2 over SSL (TAG_TLS_SEC_TRANS) using the SAS protocol. Note port must equal 0.
456connect(_Host, 0, Objkey, Timeout, Index,
457	#host_data{protocol = ssl,
458		   csiv2_mech =
459		   #'CSIIOP_CompoundSecMech'{target_requires = _TR} = _Mech,
460		   csiv2_addresses = Addresses} = HostData,
461	TaggedProfile, IOR, Ctx) ->
462    NewCtx = [#'IOP_ServiceContext'
463	      {context_id=?IOP_SecurityAttributeService,
464	       context_data = #'CSI_SASContextBody'
465	       {label = ?CSI_MsgType_MTEstablishContext,
466		value = #'CSI_EstablishContext'
467		{client_context_id = 0, %% Always 0 when stateless.
468		 authorization_token =
469		 [#'CSI_AuthorizationElement'{the_element = []}],
470		 identity_token =
471		 #'CSI_IdentityToken'{label = ?CSI_IdentityTokenType_ITTAbsent,
472				      value = true},
473		 client_authentication_token = []}}}|Ctx],
474    connect2(Addresses, Objkey, Timeout, Index, HostData,
475	     TaggedProfile, IOR, NewCtx);
476%% CSIv2 over SSL (TAG_NULL_TAG) using the SAS protocol.
477connect(Host, _, Objkey, Timeout, Index,
478	#host_data{protocol = ssl,
479		   ssl_data = #'SSLIOP_SSL'{port = Port},
480		   csiv2_mech = Mech} = HostData,
481	TaggedProfile, IOR, Ctx) when is_record(Mech, 'CSIIOP_CompoundSecMech') ->
482    connect2([{Host, Port}], Objkey, Timeout, Index, HostData,
483	     TaggedProfile, IOR, Ctx);
484%% CSIv2 over TCP (TAG_NULL_TAG) using the SAS protocol.
485connect(Host, Port, Objkey, Timeout, Index,
486	#host_data{protocol = normal,
487		   csiv2_mech = Mech} = HostData,
488	TaggedProfile, IOR, Ctx) when is_record(Mech, 'CSIIOP_CompoundSecMech') ->
489    connect2([{Host, Port}], Objkey, Timeout, Index, HostData,
490	     TaggedProfile, IOR, Ctx);
491connect(_Host, _Port, _Objkey, _Timeout, _Index, HostData, _TaggedProfile,
492	IOR, _Ctx) ->
493    orber:dbg("[~p] orber_iiop:connect(~p)~n"
494	      "Unable to use the supplied IOR.~n"
495	      "Connection Data: ~p", [?LINE, IOR, HostData], ?DEBUG_LEVEL),
496    corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO}).
497
498
499
500connect2(HostPort, Objkey, Timeout, Index, HostData, TaggedProfile, IOR, Ctx) ->
501    case try_connect(HostPort, HostData#host_data.protocol, Timeout, HostData, Ctx) of
502	error ->
503	    Alts = iop_ior:get_alt_addr(TaggedProfile),
504	    case try_connect(Alts, HostData#host_data.protocol, Timeout, HostData, Ctx) of
505		error ->
506		    case iop_ior:get_key(IOR, Index) of
507			undefined ->
508			    corba:raise(#'COMM_FAILURE'{completion_status = ?COMPLETED_NO});
509			{'external', {NewHost, NewPort, NewObjkey, NewIndex,
510				      NewTaggedProfile, NewHostData}} ->
511			    connect(NewHost, NewPort, NewObjkey, Timeout, [NewIndex|Index],
512				    NewHostData, NewTaggedProfile, IOR, Ctx);
513			_What ->
514			    orber:dbg("[~p] orber_iiop:connect2(~p)~n"
515				      "Illegal IOR; contains a mixture of local and external profiles.",
516				      [?LINE, IOR], ?DEBUG_LEVEL),
517			    corba:raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO})
518		    end;
519		X ->
520		    {X, Objkey, HostData#host_data.version}
521	    end;
522	X ->
523	    {X, Objkey, HostData#host_data.version}
524    end.
525
526try_connect([], _, _, _, _) ->
527    error;
528try_connect([{Host, Port}|T], SocketType, Timeout, HostData, Ctx) ->
529    case catch orber_iiop_pm:connect(Host, Port, SocketType, Timeout,
530				     HostData#host_data.charset,
531				     HostData#host_data.wcharset, Ctx) of
532	{ok, P, Ctx2, Int, Interface} ->
533	    {P, Ctx2, Int, Interface};
534	{'EXCEPTION', #'BAD_CONTEXT'{} = CtxExc} ->
535	    orber:dbg("[~p] orber_iiop:try_connect(~p, ~p) failed~n",
536		      [?LINE, Host, Port], ?DEBUG_LEVEL),
537	    corba:raise(CtxExc);
538	{'EXCEPTION', _PMExc} ->
539	    try_connect(T, SocketType, Timeout, HostData, Ctx);
540	{'EXIT',{timeout,_}} ->
541	    orber:dbg("[~p] orber_iiop:try_connect(~p, ~p, ~p)~n"
542		      "Connect attempt timed out",
543		      [?LINE, Host, Port, Timeout], ?DEBUG_LEVEL),
544	    try_connect(T, SocketType, Timeout, HostData, Ctx);
545	{'EXIT', What} ->
546	    orber:dbg("[~p] orber_iiop:try_connect(~p, ~p, ~p)~n"
547		      "Connect attempt resulted in: ~p",
548		      [?LINE, Host, Port, Timeout, What], ?DEBUG_LEVEL),
549	    try_connect(T, SocketType, Timeout, HostData, Ctx)
550    end.
551
552