diff options
author | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:21 +0000 |
---|---|---|
committer | William R. Otte <wotte@dre.vanderbilt.edu> | 2006-07-24 15:50:21 +0000 |
commit | 3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c (patch) | |
tree | 197c810e5f5bce17b1233a7cb8d7b50c0bcd25e2 /TAO/tao/MCAST_Parser.cpp | |
parent | 6b846cf03c0bcbd8c276cb0af61a181e5f98eaae (diff) | |
download | ATCD-3aff90f4a822fcf5d902bbfbcc9fa931d6191a8c.tar.gz |
Repo restructuring
Diffstat (limited to 'TAO/tao/MCAST_Parser.cpp')
-rw-r--r-- | TAO/tao/MCAST_Parser.cpp | 524 |
1 files changed, 524 insertions, 0 deletions
diff --git a/TAO/tao/MCAST_Parser.cpp b/TAO/tao/MCAST_Parser.cpp new file mode 100644 index 00000000000..6d182f8846b --- /dev/null +++ b/TAO/tao/MCAST_Parser.cpp @@ -0,0 +1,524 @@ +#include "tao/MCAST_Parser.h" +#include "tao/default_ports.h" +#include "tao/ORB_Core.h" +#include "tao/ORB.h" +#include "tao/Environment.h" +#include "tao/debug.h" + +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Dgram.h" +#include "ace/OS_NS_strings.h" +#include "ace/OS_NS_string.h" + +#if !defined(__ACE_INLINE__) +#include "tao/MCAST_Parser.i" +#endif /* __ACE_INLINE__ */ + + +ACE_RCSID (tao, + MCAST_Parser, + "$Id$") + + +static const char mcast_prefix[] = "mcast:"; + + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +TAO_MCAST_Parser::~TAO_MCAST_Parser (void) +{ +} + +int +TAO_MCAST_Parser::match_prefix (const char *ior_string) const +{ + return (ACE_OS::strncmp (ior_string, + ::mcast_prefix, + sizeof (::mcast_prefix) - 1) == 0); +} + +CORBA::Object_ptr +TAO_MCAST_Parser::parse_string (const char *ior, + CORBA::ORB_ptr orb + ACE_ENV_ARG_DECL) + ACE_THROW_SPEC ((CORBA::SystemException)) +{ + const char *mcast_name = + ior + sizeof (::mcast_prefix) + 1; + + assign_to_variables (mcast_name); + + /* + * Now that we got the global variables. + * we can invoke multicast_to_service and multicast_query + */ + CORBA::Object_ptr object = CORBA::Object::_nil (); + + CORBA::UShort const port = + (CORBA::UShort) ACE_OS::atoi (this->mcast_port_.in ()); + + ACE_Time_Value *timeout = orb->get_timeout (); + + object = multicast_to_service (service_name_.in (), + port, + this->mcast_address_.in (), + this->mcast_ttl_.in (), + this->mcast_nic_.in (), + orb, + timeout + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (CORBA::Object::_nil ()); + + return object; +} + +CORBA::Object_ptr +TAO_MCAST_Parser::multicast_to_service (const char *service_name, + u_short port, + const char *mcast_address, + const char *mcast_ttl, + const char *mcast_nic, + CORBA::ORB_ptr orb, + ACE_Time_Value *timeout + ACE_ENV_ARG_DECL) +{ + char buf[2048]; + char *ior = buf; + + CORBA::String_var cleaner; + + CORBA::Object_var return_value = + CORBA::Object::_nil (); + + // Use UDP multicast to locate the service. + int const result = this->multicast_query (ior, + service_name, + port, + mcast_address, + mcast_ttl, + mcast_nic, + timeout, + orb); + + // If the IOR didn't fit into <buf>, memory for it was dynamically + // allocated - make sure it gets deallocated. + if (ior != buf) + cleaner = ior; + + if (result == 0) + { + // Convert IOR to an object reference. + return_value = + orb->string_to_object (ior + ACE_ENV_ARG_PARAMETER); + ACE_CHECK_RETURN (CORBA::Object::_nil ()); + } + + // Return object reference. + return return_value._retn (); +} + +int +TAO_MCAST_Parser::multicast_query (char *&buf, + const char *service_name, + u_short port, + const char *mcast_address, + const char *mcast_ttl, + const char *mcast_nic, + ACE_Time_Value *timeout, + CORBA::ORB_ptr orb) +{ + ACE_INET_Addr my_addr; + ACE_SOCK_Acceptor acceptor; + ACE_SOCK_Stream stream; + ACE_SOCK_Dgram dgram; + + ssize_t result = 0; + + // Bind listener to any port and then find out what the port was. +#if defined (ACE_HAS_IPV6) + if (acceptor.open (ACE_Addr::sap_any, 0, AF_INET6) == -1 +#else /* ACE_HAS_IPV6 */ + if (acceptor.open (ACE_Addr::sap_any) == -1 +#endif /* !ACE_HAS_IPV6 */ + || acceptor.get_local_addr (my_addr) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("acceptor.open () || ") + ACE_TEXT ("acceptor.get_local_addr () failed\n"))); + result = -1; + } + else + { + if (TAO_debug_level > 0) + { + ACE_TCHAR addr[64]; + my_addr.addr_to_string (addr, sizeof(addr)); + ACE_DEBUG ((LM_DEBUG, + "(%P|%t) TAO_MCAST_Parser: acceptor local address %s.\n", + addr)); + } + + ACE_INET_Addr multicast_addr (port, + mcast_address); + + // Set the address if multicast_discovery_endpoint option + // is specified for the Naming Service. + ACE_CString mde (orb->orb_core ()->orb_params () + ->mcast_discovery_endpoint ()); + + if (ACE_OS::strcasecmp (service_name, + "NameService") == 0 + && mde.length () != 0) + if (multicast_addr.set (mde.c_str()) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT("ORB.cpp: Multicast address setting failed\n"))); + stream.close (); + dgram.close (); + acceptor.close (); + return -1; + } + + // Open the datagram. + if (dgram.open (ACE_Addr::sap_any) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Unable to open the Datagram!\n"))); + result = -1; + } + else + { + // Set NIC + dgram.set_nic (ACE_TEXT_CHAR_TO_TCHAR (mcast_nic), + multicast_addr.get_type ()); + + // Set TTL + int mcast_ttl_optval = ACE_OS::atoi (mcast_ttl); + +#if defined (ACE_HAS_IPV6) + if (multicast_addr.get_type () == AF_INET6) + { + if (dgram.set_option ( + IPPROTO_IPV6, + IPV6_MULTICAST_HOPS, + &mcast_ttl_optval, + sizeof (mcast_ttl_optval)) != 0) + return -1; + } + else +#endif /* ACE_HAS_IPV6 */ + if (dgram.set_option ( + IPPROTO_IP, + IP_MULTICAST_TTL, + &mcast_ttl_optval, + sizeof (mcast_ttl_optval)) != 0) + result = -1; + + // Convert the acceptor port into network byte order. + ACE_UINT16 response_port = + (ACE_UINT16) ACE_HTONS (my_addr.get_port_number ()); + + // Length of service name we will send. + CORBA::Short data_len = + (CORBA::Short) ACE_HTONS (ACE_OS::strlen (service_name) + 1); + + // Vector we will send. It contains: 1) length of service + // name string, 2)port on which we are listening for + // replies, and 3) name of service we are looking for. + const int iovcnt = 3; + iovec iovp[iovcnt]; + + // The length of service name string. + iovp[0].iov_base = (char *) &data_len; + iovp[0].iov_len = sizeof (CORBA::Short); + + // The port at which we are listening. + iovp[1].iov_base = (char *) &response_port; + iovp[1].iov_len = sizeof (ACE_UINT16); + + // The service name string. + iovp[2].iov_base = (char *) service_name; + iovp[2].iov_len = + static_cast<u_long> (ACE_OS::strlen (service_name) + 1); + + // Send the multicast. + result = dgram.send (iovp, + iovcnt, + multicast_addr); + + if (TAO_debug_level > 0) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\nsent multicast request."))); + + // Check for errors. + if (result == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("error sending IIOP multicast"))); + else + { + if (TAO_debug_level > 0) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("\n%N; Sent multicast.") + ACE_TEXT ("# of bytes sent is %d.\n"), + result)); + // Wait for response until timeout. + ACE_Time_Value tv ( + timeout == 0 + ? ACE_Time_Value (TAO_DEFAULT_SERVICE_RESOLUTION_TIMEOUT) + : *timeout); + + // Accept reply connection from server. + if (acceptor.accept (stream, + 0, + &tv) == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("multicast_query: unable to accept"))); + result = -1; + } + else + { + // Receive the IOR. + + // IOR length. + CORBA::Short ior_len; + result = stream.recv_n (&ior_len, + sizeof ior_len, + 0, + &tv); + if (result != sizeof (ior_len)) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("multicast_query: unable to receive ") + ACE_TEXT ("ior length"))); + result = -1; + } + else + { + // Allocate more space for the ior if we don't + // have enough. + ior_len = (CORBA::Short) ACE_NTOHS (ior_len); + if (ior_len > TAO_DEFAULT_IOR_SIZE) + { + buf = CORBA::string_alloc (ior_len); + if (buf == 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("multicast_query: unable to ") + ACE_TEXT ("allocate memory"))); + result = -1; + } + } + + if (result != -1) + { + // Receive the ior. + result = stream.recv_n (buf, + ior_len, + 0, + &tv); + if (result == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ( "%p\n"), + ACE_TEXT ("error reading ior"))); + else if (TAO_debug_level > 0) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("%N: service resolved to IOR <%s>\n"), + ACE_TEXT_CHAR_TO_TCHAR (buf))); + } + } + } + } + } + if (result == -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT("\nmulticast discovery of %s failed.\n"), + ACE_TEXT_CHAR_TO_TCHAR (service_name))); + + if (ACE_OS::strcasecmp (service_name, + "NameService") == 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT("Specify -m 1 when starting Naming_Service,\n") + ACE_TEXT("or see http://www.theaceorb.com/faq/#115\n") + ACE_TEXT("for using NameService without multicast.\n\n"))); + } + } + } + + // Clean up. + stream.close (); + dgram.close (); + acceptor.close (); + + return result == -1 ? -1 : 0; +} + +void +TAO_MCAST_Parser::assign_to_variables (const char * &mcast_name) +{ + /* + * The format now is "multicast_address:port:nicaddress:ttl/object_key" + */ + ACE_CString mcast_name_cstring (mcast_name); + + ssize_t pos_colon1 = mcast_name_cstring.find (':', 0); +#if defined (ACE_HAS_IPV6) + // IPv6 numeric address in host string? + bool ipv6_in_host = false; + + // Check if this is an mcast address containing a + // decimal IPv6 address representation. + if (mcast_name_cstring[0] == '[') + { + // In this case we have to find the end of the numeric address and + // start looking for the port separator from there. + int cp_pos = mcast_name_cstring.find (']', 0); + if (cp_pos == 0) + { + // No valid IPv6 address specified. + if (TAO_debug_level > 0) + { + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("\nTAO (%P|%t) MCAST_Parser: ") + ACE_TEXT ("Invalid IPv6 decimal address specified.\n"))); + } + + return; + } + else + { + if (mcast_name_cstring[cp_pos + 1] == ':') // Look for a port + pos_colon1 = cp_pos + 1; + else + pos_colon1 = cp_pos; + ipv6_in_host = true; // host string contains full IPv6 numeric address + } + } +#endif /* ACE_HAS_IPV6 */ + + if (pos_colon1 == 0) + { +#if defined (ACE_HAS_IPV6) + const char *default_addr = ACE_DEFAULT_MULTICASTV6_ADDR; +#else /* ACE_HAS_IPV6 */ + const char *default_addr = ACE_DEFAULT_MULTICAST_ADDR; +#endif /* !ACE_HAS_IPV6 */ + this->mcast_address_ = default_addr; + } + else + { +#if defined (ACE_HAS_IPV6) + if (ipv6_in_host) + this->mcast_address_ = + mcast_name_cstring.substring (1, + pos_colon1 - 2).c_str (); + else +#endif /* ACE_HAS_IPV6 */ + this->mcast_address_ = + mcast_name_cstring.substring (0, + pos_colon1).c_str (); + } + mcast_name_cstring = + mcast_name_cstring.substring (pos_colon1 + 1, + mcast_name_cstring.length() - + pos_colon1); + + ssize_t pos_colon2 = mcast_name_cstring.find (':', 0); + + if (pos_colon2 == 0) + { + /* + * If the port is not specified, use the default. + * The default multicast port is the same as the default port + * no. for Naming_Service, for now. But for other services, + * check and modify the default values as needed. + */ + char default_port[33]; + + int trial_port = TAO_DEFAULT_NAME_SERVER_REQUEST_PORT; + + if (mcast_name_cstring.find ("InterfaceRepository") != + ACE_CString::npos) + { + trial_port = TAO_DEFAULT_INTERFACEREPO_SERVER_REQUEST_PORT; + } + else if (mcast_name_cstring.find ("ImplRepoService") != + ACE_CString::npos) + { + trial_port = TAO_DEFAULT_IMPLREPO_SERVER_REQUEST_PORT; + } + else if (mcast_name_cstring.find ("TradingService") != + ACE_CString::npos) + { + trial_port = TAO_DEFAULT_TRADING_SERVER_REQUEST_PORT; + } + + + ACE_OS::itoa (trial_port, default_port, 10); + + this->mcast_port_ = (const char *) default_port; + } + else + { + this->mcast_port_ = mcast_name_cstring.substring (0, + pos_colon2).c_str (); + } + + mcast_name_cstring = + mcast_name_cstring.substring (pos_colon2 + 1, + mcast_name_cstring.length() - pos_colon2); + + + ssize_t pos_colon3 = mcast_name_cstring.find (':', 0); + + this->mcast_nic_ = + mcast_name_cstring.substring (0, + pos_colon3).c_str (); + + mcast_name_cstring = + mcast_name_cstring.substring (pos_colon3 + 1, + mcast_name_cstring.length() - pos_colon3); + + ssize_t pos_colon4 = mcast_name_cstring.find ('/', 0); + + if (pos_colon4 == 0) + { + // And, the default TTL to be 1 + const char *default_ttl = "1"; + this->mcast_ttl_ = default_ttl; + } + else + { + this->mcast_ttl_ = + mcast_name_cstring.substring (0, + pos_colon4).c_str (); + } + mcast_name_cstring = + mcast_name_cstring.substring (pos_colon4, + mcast_name_cstring.length() - pos_colon4); + + this->service_name_ = + mcast_name_cstring.substring (1, + mcast_name_cstring.length() + -1).c_str (); +} + +TAO_END_VERSIONED_NAMESPACE_DECL + +ACE_STATIC_SVC_DEFINE (TAO_MCAST_Parser, + ACE_TEXT ("MCAST_Parser"), + ACE_SVC_OBJ_T, + &ACE_SVC_NAME (TAO_MCAST_Parser), + ACE_Service_Type::DELETE_THIS | + ACE_Service_Type::DELETE_OBJ, + 0) + +ACE_FACTORY_DEFINE (TAO, TAO_MCAST_Parser) + |