Merge pull request #2301 from sonndinh/remove-dup-reactor-functions
[ACE_TAO.git] / ACE / ace / SOCK_Dgram.cpp
blob100181430254c38bf56e74836327a7a8c4df234e
1 #include "ace/SOCK_Dgram.h"
3 #include "ace/Log_Category.h"
4 #include "ace/INET_Addr.h"
5 #include "ace/ACE.h"
6 #include "ace/OS_NS_string.h"
7 #include "ace/OS_Memory.h"
8 #include "ace/OS_NS_ctype.h"
9 #include "ace/os_include/net/os_if.h"
10 #include "ace/Truncate.h"
11 #if defined (ACE_HAS_ALLOC_HOOKS)
12 # include "ace/Malloc_Base.h"
13 #endif /* ACE_HAS_ALLOC_HOOKS */
15 #if !defined (__ACE_INLINE__)
16 # include "ace/SOCK_Dgram.inl"
17 #endif /* __ACE_INLINE__ */
19 #if defined (ACE_HAS_IPV6) && defined (ACE_WIN32)
20 #include /**/ <iphlpapi.h>
21 #endif
23 // This is a workaround for platforms with non-standard
24 // definitions of the ip_mreq structure
25 #if ! defined (IMR_MULTIADDR)
26 #define IMR_MULTIADDR imr_multiaddr
27 #endif /* ! defined (IMR_MULTIADDR) */
29 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
31 ACE_ALLOC_HOOK_DEFINE (ACE_SOCK_Dgram)
33 void
34 ACE_SOCK_Dgram::dump () const
36 #if defined (ACE_HAS_DUMP)
37 ACE_TRACE ("ACE_SOCK_Dgram::dump");
38 #endif /* ACE_HAS_DUMP */
41 // Allows a client to read from a socket without having to provide a
42 // buffer to read. This method determines how much data is in the
43 // socket, allocates a buffer of this size, reads in the data, and
44 // returns the number of bytes read.
46 ssize_t
47 ACE_SOCK_Dgram::recv (iovec *io_vec,
48 ACE_Addr &addr,
49 int flags,
50 const ACE_Time_Value *timeout) const
52 ACE_TRACE ("ACE_SOCK_Dgram::recv");
53 #if defined (FIONREAD)
54 if( ACE::handle_read_ready (this->get_handle (), timeout) != 1 )
56 return -1;
59 sockaddr *saddr = (sockaddr *) addr.get_addr ();
60 int addr_len = addr.get_size ();
61 int inlen;
63 if (ACE_OS::ioctl (this->get_handle (),
64 FIONREAD,
65 &inlen) == -1)
66 return -1;
67 else if (inlen > 0)
69 #if defined (ACE_HAS_ALLOC_HOOKS)
70 ACE_ALLOCATOR_RETURN (io_vec->iov_base,
71 static_cast<char*>(ACE_Allocator::instance()->malloc(sizeof(char) * inlen)),
72 -1);
73 #else
74 ACE_NEW_RETURN (io_vec->iov_base,
75 char[inlen],
76 -1);
77 #endif /* ACE_HAS_ALLOC_HOOKS */
79 ssize_t rcv_len = ACE_OS::recvfrom (this->get_handle (),
80 (char *) io_vec->iov_base,
81 inlen,
82 flags,
83 (sockaddr *) saddr,
84 &addr_len);
85 if (rcv_len < 0)
87 #if defined (ACE_HAS_ALLOC_HOOKS)
88 ACE_Allocator::instance()->free(io_vec->iov_base);
89 #else
90 delete [] (char *)io_vec->iov_base;
91 #endif /* ACE_HAS_ALLOC_HOOKS */
92 io_vec->iov_base = 0;
94 else
96 io_vec->iov_len = ACE_Utils::truncate_cast<u_long> (rcv_len);
97 addr.set_size (addr_len);
99 return rcv_len;
101 else
102 return 0;
103 #else
104 ACE_UNUSED_ARG (flags);
105 ACE_UNUSED_ARG (addr);
106 ACE_UNUSED_ARG (io_vec);
107 ACE_UNUSED_ARG (timeout);
108 ACE_NOTSUP_RETURN (-1);
109 #endif /* FIONREAD */
112 // Here's the shared open function. Note that if we are using the
113 // PF_INET protocol family and the address of LOCAL == the address of
114 // the special variable SAP_ANY then we are going to arbitrarily bind
115 // to a portnumber.
118 ACE_SOCK_Dgram::shared_open (const ACE_Addr &local,
119 int protocol_family,
120 int ipv6_only)
122 ACE_TRACE ("ACE_SOCK_Dgram::shared_open");
123 bool error = false;
124 #if defined (ACE_HAS_IPV6)
125 int setting = !!ipv6_only;
126 if (protocol_family == PF_INET6 &&
127 -1 == ACE_OS::setsockopt (this->get_handle (),
128 IPPROTO_IPV6,
129 IPV6_V6ONLY,
130 (char *)&setting,
131 sizeof (setting)))
133 this->close();
134 return -1;
136 #else
137 ACE_UNUSED_ARG (ipv6_only);
138 #endif /* defined (ACE_HAS_IPV6) */
140 if (local == ACE_Addr::sap_any)
142 if (protocol_family == PF_INET
143 #if defined (ACE_HAS_IPV6)
144 || protocol_family == PF_INET6
145 #endif /* ACE_HAS_IPV6 */
148 if (ACE::bind_port (this->get_handle (), INADDR_ANY, protocol_family) == -1)
149 error = true;
152 else if (ACE_OS::bind (this->get_handle (),
153 reinterpret_cast<sockaddr *> (local.get_addr ()),
154 local.get_size ()) == -1)
155 error = true;
157 if (error)
158 this->close ();
160 return error ? -1 : 0;
164 ACE_SOCK_Dgram::open (const ACE_Addr &local,
165 int protocol_family,
166 int protocol,
167 ACE_Protocol_Info *protocolinfo,
168 ACE_SOCK_GROUP g,
169 u_long flags,
170 int reuse_addr,
171 int ipv6_only)
173 if (ACE_SOCK::open (SOCK_DGRAM,
174 protocol_family,
175 protocol,
176 protocolinfo,
178 flags,
179 reuse_addr) == -1)
180 return -1;
181 else if (this->shared_open (local, protocol_family, ipv6_only) == -1)
182 return -1;
183 else
184 return 0;
187 // Here's the general-purpose open routine.
190 ACE_SOCK_Dgram::open (const ACE_Addr &local,
191 int protocol_family,
192 int protocol,
193 int reuse_addr,
194 int ipv6_only)
196 ACE_TRACE ("ACE_SOCK_Dgram::open");
198 if (local != ACE_Addr::sap_any)
199 protocol_family = local.get_type ();
200 else if (protocol_family == PF_UNSPEC)
202 #if defined (ACE_HAS_IPV6)
203 protocol_family = ACE::ipv6_enabled () ? PF_INET6 : PF_INET;
204 #else
205 protocol_family = PF_INET;
206 #endif /* ACE_HAS_IPV6 */
209 if (ACE_SOCK::open (SOCK_DGRAM, protocol_family, protocol, reuse_addr) == -1)
210 return -1;
211 else
212 return this->shared_open (local, protocol_family, ipv6_only);
215 // Here's the general-purpose constructor used by a connectionless
216 // datagram ``server''...
218 ACE_SOCK_Dgram::ACE_SOCK_Dgram (const ACE_Addr &local,
219 int protocol_family,
220 int protocol,
221 int reuse_addr,
222 int ipv6_only)
224 ACE_TRACE ("ACE_SOCK_Dgram::ACE_SOCK_Dgram");
226 if (this->open (local,
227 protocol_family,
228 protocol,
229 reuse_addr,
230 ipv6_only) == -1)
231 ACELIB_ERROR ((LM_ERROR,
232 ACE_TEXT ("%p\n"),
233 ACE_TEXT ("ACE_SOCK_Dgram")));
236 ACE_SOCK_Dgram::ACE_SOCK_Dgram (const ACE_Addr &local,
237 int protocol_family,
238 int protocol,
239 ACE_Protocol_Info *protocolinfo,
240 ACE_SOCK_GROUP g,
241 u_long flags,
242 int reuse_addr,
243 int ipv6_only)
245 ACE_TRACE ("ACE_SOCK_Dgram::ACE_SOCK_Dgram");
246 if (this->open (local,
247 protocol_family,
248 protocol,
249 protocolinfo,
251 flags,
252 reuse_addr,
253 ipv6_only) == -1)
254 ACELIB_ERROR ((LM_ERROR,
255 ACE_TEXT ("%p\n"),
256 ACE_TEXT ("ACE_SOCK_Dgram")));
259 #if defined (ACE_HAS_MSG)
260 // Send an iovec of size N to ADDR as a datagram (connectionless
261 // version).
263 ssize_t
264 ACE_SOCK_Dgram::send (const iovec iov[],
265 int n,
266 const ACE_Addr &addr,
267 int flags) const
269 ACE_TRACE ("ACE_SOCK_Dgram::send");
270 msghdr send_msg;
272 send_msg.msg_iov = (iovec *) iov;
273 send_msg.msg_iovlen = n;
274 #if defined (ACE_HAS_SOCKADDR_MSG_NAME)
275 send_msg.msg_name = (struct sockaddr *) addr.get_addr ();
276 #else
277 send_msg.msg_name = (char *) addr.get_addr ();
278 #endif /* ACE_HAS_SOCKADDR_MSG_NAME */
279 send_msg.msg_namelen = addr.get_size ();
281 #if defined (ACE_HAS_4_4BSD_SENDMSG_RECVMSG)
282 send_msg.msg_control = 0;
283 send_msg.msg_controllen = 0;
284 send_msg.msg_flags = 0;
285 #elif !defined ACE_LACKS_SENDMSG
286 send_msg.msg_accrights = 0;
287 send_msg.msg_accrightslen = 0;
288 #endif /* ACE_HAS_4_4BSD_SENDMSG_RECVMSG */
290 #ifdef ACE_WIN32
291 send_msg.msg_control = 0;
292 send_msg.msg_controllen = 0;
293 #endif
295 return ACE_OS::sendmsg (this->get_handle (), &send_msg, flags);
298 // Recv an iovec of size N to ADDR as a datagram (connectionless
299 // version).
300 ssize_t
301 ACE_SOCK_Dgram::recv (iovec iov[],
302 int n,
303 ACE_Addr &addr,
304 int flags,
305 ACE_INET_Addr *to_addr) const
307 ACE_TRACE ("ACE_SOCK_Dgram::recv");
308 msghdr recv_msg;
310 #if defined (ACE_HAS_4_4BSD_SENDMSG_RECVMSG) || defined ACE_WIN32
311 #define ACE_USE_MSG_CONTROL
312 union control_buffer {
313 cmsghdr control_msg_header;
314 #if defined (IP_RECVDSTADDR) && !defined (ACE_HAS_NONCONST_CMSG_SPACE)
315 u_char padding[ACE_CMSG_SPACE (sizeof (in_addr))];
316 #elif defined (IP_PKTINFO) && !defined (ACE_HAS_NONCONST_CMSG_SPACE)
317 u_char padding[ACE_CMSG_SPACE (sizeof (in_pktinfo))];
318 #endif
319 #if defined (ACE_HAS_IPV6) && !defined (ACE_HAS_NONCONST_CMSG_SPACE)
320 u_char padding6[ACE_CMSG_SPACE (sizeof (in6_pktinfo))];
321 #endif
322 } cbuf;
323 #else
324 ACE_UNUSED_ARG (to_addr);
325 #endif
327 recv_msg.msg_iov = (iovec *) iov;
328 recv_msg.msg_iovlen = n;
329 #if defined (ACE_HAS_SOCKADDR_MSG_NAME)
330 recv_msg.msg_name = (struct sockaddr *) addr.get_addr ();
331 #else
332 recv_msg.msg_name = (char *) addr.get_addr ();
333 #endif /* ACE_HAS_SOCKADDR_MSG_NAME */
334 recv_msg.msg_namelen = addr.get_size ();
336 #ifdef ACE_USE_MSG_CONTROL
337 recv_msg.msg_control = to_addr ? std::addressof(cbuf) : nullptr;
338 recv_msg.msg_controllen = to_addr ? sizeof (cbuf) : 0;
339 #elif !defined ACE_LACKS_SENDMSG
340 recv_msg.msg_accrights = nullptr;
341 recv_msg.msg_accrightslen = 0;
342 #endif
344 ssize_t const status = ACE_OS::recvmsg (this->get_handle (), std::addressof(recv_msg), flags);
345 addr.set_size (recv_msg.msg_namelen);
346 addr.set_type (((sockaddr_in *) addr.get_addr())->sin_family);
348 #ifdef ACE_USE_MSG_CONTROL
349 if (to_addr) {
350 this->get_local_addr (*to_addr);
351 if (to_addr->get_type() == AF_INET) {
352 #if (defined (IP_RECVDSTADDR) || defined (IP_PKTINFO)) && !defined (ACE_HAS_NONCONST_CMSG_SPACE)
353 for (cmsghdr *ptr = ACE_CMSG_FIRSTHDR (&recv_msg); ptr; ptr = ACE_CMSG_NXTHDR (&recv_msg, ptr)) {
354 #if defined (IP_RECVDSTADDR)
355 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_RECVDSTADDR) {
356 to_addr->set_address ((const char *) (ACE_CMSG_DATA (ptr)),
357 sizeof (struct in_addr),
359 break;
361 #else
362 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO) {
363 to_addr->set_address ((const char *) &(((in_pktinfo *) (ACE_CMSG_DATA (ptr)))->ipi_addr),
364 sizeof (struct in_addr),
366 break;
368 #endif
370 #endif
372 #if defined (ACE_HAS_IPV6) && defined (IPV6_PKTINFO) && !defined (ACE_HAS_NONCONST_CMSG_SPACE)
373 else if (to_addr->get_type() == AF_INET6) {
374 for (cmsghdr *ptr = ACE_CMSG_FIRSTHDR (&recv_msg); ptr; ptr = ACE_CMSG_NXTHDR (&recv_msg, ptr)) {
375 if (ptr->cmsg_level == IPPROTO_IPV6 && ptr->cmsg_type == IPV6_PKTINFO) {
376 to_addr->set_address ((const char *) &(((in6_pktinfo *)(ACE_CMSG_DATA (ptr)))->ipi6_addr),
377 sizeof (struct in6_addr),
380 break;
384 #endif
386 #endif
388 return status;
391 #else /* ACE_HAS_MSG */
393 /// Send an iovec of size N to ADDR as a datagram (connectionless
394 /// version).
395 ssize_t
396 ACE_SOCK_Dgram::send (const iovec iov[],
397 int n,
398 const ACE_Addr &addr,
399 int flags) const
401 ACE_TRACE ("ACE_SOCK_Dgram::send");
403 size_t length = 0;
404 int i;
406 // Determine the total length of all the buffers in <iov>.
407 for (i = 0; i < n; i++)
408 #if ! (defined(ACE_LACKS_IOVEC) || defined(ACE_LINUX))
409 // The iov_len is unsigned on Linux and when using the ACE iovec struct. If we go
410 // ahead and try the if, it will emit a warning.
411 if (iov[i].iov_len < 0)
412 return -1;
413 else
414 #endif
415 length += iov[i].iov_len;
417 char *buf = 0;
419 #if defined (ACE_HAS_ALLOCA)
420 buf = alloca (length);
421 #else
422 # ifdef ACE_HAS_ALLOC_HOOKS
423 ACE_ALLOCATOR_RETURN (buf, (buf *)
424 ACE_Allocator::instance ()->malloc (length), -1);
425 # else
426 ACE_NEW_RETURN (buf,
427 char[length],
428 -1);
429 # endif /* ACE_HAS_ALLOC_HOOKS */
430 #endif /* !defined (ACE_HAS_ALLOCA) */
432 char *ptr = buf;
434 for (i = 0; i < n; i++)
436 ACE_OS::memcpy (ptr, iov[i].iov_base, iov[i].iov_len);
437 ptr += iov[i].iov_len;
440 ssize_t result = ACE_SOCK_Dgram::send (buf, length, addr, flags);
441 #if !defined (ACE_HAS_ALLOCA)
442 # ifdef ACE_HAS_ALLOC_HOOKS
443 ACE_Allocator::instance ()->free (buf);
444 # else
445 delete [] buf;
446 # endif /* ACE_HAS_ALLOC_HOOKS */
447 #endif /* !defined (ACE_HAS_ALLOCA) */
448 return result;
451 // Recv an iovec of size N to ADDR as a datagram (connectionless
452 // version).
454 ssize_t
455 ACE_SOCK_Dgram::recv (iovec iov[],
456 int n,
457 ACE_Addr &addr,
458 int flags,
459 ACE_INET_Addr *to_addr) const
461 ACE_TRACE ("ACE_SOCK_Dgram::recv");
463 ssize_t length = 0;
464 int i;
466 ACE_UNUSED_ARG (to_addr);
468 for (i = 0; i < n; i++)
469 #if ! (defined(ACE_LACKS_IOVEC) || defined(ACE_LINUX))
470 // The iov_len is unsigned on Linux and when using the ACE iovec struct. If we go
471 // ahead and try the if, it will emit a warning.
472 if (iov[i].iov_len < 0)
473 return -1;
474 else
475 #endif
476 length += iov[i].iov_len;
478 char *buf = nullptr;
480 #if defined (ACE_HAS_ALLOCA)
481 buf = alloca (length);
482 #else
483 # ifdef ACE_HAS_ALLOC_HOOKS
484 ACE_ALLOCATOR_RETURN (buf, (buf *)
485 ACE_Allocator::instance ()->malloc (length), -1);
486 # else
487 ACE_NEW_RETURN (buf,
488 char[length],
489 -1);
490 # endif /* ACE_HAS_ALLOC_HOOKS */
491 #endif /* !defined (ACE_HAS_ALLOCA) */
493 length = ACE_SOCK_Dgram::recv (buf, length, addr, flags);
495 if (length != -1)
497 char *ptr = buf;
498 int copyn = length;
500 for (i = 0; i < n && copyn > 0; i++)
502 ACE_OS::memcpy (iov[i].iov_base, ptr,
503 // iov_len is int on some platforms, size_t on others
504 copyn > (int) iov[i].iov_len
505 ? (size_t) iov[i].iov_len
506 : (size_t) copyn);
507 ptr += iov[i].iov_len;
508 copyn -= iov[i].iov_len;
512 #if !defined (ACE_HAS_ALLOCA)
513 # ifdef ACE_HAS_ALLOC_HOOKS
514 ACE_Allocator::instance ()->free (buf);
515 # else
516 delete [] buf;
517 # endif /* ACE_HAS_ALLOC_HOOKS */
518 #endif /* !defined (ACE_HAS_ALLOCA) */
519 return length;
522 #endif /* ACE_HAS_MSG */
524 ssize_t
525 ACE_SOCK_Dgram::recv (void *buf,
526 size_t n,
527 ACE_Addr &addr,
528 int flags,
529 const ACE_Time_Value *timeout) const
531 if( ACE::handle_read_ready (this->get_handle (), timeout) == 1 )
533 // Goes fine, call <recv> to get data
534 return this->recv (buf, n, addr, flags);
536 else
538 return -1;
542 ssize_t
543 ACE_SOCK_Dgram::send (const void *buf,
544 size_t n,
545 const ACE_Addr &addr,
546 int flags,
547 const ACE_Time_Value *timeout) const
549 // Check the status of the current socket.
550 if( ACE::handle_write_ready (this->get_handle (), timeout) == 1 )
552 // Goes fine, call <send> to transmit the data.
553 return this->send (buf, n, addr, flags);
555 else
557 return -1;
562 ACE_SOCK_Dgram::set_nic (const ACE_TCHAR *net_if,
563 int addr_family)
565 #if defined (IP_MULTICAST_IF) && (IP_MULTICAST_IF != 0)
566 # if defined (ACE_HAS_IPV6)
567 bool ipv6_mif_set = false;
568 if (addr_family == AF_INET6 || addr_family == AF_UNSPEC)
570 ACE_INET_Addr addr;
571 addr.set (static_cast<u_short> (0), ACE_IPV6_ANY);
572 ipv6_mreq send_mreq;
573 if (this->make_multicast_ifaddr6 (&send_mreq,
574 addr,
575 net_if) == -1)
576 return -1;
578 // Only let this attempt to set unknown interface when INET6 is
579 // specifically requested. Otherwise we will just try INET.
580 if (send_mreq.ipv6mr_interface != 0 || addr_family == AF_INET6)
582 if (this->ACE_SOCK::set_option
583 (IPPROTO_IPV6, IPV6_MULTICAST_IF,
584 &(send_mreq.ipv6mr_interface),
585 sizeof send_mreq.ipv6mr_interface) == -1)
586 return -1;
588 ipv6_mif_set = send_mreq.ipv6mr_interface != 0;
591 # if defined (ACE_WIN32)
592 // For Win32 net_if is distintly different between INET6 and INET
593 // so it is always either an INET6 if or an INET if.
594 if (!ipv6_mif_set && (addr_family == AF_INET || addr_family == AF_UNSPEC))
595 # else
596 if (addr_family == AF_INET || addr_family == AF_UNSPEC)
597 # endif
599 ACE_INET_Addr addr (static_cast<u_short> (0));
600 ip_mreq send_mreq;
601 if (this->make_multicast_ifaddr (&send_mreq, addr, net_if) == -1)
603 if (!ipv6_mif_set)
604 return -1;
606 else if (this->ACE_SOCK::set_option (IPPROTO_IP,
607 IP_MULTICAST_IF,
608 &(send_mreq.imr_interface),
609 sizeof send_mreq.imr_interface) == -1)
611 if (!ipv6_mif_set)
612 return -1;
615 # else /* ACE_HAS_IPV6 */
616 ACE_UNUSED_ARG (addr_family);
617 ACE_INET_Addr addr (static_cast<u_short> (0));
618 ip_mreq send_mreq;
619 if (this->make_multicast_ifaddr (&send_mreq,
620 addr,
621 net_if) == -1)
622 return -1;
623 if (this->ACE_SOCK::set_option (IPPROTO_IP,
624 IP_MULTICAST_IF,
625 &(send_mreq.imr_interface),
626 sizeof send_mreq.imr_interface) == -1)
627 return -1;
628 # endif /* !ACE_HAS_IPV6 */
629 #else /* IP_MULTICAST_IF */
630 // Send interface option not supported - ignore it.
631 // (We may have been invoked by ::subscribe, so we have to allow
632 // a non-null interface parameter in this function.)
633 ACE_UNUSED_ARG (net_if);
634 ACE_UNUSED_ARG (addr_family);
635 ACELIB_DEBUG ((LM_DEBUG,
636 ACE_TEXT ("Send interface specification not ")
637 ACE_TEXT ("supported - IGNORED.\n")));
638 #endif /* !IP_MULTICAST_IF */
640 return 0;
644 ACE_SOCK_Dgram::make_multicast_ifaddr (ip_mreq *ret_mreq,
645 const ACE_INET_Addr &mcast_addr,
646 const ACE_TCHAR *net_if)
648 ACE_TRACE ("ACE_SOCK_Dgram::make_multicast_ifaddr");
649 ip_mreq lmreq; // Scratch copy.
650 if (net_if != 0)
652 #if defined (ACE_WIN32)
653 // This port number is not necessary, just convenient
654 ACE_INET_Addr interface_addr;
655 if (interface_addr.set (mcast_addr.get_port_number (), net_if) == -1)
657 IP_ADAPTER_ADDRESSES tmp_addrs;
658 // Initial call to determine actual memory size needed
659 ULONG bufLen = 0;
660 if (::GetAdaptersAddresses (AF_INET, 0, 0, &tmp_addrs, &bufLen)
661 != ERROR_BUFFER_OVERFLOW)
663 return -1; // With output bufferlength 0 this can't be right.
666 // Get required output buffer and retrieve info for real.
667 char *buf = 0;
668 ACE_NEW_RETURN (buf, char[bufLen], -1);
669 PIP_ADAPTER_ADDRESSES pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
670 if (::GetAdaptersAddresses (AF_INET, 0, 0, pAddrs, &bufLen) != NO_ERROR)
672 delete[] buf; // clean up
673 return -1;
676 interface_addr = ACE_INET_Addr ();
677 int set_result = -1;
678 while (pAddrs && set_result == -1)
680 if (ACE_OS::strcmp (ACE_TEXT_ALWAYS_CHAR (net_if), pAddrs->AdapterName) == 0 ||
681 ACE_OS::strcmp (ACE_TEXT_ALWAYS_WCHAR (net_if), pAddrs->FriendlyName) == 0)
683 PIP_ADAPTER_UNICAST_ADDRESS pUnicast = pAddrs->FirstUnicastAddress;
684 LPSOCKADDR sa = pUnicast->Address.lpSockaddr;
685 if (sa->sa_family == AF_INET)
687 const void *addr = &(((sockaddr_in *)sa)->sin_addr);
688 set_result = interface_addr.set_address ((const char*) addr, 4, 0);
691 pAddrs = pAddrs->Next;
694 delete[] buf; // clean up
695 if (set_result == -1)
697 errno = EINVAL;
698 return -1;
701 lmreq.imr_interface.s_addr =
702 ACE_HTONL (interface_addr.get_ip_address ());
703 #else
704 ifreq if_address;
705 ACE_OS::strsncpy (if_address.ifr_name, ACE_TEXT_ALWAYS_CHAR (net_if), (sizeof if_address.ifr_name));
706 if (ACE_OS::ioctl (this->get_handle (),
707 SIOCGIFADDR,
708 &if_address) == -1)
710 // The net_if name failed to be found. It seems that older linux
711 // kernals only support the actual interface name (eg. "eth0"),
712 // not the IP address string of the interface (eg. "192.168.0.1"),
713 // which newer kernals seem to automatically translate.
714 // So assume that we have been given an IP Address and translate
715 // that instead, similar to the above for windows.
716 ACE_INET_Addr interface_addr;
717 if (interface_addr.set (mcast_addr.get_port_number (), net_if) == -1)
718 return -1; // Still doesn't work, unknown device specified.
719 lmreq.imr_interface.s_addr =
720 ACE_HTONL (interface_addr.get_ip_address ());
722 else
724 sockaddr_in *socket_address =
725 reinterpret_cast<sockaddr_in*> (&if_address.ifr_addr);
726 lmreq.imr_interface.s_addr = socket_address->sin_addr.s_addr;
728 #endif /* ACE_WIN32 */
730 else
731 lmreq.imr_interface.s_addr = INADDR_ANY;
733 lmreq.IMR_MULTIADDR.s_addr = ACE_HTONL (mcast_addr.get_ip_address ());
735 // Set return info, if requested.
736 if (ret_mreq)
737 *ret_mreq = lmreq;
739 return 0;
742 #if defined (ACE_HAS_IPV6)
743 // XXX: This will not work on any operating systems that do not support
744 // if_nametoindex or that is not Win32 >= Windows XP/Server 2003
746 ACE_SOCK_Dgram::make_multicast_ifaddr6 (ipv6_mreq *ret_mreq,
747 const ACE_INET_Addr &mcast_addr,
748 const ACE_TCHAR *net_if)
750 ACE_TRACE ("ACE_SOCK_Dgram::make_multicast_ifaddr6");
751 ipv6_mreq lmreq; // Scratch copy.
753 ACE_OS::memset (&lmreq, 0, sizeof (lmreq));
755 #if defined (ACE_WIN32) || !defined (ACE_LACKS_IF_NAMETOINDEX)
756 if (net_if != 0)
758 #if defined (ACE_WIN32)
759 int if_ix = 0;
760 bool const num_if =
761 ACE_OS::ace_isdigit (net_if[0]) &&
762 (if_ix = ACE_OS::atoi (net_if)) > 0;
764 ULONG bufLen = 15000; // Initial size as per Microsoft
765 char *buf = nullptr;
766 ACE_NEW_RETURN (buf, char[bufLen], -1);
767 DWORD dwRetVal = 0;
768 ULONG iterations = 0;
769 ULONG const maxTries = 3;
770 PIP_ADAPTER_ADDRESSES pAddrs;
773 pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
774 dwRetVal = ::GetAdaptersAddresses (AF_INET6, 0, 0, pAddrs, &bufLen);
775 if (dwRetVal == ERROR_BUFFER_OVERFLOW)
777 delete[] buf;
778 ACE_NEW_RETURN (buf, char[bufLen], -1);
779 ++iterations;
781 else
783 break;
785 } while (dwRetVal == ERROR_BUFFER_OVERFLOW && iterations < maxTries);
787 if (dwRetVal != NO_ERROR)
789 delete[] buf;
790 errno = EINVAL;
791 return -1;
794 while (pAddrs)
796 if ((num_if && pAddrs->Ipv6IfIndex == static_cast<unsigned int>(if_ix))
797 || (!num_if &&
798 (ACE_OS::strcmp (ACE_TEXT_ALWAYS_CHAR (net_if), pAddrs->AdapterName) == 0
799 || ACE_OS::strcmp (ACE_TEXT_ALWAYS_WCHAR (net_if), pAddrs->FriendlyName) == 0)))
801 lmreq.ipv6mr_interface = pAddrs->Ipv6IfIndex;
802 break;
805 pAddrs = pAddrs->Next;
808 delete[] buf; // clean up
810 #else /* ACE_WIN32 */
811 #ifndef ACE_LACKS_IF_NAMETOINDEX
812 lmreq.ipv6mr_interface = ACE_OS::if_nametoindex (ACE_TEXT_ALWAYS_CHAR (net_if));
813 #endif /* ACE_LACKS_IF_NAMETOINDEX */
814 #endif /* ACE_WIN32 */
815 if (lmreq.ipv6mr_interface == 0)
817 errno = EINVAL;
818 return -1;
821 #else /* ACE_WIN32 || !ACE_LACKS_IF_NAMETOINDEX */
822 ACE_UNUSED_ARG(net_if);
823 #endif /* ACE_WIN32 || !ACE_LACKS_IF_NAMETOINDEX */
825 // now set the multicast address
826 ACE_OS::memcpy (&lmreq.ipv6mr_multiaddr,
827 &((sockaddr_in6 *) mcast_addr.get_addr ())->sin6_addr,
828 sizeof (in6_addr));
830 // Set return info, if requested.
831 if (ret_mreq)
832 *ret_mreq = lmreq;
834 return 0;
836 #endif /* ACE_HAS_IPV6 */
838 ACE_END_VERSIONED_NAMESPACE_DECL