UIPMC_Acceptor.cpp

Go to the documentation of this file.
00001 // This may look like C, but it's really -*- C++ -*-
00002 //
00003 // $Id: UIPMC_Acceptor.cpp 79015 2007-07-24 15:03:04Z vridosh $
00004 
00005 #include "orbsvcs/PortableGroup/UIPMC_Profile.h"
00006 #include "orbsvcs/PortableGroup/UIPMC_Acceptor.h"
00007 
00008 #include "tao/MProfile.h"
00009 #include "tao/ORB_Core.h"
00010 #include "tao/debug.h"
00011 #include "tao/Protocols_Hooks.h"
00012 #include "tao/ORB_Constants.h"
00013 
00014 #include "ace/Auto_Ptr.h"
00015 #include "ace/os_include/os_netdb.h"
00016 
00017 #if !defined(__ACE_INLINE__)
00018 #include "orbsvcs/PortableGroup/UIPMC_Acceptor.inl"
00019 #endif /* __ACE_INLINE__ */
00020 
00021 ACE_RCSID (PortableGroup,
00022            UIPMC_Acceptor,
00023            "$Id: UIPMC_Acceptor.cpp 79015 2007-07-24 15:03:04Z vridosh $")
00024 
00025 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
00026 
00027 TAO_UIPMC_Acceptor::TAO_UIPMC_Acceptor (void)
00028   : TAO_Acceptor (IOP::TAG_UIPMC),
00029     addrs_ (0),
00030     hosts_ (0),
00031     endpoint_count_ (0),
00032     version_ (TAO_DEF_GIOP_MAJOR, TAO_DEF_GIOP_MINOR),
00033     orb_core_ (0),
00034     connection_handler_ (0)
00035 {
00036 }
00037 
00038 TAO_UIPMC_Acceptor::~TAO_UIPMC_Acceptor (void)
00039 {
00040   // Make sure we are closed before we start destroying the
00041   // strategies.
00042   this->close ();
00043 
00044   delete [] this->addrs_;
00045 
00046   for (size_t i = 0; i < this->endpoint_count_; ++i)
00047     CORBA::string_free (this->hosts_[i]);
00048 
00049   delete [] this->hosts_;
00050 }
00051 
00052 int
00053 TAO_UIPMC_Acceptor::create_profile (const TAO::ObjectKey &,
00054   TAO_MProfile &,
00055   CORBA::Short)
00056 {
00057   // The standard mechanism for adding profiles to object references
00058   // for each pluggable protocol doesn't apply to UIPMC profiles, so
00059   // this function just returns success without doing anything.  The
00060   // appropiate mechanism for getting UIPMC profiles is to call the
00061   // multicast group manager to get a Group reference.  Invocations
00062   // sent to this group reference will be dispatched to the servants
00063   // that belong to that group.
00064   return 0;
00065 }
00066 
00067 int
00068 TAO_UIPMC_Acceptor::is_collocated (const TAO_Endpoint *)
00069 {
00070   // @@ Not clear how
00071   // to best handle collation.  For example, one servant could
00072   // be collocated, but we still need to send the request out on
00073   // the network to see if there are any other servants in the
00074   // group.
00075   return 0;  // Not collocated
00076 }
00077 
00078 int
00079 TAO_UIPMC_Acceptor::close (void)
00080 {
00081   return 0;
00082 }
00083 
00084 int
00085 TAO_UIPMC_Acceptor::open (TAO_ORB_Core *orb_core,
00086                           ACE_Reactor *reactor,
00087                           int major,
00088                           int minor,
00089                           const char *address,
00090                           const char *options)
00091 {
00092   this->orb_core_ = orb_core;
00093 
00094   if (this->hosts_ != 0)
00095     {
00096       // The hostname cache has already been set!
00097       // This is bad mojo, i.e. an internal TAO error.
00098       ACE_ERROR_RETURN ((LM_ERROR,
00099                          ACE_TEXT ("TAO (%P|%t) ")
00100                          ACE_TEXT ("UIPMC_Acceptor::open - ")
00101                          ACE_TEXT ("hostname already set\n\n")),
00102                         -1);
00103     }
00104 
00105   if (address == 0)
00106     return -1;
00107 
00108   if (major >= 0 && minor >= 0)
00109     this->version_.set_version (static_cast<CORBA::Octet> (major),
00110                                 static_cast<CORBA::Octet> (minor));
00111   // Parse options
00112   if (this->parse_options (options) == -1)
00113     return -1;
00114 
00115   ACE_INET_Addr addr;
00116 
00117   const char *port_separator_loc = ACE_OS::strchr (address, ':');
00118   const char *specified_hostname = 0;
00119   char tmp_host[MAXHOSTNAMELEN + 1];
00120 
00121 #if defined (ACE_HAS_IPV6)
00122   // Check if this is a (possibly) IPv6 supporting profile containing a
00123   // numeric IPv6 address representation.
00124   if ((this->version_.major > TAO_MIN_IPV6_IIOP_MAJOR ||
00125         this->version_.minor >= TAO_MIN_IPV6_IIOP_MINOR) &&
00126       address[0] == '[')
00127     {
00128       // In this case we have to find the end of the numeric address and
00129       // start looking for the port separator from there.
00130       const char *cp_pos = ACE_OS::strchr(address, ']');
00131       if (cp_pos == 0)
00132         {
00133           // No valid IPv6 address specified.
00134           ACE_ERROR_RETURN ((LM_ERROR,
00135                              ACE_TEXT ("TAO (%P|%t) - ")
00136                              ACE_TEXT ("UIPMC_Acceptor::open, ")
00137                              ACE_TEXT ("Invalid IPv6 decimal address specified\n\n")),
00138                             -1);
00139         }
00140       else
00141         {
00142           if (cp_pos[1] == ':')    // Look for a port
00143             port_separator_loc = cp_pos + 1;
00144           else
00145             port_separator_loc = 0;
00146           // Extract out just the host part of the address.
00147           const size_t len = cp_pos - (address + 1);
00148           ACE_OS::memcpy (tmp_host, address + 1, len);
00149           tmp_host[len] = '\0';
00150         }
00151     }
00152   else
00153     {
00154 #endif /* ACE_HAS_IPV6 */
00155       // Extract out just the host part of the address.
00156       size_t len = port_separator_loc - address;
00157       ACE_OS::memcpy (tmp_host, address, len);
00158       tmp_host[len] = '\0';
00159 #if defined (ACE_HAS_IPV6)
00160     }
00161 #endif /* ACE_HAS_IPV6 */
00162 
00163   // Both host and port have to be specified.
00164   if (port_separator_loc == 0)
00165     {
00166       ACE_ERROR_RETURN ((LM_ERROR,
00167                          ACE_TEXT ("TAO (%P|%t) - ")
00168                          ACE_TEXT ("UIPMC_Acceptor::open, ")
00169                          ACE_TEXT ("port is not specified\n\n")),
00170                         -1);
00171     }
00172 
00173   if (addr.set (address) != 0)
00174     return -1;
00175 
00176   specified_hostname = tmp_host;
00177 
00178 #if defined (ACE_HAS_IPV6)
00179   // Check for violation of ORBConnectIPV6Only option
00180   if (this->orb_core_->orb_params ()->connect_ipv6_only () &&
00181       (addr.get_type () != AF_INET6 ||
00182        addr.is_ipv4_mapped_ipv6 ()))
00183     {
00184       ACE_ERROR_RETURN ((LM_ERROR,
00185                          ACE_TEXT ("TAO (%P|%t) - ")
00186                          ACE_TEXT ("UIPMC_Acceptor::open, ")
00187                          ACE_TEXT ("non-IPv6 endpoints not allowed when ")
00188                          ACE_TEXT ("connect_ipv6_only is set\n\n")),
00189                         -1);
00190     }
00191 #endif /* ACE_HAS_IPV6 */
00192 
00193   this->endpoint_count_ = 1;  // Only one hostname to store
00194 
00195   ACE_NEW_RETURN (this->addrs_,
00196                   ACE_INET_Addr[this->endpoint_count_],
00197                   -1);
00198 
00199   ACE_NEW_RETURN (this->hosts_,
00200                   char *[this->endpoint_count_],
00201                   -1);
00202 
00203   this->hosts_[0] = 0;
00204 
00205   if (this->hostname (orb_core,
00206                       addr,
00207                       this->hosts_[0],
00208                       specified_hostname) != 0)
00209     return -1;
00210 
00211   // Copy the addr.  The port is (re)set in
00212   // TAO_UIPMC_Acceptor::open_i().
00213   if (this->addrs_[0].set (addr) != 0)
00214     return -1;
00215 
00216   return this->open_i (addr,
00217                        reactor);
00218 }
00219 
00220 int
00221 TAO_UIPMC_Acceptor::open_default (TAO_ORB_Core *,
00222                                   ACE_Reactor *,
00223                                   int,
00224                                   int,
00225                                   const char *)
00226 {
00227   // There is no such thing as a default multicast listen
00228   // port.  The mechanism for choosing these ports is done
00229   // when creating the group ids.  (I.e. not here).
00230   return -1;
00231 }
00232 
00233 int
00234 TAO_UIPMC_Acceptor::open_i (const ACE_INET_Addr& addr,
00235                             ACE_Reactor *reactor)
00236 {
00237   ACE_NEW_RETURN (this->connection_handler_,
00238                   TAO_UIPMC_Mcast_Connection_Handler (this->orb_core_),
00239                   -1);
00240 
00241   this->connection_handler_->local_addr (addr);
00242   this->connection_handler_->open (0);
00243 
00244   int result =
00245     reactor->register_handler (this->connection_handler_,
00246                                ACE_Event_Handler::READ_MASK);
00247   if (result == -1)
00248     {
00249       // Close the handler (this will also delete connection_handler_).
00250       this->connection_handler_->close ();
00251       return result;
00252     }
00253 
00254   // Connection handler ownership now belongs to the Reactor.
00255   this->connection_handler_->remove_reference ();
00256 
00257   // Set the port for each addr.  If there is more than one network
00258   // interface then the endpoint created on each interface will be on
00259   // the same port.  This is how a wildcard socket bind() is supposed
00260   // to work.
00261   u_short port = addr.get_port_number ();
00262   for (size_t j = 0; j < this->endpoint_count_; ++j)
00263     this->addrs_[j].set_port_number (port, 1);
00264 
00265   if (TAO_debug_level > 5)
00266     {
00267       for (size_t i = 0; i < this->endpoint_count_; ++i)
00268         {
00269           ACE_DEBUG ((LM_DEBUG,
00270                       ACE_TEXT ("TAO (%P|%t) - UIPMC_Acceptor::open_i ")
00271                       ACE_TEXT ("listening on: <%s:%u>\n"),
00272                       this->hosts_[i],
00273                       this->addrs_[i].get_port_number ()));
00274         }
00275     }
00276 
00277   return 0;
00278 }
00279 
00280 int
00281 TAO_UIPMC_Acceptor::hostname (TAO_ORB_Core *,
00282                               ACE_INET_Addr &addr,
00283                               char *&host,
00284                               const char *)
00285 {
00286   // Only have dotted decimal addresses for multicast.
00287   return this->dotted_decimal_address (addr, host);
00288 }
00289 
00290 int
00291 TAO_UIPMC_Acceptor::dotted_decimal_address (ACE_INET_Addr &addr,
00292                                             char *&host)
00293 {
00294   const char *tmp = addr.get_host_addr ();
00295   if (tmp == 0)
00296     {
00297       if (TAO_debug_level > 0)
00298         ACE_DEBUG ((LM_DEBUG,
00299                     ACE_TEXT ("\n\nTAO (%P|%t) ")
00300                     ACE_TEXT ("UIPMC_Acceptor::dotted_decimal_address ")
00301                     ACE_TEXT ("- %p\n\n"),
00302                     ACE_TEXT ("cannot determine hostname")));
00303       return -1;
00304     }
00305 
00306   host = CORBA::string_dup (tmp);
00307   return 0;
00308 }
00309 
00310 CORBA::ULong
00311 TAO_UIPMC_Acceptor::endpoint_count (void)
00312 {
00313   return this->endpoint_count_;
00314 }
00315 
00316 int
00317 TAO_UIPMC_Acceptor::object_key (IOP::TaggedProfile &,
00318                                 TAO::ObjectKey &)
00319 {
00320   // No object key to extract.  Just return success.
00321   return 1;
00322 }
00323 
00324 int
00325 TAO_UIPMC_Acceptor::parse_options (const char *str)
00326 {
00327   if (str == 0)
00328     return 0;  // No options to parse.  Not a problem.
00329 
00330   // Use an option format similar to the one used for CGI scripts in
00331   // HTTP URLs.
00332   // e.g.:  option1=foo&option2=bar
00333 
00334   ACE_CString options (str);
00335 
00336   size_t len = options.length ();
00337 
00338   const char option_delimiter = '&';
00339 
00340   // Count the number of options.
00341   CORBA::ULong option_count = 1;
00342 
00343   // Only check for endpoints after the protocol specification and
00344   // before the object key.
00345   for (size_t i = 0; i < len; ++i)
00346     if (options[i] == option_delimiter)
00347       ++option_count;
00348 
00349   // The idea behind the following loop is to split the options into
00350   // (option, name) pairs.
00351   // For example,
00352   //    `option1=foo&option2=bar'
00353   // will be parsed into:
00354   //    `option1=foo'
00355   //    `option2=bar'
00356 
00357   ACE_CString::size_type begin = 0;
00358   ACE_CString::size_type end = 0;
00359 
00360   for (CORBA::ULong j = 0; j < option_count;)
00361     {
00362       if (j < option_count - 1)
00363         end = options.find (option_delimiter, begin);
00364       else
00365         end = len;
00366 
00367       ++j;  // In this way we fight MS VS warning about unreachable code.
00368 
00369       if (end == begin)
00370         ACE_ERROR_RETURN ((LM_ERROR,
00371                            ACE_TEXT ("TAO (%P|%t) Zero length UIPMC option.\n")),
00372                           -1);
00373       else if (end != ACE_CString::npos)
00374         {
00375           ACE_CString opt = options.substring (begin, end);
00376 
00377           ACE_CString::size_type const slot = opt.find ("=");
00378 
00379           if (slot == len - 1
00380               || slot == ACE_CString::npos)
00381             ACE_ERROR_RETURN ((LM_ERROR,
00382                                ACE_TEXT ("TAO (%P|%t) UIPMC option <%s> is ")
00383                                ACE_TEXT ("missing a value.\n"),
00384                                opt.c_str ()),
00385                               -1);
00386 
00387           ACE_CString name = opt.substring (0, slot);
00388           ACE_CString value = opt.substring (slot + 1);
00389 
00390           begin = end + 1;
00391 
00392           if (name.length () == 0)
00393             ACE_ERROR_RETURN ((LM_ERROR,
00394                                ACE_TEXT ("TAO (%P|%t) Zero length UIPMC ")
00395                                ACE_TEXT ("option name.\n")),
00396                               -1);
00397 
00398           if (name == "priority")
00399             {
00400               ACE_ERROR_RETURN ((LM_ERROR,
00401                                  ACE_TEXT ("TAO (%P|%t) Invalid UIPMC endpoint format: ")
00402                                  ACE_TEXT ("endpoint priorities no longer supported. \n"),
00403                                  value.c_str ()),
00404                                 -1);
00405             }
00406           else
00407             ACE_ERROR_RETURN ((LM_ERROR,
00408                                ACE_TEXT ("TAO (%P|%t) Invalid UIPMC option: <%s>\n"),
00409                                name.c_str ()),
00410                               -1);
00411         }
00412       else
00413         break;  // No other options.
00414     }
00415   return 0;
00416 }
00417 
00418 TAO_END_VERSIONED_NAMESPACE_DECL

Generated on Sun Jan 27 16:22:31 2008 for TAO_PortableGroup by doxygen 1.3.6