SOCK_Dgram_Mcast.cpp

Go to the documentation of this file.
00001 // SOCK_Dgram_Mcast.cpp,v 4.86 2006/03/14 21:15:49 sjiang Exp
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            "SOCK_Dgram_Mcast.cpp,v 4.86 2006/03/14 21:15:49 sjiang Exp")
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_LIB_TEXT ("<?>"));
00050       else
00051         {
00052           ACE_TCHAR *pc = ACE_OS::strrchr (ret_string, ACE_LIB_TEXT (':'));
00053           if (clip_portnum && pc)
00054             *pc = ACE_LIB_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_LIB_TEXT ("\nOptions: bindaddr=%s, nulliface=%s\n"),
00080               ACE_BIT_ENABLED (this->opts_, OPT_BINDADDR_YES) ?
00081                 ACE_LIB_TEXT ("<Bound>") : ACE_LIB_TEXT ("<Not Bound>"),
00082               ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL) ?
00083                 ACE_LIB_TEXT ("<All Ifaces>") : ACE_LIB_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_LIB_TEXT ("Send addr=%s iface=%s\n"),
00090               addr_string,
00091               this->send_net_if_ ? this->send_net_if_
00092                                  : ACE_LIB_TEXT ("<default>")));
00093 
00094   // Show list of subscribed addresses.
00095   ACE_DEBUG ((LM_DEBUG, ACE_LIB_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_LIB_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_LIB_TEXT ("<default>"));
00119 
00120       // Dump info.
00121       ACE_DEBUG ((LM_DEBUG,
00122                   ACE_LIB_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                                                   NULL,
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                                                   NULL,
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_LIB_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_LIB_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_LIB_TEXT ("Subscribed port# (%u) different than bound ")
00506                   ACE_LIB_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_LIB_TEXT ("Subscribed address (%s) different than ")
00529                   ACE_LIB_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   else
00606     {
00607       // Create multicast addr/if struct.
00608       if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00609         return -1;
00610       // Tell IP stack to pass messages sent to this group.
00611       else if (this->ACE_SOCK::set_option (IPPROTO_IP,
00612                                            IP_ADD_MEMBERSHIP,
00613                                            &mreq,
00614                                            sizeof mreq) == -1)
00615         return -1;
00616 
00617     }
00618 #else
00619   if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00620     return -1;
00621   // Tell IP stack to pass messages sent to this group.
00622   // Note, this is not IPv6 compliant.
00623   else if (this->ACE_SOCK::set_option (IPPROTO_IP,
00624                                        IP_ADD_MEMBERSHIP,
00625                                        &mreq,
00626                                        sizeof mreq) == -1)
00627     return -1;
00628 
00629 #endif /* ACE_HAS_IPV6 */
00630 
00631   return 0;
00632 }
00633 
00634 int
00635 ACE_SOCK_Dgram_Mcast::unsubscribe_ifs (const ACE_INET_Addr &mcast_addr,
00636                                        const ACE_TCHAR *net_if)
00637 {
00638   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_ifs");
00639 
00640 
00641   if (ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL)
00642       && net_if == 0)
00643     {
00644 #if defined (ACE_HAS_IPV6)
00645       if (mcast_addr.get_type () == AF_INET6)
00646         {
00647           size_t nr_unsubscribed = 0;
00648 # if defined(__linux__)
00649 
00650           struct if_nameindex *intf;
00651 
00652           intf = ACE_OS::if_nameindex ();
00653 
00654           if (intf == 0)
00655             return -1;
00656 
00657           int index = 0;
00658           while (intf[index].if_index != 0 || intf[index].if_name != 0)
00659             {
00660               if (this->leave (mcast_addr, ACE_TEXT_CHAR_TO_TCHAR(intf[index].if_name)) == 0)
00661                 ++nr_unsubscribed;
00662 
00663               ++index;
00664             }
00665 
00666           ACE_OS::if_freenameindex (intf);
00667 
00668 # elif defined (ACE_WIN32)
00669 
00670           IP_ADAPTER_ADDRESSES tmp_addrs;
00671           // Initial call to determine actual memory size needed
00672           DWORD dwRetVal;
00673           ULONG bufLen = 0;
00674           if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
00675                                                   0,
00676                                                   NULL,
00677                                                   &tmp_addrs,
00678                                                   &bufLen)) != ERROR_BUFFER_OVERFLOW)
00679             return -1; // With output bufferlength 0 this can't be right.
00680 
00681           // Get required output buffer and retrieve info for real.
00682           PIP_ADAPTER_ADDRESSES pAddrs;
00683           char *buf;
00684           ACE_NEW_RETURN (buf,
00685                           char[bufLen],
00686                           -1);
00687           pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
00688           if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
00689                                                   0,
00690                                                   NULL,
00691                                                   pAddrs,
00692                                                   &bufLen)) != NO_ERROR)
00693             {
00694               delete[] buf; // clean up
00695               return -1;
00696             }
00697 
00698           while (pAddrs)
00699             {
00700               if (this->leave (mcast_addr, ACE_TEXT_CHAR_TO_TCHAR(pAddrs->AdapterName)) == 0)
00701                 ++nr_unsubscribed;
00702 
00703               pAddrs = pAddrs->Next;
00704             }
00705 
00706           delete[] buf; // clean up
00707 
00708 # endif /* ACE_WIN32 */
00709 
00710           if (nr_unsubscribed == 0)
00711             {
00712               errno = ENODEV;
00713               return -1;
00714             }
00715 
00716           return 1;
00717 
00718 
00719         }
00720       else
00721         {
00722           // Unsubscribe on all local multicast-capable network interfaces, by
00723           // doing recursive calls with specific interfaces.
00724 
00725           ACE_INET_Addr *if_addrs = 0;
00726           size_t if_cnt;
00727 
00728           // NOTE - <get_ip_interfaces> doesn't always get all of the
00729           // interfaces.  In particular, it may not get a PPP interface.  This
00730           // is a limitation of the way <get_ip_interfaces> works with
00731           // old versions of MSVC.  The reliable way of getting the interface
00732           // list is available only with MSVC 5 and newer.
00733           if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
00734             return -1;
00735 
00736           size_t nr_unsubscribed = 0;
00737 
00738           if (if_cnt < 2)
00739             {
00740               if (this->leave (mcast_addr,
00741                                ACE_LIB_TEXT ("0.0.0.0")) == 0)
00742                 ++nr_unsubscribed;
00743             }
00744           else
00745             {
00746               while (if_cnt > 0)
00747                 {
00748                   --if_cnt;
00749                   // Convert to 0-based for indexing, next loop check
00750                   if (if_addrs[if_cnt].get_type () != AF_INET || if_addrs[if_cnt].is_loopback ())
00751                     continue;
00752                   if (this->leave (mcast_addr,
00753                                    ACE_TEXT_CHAR_TO_TCHAR
00754                                    (if_addrs[if_cnt].get_host_addr ())) == 0)
00755                     ++nr_unsubscribed;
00756                 }
00757             }
00758 
00759           delete [] if_addrs;
00760 
00761           if (nr_unsubscribed == 0)
00762             {
00763               errno = ENODEV;
00764               return -1;
00765             }
00766 
00767           return 1;
00768 
00769         }
00770 #else /* ACE_HAS_IPV6 */
00771       // Unsubscribe on all local multicast-capable network interfaces, by
00772       // doing recursive calls with specific interfaces.
00773 
00774       ACE_INET_Addr *if_addrs = 0;
00775       size_t if_cnt;
00776 
00777       // NOTE - <get_ip_interfaces> doesn't always get all of the
00778       // interfaces.  In particular, it may not get a PPP interface.  This
00779       // is a limitation of the way <get_ip_interfaces> works with
00780       // old versions of MSVC.  The reliable way of getting the interface list
00781       // is available only with MSVC 5 and newer.
00782       if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
00783         return -1;
00784 
00785       size_t nr_unsubscribed = 0;
00786 
00787       if (if_cnt < 2)
00788         {
00789           if (this->leave (mcast_addr,
00790                            ACE_LIB_TEXT ("0.0.0.0")) == 0)
00791             ++nr_unsubscribed;
00792         }
00793       else
00794         {
00795           while (if_cnt > 0)
00796             {
00797               --if_cnt;
00798               // Convert to 0-based for indexing, next loop check
00799               if (if_addrs[if_cnt].is_loopback ())
00800                 continue;
00801               if (this->leave (mcast_addr,
00802                                ACE_TEXT_CHAR_TO_TCHAR
00803                                (if_addrs[if_cnt].get_host_addr ())) == 0)
00804                 ++nr_unsubscribed;
00805             }
00806         }
00807 
00808       delete [] if_addrs;
00809 
00810       if (nr_unsubscribed == 0)
00811         {
00812           errno = ENODEV;
00813           return -1;
00814         }
00815 
00816       return 1;
00817 #endif /* !ACE_HAS_IPV6 */
00818     }
00819 
00820   return 0;
00821 }
00822 
00823 
00824 // Unsubscribe, and remove address from subscription list.
00825 // Note: If there are duplicate entries, only finds the first in the list (this
00826 // is a defined restriction - most environments don't allow duplicates to be
00827 // created.)
00828 int
00829 ACE_SOCK_Dgram_Mcast::unsubscribe (const ACE_INET_Addr &mcast_addr,
00830                                    const ACE_TCHAR *net_if,
00831                                    int protocol_family,
00832                                    int protocol)
00833 {
00834   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe");
00835 
00836   ACE_UNUSED_ARG (protocol_family);
00837   ACE_UNUSED_ARG (protocol);
00838 
00839   return this->leave (mcast_addr, net_if);
00840 }
00841 
00842 int
00843 ACE_SOCK_Dgram_Mcast::leave (const ACE_INET_Addr &mcast_addr,
00844                              const ACE_TCHAR *net_if)
00845 {
00846   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::leave");
00847   // Unsubscribe.
00848   int result = this->unsubscribe_i (mcast_addr,
00849                                     net_if);
00850 
00851 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00852   // (Unconditionally) Remove this addr/if from subscription list.
00853   // (Addr/if is removed even if unsubscribe failed)
00854   ip_mreq  tgt_mreq;
00855   if (this->make_multicast_ifaddr (&tgt_mreq,
00856                                    mcast_addr,
00857                                    net_if) != -1)
00858     {
00859       ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
00860                                 this->subscription_list_lock_, -1));
00861       subscription_list_iter_t iter (this->subscription_list_);
00862       for (; !iter.done (); iter.advance ())
00863         {
00864           ip_mreq  *pm = iter.next ();
00865           if (ACE_SDM_helpers::is_equal (*pm, tgt_mreq))
00866             {
00867               iter.remove ();
00868               delete pm;
00869               break;
00870             }
00871         }
00872     }
00873 #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
00874 
00875   return result >= 0 ? 0 : result;
00876 }
00877 
00878 // Attempt unsubscribe and return status.
00879 int
00880 ACE_SOCK_Dgram_Mcast::unsubscribe_i (const ACE_INET_Addr &mcast_addr,
00881                                      const ACE_TCHAR *net_if)
00882 {
00883   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_i");
00884 
00885   int result = this->unsubscribe_ifs (mcast_addr,
00886                                       net_if);
00887 
00888   // Check for error or "short-circuit" return.
00889   if (result != 0)
00890     return result;
00891 
00892 #if defined (ACE_HAS_IPV6)
00893   if (mcast_addr.get_type () == AF_INET6)
00894     {
00895       // Validate addr/if specifications and create addr/if struct.
00896       ipv6_mreq  mreq;
00897       if (this->make_multicast_ifaddr6 (&mreq, mcast_addr, net_if) == -1)
00898         {
00899           return -1;
00900         }
00901       // Tell network device driver to stop reading datagrams with the
00902       // <mcast_addr>.
00903       else if (ACE_SOCK::set_option (IPPROTO_IPV6,
00904                                      IPV6_LEAVE_GROUP,
00905                                      &mreq,
00906                                      sizeof mreq) == -1)
00907         {
00908           return -1;
00909         }
00910 
00911     }
00912   else  // IPv4
00913     {
00914       // Validate addr/if specifications and create addr/if struct.
00915       ip_mreq  mreq;
00916       if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00917         {
00918           return -1;
00919         }
00920       // Tell network device driver to stop reading datagrams with the
00921       // <mcast_addr>.
00922       else if (ACE_SOCK::set_option (IPPROTO_IP,
00923                                      IP_DROP_MEMBERSHIP,
00924                                      &mreq,
00925                                  sizeof mreq) == -1)
00926         {
00927           return -1;
00928         }
00929 
00930     }
00931 #else
00932   // Validate addr/if specifications and create addr/if struct.
00933   ip_mreq  mreq;
00934   if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00935     {
00936       return -1;
00937     }
00938   // Tell network device driver to stop reading datagrams with the
00939   // <mcast_addr>.
00940   // Note, this is not IPv6 friendly...
00941   else if (ACE_SOCK::set_option (IPPROTO_IP,
00942                                  IP_DROP_MEMBERSHIP,
00943                                  &mreq,
00944                                  sizeof mreq) == -1)
00945     {
00946       return -1;
00947     }
00948 #endif /* ACE_HAS_IPV6 */
00949 
00950   return 0;
00951 }
00952 
00953 int
00954 ACE_SOCK_Dgram_Mcast::unsubscribe (void)
00955 {
00956   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe");
00957 
00958   // Can't implement this reliably without keeping an expensive list,
00959   // and can't close the socket since the caller may want to continue
00960   // using the socket to send() or join() new groups.  Even if we
00961   // wanted to be clever and reopen the socket, we'd need to know what
00962   // options had been set, and reset them--and we have no way of doing
00963   // that either. :-(
00964   // Should this return -1?
00965   ACE_ERROR_RETURN ((LM_INFO,
00966                      ACE_LIB_TEXT ("ACE_SOCK_Dgram_Mcast::unsubscribe (void) ")
00967                      ACE_LIB_TEXT ("has been deprecated. You must either ")
00968                      ACE_LIB_TEXT ("close to socket to unsubscribe to all ")
00969                      ACE_LIB_TEXT ("or unsubscribe to each individually.\n")),
00970                      0);
00971 }
00972 
00973 int
00974 ACE_SOCK_Dgram_Mcast::clear_subs_list (void)
00975 {
00976   ACE_TRACE ("ACE_SOCK_Dgram_Mcast::clear_subs_list");
00977   int  result = 0;
00978 
00979 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00980   ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
00981                             this->subscription_list_lock_, -1));
00982   subscription_list_iter_t iter (this->subscription_list_);
00983   for (; !iter.done (); /*Hack: Do _not_ ::advance after remove*/)
00984     {
00985       ip_mreq  *pm = iter.next ();
00986       iter.remove ();
00987       delete pm;
00988     }
00989 #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
00990   return result;
00991 }
00992 
00993 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Thu Nov 9 09:42:04 2006 for ACE by doxygen 1.3.6