1 #include "ace/SOCK_Dgram_Mcast.h"
3 #include "ace/OS_Memory.h"
4 #include "ace/OS_NS_string.h"
5 #include "ace/OS_NS_errno.h"
6 #include "ace/os_include/net/os_if.h"
7 #include "ace/os_include/arpa/os_inet.h"
8 #if defined (ACE_HAS_ALLOC_HOOKS)
9 # include "ace/Malloc_Base.h"
10 #endif /* ACE_HAS_ALLOC_HOOKS */
12 #if defined (ACE_LINUX) && defined (ACE_HAS_IPV6)
13 #include "ace/OS_NS_sys_socket.h"
16 #if defined (ACE_WIN32)
17 #include /**/ <iphlpapi.h>
20 #if defined (ACE_HAS_GETIFADDRS)
21 # if defined (ACE_VXWORKS) && (ACE_VXWORKS < 0x700)
22 # include /**/ <net/ifaddrs.h>
24 # include /**/ <ifaddrs.h>
25 # endif /*ACE_VXWORKS */
26 #endif /* ACE_HAS_GETIFADDRS */
28 #if !defined (__ACE_INLINE__)
29 #include "ace/SOCK_Dgram_Mcast.inl"
30 #endif /* __ACE_INLINE__ */
32 #include "ace/Log_Category.h"
34 // This is a workaround for platforms with non-standard
35 // definitions of the ip_mreq structure
36 #if ! defined (IMR_MULTIADDR)
37 #define IMR_MULTIADDR imr_multiaddr
38 #endif /* ! defined (IMR_MULTIADDR) */
40 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
42 // Helper (inline) functions.
46 // Convert ACE_INET_Addr to string, using local formatting rules.
48 static void addr_to_string (const ACE_INET_Addr
&ip_addr
,
49 ACE_TCHAR
*ret_string
, // results here.
51 int clip_portnum
) // clip port# info?
53 if (ip_addr
.addr_to_string (ret_string
, len
, 1) == -1)
54 ACE_OS::strcpy (ret_string
, ACE_TEXT ("<?>"));
57 ACE_TCHAR
*pc
= ACE_OS::strrchr (ret_string
, ACE_TEXT (':'));
58 if (clip_portnum
&& pc
)
59 *pc
= ACE_TEXT ('\0'); // clip port# info.
62 // op== for ip_mreq structs.
63 static int is_equal (const ip_mreq
&m1
, const ip_mreq
&m2
)
65 return m1
.IMR_MULTIADDR
.s_addr
== m2
.IMR_MULTIADDR
.s_addr
66 && m1
.imr_interface
.s_addr
== m2
.imr_interface
.s_addr
;
70 ACE_ALLOC_HOOK_DEFINE (ACE_SOCK_Dgram_Mcast
)
73 ACE_SOCK_Dgram_Mcast::dump () const
75 #if defined (ACE_HAS_DUMP)
76 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::dump");
78 ACELIB_DEBUG ((LM_DEBUG
, ACE_BEGIN_DUMP
, this));
80 # if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
81 ACE_TCHAR addr_string
[MAXNAMELEN
+ 1];
83 ACELIB_DEBUG ((LM_DEBUG
,
84 ACE_TEXT ("\nOptions: bindaddr=%s, nulliface=%s\n"),
85 ACE_BIT_ENABLED (this->opts_
, OPT_BINDADDR_YES
) ?
86 ACE_TEXT ("<Bound>") : ACE_TEXT ("<Not Bound>"),
87 ACE_BIT_ENABLED (this->opts_
, OPT_NULLIFACE_ALL
) ?
88 ACE_TEXT ("<All Ifaces>") : ACE_TEXT ("<Default Iface>")));
90 // Show default send addr, port#, and interface.
91 ACE_SDM_helpers::addr_to_string (this->send_addr_
, addr_string
,
92 sizeof addr_string
, 0);
93 ACELIB_DEBUG ((LM_DEBUG
,
94 ACE_TEXT ("Send addr=%s iface=%s\n"),
96 this->send_net_if_
? this->send_net_if_
97 : ACE_TEXT ("<default>")));
99 // Show list of subscribed addresses.
100 ACELIB_DEBUG ((LM_DEBUG
, ACE_TEXT ("Subscription list:\n")));
102 ACE_MT (ACE_GUARD (ACE_SDM_LOCK
, guard
, this->subscription_list_lock_
));
103 subscription_list_iter_t
iter (this->subscription_list_
);
104 for ( ; !iter
.done (); iter
.advance ())
106 ACE_TCHAR iface_string
[MAXNAMELEN
+ 1];
107 ip_mreq
*pm
= iter
.next ();
109 // Get subscribed address (w/out port# info - not relevant).
110 ACE_INET_Addr
ip_addr (static_cast<u_short
> (0),
111 ACE_NTOHL (pm
->IMR_MULTIADDR
.s_addr
));
112 ACE_SDM_helpers::addr_to_string (ip_addr
, addr_string
,
113 sizeof addr_string
, 1);
115 // Get interface address/specification.
116 ACE_INET_Addr
if_addr (static_cast<u_short
> (0),
117 ACE_NTOHL (pm
->imr_interface
.s_addr
));
118 ACE_SDM_helpers::addr_to_string (if_addr
, iface_string
,
119 sizeof iface_string
, 1);
120 if (ACE_OS::strcmp (iface_string
, ACE_TEXT ("0.0.0.0")) == 0)
121 // Receives on system default iface. (Note that null_iface_opt_
122 // option processing has already occurred.)
123 ACE_OS::strcpy (iface_string
, ACE_TEXT ("<default>"));
126 ACELIB_DEBUG ((LM_DEBUG
,
127 ACE_TEXT ("\taddr=%s iface=%s\n"),
131 # endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
132 ACELIB_DEBUG ((LM_DEBUG
, ACE_END_DUMP
));
133 #endif /* ACE_HAS_DUMP */
137 ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast
138 (ACE_SOCK_Dgram_Mcast::options opts
)
142 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast");
146 ACE_SOCK_Dgram_Mcast::~ACE_SOCK_Dgram_Mcast ()
148 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::~ACE_SOCK_Dgram_Mcast");
150 // Free memory and optionally unsubscribe from currently subscribed group(s).
151 #if defined (ACE_HAS_ALLOC_HOOKS)
152 ACE_Allocator::instance()->free(this->send_net_if_
);
154 delete [] this->send_net_if_
;
155 #endif /* ACE_HAS_ALLOC_HOOKS */
156 this->clear_subs_list ();
160 ACE_SOCK_Dgram_Mcast::open (const ACE_INET_Addr
&mcast_addr
,
161 const ACE_TCHAR
*net_if
,
164 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::open");
166 // Only perform the <open> initialization if we haven't been opened
168 // No sanity check? We should probably flag an error if the user
169 // makes multiple calls to open().
170 if (this->get_handle () != ACE_INVALID_HANDLE
)
173 // Invoke lower-layer ::open.
174 if (ACE_SOCK::open (SOCK_DGRAM
,
175 mcast_addr
.get_type (),
180 return this->open_i (mcast_addr
, net_if
, reuse_addr
);
184 ACE_SOCK_Dgram_Mcast::open_i (const ACE_INET_Addr
&mcast_addr
,
185 const ACE_TCHAR
*net_if
,
188 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::open_i");
189 // ACE_SOCK::open calls this if reuse_addr is set, so we only need to
190 // process port reuse option.
193 #if defined (SO_REUSEPORT)
195 if (this->ACE_SOCK::set_option (SOL_SOCKET
,
200 #endif /* SO_REUSEPORT */
203 // Create an address/port# to bind the socket to. Use mcast_addr to
204 // initialize bind_addy to pick up the correct protocol family. If
205 // OPT_BINDADDR_YES is set, then we're done. Else use mcast_addr's
206 // port number and use the "any" address.
207 ACE_INET_Addr
bind_addy (mcast_addr
);
208 if (ACE_BIT_DISABLED (this->opts_
, OPT_BINDADDR_YES
))
210 #if defined (ACE_HAS_IPV6)
211 if (mcast_addr
.get_type () == PF_INET6
)
213 if (bind_addy
.set (mcast_addr
.get_port_number (), "::",
218 // Bind to "any" address and explicit port#.
219 if (bind_addy
.set (mcast_addr
.get_port_number ()) == -1)
222 // Bind to "any" address and explicit port#.
223 if (bind_addy
.set (mcast_addr
.get_port_number ()) == -1)
225 #endif /* ACE_HAS_IPV6 */
228 // Bind to the address (which may be INADDR_ANY) and port# (which may be 0)
229 if (ACE_SOCK_Dgram::shared_open (bind_addy
, bind_addy
.get_type ()) == -1)
232 // Cache the actual bound address (which may be INADDR_ANY)
233 // and the actual bound port# (which will be a valid, non-zero port#).
234 ACE_INET_Addr bound_addy
;
235 if (this->get_local_addr (bound_addy
) == -1)
237 // (Unexpected failure - should be bound to something)
238 if (bound_addy
.set (bind_addy
) == -1)
240 // (Shouldn't happen - bind_addy is a valid addy; punt.)
245 this->send_addr_
= mcast_addr
;
246 this->send_addr_
.set_port_number (bound_addy
.get_port_number ());
249 if (this->set_nic (net_if
, mcast_addr
.get_type ()))
251 #if defined (ACE_HAS_ALLOC_HOOKS)
252 this->send_net_if_
= static_cast<ACE_TCHAR
*>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR
) * (ACE_OS::strlen (net_if
) + 1)));
254 this->send_net_if_
= new ACE_TCHAR
[ACE_OS::strlen (net_if
) + 1];
255 #endif /* ACE_HAS_ALLOC_HOOKS */
256 ACE_OS::strcpy (this->send_net_if_
, net_if
);
263 ACE_SOCK_Dgram_Mcast::subscribe_ifs (const ACE_INET_Addr
&mcast_addr
,
264 const ACE_TCHAR
*net_if
,
267 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_ifs");
269 if (ACE_BIT_ENABLED (this->opts_
, OPT_NULLIFACE_ALL
)
272 int family
= mcast_addr
.get_type ();
273 size_t nr_subscribed
= 0;
275 #if defined (ACE_HAS_GETIFADDRS)
277 // Take advantage of the BSD getifaddrs function that simplifies
278 // access to connected interfaces.
279 struct ifaddrs
*ifap
= 0;
280 struct ifaddrs
*p_if
= 0;
282 if (::getifaddrs (&ifap
) != 0)
285 // Not every interface is for IP, and not all are up and multicast.
288 p_if
= p_if
->ifa_next
)
290 // Some OSes can return interfaces with no ifa_addr if the
291 // interface has no assigned address.
292 // If there is an address but it's not the family we want, ignore it.
293 if (p_if
->ifa_addr
== 0 || p_if
->ifa_addr
->sa_family
!= family
)
296 // Check to see if it's up and supports multicast.
297 unsigned int wanted
= IFF_UP
| IFF_MULTICAST
;
298 if ((p_if
->ifa_flags
& wanted
) != wanted
)
301 // Sometimes the kernel returns 0.0.0.0 as the interface
302 // address, skip those...
303 if (p_if
->ifa_addr
->sa_family
== PF_INET
)
305 struct sockaddr_in
*addr
=
306 reinterpret_cast<sockaddr_in
*> (p_if
->ifa_addr
);
308 if (addr
->sin_addr
.s_addr
== INADDR_ANY
)
311 # if defined (ACE_HAS_IPV6)
312 else if (p_if
->ifa_addr
->sa_family
== AF_INET6
)
314 struct sockaddr_in6
*addr
=
315 reinterpret_cast<sockaddr_in6
*> (p_if
->ifa_addr
);
317 // Skip the ANY address
318 if (IN6_IS_ADDR_UNSPECIFIED(&addr
->sin6_addr
))
321 # endif /* ACE_HAS_IPV6 */
323 // Ok, now join on this interface.
324 if (this->join (mcast_addr
,
326 ACE_TEXT_CHAR_TO_TCHAR(p_if
->ifa_name
)) == 0)
330 ::freeifaddrs (ifap
);
332 # elif defined (ACE_WIN32)
334 IP_ADAPTER_ADDRESSES tmp_addrs
;
335 // Initial call to determine actual memory size needed
338 // Note... GetAdaptersAddresses returns different bufLen values depending
339 // on how many multicast joins there are on the system. To avoid this,
340 // specify that we don't want to know about multicast addresses. This
341 // does not avoid multicastable interfaces and makes the size-check
342 // more reliable across varying conditions.
343 DWORD flags
= GAA_FLAG_SKIP_MULTICAST
;
344 if ((dwRetVal
= ::GetAdaptersAddresses (family
,
348 &bufLen
)) != ERROR_BUFFER_OVERFLOW
)
351 return -1; // With output bufferlength 0 this can't be right.
354 // Get required output buffer and retrieve info for real.
355 PIP_ADAPTER_ADDRESSES pAddrs
;
360 pAddrs
= reinterpret_cast<PIP_ADAPTER_ADDRESSES
> (buf
);
361 if ((dwRetVal
= ::GetAdaptersAddresses (family
,
365 &bufLen
)) != NO_ERROR
)
367 delete[] buf
; // clean up
372 for (; pAddrs
; pAddrs
= pAddrs
->Next
)
374 if (pAddrs
->OperStatus
!= IfOperStatusUp
)
377 // The ACE_SOCK_Dgram::make_multicast_ifaddr (IPv4), called by join(),
378 // can only deal with a dotted-decimal address, not an interface name.
379 if (family
== AF_INET
)
381 ACE_INET_Addr
intf_addr ((sockaddr_in
*)(pAddrs
->FirstUnicastAddress
->Address
.lpSockaddr
),
382 pAddrs
->FirstUnicastAddress
->Address
.iSockaddrLength
);
383 char intf_addr_str
[INET_ADDRSTRLEN
];
384 intf_addr
.get_host_addr (intf_addr_str
, sizeof (intf_addr_str
));
385 if (this->join (mcast_addr
, reuse_addr
,
386 ACE_TEXT_CHAR_TO_TCHAR(intf_addr_str
)) == 0)
391 if (this->join (mcast_addr
, reuse_addr
,
392 ACE_TEXT_CHAR_TO_TCHAR(pAddrs
->AdapterName
)) == 0)
397 delete[] buf
; // clean up
401 // Subscribe on all local multicast-capable network interfaces, by
402 // doing recursive calls with specific interfaces.
404 ACE_INET_Addr
*if_addrs
= 0;
407 if (ACE::get_ip_interfaces (if_cnt
, if_addrs
) != 0)
412 if (this->join (mcast_addr
,
414 ACE_TEXT ("0.0.0.0")) == 0)
419 // Iterate through all the interfaces, figure out which ones
420 // offer multicast service, and subscribe to them.
425 // Convert to 0-based for indexing, next loop check.
426 if (if_addrs
[if_cnt
].get_type () != family
|| if_addrs
[if_cnt
].is_loopback ())
428 char addr_buf
[INET6_ADDRSTRLEN
];
429 if (this->join (mcast_addr
,
431 ACE_TEXT_CHAR_TO_TCHAR
432 (if_addrs
[if_cnt
].get_host_addr (addr_buf
, INET6_ADDRSTRLEN
))) == 0)
439 # endif /* ACE_WIN32 */
441 if (nr_subscribed
== 0)
450 // Subscribe on a specific interface, or on the default interface.
452 #if defined (ACE_HAS_IPV6)
453 if (mcast_addr
.get_type () == AF_INET6
)
455 if (this->make_multicast_ifaddr6 (0, mcast_addr
, net_if
) == -1)
459 #endif /* ACE_HAS_IPV6 - Fall into IPv4-only case */
461 // Validate passed multicast addr and iface specifications.
462 if (this->make_multicast_ifaddr (0,
472 ACE_SOCK_Dgram_Mcast::join (const ACE_INET_Addr
&mcast_addr
,
474 const ACE_TCHAR
*net_if
)
476 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::join");
477 ACE_INET_Addr subscribe_addr
= mcast_addr
;
479 // If port# is 0, insert bound port# if it is set. (To satisfy lower-level
480 // port# validation.)
481 u_short def_port_number
= this->send_addr_
.get_port_number ();
482 if (subscribe_addr
.get_port_number () == 0
483 && def_port_number
!= 0)
485 subscribe_addr
.set_port_number (def_port_number
);
488 // Check for port# different than bound port#.
489 u_short sub_port_number
= mcast_addr
.get_port_number ();
490 if (sub_port_number
!= 0
491 && def_port_number
!= 0
492 && sub_port_number
!= def_port_number
)
494 ACELIB_ERROR ((LM_ERROR
,
495 ACE_TEXT ("Subscribed port# (%u) different than bound ")
496 ACE_TEXT ("port# (%u).\n"),
497 (u_int
) sub_port_number
,
498 (u_int
) def_port_number
));
503 // If bind_addr_opt_ is enabled, check for address different than
505 ACE_INET_Addr
tmp_addr (this->send_addr_
);
506 tmp_addr
.set_port_number (mcast_addr
.get_port_number ()); // force equal port numbers
507 if (ACE_BIT_ENABLED (this->opts_
, OPT_BINDADDR_YES
)
508 && !this->send_addr_
.is_any ()
509 && this->send_addr_
!= mcast_addr
)
511 ACE_TCHAR sub_addr_string
[MAXNAMELEN
+ 1];
512 ACE_TCHAR bound_addr_string
[MAXNAMELEN
+ 1];
513 ACE_SDM_helpers::addr_to_string (mcast_addr
, sub_addr_string
,
514 sizeof sub_addr_string
, 1);
515 ACE_SDM_helpers::addr_to_string (this->send_addr_
, bound_addr_string
,
516 sizeof bound_addr_string
, 1);
517 ACELIB_ERROR ((LM_ERROR
,
518 ACE_TEXT ("Subscribed address (%s) different than ")
519 ACE_TEXT ("bound address (%s).\n"),
526 // Attempt subscription.
527 int result
= this->subscribe_i (subscribe_addr
, reuse_addr
, net_if
);
529 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
532 // Add this addr/iface info to the list of subscriptions.
533 // (Assumes this is unique addr/iface combo - most systems don't allow
534 // re-sub to same addr/iface.)
535 ip_mreq
*pmreq
= new ip_mreq
;
537 if (this->make_multicast_ifaddr (pmreq
, subscribe_addr
, net_if
) != -1)
539 ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK
, guard
,
540 this->subscription_list_lock_
, -1));
541 this->subscription_list_
.insert_tail (pmreq
);
544 // this still isn't really right. If ACE_GUARD_RETURN fails, we leak.
545 // Need to add one of Chris' fancy ace auto pointers (bound?).
548 #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
550 return result
>= 0 ? 0 : result
;
553 // Attempt subscribe and return status.
555 ACE_SOCK_Dgram_Mcast::subscribe_i (const ACE_INET_Addr
&mcast_addr
,
557 const ACE_TCHAR
*net_if
)
559 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_i");
561 #if defined (ACE_HAS_IPV6)
563 #endif /* ACE_LINUX && ACE_HAS_IPV6 */
565 // Open the socket IFF this is the first ::subscribe and ::open
566 // was not explicitly invoked.
567 if (this->open (mcast_addr
, net_if
, reuse_addr
) == -1)
570 // Only do this if net_if == 0, i.e., INADDR_ANY
573 int const result
= this->subscribe_ifs (mcast_addr
, net_if
, reuse_addr
);
574 // Check for error or "short-circuit" return.
579 #if defined (ACE_HAS_IPV6)
580 if (mcast_addr
.get_type () == AF_INET6
)
582 if (this->make_multicast_ifaddr6 (&mreq6
, mcast_addr
, net_if
) == -1)
584 // Tell IP stack to pass messages sent to this group.
585 else if (this->ACE_SOCK::set_option (IPPROTO_IPV6
,
593 // Fall through for IPv4 case
594 #endif /* ACE_HAS_IPV6 */
596 // Create multicast addr/if struct.
597 if (this->make_multicast_ifaddr (&mreq
, mcast_addr
, net_if
) == -1)
599 // Tell IP stack to pass messages sent to this group.
600 else if (this->ACE_SOCK::set_option (IPPROTO_IP
,
610 ACE_SOCK_Dgram_Mcast::unsubscribe_ifs (const ACE_INET_Addr
&mcast_addr
,
611 const ACE_TCHAR
*net_if
)
613 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_ifs");
616 if (ACE_BIT_ENABLED (this->opts_
, OPT_NULLIFACE_ALL
)
619 #if defined (ACE_HAS_IPV6)
620 if (mcast_addr
.get_type () == AF_INET6
)
622 size_t nr_unsubscribed
= 0;
623 # if defined(ACE_LINUX)
624 struct if_nameindex
*intf
= ACE_OS::if_nameindex ();
630 while (intf
[index
].if_index
!= 0 || intf
[index
].if_name
!= 0)
632 if (this->leave (mcast_addr
, ACE_TEXT_CHAR_TO_TCHAR(intf
[index
].if_name
)) == 0)
638 ACE_OS::if_freenameindex (intf
);
640 # elif defined (ACE_WIN32)
642 IP_ADAPTER_ADDRESSES tmp_addrs
;
643 // Initial call to determine actual memory size needed
646 if ((dwRetVal
= ::GetAdaptersAddresses (AF_INET6
,
650 &bufLen
)) != ERROR_BUFFER_OVERFLOW
)
651 return -1; // With output bufferlength 0 this can't be right.
653 // Get required output buffer and retrieve info for real.
654 PIP_ADAPTER_ADDRESSES pAddrs
;
659 pAddrs
= reinterpret_cast<PIP_ADAPTER_ADDRESSES
> (buf
);
660 if ((dwRetVal
= ::GetAdaptersAddresses (AF_INET6
,
664 &bufLen
)) != NO_ERROR
)
666 delete[] buf
; // clean up
672 if (this->leave (mcast_addr
, ACE_TEXT_CHAR_TO_TCHAR(pAddrs
->AdapterName
)) == 0)
675 pAddrs
= pAddrs
->Next
;
678 delete[] buf
; // clean up
680 # endif /* ACE_WIN32 */
682 if (nr_unsubscribed
== 0)
692 // Unsubscribe on all local multicast-capable network interfaces, by
693 // doing recursive calls with specific interfaces.
695 ACE_INET_Addr
*if_addrs
= 0;
698 // NOTE - <get_ip_interfaces> doesn't always get all of the
699 // interfaces. In particular, it may not get a PPP interface. This
700 // is a limitation of the way <get_ip_interfaces> works with
701 // old versions of MSVC. The reliable way of getting the interface
702 // list is available only with MSVC 5 and newer.
703 if (ACE::get_ip_interfaces (if_cnt
, if_addrs
) != 0)
706 size_t nr_unsubscribed
= 0;
710 if (this->leave (mcast_addr
,
711 ACE_TEXT ("0.0.0.0")) == 0)
719 // Convert to 0-based for indexing, next loop check
720 if (if_addrs
[if_cnt
].get_type () != AF_INET
|| if_addrs
[if_cnt
].is_loopback ())
722 char addr_buf
[INET6_ADDRSTRLEN
];
723 if (this->leave (mcast_addr
,
724 ACE_TEXT_CHAR_TO_TCHAR
725 (if_addrs
[if_cnt
].get_host_addr (addr_buf
, INET6_ADDRSTRLEN
))) == 0)
732 if (nr_unsubscribed
== 0)
740 #else /* ACE_HAS_IPV6 */
741 // Unsubscribe on all local multicast-capable network interfaces, by
742 // doing recursive calls with specific interfaces.
744 ACE_INET_Addr
*if_addrs
= 0;
747 // NOTE - <get_ip_interfaces> doesn't always get all of the
748 // interfaces. In particular, it may not get a PPP interface. This
749 // is a limitation of the way <get_ip_interfaces> works with
750 // old versions of MSVC. The reliable way of getting the interface list
751 // is available only with MSVC 5 and newer.
752 if (ACE::get_ip_interfaces (if_cnt
, if_addrs
) != 0)
755 size_t nr_unsubscribed
= 0;
759 if (this->leave (mcast_addr
,
760 ACE_TEXT ("0.0.0.0")) == 0)
768 // Convert to 0-based for indexing, next loop check
769 if (if_addrs
[if_cnt
].is_loopback ())
771 char addr_buf
[INET6_ADDRSTRLEN
];
772 if (this->leave (mcast_addr
,
773 ACE_TEXT_CHAR_TO_TCHAR
774 (if_addrs
[if_cnt
].get_host_addr (addr_buf
, INET6_ADDRSTRLEN
))) == 0)
781 if (nr_unsubscribed
== 0)
788 #endif /* !ACE_HAS_IPV6 */
796 ACE_SOCK_Dgram_Mcast::leave (const ACE_INET_Addr
&mcast_addr
,
797 const ACE_TCHAR
*net_if
)
799 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::leave");
801 int result
= this->unsubscribe_i (mcast_addr
,
804 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
805 // (Unconditionally) Remove this addr/if from subscription list.
806 // (Addr/if is removed even if unsubscribe failed)
808 if (this->make_multicast_ifaddr (&tgt_mreq
,
812 ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK
, guard
,
813 this->subscription_list_lock_
, -1));
814 subscription_list_iter_t
iter (this->subscription_list_
);
815 for (; !iter
.done (); iter
.advance ())
817 ip_mreq
*pm
= iter
.next ();
818 if (ACE_SDM_helpers::is_equal (*pm
, tgt_mreq
))
826 #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
828 return result
>= 0 ? 0 : result
;
831 // Attempt unsubscribe and return status.
833 ACE_SOCK_Dgram_Mcast::unsubscribe_i (const ACE_INET_Addr
&mcast_addr
,
834 const ACE_TCHAR
*net_if
)
836 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_i");
838 int result
= this->unsubscribe_ifs (mcast_addr
,
841 // Check for error or "short-circuit" return.
845 #if defined (ACE_HAS_IPV6)
846 if (mcast_addr
.get_type () == AF_INET6
)
848 // Validate addr/if specifications and create addr/if struct.
850 if (this->make_multicast_ifaddr6 (&mreq
, mcast_addr
, net_if
) == -1)
854 // Tell network device driver to stop reading datagrams with the
856 else if (ACE_SOCK::set_option (IPPROTO_IPV6
,
867 // Validate addr/if specifications and create addr/if struct.
869 if (this->make_multicast_ifaddr (&mreq
, mcast_addr
, net_if
) == -1)
873 // Tell network device driver to stop reading datagrams with the
875 else if (ACE_SOCK::set_option (IPPROTO_IP
,
885 // Validate addr/if specifications and create addr/if struct.
887 if (this->make_multicast_ifaddr (&mreq
, mcast_addr
, net_if
) == -1)
891 // Tell network device driver to stop reading datagrams with the
893 // Note, this is not IPv6 friendly...
894 else if (ACE_SOCK::set_option (IPPROTO_IP
,
901 #endif /* ACE_HAS_IPV6 */
907 ACE_SOCK_Dgram_Mcast::clear_subs_list ()
909 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::clear_subs_list");
912 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
913 ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK
, guard
,
914 this->subscription_list_lock_
, -1));
915 subscription_list_iter_t
iter (this->subscription_list_
);
916 for (; !iter
.done (); /*Hack: Do _not_ ::advance after remove*/)
918 ip_mreq
*pm
= iter
.next ();
922 #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
926 ACE_END_VERSIONED_NAMESPACE_DECL