2 #include "tao/IIOP_Connection_Handler.h"
4 #if defined (TAO_HAS_IIOP) && (TAO_HAS_IIOP != 0)
7 #include "tao/ORB_Core.h"
8 #include "tao/IIOP_Transport.h"
9 #include "tao/IIOP_Endpoint.h"
10 #include "tao/IIOPC.h"
11 #include "tao/Thread_Lane_Resources.h"
12 #include "tao/Base_Transport_Property.h"
13 #include "tao/Protocols_Hooks.h"
14 #include "tao/Wait_Strategy.h"
16 #include "ace/os_include/netinet/os_tcp.h"
17 #include "ace/os_include/os_netdb.h"
19 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
22 #ifdef TAO_LOG_CH_REF_COUNTS
23 ACE_Event_Handler::Reference_Count
24 TAO_IIOP_Connection_Handler::add_reference ()
26 Reference_Count rc
= TAO_IIOP_SVC_HANDLER::add_reference ();
27 if (TAO_debug_level
> 9)
29 TAO_Transport
*tport
= this->transport ();
30 TAOLIB_DEBUG ((LM_DEBUG
,
31 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler[%d]::")
32 ACE_TEXT("add_reference, up to %d\n"),
33 tport
!= 0 ? tport
->id () : 0,
39 ACE_Event_Handler::Reference_Count
40 TAO_IIOP_Connection_Handler::remove_reference ()
42 TAO_Transport
*tport
= this->transport ();
43 Reference_Count rc
= TAO_IIOP_SVC_HANDLER::remove_reference ();
44 if (TAO_debug_level
> 9)
46 TAOLIB_DEBUG ((LM_DEBUG
,
47 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler[%d]::")
48 ACE_TEXT("remove_reference, down to %d\n"),
49 tport
!= 0 ? tport
->id () : 0,
54 #endif /*TAO_LOG_CH_REF_COUNTS*/
57 TAO_IIOP_Connection_Handler::TAO_IIOP_Connection_Handler (ACE_Thread_Manager
*t
)
58 : TAO_IIOP_SVC_HANDLER (t
, nullptr , nullptr),
59 TAO_Connection_Handler (nullptr),
60 dscp_codepoint_ (IPDSFIELD_DSCP_DEFAULT
<< 2)
62 // This constructor should *never* get called, it is just here to
63 // make the compiler happy: the default implementation of the
64 // Creation_Strategy requires a constructor with that signature, we
65 // don't use that implementation, but some (most?) compilers
66 // instantiate it anyway.
71 TAO_IIOP_Connection_Handler::TAO_IIOP_Connection_Handler (
72 TAO_ORB_Core
*orb_core
)
73 : TAO_IIOP_SVC_HANDLER (orb_core
->thr_mgr (), nullptr, nullptr),
74 TAO_Connection_Handler (orb_core
),
75 dscp_codepoint_ (IPDSFIELD_DSCP_DEFAULT
<< 2)
77 TAO_IIOP_Transport
* specific_transport
= nullptr;
78 ACE_NEW (specific_transport
,
79 TAO_IIOP_Transport (this, orb_core
));
81 if (TAO_debug_level
> 9)
83 TAO_Transport
*tport
= static_cast<TAO_Transport
*> (specific_transport
);
84 TAOLIB_DEBUG ((LM_DEBUG
,
85 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler[%d]::")
86 ACE_TEXT("IIOP_Connection_Handler, ")
87 ACE_TEXT("this=%@\n"),
88 tport
!= nullptr ? tport
->id () : 0,
92 // store this pointer (indirectly increment ref count)
93 this->transport (specific_transport
);
96 TAO_IIOP_Connection_Handler::~TAO_IIOP_Connection_Handler ()
98 if (TAO_debug_level
> 9)
100 TAO_Transport
*tport
= this->transport ();
101 TAOLIB_DEBUG ((LM_DEBUG
,
102 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler[%d]::")
103 ACE_TEXT("~IIOP_Connection_Handler, ")
104 ACE_TEXT("this=%@, transport=%@\n"),
105 tport
!= nullptr ? tport
->id () : 0,
109 delete this->transport ();
111 this->release_os_resources ();
113 if (result
== -1 && TAO_debug_level
)
115 TAOLIB_ERROR ((LM_ERROR
,
116 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler::")
117 ACE_TEXT("~IIOP_Connection_Handler, ")
118 ACE_TEXT("release_os_resources() failed %m\n")));
123 TAO_IIOP_Connection_Handler::open_handler (void *v
)
125 return this->open (v
);
129 TAO_IIOP_Connection_Handler::open (void*)
131 if (this->shared_open() == -1)
134 TAO_IIOP_Protocol_Properties protocol_properties
;
136 // Initialize values from ORB params.
137 protocol_properties
.send_buffer_size_
=
138 this->orb_core ()->orb_params ()->sock_sndbuf_size ();
139 protocol_properties
.recv_buffer_size_
=
140 this->orb_core ()->orb_params ()->sock_rcvbuf_size ();
141 protocol_properties
.no_delay_
=
142 this->orb_core ()->orb_params ()->nodelay ();
143 protocol_properties
.keep_alive_
=
144 this->orb_core ()->orb_params ()->sock_keepalive ();
145 protocol_properties
.dont_route_
=
146 this->orb_core ()->orb_params ()->sock_dontroute ();
147 protocol_properties
.hop_limit_
=
148 this->orb_core ()->orb_params ()->ip_hoplimit ();
150 TAO_Protocols_Hooks
*tph
= this->orb_core ()->get_protocols_hooks ();
156 if (this->transport ()->opened_as () == TAO::TAO_CLIENT_ROLE
)
158 tph
->client_protocol_properties_at_orb_level (protocol_properties
);
162 tph
->server_protocol_properties_at_orb_level (protocol_properties
);
165 catch (const ::CORBA::Exception
&)
171 if (this->set_socket_option (this->peer (),
172 protocol_properties
.send_buffer_size_
,
173 protocol_properties
.recv_buffer_size_
) == -1)
178 #if !defined (ACE_LACKS_TCP_NODELAY)
179 if (this->peer ().set_option (ACE_IPPROTO_TCP
,
181 (void *) &protocol_properties
.no_delay_
,
182 sizeof (protocol_properties
.no_delay_
)) == -1)
184 #endif /* ! ACE_LACKS_TCP_NODELAY */
186 if (protocol_properties
.keep_alive_
)
189 set_option (SOL_SOCKET
,
191 (void *) &protocol_properties
.keep_alive_
,
192 sizeof (protocol_properties
.keep_alive_
)) == -1
199 #if !defined (ACE_LACKS_SO_DONTROUTE)
200 if (protocol_properties
.dont_route_
)
203 set_option (SOL_SOCKET
,
205 (void *) &protocol_properties
.dont_route_
,
206 sizeof (protocol_properties
.dont_route_
)) == -1
212 #endif /* ! ACE_LACKS_SO_DONTROUTE */
214 if (protocol_properties
.hop_limit_
>= 0)
217 #if defined (ACE_HAS_IPV6)
218 ACE_INET_Addr local_addr
;
219 if (this->peer ().get_local_addr (local_addr
) == -1)
223 else if (local_addr
.get_type () == AF_INET6
)
225 #if defined (ACE_WIN32)
227 static_cast<DWORD
> (protocol_properties
.hop_limit_
);
230 static_cast<int> (protocol_properties
.hop_limit_
);
232 result
= this->peer ().set_option (
239 #endif /* ACE_HAS_IPV6 */
241 #if defined (ACE_WIN32)
243 static_cast<DWORD
> (protocol_properties
.hop_limit_
);
246 static_cast<int> (protocol_properties
.hop_limit_
);
248 result
= this->peer ().set_option (
259 TAOLIB_ERROR ((LM_ERROR
,
260 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler::open, ")
261 ACE_TEXT("couldn't set hop limit\n\n")));
267 if (this->transport ()->wait_strategy ()->non_blocking ()
268 || this->transport ()->opened_as () == TAO::TAO_SERVER_ROLE
)
270 if (this->peer ().enable (ACE_NONBLOCK
) == -1)
274 // Called by the <Strategy_Acceptor> when the handler is
275 // completely connected.
277 ACE_INET_Addr remote_addr
;
278 if (this->peer ().get_remote_addr (remote_addr
) == -1)
281 ACE_INET_Addr local_addr
;
282 if (this->peer ().get_local_addr (local_addr
) == -1)
285 if (TAO_debug_level
> 2)
286 TAOLIB_DEBUG ((LM_DEBUG
,
287 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler::open, ")
288 ACE_TEXT("The local addr is <%C:%d>\n"),
289 local_addr
.get_host_addr (),
290 local_addr
.get_port_number()));
292 if (local_addr
== remote_addr
)
294 if (TAO_debug_level
> 0)
296 ACE_TCHAR remote_as_string
[MAXHOSTNAMELEN
+ 16];
297 ACE_TCHAR local_as_string
[MAXHOSTNAMELEN
+ 16];
299 (void) remote_addr
.addr_to_string (remote_as_string
,
300 sizeof(remote_as_string
));
301 (void) local_addr
.addr_to_string (local_as_string
,
302 sizeof(local_as_string
));
303 TAOLIB_ERROR ((LM_ERROR
,
304 ACE_TEXT("TAO(%P|%t) - IIOP_Connection_Handler::open, ")
305 ACE_TEXT("Holy Cow! The remote addr and ")
306 ACE_TEXT("local addr are identical (%s == %s)\n"),
307 remote_as_string
, local_as_string
));
312 #if defined (ACE_HAS_IPV6) && !defined (ACE_HAS_IPV6_V6ONLY)
313 // Check if we need to invalidate accepted connections
314 // from IPv4 mapped IPv6 addresses
315 if (this->orb_core ()->orb_params ()->connect_ipv6_only () &&
316 remote_addr
.is_ipv4_mapped_ipv6 ())
318 if (TAO_debug_level
> 0)
320 ACE_TCHAR remote_as_string
[MAXHOSTNAMELEN
+ 16];
322 (void) remote_addr
.addr_to_string (remote_as_string
,
323 sizeof(remote_as_string
));
325 TAOLIB_ERROR ((LM_ERROR
,
326 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler::open, ")
327 ACE_TEXT("invalid connection from IPv4 mapped IPv6 interface <%s>!\n"),
332 #endif /* ACE_HAS_IPV6 && ACE_HAS_IPV6_V6ONLY */
334 if (TAO_debug_level
> 0)
336 ACE_TCHAR client_addr
[MAXHOSTNAMELEN
+ 16];
338 // Verify that we can resolve the peer hostname.
339 if (remote_addr
.addr_to_string (client_addr
, sizeof (client_addr
)) == -1)
342 TAOLIB_DEBUG ((LM_DEBUG
,
343 ACE_TEXT ("TAO (%P|%t) - IIOP_Connection_Handler::open, IIOP ")
344 ACE_TEXT ("connection to peer <%s> on [%d]\n"),
345 client_addr
, this->peer ().get_handle ()));
348 // Set that the transport is now connected, if fails we return -1
349 // Use C-style cast b/c otherwise we get warnings on lots of
351 if (!this->transport ()->post_open ((size_t) this->get_handle ()))
353 this->state_changed (TAO_LF_Event::LFS_SUCCESS
,
354 this->orb_core ()->leader_follower ());
360 TAO_IIOP_Connection_Handler::resume_handler ()
362 return ACE_Event_Handler::ACE_APPLICATION_RESUMES_HANDLER
;
366 TAO_IIOP_Connection_Handler::close_connection ()
368 // To maintain maximum compatibility, we only set this socket option
369 // if the user has provided a linger timeout.
370 int const linger
= this->orb_core()->orb_params()->linger ();
375 #if defined(ACE_HAS_LINGER_MS)
376 lval
.l_linger_ms
= linger
* 1000;
378 lval
.l_linger
= (u_short
)linger
;
380 if (this->peer ().set_option(SOL_SOCKET
,
383 sizeof (lval
)) == -1)
387 TAOLIB_DEBUG ((LM_DEBUG
,
388 ACE_TEXT ("TAO (%P|%t) Unable to set ")
389 ACE_TEXT ("SO_LINGER on %d\n"),
390 this->peer ().get_handle ()));
395 return this->close_connection_eh (this);
399 TAO_IIOP_Connection_Handler::handle_input (ACE_HANDLE h
)
401 return this->handle_input_eh (h
, this);
405 TAO_IIOP_Connection_Handler::handle_output (ACE_HANDLE handle
)
407 int const result
= this->handle_output_eh (handle
, this);
411 this->close_connection ();
420 TAO_IIOP_Connection_Handler::handle_timeout (const ACE_Time_Value
&,
423 // Using this to ensure this instance will be deleted (if necessary)
424 // only after reset_state(). Without this, when this refcount==1 -
425 // the call to close() will cause a call to remove_reference() which
426 // will delete this. At that point this->reset_state() is in no
427 // man's territory and that causes SEGV on some platforms (Windows!)
429 TAO_Auto_Reference
<TAO_IIOP_Connection_Handler
> safeguard (*this);
431 // NOTE: Perhaps not the best solution, as it feels like the upper
432 // layers should be responsible for this?
434 // We don't use this upcall for I/O. This is only used by the
435 // Connector to indicate that the connection timedout. Therefore,
436 // we should call close()
438 int const ret
= this->close ();
439 this->reset_state (TAO_LF_Event::LFS_TIMEOUT
);
440 if (TAO_debug_level
> 9)
442 TAOLIB_DEBUG ((LM_DEBUG
, "TAO (%P|%t) - TAO_IIOP_Connection_Handler[%d]::"
443 "handle_timeout reset state to LFS_TIMEOUT\n",
444 this->transport ()-> id()));
450 TAO_IIOP_Connection_Handler::handle_close (ACE_HANDLE
, ACE_Reactor_Mask
)
456 TAO_IIOP_Connection_Handler::close (u_long flags
)
458 return this->close_handler (flags
);
462 TAO_IIOP_Connection_Handler::release_os_resources ()
464 return this->peer ().close ();
468 TAO_IIOP_Connection_Handler::add_transport_to_cache ()
473 if (this->peer ().get_remote_addr (addr
) == -1)
476 // Construct an IIOP_Endpoint object
477 TAO_IIOP_Endpoint
endpoint (
479 this->orb_core()->orb_params()->cache_incoming_by_dotted_decimal_address ());
481 // Construct a property object
482 TAO_Base_Transport_Property
prop (&endpoint
);
484 TAO::Transport_Cache_Manager
&cache
=
485 this->orb_core ()->lane_resources ().transport_cache ();
487 // Idle the transport..
488 return cache
.cache_transport (&prop
, this->transport ());
492 TAO_IIOP_Connection_Handler::process_listen_point_list (
493 IIOP::ListenPointList
&listen_list
)
495 // Get the size of the list
496 CORBA::ULong len
= listen_list
.length ();
498 if (TAO_debug_level
> 0 && len
== 0)
500 TAOLIB_ERROR ((LM_ERROR
,
501 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler::")
502 ACE_TEXT("process_listen_point_list, ")
503 ACE_TEXT("Received list of size 0, check client config.\n")));
506 // @@ We can only handle a single endpoint for now because the
507 // transport is recached for each endpoint, loosing older
508 // information. This means that when more than one listen_point is
509 // sent, the cache will end up only being associated with the last
510 // address. This poses a problem at invocation time because the
511 // default endpoint selector steps through the profiles/endpoints
512 // sequentially and will try and possibly succeed in connecting to
513 // one of the earlier endpoints. My assumption is that when this
514 // method is called, it is before the first attempt to connect to
515 // any object in the target process, thus the first listen point in
516 // the list will correspond with the first profile and thus that
517 // should match the cache.
519 // Probably what needs to be done to make this model work well is to
520 // allow the transport cache to have multiple keys reference the
521 // same transport so that rather than recaching, we simply add a
524 for (CORBA::ULong i
= 0; i
< len
; ++i
)
526 IIOP::ListenPoint listen_point
= listen_list
[i
];
528 // since the supplied host/port could be unresolvable, the assigning
529 // constructor of the INET addr should not be as it will emit an error
530 // if the underlying set fails. An unresolvable address in this case
531 // is OK, as it will only be used to find an already cached transport.
533 (void)addr
.set(listen_point
.port
, listen_point
.host
.in ());
535 if (TAO_debug_level
> 0)
537 TAOLIB_DEBUG ((LM_DEBUG
,
538 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler::")
539 ACE_TEXT("process_listen_point_list, ")
540 ACE_TEXT("Listening port [%d] on [%C]\n"),
542 listen_point
.host
.in ()));
545 // Construct an IIOP_Endpoint object using the host as provided
546 // in the listen point list. We must use host in that form because
547 // that's also how the ORB on the other side will advertise the host
549 TAO_IIOP_Endpoint
endpoint (listen_point
.host
.in (),
550 listen_point
.port
, addr
);
552 // Construct a property object
553 TAO_Base_Transport_Property
prop (&endpoint
);
555 // Mark the connection as bidirectional
556 prop
.set_bidir_flag (1);
558 // The property for this handler has changed. Recache the
559 // handler with this property
560 if (this->transport ()->recache_transport (&prop
) == -1)
563 // Make the handler idle and ready for use
564 this->transport ()->make_idle ();
571 TAO_IIOP_Connection_Handler::set_tos (int tos
)
573 if (tos
!= this->dscp_codepoint_
)
576 #if defined (ACE_HAS_IPV6)
577 ACE_INET_Addr local_addr
;
578 if (this->peer ().get_local_addr (local_addr
) == -1)
580 else if (local_addr
.get_type () == AF_INET6
)
581 # if !defined (IPV6_TCLASS)
582 // IPv6 defines option IPV6_TCLASS for specifying traffic class/priority
583 // but not many implementations yet (very new;-).
587 TAOLIB_DEBUG ((LM_DEBUG
,
588 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler::")
589 ACE_TEXT("set_dscp_codepoint -> IPV6_TCLASS not supported yet\n")));
593 # else /* !IPV6_TCLASS */
594 result
= this->peer ().set_option (IPPROTO_IPV6
,
599 # endif /* IPV6_TCLASS */
600 #endif /* ACE_HAS_IPV6 */
601 result
= this->peer ().set_option (IPPROTO_IP
,
608 TAOLIB_DEBUG ((LM_DEBUG
,
609 ACE_TEXT("TAO (%P|%t) - IIOP_Connection_Handler::")
610 ACE_TEXT("set_dscp_codepoint -> dscp: %x; result: %d; %C\n"),
613 result
== -1 ? "try running as superuser" : ""));
616 // On successful setting of TOS field.
618 this->dscp_codepoint_
= tos
;
624 TAO_IIOP_Connection_Handler::set_dscp_codepoint (CORBA::Long dscp_codepoint
)
626 int tos
= IPDSFIELD_DSCP_DEFAULT
<< 2;
628 CORBA::Long codepoint
= dscp_codepoint
;
630 tos
= static_cast<int> (codepoint
) << 2;
638 TAO_IIOP_Connection_Handler::set_dscp_codepoint (CORBA::Boolean set_network_priority
)
640 int tos
= IPDSFIELD_DSCP_DEFAULT
<< 2;
642 if (set_network_priority
)
644 TAO_Protocols_Hooks
*tph
= this->orb_core ()->get_protocols_hooks ();
648 CORBA::Long codepoint
= tph
->get_dscp_codepoint ();
650 tos
= static_cast<int> (codepoint
) << 2;
659 TAO_IIOP_Connection_Handler::abort ()
661 struct linger lval
= { 0, 0 };
664 if (this->peer ().set_option(SOL_SOCKET
,
667 sizeof (lval
)) == -1)
671 TAOLIB_DEBUG ((LM_DEBUG
,
672 ACE_TEXT ("TAO (%P|%t) Unable to set ")
673 ACE_TEXT ("SO_LINGER on %d\n"),
674 this->peer ().get_handle ()));
680 TAO_IIOP_Connection_Handler::handle_write_ready (const ACE_Time_Value
*timeout
)
682 return ACE::handle_write_ready (this->peer ().get_handle (), timeout
);
685 TAO_END_VERSIONED_NAMESPACE_DECL
687 #endif /* TAO_HAS_IIOP && TAO_HAS_IIOP != 0 */