MCAST_Parser.cpp

Go to the documentation of this file.
00001 #include "tao/MCAST_Parser.h"
00002 
00003 #if (TAO_HAS_MCAST_PARSER == 1)
00004 
00005 #include "tao/default_ports.h"
00006 #include "tao/ORB_Core.h"
00007 #include "tao/ORB.h"
00008 #include "tao/debug.h"
00009 
00010 #include "ace/SOCK_Acceptor.h"
00011 #include "ace/SOCK_Dgram.h"
00012 #include "ace/OS_NS_strings.h"
00013 #include "ace/OS_NS_string.h"
00014 
00015 #if !defined(__ACE_INLINE__)
00016 #include "tao/MCAST_Parser.inl"
00017 #endif /* __ACE_INLINE__ */
00018 
00019 
00020 ACE_RCSID (tao,
00021            MCAST_Parser,
00022            "$Id: MCAST_Parser.cpp 79727 2007-09-26 18:12:47Z johnnyw $")
00023 
00024 
00025 static const char mcast_prefix[] = "mcast:";
00026 
00027 
00028 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
00029 
00030 TAO_MCAST_Parser::~TAO_MCAST_Parser (void)
00031 {
00032 }
00033 
00034 bool
00035 TAO_MCAST_Parser::match_prefix (const char *ior_string) const
00036 {
00037   return (ACE_OS::strncmp (ior_string,
00038                            ::mcast_prefix,
00039                            sizeof (::mcast_prefix) - 1) == 0);
00040 }
00041 
00042 CORBA::Object_ptr
00043 TAO_MCAST_Parser::parse_string (const char *ior, CORBA::ORB_ptr orb)
00044 {
00045   char const * const mcast_name =
00046     ior + sizeof (::mcast_prefix) + 1;
00047 
00048   assign_to_variables (mcast_name);
00049 
00050   /*
00051    * Now that we got the global variables.
00052    * we can invoke multicast_to_service and multicast_query
00053    */
00054   ACE_Time_Value *timeout = orb->get_timeout ();
00055 
00056   return
00057     this->multicast_to_service (service_name_.in (),
00058                                 this->mcast_port_,
00059                                 this->mcast_address_.in (),
00060                                 this->mcast_ttl_,
00061                                 this->mcast_nic_.in (),
00062                                 orb,
00063                                 timeout);
00064 }
00065 
00066 CORBA::Object_ptr
00067 TAO_MCAST_Parser::multicast_to_service (const char *service_name,
00068                                         unsigned short port,
00069                                         const char *mcast_address,
00070                                         int mcast_ttl,
00071                                         const char *mcast_nic,
00072                                         CORBA::ORB_ptr orb,
00073                                         ACE_Time_Value *timeout)
00074 {
00075   char buf[TAO_DEFAULT_IOR_SIZE];
00076   char * ior = buf;
00077 
00078   // Use UDP multicast to locate the  service.
00079   int const result = this->multicast_query (ior,
00080                                             service_name,
00081                                             port,
00082                                             mcast_address,
00083                                             mcast_ttl,
00084                                             mcast_nic,
00085                                             timeout,
00086                                             orb);
00087 
00088   CORBA::Object_var return_value;
00089 
00090   if (result == 0)
00091     {
00092       CORBA::String_var cleaner;
00093       // If the IOR didn't fit into <buf>, memory for it was dynamically
00094       // allocated - make sure it gets deallocated.
00095       if (ior != buf)
00096         cleaner = ior;
00097 
00098       // Convert IOR to an object reference.
00099       return_value =
00100         orb->string_to_object (ior);
00101     }
00102 
00103   // Return object reference.
00104   return return_value._retn ();
00105 }
00106 
00107 int
00108 TAO_MCAST_Parser::multicast_query (char* & buf,
00109                                    const char *service_name,
00110                                    unsigned short port,
00111                                    const char *mcast_address,
00112                                    int mcast_ttl,
00113                                    const char *mcast_nic,
00114                                    ACE_Time_Value *timeout,
00115                                    CORBA::ORB_ptr orb)
00116 {
00117   ACE_INET_Addr my_addr;
00118   ACE_SOCK_Acceptor acceptor;
00119   ACE_SOCK_Stream stream;
00120   ACE_SOCK_Dgram dgram;
00121 
00122   ssize_t result = 0;
00123 
00124   // Bind listener to any port and then find out what the port was.
00125 #if defined (ACE_HAS_IPV6)
00126   if (acceptor.open (ACE_Addr::sap_any, 0, AF_INET6) == -1
00127 #else /* ACE_HAS_IPV6 */
00128   if (acceptor.open (ACE_Addr::sap_any) == -1
00129 #endif /* !ACE_HAS_IPV6 */
00130       || acceptor.get_local_addr (my_addr) == -1)
00131     {
00132       ACE_ERROR ((LM_ERROR,
00133                   ACE_TEXT ("acceptor.open () || ")
00134                   ACE_TEXT ("acceptor.get_local_addr () failed\n")));
00135       result = -1;
00136     }
00137   else
00138     {
00139       if (TAO_debug_level > 0)
00140         {
00141           ACE_TCHAR addr[64];
00142           my_addr.addr_to_string (addr, sizeof(addr));
00143           ACE_DEBUG ((LM_DEBUG,
00144                       "(%P|%t) TAO_MCAST_Parser: acceptor local address %s.\n",
00145                       addr));
00146         }
00147 
00148       ACE_INET_Addr multicast_addr (port,
00149                                     mcast_address);
00150 
00151       // Set the address if multicast_discovery_endpoint option
00152       // is specified for the Naming Service.
00153       ACE_CString mde (orb->orb_core ()->orb_params ()
00154                        ->mcast_discovery_endpoint ());
00155 
00156       if (ACE_OS::strcasecmp (service_name,
00157                               "NameService") == 0
00158           && mde.length () != 0)
00159         if (multicast_addr.set (mde.c_str()) == -1)
00160           {
00161             ACE_ERROR ((LM_ERROR,
00162                         ACE_TEXT("ORB.cpp: Multicast address setting failed\n")));
00163             stream.close ();
00164             dgram.close ();
00165             acceptor.close ();
00166             return -1;
00167           }
00168 
00169       // Open the datagram.
00170       if (dgram.open (ACE_Addr::sap_any, multicast_addr.get_type ()) == -1)
00171         {
00172           ACE_ERROR ((LM_ERROR,
00173                       ACE_TEXT ("Unable to open the Datagram!\n")));
00174           result = -1;
00175         }
00176       else
00177         {
00178           // Set NIC
00179           dgram.set_nic (ACE_TEXT_CHAR_TO_TCHAR (mcast_nic),
00180                          multicast_addr.get_type ());
00181 
00182           // Set TTL
00183           int mcast_ttl_optval = mcast_ttl;
00184 
00185 #if defined (ACE_HAS_IPV6)
00186           if (multicast_addr.get_type () == AF_INET6)
00187             {
00188               if (dgram.set_option (
00189                     IPPROTO_IPV6,
00190                     IPV6_MULTICAST_HOPS,
00191                     &mcast_ttl_optval,
00192                     sizeof (mcast_ttl_optval)) != 0)
00193                 return -1;
00194             }
00195           else
00196 #endif  /* ACE_HAS_IPV6 */
00197           if (dgram.set_option (
00198                 IPPROTO_IP,
00199                 IP_MULTICAST_TTL,
00200                 &mcast_ttl_optval,
00201                 sizeof (mcast_ttl_optval)) != 0)
00202             result = -1;
00203 
00204           // Convert the acceptor port into network byte order.
00205           ACE_UINT16 response_port =
00206             (ACE_UINT16) ACE_HTONS (my_addr.get_port_number ());
00207 
00208           // Length of service name we will send.
00209           CORBA::Short data_len =
00210             (CORBA::Short) ACE_HTONS (ACE_OS::strlen (service_name) + 1);
00211 
00212           // Vector we will send.  It contains: 1) length of service
00213           // name string, 2)port on which we are listening for
00214           // replies, and 3) name of service we are looking for.
00215           const int iovcnt = 3;
00216           iovec iovp[iovcnt];
00217 
00218           // The length of service name string.
00219           iovp[0].iov_base = (char *) &data_len;
00220           iovp[0].iov_len  = sizeof (CORBA::Short);
00221 
00222           // The port at which we are listening.
00223           iovp[1].iov_base = (char *) &response_port;
00224           iovp[1].iov_len  = sizeof (ACE_UINT16);
00225 
00226           // The service name string.
00227           iovp[2].iov_base = (char *) service_name;
00228           iovp[2].iov_len  =
00229             static_cast<u_long> (ACE_OS::strlen (service_name) + 1);
00230 
00231           // Send the multicast.
00232           result = dgram.send (iovp,
00233                                iovcnt,
00234                                multicast_addr);
00235 
00236           if (TAO_debug_level > 0)
00237             ACE_DEBUG ((LM_DEBUG,
00238                         ACE_TEXT ("\nsent multicast request.")));
00239 
00240           // Check for errors.
00241           if (result == -1)
00242             ACE_ERROR ((LM_ERROR,
00243                         ACE_TEXT ("%p\n"),
00244                         ACE_TEXT ("error sending IIOP multicast")));
00245           else
00246             {
00247               if (TAO_debug_level > 0)
00248                 ACE_DEBUG ((LM_DEBUG,
00249                             ACE_TEXT ("\n%N; Sent multicast.")
00250                             ACE_TEXT ("# of bytes sent is %d.\n"),
00251                             result));
00252               // Wait for response until timeout.
00253               ACE_Time_Value tv (
00254                 timeout == 0
00255                 ? ACE_Time_Value (TAO_DEFAULT_SERVICE_RESOLUTION_TIMEOUT)
00256                 : *timeout);
00257 
00258               // Accept reply connection from server.
00259               if (acceptor.accept (stream,
00260                                    0,
00261                                    &tv) == -1)
00262                 {
00263                   ACE_ERROR ((LM_ERROR,
00264                               ACE_TEXT ("%p\n"),
00265                               ACE_TEXT ("multicast_query: unable to accept")));
00266                   result = -1;
00267                 }
00268               else
00269                 {
00270                   // Receive the IOR.
00271 
00272                   // IOR length.
00273                   CORBA::Short ior_len;
00274                   result = stream.recv_n (&ior_len,
00275                                           sizeof ior_len,
00276                                           0,
00277                                           &tv);
00278                   if (result != sizeof (ior_len))
00279                     {
00280                       ACE_ERROR ((LM_ERROR,
00281                                   ACE_TEXT ("%p\n"),
00282                                   ACE_TEXT ("multicast_query: unable to receive ")
00283                                   ACE_TEXT ("ior length")));
00284                       result = -1;
00285                     }
00286                   else
00287                     {
00288                       // Allocate more space for the ior if we don't
00289                       // have enough.
00290                       ior_len = (CORBA::Short) ACE_NTOHS (ior_len);
00291                       if (ior_len >= TAO_DEFAULT_IOR_SIZE)
00292                         {
00293                           buf = CORBA::string_alloc (ior_len);
00294                           if (buf == 0)
00295                             {
00296                               ACE_ERROR ((LM_ERROR,
00297                                           ACE_TEXT ("%p\n"),
00298                                           ACE_TEXT ("multicast_query: unable to ")
00299                                           ACE_TEXT ("allocate memory")));
00300                               result = -1;
00301                             }
00302                         }
00303 
00304                       if (result != -1)
00305                         {
00306                           // Receive the ior.
00307                           result = stream.recv_n (buf,
00308                                                   ior_len,
00309                                                   0,
00310                                                   &tv);
00311                           if (result == -1)
00312                             ACE_ERROR ((LM_ERROR,
00313                                         ACE_TEXT ( "%p\n"),
00314                                         ACE_TEXT ("error reading ior")));
00315                           else if (TAO_debug_level > 0)
00316                             ACE_DEBUG ((LM_DEBUG,
00317                                         ACE_TEXT ("%N: service resolved to IOR <%s>\n"),
00318                                         ACE_TEXT_CHAR_TO_TCHAR (buf)));
00319                         }
00320                     }
00321                 }
00322             }
00323         }
00324         if (result == -1)
00325           {
00326             ACE_ERROR ((LM_ERROR,
00327                         ACE_TEXT("\nmulticast discovery of %s failed.\n"),
00328                         ACE_TEXT_CHAR_TO_TCHAR (service_name)));
00329 
00330             if (ACE_OS::strcasecmp (service_name,
00331                                     "NameService") == 0)
00332              {
00333                ACE_ERROR ((LM_ERROR,
00334                            ACE_TEXT("Specify -m 1 when starting Naming_Service,\n")
00335                            ACE_TEXT("or see http://www.theaceorb.com/faq/#115\n")
00336                            ACE_TEXT("for using NameService without multicast.\n\n")));
00337              }
00338           }
00339     }
00340 
00341   // Clean up.
00342   stream.close ();
00343   dgram.close ();
00344   acceptor.close ();
00345 
00346   return result == -1 ? -1 : 0;
00347 }
00348 
00349 void
00350 TAO_MCAST_Parser::assign_to_variables (char const * mcast_name)
00351 {
00352   /*
00353    * The format now is "multicast_address:port:nicaddress:ttl/object_key"
00354    */
00355   ACE_CString mcast_name_cstring (mcast_name);
00356 
00357   ACE_CString::size_type pos_colon1 = mcast_name_cstring.find (':', 0);
00358 
00359 #if defined (ACE_HAS_IPV6)
00360   // IPv6 numeric address in host string?
00361   bool ipv6_in_host = false;
00362 
00363   // Check if this is an mcast address containing a
00364   // decimal IPv6 address representation.
00365   if (mcast_name_cstring[0] == '[')
00366     {
00367       // In this case we have to find the end of the numeric address and
00368       // start looking for the port separator from there.
00369       ACE_CString::size_type const cp_pos = mcast_name_cstring.find (']', 0);
00370       if (cp_pos == 0)
00371         {
00372           // No valid IPv6 address specified.
00373           if (TAO_debug_level > 0)
00374             {
00375               ACE_ERROR ((LM_ERROR,
00376                           ACE_TEXT ("\nTAO (%P|%t) MCAST_Parser: ")
00377                           ACE_TEXT ("Invalid IPv6 decimal address specified.\n")));
00378             }
00379 
00380           return;
00381         }
00382       else
00383         {
00384           if (mcast_name_cstring[cp_pos + 1] == ':')    // Look for a port
00385             pos_colon1 = cp_pos + 1;
00386           else
00387             pos_colon1 = cp_pos;
00388           ipv6_in_host = true; // host string contains full IPv6 numeric address
00389         }
00390     }
00391 #endif  /* ACE_HAS_IPV6 */
00392 
00393   if (pos_colon1 == 0)
00394     {
00395 #if defined (ACE_HAS_IPV6)
00396       const char default_addr[] = ACE_DEFAULT_MULTICASTV6_ADDR;
00397 #else /* ACE_HAS_IPV6 */
00398       const char default_addr[] = ACE_DEFAULT_MULTICAST_ADDR;
00399 #endif  /* !ACE_HAS_IPV6 */
00400       this->mcast_address_ = default_addr;
00401     }
00402   else
00403     {
00404 #if defined (ACE_HAS_IPV6)
00405       if (ipv6_in_host)
00406         this->mcast_address_ =
00407           mcast_name_cstring.substring (1,
00408                                         pos_colon1 - 2).c_str ();
00409       else
00410 #endif  /* ACE_HAS_IPV6 */
00411       this->mcast_address_ =
00412         mcast_name_cstring.substring (0,
00413                                       pos_colon1).c_str ();
00414     }
00415   mcast_name_cstring =
00416     mcast_name_cstring.substring (pos_colon1 + 1,
00417                                   mcast_name_cstring.length() -
00418                                   pos_colon1);
00419 
00420   ACE_CString::size_type const pos_colon2 = mcast_name_cstring.find (':', 0);
00421 
00422   if (pos_colon2 == 0)
00423     {
00424       if (mcast_name_cstring.find ("InterfaceRepository") != ACE_CString::npos)
00425         {
00426           this->mcast_port_ =
00427             TAO_DEFAULT_INTERFACEREPO_SERVER_REQUEST_PORT;
00428         }
00429       else if (mcast_name_cstring.find ("ImplRepoService") != ACE_CString::npos)
00430         {
00431           this->mcast_port_ =
00432             TAO_DEFAULT_IMPLREPO_SERVER_REQUEST_PORT;
00433         }
00434       else if (mcast_name_cstring.find ("TradingService") != ACE_CString::npos)
00435         {
00436           this->mcast_port_ = TAO_DEFAULT_TRADING_SERVER_REQUEST_PORT;
00437         }
00438     }
00439   else
00440     {
00441       int const the_port =
00442         ACE_OS::atoi (mcast_name_cstring.substring (0, pos_colon2).c_str ());
00443 
00444       if (the_port > 0 && the_port < 0xffffL)
00445         this->mcast_port_ = the_port;
00446     }
00447 
00448   mcast_name_cstring =
00449     mcast_name_cstring.substring (pos_colon2 + 1,
00450                                   mcast_name_cstring.length() - pos_colon2);
00451 
00452 
00453   ACE_CString::size_type const pos_colon3 = mcast_name_cstring.find (':', 0);
00454 
00455   this->mcast_nic_ = mcast_name_cstring.substring (0, pos_colon3).c_str ();
00456 
00457   mcast_name_cstring =
00458     mcast_name_cstring.substring (pos_colon3 + 1,
00459                                   mcast_name_cstring.length() - pos_colon3);
00460 
00461   ACE_CString::size_type const pos_colon4 = mcast_name_cstring.find ('/', 0);
00462 
00463   if (pos_colon4 != 0)
00464     {
00465       // Change TTL to non-default value.
00466       int const the_ttl =
00467         ACE_OS::atoi (mcast_name_cstring.substring (0, pos_colon4).c_str ());
00468 
00469       if (the_ttl > 0 && the_ttl <= 255)  // Valid TTLs: (0, 255]
00470         this->mcast_ttl_ = the_ttl;
00471     }
00472 
00473   mcast_name_cstring =
00474     mcast_name_cstring.substring (pos_colon4,
00475                                   mcast_name_cstring.length() - pos_colon4);
00476 
00477   this->service_name_ =
00478     mcast_name_cstring.substring (1, mcast_name_cstring.length() - 1).c_str ();
00479 }
00480 
00481 TAO_END_VERSIONED_NAMESPACE_DECL
00482 
00483 ACE_STATIC_SVC_DEFINE (TAO_MCAST_Parser,
00484                        ACE_TEXT ("MCAST_Parser"),
00485                        ACE_SVC_OBJ_T,
00486                        &ACE_SVC_NAME (TAO_MCAST_Parser),
00487                        ACE_Service_Type::DELETE_THIS |
00488                                   ACE_Service_Type::DELETE_OBJ,
00489                        0)
00490 
00491 ACE_FACTORY_DEFINE (TAO, TAO_MCAST_Parser)
00492 
00493 #endif /* TAO_HAS_MCAST_PARSER == 1 */

Generated on Tue Feb 2 17:37:52 2010 for TAO by  doxygen 1.4.7