Public Types | Public Member Functions | Public Attributes | Protected Member Functions | Private Member Functions | Private Attributes

ACE_SOCK_Dgram_Mcast Class Reference

Defines the ACE socket wrapper for UDP/IP multicast. More...

#include <SOCK_Dgram_Mcast.h>

Inheritance diagram for ACE_SOCK_Dgram_Mcast:
Inheritance graph
[legend]
Collaboration diagram for ACE_SOCK_Dgram_Mcast:
Collaboration graph
[legend]

List of all members.

Public Types

enum  options {
  OPT_BINDADDR_NO = 0, OPT_BINDADDR_YES = 1, DEFOPT_BINDADDR = OPT_BINDADDR_NO, OPT_NULLIFACE_ONE = 0,
  OPT_NULLIFACE_ALL = 2, DEFOPT_NULLIFACE = OPT_NULLIFACE_ONE, DEFOPTS = DEFOPT_BINDADDR | DEFOPT_NULLIFACE
}
 

Option parameters.

More...

Public Member Functions

 ACE_SOCK_Dgram_Mcast (options opts=DEFOPTS)
 ~ACE_SOCK_Dgram_Mcast (void)
int open (const ACE_INET_Addr &mcast_addr, const ACE_TCHAR *net_if=0, int reuse_addr=1)
int join (const ACE_INET_Addr &mcast_addr, int reuse_addr=1, const ACE_TCHAR *net_if=0)
int leave (const ACE_INET_Addr &mcast_addr, const ACE_TCHAR *net_if=0)
ssize_t send (const void *buf, size_t n, int flags=0) const
ssize_t send (const iovec iov[], int n, int flags=0) const
int set_option (int option, char optval)
 Set a socket option.
void dump (void) const
 Dump the state of an object.

Public Attributes

 ACE_ALLOC_HOOK_DECLARE
 Declare the dynamic allocation hooks.

Protected Member Functions

int open_i (const ACE_INET_Addr &mcast_addr, const ACE_TCHAR *net_if=0, int reuse_addr=1)
int clear_subs_list (void)
 Empty the dynamic subscription list.

Private Member Functions

int subscribe_ifs (const ACE_INET_Addr &mcast_addr, const ACE_TCHAR *net_if, int reuse_addr)
int subscribe_i (const ACE_INET_Addr &mcast_addr, int reuse_addr=1, const ACE_TCHAR *net_if=0)
 Do subscription processing w/out updating the subscription list.
int unsubscribe_ifs (const ACE_INET_Addr &mcast_addr, const ACE_TCHAR *net_if=0)
 Unsubscribe from a multicast address on one or more network interface(s).
int unsubscribe_i (const ACE_INET_Addr &mcast_addr, const ACE_TCHAR *net_if=0)
 Do unsubscription processing w/out udpating subscription list.

Private Attributes

int opts_
 Per-instance options..
ACE_INET_Addr send_addr_
 Multicast address to which local <send> methods send datagrams.
ACE_TCHARsend_net_if_
 Network interface to which all <send> methods send multicast datagrams.

Detailed Description

Defines the ACE socket wrapper for UDP/IP multicast.

Supports multiple simultaneous subscriptions, unsubscription from one or all subscriptions, and independent send/recv address and interface specifications. Template parameters and/or ctor arguments determine per-instance optional functionality.

Note that multicast semantics and implementation details are _very_ environment-specific; this class is just a wrapper around the underlying implementation and does not try to normalize the concept of multicast communications.

Usage Notes:

Interface specification notes (for <subscribe> and <unsubscribe>):

Definition at line 94 of file SOCK_Dgram_Mcast.h.


Member Enumeration Documentation

Option parameters.

These control per-instance optional functionality. They are set via optional constructor arguments.

Note:
Certain option values are not valid for all environments (see comments in source file for environment-specific restrictions). Default values are always valid values for the compilation environment.
Enumerator:
OPT_BINDADDR_NO 

Disable address bind. (Bind only port.).

OPT_BINDADDR_YES 

Enable address bind. (Bind port and address.).

DEFOPT_BINDADDR 

Default value for BINDADDR option. (Environment-dependent.).

OPT_NULLIFACE_ONE 

Define the interpretation of 'NULL' as a recv interface specification.

If (net_if==NULL), use default interface.

OPT_NULLIFACE_ALL 

If (net_if==NULL), use all mcast interfaces.

DEFOPT_NULLIFACE 

Default value for NULLIFACE option. (Environment-dependent.).

DEFOPTS 

All default options.

