summaryrefslogtreecommitdiff
path: root/ace/SOCK_Dgram_Mcast.cpp
diff options
context:
space:
mode:
authorcrodrigu <crodrigu@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2002-06-25 23:25:58 +0000
committercrodrigu <crodrigu@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2002-06-25 23:25:58 +0000
commit116bf25582c26fb11871c8f8c541a06dfa7e21ac (patch)
treeb2b6ccbc35c6b96573750c74b1bdf2ad244c41ea /ace/SOCK_Dgram_Mcast.cpp
parent84053c2e2800d063f62fdb308cc24cb6839f02b4 (diff)
downloadATCD-116bf25582c26fb11871c8f8c541a06dfa7e21ac.tar.gz
ChangeLogTag: Tue Jun 25 23:22:09 UTC 2002 Craig Rodrigues <crodrigu@bbn.com>
Diffstat (limited to 'ace/SOCK_Dgram_Mcast.cpp')
-rw-r--r--ace/SOCK_Dgram_Mcast.cpp434
1 files changed, 413 insertions, 21 deletions
diff --git a/ace/SOCK_Dgram_Mcast.cpp b/ace/SOCK_Dgram_Mcast.cpp
index b812b3c6e8c..5261aa6122b 100644
--- a/ace/SOCK_Dgram_Mcast.cpp
+++ b/ace/SOCK_Dgram_Mcast.cpp
@@ -1,23 +1,415 @@
-/* $Id$ */
-/*
- * The legacy ACE_SOCK_Dgram_Mcast class is a specialization of the newer
- * ACE_SOCK_Dgram_Mcast_Ex templated class.
- *
- * This file is a vestige of the original class, which is only used to satisfy
- * automated build rules and to elicit environment-specific template support
- * behavior, if necessary.
- */
-
-// Build the "real" class files.
#include "ace/SOCK_Dgram_Mcast.h"
+#include "ace/INET_Addr.h"
+#include "ace/ACE.h"
-// Instantiate SOCK_Dgram_Mcast_Ex internal templates, if necessary.
-#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
-template class ACE_SOCK_Dgram_Mcast_Ex<ACE_SYNCH_MUTEX>;
-template class ACE_DLList_Iterator<ip_mreq>;
-template class ACE_DLList<ip_mreq>;
-#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
-#pragma instantiate ACE_SOCK_Dgram_Mcast_Ex<ACE_SYNCH_MUTEX>;
-#pragma instantiate ACE_DLList_Iterator<ip_mreq>
-#pragma instantiate ACE_DLList<ip_mreq>
-#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+#if defined (ACE_LACKS_INLINE_FUNCTIONS)
+#include "ace/SOCK_Dgram_Mcast.i"
+#endif /* ACE_LACKS_INLINE_FUNCTIONS */
+
+// This is a workaround for platforms with non-standard
+// definitions of the ip_mreq structure
+#if ! defined (IMR_MULTIADDR)
+#define IMR_MULTIADDR imr_multiaddr
+#endif /* ! defined (IMR_MULTIADDR) */
+
+ACE_RCSID (ace,
+ SOCK_Dgram_Mcast,
+ "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_SOCK_Dgram_Mcast)
+
+void
+ACE_SOCK_Dgram_Mcast::dump (void) const
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast::dump");
+}
+
+// Dummy default constructor...
+
+ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast (void)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast");
+}
+
+int
+ACE_SOCK_Dgram_Mcast::open (const ACE_Addr &mcast_addr,
+ int protocol_family,
+ int protocol,
+ int reuse_addr)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast::open");
+
+ // Make a copy of address to use in the <send> methods. Note: Sun
+ // C++ 4.2 needs the useless const_cast.
+ this->mcast_addr_.set (ACE_reinterpret_cast (const ACE_INET_Addr &,
+ ACE_const_cast (ACE_Addr &,
+ mcast_addr)));
+ // Only perform the <open> initialization if we haven't been opened
+ // earlier.
+ if (this->get_handle () == ACE_INVALID_HANDLE)
+ {
+ if (ACE_SOCK::open (SOCK_DGRAM,
+ protocol_family,
+ protocol,
+ reuse_addr) == -1)
+ return -1;
+
+ int one = 1;
+ if (reuse_addr
+ && this->ACE_SOCK::set_option (SOL_SOCKET,
+ SO_REUSEADDR,
+ &one,
+ sizeof one) == -1)
+ return -1;
+#if defined (SO_REUSEPORT)
+ else if (this->ACE_SOCK::set_option (SOL_SOCKET,
+ SO_REUSEPORT,
+ &one,
+ sizeof one) == -1)
+ return -1;
+#endif /* SO_REUSEPORT */
+
+ // Create an address to bind the socket to.
+ ACE_INET_Addr local;
+
+#if defined (linux)
+ local = this->mcast_addr_;
+#else /* linux */
+ if (local.set (this->mcast_addr_.get_port_number ()) == -1)
+ return -1;
+#endif /* linux */
+
+ if (ACE_SOCK_Dgram::shared_open (local,
+ protocol_family) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ACE_SOCK_Dgram_Mcast::subscribe_ifs (const ACE_INET_Addr &mcast_addr,
+ const ACE_TCHAR *net_if,
+ int protocol_family,
+ int protocol,
+ int reuse_addr)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_ifs");
+#if defined (ACE_WIN32)
+ // Windows NT's winsock has trouble with multicast subscribes in the
+ // presence of multiple network interfaces when the IP address is
+ // given as INADDR_ANY. It will pick the first interface and only
+ // accept mcast there. So, to work around this, cycle through all
+ // of the interfaces known and subscribe to all the non-loopback
+ // ones.
+ //
+ // Note that this only needs to be done on NT, but there's no way to
+ // tell at this point if the code will be running on NT - only if it
+ // is compiled for NT-only or for NT/95, and that doesn't really
+ // help us. It doesn't hurt to do this on Win95, it's just a little
+ // slower than it normally would be.
+ //
+ // NOTE - <ACE::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 <ACE::get_ip_interfaces> works with
+ // MSVC. The reliable way of getting the interface list is
+ // available only with MSVC 5.
+
+ if (net_if == 0)
+ {
+ 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->subscribe (mcast_addr,
+ reuse_addr,
+ ACE_LIB_TEXT ("0.0.0.0"),
+ protocol_family,
+ protocol) == 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_ip_address() == INADDR_LOOPBACK)
+ continue;
+ if (this->subscribe (mcast_addr,
+ reuse_addr,
+ ACE_TEXT_CHAR_TO_TCHAR
+ (if_addrs[if_cnt].get_host_addr()),
+ protocol_family,
+ protocol) == 0)
+ ++nr_subscribed;
+ }
+
+ delete [] if_addrs;
+
+ if (nr_subscribed == 0)
+ {
+ errno = ENODEV;
+ return -1;
+ }
+ else
+ // 1 indicates a "short-circuit" return. This handles the
+ // rather bizarre semantics of checking all the interfaces on
+ // NT.
+ return 1;
+ }
+#else
+ ACE_UNUSED_ARG (mcast_addr);
+ ACE_UNUSED_ARG (net_if);
+ ACE_UNUSED_ARG (protocol_family);
+ ACE_UNUSED_ARG (protocol);
+ ACE_UNUSED_ARG (reuse_addr);
+#endif /* ACE_WIN32 */
+ // Otherwise, do it like everyone else...
+
+ return 0;
+}
+
+int
+ACE_SOCK_Dgram_Mcast::subscribe (const ACE_INET_Addr &mcast_addr,
+ int reuse_addr,
+ const ACE_TCHAR *net_if,
+ int protocol_family,
+ int protocol)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe");
+
+ if (this->open (mcast_addr,
+ protocol_family,
+ protocol,
+ reuse_addr) == -1)
+ return -1;
+
+ int result = this->subscribe_ifs (mcast_addr,
+ net_if,
+ protocol_family,
+ protocol,
+ reuse_addr);
+ // Check for the "short-circuit" return value of 1 (for NT). This
+ // handles the rather bizarre semantics of checking all the
+ // interfaces on NT.
+ if (result != 0)
+ return result;
+
+ ip_mreq multicast_address;
+
+ // Create multicast request.
+ result = this->make_multicast_address_i (mcast_addr,
+ multicast_address,
+ net_if);
+ if (result != 0)
+ return result;
+
+ // Tell network device driver to read datagrams with a
+ // multicast_address IP interface.
+ result = this->ACE_SOCK::set_option (IPPROTO_IP,
+ IP_ADD_MEMBERSHIP,
+ &multicast_address,
+ sizeof multicast_address);
+ if (result != 0)
+ return result;
+
+ // Set the <mcast_request_if_> field. This is mostly a convenience
+ // for applications that subscribe to a single multicast group,
+ // using the internal field allows them to simply call the
+ // unsubscribe() operation.
+ // Notice that such applications are using a non-reentrant interface
+ // of the class, and thus should use proper synchronization for it.
+ this->mcast_request_if_ = multicast_address;
+
+ return 0;
+}
+
+int
+ACE_SOCK_Dgram_Mcast::unsubscribe_ifs (const ACE_INET_Addr &mcast_addr,
+ const ACE_TCHAR *net_if,
+ int protocol_family,
+ int protocol)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_ifs");
+#if defined (ACE_WIN32)
+ // Windows NT's winsock has trouble with multicast subscribes in the
+ // presence of multiple network interfaces when the IP address is
+ // given as INADDR_ANY. It will pick the first interface and only
+ // accept mcast there. So, to work around this, cycle through all
+ // of the interfaces known and subscribe to all the non-loopback
+ // ones.
+ //
+ // Note that this only needs to be done on NT, but there's no way to
+ // tell at this point if the code will be running on NT - only if it
+ // is compiled for NT-only or for NT/95, and that doesn't really
+ // help us. It doesn't hurt to do this on Win95, it's just a little
+ // slower than it normally would be.
+ //
+ // NOTE - <ACE::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 <ACE::get_ip_interfaces> works with
+ // MSVC. The reliable way of getting the interface list is
+ // available only with MSVC 5.
+
+ if (net_if == 0)
+ {
+ 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_unsubscribed = 0;
+
+ if (if_cnt < 2)
+ {
+ if (this->unsubscribe (mcast_addr,
+ ACE_LIB_TEXT ("0.0.0.0"),
+ protocol_family,
+ protocol) == 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_ip_address() == INADDR_LOOPBACK)
+ continue;
+ if (this->unsubscribe (mcast_addr,
+ ACE_TEXT_CHAR_TO_TCHAR
+ (if_addrs[if_cnt].get_host_addr()),
+ protocol_family,
+ protocol) == 0)
+ ++nr_unsubscribed;
+ }
+
+ delete [] if_addrs;
+
+ if (nr_unsubscribed == 0)
+ {
+ errno = ENODEV;
+ return -1;
+ }
+
+ return 1;
+ }
+#else
+ ACE_UNUSED_ARG (mcast_addr);
+ ACE_UNUSED_ARG (net_if);
+ ACE_UNUSED_ARG (protocol_family);
+ ACE_UNUSED_ARG (protocol);
+#endif /* ACE_WIN32 */
+
+ return 0;
+}
+
+int
+ACE_SOCK_Dgram_Mcast::unsubscribe (const ACE_INET_Addr &mcast_addr,
+ const ACE_TCHAR *net_if,
+ int protocol_family,
+ int protocol)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe");
+ int result = this->unsubscribe_ifs (mcast_addr,
+ net_if,
+ protocol_family,
+ protocol);
+
+ // Check for the "short-circuit" return value of 1 (for NT).
+ if (result != 0)
+ return result;
+
+ // Otherwise, do it like everyone else.
+
+ ip_mreq multicast_address;
+
+ // Create multicast request.
+ result = this->make_multicast_address_i (mcast_addr,
+ multicast_address,
+ net_if);
+ if (result != 0)
+ return result;
+
+ // Tell network device driver to stop reading datagrams with the
+ // <mcast_addr>.
+ return ACE_SOCK::set_option (IPPROTO_IP,
+ IP_DROP_MEMBERSHIP,
+ &multicast_address,
+ sizeof multicast_address);
+}
+
+int
+ACE_SOCK_Dgram_Mcast::unsubscribe (void)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe");
+ return this->ACE_SOCK::set_option (IPPROTO_IP,
+ IP_DROP_MEMBERSHIP,
+ &this->mcast_request_if_,
+ sizeof this->mcast_request_if_);
+}
+
+int
+ACE_SOCK_Dgram_Mcast::make_multicast_address_i (const ACE_INET_Addr &mcast_addr,
+ ip_mreq &multicast_address ,
+ const ACE_TCHAR *net_if)
+{
+ if (net_if != 0)
+ {
+#if defined (ACE_WIN32)
+ // This port number is not necessary, just convenient
+ ACE_INET_Addr interface_addr;
+ if (interface_addr.set (mcast_addr.get_port_number (),
+ net_if) == -1)
+ return -1;
+ multicast_address.imr_interface.s_addr =
+ htonl (interface_addr.get_ip_address ());
+#else
+ ifreq if_address;
+
+#if defined (ACE_PSOS)
+ // Look up the interface by number, not name.
+ if_address.ifr_ifno = ACE_OS::atoi (net_if);
+#else
+ ACE_OS::strcpy (if_address.ifr_name, net_if);
+#endif /* defined (ACE_PSOS) */
+
+ if (ACE_OS::ioctl (this->get_handle (),
+ SIOCGIFADDR,
+ &if_address) == -1)
+ return -1;
+
+ sockaddr_in *socket_address;
+ socket_address = ACE_reinterpret_cast(sockaddr_in *,
+ &if_address.ifr_addr);
+ multicast_address.imr_interface.s_addr = socket_address->sin_addr.s_addr;
+#endif /* ACE_WIN32 */
+ }
+ else
+ multicast_address.imr_interface.s_addr = INADDR_ANY;
+
+ multicast_address.IMR_MULTIADDR.s_addr = htonl (mcast_addr.get_ip_address ());
+ return 0;
+}
+
+int
+ACE_SOCK_Dgram_Mcast::make_multicast_address (const ACE_INET_Addr &mcast_addr,
+ const ACE_TCHAR *net_if)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast::make_multicast_address");
+
+ return this->make_multicast_address_i (mcast_addr,
+ this->mcast_request_if_,
+ net_if );
+}