PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/dep/acelite/ace/SOCK_Dgram_Mcast.cpp

https://github.com/chucho/FaceCore
C++ | 928 lines | 687 code | 135 blank | 106 comment | 200 complexity | cf642e7bb5ca9c129fdd229d5ff552ae MD5 | raw file
  1. // $Id: SOCK_Dgram_Mcast.cpp 91286 2010-08-05 09:04:31Z johnnyw $
  2. #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 (__linux__) && defined (ACE_HAS_IPV6)
  9. #include "ace/OS_NS_sys_socket.h"
  10. #endif
  11. #if defined (ACE_HAS_IPV6) && defined (ACE_WIN32)
  12. #include /**/ <iphlpapi.h>
  13. #endif
  14. #if !defined (__ACE_INLINE__)
  15. #include "ace/SOCK_Dgram_Mcast.inl"
  16. #endif /* __ACE_INLINE__ */
  17. #include "ace/Log_Msg.h"
  18. // This is a workaround for platforms with non-standard
  19. // definitions of the ip_mreq structure
  20. #if ! defined (IMR_MULTIADDR)
  21. #define IMR_MULTIADDR imr_multiaddr
  22. #endif /* ! defined (IMR_MULTIADDR) */
  23. ACE_BEGIN_VERSIONED_NAMESPACE_DECL
  24. // Helper (inline) functions.
  25. class ACE_SDM_helpers
  26. {
  27. public:
  28. // Convert ACE_INET_Addr to string, using local formatting rules.
  29. static void addr_to_string (const ACE_INET_Addr &ip_addr,
  30. ACE_TCHAR *ret_string, // results here.
  31. size_t len,
  32. int clip_portnum) // clip port# info?
  33. {
  34. if (ip_addr.addr_to_string (ret_string, len, 1) == -1)
  35. ACE_OS::strcpy (ret_string, ACE_TEXT ("<?>"));
  36. else
  37. {
  38. ACE_TCHAR *pc = ACE_OS::strrchr (ret_string, ACE_TEXT (':'));
  39. if (clip_portnum && pc)
  40. *pc = ACE_TEXT ('\0'); // clip port# info.
  41. }
  42. }
  43. // op== for ip_mreq structs.
  44. static int is_equal (const ip_mreq &m1, const ip_mreq &m2)
  45. {
  46. return m1.IMR_MULTIADDR.s_addr == m2.IMR_MULTIADDR.s_addr
  47. && m1.imr_interface.s_addr == m2.imr_interface.s_addr;
  48. }
  49. };
  50. ACE_ALLOC_HOOK_DEFINE (ACE_SOCK_Dgram_Mcast)
  51. void
  52. ACE_SOCK_Dgram_Mcast::dump (void) const
  53. {
  54. #if defined (ACE_HAS_DUMP)
  55. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::dump");
  56. ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
  57. # if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
  58. ACE_TCHAR addr_string[MAXNAMELEN + 1];
  59. ACE_DEBUG ((LM_DEBUG,
  60. ACE_TEXT ("\nOptions: bindaddr=%s, nulliface=%s\n"),
  61. ACE_BIT_ENABLED (this->opts_, OPT_BINDADDR_YES) ?
  62. ACE_TEXT ("<Bound>") : ACE_TEXT ("<Not Bound>"),
  63. ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL) ?
  64. ACE_TEXT ("<All Ifaces>") : ACE_TEXT ("<Default Iface>")));
  65. // Show default send addr, port#, and interface.
  66. ACE_SDM_helpers::addr_to_string (this->send_addr_, addr_string,
  67. sizeof addr_string, 0);
  68. ACE_DEBUG ((LM_DEBUG,
  69. ACE_TEXT ("Send addr=%s iface=%s\n"),
  70. addr_string,
  71. this->send_net_if_ ? this->send_net_if_
  72. : ACE_TEXT ("<default>")));
  73. // Show list of subscribed addresses.
  74. ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Subscription list:\n")));
  75. ACE_MT (ACE_GUARD (ACE_SDM_LOCK, guard, this->subscription_list_lock_));
  76. subscription_list_iter_t iter (this->subscription_list_);
  77. for ( ; !iter.done (); iter.advance ())
  78. {
  79. ACE_TCHAR iface_string[MAXNAMELEN + 1];
  80. ip_mreq *pm = iter.next ();
  81. // Get subscribed address (w/out port# info - not relevant).
  82. ACE_INET_Addr ip_addr (static_cast<u_short> (0),
  83. ACE_NTOHL (pm->IMR_MULTIADDR.s_addr));
  84. ACE_SDM_helpers::addr_to_string (ip_addr, addr_string,
  85. sizeof addr_string, 1);
  86. // Get interface address/specification.
  87. ACE_INET_Addr if_addr (static_cast<u_short> (0),
  88. ACE_NTOHL (pm->imr_interface.s_addr));
  89. ACE_SDM_helpers::addr_to_string (if_addr, iface_string,
  90. sizeof iface_string, 1);
  91. if (ACE_OS::strcmp (iface_string, ACE_TEXT ("0.0.0.0")) == 0)
  92. // Receives on system default iface. (Note that null_iface_opt_
  93. // option processing has already occurred.)
  94. ACE_OS::strcpy (iface_string, ACE_TEXT ("<default>"));
  95. // Dump info.
  96. ACE_DEBUG ((LM_DEBUG,
  97. ACE_TEXT ("\taddr=%s iface=%s\n"),
  98. addr_string,
  99. iface_string));
  100. }
  101. # endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
  102. ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
  103. #endif /* ACE_HAS_DUMP */
  104. }
  105. // Constructor.
  106. ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast
  107. (ACE_SOCK_Dgram_Mcast::options opts)
  108. : opts_ (opts),
  109. send_net_if_ (0)
  110. {
  111. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast");
  112. }
  113. // Destructor.
  114. ACE_SOCK_Dgram_Mcast::~ACE_SOCK_Dgram_Mcast (void)
  115. {
  116. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::~ACE_SOCK_Dgram_Mcast");
  117. // Free memory and optionally unsubscribe from currently subscribed group(s).
  118. delete [] this->send_net_if_;
  119. this->clear_subs_list ();
  120. }
  121. int
  122. ACE_SOCK_Dgram_Mcast::open (const ACE_INET_Addr &mcast_addr,
  123. const ACE_TCHAR *net_if,
  124. int reuse_addr)
  125. {
  126. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::open");
  127. // Only perform the <open> initialization if we haven't been opened
  128. // earlier.
  129. // No sanity check? We should probably flag an error if the user
  130. // makes multiple calls to open().
  131. if (this->get_handle () != ACE_INVALID_HANDLE)
  132. return 0;
  133. // Invoke lower-layer ::open.
  134. if (ACE_SOCK::open (SOCK_DGRAM,
  135. mcast_addr.get_type (),
  136. 0, // always use 0
  137. reuse_addr) == -1)
  138. return -1;
  139. return this->open_i (mcast_addr, net_if, reuse_addr);
  140. }
  141. int
  142. ACE_SOCK_Dgram_Mcast::open_i (const ACE_INET_Addr &mcast_addr,
  143. const ACE_TCHAR *net_if,
  144. int reuse_addr)
  145. {
  146. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::open_i");
  147. // ACE_SOCK::open calls this if reuse_addr is set, so we only need to
  148. // process port reuse option.
  149. if (reuse_addr)
  150. {
  151. #if defined (SO_REUSEPORT)
  152. int one = 1;
  153. if (this->ACE_SOCK::set_option (SOL_SOCKET,
  154. SO_REUSEPORT,
  155. &one,
  156. sizeof one) == -1)
  157. return -1;
  158. #endif /* SO_REUSEPORT */
  159. }
  160. // Create an address/port# to bind the socket to. Use mcast_addr to
  161. // initialize bind_addy to pick up the correct protocol family. If
  162. // OPT_BINDADDR_YES is set, then we're done. Else use mcast_addr's
  163. // port number and use the "any" address.
  164. ACE_INET_Addr bind_addy (mcast_addr);
  165. if (ACE_BIT_DISABLED (this->opts_, OPT_BINDADDR_YES))
  166. {
  167. #if defined (ACE_HAS_IPV6)
  168. if (mcast_addr.get_type () == PF_INET6)
  169. {
  170. if (bind_addy.set (mcast_addr.get_port_number (), "::",
  171. 1, AF_INET6) == -1)
  172. return -1;
  173. }
  174. else
  175. // Bind to "any" address and explicit port#.
  176. if (bind_addy.set (mcast_addr.get_port_number ()) == -1)
  177. return -1;
  178. #else
  179. // Bind to "any" address and explicit port#.
  180. if (bind_addy.set (mcast_addr.get_port_number ()) == -1)
  181. return -1;
  182. #endif /* ACE_HAS_IPV6 */
  183. }
  184. // Bind to the address (which may be INADDR_ANY) and port# (which may be 0)
  185. if (ACE_SOCK_Dgram::shared_open (bind_addy, bind_addy.get_type ()) == -1)
  186. return -1;
  187. // Cache the actual bound address (which may be INADDR_ANY)
  188. // and the actual bound port# (which will be a valid, non-zero port#).
  189. ACE_INET_Addr bound_addy;
  190. if (this->get_local_addr (bound_addy) == -1)
  191. {
  192. // (Unexpected failure - should be bound to something)
  193. if (bound_addy.set (bind_addy) == -1)
  194. {
  195. // (Shouldn't happen - bind_addy is a valid addy; punt.)
  196. return -1;
  197. }
  198. }
  199. this->send_addr_ = mcast_addr;
  200. this->send_addr_.set_port_number (bound_addy.get_port_number ());
  201. if (net_if)
  202. {
  203. if (this->set_nic (net_if, mcast_addr.get_type ()))
  204. return -1;
  205. this->send_net_if_ = new ACE_TCHAR[ACE_OS::strlen (net_if) + 1];
  206. ACE_OS::strcpy (this->send_net_if_, net_if);
  207. }
  208. return 0;
  209. }
  210. int
  211. ACE_SOCK_Dgram_Mcast::subscribe_ifs (const ACE_INET_Addr &mcast_addr,
  212. const ACE_TCHAR *net_if,
  213. int reuse_addr)
  214. {
  215. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_ifs");
  216. if (ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL)
  217. && net_if == 0)
  218. {
  219. #if defined (ACE_HAS_IPV6)
  220. if (mcast_addr.get_type () == AF_INET6)
  221. {
  222. size_t nr_subscribed = 0;
  223. # if defined(__linux__)
  224. struct if_nameindex *intf;
  225. intf = ACE_OS::if_nameindex ();
  226. if (intf == 0)
  227. return -1;
  228. int index = 0;
  229. while (intf[index].if_index != 0 || intf[index].if_name != 0)
  230. {
  231. if (this->join (mcast_addr, reuse_addr,
  232. ACE_TEXT_CHAR_TO_TCHAR(intf[index].if_name)) == 0)
  233. ++nr_subscribed;
  234. ++index;
  235. }
  236. ACE_OS::if_freenameindex (intf);
  237. # elif defined (ACE_WIN32)
  238. IP_ADAPTER_ADDRESSES tmp_addrs;
  239. // Initial call to determine actual memory size needed
  240. DWORD dwRetVal;
  241. ULONG bufLen = 0;
  242. if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
  243. 0,
  244. 0,
  245. &tmp_addrs,
  246. &bufLen)) != ERROR_BUFFER_OVERFLOW)
  247. return -1; // With output bufferlength 0 this can't be right.
  248. // Get required output buffer and retrieve info for real.
  249. PIP_ADAPTER_ADDRESSES pAddrs;
  250. char *buf;
  251. ACE_NEW_RETURN (buf,
  252. char[bufLen],
  253. -1);
  254. pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
  255. if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
  256. 0,
  257. 0,
  258. pAddrs,
  259. &bufLen)) != NO_ERROR)
  260. {
  261. delete[] buf; // clean up
  262. return -1;
  263. }
  264. while (pAddrs)
  265. {
  266. if (this->join (mcast_addr, reuse_addr,
  267. ACE_TEXT_CHAR_TO_TCHAR(pAddrs->AdapterName)) == 0)
  268. ++nr_subscribed;
  269. pAddrs = pAddrs->Next;
  270. }
  271. delete[] buf; // clean up
  272. # endif /* ACE_WIN32 */
  273. if (nr_subscribed == 0)
  274. {
  275. errno = ENODEV;
  276. return -1;
  277. }
  278. return 1;
  279. }
  280. else
  281. {
  282. // Subscribe on all local multicast-capable network interfaces, by
  283. // doing recursive calls with specific interfaces.
  284. ACE_INET_Addr *if_addrs = 0;
  285. size_t if_cnt;
  286. if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
  287. return -1;
  288. size_t nr_subscribed = 0;
  289. if (if_cnt < 2)
  290. {
  291. if (this->join (mcast_addr,
  292. reuse_addr,
  293. ACE_TEXT ("0.0.0.0")) == 0)
  294. ++nr_subscribed;
  295. }
  296. else
  297. {
  298. // Iterate through all the interfaces, figure out which ones
  299. // offer multicast service, and subscribe to them.
  300. while (if_cnt > 0)
  301. {
  302. --if_cnt;
  303. // Convert to 0-based for indexing, next loop check.
  304. if (if_addrs[if_cnt].get_type () != AF_INET || if_addrs[if_cnt].is_loopback ())
  305. continue;
  306. char addr_buf[INET6_ADDRSTRLEN];
  307. if (this->join (mcast_addr,
  308. reuse_addr,
  309. ACE_TEXT_CHAR_TO_TCHAR
  310. (if_addrs[if_cnt].get_host_addr (addr_buf, INET6_ADDRSTRLEN))) == 0)
  311. ++nr_subscribed;
  312. }
  313. }
  314. delete [] if_addrs;
  315. if (nr_subscribed == 0)
  316. {
  317. errno = ENODEV;
  318. return -1;
  319. }
  320. // 1 indicates a "short-circuit" return. This handles the
  321. // recursive behavior of checking all the interfaces.
  322. return 1;
  323. }
  324. #else
  325. // Subscribe on all local multicast-capable network interfaces, by
  326. // doing recursive calls with specific interfaces.
  327. ACE_INET_Addr *if_addrs = 0;
  328. size_t if_cnt;
  329. if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
  330. return -1;
  331. size_t nr_subscribed = 0;
  332. if (if_cnt < 2)
  333. {
  334. if (this->join (mcast_addr,
  335. reuse_addr,
  336. ACE_TEXT ("0.0.0.0")) == 0)
  337. ++nr_subscribed;
  338. }
  339. else
  340. {
  341. // Iterate through all the interfaces, figure out which ones
  342. // offer multicast service, and subscribe to them.
  343. while (if_cnt > 0)
  344. {
  345. --if_cnt;
  346. // Convert to 0-based for indexing, next loop check.
  347. if (if_addrs[if_cnt].is_loopback ())
  348. continue;
  349. char addr_buf[INET6_ADDRSTRLEN];
  350. if (this->join (mcast_addr,
  351. reuse_addr,
  352. ACE_TEXT_CHAR_TO_TCHAR
  353. (if_addrs[if_cnt].get_host_addr (addr_buf, INET6_ADDRSTRLEN))) == 0)
  354. ++nr_subscribed;
  355. }
  356. }
  357. delete [] if_addrs;
  358. if (nr_subscribed == 0)
  359. {
  360. errno = ENODEV;
  361. return -1;
  362. }
  363. // 1 indicates a "short-circuit" return. This handles the
  364. // recursive behavior of checking all the interfaces.
  365. return 1;
  366. #endif /* ACE_HAS_IPV6 */
  367. }
  368. #if defined (ACE_HAS_IPV6)
  369. if (mcast_addr.get_type () == AF_INET6)
  370. {
  371. if (this->make_multicast_ifaddr6 (0, mcast_addr, net_if) == -1)
  372. return -1;
  373. }
  374. else
  375. {
  376. // Validate passed multicast addr and iface specifications.
  377. if (this->make_multicast_ifaddr (0,
  378. mcast_addr,
  379. net_if) == -1)
  380. return -1;
  381. }
  382. #else
  383. // Validate passed multicast addr and iface specifications.
  384. if (this->make_multicast_ifaddr (0,
  385. mcast_addr,
  386. net_if) == -1)
  387. return -1;
  388. #endif /* ACE_HAS_IPV6 */
  389. return 0;
  390. }
  391. int
  392. ACE_SOCK_Dgram_Mcast::join (const ACE_INET_Addr &mcast_addr,
  393. int reuse_addr,
  394. const ACE_TCHAR *net_if)
  395. {
  396. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::join");
  397. ACE_INET_Addr subscribe_addr = mcast_addr;
  398. // If port# is 0, insert bound port# if it is set. (To satisfy lower-level
  399. // port# validation.)
  400. u_short def_port_number = this->send_addr_.get_port_number ();
  401. if (subscribe_addr.get_port_number () == 0
  402. && def_port_number != 0)
  403. {
  404. subscribe_addr.set_port_number (def_port_number);
  405. }
  406. // Check for port# different than bound port#.
  407. u_short sub_port_number = mcast_addr.get_port_number ();
  408. if (sub_port_number != 0
  409. && def_port_number != 0
  410. && sub_port_number != def_port_number)
  411. {
  412. ACE_ERROR ((LM_ERROR,
  413. ACE_TEXT ("Subscribed port# (%u) different than bound ")
  414. ACE_TEXT ("port# (%u).\n"),
  415. (u_int) sub_port_number,
  416. (u_int) def_port_number));
  417. errno = ENXIO;
  418. return -1;
  419. }
  420. // If bind_addr_opt_ is enabled, check for address different than
  421. // bound address.
  422. ACE_INET_Addr tmp_addr (this->send_addr_);
  423. tmp_addr.set_port_number (mcast_addr.get_port_number ()); // force equal port numbers
  424. if (ACE_BIT_ENABLED (this->opts_, OPT_BINDADDR_YES)
  425. && !this->send_addr_.is_any ()
  426. && this->send_addr_ != mcast_addr)
  427. {
  428. ACE_TCHAR sub_addr_string[MAXNAMELEN + 1];
  429. ACE_TCHAR bound_addr_string[MAXNAMELEN + 1];
  430. ACE_SDM_helpers::addr_to_string (mcast_addr, sub_addr_string,
  431. sizeof sub_addr_string, 1);
  432. ACE_SDM_helpers::addr_to_string (this->send_addr_, bound_addr_string,
  433. sizeof bound_addr_string, 1);
  434. ACE_ERROR ((LM_ERROR,
  435. ACE_TEXT ("Subscribed address (%s) different than ")
  436. ACE_TEXT ("bound address (%s).\n"),
  437. sub_addr_string,
  438. bound_addr_string));
  439. errno = ENXIO;
  440. return -1;
  441. }
  442. // Attempt subscription.
  443. int result = this->subscribe_i (subscribe_addr, reuse_addr, net_if);
  444. #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
  445. if (result == 0)
  446. {
  447. // Add this addr/iface info to the list of subscriptions.
  448. // (Assumes this is unique addr/iface combo - most systems don't allow
  449. // re-sub to same addr/iface.)
  450. ip_mreq *pmreq = new ip_mreq;
  451. // (should not fail)
  452. if (this->make_multicast_ifaddr (pmreq, subscribe_addr, net_if) != -1)
  453. {
  454. ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
  455. this->subscription_list_lock_, -1));
  456. this->subscription_list_.insert_tail (pmreq);
  457. return 0;
  458. }
  459. // this still isn't really right. If ACE_GUARD_RETURN fails, we leak.
  460. // Need to add one of Chris' fancy ace auto pointers (bound?).
  461. delete pmreq;
  462. }
  463. #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
  464. return result >= 0 ? 0 : result;
  465. }
  466. // Attempt subscribe and return status.
  467. int
  468. ACE_SOCK_Dgram_Mcast::subscribe_i (const ACE_INET_Addr &mcast_addr,
  469. int reuse_addr,
  470. const ACE_TCHAR *net_if)
  471. {
  472. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_i");
  473. ip_mreq mreq;
  474. #if defined (ACE_HAS_IPV6)
  475. ipv6_mreq mreq6;
  476. #endif /* __linux__ && ACE_HAS_IPV6 */
  477. // Open the socket IFF this is the first ::subscribe and ::open
  478. // was not explicitly invoked.
  479. if (this->open (mcast_addr,
  480. net_if,
  481. reuse_addr) == -1)
  482. return -1;
  483. // Only do this if net_if == 0, i.e., INADDR_ANY
  484. if (net_if == 0)
  485. {
  486. int result = this->subscribe_ifs (mcast_addr,
  487. net_if,
  488. reuse_addr);
  489. // Check for error or "short-circuit" return.
  490. if (result != 0)
  491. return result;
  492. }
  493. #if defined (ACE_HAS_IPV6)
  494. if (mcast_addr.get_type () == AF_INET6)
  495. {
  496. if (this->make_multicast_ifaddr6 (&mreq6, mcast_addr, net_if) == -1)
  497. return -1;
  498. // Tell IP stack to pass messages sent to this group.
  499. else if (this->ACE_SOCK::set_option (IPPROTO_IPV6,
  500. IPV6_JOIN_GROUP,
  501. &mreq6,
  502. sizeof mreq6) == -1)
  503. return -1;
  504. return 0;
  505. }
  506. // Fall through for IPv4 case
  507. #endif /* ACE_HAS_IPV6 */
  508. // Create multicast addr/if struct.
  509. if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
  510. return -1;
  511. // Tell IP stack to pass messages sent to this group.
  512. else if (this->ACE_SOCK::set_option (IPPROTO_IP,
  513. IP_ADD_MEMBERSHIP,
  514. &mreq,
  515. sizeof mreq) == -1)
  516. return -1;
  517. return 0;
  518. }
  519. int
  520. ACE_SOCK_Dgram_Mcast::unsubscribe_ifs (const ACE_INET_Addr &mcast_addr,
  521. const ACE_TCHAR *net_if)
  522. {
  523. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_ifs");
  524. if (ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL)
  525. && net_if == 0)
  526. {
  527. #if defined (ACE_HAS_IPV6)
  528. if (mcast_addr.get_type () == AF_INET6)
  529. {
  530. size_t nr_unsubscribed = 0;
  531. # if defined(__linux__)
  532. struct if_nameindex *intf;
  533. intf = ACE_OS::if_nameindex ();
  534. if (intf == 0)
  535. return -1;
  536. int index = 0;
  537. while (intf[index].if_index != 0 || intf[index].if_name != 0)
  538. {
  539. if (this->leave (mcast_addr, ACE_TEXT_CHAR_TO_TCHAR(intf[index].if_name)) == 0)
  540. ++nr_unsubscribed;
  541. ++index;
  542. }
  543. ACE_OS::if_freenameindex (intf);
  544. # elif defined (ACE_WIN32)
  545. IP_ADAPTER_ADDRESSES tmp_addrs;
  546. // Initial call to determine actual memory size needed
  547. DWORD dwRetVal;
  548. ULONG bufLen = 0;
  549. if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
  550. 0,
  551. 0,
  552. &tmp_addrs,
  553. &bufLen)) != ERROR_BUFFER_OVERFLOW)
  554. return -1; // With output bufferlength 0 this can't be right.
  555. // Get required output buffer and retrieve info for real.
  556. PIP_ADAPTER_ADDRESSES pAddrs;
  557. char *buf;
  558. ACE_NEW_RETURN (buf,
  559. char[bufLen],
  560. -1);
  561. pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
  562. if ((dwRetVal = ::GetAdaptersAddresses (AF_INET6,
  563. 0,
  564. 0,
  565. pAddrs,
  566. &bufLen)) != NO_ERROR)
  567. {
  568. delete[] buf; // clean up
  569. return -1;
  570. }
  571. while (pAddrs)
  572. {
  573. if (this->leave (mcast_addr, ACE_TEXT_CHAR_TO_TCHAR(pAddrs->AdapterName)) == 0)
  574. ++nr_unsubscribed;
  575. pAddrs = pAddrs->Next;
  576. }
  577. delete[] buf; // clean up
  578. # endif /* ACE_WIN32 */
  579. if (nr_unsubscribed == 0)
  580. {
  581. errno = ENODEV;
  582. return -1;
  583. }
  584. return 1;
  585. }
  586. else
  587. {
  588. // Unsubscribe on all local multicast-capable network interfaces, by
  589. // doing recursive calls with specific interfaces.
  590. ACE_INET_Addr *if_addrs = 0;
  591. size_t if_cnt;
  592. // NOTE - <get_ip_interfaces> doesn't always get all of the
  593. // interfaces. In particular, it may not get a PPP interface. This
  594. // is a limitation of the way <get_ip_interfaces> works with
  595. // old versions of MSVC. The reliable way of getting the interface
  596. // list is available only with MSVC 5 and newer.
  597. if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
  598. return -1;
  599. size_t nr_unsubscribed = 0;
  600. if (if_cnt < 2)
  601. {
  602. if (this->leave (mcast_addr,
  603. ACE_TEXT ("0.0.0.0")) == 0)
  604. ++nr_unsubscribed;
  605. }
  606. else
  607. {
  608. while (if_cnt > 0)
  609. {
  610. --if_cnt;
  611. // Convert to 0-based for indexing, next loop check
  612. if (if_addrs[if_cnt].get_type () != AF_INET || if_addrs[if_cnt].is_loopback ())
  613. continue;
  614. char addr_buf[INET6_ADDRSTRLEN];
  615. if (this->leave (mcast_addr,
  616. ACE_TEXT_CHAR_TO_TCHAR
  617. (if_addrs[if_cnt].get_host_addr (addr_buf, INET6_ADDRSTRLEN))) == 0)
  618. ++nr_unsubscribed;
  619. }
  620. }
  621. delete [] if_addrs;
  622. if (nr_unsubscribed == 0)
  623. {
  624. errno = ENODEV;
  625. return -1;
  626. }
  627. return 1;
  628. }
  629. #else /* ACE_HAS_IPV6 */
  630. // Unsubscribe on all local multicast-capable network interfaces, by
  631. // doing recursive calls with specific interfaces.
  632. ACE_INET_Addr *if_addrs = 0;
  633. size_t if_cnt;
  634. // NOTE - <get_ip_interfaces> doesn't always get all of the
  635. // interfaces. In particular, it may not get a PPP interface. This
  636. // is a limitation of the way <get_ip_interfaces> works with
  637. // old versions of MSVC. The reliable way of getting the interface list
  638. // is available only with MSVC 5 and newer.
  639. if (ACE::get_ip_interfaces (if_cnt, if_addrs) != 0)
  640. return -1;
  641. size_t nr_unsubscribed = 0;
  642. if (if_cnt < 2)
  643. {
  644. if (this->leave (mcast_addr,
  645. ACE_TEXT ("0.0.0.0")) == 0)
  646. ++nr_unsubscribed;
  647. }
  648. else
  649. {
  650. while (if_cnt > 0)
  651. {
  652. --if_cnt;
  653. // Convert to 0-based for indexing, next loop check
  654. if (if_addrs[if_cnt].is_loopback ())
  655. continue;
  656. char addr_buf[INET6_ADDRSTRLEN];
  657. if (this->leave (mcast_addr,
  658. ACE_TEXT_CHAR_TO_TCHAR
  659. (if_addrs[if_cnt].get_host_addr (addr_buf, INET6_ADDRSTRLEN))) == 0)
  660. ++nr_unsubscribed;
  661. }
  662. }
  663. delete [] if_addrs;
  664. if (nr_unsubscribed == 0)
  665. {
  666. errno = ENODEV;
  667. return -1;
  668. }
  669. return 1;
  670. #endif /* !ACE_HAS_IPV6 */
  671. }
  672. return 0;
  673. }
  674. int
  675. ACE_SOCK_Dgram_Mcast::leave (const ACE_INET_Addr &mcast_addr,
  676. const ACE_TCHAR *net_if)
  677. {
  678. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::leave");
  679. // Unsubscribe.
  680. int result = this->unsubscribe_i (mcast_addr,
  681. net_if);
  682. #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
  683. // (Unconditionally) Remove this addr/if from subscription list.
  684. // (Addr/if is removed even if unsubscribe failed)
  685. ip_mreq tgt_mreq;
  686. if (this->make_multicast_ifaddr (&tgt_mreq,
  687. mcast_addr,
  688. net_if) != -1)
  689. {
  690. ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
  691. this->subscription_list_lock_, -1));
  692. subscription_list_iter_t iter (this->subscription_list_);
  693. for (; !iter.done (); iter.advance ())
  694. {
  695. ip_mreq *pm = iter.next ();
  696. if (ACE_SDM_helpers::is_equal (*pm, tgt_mreq))
  697. {
  698. iter.remove ();
  699. delete pm;
  700. break;
  701. }
  702. }
  703. }
  704. #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
  705. return result >= 0 ? 0 : result;
  706. }
  707. // Attempt unsubscribe and return status.
  708. int
  709. ACE_SOCK_Dgram_Mcast::unsubscribe_i (const ACE_INET_Addr &mcast_addr,
  710. const ACE_TCHAR *net_if)
  711. {
  712. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_i");
  713. int result = this->unsubscribe_ifs (mcast_addr,
  714. net_if);
  715. // Check for error or "short-circuit" return.
  716. if (result != 0)
  717. return result;
  718. #if defined (ACE_HAS_IPV6)
  719. if (mcast_addr.get_type () == AF_INET6)
  720. {
  721. // Validate addr/if specifications and create addr/if struct.
  722. ipv6_mreq mreq;
  723. if (this->make_multicast_ifaddr6 (&mreq, mcast_addr, net_if) == -1)
  724. {
  725. return -1;
  726. }
  727. // Tell network device driver to stop reading datagrams with the
  728. // <mcast_addr>.
  729. else if (ACE_SOCK::set_option (IPPROTO_IPV6,
  730. IPV6_LEAVE_GROUP,
  731. &mreq,
  732. sizeof mreq) == -1)
  733. {
  734. return -1;
  735. }
  736. }
  737. else // IPv4
  738. {
  739. // Validate addr/if specifications and create addr/if struct.
  740. ip_mreq mreq;
  741. if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
  742. {
  743. return -1;
  744. }
  745. // Tell network device driver to stop reading datagrams with the
  746. // <mcast_addr>.
  747. else if (ACE_SOCK::set_option (IPPROTO_IP,
  748. IP_DROP_MEMBERSHIP,
  749. &mreq,
  750. sizeof mreq) == -1)
  751. {
  752. return -1;
  753. }
  754. }
  755. #else
  756. // Validate addr/if specifications and create addr/if struct.
  757. ip_mreq mreq;
  758. if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
  759. {
  760. return -1;
  761. }
  762. // Tell network device driver to stop reading datagrams with the
  763. // <mcast_addr>.
  764. // Note, this is not IPv6 friendly...
  765. else if (ACE_SOCK::set_option (IPPROTO_IP,
  766. IP_DROP_MEMBERSHIP,
  767. &mreq,
  768. sizeof mreq) == -1)
  769. {
  770. return -1;
  771. }
  772. #endif /* ACE_HAS_IPV6 */
  773. return 0;
  774. }
  775. int
  776. ACE_SOCK_Dgram_Mcast::clear_subs_list (void)
  777. {
  778. ACE_TRACE ("ACE_SOCK_Dgram_Mcast::clear_subs_list");
  779. int result = 0;
  780. #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
  781. ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
  782. this->subscription_list_lock_, -1));
  783. subscription_list_iter_t iter (this->subscription_list_);
  784. for (; !iter.done (); /*Hack: Do _not_ ::advance after remove*/)
  785. {
  786. ip_mreq *pm = iter.next ();
  787. iter.remove ();
  788. delete pm;
  789. }
  790. #endif /* ACE_SOCK_DGRAM_MCAST_DUMPABLE */
  791. return result;
  792. }
  793. ACE_END_VERSIONED_NAMESPACE_DECL