summaryrefslogtreecommitdiff
path: root/ACE/ace/QoS/SOCK_Dgram_Mcast_QoS.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/ace/QoS/SOCK_Dgram_Mcast_QoS.cpp')
-rw-r--r--ACE/ace/QoS/SOCK_Dgram_Mcast_QoS.cpp258
1 files changed, 258 insertions, 0 deletions
diff --git a/ACE/ace/QoS/SOCK_Dgram_Mcast_QoS.cpp b/ACE/ace/QoS/SOCK_Dgram_Mcast_QoS.cpp
new file mode 100644
index 00000000000..548c56bef12
--- /dev/null
+++ b/ACE/ace/QoS/SOCK_Dgram_Mcast_QoS.cpp
@@ -0,0 +1,258 @@
+// $Id$
+
+#include "SOCK_Dgram_Mcast_QoS.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_sys_socket.h"
+
+#if defined (ACE_WIN32)
+#include "ace/Sock_Connect.h" // needed for subscribe_ifs()
+#endif /* ACE_WIN32 */
+
+#if !defined (__ACE_INLINE__)
+#include "SOCK_Dgram_Mcast_QoS.i"
+#endif /* __ACE_INLINE__ */
+
+// 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 (QoS,
+ SOCK_Dgram_Mcast_QoS,
+ "$Id$")
+
+ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+
+ACE_ALLOC_HOOK_DEFINE(ACE_SOCK_Dgram_Mcast_QoS)
+
+// Dummy default constructor...
+
+ACE_SOCK_Dgram_Mcast_QoS::ACE_SOCK_Dgram_Mcast_QoS (options opts)
+ : ACE_SOCK_Dgram_Mcast (opts)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast_QoS::ACE_SOCK_Dgram_Mcast_QoS");
+}
+
+int
+ACE_SOCK_Dgram_Mcast_QoS::open (const ACE_INET_Addr &addr,
+ const ACE_QoS_Params &qos_params,
+ int protocol_family,
+ int protocol,
+ ACE_Protocol_Info *protocolinfo,
+ ACE_SOCK_GROUP g,
+ u_long flags,
+ int reuse_addr)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast_QoS::open");
+
+ ACE_UNUSED_ARG (qos_params);
+
+ // Only perform the <open> initialization if we haven't been opened
+ // earlier.
+ if (this->get_handle () != ACE_INVALID_HANDLE)
+ return 0;
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Get Handle Returns Invalid Handle\n"));
+
+ if (ACE_SOCK::open (SOCK_DGRAM,
+ protocol_family,
+ protocol,
+ protocolinfo,
+ g,
+ flags,
+ reuse_addr) == -1)
+ return -1;
+
+ return this->open_i (addr, 0, reuse_addr);
+}
+
+
+int
+ACE_SOCK_Dgram_Mcast_QoS::subscribe_ifs (const ACE_INET_Addr &mcast_addr,
+ const ACE_QoS_Params &qos_params,
+ const ACE_TCHAR *net_if,
+ int protocol_family,
+ int protocol,
+ int reuse_addr,
+ ACE_Protocol_Info *protocolinfo)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast_QoS::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_Sock_Connect::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_Sock_Connect::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,
+ qos_params,
+ reuse_addr,
+ ACE_LIB_TEXT ("0.0.0.0"),
+ protocol_family,
+ protocol,
+ protocolinfo) == 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,
+ qos_params,
+ reuse_addr,
+ ACE_TEXT_CHAR_TO_TCHAR
+ (if_addrs[if_cnt].get_host_addr()),
+ protocol_family,
+ protocol,
+ protocolinfo) == 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 (qos_params);
+ ACE_UNUSED_ARG (protocol_family);
+ ACE_UNUSED_ARG (protocol);
+ ACE_UNUSED_ARG (reuse_addr);
+ ACE_UNUSED_ARG (protocolinfo);
+#endif /* ACE_WIN32 */
+ // Otherwise, do it like everyone else...
+
+ // Create multicast request.
+ if (this->make_multicast_ifaddr (0,
+ mcast_addr,
+ net_if) == -1)
+ return -1;
+ else
+ return 0;
+}
+
+int
+ACE_SOCK_Dgram_Mcast_QoS::subscribe (const ACE_INET_Addr &mcast_addr,
+ const ACE_QoS_Params &qos_params,
+ int reuse_addr,
+ const ACE_TCHAR *net_if,
+ int protocol_family,
+ int protocol,
+ ACE_Protocol_Info *protocolinfo,
+ ACE_SOCK_GROUP g,
+ u_long flags,
+ ACE_QoS_Session *qos_session)
+{
+ ACE_TRACE ("ACE_SOCK_Dgram_Mcast_QoS::subscribe");
+
+ if (this->open (mcast_addr,
+ qos_params,
+ protocol_family,
+ protocol,
+ protocolinfo,
+ g,
+ flags,
+ reuse_addr) == -1)
+ return -1;
+
+ // The following method call only applies to Win32 currently.
+ int result = this->subscribe_ifs (mcast_addr,
+ qos_params,
+ net_if,
+ protocol_family,
+ protocol,
+ reuse_addr,
+ protocolinfo);
+ // Check for the "short-circuit" return value of 1 (for NT).
+ if (result != 0)
+ return result;
+
+ // Tell network device driver to read datagrams with a
+ // <mcast_request_if_> IP interface.
+ else
+ {
+ // Check if the mcast_addr passed into this method is the
+ // same as the QoS session address.
+ if (qos_session != 0 && mcast_addr == qos_session->dest_addr ())
+ {
+ // Subscribe to the QoS session.
+ if (this->qos_manager_.join_qos_session (qos_session) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Unable to join QoS Session\n")),
+ -1);
+ }
+ else
+ {
+ if (this->close () != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("Unable to close socket\n")));
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Dest Addr in the QoS Session does")
+ ACE_LIB_TEXT (" not match the address passed into")
+ ACE_LIB_TEXT (" subscribe\n")),
+ -1);
+ }
+
+ ip_mreq ret_mreq;
+ this->make_multicast_ifaddr (&ret_mreq, mcast_addr, net_if);
+
+ // XX This is windows stuff only. fredk
+ if (ACE_OS::join_leaf (this->get_handle (),
+ reinterpret_cast<const sockaddr *> (&ret_mreq.IMR_MULTIADDR.s_addr),
+ sizeof ret_mreq.IMR_MULTIADDR.s_addr,
+ qos_params) == ACE_INVALID_HANDLE
+ && errno != ENOTSUP)
+ return -1;
+
+ else
+ if (qos_params.socket_qos () != 0 && qos_session != 0)
+ qos_session->qos (*(qos_params.socket_qos ()));
+
+ return 0;
+ }
+}
+
+ACE_END_VERSIONED_NAMESPACE_DECL