Definition at line 107 of file SOCK_Dgram_Mcast.h.

  {
  // Define whether a specific (multicast) address (in addition to the port#)
  // is bound to the socket.
  // Notes:
  // - Effect of doing this is stack/environment dependent, but in most
  //   environments can be used to filter out unwanted unicast, broadcast, and
  //   (other) multicast messages sent to the same port#.
  // - Some IP stacks (e.g. some Win32) do not support binding multicast
  //   addresses.  Using this option will always cause an <open> error.
  // - It's not strictly possible for user code to do this level of filtering
  //   w/out the bind; some environments support ways to determine which address
  //   a message was sent _to_, but this class interface does not support access
  //   to that info.
  // - The address (and port#) passed to <open> (or the first <subscribe>, if
  //   <open> is not explicitly invoked) is the one that is bound.
  //
    /// Disable address bind. (Bind only port.)
    // Note that this might seem odd, but we need a way to distinquish between
    // default behavior, which might or might not be to bind, and explicitely
    // choosing to bind or not to bind--which "is the question." ;-)
    OPT_BINDADDR_NO   = 0,
    /// Enable address bind. (Bind port and address.)
    OPT_BINDADDR_YES   = 1,
    /// Default value for BINDADDR option. (Environment-dependent.)
#if defined (ACE_LACKS_PERFECT_MULTICAST_FILTERING) \
    && (ACE_LACKS_PERFECT_MULTICAST_FILTERING == 1)
      // Platforms that don't support perfect filtering. Note that perfect
      // filtering only really applies to multicast traffic, not unicast
      // or broadcast.
      DEFOPT_BINDADDR  = OPT_BINDADDR_YES,
# else
      // At least some Win32 OS's can not bind mcast addr, so disable it.
      // General-purpose default behavior is 'disabled', since effect is
      // environment-specific and side-effects might be surprising.
      DEFOPT_BINDADDR  = OPT_BINDADDR_NO,
#endif /* ACE_LACKS_PERFECT_MULTICAST_FILTERING = 1) */
  //
  /// Define the interpretation of 'NULL' as a recv interface specification.
  // If the interface part of a multicast address specification is NULL, it
  // will be interpreted to mean either "the default interface" or "all
  // interfaces", depending on the setting of this option.
  // Notes:
  // - The 'nulliface_all' option can not be used in environments which do
  //   not fully support the <ACE_Sock_Connect::get_ip_interfaces> method
  //   (e.g. non-Windows).
  //   If it is, using NULL for iface will _always_ fail.
  // - The default behavior in most IP stacks is to use the 'default' interface,
  //   where 'default' has rather ad-hoc semantics.
  // - This applies only to receives, not sends (which always use only one
  //   interface; NULL means use the "system default" interface).
  // Supported values:
    /// If (net_if==NULL), use default interface.
    // Note that this might seem odd, but we need a way to distinquish between
    // default behavior, which might or might not be to bind, and explicitely
    // choosing to bind or not to bind--which "is the question." ;-)
    OPT_NULLIFACE_ONE  = 0,
    /// If (net_if==NULL), use all mcast interfaces.
    OPT_NULLIFACE_ALL  = 2,
    /// Default value for NULLIFACE option. (Environment-dependent.)
#ifdef ACE_WIN32
      // This is the (ad-hoc) legacy behavior for Win32/WinSock.
      // Notice: Older version of WinSock/MSVC may not get all multicast-capable
      // interfaces (e.g. PPP interfaces).
      DEFOPT_NULLIFACE = OPT_NULLIFACE_ALL,
#else
      // General-purpose default behavior (as per legacy behavior).
      DEFOPT_NULLIFACE = OPT_NULLIFACE_ONE,
#endif /* ACE_WIN32 */
    /// All default options.
    DEFOPTS = DEFOPT_BINDADDR | DEFOPT_NULLIFACE
  };


Constructor & Destructor Documentation

ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast ( ACE_SOCK_Dgram_Mcast::options  opts = DEFOPTS  ) 

Ctor - Create an unitialized instance and define per-instance optional functionality. You must invoke <open> or <subscribe>, to create/bind a socket and define operational parameters, before performing any I/O with this instance.

Definition at line 133 of file SOCK_Dgram_Mcast.cpp.

  :  opts_ (opts),
     send_net_if_ (0)
{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast");
}

ACE_SOCK_Dgram_Mcast::~ACE_SOCK_Dgram_Mcast ( void   ) 

Dtor - Release all resources and implicitly or explicitly unsubscribe from all currently subscribed groups. The OPT_DTORUNSUB_YES_ option defines whether an explicit <unsusbcribe> is done by the destructor. If not, most systems will automatically unsubscribe upon the close of the socket.

Definition at line 141 of file SOCK_Dgram_Mcast.cpp.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::~ACE_SOCK_Dgram_Mcast");

  // Free memory and optionally unsubscribe from currently subscribed group(s).
  delete [] this->send_net_if_;
  this->clear_subs_list ();
}


Member Function Documentation

int ACE_SOCK_Dgram_Mcast::clear_subs_list ( void   )  [protected]

Empty the dynamic subscription list.

Definition at line 913 of file SOCK_Dgram_Mcast.cpp.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::clear_subs_list");
  int result = 0;

#if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
  ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
                            this->subscription_list_lock_, -1));
  subscription_list_iter_t iter (this->subscription_list_);
  for (; !iter.done (); /*Hack: Do _not_ ::advance after remove*/)
    {
      ip_mreq  *pm = iter.next ();
      iter.remove ();
      delete pm;
    }
#endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
  return result;
}

void ACE_SOCK_Dgram_Mcast::dump ( void   )  const

Dump the state of an object.

Logs the setting of all options, the bound address, the send address and interface, and the list of current subscriptions.

Reimplemented from ACE_SOCK_Dgram.

Definition at line 68 of file SOCK_Dgram_Mcast.cpp.

{
#if defined (ACE_HAS_DUMP)
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::dump");

  ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));

