MCAST_Parser.cpp

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

Generated on Thu Nov 9 11:54:15 2006 for TAO by doxygen 1.3.6