SOCK_Dgram_Mcast.cpp

Go to the documentation of this file.
00001 // $Id: SOCK_Dgram_Mcast.cpp 81517 2008-04-29 07:23:47Z 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 81517 2008-04-29 07:23:47Z 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->join (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->join (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->join (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->join (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 int
00466 ACE_SOCK_Dgram_Mcast::join (const ACE_INET_Addr &mcast_addr,
00467                             int reuse_addr,
00468                             const ACE_TCHAR *net_if)
00469 {
00470   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::join");
00471   ACE_INET_Addr subscribe_addr = mcast_addr;
00472 
00473   // If port# is 0, insert bound port# if it is set. (To satisfy lower-level
00474   // port# validation.)
00475   u_short def_port_number = this->send_addr_.get_port_number ();
00476   if (subscribe_addr.get_port_number () == 0
00477       && def_port_number != 0)
00478     {
00479       subscribe_addr.set_port_number (def_port_number);
00480     }
00481 
00482   // Check for port# different than bound port#.
00483   u_short sub_port_number = mcast_addr.get_port_number ();
00484   if (sub_port_number != 0
00485       && def_port_number != 0
00486       && sub_port_number != def_port_number)
00487     {
00488       ACE_ERROR ((LM_ERROR,
00489                   ACE_TEXT ("Subscribed port# (%u) different than bound ")
00490                   ACE_TEXT ("port# (%u).\n"),
00491                   (u_int) sub_port_number,
00492                   (u_int) def_port_number));
00493       errno = ENXIO;
00494       return -1;
00495     }
00496 
00497   // If bind_addr_opt_ is enabled, check for address different than
00498   // bound address.
00499   ACE_INET_Addr tmp_addr (this->send_addr_);
00500   tmp_addr.set_port_number (mcast_addr.get_port_number ()); // force equal port numbers
00501   if (ACE_BIT_ENABLED (this->opts_, OPT_BINDADDR_YES)
00502       && !this->send_addr_.is_any ()
00503       && this->send_addr_ != mcast_addr)
00504     {
00505       ACE_TCHAR sub_addr_string[MAXNAMELEN + 1];
00506       ACE_TCHAR bound_addr_string[MAXNAMELEN + 1];
00507       ACE_SDM_helpers::addr_to_string (mcast_addr, sub_addr_string,
00508                                        sizeof sub_addr_string, 1);
00509       ACE_SDM_helpers::addr_to_string (this->send_addr_, bound_addr_string,
00510                                        sizeof bound_addr_string, 1);
00511       ACE_ERROR ((LM_ERROR,
00512                   ACE_TEXT ("Subscribed address (%s) different than ")
00513                   ACE_TEXT ("bound address (%s).\n"),
00514                   sub_addr_string,
00515                   bound_addr_string));
00516       errno = ENXIO;
00517       return -1;
00518     }
00519 
00520   // Attempt subscription.
00521   int result = this->subscribe_i (subscribe_addr, reuse_addr, net_if);
00522 
00523 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00524   if (result == 0)
00525     {
00526       // Add this addr/iface info to the list of subscriptions.
00527       // (Assumes this is unique addr/iface combo - most systems don't allow
00528       // re-sub to same addr/iface.)
00529       ip_mreq  *pmreq = new ip_mreq;
00530       // (should not fail)
00531       if (this->make_multicast_ifaddr (pmreq, subscribe_addr, net_if) != -1)
00532         {
00533           ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
00534                                     this->subscription_list_lock_, -1));
00535           this->subscription_list_.insert_tail (pmreq);
00536           return 0;
00537         }
00538       // this still isn't really right. If ACE_GUARD_RETURN fails, we leak.
00539       // Need to add one of Chris' fancy ace auto pointers (bound?).
00540       delete pmreq;
00541     }
00542 #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
00543 
00544   return result >= 0 ? 0 : result;
00545 }
00546 
00547 // Attempt subscribe and return status.
00548 int
00549 ACE_SOCK_Dgram_Mcast::subscribe_i (const ACE_INET_Addr &mcast_addr,
00550                                    int reuse_addr,
00551                                    const ACE_TCHAR *net_if)
00552 {
00553   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_i");
00554   ip_mreq  mreq;
00555 #if defined (ACE_HAS_IPV6)
00556   ipv6_mreq mreq6;
00557 #endif /* __linux__ && ACE_HAS_IPV6 */
00558 
00559   // Open the socket IFF this is the first ::subscribe and ::open
00560   // was not explicitly invoked.
00561   if (this->open (mcast_addr,
00562                   net_if,
00563                   reuse_addr) == -1)
00564     return -1;
00565 
00566   // Only do this if net_if == 0, i.e., INADDR_ANY
00567   if (net_if == 0)
00568     {
00569       int result = this->subscribe_ifs (mcast_addr,
00570                                         net_if,
00571                                         reuse_addr);
00572       // Check for error or "short-circuit" return.
00573       if (result != 0)
00574         return result;
00575     }
00576 
00577 #if defined (ACE_HAS_IPV6)
00578   if (mcast_addr.get_type () == AF_INET6)
00579     {
00580       if (this->make_multicast_ifaddr6 (&mreq6, mcast_addr, net_if) == -1)
00581         return -1;
00582       // Tell IP stack to pass messages sent to this group.
00583       else if (this->ACE_SOCK::set_option (IPPROTO_IPV6,
00584                                            IPV6_JOIN_GROUP,
00585                                            &mreq6,
00586                                            sizeof mreq6) == -1)
00587         return -1;
00588 
00589       return 0;
00590     }
00591   // Fall through for IPv4 case
00592 #endif /* ACE_HAS_IPV6 */
00593 
00594   // Create multicast addr/if struct.
00595   if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00596     return -1;
00597   // Tell IP stack to pass messages sent to this group.
00598   else if (this->ACE_SOCK::set_option (IPPROTO_IP,
00599                                        IP_ADD_MEMBERSHIP,
00600                                        &mreq,
00601                                        sizeof mreq) == -1)
00602     return -1;
00603 
00604   return 0;
00605 }
00606 
00607 int
00608 ACE_SOCK_Dgram_Mcast::unsubscribe_ifs (const ACE_INET_Addr &mcast_addr,
00609                                        const ACE_TCHAR *net_if)
00610 {
00611   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_ifs");
00612 
00613 
00614   if (ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL)
00615       && net_if == 0)
00616     {
00617 #if defined (ACE_HAS_IPV6)
00618       if (mcast_addr.get_type () == AF_INET6)
00619         {
00620           size_t nr_unsubscribed = 0;
00621 # if defined(__linux__)
00622 
00623           struct if_nameindex *intf;
00624 
00625           intf = ACE_OS::if_nameindex ();
00626 
00627           if (intf == 0)
00628             return -1;
00629 
00630           int index = 0;
00631           while (intf[index].if_index != 0 || intf[index].if_name != 0)
00632             {
00633               if (this->leave (mcast_addr, ACE_TEXT_CHAR_TO_TCHAR(intf[index].if_name)) == 0)
00634                 ++nr_unsubscribed;
00635 
00636               ++index;
00637             }
00638 
00639           ACE_OS::if_freenameindex (intf);
00640 
00641 # elif defined (ACE_WIN32)
00642 
00643           IP_ADAPTER_ADDRESSES tmp_addrs;
00644           // Initial call to determine actual memory size needed
00645           DWORD dwRetVal;
00646           ULONG bufLen = 0;
00647           if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
00648                                                   0,
00649                                                   0,
00650                                                   &tmp_addrs,
00651                                                   &bufLen)) != ERROR_BUFFER_OVERFLOW)
00652             return -1; // With output bufferlength 0 this can't be right.
00653 
00654           // Get required output buffer and retrieve info for real.
00655           PIP_ADAPTER_ADDRESSES pAddrs;
00656           char *buf;
00657           ACE_NEW_RETURN (buf,
00658                           char[bufLen],
00659                           -1);
00660           pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
00661           if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
00662                                                   0,
00663                                                   0,
00664                                                   pAddrs,
00665                                                   &bufLen)) != NO_ERROR)
00666             {
00667               delete[] buf; // clean up
00668               return -1;
00669             }
00670 
00671           while (pAddrs)
00672             {
00673               if (this->leave (mcast_addr, ACE_TEXT_CHAR_TO_TCHAR(pAddrs->AdapterName)) == 0)
00674                 ++nr_unsubscribed;
00675 
00676               pAddrs = pAddrs->Next;
00677             }
00678 
00679           delete[] buf; // clean up
00680 
00681 # endif /* ACE_WIN32 */
00682 
00683           if (nr_unsubscribed == 0)
00684             {
00685               errno = ENODEV;
00686               return -1;
00687             }
00688 
00689           return 1;
00690 
00691 
00692         }
00693       else
00694         {
00695           // Unsubscribe on all local multicast-capable network interfaces, by
00696           // doing recursive calls with specific interfaces.
00697 
00698           ACE_INET_Addr *if_addrs = 0;
00699           size_t if_cnt;
00700 
00701           // NOTE - <get_ip_interfaces> doesn't always get all of the
00702           // interfaces.  In particular, it may not get a PPP interface.  This
00703           // is a limitation of the way <get_ip_interfaces> works with
00704           // old versions of MSVC.  The reliable way of getting the interface
00705           // list is available only with MSVC 5 and newer.
00706           if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
00707             return -1;
00708 
00709           size_t nr_unsubscribed = 0;
00710 
00711           if (if_cnt < 2)
00712             {
00713               if (this->leave (mcast_addr,
00714                                ACE_TEXT ("0.0.0.0")) == 0)
00715                 ++nr_unsubscribed;
00716             }
00717           else
00718             {
00719               while (if_cnt > 0)
00720                 {
00721                   --if_cnt;
00722                   // Convert to 0-based for indexing, next loop check
00723                   if (if_addrs[if_cnt].get_type () != AF_INET || if_addrs[if_cnt].is_loopback ())
00724                     continue;
00725                   if (this->leave (mcast_addr,
00726                                    ACE_TEXT_CHAR_TO_TCHAR
00727                                    (if_addrs[if_cnt].get_host_addr ())) == 0)
00728                     ++nr_unsubscribed;
00729                 }
00730             }
00731 
00732           delete [] if_addrs;
00733 
00734           if (nr_unsubscribed == 0)
00735             {
00736               errno = ENODEV;
00737               return -1;
00738             }
00739 
00740           return 1;
00741 
00742         }
00743 #else /* ACE_HAS_IPV6 */
00744       // Unsubscribe on all local multicast-capable network interfaces, by
00745       // doing recursive calls with specific interfaces.
00746 
00747       ACE_INET_Addr *if_addrs = 0;
00748       size_t if_cnt;
00749 
00750       // NOTE - <get_ip_interfaces> doesn't always get all of the
00751       // interfaces.  In particular, it may not get a PPP interface.  This
00752       // is a limitation of the way <get_ip_interfaces> works with
00753       // old versions of MSVC.  The reliable way of getting the interface list
00754       // is available only with MSVC 5 and newer.
00755       if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
00756         return -1;
00757 
00758       size_t nr_unsubscribed = 0;
00759 
00760       if (if_cnt < 2)
00761         {
00762           if (this->leave (mcast_addr,
00763                            ACE_TEXT ("0.0.0.0")) == 0)
00764             ++nr_unsubscribed;
00765         }
00766       else
00767         {
00768           while (if_cnt > 0)
00769             {
00770               --if_cnt;
00771               // Convert to 0-based for indexing, next loop check
00772               if (if_addrs[if_cnt].is_loopback ())
00773                 continue;
00774               if (this->leave (mcast_addr,
00775                                ACE_TEXT_CHAR_TO_TCHAR
00776                                (if_addrs[if_cnt].get_host_addr ())) == 0)
00777                 ++nr_unsubscribed;
00778             }
00779         }
00780 
00781       delete [] if_addrs;
00782 
00783       if (nr_unsubscribed == 0)
00784         {
00785           errno = ENODEV;
00786           return -1;
00787         }
00788 
00789       return 1;
00790 #endif /* !ACE_HAS_IPV6 */
00791     }
00792 
00793   return 0;
00794 }
00795 
00796 
00797 int
00798 ACE_SOCK_Dgram_Mcast::leave (const ACE_INET_Addr &mcast_addr,
00799                              const ACE_TCHAR *net_if)
00800 {
00801   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::leave");
00802   // Unsubscribe.
00803   int result = this->unsubscribe_i (mcast_addr,
00804                                     net_if);
00805 
00806 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00807   // (Unconditionally) Remove this addr/if from subscription list.
00808   // (Addr/if is removed even if unsubscribe failed)
00809   ip_mreq  tgt_mreq;
00810   if (this->make_multicast_ifaddr (&tgt_mreq,
00811                                    mcast_addr,
00812                                    net_if) != -1)
00813     {
00814       ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
00815                                 this->subscription_list_lock_, -1));
00816       subscription_list_iter_t iter (this->subscription_list_);
00817       for (; !iter.done (); iter.advance ())
00818         {
00819           ip_mreq  *pm = iter.next ();
00820           if (ACE_SDM_helpers::is_equal (*pm, tgt_mreq))
00821             {
00822               iter.remove ();
00823               delete pm;
00824               break;
00825             }
00826         }
00827     }
00828 #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
00829 
00830   return result >= 0 ? 0 : result;
00831 }
00832 
00833 // Attempt unsubscribe and return status.
00834 int
00835 ACE_SOCK_Dgram_Mcast::unsubscribe_i (const ACE_INET_Addr &mcast_addr,
00836                                      const ACE_TCHAR *net_if)
00837 {
00838   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_i");
00839 
00840   int result = this->unsubscribe_ifs (mcast_addr,
00841                                       net_if);
00842 
00843   // Check for error or "short-circuit" return.
00844   if (result != 0)
00845     return result;
00846 
00847 #if defined (ACE_HAS_IPV6)
00848   if (mcast_addr.get_type () == AF_INET6)
00849     {
00850       // Validate addr/if specifications and create addr/if struct.
00851       ipv6_mreq  mreq;
00852       if (this->make_multicast_ifaddr6 (&mreq, mcast_addr, net_if) == -1)
00853         {
00854           return -1;
00855         }
00856       // Tell network device driver to stop reading datagrams with the
00857       // <mcast_addr>.
00858       else if (ACE_SOCK::set_option (IPPROTO_IPV6,
00859                                      IPV6_LEAVE_GROUP,
00860                                      &mreq,
00861                                      sizeof mreq) == -1)
00862         {
00863           return -1;
00864         }
00865 
00866     }
00867   else  // IPv4
00868     {
00869       // Validate addr/if specifications and create addr/if struct.
00870       ip_mreq  mreq;
00871       if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00872         {
00873           return -1;
00874         }
00875       // Tell network device driver to stop reading datagrams with the
00876       // <mcast_addr>.
00877       else if (ACE_SOCK::set_option (IPPROTO_IP,
00878                                      IP_DROP_MEMBERSHIP,
00879                                      &mreq,
00880                                  sizeof mreq) == -1)
00881         {
00882           return -1;
00883         }
00884 
00885     }
00886 #else
00887   // Validate addr/if specifications and create addr/if struct.
00888   ip_mreq  mreq;
00889   if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00890     {
00891       return -1;
00892     }
00893   // Tell network device driver to stop reading datagrams with the
00894   // <mcast_addr>.
00895   // Note, this is not IPv6 friendly...
00896   else if (ACE_SOCK::set_option (IPPROTO_IP,
00897                                  IP_DROP_MEMBERSHIP,
00898                                  &mreq,
00899                                  sizeof mreq) == -1)
00900     {
00901       return -1;
00902     }
00903 #endif /* ACE_HAS_IPV6 */
00904 
00905   return 0;
00906 }
00907 
00908 int
00909 ACE_SOCK_Dgram_Mcast::clear_subs_list (void)
00910 {
00911   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::clear_subs_list");
00912   int result = 0;
00913 
00914 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00915   ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
00916                             this->subscription_list_lock_, -1));
00917   subscription_list_iter_t iter (this->subscription_list_);
00918   for (; !iter.done (); /*Hack: Do _not_ ::advance after remove*/)
00919     {
00920       ip_mreq  *pm = iter.next ();
00921       iter.remove ();
00922       delete pm;
00923     }
00924 #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
00925   return result;
00926 }
00927 
00928 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Tue Feb 2 17:18:42 2010 for ACE by  doxygen 1.4.7