# if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
  ACE_TCHAR addr_string[MAXNAMELEN + 1];

  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("\nOptions: bindaddr=%s, nulliface=%s\n"),
              ACE_BIT_ENABLED (this->opts_, OPT_BINDADDR_YES) ?
                ACE_TEXT ("<Bound>") : ACE_TEXT ("<Not Bound>"),
              ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL) ?
                ACE_TEXT ("<All Ifaces>") : ACE_TEXT ("<Default Iface>")));

  // Show default send addr, port#, and interface.
  ACE_SDM_helpers::addr_to_string (this->send_addr_, addr_string,
                                   sizeof addr_string, 0);
  ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT ("Send addr=%s iface=%s\n"),
              addr_string,
              this->send_net_if_ ? this->send_net_if_
                                 : ACE_TEXT ("<default>")));

  // Show list of subscribed addresses.
  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Subscription list:\n")));

  ACE_MT (ACE_GUARD (ACE_SDM_LOCK, guard, this->subscription_list_lock_));
  subscription_list_iter_t  iter (this->subscription_list_);
  for ( ; !iter.done (); iter.advance ())
    {
      ACE_TCHAR iface_string[MAXNAMELEN + 1];
      ip_mreq *pm = iter.next ();

      // Get subscribed address (w/out port# info - not relevant).
      ACE_INET_Addr ip_addr (static_cast<u_short> (0),
                             ACE_NTOHL (pm->IMR_MULTIADDR.s_addr));
      ACE_SDM_helpers::addr_to_string (ip_addr, addr_string,
                                       sizeof addr_string, 1);

      // Get interface address/specification.
      ACE_INET_Addr if_addr (static_cast<u_short> (0),
                             ACE_NTOHL (pm->imr_interface.s_addr));
      ACE_SDM_helpers::addr_to_string (if_addr, iface_string,
                                       sizeof iface_string, 1);
      if (ACE_OS::strcmp (iface_string, ACE_TEXT ("0.0.0.0")) == 0)
        // Receives on system default iface. (Note that null_iface_opt_
        // option processing has already occurred.)
        ACE_OS::strcpy (iface_string, ACE_TEXT ("<default>"));

      // Dump info.
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("\taddr=%s iface=%s\n"),
                  addr_string,
                  iface_string));
    }
# endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
  ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
#endif /* ACE_HAS_DUMP */
}

int ACE_SOCK_Dgram_Mcast::join ( const ACE_INET_Addr mcast_addr,
int  reuse_addr = 1,
const ACE_TCHAR net_if = 0 
)

Join a multicast group on a given interface (or all interfaces, if supported). The given group is joined on the specified interface. If option OPT_NULLIFACE_ALL is used and <net_if> is = 0, the group is joined on all multicast capable interfaces (IFF supported). Multiple subscriptions to various address and interface combinations are supported and tracked. If this is the first invocation of <subscribe>, and <open> was not previously invoked, <open> will be invoked using <mcast_addr> for binding the socket and <net_if> as the interface for <send>.

Returns: -1 if the call fails. Failure can occur due to problems with the address, port#, and/or interface parameters or during the subscription attempt. Once bind() has been invoked (by the first <open> or <subscribe>), returns errno of ENXIO if the port# is not 0 and does not match the bound port#, or if OPT_BINDADDR_YES option is used and the address does not match the bound address. Returns errno of ENODEV if the addr/port#/interface parameters appeared valid, but no subscription(s) succeeded. An error is unconditionally returned if option OPT_NULLIFACE_ALL is used, <net_if> is NULL, and <ACE_Sock_Connect::get_ip_interfaces> is not implemented in this environment.

Note that the optional reuse_addr parameter does not apply to subscriptions; it is only used if <open> is implicitly invoked (see above).

Uses the mcast_addr to determine protocol_family, and protocol which we always pass as 0 anyway.

Definition at line 468 of file SOCK_Dgram_Mcast.cpp.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::join");
  ACE_INET_Addr subscribe_addr = mcast_addr;

  // If port# is 0, insert bound port# if it is set. (To satisfy lower-level
  // port# validation.)
  u_short def_port_number = this->send_addr_.get_port_number ();
  if (subscribe_addr.get_port_number () == 0
      && def_port_number != 0)
    {
      subscribe_addr.set_port_number (def_port_number);
    }

  // Check for port# different than bound port#.
  u_short sub_port_number = mcast_addr.get_port_number ();
  if (sub_port_number != 0
      && def_port_number != 0
      && sub_port_number != def_port_number)
    {
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Subscribed port# (%u) different than bound ")
                  ACE_TEXT ("port# (%u).\n"),
                  (u_int) sub_port_number,
                  (u_int) def_port_number));
      errno = ENXIO;
      return -1;
    }

  // If bind_addr_opt_ is enabled, check for address different than
  // bound address.
  ACE_INET_Addr tmp_addr (this->send_addr_);
  tmp_addr.set_port_number (mcast_addr.get_port_number ()); // force equal port numbers
  if (ACE_BIT_ENABLED (this->opts_, OPT_BINDADDR_YES)
      && !this->send_addr_.is_any ()
      && this->send_addr_ != mcast_addr)
    {
      ACE_TCHAR sub_addr_string[MAXNAMELEN + 1];
      ACE_TCHAR bound_addr_string[MAXNAMELEN + 1];
      ACE_SDM_helpers::addr_to_string (mcast_addr, sub_addr_string,
                                       sizeof sub_addr_string, 1);
      ACE_SDM_helpers::addr_to_string (this->send_addr_, bound_addr_string,
                                       sizeof bound_addr_string, 1);
      ACE_ERROR ((LM_ERROR,
                  ACE_TEXT ("Subscribed address (%s) different than ")
                  ACE_TEXT ("bound address (%s).\n"),
                  sub_addr_string,
                  bound_addr_string));
      errno = ENXIO;
      return -1;
    }

  // Attempt subscription.
  int result = this->subscribe_i (subscribe_addr, reuse_addr, net_if);

