00001 #include "ace_pch.h"
00002
00003
00004 #include "ace/SOCK_Dgram_Mcast.h"
00005
00006 #if defined (ACE_LACKS_INLINE_FUNCTIONS)
00007 #include "ace/SOCK_Dgram_Mcast.i"
00008 #endif
00009
00010 ACE_RCSID (ace,
00011 SOCK_Dgram_Mcast,
00012 "$Id: SOCK_Dgram_Mcast.cpp,v 1.1.1.4.2.1 2003/03/13 19:44:22 chad Exp $")
00013
00014 #include "ace/Log_Msg.h"
00015
00016
00017
00018 #if ! defined (IMR_MULTIADDR)
00019 #define IMR_MULTIADDR imr_multiaddr
00020 #endif
00021
00022
00023 class ACE_SDM_helpers
00024 {
00025 public:
00026
00027
00028 static void addr_to_string (const ACE_INET_Addr &ip_addr,
00029 ACE_TCHAR *ret_string,
00030 size_t len,
00031 int clip_portnum)
00032 {
00033 if (ip_addr.addr_to_string (ret_string, len, 1) == -1)
00034 {
00035 ACE_OS_String::strcpy (ret_string, ACE_LIB_TEXT ("<?>"));
00036 }
00037 else
00038 {
00039 ACE_TCHAR *pc;
00040 if (clip_portnum
00041 && (pc = ACE_OS_String::strchr (ret_string, ACE_LIB_TEXT (':'))))
00042 *pc = ACE_LIB_TEXT ('\0');
00043 }
00044 }
00045
00046 static int is_equal (const ip_mreq &m1, const ip_mreq &m2)
00047 {
00048 return m1.IMR_MULTIADDR.s_addr == m2.IMR_MULTIADDR.s_addr
00049 && m1.imr_interface.s_addr == m2.imr_interface.s_addr;
00050 }
00051 };
00052
00053 ACE_ALLOC_HOOK_DEFINE (ACE_SOCK_Dgram_Mcast)
00054
00055 void
00056 ACE_SOCK_Dgram_Mcast::dump (void) const
00057 {
00058 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::dump");
00059
00060 ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00061
00062 # if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00063 ACE_TCHAR addr_string[MAXNAMELEN + 1];
00064
00065 ACE_DEBUG ((LM_DEBUG,
00066 ACE_LIB_TEXT ("\nOptions: bindaddr=%s, nulliface=%s\n"),
00067 ACE_BIT_ENABLED (this->opts_, OPT_BINDADDR_YES) ?
00068 ACE_LIB_TEXT ("<Bound>") : ACE_LIB_TEXT ("<Not Bound>"),
00069 ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL) ?
00070 ACE_LIB_TEXT ("<All Ifaces>") : ACE_LIB_TEXT ("<Default Iface>")));
00071
00072
00073 ACE_SDM_helpers::addr_to_string (this->send_addr_, addr_string,
00074 sizeof addr_string, 0);
00075 ACE_DEBUG ((LM_DEBUG,
00076 ACE_LIB_TEXT ("Send addr=%s iface=%s\n"),
00077 addr_string,
00078 this->send_net_if_ ? this->send_net_if_
00079 : ACE_LIB_TEXT ("<default>")));
00080
00081
00082 ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("Subscription list:\n")));
00083
00084 ACE_MT (ACE_GUARD (ACE_SDM_LOCK, guard, this->subscription_list_lock_));
00085 subscription_list_iter_t iter (this->subscription_list_);
00086 for ( ; !iter.done (); iter.advance ())
00087 {
00088 ACE_TCHAR iface_string[MAXNAMELEN + 1];
00089 ip_mreq *pm = iter.next ();
00090
00091
00092 ACE_INET_Addr ip_addr (ACE_static_cast (u_short, 0),
00093 ACE_NTOHL (pm->IMR_MULTIADDR.s_addr));
00094 ACE_SDM_helpers::addr_to_string (ip_addr, addr_string,
00095 sizeof addr_string, 1);
00096
00097
00098 ACE_INET_Addr if_addr (ACE_static_cast (u_short, 0),
00099 ACE_NTOHL (pm->imr_interface.s_addr));
00100 ACE_SDM_helpers::addr_to_string (if_addr, iface_string,
00101 sizeof iface_string, 1);
00102 if (ACE_OS_String::strcmp (iface_string, ACE_LIB_TEXT ("0.0.0.0")) == 0)
00103
00104
00105 ACE_OS_String::strcpy (iface_string, ACE_LIB_TEXT ("<default>"));
00106
00107
00108 ACE_DEBUG ((LM_DEBUG,
00109 ACE_LIB_TEXT ("\taddr=%s iface=%s\n"),
00110 addr_string,
00111 iface_string));
00112 }
00113 # endif
00114 ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00115 }
00116
00117
00118 ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast
00119 (ACE_SOCK_Dgram_Mcast::options opts)
00120 : opts_ (opts),
00121 send_net_if_ (0)
00122 {
00123 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::ACE_SOCK_Dgram_Mcast");
00124 }
00125
00126
00127 ACE_SOCK_Dgram_Mcast::~ACE_SOCK_Dgram_Mcast (void)
00128 {
00129 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::~ACE_SOCK_Dgram_Mcast");
00130
00131
00132 delete [] this->send_net_if_;
00133 this->clear_subs_list ();
00134 }
00135
00136 int
00137 ACE_SOCK_Dgram_Mcast::open (const ACE_INET_Addr &mcast_addr,
00138 const ACE_TCHAR *net_if,
00139 int reuse_addr)
00140 {
00141 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::open");
00142
00143
00144
00145
00146
00147 if (this->get_handle () != ACE_INVALID_HANDLE)
00148 return 0;
00149
00150
00151 if (ACE_SOCK::open (SOCK_DGRAM,
00152 mcast_addr.get_type (),
00153 0,
00154 reuse_addr) == -1)
00155 return -1;
00156
00157 return open_i (mcast_addr, net_if, reuse_addr);
00158 }
00159
00160 int
00161 ACE_SOCK_Dgram_Mcast::open_i (const ACE_INET_Addr &mcast_addr,
00162 const ACE_TCHAR *net_if,
00163 int reuse_addr)
00164 {
00165 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::open_i");
00166
00167
00168 if (reuse_addr)
00169 {
00170 #if defined (SO_REUSEPORT)
00171 int one = 1;
00172 if (this->ACE_SOCK::set_option (SOL_SOCKET,
00173 SO_REUSEPORT,
00174 &one,
00175 sizeof one) == -1)
00176 return -1;
00177 #endif
00178 }
00179
00180
00181
00182
00183
00184 ACE_INET_Addr bind_addy (mcast_addr);
00185 if (ACE_BIT_DISABLED (this->opts_, OPT_BINDADDR_YES))
00186 {
00187
00188 if (bind_addy.set (mcast_addr.get_port_number ()) == -1)
00189 return -1;
00190 }
00191
00192
00193 if (ACE_SOCK_Dgram::shared_open (bind_addy, bind_addy.get_type ()) == -1)
00194 return -1;
00195
00196
00197
00198 ACE_INET_Addr bound_addy;
00199 if (this->get_local_addr (bound_addy) == -1)
00200 {
00201
00202 if (bound_addy.set (bind_addy) == -1)
00203 {
00204
00205 return -1;
00206 }
00207 }
00208
00209 this->send_addr_ = mcast_addr;
00210 this->send_addr_.set_port_number (bound_addy.get_port_number ());
00211 if (net_if)
00212 {
00213 #if defined (IP_MULTICAST_IF) && (IP_MULTICAST_IF != 0)
00214 ip_mreq send_mreq;
00215 if (this->make_multicast_ifaddr (&send_mreq,
00216 mcast_addr,
00217 net_if) == -1)
00218 return -1;
00219 if (this->ACE_SOCK::set_option (IPPROTO_IP,
00220 IP_MULTICAST_IF,
00221 &(send_mreq.imr_interface),
00222 sizeof send_mreq.imr_interface) == -1)
00223 return -1;
00224 this->send_net_if_ = new ACE_TCHAR[ACE_OS_String::strlen (net_if) + 1];
00225 ACE_OS_String::strcpy (this->send_net_if_, net_if);
00226 #else
00227
00228
00229
00230 ACE_DEBUG ((LM_DEBUG,
00231 ACE_LIB_TEXT ("Send interface specification not ")
00232 ACE_LIB_TEXT ("supported - IGNORED.\n")));
00233 #endif // IP_MULTICAST_IF
00234 }
00235
00236 return 0;
00237 }
00238
00239 int
00240 ACE_SOCK_Dgram_Mcast::subscribe_ifs (const ACE_INET_Addr &mcast_addr,
00241 const ACE_TCHAR *net_if,
00242 int reuse_addr)
00243 {
00244 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_ifs");
00245
00246 if (ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL)
00247 && net_if == 0)
00248 {
00249
00250
00251
00252 ACE_INET_Addr *if_addrs = 0;
00253 size_t if_cnt;
00254
00255 if (ACE_Sock_Connect::get_ip_interfaces (if_cnt, if_addrs) != 0)
00256 return -1;
00257
00258 size_t nr_subscribed = 0;
00259
00260 if (if_cnt < 2)
00261 {
00262 if (this->subscribe (mcast_addr,
00263 reuse_addr,
00264 ACE_LIB_TEXT ("0.0.0.0")) == 0)
00265 ++nr_subscribed;
00266 }
00267 else
00268 {
00269
00270
00271 while (if_cnt > 0)
00272 {
00273 --if_cnt;
00274
00275
00276 if (if_addrs[if_cnt].get_ip_address () == INADDR_LOOPBACK)
00277 continue;
00278 if (this->subscribe (mcast_addr,
00279 reuse_addr,
00280 ACE_TEXT_CHAR_TO_TCHAR
00281 (if_addrs[if_cnt].get_host_addr ())) == 0)
00282 ++nr_subscribed;
00283 }
00284 }
00285
00286 delete [] if_addrs;
00287
00288 if (nr_subscribed == 0)
00289 {
00290 errno = ENODEV;
00291 return -1;
00292 }
00293
00294
00295
00296 return 1;
00297 }
00298
00299
00300 if (this->make_multicast_ifaddr (0,
00301 mcast_addr,
00302 net_if) == -1)
00303 return -1;
00304
00305 return 0;
00306 }
00307
00308
00309 int
00310 ACE_SOCK_Dgram_Mcast::subscribe (const ACE_INET_Addr &mcast_addr,
00311 int reuse_addr,
00312 const ACE_TCHAR *net_if,
00313 int protocol_family,
00314 int protocol)
00315 {
00316 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe");
00317
00318 ACE_UNUSED_ARG (protocol_family);
00319 ACE_UNUSED_ARG (protocol);
00320
00321 return this->join (mcast_addr,reuse_addr, net_if);
00322 }
00323
00324 int
00325 ACE_SOCK_Dgram_Mcast::join (const ACE_INET_Addr &mcast_addr,
00326 int reuse_addr,
00327 const ACE_TCHAR *net_if)
00328 {
00329 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::join");
00330 ACE_INET_Addr subscribe_addr = mcast_addr;
00331
00332
00333
00334 u_short def_port_number = this->send_addr_.get_port_number ();
00335 if (subscribe_addr.get_port_number () == 0
00336 && def_port_number != 0)
00337 {
00338 subscribe_addr.set_port_number (def_port_number);
00339 }
00340
00341
00342 u_short sub_port_number = mcast_addr.get_port_number ();
00343 if (sub_port_number != 0
00344 && def_port_number != 0
00345 && sub_port_number != def_port_number)
00346 {
00347 ACE_ERROR ((LM_ERROR,
00348 ACE_LIB_TEXT ("Subscribed port# (%u) different than bound ")
00349 ACE_LIB_TEXT ("port# (%u).\n"),
00350 (u_int) sub_port_number,
00351 (u_int) def_port_number));
00352 errno = ENXIO;
00353 return -1;
00354 }
00355
00356
00357
00358 if (ACE_BIT_ENABLED (this->opts_, OPT_BINDADDR_YES)
00359 && this->send_addr_.get_ip_address () != INADDR_ANY
00360 && this->send_addr_.get_ip_address () != mcast_addr.get_ip_address ())
00361 {
00362 ACE_TCHAR sub_addr_string[MAXNAMELEN + 1];
00363 ACE_TCHAR bound_addr_string[MAXNAMELEN + 1];
00364 ACE_SDM_helpers::addr_to_string (mcast_addr, sub_addr_string,
00365 sizeof sub_addr_string, 1);
00366 ACE_SDM_helpers::addr_to_string (this->send_addr_, bound_addr_string,
00367 sizeof bound_addr_string, 1);
00368 ACE_ERROR ((LM_ERROR,
00369 ACE_LIB_TEXT ("Subscribed address (%s) different than ")
00370 ACE_LIB_TEXT ("bound address (%s).\n"),
00371 sub_addr_string,
00372 bound_addr_string));
00373 errno = ENXIO;
00374 return -1;
00375 }
00376
00377
00378 int result = this->subscribe_i (subscribe_addr, reuse_addr, net_if);
00379
00380 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00381 if (result == 0)
00382 {
00383
00384
00385
00386 ip_mreq *pmreq = new ip_mreq;
00387
00388 if (this->make_multicast_ifaddr (pmreq, subscribe_addr, net_if) != -1)
00389 {
00390 ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
00391 this->subscription_list_lock_, -1));
00392 this->subscription_list_.insert_tail (pmreq);
00393 return 0;
00394 }
00395
00396
00397 delete pmreq;
00398 }
00399 #endif
00400
00401 return result >= 0 ? 0 : result;
00402 }
00403
00404
00405 int
00406 ACE_SOCK_Dgram_Mcast::subscribe_i (const ACE_INET_Addr &mcast_addr,
00407 int reuse_addr,
00408 const ACE_TCHAR *net_if)
00409 {
00410 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::subscribe_i");
00411 ip_mreq mreq;
00412
00413
00414
00415 if (this->open (mcast_addr,
00416 net_if,
00417 reuse_addr) == -1)
00418 return -1;
00419
00420
00421 if (net_if == 0)
00422 {
00423 int result = this->subscribe_ifs (mcast_addr,
00424 net_if,
00425 reuse_addr);
00426
00427 if (result != 0)
00428 return result;
00429 }
00430
00431
00432 if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00433 return -1;
00434
00435
00436
00437 else if (this->ACE_SOCK::set_option (IPPROTO_IP,
00438 IP_ADD_MEMBERSHIP,
00439 &mreq,
00440 sizeof mreq) == -1)
00441 return -1;
00442
00443 return 0;
00444 }
00445
00446 int
00447 ACE_SOCK_Dgram_Mcast::unsubscribe_ifs (const ACE_INET_Addr &mcast_addr,
00448 const ACE_TCHAR *net_if)
00449 {
00450 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_ifs");
00451
00452
00453 if (ACE_BIT_ENABLED (this->opts_, OPT_NULLIFACE_ALL)
00454 && net_if == 0)
00455 {
00456
00457
00458
00459 ACE_INET_Addr *if_addrs = 0;
00460 size_t if_cnt;
00461
00462
00463
00464
00465
00466
00467 if (ACE_Sock_Connect::get_ip_interfaces (if_cnt, if_addrs) != 0)
00468 return -1;
00469
00470 size_t nr_unsubscribed = 0;
00471
00472 if (if_cnt < 2)
00473 {
00474 if (this->leave (mcast_addr,
00475 ACE_LIB_TEXT ("0.0.0.0")) == 0)
00476 ++nr_unsubscribed;
00477 }
00478 else
00479 {
00480 while (if_cnt > 0)
00481 {
00482 --if_cnt;
00483
00484 if (if_addrs[if_cnt].get_ip_address () == INADDR_LOOPBACK)
00485 continue;
00486 if (this->leave (mcast_addr,
00487 ACE_TEXT_CHAR_TO_TCHAR
00488 (if_addrs[if_cnt].get_host_addr ())) == 0)
00489 ++nr_unsubscribed;
00490 }
00491 }
00492
00493 delete [] if_addrs;
00494
00495 if (nr_unsubscribed == 0)
00496 {
00497 errno = ENODEV;
00498 return -1;
00499 }
00500
00501 return 1;
00502 }
00503
00504 return 0;
00505 }
00506
00507
00508
00509
00510
00511
00512 int
00513 ACE_SOCK_Dgram_Mcast::unsubscribe (const ACE_INET_Addr &mcast_addr,
00514 const ACE_TCHAR *net_if,
00515 int protocol_family,
00516 int protocol)
00517 {
00518 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe");
00519
00520 ACE_UNUSED_ARG (protocol_family);
00521 ACE_UNUSED_ARG (protocol);
00522
00523 return this->leave (mcast_addr, net_if);
00524 }
00525
00526 int
00527 ACE_SOCK_Dgram_Mcast::leave (const ACE_INET_Addr &mcast_addr,
00528 const ACE_TCHAR *net_if)
00529 {
00530 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::leave");
00531
00532 int result = this->unsubscribe_i (mcast_addr,
00533 net_if);
00534
00535 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00536
00537
00538 ip_mreq tgt_mreq;
00539 if (this->make_multicast_ifaddr (&tgt_mreq,
00540 mcast_addr,
00541 net_if) != -1)
00542 {
00543 ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
00544 this->subscription_list_lock_, -1));
00545 subscription_list_iter_t iter (this->subscription_list_);
00546 for (; !iter.done (); iter.advance ())
00547 {
00548 ip_mreq *pm = iter.next ();
00549 if (ACE_SDM_helpers::is_equal (*pm, tgt_mreq))
00550 {
00551 iter.remove ();
00552 delete pm;
00553 break;
00554 }
00555 }
00556 }
00557 #endif
00558
00559 return result >= 0 ? 0 : result;
00560 }
00561
00562
00563 int
00564 ACE_SOCK_Dgram_Mcast::unsubscribe_i (const ACE_INET_Addr &mcast_addr,
00565 const ACE_TCHAR *net_if)
00566 {
00567 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe_i");
00568
00569 int result = this->unsubscribe_ifs (mcast_addr,
00570 net_if);
00571
00572
00573 if (result != 0)
00574 return result;
00575
00576
00577 ip_mreq mreq;
00578 if (this->make_multicast_ifaddr (&mreq, mcast_addr, net_if) == -1)
00579 {
00580 return -1;
00581 }
00582
00583
00584
00585 else if (ACE_SOCK::set_option (IPPROTO_IP,
00586 IP_DROP_MEMBERSHIP,
00587 &mreq,
00588 sizeof mreq) == -1)
00589 {
00590 return -1;
00591 }
00592
00593 return 0;
00594 }
00595
00596 int
00597 ACE_SOCK_Dgram_Mcast::unsubscribe (void)
00598 {
00599 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::unsubscribe");
00600
00601
00602
00603
00604
00605
00606
00607
00608 ACE_ERROR_RETURN ((LM_INFO,
00609 ACE_LIB_TEXT ("ACE_SOCK_Dgram_Mcast::unsubscribe (void) ")
00610 ACE_LIB_TEXT ("has been deprecated. You must either ")
00611 ACE_LIB_TEXT ("close to socket to unsubscribe to all ")
00612 ACE_LIB_TEXT ("or unsubscribe to each individually.\n")),
00613 0);
00614 }
00615
00616 int
00617 ACE_SOCK_Dgram_Mcast::clear_subs_list (void)
00618 {
00619 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::clear_subs_list");
00620 int result = 0;
00621
00622 #if defined (ACE_SOCK_DGRAM_MCAST_DUMPABLE)
00623 ACE_MT (ACE_GUARD_RETURN (ACE_SDM_LOCK, guard,
00624 this->subscription_list_lock_, -1));
00625 subscription_list_iter_t iter (this->subscription_list_);
00626 for (; !iter.done (); )
00627 {
00628 ip_mreq *pm = iter.next ();
00629 iter.remove ();
00630 delete pm;
00631 }
00632 #endif
00633 return result;
00634 }
00635
00636 int
00637 ACE_SOCK_Dgram_Mcast::make_multicast_ifaddr (ip_mreq *ret_mreq,
00638 const ACE_INET_Addr &mcast_addr,
00639 const ACE_TCHAR *net_if)
00640 {
00641 ACE_TRACE ("ACE_SOCK_Dgram_Mcast::make_multicast_ifaddr");
00642 ip_mreq lmreq;
00643 if (net_if != 0)
00644 {
00645 #if defined (ACE_WIN32)
00646
00647 ACE_INET_Addr interface_addr;
00648 if (interface_addr.set (mcast_addr.get_port_number (), net_if) == -1)
00649 return -1;
00650 lmreq.imr_interface.s_addr =
00651 ACE_HTONL (interface_addr.get_ip_address ());
00652 #else
00653 ifreq if_address;
00654
00655 #if defined (ACE_PSOS)
00656
00657 if_address.ifr_ifno = ACE_OS::atoi (net_if);
00658 #else
00659 ACE_OS_String::strcpy (if_address.ifr_name, net_if);
00660 #endif
00661
00662 if (ACE_OS::ioctl (this->get_handle (),
00663 SIOCGIFADDR,
00664 &if_address) == -1)
00665 return -1;
00666
00667 sockaddr_in *socket_address;
00668 socket_address = ACE_reinterpret_cast (sockaddr_in*,
00669 &if_address.ifr_addr);
00670 lmreq.imr_interface.s_addr = socket_address->sin_addr.s_addr;
00671 #endif
00672 }
00673 else
00674 lmreq.imr_interface.s_addr = INADDR_ANY;
00675
00676 lmreq.IMR_MULTIADDR.s_addr = ACE_HTONL (mcast_addr.get_ip_address ());
00677
00678
00679 if (ret_mreq)
00680 *ret_mreq = lmreq;
00681
00682 return 0;
00683 }
00684