SOCK_Dgram_Mcast.cpp

Go to the documentation of this file.
00001 // $Id: SOCK_Dgram_Mcast.cpp 79134 2007-07-31 18:23:50Z johnnyw $
00002 
00003 #include "ace/SOCK_Dgram_Mcast.h"
00004 
00005 #include "ace/OS_Memory.h"
00006 #include "ace/OS_NS_string.h"
00007 #include "ace/OS_NS_errno.h"
00008 #include "ace/os_include/net/os_if.h"
00009 #include "ace/os_include/arpa/os_inet.h"
00010 
00011 #if defined (__linux__) && defined (ACE_HAS_IPV6)
00012 #include "ace/OS_NS_sys_socket.h"
00013 #endif
00014 
00015 #if defined (ACE_HAS_IPV6) && defined (ACE_WIN32)
00016 #include /**/ <Iphlpapi.h>
00017 #endif
00018 
00019 #if !defined (__ACE_INLINE__)
00020 #include "ace/SOCK_Dgram_Mcast.inl"
00021 #endif /* __ACE_INLINE__ */
00022 
00023 ACE_RCSID (ace,
00024            SOCK_Dgram_Mcast,
00025            "$Id: SOCK_Dgram_Mcast.cpp 79134 2007-07-31 18:23:50Z johnnyw $")
00026 
00027 #include "ace/Log_Msg.h"
00028 
00029 // This is a workaround for platforms with non-standard
00030 // definitions of the ip_mreq structure
00031 #if ! defined (IMR_MULTIADDR)
00032 #define IMR_MULTIADDR imr_multiaddr
00033 #endif /* ! defined (IMR_MULTIADDR) */
00034 
00035 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00036 
00037 // Helper (inline) functions.
00038 class ACE_SDM_helpers
00039 {
00040 public:
00041   // Convert ACE_INET_Addr to string, using local formatting rules.
00042 
00043   static void addr_to_string (const ACE_INET_Addr &ip_addr,
00044                               ACE_TCHAR *ret_string,  // results here.
00045                               size_t len,
00046                               int clip_portnum)       // clip port# info?
00047     {
00048       if (ip_addr.addr_to_string (ret_string, len, 1) == -1)
00049         ACE_OS::strcpy (ret_string, ACE_TEXT ("<?>"));
00050       else
00051         {
00052           ACE_TCHAR *pc = ACE_OS::strrchr (ret_string, ACE_TEXT (':'));
00053           if (clip_portnum && pc)
00054             *pc = ACE_TEXT ('\0'); // clip port# info.
00055         }
00056     }
00057     // op== for ip_mreq structs.
00058     static int is_equal (const ip_mreq &m1, const ip_mreq &m2)
00059       {
00060         return m1.IMR_MULTIADDR.s_addr == m2.IMR_MULTIADDR.s_addr
00061           && m1.imr_interface.s_addr == m2.imr_interface.s_addr;
00062       }
00063 };
00064 
00065 ACE_ALLOC_HOOK_DEFINE (ACE_SOCK_Dgram_Mcast)
00066 
00067 void
00068 ACE_SOCK_Dgram_Mcast::dump (void) const
00069 {
00070 #if defined (ACE_HAS_DUMP)
00071   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::dump");
00072 
00073   ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00074 
00075 # if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00076   ACE_TCHAR addr_string[MAXNAMELEN + 1];
00077 
00078   ACE_DEBUG ((LM_DEBUG,
00079               ACE_TEXT ("\nOptions: bindaddr=%s, nulliface=%s\n"),
00080               ACE_BIT_ENABLED (this->opts_, OPT_BINDADDR_YES) ?
00081                 ACE_TEXT ("<Bound>") : ACE_TEXT ("<Not Bound>"),
00082               ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL) ?
00083                 ACE_TEXT ("<All Ifaces>") : ACE_TEXT ("<Default Iface>")));
00084 
00085   // Show default send addr, port#, and interface.
00086   ACE_SDM_helpers::addr_to_string (this->send_addr_, addr_string,
00087                                    sizeof addr_string, 0);
00088   ACE_DEBUG ((LM_DEBUG,
00089               ACE_TEXT ("Send addr=%s iface=%s\n"),
00090               addr_string,
00091               this->send_net_if_ ? this->send_net_if_
00092                                  : ACE_TEXT ("<default>")));
00093 
00094   // Show list of subscribed addresses.
00095   ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Subscription list:\n")));
00096 
00097   ACE_MT (ACE_GUARD (ACE_SDM_LOCK, guard, this->subscription_list_lock_));
00098   subscription_list_iter_t  iter (this->subscription_list_);
00099   for ( ; !iter.done (); iter.advance ())
00100     {
00101       ACE_TCHAR iface_string[MAXNAMELEN + 1];
00102       ip_mreq *pm = iter.next ();
00103 
00104       // Get subscribed address (w/out port# info - not relevant).
00105       ACE_INET_Addr ip_addr (static_cast<u_short> (0),
00106                              ACE_NTOHL (pm->IMR_MULTIADDR.s_addr));
00107       ACE_SDM_helpers::addr_to_string (ip_addr, addr_string,
00108                                        sizeof addr_string, 1);
00109 
00110       // Get interface address/specification.
00111       ACE_INET_Addr if_addr (static_cast<u_short> (0),
00112                              ACE_NTOHL (pm->imr_interface.s_addr));
00113       ACE_SDM_helpers::addr_to_string (if_addr, iface_string,
00114                                        sizeof iface_string, 1);
00115       if (ACE_OS::strcmp (iface_string, ACE_TEXT ("0.0.0.0")) == 0)
00116         // Receives on system default iface. (Note that null_iface_opt_
00117         // option processing has already occurred.)
00118         ACE_OS::strcpy (iface_string, ACE_TEXT ("<default>"));
00119 
00120       // Dump info.
00121       ACE_DEBUG ((LM_DEBUG,
00122                   ACE_TEXT ("\taddr=%s iface=%s\n"),
00123                   addr_string,
00124                   iface_string));
00125     }
00126 # endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
00127   ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00128 #endif /* ACE_HAS_DUMP */
00129 }
00130 
00131 // Constructor.
00132 ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast
00133   (ACE_SOCK_Dgram_Mcast::options opts)
00134   :  opts_ (opts),
00135      send_net_if_ (0)
00136 {
00137   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast");
00138 }
00139 
00140 // Destructor.
00141 ACE_SOCK_Dgram_Mcast::~ACE_SOCK_Dgram_Mcast (void)
00142 {
00143   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::~ACE_SOCK_Dgram_Mcast");
00144 
00145   // Free memory and optionally unsubscribe from currently subscribed group(s).
00146   delete [] this->send_net_if_;
00147   this->clear_subs_list ();
00148 }
00149 
00150 int
00151 ACE_SOCK_Dgram_Mcast::open (const ACE_INET_Addr &mcast_addr,
00152                             const ACE_TCHAR *net_if,
00153                             int reuse_addr)
00154 {
00155   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::open");
00156 
00157   // Only perform the <open> initialization if we haven't been opened
00158   // earlier.
00159   // No sanity check?  We should probably flag an error if the user
00160   // makes multiple calls to open().
00161   if (this->get_handle () != ACE_INVALID_HANDLE)
00162     return 0;
00163 
00164   // Invoke lower-layer ::open.
00165   if (ACE_SOCK::open (SOCK_DGRAM,
00166                       mcast_addr.get_type (),
00167                       0, // always use 0
00168                       reuse_addr) == -1)
00169     return -1;
00170 
00171   return this->open_i (mcast_addr, net_if, reuse_addr);
00172 }
00173 
00174 int
00175 ACE_SOCK_Dgram_Mcast::open_i (const ACE_INET_Addr &mcast_addr,
00176                               const ACE_TCHAR *net_if,
00177                               int reuse_addr)
00178 {
00179   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::open_i");
00180   // ACE_SOCK::open calls this if reuse_addr is set, so we only need to
00181   // process port reuse option.
00182   if (reuse_addr)
00183     {
00184 #if defined (SO_REUSEPORT)
00185       int one = 1;
00186       if (this->ACE_SOCK::set_option (SOL_SOCKET,
00187                                       SO_REUSEPORT,
00188                                       &one,
00189                                       sizeof one) == -1)
00190         return -1;
00191 #endif /* SO_REUSEPORT */
00192     }
00193 
00194   // Create an address/port# to bind the socket to. Use mcast_addr to
00195   // initialize bind_addy to pick up the correct protocol family. If
00196   // OPT_BINDADDR_YES is set, then we're done. Else use mcast_addr's
00197   // port number and use the "any" address.
00198   ACE_INET_Addr bind_addy (mcast_addr);
00199   if (ACE_BIT_DISABLED (this->opts_, OPT_BINDADDR_YES))
00200     {
00201 #if defined (ACE_HAS_IPV6)
00202       if (mcast_addr.get_type () == PF_INET6)
00203         {
00204           if (bind_addy.set (mcast_addr.get_port_number (), "::",
00205                              1, AF_INET6) == -1)
00206             return -1;
00207         }
00208       else
00209         // Bind to "any" address and explicit port#.
00210         if (bind_addy.set (mcast_addr.get_port_number ()) == -1)
00211           return -1;
00212 #else
00213       // Bind to "any" address and explicit port#.
00214       if (bind_addy.set (mcast_addr.get_port_number ()) == -1)
00215         return -1;
00216 #endif /* ACE_HAS_IPV6 */
00217     }
00218 
00219   // Bind to the address (which may be INADDR_ANY) and port# (which may be 0)
00220   if (ACE_SOCK_Dgram::shared_open (bind_addy, bind_addy.get_type ()) == -1)
00221     return -1;
00222 
00223   // Cache the actual bound address (which may be INADDR_ANY)
00224   // and the actual bound port# (which will be a valid, non-zero port#).
00225   ACE_INET_Addr bound_addy;
00226   if (this->get_local_addr (bound_addy) == -1)
00227     {
00228       // (Unexpected failure - should be bound to something)
00229       if (bound_addy.set (bind_addy) == -1)
00230         {
00231           // (Shouldn't happen - bind_addy is a valid addy; punt.)
00232           return -1;
00233         }
00234     }
00235 
00236   this->send_addr_ = mcast_addr;
00237   this->send_addr_.set_port_number (bound_addy.get_port_number ());
00238   if (net_if)
00239     {
00240       if (this->set_nic (net_if, mcast_addr.get_type ()))
00241         return -1;
00242 
00243       this->send_net_if_ = new ACE_TCHAR[ACE_OS::strlen (net_if) + 1];
00244       ACE_OS::strcpy (this->send_net_if_, net_if);
00245     }
00246 
00247   return 0;
00248 }
00249 
00250 int
00251 ACE_SOCK_Dgram_Mcast::subscribe_ifs (const ACE_INET_Addr &mcast_addr,
00252                                      const ACE_TCHAR *net_if,
00253                                      int reuse_addr)
00254 {
00255   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_ifs");
00256 
00257   if (ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL)
00258       && net_if == 0)
00259     {
00260 #if defined (ACE_HAS_IPV6)
00261       if (mcast_addr.get_type () == AF_INET6)
00262         {
00263           size_t nr_subscribed = 0;
00264 # if defined(__linux__)
00265           struct if_nameindex *intf;
00266 
00267           intf = ACE_OS::if_nameindex ();
00268 
00269           if (intf == 0)
00270             return -1;
00271 
00272           int index = 0;
00273           while (intf[index].if_index != 0 || intf[index].if_name != 0)
00274             {
00275               if (this->join (mcast_addr, reuse_addr,
00276                               ACE_TEXT_CHAR_TO_TCHAR(intf[index].if_name)) == 0)
00277                 ++nr_subscribed;
00278 
00279               ++index;
00280             }
00281 
00282           ACE_OS::if_freenameindex (intf);
00283 
00284 # elif defined (ACE_WIN32)
00285 
00286           IP_ADAPTER_ADDRESSES tmp_addrs;
00287           // Initial call to determine actual memory size needed
00288           DWORD dwRetVal;
00289           ULONG bufLen = 0;
00290           if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
00291                                                   0,
00292                                                   0,
00293                                                   &tmp_addrs,
00294                                                   &bufLen)) != ERROR_BUFFER_OVERFLOW)
00295             return -1; // With output bufferlength 0 this can't be right.
00296 
00297           // Get required output buffer and retrieve info for real.
00298           PIP_ADAPTER_ADDRESSES pAddrs;
00299           char *buf;
00300           ACE_NEW_RETURN (buf,
00301                           char[bufLen],
00302                           -1);
00303           pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
00304           if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
00305                                                   0,
00306                                                   0,
00307                                                   pAddrs,
00308                                                   &bufLen)) != NO_ERROR)
00309             {
00310               delete[] buf; // clean up
00311               return -1;
00312             }
00313 
00314           while (pAddrs)
00315             {
00316               if (this->join (mcast_addr, reuse_addr,
00317                               ACE_TEXT_CHAR_TO_TCHAR(pAddrs->AdapterName)) == 0)
00318                 ++nr_subscribed;
00319 
00320               pAddrs = pAddrs->Next;
00321             }
00322 
00323           delete[] buf; // clean up
00324 
00325 # endif /* ACE_WIN32 */
00326 
00327           if (nr_subscribed == 0)
00328             {
00329               errno = ENODEV;
00330               return -1;
00331             }
00332 
00333           return 1;
00334         }
00335       else
00336         {
00337           // Subscribe on all local multicast-capable network interfaces, by
00338           // doing recursive calls with specific interfaces.
00339 
00340           ACE_INET_Addr *if_addrs = 0;
00341           size_t if_cnt;
00342 
00343           if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
00344             return -1;
00345 
00346           size_t nr_subscribed = 0;
00347 
00348           if (if_cnt < 2)
00349             {
00350               if (this->subscribe (mcast_addr,
00351                                    reuse_addr,
00352                                    ACE_TEXT ("0.0.0.0")) == 0)
00353                 ++nr_subscribed;
00354             }
00355           else
00356             {
00357               // Iterate through all the interfaces, figure out which ones
00358               // offer multicast service, and subscribe to them.
00359               while (if_cnt > 0)
00360                 {
00361                   --if_cnt;
00362 
00363                   // Convert to 0-based for indexing, next loop check.
00364                   if (if_addrs[if_cnt].get_type () != AF_INET || if_addrs[if_cnt].is_loopback ())
00365                     continue;
00366                   if (this->subscribe (mcast_addr,
00367                                        reuse_addr,
00368                                        ACE_TEXT_CHAR_TO_TCHAR
00369                                    (if_addrs[if_cnt].get_host_addr ())) == 0)
00370                     ++nr_subscribed;
00371                 }
00372             }
00373 
00374           delete [] if_addrs;
00375 
00376           if (nr_subscribed == 0)
00377             {
00378               errno = ENODEV;
00379               return -1;
00380             }
00381 
00382           // 1 indicates a "short-circuit" return.  This handles the
00383           // recursive behavior of checking all the interfaces.
00384           return 1;
00385 
00386         }
00387 #else
00388       // Subscribe on all local multicast-capable network interfaces, by
00389       // doing recursive calls with specific interfaces.
00390 
00391       ACE_INET_Addr *if_addrs = 0;
00392       size_t if_cnt;
00393 
00394       if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
00395         return -1;
00396 
00397       size_t nr_subscribed = 0;
00398 
00399       if (if_cnt < 2)
00400         {
00401           if (this->subscribe (mcast_addr,
00402                                reuse_addr,
00403                                ACE_TEXT ("0.0.0.0")) == 0)
00404             ++nr_subscribed;
00405         }
00406       else
00407         {
00408           // Iterate through all the interfaces, figure out which ones
00409           // offer multicast service, and subscribe to them.
00410           while (if_cnt > 0)
00411             {
00412               --if_cnt;
00413 
00414               // Convert to 0-based for indexing, next loop check.
00415               if (if_addrs[if_cnt].is_loopback ())
00416                 continue;
00417               if (this->subscribe (mcast_addr,
00418                                    reuse_addr,
00419                                    ACE_TEXT_CHAR_TO_TCHAR
00420                                      (if_addrs[if_cnt].get_host_addr ())) == 0)
00421                 ++nr_subscribed;
00422             }
00423         }
00424 
00425       delete [] if_addrs;
00426 
00427       if (nr_subscribed == 0)
00428         {
00429           errno = ENODEV;
00430           return -1;
00431         }
00432 
00433       // 1 indicates a "short-circuit" return.  This handles the
00434       // recursive behavior of checking all the interfaces.
00435       return 1;
00436 #endif /* ACE_HAS_IPV6 */
00437     }
00438 
00439 #if defined (ACE_HAS_IPV6)
00440   if (mcast_addr.get_type () == AF_INET6)
00441     {
00442       if (this->make_multicast_ifaddr6 (0, mcast_addr, net_if) == -1)
00443         return -1;
00444     }
00445   else
00446     {
00447       // Validate passed multicast addr and iface specifications.
00448       if (this->make_multicast_ifaddr (0,
00449                                        mcast_addr,
00450                                        net_if) == -1)
00451         return -1;
00452     }
00453 #else
00454     // Validate passed multicast addr and iface specifications.
00455     if (this->make_multicast_ifaddr (0,
00456                                      mcast_addr,
00457                                      net_if) == -1)
00458       return -1;
00459 #endif /* ACE_HAS_IPV6 */
00460 
00461   return 0;
00462 
00463 }
00464 
00465 // Subscribe and add address/iface to subscription list if successful.
00466 int
00467 ACE_SOCK_Dgram_Mcast::subscribe (const ACE_INET_Addr &mcast_addr,
00468                                  int reuse_addr,
00469                                  const ACE_TCHAR *net_if,
00470                                  int protocol_family,
00471                                  int protocol)
00472 {
00473   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe");
00474 
00475   ACE_UNUSED_ARG (protocol_family);
00476   ACE_UNUSED_ARG (protocol);
00477 
00478   return this->join (mcast_addr,reuse_addr, net_if);
00479 }
00480 
00481 int
00482 ACE_SOCK_Dgram_Mcast::join (const ACE_INET_Addr &mcast_addr,
00483                             int reuse_addr,
00484                             const ACE_TCHAR *net_if)
00485 {
00486   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::join");
00487   ACE_INET_Addr subscribe_addr = mcast_addr;
00488 
00489   // If port# is 0, insert bound port# if it is set. (To satisfy lower-level
00490   // port# validation.)
00491   u_short def_port_number = this->send_addr_.get_port_number ();
00492   if (subscribe_addr.get_port_number () == 0
00493       && def_port_number != 0)
00494     {
00495       subscribe_addr.set_port_number (def_port_number);
00496     }
00497 
00498   // Check for port# different than bound port#.
00499   u_short sub_port_number = mcast_addr.get_port_number ();
00500   if (sub_port_number != 0
00501       && def_port_number != 0
00502       && sub_port_number != def_port_number)
00503     {
00504       ACE_ERROR ((LM_ERROR,
00505                   ACE_TEXT ("Subscribed port# (%u) different than bound ")
00506                   ACE_TEXT ("port# (%u).\n"),
00507                   (u_int) sub_port_number,
00508                   (u_int) def_port_number));
00509       errno = ENXIO;
00510       return -1;
00511     }
00512 
00513   // If bind_addr_opt_ is enabled, check for address different than
00514   // bound address.
00515   ACE_INET_Addr tmp_addr (this->send_addr_);
00516   tmp_addr.set_port_number (mcast_addr.get_port_number ()); // force equal port numbers
00517   if (ACE_BIT_ENABLED (this->opts_, OPT_BINDADDR_YES)
00518       && !this->send_addr_.is_any ()
00519       && this->send_addr_ != mcast_addr)
00520     {
00521       ACE_TCHAR sub_addr_string[MAXNAMELEN + 1];
00522       ACE_TCHAR bound_addr_string[MAXNAMELEN + 1];
00523       ACE_SDM_helpers::addr_to_string (mcast_addr, sub_addr_string,
00524                                        sizeof sub_addr_string, 1);
00525       ACE_SDM_helpers::addr_to_string (this->send_addr_, bound_addr_string,
00526                                        sizeof bound_addr_string, 1);
00527       ACE_ERROR ((LM_ERROR,
00528                   ACE_TEXT ("Subscribed address (%s) different than ")
00529                   ACE_TEXT ("bound address (%s).\n"),
00530                   sub_addr_string,
00531                   bound_addr_string));
00532       errno = ENXIO;
00533       return -1;
00534     }
00535 
00536   // Attempt subscription.
00537   int  result = this->subscribe_i (subscribe_addr, reuse_addr, net_if);
00538 
00539 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00540   if (result == 0)
00541     {
00542       // Add this addr/iface info to the list of subscriptions.
00543       // (Assumes this is unique addr/iface combo - most systems don't allow
00544       // re-sub to same addr/iface.)
00545       ip_mreq  *pmreq = new ip_mreq;
00546       // (should not fail)
00547       if (this->make_multicast_ifaddr (pmreq, subscribe_addr, net_if) != -1)
00548         {
00549           ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
00550                                     this->subscription_list_lock_, -1));
00551           this->subscription_list_.insert_tail (pmreq);
00552           return 0;
00553         }
00554       // this still isn't really right. If ACE_GUARD_RETURN fails, we leak.
00555       // Need to add one of Chris' fancy ace auto pointers (bound?).
00556       delete pmreq;
00557     }
00558 #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
00559 
00560   return result >= 0 ? 0 : result;
00561 }
00562 
00563 // Attempt subscribe and return status.
00564 int
00565 ACE_SOCK_Dgram_Mcast::subscribe_i (const ACE_INET_Addr &mcast_addr,
00566                                    int reuse_addr,
00567                                    const ACE_TCHAR *net_if)
00568 {
00569   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_i");
00570   ip_mreq  mreq;
00571 #if defined (ACE_HAS_IPV6)
00572   ipv6_mreq mreq6;
00573 #endif /* __linux__ && ACE_HAS_IPV6 */
00574 
00575   // Open the socket IFF this is the first ::subscribe and ::open
00576   // was not explicitly invoked.
00577   if (this->open (mcast_addr,
00578                   net_if,
00579                   reuse_addr) == -1)
00580     return -1;
00581 
00582   // Only do this if net_if == 0, i.e., INADDR_ANY
00583   if (net_if == 0)
00584     {
00585       int result = this->subscribe_ifs (mcast_addr,
00586                                         net_if,
00587                                         reuse_addr);
00588       // Check for error or "short-circuit" return.
00589       if (result != 0)
00590         return result;
00591     }
00592 
00593 #if defined (ACE_HAS_IPV6)
00594   if (mcast_addr.get_type () == AF_INET6)
00595     {
00596       if (this->make_multicast_ifaddr6 (&mreq6, mcast_addr, net_if) == -1)
00597         return -1;
00598       // Tell IP stack to pass messages sent to this group.
00599       else if (this->ACE_SOCK::set_option (IPPROTO_IPV6,
00600                                            IPV6_JOIN_GROUP,
00601                                            &mreq6,
00602                                            sizeof mreq6) == -1)
00603         return -1;
00604 
00605       return 0;
00606     }
00607   // Fall through for IPv4 case
00608 #endif /* ACE_HAS_IPV6 */
00609 
00610   // Create multicast addr/if struct.
00611   if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00612     return -1;
00613   // Tell IP stack to pass messages sent to this group.
00614   else if (this->ACE_SOCK::set_option (IPPROTO_IP,
00615                                        IP_ADD_MEMBERSHIP,
00616                                        &mreq,
00617                                        sizeof mreq) == -1)
00618     return -1;
00619 
00620   return 0;
00621 }
00622 
00623 int
00624 ACE_SOCK_Dgram_Mcast::unsubscribe_ifs (const ACE_INET_Addr &mcast_addr,
00625                                        const ACE_TCHAR *net_if)
00626 {
00627   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_ifs");
00628 
00629 
00630   if (ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL)
00631       && net_if == 0)
00632     {
00633 #if defined (ACE_HAS_IPV6)
00634       if (mcast_addr.get_type () == AF_INET6)
00635         {
00636           size_t nr_unsubscribed = 0;
00637 # if defined(__linux__)
00638 
00639           struct if_nameindex *intf;
00640 
00641           intf = ACE_OS::if_nameindex ();
00642 
00643           if (intf == 0)
00644             return -1;
00645 
00646           int index = 0;
00647           while (intf[index].if_index != 0 || intf[index].if_name != 0)
00648             {
00649               if (this->leave (mcast_addr, ACE_TEXT_CHAR_TO_TCHAR(intf[index].if_name)) == 0)
00650                 ++nr_unsubscribed;
00651 
00652               ++index;
00653             }
00654 
00655           ACE_OS::if_freenameindex (intf);
00656 
00657 # elif defined (ACE_WIN32)
00658 
00659           IP_ADAPTER_ADDRESSES tmp_addrs;
00660           // Initial call to determine actual memory size needed
00661           DWORD dwRetVal;
00662           ULONG bufLen = 0;
00663           if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
00664                                                   0,
00665                                                   0,
00666                                                   &tmp_addrs,
00667                                                   &bufLen)) != ERROR_BUFFER_OVERFLOW)
00668             return -1; // With output bufferlength 0 this can't be right.
00669 
00670           // Get required output buffer and retrieve info for real.
00671           PIP_ADAPTER_ADDRESSES pAddrs;
00672           char *buf;
00673           ACE_NEW_RETURN (buf,
00674                           char[bufLen],
00675                           -1);
00676           pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
00677           if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
00678                                                   0,
00679                                                   0,
00680                                                   pAddrs,
00681                                                   &bufLen)) != NO_ERROR)
00682             {
00683               delete[] buf; // clean up
00684               return -1;
00685             }
00686 
00687           while (pAddrs)
00688             {
00689               if (this->leave (mcast_addr, ACE_TEXT_CHAR_TO_TCHAR(pAddrs->AdapterName)) == 0)
00690                 ++nr_unsubscribed;
00691 
00692               pAddrs = pAddrs->Next;
00693             }
00694 
00695           delete[] buf; // clean up
00696 
00697 # endif /* ACE_WIN32 */
00698 
00699           if (nr_unsubscribed == 0)
00700             {
00701               errno = ENODEV;
00702               return -1;
00703             }
00704 
00705           return 1;
00706 
00707 
00708         }
00709       else
00710         {
00711           // Unsubscribe on all local multicast-capable network interfaces, by
00712           // doing recursive calls with specific interfaces.
00713 
00714           ACE_INET_Addr *if_addrs = 0;
00715           size_t if_cnt;
00716 
00717           // NOTE - <get_ip_interfaces> doesn't always get all of the
00718           // interfaces.  In particular, it may not get a PPP interface.  This
00719           // is a limitation of the way <get_ip_interfaces> works with
00720           // old versions of MSVC.  The reliable way of getting the interface
00721           // list is available only with MSVC 5 and newer.
00722           if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
00723             return -1;
00724 
00725           size_t nr_unsubscribed = 0;
00726 
00727           if (if_cnt < 2)
00728             {
00729               if (this->leave (mcast_addr,
00730                                ACE_TEXT ("0.0.0.0")) == 0)
00731                 ++nr_unsubscribed;
00732             }
00733           else
00734             {
00735               while (if_cnt > 0)
00736                 {
00737                   --if_cnt;
00738                   // Convert to 0-based for indexing, next loop check
00739                   if (if_addrs[if_cnt].get_type () != AF_INET || if_addrs[if_cnt].is_loopback ())
00740                     continue;
00741                   if (this->leave (mcast_addr,
00742                                    ACE_TEXT_CHAR_TO_TCHAR
00743                                    (if_addrs[if_cnt].get_host_addr ())) == 0)
00744                     ++nr_unsubscribed;
00745                 }
00746             }
00747 
00748           delete [] if_addrs;
00749 
00750           if (nr_unsubscribed == 0)
00751             {
00752               errno = ENODEV;
00753               return -1;
00754             }
00755 
00756           return 1;
00757 
00758         }
00759 #else /* ACE_HAS_IPV6 */
00760       // Unsubscribe on all local multicast-capable network interfaces, by
00761       // doing recursive calls with specific interfaces.
00762 
00763       ACE_INET_Addr *if_addrs = 0;
00764       size_t if_cnt;
00765 
00766       // NOTE - <get_ip_interfaces> doesn't always get all of the
00767       // interfaces.  In particular, it may not get a PPP interface.  This
00768       // is a limitation of the way <get_ip_interfaces> works with
00769       // old versions of MSVC.  The reliable way of getting the interface list
00770       // is available only with MSVC 5 and newer.
00771       if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
00772         return -1;
00773 
00774       size_t nr_unsubscribed = 0;
00775 
00776       if (if_cnt < 2)
00777         {
00778           if (this->leave (mcast_addr,
00779                            ACE_TEXT ("0.0.0.0")) == 0)
00780             ++nr_unsubscribed;
00781         }
00782       else
00783         {
00784           while (if_cnt > 0)
00785             {
00786               --if_cnt;
00787               // Convert to 0-based for indexing, next loop check
00788               if (if_addrs[if_cnt].is_loopback ())
00789                 continue;
00790               if (this->leave (mcast_addr,
00791                                ACE_TEXT_CHAR_TO_TCHAR
00792                                (if_addrs[if_cnt].get_host_addr ())) == 0)
00793                 ++nr_unsubscribed;
00794             }
00795         }
00796 
00797       delete [] if_addrs;
00798 
00799       if (nr_unsubscribed == 0)
00800         {
00801           errno = ENODEV;
00802           return -1;
00803         }
00804 
00805       return 1;
00806 #endif /* !ACE_HAS_IPV6 */
00807     }
00808 
00809   return 0;
00810 }
00811 
00812 
00813 // Unsubscribe, and remove address from subscription list.
00814 // Note: If there are duplicate entries, only finds the first in the list (this
00815 // is a defined restriction - most environments don't allow duplicates to be
00816 // created.)
00817 int
00818 ACE_SOCK_Dgram_Mcast::unsubscribe (const ACE_INET_Addr &mcast_addr,
00819                                    const ACE_TCHAR *net_if,
00820                                    int protocol_family,
00821                                    int protocol)
00822 {
00823   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe");
00824 
00825   ACE_UNUSED_ARG (protocol_family);
00826   ACE_UNUSED_ARG (protocol);
00827 
00828   return this->leave (mcast_addr, net_if);
00829 }
00830 
00831 int
00832 ACE_SOCK_Dgram_Mcast::leave (const ACE_INET_Addr &mcast_addr,
00833                              const ACE_TCHAR *net_if)
00834 {
00835   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::leave");
00836   // Unsubscribe.
00837   int result = this->unsubscribe_i (mcast_addr,
00838                                     net_if);
00839 
00840 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00841   // (Unconditionally) Remove this addr/if from subscription list.
00842   // (Addr/if is removed even if unsubscribe failed)
00843   ip_mreq  tgt_mreq;
00844   if (this->make_multicast_ifaddr (&tgt_mreq,
00845                                    mcast_addr,
00846                                    net_if) != -1)
00847     {
00848       ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
00849                                 this->subscription_list_lock_, -1));
00850       subscription_list_iter_t iter (this->subscription_list_);
00851       for (; !iter.done (); iter.advance ())
00852         {
00853           ip_mreq  *pm = iter.next ();
00854           if (ACE_SDM_helpers::is_equal (*pm, tgt_mreq))
00855             {
00856               iter.remove ();
00857               delete pm;
00858               break;
00859             }
00860         }
00861     }
00862 #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
00863 
00864   return result >= 0 ? 0 : result;
00865 }
00866 
00867 // Attempt unsubscribe and return status.
00868 int
00869 ACE_SOCK_Dgram_Mcast::unsubscribe_i (const ACE_INET_Addr &mcast_addr,
00870                                      const ACE_TCHAR *net_if)
00871 {
00872   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_i");
00873 
00874   int result = this->unsubscribe_ifs (mcast_addr,
00875                                       net_if);
00876 
00877   // Check for error or "short-circuit" return.
00878   if (result != 0)
00879     return result;
00880 
00881 #if defined (ACE_HAS_IPV6)
00882   if (mcast_addr.get_type () == AF_INET6)
00883     {
00884       // Validate addr/if specifications and create addr/if struct.
00885       ipv6_mreq  mreq;
00886       if (this->make_multicast_ifaddr6 (&mreq, mcast_addr, net_if) == -1)
00887         {
00888           return -1;
00889         }
00890       // Tell network device driver to stop reading datagrams with the
00891       // <mcast_addr>.
00892       else if (ACE_SOCK::set_option (IPPROTO_IPV6,
00893                                      IPV6_LEAVE_GROUP,
00894                                      &mreq,
00895                                      sizeof mreq) == -1)
00896         {
00897           return -1;
00898         }
00899 
00900     }
00901   else  // IPv4
00902     {
00903       // Validate addr/if specifications and create addr/if struct.
00904       ip_mreq  mreq;
00905       if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00906         {
00907           return -1;
00908         }
00909       // Tell network device driver to stop reading datagrams with the
00910       // <mcast_addr>.
00911       else if (ACE_SOCK::set_option (IPPROTO_IP,
00912                                      IP_DROP_MEMBERSHIP,
00913                                      &mreq,
00914                                  sizeof mreq) == -1)
00915         {
00916           return -1;
00917         }
00918 
00919     }
00920 #else
00921   // Validate addr/if specifications and create addr/if struct.
00922   ip_mreq  mreq;
00923   if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00924     {
00925       return -1;
00926     }
00927   // Tell network device driver to stop reading datagrams with the
00928   // <mcast_addr>.
00929   // Note, this is not IPv6 friendly...
00930   else if (ACE_SOCK::set_option (IPPROTO_IP,
00931                                  IP_DROP_MEMBERSHIP,
00932                                  &mreq,
00933                                  sizeof mreq) == -1)
00934     {
00935       return -1;
00936     }
00937 #endif /* ACE_HAS_IPV6 */
00938 
00939   return 0;
00940 }
00941 
00942 int
00943 ACE_SOCK_Dgram_Mcast::unsubscribe (void)
00944 {
00945   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe");
00946 
00947   // Can't implement this reliably without keeping an expensive list,
00948   // and can't close the socket since the caller may want to continue
00949   // using the socket to send() or join() new groups.  Even if we
00950   // wanted to be clever and reopen the socket, we'd need to know what
00951   // options had been set, and reset them--and we have no way of doing
00952   // that either. :-(
00953   // Should this return -1?
00954   ACE_ERROR_RETURN ((LM_INFO,
00955                      ACE_TEXT ("ACE_SOCK_Dgram_Mcast::unsubscribe (void) ")
00956                      ACE_TEXT ("has been deprecated. You must either ")
00957                      ACE_TEXT ("close to socket to unsubscribe to all ")
00958                      ACE_TEXT ("or unsubscribe to each individually.\n")),
00959                      0);
00960 }
00961 
00962 int
00963 ACE_SOCK_Dgram_Mcast::clear_subs_list (void)
00964 {
00965   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::clear_subs_list");
00966   int  result = 0;
00967 
00968 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00969   ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
00970                             this->subscription_list_lock_, -1));
00971   subscription_list_iter_t iter (this->subscription_list_);
00972   for (; !iter.done (); /*Hack: Do _not_ ::advance after remove*/)
00973     {
00974       ip_mreq  *pm = iter.next ();
00975       iter.remove ();
00976       delete pm;
00977     }
00978 #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
00979   return result;
00980 }
00981 
00982 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Sun Jan 27 12:05:38 2008 for ACE by doxygen 1.3.6