#if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
  if (result == 0)
    {
      // Add this addr/iface info to the list of subscriptions.
      // (Assumes this is unique addr/iface combo - most systems don't allow
      // re-sub to same addr/iface.)
      ip_mreq  *pmreq = new ip_mreq;
      // (should not fail)
      if (this->make_multicast_ifaddr (pmreq, subscribe_addr, net_if) != -1)
        {
          ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
                                    this->subscription_list_lock_, -1));
          this->subscription_list_.insert_tail (pmreq);
          return 0;
        }
      // this still isn't really right. If ACE_GUARD_RETURN fails, we leak.
      // Need to add one of Chris' fancy ace auto pointers (bound?).
      delete pmreq;
    }
#endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */

  return result >= 0 ? 0 : result;
}

int ACE_SOCK_Dgram_Mcast::leave ( const ACE_INET_Addr mcast_addr,
const ACE_TCHAR net_if = 0 
)

Leave a multicast group on a given interface (or all interfaces, if supported). The specified group/interface combination is unsubscribed. If option OPT_NULLIFACE_ALL is used and <net_if> is = 0, the group is unsubscribed from all interfaces (IFF supported).

Returns: -1 if the unsubscribe failed. Most environments will return -1 if there was no active subscription for this address/interface combination. An error is unconditionally returned if option OPT_NULLIFACE_ALL is used, <net_if> is = 0, and <ACE_Sock_Connect::get_ip_interfaces> is not implemented in this environment (_even if_ the <subscribe> specifies a non- NULL <net_if>).

leave() replaces unsubscribe() and uses mcast_addr to determine protocol_family, and protocol which we always pass as 0 anyway.

Definition at line 802 of file SOCK_Dgram_Mcast.cpp.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::leave");
  // Unsubscribe.
  int result = this->unsubscribe_i (mcast_addr,
                                    net_if);

#if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
  // (Unconditionally) Remove this addr/if from subscription list.
  // (Addr/if is removed even if unsubscribe failed)
  ip_mreq  tgt_mreq;
  if (this->make_multicast_ifaddr (&tgt_mreq,
                                   mcast_addr,
                                   net_if) != -1)
    {
      ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
                                this->subscription_list_lock_, -1));
      subscription_list_iter_t iter (this->subscription_list_);
      for (; !iter.done (); iter.advance ())
        {
          ip_mreq  *pm = iter.next ();
          if (ACE_SDM_helpers::is_equal (*pm, tgt_mreq))
            {
              iter.remove ();
              delete pm;
              break;
            }
        }
    }
#endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */

  return result >= 0 ? 0 : result;
}

int ACE_SOCK_Dgram_Mcast::open ( const ACE_INET_Addr mcast_addr,
const ACE_TCHAR net_if = 0,
int  reuse_addr = 1 
)

Explicitly open/bind the socket and define the network interface and default multicast address used for sending messages. This method is optional; if not explicitly invoked, it is invoked by the first <subscribe>, using the subscribed address/port# and network interface parameters. The <mcast_addr> parameter defines the default send address/port# and also the port# and, if the OPT_BINDADDR_YES option is used, the multicast address that is bound to this socket. If the <send_net_if> parameter != 0, it defines the network interface used for all sends by this instance, otherwise the system "default" interface is used. (The <send_net_if> parameter is ignored if this feature is not supported by the envriornment.) The port# in <mcast_addr> may be 0, in which case a system-assigned (ephemeral) port# is used for sending and receiving. If reuse_addr != 0, the SO_REUSEADDR option and, if it is supported, the SO_REUSEPORT option are enabled.

Returns: -1 if the call fails. Failure can occur due to problems with the address, port#, and/or interface parameters or during system open() or socket option processing.

Definition at line 151 of file SOCK_Dgram_Mcast.cpp.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::open");

  // Only perform the <open> initialization if we haven't been opened
  // earlier.
  // No sanity check?  We should probably flag an error if the user
  // makes multiple calls to open().
  if (this->get_handle () != ACE_INVALID_HANDLE)
    return 0;

  // Invoke lower-layer ::open.
  if (ACE_SOCK::open (SOCK_DGRAM,
                      mcast_addr.get_type (),
                      0, // always use 0
                      reuse_addr) == -1)
    return -1;

  return this->open_i (mcast_addr, net_if, reuse_addr);
}

