Updated logging to include the class/method so that it is more obvious where these...
[ACE_TAO.git] / TAO / tao / IIOP_Acceptor.cpp
blob0362bb59c838f6578fba62fc82b832176639af41
1 #include "tao/IIOP_Acceptor.h"
3 #if defined (TAO_HAS_IIOP) && (TAO_HAS_IIOP != 0)
5 #include "tao/IIOP_Profile.h"
6 #include "tao/MProfile.h"
7 #include "tao/debug.h"
8 #include "tao/Protocols_Hooks.h"
9 #include "tao/Codeset_Manager.h"
10 #include "tao/Transport.h"
11 #include "tao/ORB_Core.h"
12 #include "tao/CDR.h"
14 #if !defined(__ACE_INLINE__)
15 #include "tao/IIOP_Acceptor.inl"
16 #endif /* __ACE_INLINE__ */
18 #include "ace/OS_NS_string.h"
19 #include "ace/os_include/os_netdb.h"
20 #include <cstring>
22 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
24 TAO_IIOP_Acceptor::TAO_IIOP_Acceptor ()
25 : TAO_Acceptor (IOP::TAG_INTERNET_IOP),
26 addrs_ (nullptr),
27 port_span_ (1),
28 hosts_ (nullptr),
29 hostname_in_ior_ (nullptr),
30 endpoint_count_ (0),
31 version_ (TAO_DEF_GIOP_MAJOR, TAO_DEF_GIOP_MINOR),
32 orb_core_ (nullptr),
33 reuse_addr_ (1),
34 #if defined (ACE_HAS_IPV6) && !defined (ACE_USES_IPV4_IPV6_MIGRATION)
35 default_address_ (static_cast<unsigned short> (0), ACE_IPV6_ANY, AF_INET6),
36 #else
37 default_address_ (static_cast<unsigned short> (0), static_cast<ACE_UINT32> (INADDR_ANY)),
38 #endif /* ACE_HAS_IPV6 && !ACE_USES_IPV4_IPV6_MIGRATION */
39 base_acceptor_ (this),
40 creation_strategy_ (nullptr),
41 concurrency_strategy_ (nullptr),
42 accept_strategy_ (nullptr)
44 #if defined (ACE_HAS_IPV6) && defined (ACE_USES_IPV4_IPV6_MIGRATION)
45 if (ACE::ipv6_enabled())
46 default_address_.set (
47 static_cast<unsigned short> (0),
48 ACE_IPV6_ANY,
49 AF_INET6);
50 #endif /* ACE_HAS_IPV6 && ACE_USES_IPV4_IPV6_MIGRATION */
53 TAO_IIOP_Acceptor::~TAO_IIOP_Acceptor ()
55 // Make sure we are closed before we start destroying the
56 // strategies.
57 this->close ();
59 delete this->creation_strategy_;
60 delete this->concurrency_strategy_;
61 delete this->accept_strategy_;
63 delete [] this->addrs_;
65 for (CORBA::ULong i = 0; i < this->endpoint_count_; ++i)
66 CORBA::string_free (this->hosts_[i]);
68 delete [] this->hosts_;
70 delete [] this->hostname_in_ior_;
73 // TODO =
74 // 2) For V1.[1,2] there are tagged components
75 int
76 TAO_IIOP_Acceptor::create_profile (const TAO::ObjectKey &object_key,
77 TAO_MProfile &mprofile,
78 CORBA::Short priority)
80 // Sanity check.
81 if (this->endpoint_count_ == 0)
82 return -1;
84 // Check if multiple endpoints should be put in one profile or
85 // if they should be spread across multiple profiles.
86 if (priority == TAO_INVALID_PRIORITY &&
87 this->orb_core_->orb_params ()->shared_profile () == 0)
88 return this->create_new_profile (object_key, mprofile, priority);
89 else
90 return this->create_shared_profile (object_key, mprofile, priority);
93 int
94 TAO_IIOP_Acceptor::create_new_profile (const TAO::ObjectKey &object_key,
95 TAO_MProfile &mprofile,
96 CORBA::Short priority)
98 // Adding this->endpoint_count_ to the TAO_MProfile.
99 int const count = mprofile.profile_count ();
100 if ((mprofile.size () - count) < this->endpoint_count_
101 && mprofile.grow (count + this->endpoint_count_) == -1)
102 return -1;
104 // Create a profile for each acceptor endpoint.
105 for (CORBA::ULong i = 0; i < this->endpoint_count_; ++i)
107 // Skip if the host name
108 if (i > 0
109 && (this->addrs_[i].get_port_number() == this->addrs_[0].get_port_number())
110 && ACE_OS::strcmp(this->hosts_[i], this->hosts_[0]) == 0)
111 continue;
113 TAO_IIOP_Profile *pfile = nullptr;
114 ACE_NEW_RETURN (pfile,
115 TAO_IIOP_Profile (this->hosts_[i],
116 this->addrs_[i].get_port_number (),
117 object_key,
118 this->addrs_[i],
119 this->version_,
120 this->orb_core_),
121 -1);
122 pfile->endpoint ()->priority (priority);
124 if (mprofile.give_profile (pfile) == -1)
126 pfile->_decr_refcnt ();
127 pfile = nullptr;
128 return -1;
131 // Do not add any tagged components to the profile if configured
132 // by the user not to do so, or if an IIOP 1.0 endpoint is being
133 // created (IIOP 1.0 did not support tagged components).
134 if (!this->orb_core_->orb_params ()->std_profile_components ()
135 || (this->version_.major == 1 && this->version_.minor == 0))
136 continue;
138 pfile->tagged_components ().set_orb_type (TAO_ORB_TYPE);
140 TAO_Codeset_Manager *csm = this->orb_core_->codeset_manager();
141 if (csm)
142 csm->set_codeset(pfile->tagged_components());
145 return 0;
149 TAO_IIOP_Acceptor::create_shared_profile (const TAO::ObjectKey &object_key,
150 TAO_MProfile &mprofile,
151 CORBA::Short priority)
153 CORBA::ULong index = 0;
154 TAO_Profile *pfile = nullptr;
155 TAO_IIOP_Profile *iiop_profile = nullptr;
157 // First see if @a mprofile already contains a IIOP profile.
158 for (TAO_PHandle i = 0; i != mprofile.profile_count (); ++i)
160 pfile = mprofile.get_profile (i);
161 if (pfile->tag () == IOP::TAG_INTERNET_IOP)
163 iiop_profile = dynamic_cast<TAO_IIOP_Profile *> (pfile);
164 break;
168 // If <mprofile> doesn't contain a IIOP_Profile, we need to create
169 // one.
170 if (iiop_profile == nullptr)
172 ACE_NEW_RETURN (iiop_profile,
173 TAO_IIOP_Profile (this->hosts_[0],
174 this->addrs_[0].get_port_number (),
175 object_key,
176 this->addrs_[0],
177 this->version_,
178 this->orb_core_),
179 -1);
181 iiop_profile->endpoint ()->priority (priority);
183 if (mprofile.give_profile (iiop_profile) == -1)
185 iiop_profile->_decr_refcnt ();
186 iiop_profile = nullptr;
187 return -1;
190 // Do not add any tagged components to the profile if configured
191 // by the user not to do so, or if an IIOP 1.0 endpoint is being
192 // created (IIOP 1.0 did not support tagged components).
193 if (this->orb_core_->orb_params ()->std_profile_components ()
194 && (this->version_.major >= 1 && this->version_.minor >= 1))
196 iiop_profile->tagged_components ().set_orb_type (TAO_ORB_TYPE);
197 TAO_Codeset_Manager *csm = this->orb_core_->codeset_manager();
198 if (csm)
199 csm->set_codeset(iiop_profile->tagged_components());
202 index = 1;
205 // Add any remaining acceptor endpoints to the IIOP_Profile.
206 for (;
207 index < this->endpoint_count_;
208 ++index)
210 if (index > 0 &&
211 this->addrs_[index].get_port_number() == this->addrs_[0].get_port_number() &&
212 ACE_OS::strcmp(this->hosts_[index], this->hosts_[0]) == 0)
213 continue;
215 TAO_IIOP_Endpoint *endpoint = nullptr;
216 ACE_NEW_RETURN (endpoint,
217 TAO_IIOP_Endpoint (this->hosts_[index],
218 this->addrs_[index].get_port_number (),
219 this->addrs_[index]),
220 -1);
221 endpoint->priority (priority);
222 iiop_profile->add_endpoint (endpoint);
225 return 0;
229 TAO_IIOP_Acceptor::is_collocated (const TAO_Endpoint *endpoint)
231 const TAO_IIOP_Endpoint *endp =
232 dynamic_cast<const TAO_IIOP_Endpoint *> (endpoint);
234 // Make sure the dynamically cast pointer is valid.
235 if (endp == nullptr)
236 return 0;
238 for (CORBA::ULong i = 0; i < this->endpoint_count_; ++i)
240 // compare the port and host name. Please do *NOT* optimize
241 // this code by comparing the IP address instead. That would
242 // trigger the following bug:
244 // http://bugzilla.dre.vanderbilt.edu/show_bug.cgi?id=1220
246 if (endp->port() == this->addrs_[i].get_port_number()
247 && ACE_OS::strcmp(endp->host(), this->hosts_[i]) == 0)
248 return 1;
251 return 0;
255 TAO_IIOP_Acceptor::close ()
257 return this->base_acceptor_.close ();
261 TAO_IIOP_Acceptor::open (TAO_ORB_Core *orb_core,
262 ACE_Reactor *reactor,
263 int major,
264 int minor,
265 const char *address,
266 const char *options)
268 if (TAO_debug_level > 2)
270 TAOLIB_DEBUG ((LM_DEBUG,
271 ACE_TEXT ("TAO (%P|%t) - ")
272 ACE_TEXT ("IIOP_Acceptor::open, address==%C, options=%C\n"),
273 address, options));
276 this->orb_core_ = orb_core;
278 if (this->hosts_ != nullptr)
280 // The hostname cache has already been set!
281 // This is bad mojo, i.e. an internal TAO error.
282 TAOLIB_ERROR_RETURN ((LM_ERROR,
283 ACE_TEXT ("TAO (%P|%t) - ")
284 ACE_TEXT ("IIOP_Acceptor::open, ")
285 ACE_TEXT ("hostname already set\n\n")),
286 -1);
289 if (address == nullptr)
290 return -1;
292 if (major >=0 && minor >= 0)
293 this->version_.set_version (static_cast<CORBA::Octet> (major),
294 static_cast<CORBA::Octet> (minor));
295 // Parse options
296 if (this->parse_options (options) == -1)
297 return -1;
299 ACE_CString specified_hostname;
300 ACE_INET_Addr addr;
301 int def_type = AF_UNSPEC;
303 if (this->parse_address (address,
304 addr,
305 specified_hostname,
306 &def_type) == -1)
307 return -1;
309 if (specified_hostname.length() == 0)
311 // The address is a port number or port name. No hostname was
312 // specified. The hostname for each network interface and the
313 // fully qualified domain name must be obtained.
315 // Check for multiple network interfaces.
316 if (this->probe_interfaces (orb_core, def_type) == -1)
317 return -1;
319 // Probe interfaces has a side effect of potentially modifying
320 // the default address, since that is where the address family
321 // is considered.
322 addr.set(this->default_address_);
324 return this->open_i (addr, reactor);
327 #if defined (ACE_HAS_IPV6)
328 // Check for violation of ORBConnectIPV6Only option
329 if (this->orb_core_->orb_params ()->connect_ipv6_only () &&
330 (addr.get_type () != AF_INET6 ||
331 addr.is_ipv4_mapped_ipv6 ()))
333 TAOLIB_ERROR_RETURN ((LM_ERROR,
334 ACE_TEXT ("TAO (%P|%t) - ")
335 ACE_TEXT ("IIOP_Acceptor::open, ")
336 ACE_TEXT ("non-IPv6 endpoints not allowed when ")
337 ACE_TEXT ("connect_ipv6_only is set\n\n")),
338 -1);
340 #endif /* ACE_HAS_IPV6 */
342 if (TAO_debug_level > 2)
344 TAOLIB_DEBUG ((LM_DEBUG,
345 ACE_TEXT ("TAO (%P|%t) - ")
346 ACE_TEXT ("IIOP_Acceptor::open, specified host=%C:%d\n"),
347 (specified_hostname.length() == 0 ? "<null>" : specified_hostname.c_str()),
348 addr.get_port_number ()));
351 this->endpoint_count_ = 1; // Only one hostname to store
353 ACE_NEW_RETURN (this->addrs_,
354 ACE_INET_Addr[this->endpoint_count_],
355 -1);
357 ACE_NEW_RETURN (this->hosts_,
358 char *[this->endpoint_count_],
359 -1);
361 this->hosts_[0] = nullptr;
363 if (this->hostname_in_ior_ != nullptr)
365 if (TAO_debug_level > 2)
367 TAOLIB_DEBUG ((LM_DEBUG,
368 ACE_TEXT ("TAO (%P|%t) - ")
369 ACE_TEXT ("IIOP_Acceptor::open, ")
370 ACE_TEXT ("overriding address in IOR with %C\n"),
371 this->hostname_in_ior_));
373 specified_hostname = this->hostname_in_ior_;
376 if (this->hostname (orb_core,
377 addr,
378 this->hosts_[0],
379 specified_hostname.c_str()) != 0)
380 return -1;
382 // Copy the addr. The port is (re)set in
383 // TAO_IIOP_Acceptor::open_i().
384 if (this->addrs_[0].set (addr) != 0)
385 return -1;
387 return this->open_i (addr, reactor);
391 TAO_IIOP_Acceptor::open_default (TAO_ORB_Core *orb_core,
392 ACE_Reactor *reactor,
393 int major,
394 int minor,
395 const char *options)
397 this->orb_core_ = orb_core;
399 if (this->hosts_ != nullptr)
401 // The hostname cache has already been set!
402 // This is bad mojo, i.e. an internal TAO error.
403 TAOLIB_ERROR_RETURN ((LM_ERROR,
404 ACE_TEXT ("TAO (%P|%t) - ")
405 ACE_TEXT ("IIOP_Acceptor::open_default, ")
406 ACE_TEXT ("hostname already set\n\n")),
407 -1);
410 if (major >= 0 && minor >= 0)
411 this->version_.set_version (static_cast<CORBA::Octet> (major),
412 static_cast<CORBA::Octet> (minor));
414 // Parse options
415 if (this->parse_options (options) == -1)
416 return -1;
418 // Check for multiple network interfaces.
419 if (this->probe_interfaces (orb_core) == -1)
420 return -1;
422 // Now that each network interface's hostname has been cached, open
423 // an endpoint on each network interface using the INADDR_ANY
424 // address.
425 ACE_INET_Addr addr;
427 if (addr.set (this->default_address_) != 0)
428 return -1;
430 return this->open_i (addr, reactor);
434 TAO_IIOP_Acceptor::open_i (const ACE_INET_Addr& addr,
435 ACE_Reactor *reactor)
437 ACE_NEW_RETURN (this->creation_strategy_,
438 CREATION_STRATEGY (this->orb_core_),
439 -1);
441 ACE_NEW_RETURN (this->concurrency_strategy_,
442 CONCURRENCY_STRATEGY (this->orb_core_),
443 -1);
445 ACE_NEW_RETURN (this->accept_strategy_,
446 ACCEPT_STRATEGY (this->orb_core_),
447 -1);
449 unsigned short const requested_port = addr.get_port_number ();
450 if (requested_port == 0)
452 // don't care, i.e., let the OS choose an ephemeral port
453 if (this->base_acceptor_.open (addr,
454 reactor,
455 this->creation_strategy_,
456 this->accept_strategy_,
457 this->concurrency_strategy_,
458 nullptr, nullptr, nullptr, ACE_DEFAULT_ACCEPTOR_USE_SELECT,
459 this->reuse_addr_) == -1)
461 if (TAO_debug_level > 0)
462 TAOLIB_ERROR ((LM_ERROR,
463 ACE_TEXT ("TAO (%P|%t) - IIOP_Acceptor::open_i, ")
464 ACE_TEXT ("%p\n"),
465 ACE_TEXT ("cannot open acceptor")));
466 return -1;
469 else
471 ACE_INET_Addr a(addr);
473 bool found_a_port = false;
474 ACE_UINT32 const last_port = ACE_MIN (requested_port + this->port_span_ - 1,
475 ACE_MAX_DEFAULT_PORT);
477 for (ACE_UINT32 p = requested_port; p <= last_port; p++)
479 if (TAO_debug_level > 5)
480 TAOLIB_DEBUG ((LM_DEBUG,
481 ACE_TEXT ("TAO (%P|%t) - IIOP_Acceptor::open_i, ")
482 ACE_TEXT ("trying to listen on port %d\n"), p));
484 // Now try to actually open on that port
485 a.set_port_number ((u_short)p);
486 if (this->base_acceptor_.open (a,
487 reactor,
488 this->creation_strategy_,
489 this->accept_strategy_,
490 this->concurrency_strategy_,
491 nullptr, nullptr, nullptr, ACE_DEFAULT_ACCEPTOR_USE_SELECT,
492 this->reuse_addr_) != -1)
494 found_a_port = true;
495 break;
499 // Now, if we couldn't locate a port, we punt
500 if (! found_a_port)
502 if (TAO_debug_level > 0)
503 TAOLIB_DEBUG ((LM_DEBUG,
504 ACE_TEXT ("TAO (%P|%t) - IIOP_Acceptor::open_i, ")
505 ACE_TEXT ("cannot open acceptor in port range (%d,%d)")
506 ACE_TEXT ("- %p\n"),
507 requested_port, last_port, ACE_TEXT("")));
508 return -1;
512 #if defined (ACE_HAS_IPV6) && defined (ACE_HAS_IPV6_V6ONLY)
513 // Check if need to prevent this acceptor from accepting connections
514 // from IPv4 mapped IPv6 addresses
515 if (this->orb_core_->orb_params ()->connect_ipv6_only () &&
516 addr.is_any ())
518 if (TAO_debug_level > 5)
519 TAOLIB_DEBUG ((LM_DEBUG,
520 ACE_TEXT("TAO (%P|%t) - IIOP_Acceptor::open_i, ")
521 ACE_TEXT("setting IPV6_V6ONLY\n")));
523 // Prevent server from accepting connections from IPv4-mapped addresses.
524 int on = 1;
525 if (this->base_acceptor_.acceptor ().set_option (IPPROTO_IPV6,
526 IPV6_V6ONLY,
527 (void *) &on,
528 sizeof (on)) == -1)
530 TAOLIB_ERROR ((LM_ERROR,
531 ACE_TEXT ("TAO (%P|%t) - IIOP_Acceptor::open_i, ")
532 ACE_TEXT ("%p\n"),
533 ACE_TEXT ("cannot set IPV6_V6ONLY")));
536 #endif /* ACE_HAS_IPV6 && ACE_HAS_IPV6_V6ONLY */
538 ACE_INET_Addr address;
540 // We do this make sure the port number the endpoint is listening on
541 // gets set in the addr.
542 if (this->base_acceptor_.acceptor ().get_local_addr (address) != 0)
544 if (TAO_debug_level > 0)
545 TAOLIB_ERROR ((LM_ERROR,
546 ACE_TEXT ("TAO (%P|%t) - IIOP_Acceptor::open_i, ")
547 ACE_TEXT ("%p\n"),
548 ACE_TEXT ("cannot get local addr")));
549 return -1;
552 // Set the port for each addr. If there is more than one network
553 // interface then the endpoint created on each interface will be on
554 // the same port. This is how a wildcard socket bind() is supposed
555 // to work.
556 unsigned short port = address.get_port_number ();
557 for (CORBA::ULong j = 0; j < this->endpoint_count_; ++j)
558 this->addrs_[j].set_port_number (port, 1);
560 this->default_address_.set_port_number (port);
562 (void) this->base_acceptor_.acceptor().enable (ACE_CLOEXEC);
563 // This avoids having child processes acquire the listen socket thereby
564 // denying the server the opportunity to restart on a well-known endpoint.
565 // This does not affect the aberrent behavior on Win32 platforms.
567 if (TAO_debug_level > 5)
569 for (CORBA::ULong i = 0; i < this->endpoint_count_; ++i)
571 TAOLIB_DEBUG ((LM_DEBUG,
572 ACE_TEXT ("TAO (%P|%t) - IIOP_Acceptor::open_i, ")
573 ACE_TEXT ("listening on: <%C:%u>\n"),
574 this->hosts_[i],
575 this->addrs_[i].get_port_number ()));
579 // In the event that an accept() fails, we can examine the reason. If
580 // the reason warrants it, we can try accepting again at a later time.
581 // The amount of time we wait to accept again is governed by this orb
582 // parameter.
583 this->set_error_retry_delay (
584 this->orb_core_->orb_params ()->accept_error_delay());
586 return 0;
590 TAO_IIOP_Acceptor::hostname (TAO_ORB_Core *orb_core,
591 const ACE_INET_Addr &addr,
592 char *&host,
593 const char *specified_hostname)
595 if (this->hostname_in_ior_ != nullptr)
597 if (TAO_debug_level >= 5)
598 TAOLIB_DEBUG ((LM_DEBUG,
599 ACE_TEXT ("TAO (%P|%t) - IIOP_Acceptor::hostname, ")
600 ACE_TEXT ("overriding the hostname with <%C>\n"),
601 this->hostname_in_ior_));
603 host = CORBA::string_dup (this->hostname_in_ior_);
605 else if (orb_core->orb_params ()->use_dotted_decimal_addresses ())
607 // If dotted decimal addresses are enabled,
608 // just return ours.
609 return this->dotted_decimal_address (addr, host);
611 else if (specified_hostname != nullptr)
613 // If the user specified a hostname, pass it back
614 // blindly as it overrides our choice of hostname.
615 host = CORBA::string_dup (specified_hostname);
617 else
619 char tmp_host[MAXHOSTNAMELEN + 1];
621 // Get the hostname associated with our address
622 #if defined (ACE_HAS_IPV6)
623 // If we have a IPv4-compatible IPv6 address don't do hostname lookup
624 // because that gets us into trouble. Most likely we get the same hostname
625 // returned as for the actual IPv4 address but resolving that into an IPv6
626 // address at the client will fail.
627 if (addr.is_ipv4_compat_ipv6 () ||
628 addr.get_host_name (tmp_host, sizeof (tmp_host)) != 0)
629 #else /* ACE_HAS_IPV6 */
630 if (addr.get_host_name (tmp_host, sizeof (tmp_host)) != 0)
631 #endif /* !ACE_HAS_IPV6 */
633 // On failure, just return the decimal address.
634 return this->dotted_decimal_address (addr, host);
636 else
638 host = CORBA::string_dup (tmp_host);
642 return 0;
647 TAO_IIOP_Acceptor::parse_address (const char *address,
648 ACE_INET_Addr &addr,
649 ACE_CString &specified_hostname,
650 int *def_type)
653 ACE_INET_Addr tmp;
654 addr.set (tmp);
655 specified_hostname.clear();
658 const char *port_separator_loc = std::strchr (address, ':');
659 char tmp_host[MAXHOSTNAMELEN + 1];
660 tmp_host[0] = '\0';
661 bool host_defaulted = port_separator_loc == address;
662 bool ipv6_in_host = false;
663 if (def_type)
664 *def_type = AF_UNSPEC;
666 #if defined (ACE_HAS_IPV6)
667 // Check if this is a (possibly) IPv6 supporting profile containing a
668 // numeric IPv6 address representation.
669 if ((this->version_.major > TAO_MIN_IPV6_IIOP_MAJOR ||
670 this->version_.minor >= TAO_MIN_IPV6_IIOP_MINOR) &&
671 address[0] == '[')
673 // In this case we have to find the end of the numeric address and
674 // start looking for the port separator from there.
675 char const * const cp_pos = std::strchr (address, ']');
676 if (cp_pos == 0)
678 // No valid IPv6 address specified.
679 TAOLIB_ERROR_RETURN ((LM_ERROR,
680 ACE_TEXT ("TAO (%P|%t) - ")
681 ACE_TEXT ("IIOP_Acceptor::open, ")
682 ACE_TEXT ("Invalid IPv6 decimal address specified\n\n")),
683 -1);
685 else
687 // Extract out just the host part of the address.
688 size_t const len = cp_pos - (address + 1);
690 if (len >= sizeof (tmp_host))
691 return -1;
693 ipv6_in_host = true;
694 host_defaulted = (cp_pos == address+1) ||
695 (cp_pos == address+3 && address[1] == ':' && address[2] == ':');
696 if (cp_pos[1] == ':') // Look for a port
697 port_separator_loc = cp_pos + 1;
698 else
699 port_separator_loc = 0;
700 if (def_type)
701 *def_type = AF_INET6;
703 ACE_OS::memcpy (tmp_host, address + 1, len);
704 tmp_host[len] = '\0';
707 else
708 #endif /* ACE_HAS_IPV6 */
709 if (!host_defaulted)
711 if (port_separator_loc != nullptr)
713 // Extract out just the host part of the address.
714 size_t const len = port_separator_loc - address;
716 if (len >= sizeof (tmp_host))
717 return -1;
719 ACE_OS::memcpy (tmp_host, address, len);
720 tmp_host[len] = '\0';
722 else
723 ACE_OS::strcpy (tmp_host, address);
726 if (!ipv6_in_host && !host_defaulted)
728 if (addr.set((unsigned short)0,tmp_host) != 0)
729 return -1;
730 this->default_address_.set(addr);
731 host_defaulted = addr.is_any();
732 if (def_type)
733 *def_type = AF_INET;
736 if (host_defaulted)
738 // First convert the port into a usable form.
739 unsigned short portno = 0;
740 if (port_separator_loc != nullptr)
742 portno =
743 static_cast<u_short> (ACE_OS::atoi (port_separator_loc +
744 sizeof (':')));
746 this->default_address_.set_port_number (portno);
748 // Now reset the port and set the host.
749 if (addr.set (this->default_address_) != 0)
750 return -1;
752 else if (port_separator_loc == nullptr)
754 // The address is a hostname. No port was specified, so assume
755 // port zero (port will be chosen for us).
756 specified_hostname = tmp_host[0] == '\0' ? address : tmp_host;
757 if (addr.set ((unsigned short) 0,
758 specified_hostname.c_str()) != 0)
759 return -1;
761 else
763 // Host and port were specified.
764 if (addr.set (address) != 0)
765 return -1;
766 if (tmp_host[0] == '\0')
768 // Extract out just the host part of the address.
769 size_t const len = port_separator_loc - address;
771 if (len >= sizeof (tmp_host))
772 return -1;
774 ACE_OS::memcpy (tmp_host, address, len);
775 tmp_host[len] = '\0';
777 specified_hostname = tmp_host;
780 return 1;
785 TAO_IIOP_Acceptor::dotted_decimal_address (const ACE_INET_Addr &addr,
786 char *&host)
788 int result = 0;
789 const char *tmp = nullptr;
791 // If the IP address in the INET_Addr is the IN(6)ADDR_ANY address,
792 // then force the actual IP address to be used by initializing a new
793 // INET_Addr with the hostname from the original one. If that fails
794 // then something is seriously wrong with the systems networking
795 // setup.
796 if (addr.is_any ())
798 ACE_INET_Addr new_addr;
799 #if defined (ACE_HAS_IPV6)
800 result = new_addr.set (addr.get_port_number (),
801 addr.get_host_name (),
802 1, /* encode */
803 addr.get_type ());
804 #else /* ACE_HAS_IPV6 */
805 result = new_addr.set (addr.get_port_number (),
806 addr.get_host_name ());
807 #endif /* !ACE_HAS_IPV6 */
808 tmp = new_addr.get_host_addr ();
810 else
811 tmp = addr.get_host_addr ();
813 if (tmp == nullptr || result != 0)
815 if (TAO_debug_level > 0)
816 TAOLIB_ERROR ((LM_ERROR,
817 ACE_TEXT ("TAO (%P|%t) - ")
818 ACE_TEXT ("IIOP_Acceptor::dotted_decimal_address, ")
819 ACE_TEXT ("- %p\n"),
820 ACE_TEXT ("cannot determine hostname")));
821 return -1;
824 host = CORBA::string_dup (tmp);
825 return 0;
829 TAO_IIOP_Acceptor::probe_interfaces (TAO_ORB_Core *orb_core, int def_type)
831 // Extract the hostname for each network interface, and then cache
832 // it. The hostnames will then be used when creating a
833 // TAO_IIOP_Profile for each endpoint setup on the probed
834 // network interfaces.
835 ACE_INET_Addr *if_addrs = nullptr;
836 size_t if_cnt = 0;
838 if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0
839 && errno != ENOTSUP)
841 // In the case where errno == ENOTSUP, if_cnt and if_addrs will
842 // not be modified, and will each remain equal to zero. This
843 // causes the default interface to be used.
844 return -1;
847 if (if_cnt == 0 || if_addrs == nullptr)
849 if (TAO_debug_level > 0)
851 TAOLIB_DEBUG ((LM_WARNING,
852 ACE_TEXT ("TAO (%P|%t) - Unable to probe network ")
853 ACE_TEXT ("interfaces. Using default.\n")));
856 if_cnt = 1; // Force the network interface count to be one.
857 delete [] if_addrs;
858 ACE_NEW_RETURN (if_addrs,
859 ACE_INET_Addr[if_cnt],
860 -1);
863 // Scan for the loopback interface since it shouldn't be included in
864 // the list of cached hostnames unless it is the only interface.
865 size_t lo_cnt = 0; // Loopback interface count
866 for (size_t j = 0; j < if_cnt; ++j)
867 if (if_addrs[j].is_loopback ())
868 ++lo_cnt;
870 #if defined (ACE_HAS_IPV6)
871 size_t ipv4_cnt = 0;
872 size_t ipv4_lo_cnt = 0;
873 size_t ipv6_ll = 0;
874 bool ipv4_non_lo = false;
875 bool ipv6_non_ll = false;
876 // Scan for IPv4 interfaces since these should not be included
877 // when IPv6-only is selected.
878 for (size_t j = 0; j < if_cnt; ++j)
879 if (if_addrs[j].get_type () != AF_INET6 ||
880 if_addrs[j].is_ipv4_mapped_ipv6 ())
882 ++ipv4_cnt;
883 if (if_addrs[j].is_loopback ())
884 ++ipv4_lo_cnt; // keep track of IPv4 loopback ifs
885 else
886 ipv4_non_lo = true;
888 else if (!if_addrs[j].is_linklocal () &&
889 !if_addrs[j].is_loopback())
891 ipv6_non_ll = true; // we have at least 1 non-local IPv6 if
893 else if (!orb_core->orb_params ()->use_ipv6_link_local () &&
894 if_addrs[j].is_linklocal ())
896 ++ipv6_ll; // count link local addrs to exclude them afterwards
898 #endif /* ACE_HAS_IPV6 */
900 // The instantiation for this template is in
901 // tao/IIOP_Connector.cpp.
902 ACE_Auto_Basic_Array_Ptr<ACE_INET_Addr> safe_if_addrs (if_addrs);
904 #if defined (ACE_HAS_IPV6)
905 bool ipv4_only = def_type == AF_INET;
906 bool ipv6_only = (def_type == AF_INET6) ||
907 orb_core->orb_params ()->connect_ipv6_only ();
908 #if defined (ACE_WIN32)
909 OSVERSIONINFO vinfo;
910 vinfo.dwOSVersionInfoSize = sizeof (vinfo);
911 int vres = GetVersionEx (&vinfo);
912 if (vres == 0 || vinfo.dwMajorVersion < 6)
914 if (this->default_address_.get_type () == AF_INET)
915 ipv4_only = true;
916 else
917 ipv6_only = true;
919 #endif /* ACE_WIN32 */
920 // If the loopback interface is the only interface then include it
921 // in the list of interfaces to query for a hostname, otherwise
922 // exclude it from the list.
923 bool ignore_lo;
924 if (ipv6_only)
925 // only exclude loopback if non-local if exists
926 ignore_lo = ipv6_non_ll;
927 else if (ipv4_only)
928 ignore_lo = ipv4_cnt != ipv4_lo_cnt;
929 else
931 ipv6_non_ll |= ipv4_non_lo;
932 ignore_lo = ipv6_non_ll;
935 // Adjust counts for IPv6 only if required
936 size_t if_ok_cnt = if_cnt;
937 if (ipv6_only)
939 if_ok_cnt -= ipv4_cnt;
940 lo_cnt -= ipv4_lo_cnt;
941 ipv4_lo_cnt = 0;
943 else if (ipv4_only)
945 if_ok_cnt = ipv4_cnt;
946 lo_cnt = ipv4_lo_cnt;
947 ipv6_ll = 0;
950 // In case there are no non-local IPv6 ifs in the list only exclude
951 // IPv4 loopback.
952 // IPv6 loopback will be needed to successfully connect IPv6 clients
953 // in a localhost environment.
954 if (!ipv4_only && !ipv6_non_ll)
955 lo_cnt = ipv4_lo_cnt;
957 if (!ignore_lo)
958 this->endpoint_count_ = static_cast<CORBA::ULong> (if_ok_cnt - ipv6_ll);
959 else
960 this->endpoint_count_ = static_cast<CORBA::ULong> (if_ok_cnt - ipv6_ll - lo_cnt);
961 #else /* ACE_HAS_IPV6 */
962 // If the loopback interface is the only interface then include it
963 // in the list of interfaces to query for a hostname, otherwise
964 // exclude it from the list.
965 bool ignore_lo;
966 ignore_lo = if_cnt != lo_cnt;
967 if (!ignore_lo)
968 this->endpoint_count_ = static_cast<CORBA::ULong> (if_cnt);
969 else
970 this->endpoint_count_ = static_cast<CORBA::ULong> (if_cnt - lo_cnt);
971 #endif /* !ACE_HAS_IPV6 */
973 if (this->endpoint_count_ == 0)
975 if (TAO_debug_level > 0)
976 TAOLIB_DEBUG ((LM_DEBUG,
977 ACE_TEXT("(%P|%t) TAO_IIOP_Acceptor::probe_interfaces ")
978 ACE_TEXT("found no usable addresses, def_type = %d\n"),
979 def_type));
980 return -1;
983 ACE_NEW_RETURN (this->addrs_,
984 ACE_INET_Addr[this->endpoint_count_],
985 -1);
987 ACE_NEW_RETURN (this->hosts_,
988 char *[this->endpoint_count_],
989 -1);
991 ACE_OS::memset (this->hosts_, 0, sizeof (char*) * this->endpoint_count_);
993 // The number of hosts/interfaces we want to cache may not be the
994 // same as the number of detected interfaces so keep a separate
995 // count.
996 size_t host_cnt = 0;
998 for (size_t i = 0; i < if_cnt; ++i)
1000 #if defined (ACE_HAS_IPV6)
1001 // Ignore any loopback interface if there are other
1002 // non-loopback interfaces.
1003 if (ignore_lo &&
1004 if_addrs[i].is_loopback () &&
1005 (ipv4_only ||
1006 ipv6_non_ll ||
1007 if_addrs[i].get_type () != AF_INET6))
1008 continue;
1010 // Ignore any non-IPv4 interfaces when so required.
1011 if (ipv4_only &&
1012 (if_addrs[i].get_type () != AF_INET))
1013 continue;
1015 // Ignore any non-IPv6 interfaces when so required.
1016 if (ipv6_only &&
1017 (if_addrs[i].get_type () != AF_INET6 ||
1018 if_addrs[i].is_ipv4_mapped_ipv6 ()))
1019 continue;
1021 // Ignore all IPv6 link local interfaces when so required.
1022 if (!orb_core->orb_params ()->use_ipv6_link_local () &&
1023 if_addrs[i].is_linklocal ())
1024 continue;
1025 #else /* ACE_HAS_IPV6 */
1026 // Ignore any loopback interface if there are other
1027 // non-loopback interfaces.
1028 if (ignore_lo &&
1029 if_addrs[i].is_loopback ())
1030 continue;
1031 #endif /* !ACE_HAS_IPV6 */
1033 if (this->hostname (orb_core,
1034 if_addrs[i],
1035 this->hosts_[host_cnt]) != 0)
1036 return -1;
1038 // Copy the addr. The port is (re)set in
1039 // TAO_IIOP_Acceptor::open_i().
1040 if (this->addrs_[host_cnt].set (if_addrs[i]) != 0)
1041 return -1;
1043 ++host_cnt;
1046 return 0;
1049 CORBA::ULong
1050 TAO_IIOP_Acceptor::endpoint_count ()
1052 return this->endpoint_count_;
1056 TAO_IIOP_Acceptor::object_key (IOP::TaggedProfile &profile,
1057 TAO::ObjectKey &object_key)
1059 // Create the decoding stream from the encapsulation in the buffer,
1060 #if (TAO_NO_COPY_OCTET_SEQUENCES == 1)
1061 TAO_InputCDR cdr (profile.profile_data.mb ());
1062 #else
1063 TAO_InputCDR cdr (reinterpret_cast<char*> (profile.profile_data.get_buffer ()),
1064 profile.profile_data.length ());
1065 #endif /* TAO_NO_COPY_OCTET_SEQUENCES == 1 */
1067 CORBA::Octet major = 0;
1068 CORBA::Octet minor = 0;
1070 // Read the version. We just read it here. We don't*do any*
1071 // processing.
1072 if (!(cdr.read_octet (major)
1073 && cdr.read_octet (minor)))
1075 if (TAO_debug_level > 0)
1077 TAOLIB_DEBUG ((LM_DEBUG,
1078 ACE_TEXT ("TAO (%P|%t) - TAO_IIOP_Acceptor::object_key, v%d.%d\n"),
1079 major,
1080 minor));
1082 return -1;
1085 CORBA::String_var host;
1086 CORBA::UShort port = 0;
1088 // Get host and port. No processing here too..
1089 if (cdr.read_string (host.out ()) == 0
1090 || cdr.read_ushort (port) == 0)
1092 if (TAO_debug_level > 0)
1094 TAOLIB_DEBUG ((LM_DEBUG,
1095 ACE_TEXT ("TAO (%P|%t) - TAO_IIOP_Acceptor::object_key, ")
1096 ACE_TEXT ("error while decoding host/port\n")));
1098 return -1;
1101 // ... and object key.
1102 if ((cdr >> object_key) == 0)
1103 return -1;
1105 // We are NOT bothered about the rest.
1107 return 1;
1111 TAO_IIOP_Acceptor::parse_options (const char *str)
1113 if (str == nullptr)
1114 return 0; // No options to parse. Not a problem.
1116 // Use an option format similar to the one used for CGI scripts in
1117 // HTTP URLs.
1118 // e.g.: option1=foo&option2=bar
1120 const ACE_CString options (str);
1122 const size_t len = options.length ();
1124 static const char option_delimiter = '&';
1126 // Count the number of options.
1127 int argc = 1;
1129 for (size_t i = 0; i < len; ++i)
1130 if (options[i] == option_delimiter)
1131 argc++;
1133 // The idea behind the following loop is to split the options into
1134 // (option, name) pairs.
1135 // For example,
1136 // `option1=foo&option2=bar'
1137 // will be parsed into:
1138 // `option1=foo'
1139 // `option2=bar'
1141 ACE_CString *argv_base = nullptr;
1142 ACE_NEW_RETURN (argv_base, ACE_CString[argc],-1);
1143 ACE_CString **argv = nullptr;
1144 ACE_NEW_RETURN (argv, ACE_CString*[argc],-1);
1146 ACE_CString::size_type begin = 0;
1147 ACE_CString::size_type end = 0;
1148 int result = 0;
1149 for (int j = 0; j < argc; ++j)
1151 if (j < argc - 1)
1152 end = options.find (option_delimiter, begin);
1153 else
1154 end = len;
1156 if (end == begin)
1158 TAOLIB_ERROR ((LM_ERROR,
1159 ACE_TEXT ("TAO (%P|%t) - Zero length IIOP option.\n")));
1160 result = -1;
1161 break;
1163 else if (end != options.npos)
1165 argv_base[j] = options.substring (begin, end - begin);
1166 argv[j] = &argv_base[j];
1167 begin = end + 1;
1169 else
1171 break; // No other options.
1175 if (result == 0)
1176 result = this->parse_options_i (argc,argv);
1178 if (argc > 0)
1180 TAOLIB_ERROR ((LM_ERROR,
1181 ACE_TEXT ("TAO (%P|%t) - IIOP")
1182 ACE_TEXT (" endpoint has %d unknown options:\n"),
1183 argc));
1184 for (int i = 0; i < argc; i++)
1185 TAOLIB_ERROR ((LM_ERROR,
1186 ACE_TEXT("\t%C\n"),
1187 argv[i]->c_str()));
1188 result = -1;
1190 delete [] argv;
1191 delete [] argv_base;
1192 return result;
1196 TAO_IIOP_Acceptor::parse_options_i (int &argc,
1197 ACE_CString **argv)
1199 int i = 0;
1200 while (i < argc)
1202 ACE_CString::size_type const len = argv[i]->length ();
1203 ACE_CString::size_type const slot = argv[i]->find ('=');
1205 if (slot == len - 1
1206 || slot == ACE_CString::npos)
1207 TAOLIB_ERROR_RETURN ((LM_ERROR,
1208 ACE_TEXT ("TAO (%P|%t) - IIOP option <%C> is ")
1209 ACE_TEXT ("missing a value.\n"),
1210 argv[i]->c_str ()),
1211 -1);
1213 ACE_CString name = argv[i]->substring (0, slot);
1214 ACE_CString value = argv[i]->substring (slot + 1);
1216 if (name.length () == 0)
1217 TAOLIB_ERROR_RETURN ((LM_ERROR,
1218 ACE_TEXT ("TAO (%P|%t) Zero length IIOP ")
1219 ACE_TEXT ("option name.\n")),
1220 -1);
1221 if (name == "portspan")
1223 int const range = ACE_OS::atoi (value.c_str ());
1224 // @@ What's the lower bound on the range? zero, or one?
1225 if (range < 1 || range > ACE_MAX_DEFAULT_PORT)
1226 TAOLIB_ERROR_RETURN ((LM_ERROR,
1227 ACE_TEXT ("TAO (%P|%t) Invalid IIOP endpoint ")
1228 ACE_TEXT ("portspan: <%C>\n")
1229 ACE_TEXT ("Valid range 1 -- %d\n"),
1230 value.c_str (), ACE_MAX_DEFAULT_PORT),
1231 -1);
1233 this->port_span_ = static_cast <u_short> (range);
1235 else if (name == "hostname_in_ior")
1237 this->hostname_in_ior_ = value.rep ();
1239 else if (name == "reuse_addr")
1241 this->reuse_addr_ = ACE_OS::atoi (value.c_str ());
1243 else
1245 // the name is not known, skip to the next option
1246 ++i;
1247 continue;
1249 // at the end, we've consumed this argument. Shift the list and
1250 // put this one on the end. This technique has the effect of
1251 // putting them in reverse order, but that doesn't matter, since
1252 // these arguments are only whole strings.
1253 --argc;
1254 ACE_CString *temp = argv[i];
1255 for (int j = i; j <= argc-1; ++j)
1256 argv[j] = argv[j+1];
1257 argv[argc] = temp;
1259 return 0;
1262 TAO_END_VERSIONED_NAMESPACE_DECL
1264 #endif /* TAO_HAS_IIOP && TAO_HAS_IIOP != 0 */