Defines the ACE socket wrapper for UDP/IP multicast. More...
#include <SOCK_Dgram_Mcast.h>
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_TCHAR * | send_net_if_ |
Network interface to which all <send> methods send multicast datagrams. |
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.
Option parameters.
These control per-instance optional functionality. They are set via optional constructor arguments.
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 };
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 (); }
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.
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; }
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.
int ACE_SOCK_Dgram_Mcast::opts_ [private] |
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.
ACE_TCHAR* ACE_SOCK_Dgram_Mcast::send_net_if_ [private] |
Network interface to which all <send> methods send multicast datagrams.
Definition at line 363 of file SOCK_Dgram_Mcast.h.