int ACE_SOCK_Dgram_Mcast::open_i ( const ACE_INET_Addr mcast_addr,
const ACE_TCHAR net_if = 0,
int  reuse_addr = 1 
) [protected]

Contains common open functionality so that inheriting classes can reuse it.

Definition at line 175 of file SOCK_Dgram_Mcast.cpp.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::open_i");
  // ACE_SOCK::open calls this if reuse_addr is set, so we only need to
  // process port reuse option.
  if (reuse_addr)
    {
#if defined (SO_REUSEPORT)
      int one = 1;
      if (this->ACE_SOCK::set_option (SOL_SOCKET,
                                      SO_REUSEPORT,
                                      &one,
                                      sizeof one) == -1)
        return -1;
#endif /* SO_REUSEPORT */
    }

  // Create an address/port# to bind the socket to. Use mcast_addr to
  // initialize bind_addy to pick up the correct protocol family. If
  // OPT_BINDADDR_YES is set, then we're done. Else use mcast_addr's
  // port number and use the "any" address.
  ACE_INET_Addr bind_addy (mcast_addr);
  if (ACE_BIT_DISABLED (this->opts_, OPT_BINDADDR_YES))
    {
#if defined (ACE_HAS_IPV6)
      if (mcast_addr.get_type () == PF_INET6)
        {
          if (bind_addy.set (mcast_addr.get_port_number (), "::",
                             1, AF_INET6) == -1)
            return -1;
        }
      else
        // Bind to "any" address and explicit port#.
        if (bind_addy.set (mcast_addr.get_port_number ()) == -1)
          return -1;
#else
      // Bind to "any" address and explicit port#.
      if (bind_addy.set (mcast_addr.get_port_number ()) == -1)
        return -1;
#endif /* ACE_HAS_IPV6 */
    }

  // Bind to the address (which may be INADDR_ANY) and port# (which may be 0)
  if (ACE_SOCK_Dgram::shared_open (bind_addy, bind_addy.get_type ()) == -1)
    return -1;

  // Cache the actual bound address (which may be INADDR_ANY)
  // and the actual bound port# (which will be a valid, non-zero port#).
  ACE_INET_Addr bound_addy;
  if (this->get_local_addr (bound_addy) == -1)
    {
      // (Unexpected failure - should be bound to something)
      if (bound_addy.set (bind_addy) == -1)
        {
          // (Shouldn't happen - bind_addy is a valid addy; punt.)
          return -1;
        }
    }

  this->send_addr_ = mcast_addr;
  this->send_addr_.set_port_number (bound_addy.get_port_number ());
  if (net_if)
    {
      if (this->set_nic (net_if, mcast_addr.get_type ()))
        return -1;

      this->send_net_if_ = new ACE_TCHAR[ACE_OS::strlen (net_if) + 1];
      ACE_OS::strcpy (this->send_net_if_, net_if);
    }

  return 0;
}

ssize_t ACE_SOCK_Dgram_Mcast::send ( const void *  buf,
size_t  n,
int  flags = 0 
) const

Send n bytes in buf, using the multicast address and network interface defined by the first <open> or <subscribe>.

Definition at line 29 of file SOCK_Dgram_Mcast.inl.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::send");
  return this->ACE_SOCK_Dgram::send (buf,
                                     n,
                                     this->send_addr_,
                                     flags);
}

ssize_t ACE_SOCK_Dgram_Mcast::send ( const iovec  iov[],
int  n,
int  flags = 0 
) const

Send n <iovecs>, using the multicast address and network interface defined by the first <open> or <subscribe>.

Definition at line 41 of file SOCK_Dgram_Mcast.inl.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::send");
  return this->ACE_SOCK_Dgram::send (iov,
                                     n,
                                     this->send_addr_,
                                     flags);
}

int ACE_SOCK_Dgram_Mcast::set_option ( int  option,
char  optval 
)

Set a socket option.

Set an IP option that takes a char as input, such as IP_MULTICAST_LOOP or IP_MULTICAST_TTL. This is just a more concise, nice interface to a subset of possible ACE_SOCK::set_option calls, but only works for IPPROTO_IP or IPPROTO_IPV6 level options.

Returns 0 on success, -1 on failure.

Deprecated:
This method has been deprecated since it cannot be used easily with with IPv6 options. Use ACE_SOCK::set_option instead.

Definition at line 8 of file SOCK_Dgram_Mcast.inl.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::set_option");

  if (this->get_handle () == ACE_INVALID_HANDLE)
    return -1;

  int level = IPPROTO_IP;
#if defined (IPPROTO_IPV6) && ! defined (INTEGRITY)
  if (this->send_addr_.get_type () == PF_INET6)
    level = IPPROTO_IPV6;
#endif /* IPPROTO_IPV6 */

  return this->ACE_SOCK::set_option (level,
                                     option,
                                     &optval,
                                     sizeof (optval));
}

int ACE_SOCK_Dgram_Mcast::subscribe_i ( const ACE_INET_Addr mcast_addr,
int  reuse_addr = 1,
const ACE_TCHAR net_if = 0 
) [private]

Do subscription processing w/out updating the subscription list.

Definition at line 551 of file SOCK_Dgram_Mcast.cpp.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_i");
  ip_mreq  mreq;
#if defined (ACE_HAS_IPV6)
  ipv6_mreq mreq6;
#endif /* __linux__ && ACE_HAS_IPV6 */

  // Open the socket IFF this is the first ::subscribe and ::open
  // was not explicitly invoked.
  if (this->open (mcast_addr,
                  net_if,
                  reuse_addr) == -1)
    return -1;

  // Only do this if net_if == 0, i.e., INADDR_ANY
  if (net_if == 0)
    {
      int result = this->subscribe_ifs (mcast_addr,
                                        net_if,
                                        reuse_addr);
      // Check for error or "short-circuit" return.
      if (result != 0)
        return result;
    }

#if defined (ACE_HAS_IPV6)
  if (mcast_addr.get_type () == AF_INET6)
    {
      if (this->make_multicast_ifaddr6 (&mreq6, mcast_addr, net_if) == -1)
        return -1;
      // Tell IP stack to pass messages sent to this group.
      else if (this->ACE_SOCK::set_option (IPPROTO_IPV6,
                                           IPV6_JOIN_GROUP,
                                           &mreq6,
                                           sizeof mreq6) == -1)
        return -1;

      return 0;
    }
  // Fall through for IPv4 case
#endif /* ACE_HAS_IPV6 */

  // Create multicast addr/if struct.
  if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
    return -1;
  // Tell IP stack to pass messages sent to this group.
  else if (this->ACE_SOCK::set_option (IPPROTO_IP,
                                       IP_ADD_MEMBERSHIP,
                                       &mreq,
                                       sizeof mreq) == -1)
    return -1;

  return 0;
}

int ACE_SOCK_Dgram_Mcast::subscribe_ifs ( const ACE_INET_Addr mcast_addr,
const ACE_TCHAR net_if,
int  reuse_addr 
) [private]

Subscribe to a multicast address on one or more network interface(s). (No QoS support.)

Definition at line 251 of file SOCK_Dgram_Mcast.cpp.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_ifs");

  if (ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL)
      && net_if == 0)
    {
#if defined (ACE_HAS_IPV6)
      if (mcast_addr.get_type () == AF_INET6)
        {
          size_t nr_subscribed = 0;
# if defined(__linux__)
          struct if_nameindex *intf;

          intf = ACE_OS::if_nameindex ();

          if (intf == 0)
            return -1;

          int index = 0;
          while (intf[index].if_index != 0 || intf[index].if_name != 0)
            {
              if (this->join (mcast_addr, reuse_addr,
                              ACE_TEXT_CHAR_TO_TCHAR(intf[index].if_name)) == 0)
                ++nr_subscribed;

              ++index;
            }

          ACE_OS::if_freenameindex (intf);

# elif defined (ACE_WIN32)

          IP_ADAPTER_ADDRESSES tmp_addrs;
          // Initial call to determine actual memory size needed
          DWORD dwRetVal;
          ULONG bufLen = 0;
          if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
                                                  0,
                                                  0,
                                                  &tmp_addrs,
                                                  &bufLen)) != ERROR_BUFFER_OVERFLOW)
            return -1; // With output bufferlength 0 this can't be right.

          // Get required output buffer and retrieve info for real.
          PIP_ADAPTER_ADDRESSES pAddrs;
          char *buf;
          ACE_NEW_RETURN (buf,
                          char[bufLen],
                          -1);
          pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
          if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
                                                  0,
                                                  0,
                                                  pAddrs,
                                                  &bufLen)) != NO_ERROR)
            {
              delete[] buf; // clean up
              return -1;
            }

          while (pAddrs)
            {
              if (this->join (mcast_addr, reuse_addr,
                              ACE_TEXT_CHAR_TO_TCHAR(pAddrs->AdapterName)) == 0)
                ++nr_subscribed;

              pAddrs = pAddrs->Next;
            }

          delete[] buf; // clean up

# endif /* ACE_WIN32 */

          if (nr_subscribed == 0)
            {
              errno = ENODEV;
              return -1;
            }

          return 1;
        }
      else
        {
          // Subscribe on all local multicast-capable network interfaces, by
          // doing recursive calls with specific interfaces.

          ACE_INET_Addr *if_addrs = 0;
          size_t if_cnt;

          if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
            return -1;

          size_t nr_subscribed = 0;

          if (if_cnt < 2)
            {
              if (this->join (mcast_addr,
                              reuse_addr,
                              ACE_TEXT ("0.0.0.0")) == 0)
                ++nr_subscribed;
            }
          else
            {
              // Iterate through all the interfaces, figure out which ones
              // offer multicast service, and subscribe to them.
              while (if_cnt > 0)
                {
                  --if_cnt;

                  // Convert to 0-based for indexing, next loop check.
                  if (if_addrs[if_cnt].get_type () != AF_INET || if_addrs[if_cnt].is_loopback ())
                    continue;
                  char addr_buf[INET6_ADDRSTRLEN];
                  if (this->join (mcast_addr,
                                  reuse_addr,
                                  ACE_TEXT_CHAR_TO_TCHAR
                                   (if_addrs[if_cnt].get_host_addr (addr_buf, INET6_ADDRSTRLEN))) == 0)
                    ++nr_subscribed;
                }
            }

          delete [] if_addrs;

          if (nr_subscribed == 0)
            {
              errno = ENODEV;
              return -1;
            }

          // 1 indicates a "short-circuit" return.  This handles the
          // recursive behavior of checking all the interfaces.
          return 1;

        }
#else
      // Subscribe on all local multicast-capable network interfaces, by
      // doing recursive calls with specific interfaces.

      ACE_INET_Addr *if_addrs = 0;
      size_t if_cnt;

      if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
        return -1;

      size_t nr_subscribed = 0;

      if (if_cnt < 2)
        {
          if (this->join (mcast_addr,
                          reuse_addr,
                          ACE_TEXT ("0.0.0.0")) == 0)
            ++nr_subscribed;
        }
      else
        {
          // Iterate through all the interfaces, figure out which ones
          // offer multicast service, and subscribe to them.
          while (if_cnt > 0)
            {
              --if_cnt;

              // Convert to 0-based for indexing, next loop check.
              if (if_addrs[if_cnt].is_loopback ())
                continue;
              char addr_buf[INET6_ADDRSTRLEN];
              if (this->join (mcast_addr,
                              reuse_addr,
                              ACE_TEXT_CHAR_TO_TCHAR
                                     (if_addrs[if_cnt].get_host_addr (addr_buf, INET6_ADDRSTRLEN))) == 0)
                ++nr_subscribed;
            }
        }

      delete [] if_addrs;

      if (nr_subscribed == 0)
        {
          errno = ENODEV;
          return -1;
        }

      // 1 indicates a "short-circuit" return.  This handles the
      // recursive behavior of checking all the interfaces.
      return 1;
#endif /* ACE_HAS_IPV6 */
    }

#if defined (ACE_HAS_IPV6)
  if (mcast_addr.get_type () == AF_INET6)
    {
      if (this->make_multicast_ifaddr6 (0, mcast_addr, net_if) == -1)
        return -1;
    }
  else
    {
      // Validate passed multicast addr and iface specifications.
      if (this->make_multicast_ifaddr (0,
                                       mcast_addr,
                                       net_if) == -1)
        return -1;
    }
#else
    // Validate passed multicast addr and iface specifications.
    if (this->make_multicast_ifaddr (0,
                                     mcast_addr,
                                     net_if) == -1)
      return -1;
#endif /* ACE_HAS_IPV6 */

  return 0;

}

int ACE_SOCK_Dgram_Mcast::unsubscribe_i ( const ACE_INET_Addr mcast_addr,
const ACE_TCHAR net_if = 0 
) [private]

Do unsubscription processing w/out udpating subscription list.

Definition at line 839 of file SOCK_Dgram_Mcast.cpp.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_i");

  int result = this->unsubscribe_ifs (mcast_addr,
                                      net_if);

  // Check for error or "short-circuit" return.
  if (result != 0)
    return result;

#if defined (ACE_HAS_IPV6)
  if (mcast_addr.get_type () == AF_INET6)
    {
      // Validate addr/if specifications and create addr/if struct.
      ipv6_mreq  mreq;
      if (this->make_multicast_ifaddr6 (&mreq, mcast_addr, net_if) == -1)
        {
          return -1;
        }
      // Tell network device driver to stop reading datagrams with the
      // <mcast_addr>.
      else if (ACE_SOCK::set_option (IPPROTO_IPV6,
                                     IPV6_LEAVE_GROUP,
                                     &mreq,
                                     sizeof mreq) == -1)
        {
          return -1;
        }

    }
  else  // IPv4
    {
      // Validate addr/if specifications and create addr/if struct.
      ip_mreq  mreq;
      if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
        {
          return -1;
        }
      // Tell network device driver to stop reading datagrams with the
      // <mcast_addr>.
      else if (ACE_SOCK::set_option (IPPROTO_IP,
                                     IP_DROP_MEMBERSHIP,
                                     &mreq,
                                 sizeof mreq) == -1)
        {
          return -1;
        }

    }
#else
  // Validate addr/if specifications and create addr/if struct.
  ip_mreq  mreq;
  if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
    {
      return -1;
    }
  // Tell network device driver to stop reading datagrams with the
  // <mcast_addr>.
  // Note, this is not IPv6 friendly...
  else if (ACE_SOCK::set_option (IPPROTO_IP,
                                 IP_DROP_MEMBERSHIP,
                                 &mreq,
                                 sizeof mreq) == -1)
    {
      return -1;
    }
#endif /* ACE_HAS_IPV6 */

  return 0;
}

int ACE_SOCK_Dgram_Mcast::unsubscribe_ifs ( const ACE_INET_Addr mcast_addr,
const ACE_TCHAR net_if = 0 
) [private]

Unsubscribe from a multicast address on one or more network interface(s).

Definition at line 610 of file SOCK_Dgram_Mcast.cpp.

{
  ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_ifs");


  if (ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL)
      && net_if == 0)
    {
#if defined (ACE_HAS_IPV6)
      if (mcast_addr.get_type () == AF_INET6)
        {
          size_t nr_unsubscribed = 0;
# if defined(__linux__)

          struct if_nameindex *intf;

          intf = ACE_OS::if_nameindex ();

          if (intf == 0)
            return -1;

          int index = 0;
          while (intf[index].if_index != 0 || intf[index].if_name != 0)
            {
              if (this->leave (mcast_addr, ACE_TEXT_CHAR_TO_TCHAR(intf[index].if_name)) == 0)
                ++nr_unsubscribed;

              ++index;
            }

          ACE_OS::if_freenameindex (intf);

# elif defined (ACE_WIN32)

          IP_ADAPTER_ADDRESSES tmp_addrs;
          // Initial call to determine actual memory size needed
          DWORD dwRetVal;
          ULONG bufLen = 0;
          if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
                                                  0,
                                                  0,
                                                  &tmp_addrs,
                                                  &bufLen)) != ERROR_BUFFER_OVERFLOW)
            return -1; // With output bufferlength 0 this can't be right.

          // Get required output buffer and retrieve info for real.
          PIP_ADAPTER_ADDRESSES pAddrs;
          char *buf;
          ACE_NEW_RETURN (buf,
                          char[bufLen],
                          -1);
          pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
          if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
                                                  0,
                                                  0,
                                                  pAddrs,
                                                  &bufLen)) != NO_ERROR)
            {
              delete[] buf; // clean up
              return -1;
            }

          while (pAddrs)
            {
              if (this->leave (mcast_addr, ACE_TEXT_CHAR_TO_TCHAR(pAddrs->AdapterName)) == 0)
                ++nr_unsubscribed;

              pAddrs = pAddrs->Next;
            }

          delete[] buf; // clean up

# endif /* ACE_WIN32 */

          if (nr_unsubscribed == 0)
            {
              errno = ENODEV;
              return -1;
            }

          return 1;


        }
      else
        {
          // Unsubscribe on all local multicast-capable network interfaces, by
          // doing recursive calls with specific interfaces.

          ACE_INET_Addr *if_addrs = 0;
          size_t if_cnt;

          // NOTE - <get_ip_interfaces> doesn't always get all of the
          // interfaces.  In particular, it may not get a PPP interface.  This
          // is a limitation of the way <get_ip_interfaces> works with
          // old versions of MSVC.  The reliable way of getting the interface
          // list is available only with MSVC 5 and newer.
          if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
            return -1;

          size_t nr_unsubscribed = 0;

          if (if_cnt < 2)
            {
              if (this->leave (mcast_addr,
                               ACE_TEXT ("0.0.0.0")) == 0)
                ++nr_unsubscribed;
            }
          else
            {
              while (if_cnt > 0)
                {
                  --if_cnt;
                  // Convert to 0-based for indexing, next loop check
                  if (if_addrs[if_cnt].get_type () != AF_INET || if_addrs[if_cnt].is_loopback ())
                    continue;
                  char addr_buf[INET6_ADDRSTRLEN];
                  if (this->leave (mcast_addr,
                                   ACE_TEXT_CHAR_TO_TCHAR
                                   (if_addrs[if_cnt].get_host_addr (addr_buf, INET6_ADDRSTRLEN))) == 0)
                    ++nr_unsubscribed;
                }
            }

          delete [] if_addrs;

          if (nr_unsubscribed == 0)
            {
              errno = ENODEV;
              return -1;
            }

          return 1;

        }
#else /* ACE_HAS_IPV6 */
      // Unsubscribe on all local multicast-capable network interfaces, by
      // doing recursive calls with specific interfaces.

      ACE_INET_Addr *if_addrs = 0;
      size_t if_cnt;

      // NOTE - <get_ip_interfaces> doesn't always get all of the
      // interfaces.  In particular, it may not get a PPP interface.  This
      // is a limitation of the way <get_ip_interfaces> works with
      // old versions of MSVC.  The reliable way of getting the interface list
      // is available only with MSVC 5 and newer.
      if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
        return -1;

      size_t nr_unsubscribed = 0;

      if (if_cnt < 2)
        {
          if (this->leave (mcast_addr,
                           ACE_TEXT ("0.0.0.0")) == 0)
            ++nr_unsubscribed;
        }
      else
        {
          while (if_cnt > 0)
            {
              --if_cnt;
              // Convert to 0-based for indexing, next loop check
              if (if_addrs[if_cnt].is_loopback ())
                continue;
              char addr_buf[INET6_ADDRSTRLEN];
              if (this->leave (mcast_addr,
                               ACE_TEXT_CHAR_TO_TCHAR
                               (if_addrs[if_cnt].get_host_addr (addr_buf, INET6_ADDRSTRLEN))) == 0)
                ++nr_unsubscribed;
            }
        }

      delete [] if_addrs;

      if (nr_unsubscribed == 0)
        {
          errno = ENODEV;
          return -1;
        }

      return 1;
#endif /* !ACE_HAS_IPV6 */
    }

  return 0;
}


Member Data Documentation

Declare the dynamic allocation hooks.

Reimplemented from ACE_SOCK_Dgram.

Reimplemented in ACE_SOCK_Dgram_Mcast_QoS.

Definition at line 319 of file SOCK_Dgram_Mcast.h.

Per-instance options..

Definition at line 358 of file SOCK_Dgram_Mcast.h.

Multicast address to which local <send> methods send datagrams.

Definition at line 361 of file SOCK_Dgram_Mcast.h.

Network interface to which all <send> methods send multicast datagrams.

Definition at line 363 of file SOCK_Dgram_Mcast.h.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines