Document return values
[ACE_TAO.git] / ACE / ace / SOCK_Dgram.cpp
blobd23422f422588e0c6b23a0959c4a04ad42bfec03
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 (),
149 INADDR_ANY,
150 protocol_family) == -1)
151 error = true;
154 else if (ACE_OS::bind (this->get_handle (),
155 reinterpret_cast<sockaddr *> (local.get_addr ()),
156 local.get_size ()) == -1)
157 error = true;
159 if (error)
160 this->close ();
162 return error ? -1 : 0;
166 ACE_SOCK_Dgram::open (const ACE_Addr &local,
167 int protocol_family,
168 int protocol,
169 ACE_Protocol_Info *protocolinfo,
170 ACE_SOCK_GROUP g,
171 u_long flags,
172 int reuse_addr,
173 int ipv6_only)
175 if (ACE_SOCK::open (SOCK_DGRAM,
176 protocol_family,
177 protocol,
178 protocolinfo,
180 flags,
181 reuse_addr) == -1)
182 return -1;
183 else if (this->shared_open (local,
184 protocol_family,
185 ipv6_only) == -1)
186 return -1;
187 else
188 return 0;
191 // Here's the general-purpose open routine.
194 ACE_SOCK_Dgram::open (const ACE_Addr &local,
195 int protocol_family,
196 int protocol,
197 int reuse_addr,
198 int ipv6_only)
200 ACE_TRACE ("ACE_SOCK_Dgram::open");
202 if (local != ACE_Addr::sap_any)
203 protocol_family = local.get_type ();
204 else if (protocol_family == PF_UNSPEC)
206 #if defined (ACE_HAS_IPV6)
207 protocol_family = ACE::ipv6_enabled () ? PF_INET6 : PF_INET;
208 #else
209 protocol_family = PF_INET;
210 #endif /* ACE_HAS_IPV6 */
213 if (ACE_SOCK::open (SOCK_DGRAM,
214 protocol_family,
215 protocol,
216 reuse_addr) == -1)
217 return -1;
218 else
219 return this->shared_open (local,
220 protocol_family,
221 ipv6_only);
224 // Here's the general-purpose constructor used by a connectionless
225 // datagram ``server''...
227 ACE_SOCK_Dgram::ACE_SOCK_Dgram (const ACE_Addr &local,
228 int protocol_family,
229 int protocol,
230 int reuse_addr,
231 int ipv6_only)
233 ACE_TRACE ("ACE_SOCK_Dgram::ACE_SOCK_Dgram");
235 if (this->open (local,
236 protocol_family,
237 protocol,
238 reuse_addr,
239 ipv6_only) == -1)
240 ACELIB_ERROR ((LM_ERROR,
241 ACE_TEXT ("%p\n"),
242 ACE_TEXT ("ACE_SOCK_Dgram")));
245 ACE_SOCK_Dgram::ACE_SOCK_Dgram (const ACE_Addr &local,
246 int protocol_family,
247 int protocol,
248 ACE_Protocol_Info *protocolinfo,
249 ACE_SOCK_GROUP g,
250 u_long flags,
251 int reuse_addr,
252 int ipv6_only)
254 ACE_TRACE ("ACE_SOCK_Dgram::ACE_SOCK_Dgram");
255 if (this->open (local,
256 protocol_family,
257 protocol,
258 protocolinfo,
260 flags,
261 reuse_addr,
262 ipv6_only) == -1)
263 ACELIB_ERROR ((LM_ERROR,
264 ACE_TEXT ("%p\n"),
265 ACE_TEXT ("ACE_SOCK_Dgram")));
268 #if defined (ACE_HAS_MSG)
269 // Send an iovec of size N to ADDR as a datagram (connectionless
270 // version).
272 ssize_t
273 ACE_SOCK_Dgram::send (const iovec iov[],
274 int n,
275 const ACE_Addr &addr,
276 int flags) const
278 ACE_TRACE ("ACE_SOCK_Dgram::send");
279 msghdr send_msg;
281 send_msg.msg_iov = (iovec *) iov;
282 send_msg.msg_iovlen = n;
283 #if defined (ACE_HAS_SOCKADDR_MSG_NAME)
284 send_msg.msg_name = (struct sockaddr *) addr.get_addr ();
285 #else
286 send_msg.msg_name = (char *) addr.get_addr ();
287 #endif /* ACE_HAS_SOCKADDR_MSG_NAME */
288 send_msg.msg_namelen = addr.get_size ();
290 #if defined (ACE_HAS_4_4BSD_SENDMSG_RECVMSG)
291 send_msg.msg_control = 0;
292 send_msg.msg_controllen = 0;
293 send_msg.msg_flags = 0;
294 #elif !defined ACE_LACKS_SENDMSG
295 send_msg.msg_accrights = 0;
296 send_msg.msg_accrightslen = 0;
297 #endif /* ACE_HAS_4_4BSD_SENDMSG_RECVMSG */
299 #ifdef ACE_WIN32
300 send_msg.msg_control = 0;
301 send_msg.msg_controllen = 0;
302 #endif
304 return ACE_OS::sendmsg (this->get_handle (),
305 &send_msg,
306 flags);
309 // Recv an iovec of size N to ADDR as a datagram (connectionless
310 // version).
312 ssize_t
313 ACE_SOCK_Dgram::recv (iovec iov[],
314 int n,
315 ACE_Addr &addr,
316 int flags,
317 ACE_INET_Addr *to_addr) const
319 ACE_TRACE ("ACE_SOCK_Dgram::recv");
320 msghdr recv_msg;
322 #if defined (ACE_HAS_4_4BSD_SENDMSG_RECVMSG) || defined ACE_WIN32
323 #define ACE_USE_MSG_CONTROL
324 union control_buffer {
325 cmsghdr control_msg_header;
326 #if defined (IP_RECVDSTADDR)
327 u_char padding[ACE_CMSG_SPACE (sizeof (in_addr))];
328 #elif defined (IP_PKTINFO)
329 u_char padding[ACE_CMSG_SPACE (sizeof (in_pktinfo))];
330 #endif
331 #if defined (ACE_HAS_IPV6)
332 u_char padding6[ACE_CMSG_SPACE (sizeof (in6_pktinfo))];
333 #endif
334 } cbuf;
335 #else
336 ACE_UNUSED_ARG (to_addr);
337 #endif
339 recv_msg.msg_iov = (iovec *) iov;
340 recv_msg.msg_iovlen = n;
341 #if defined (ACE_HAS_SOCKADDR_MSG_NAME)
342 recv_msg.msg_name = (struct sockaddr *) addr.get_addr ();
343 #else
344 recv_msg.msg_name = (char *) addr.get_addr ();
345 #endif /* ACE_HAS_SOCKADDR_MSG_NAME */
346 recv_msg.msg_namelen = addr.get_size ();
348 #ifdef ACE_USE_MSG_CONTROL
349 recv_msg.msg_control = to_addr ? &cbuf : 0;
350 recv_msg.msg_controllen = to_addr ? sizeof (cbuf) : 0;
351 #elif !defined ACE_LACKS_SENDMSG
352 recv_msg.msg_accrights = 0;
353 recv_msg.msg_accrightslen = 0;
354 #endif
356 ssize_t status = ACE_OS::recvmsg (this->get_handle (),
357 &recv_msg,
358 flags);
359 addr.set_size (recv_msg.msg_namelen);
360 addr.set_type (((sockaddr_in *) addr.get_addr())->sin_family);
362 #ifdef ACE_USE_MSG_CONTROL
363 if (to_addr) {
364 this->get_local_addr (*to_addr);
365 if (to_addr->get_type() == AF_INET) {
366 #if defined (IP_RECVDSTADDR) || defined (IP_PKTINFO)
367 for (cmsghdr *ptr = ACE_CMSG_FIRSTHDR (&recv_msg); ptr; ptr = ACE_CMSG_NXTHDR (&recv_msg, ptr)) {
368 #if defined (IP_RECVDSTADDR)
369 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_RECVDSTADDR) {
370 to_addr->set_address ((const char *) (ACE_CMSG_DATA (ptr)),
371 sizeof (struct in_addr),
373 break;
375 #else
376 if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO) {
377 to_addr->set_address ((const char *) &(((in_pktinfo *) (ACE_CMSG_DATA (ptr)))->ipi_addr),
378 sizeof (struct in_addr),
380 break;
382 #endif
384 #endif
386 #if defined (ACE_HAS_IPV6) && defined (IPV6_PKTINFO)
387 else if (to_addr->get_type() == AF_INET6) {
388 for (cmsghdr *ptr = ACE_CMSG_FIRSTHDR (&recv_msg); ptr; ptr = ACE_CMSG_NXTHDR (&recv_msg, ptr)) {
389 if (ptr->cmsg_level == IPPROTO_IPV6 && ptr->cmsg_type == IPV6_PKTINFO) {
390 to_addr->set_address ((const char *) &(((in6_pktinfo *)(ACE_CMSG_DATA (ptr)))->ipi6_addr),
391 sizeof (struct in6_addr),
394 break;
398 #endif
400 #endif
402 return status;
405 #else /* ACE_HAS_MSG */
407 // Send an iovec of size N to ADDR as a datagram (connectionless
408 // version).
409 ssize_t
410 ACE_SOCK_Dgram::send (const iovec iov[],
411 int n,
412 const ACE_Addr &addr,
413 int flags) const
415 ACE_TRACE ("ACE_SOCK_Dgram::send");
417 size_t length = 0;
418 int i;
420 // Determine the total length of all the buffers in <iov>.
421 for (i = 0; i < n; i++)
422 #if ! (defined(ACE_LACKS_IOVEC) || defined(ACE_LINUX))
423 // The iov_len is unsigned on Linux and when using the ACE iovec struct. If we go
424 // ahead and try the if, it will emit a warning.
425 if (iov[i].iov_len < 0)
426 return -1;
427 else
428 #endif
429 length += iov[i].iov_len;
431 char *buf = 0;
433 #if defined (ACE_HAS_ALLOCA)
434 buf = alloca (length);
435 #else
436 # ifdef ACE_HAS_ALLOC_HOOKS
437 ACE_ALLOCATOR_RETURN (buf, (buf *)
438 ACE_Allocator::instance ()->malloc (length), -1);
439 # else
440 ACE_NEW_RETURN (buf,
441 char[length],
442 -1);
443 # endif /* ACE_HAS_ALLOC_HOOKS */
444 #endif /* !defined (ACE_HAS_ALLOCA) */
446 char *ptr = buf;
448 for (i = 0; i < n; i++)
450 ACE_OS::memcpy (ptr, iov[i].iov_base, iov[i].iov_len);
451 ptr += iov[i].iov_len;
454 ssize_t result = ACE_SOCK_Dgram::send (buf, length, addr, flags);
455 #if !defined (ACE_HAS_ALLOCA)
456 # ifdef ACE_HAS_ALLOC_HOOKS
457 ACE_Allocator::instance ()->free (buf);
458 # else
459 delete [] buf;
460 # endif /* ACE_HAS_ALLOC_HOOKS */
461 #endif /* !defined (ACE_HAS_ALLOCA) */
462 return result;
465 // Recv an iovec of size N to ADDR as a datagram (connectionless
466 // version).
468 ssize_t
469 ACE_SOCK_Dgram::recv (iovec iov[],
470 int n,
471 ACE_Addr &addr,
472 int flags,
473 ACE_INET_Addr *to_addr) const
475 ACE_TRACE ("ACE_SOCK_Dgram::recv");
477 ssize_t length = 0;
478 int i;
480 ACE_UNUSED_ARG (to_addr);
482 for (i = 0; i < n; i++)
483 #if ! (defined(ACE_LACKS_IOVEC) || defined(ACE_LINUX))
484 // The iov_len is unsigned on Linux and when using the ACE iovec struct. If we go
485 // ahead and try the if, it will emit a warning.
486 if (iov[i].iov_len < 0)
487 return -1;
488 else
489 #endif
490 length += iov[i].iov_len;
492 char *buf = 0;
494 #if defined (ACE_HAS_ALLOCA)
495 buf = alloca (length);
496 #else
497 # ifdef ACE_HAS_ALLOC_HOOKS
498 ACE_ALLOCATOR_RETURN (buf, (buf *)
499 ACE_Allocator::instance ()->malloc (length), -1);
500 # else
501 ACE_NEW_RETURN (buf,
502 char[length],
503 -1);
504 # endif /* ACE_HAS_ALLOC_HOOKS */
505 #endif /* !defined (ACE_HAS_ALLOCA) */
507 length = ACE_SOCK_Dgram::recv (buf, length, addr, flags);
509 if (length != -1)
511 char *ptr = buf;
512 int copyn = length;
514 for (i = 0;
515 i < n && copyn > 0;
516 i++)
518 ACE_OS::memcpy (iov[i].iov_base, ptr,
519 // iov_len is int on some platforms, size_t on others
520 copyn > (int) iov[i].iov_len
521 ? (size_t) iov[i].iov_len
522 : (size_t) copyn);
523 ptr += iov[i].iov_len;
524 copyn -= iov[i].iov_len;
528 #if !defined (ACE_HAS_ALLOCA)
529 # ifdef ACE_HAS_ALLOC_HOOKS
530 ACE_Allocator::instance ()->free (buf);
531 # else
532 delete [] buf;
533 # endif /* ACE_HAS_ALLOC_HOOKS */
534 #endif /* !defined (ACE_HAS_ALLOCA) */
535 return length;
538 #endif /* ACE_HAS_MSG */
540 ssize_t
541 ACE_SOCK_Dgram::recv (void *buf,
542 size_t n,
543 ACE_Addr &addr,
544 int flags,
545 const ACE_Time_Value *timeout) const
547 if( ACE::handle_read_ready (this->get_handle (), timeout) == 1 )
549 // Goes fine, call <recv> to get data
550 return this->recv (buf, n, addr, flags);
552 else
554 return -1;
558 ssize_t
559 ACE_SOCK_Dgram::send (const void *buf,
560 size_t n,
561 const ACE_Addr &addr,
562 int flags,
563 const ACE_Time_Value *timeout) const
565 // Check the status of the current socket.
566 if( ACE::handle_write_ready (this->get_handle (), timeout) == 1 )
568 // Goes fine, call <send> to transmit the data.
569 return this->send (buf, n, addr, flags);
571 else
573 return -1;
578 ACE_SOCK_Dgram::set_nic (const ACE_TCHAR *net_if,
579 int addr_family)
581 #if defined (IP_MULTICAST_IF) && (IP_MULTICAST_IF != 0)
582 # if defined (ACE_HAS_IPV6)
583 bool ipv6_mif_set = false;
584 if (addr_family == AF_INET6 || addr_family == AF_UNSPEC)
586 ACE_INET_Addr addr;
587 addr.set (static_cast<u_short> (0), ACE_IPV6_ANY);
588 ipv6_mreq send_mreq;
589 if (this->make_multicast_ifaddr6 (&send_mreq,
590 addr,
591 net_if) == -1)
592 return -1;
594 // Only let this attempt to set unknown interface when INET6 is
595 // specifically requested. Otherwise we will just try INET.
596 if (send_mreq.ipv6mr_interface != 0 || addr_family == AF_INET6)
598 if (this->ACE_SOCK::set_option
599 (IPPROTO_IPV6, IPV6_MULTICAST_IF,
600 &(send_mreq.ipv6mr_interface),
601 sizeof send_mreq.ipv6mr_interface) == -1)
602 return -1;
604 ipv6_mif_set = send_mreq.ipv6mr_interface != 0;
607 # if defined (ACE_WIN32)
608 // For Win32 net_if is distintly different between INET6 and INET
609 // so it is always either an INET6 if or an INET if.
610 if (!ipv6_mif_set && (addr_family == AF_INET || addr_family == AF_UNSPEC))
611 # else
612 if (addr_family == AF_INET || addr_family == AF_UNSPEC)
613 # endif
615 ACE_INET_Addr addr (static_cast<u_short> (0));
616 ip_mreq send_mreq;
617 if (this->make_multicast_ifaddr (&send_mreq,
618 addr,
619 net_if) == -1)
621 if (!ipv6_mif_set)
622 return -1;
624 else if (this->ACE_SOCK::set_option (IPPROTO_IP,
625 IP_MULTICAST_IF,
626 &(send_mreq.imr_interface),
627 sizeof send_mreq.imr_interface) == -1)
629 if (!ipv6_mif_set)
630 return -1;
633 # else /* ACE_HAS_IPV6 */
634 ACE_UNUSED_ARG (addr_family);
635 ACE_INET_Addr addr (static_cast<u_short> (0));
636 ip_mreq send_mreq;
637 if (this->make_multicast_ifaddr (&send_mreq,
638 addr,
639 net_if) == -1)
640 return -1;
641 if (this->ACE_SOCK::set_option (IPPROTO_IP,
642 IP_MULTICAST_IF,
643 &(send_mreq.imr_interface),
644 sizeof send_mreq.imr_interface) == -1)
645 return -1;
646 # endif /* !ACE_HAS_IPV6 */
647 #else /* IP_MULTICAST_IF */
648 // Send interface option not supported - ignore it.
649 // (We may have been invoked by ::subscribe, so we have to allow
650 // a non-null interface parameter in this function.)
651 ACE_UNUSED_ARG (net_if);
652 ACE_UNUSED_ARG (addr_family);
653 ACELIB_DEBUG ((LM_DEBUG,
654 ACE_TEXT ("Send interface specification not ")
655 ACE_TEXT ("supported - IGNORED.\n")));
656 #endif /* !IP_MULTICAST_IF */
658 return 0;
662 ACE_SOCK_Dgram::make_multicast_ifaddr (ip_mreq *ret_mreq,
663 const ACE_INET_Addr &mcast_addr,
664 const ACE_TCHAR *net_if)
666 ACE_TRACE ("ACE_SOCK_Dgram::make_multicast_ifaddr");
667 ip_mreq lmreq; // Scratch copy.
668 if (net_if != 0)
670 #if defined (ACE_WIN32)
671 // This port number is not necessary, just convenient
672 ACE_INET_Addr interface_addr;
673 if (interface_addr.set (mcast_addr.get_port_number (), net_if) == -1)
675 IP_ADAPTER_ADDRESSES tmp_addrs;
676 // Initial call to determine actual memory size needed
677 ULONG bufLen = 0;
678 if (::GetAdaptersAddresses (AF_INET, 0, 0, &tmp_addrs, &bufLen)
679 != ERROR_BUFFER_OVERFLOW)
681 return -1; // With output bufferlength 0 this can't be right.
684 // Get required output buffer and retrieve info for real.
685 char *buf = 0;
686 ACE_NEW_RETURN (buf, char[bufLen], -1);
687 PIP_ADAPTER_ADDRESSES pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
688 if (::GetAdaptersAddresses (AF_INET, 0, 0, pAddrs, &bufLen) != NO_ERROR)
690 delete[] buf; // clean up
691 return -1;
694 interface_addr = ACE_INET_Addr ();
695 int set_result = -1;
696 while (pAddrs && set_result == -1)
698 if (ACE_OS::strcmp (ACE_TEXT_ALWAYS_CHAR (net_if), pAddrs->AdapterName) == 0 ||
699 ACE_OS::strcmp (ACE_TEXT_ALWAYS_WCHAR (net_if), pAddrs->FriendlyName) == 0)
701 PIP_ADAPTER_UNICAST_ADDRESS pUnicast = pAddrs->FirstUnicastAddress;
702 LPSOCKADDR sa = pUnicast->Address.lpSockaddr;
703 if (sa->sa_family == AF_INET)
705 const void *addr = &(((sockaddr_in *)sa)->sin_addr);
706 set_result = interface_addr.set_address ((const char*) addr, 4, 0);
709 pAddrs = pAddrs->Next;
712 delete[] buf; // clean up
713 if (set_result == -1)
715 errno = EINVAL;
716 return -1;
719 lmreq.imr_interface.s_addr =
720 ACE_HTONL (interface_addr.get_ip_address ());
721 #else
722 ifreq if_address;
723 ACE_OS::strsncpy (if_address.ifr_name, ACE_TEXT_ALWAYS_CHAR (net_if), (sizeof if_address.ifr_name));
724 if (ACE_OS::ioctl (this->get_handle (),
725 SIOCGIFADDR,
726 &if_address) == -1)
728 // The net_if name failed to be found. It seems that older linux
729 // kernals only support the actual interface name (eg. "eth0"),
730 // not the IP address string of the interface (eg. "192.168.0.1"),
731 // which newer kernals seem to automatically translate.
732 // So assume that we have been given an IP Address and translate
733 // that instead, similar to the above for windows.
734 ACE_INET_Addr interface_addr;
735 if (interface_addr.set (mcast_addr.get_port_number (), net_if) == -1)
736 return -1; // Still doesn't work, unknown device specified.
737 lmreq.imr_interface.s_addr =
738 ACE_HTONL (interface_addr.get_ip_address ());
740 else
742 sockaddr_in *socket_address =
743 reinterpret_cast<sockaddr_in*> (&if_address.ifr_addr);
744 lmreq.imr_interface.s_addr = socket_address->sin_addr.s_addr;
746 #endif /* ACE_WIN32 */
748 else
749 lmreq.imr_interface.s_addr = INADDR_ANY;
751 lmreq.IMR_MULTIADDR.s_addr = ACE_HTONL (mcast_addr.get_ip_address ());
753 // Set return info, if requested.
754 if (ret_mreq)
755 *ret_mreq = lmreq;
757 return 0;
760 #if defined (ACE_HAS_IPV6)
761 // XXX: This will not work on any operating systems that do not support
762 // if_nametoindex or that is not Win32 >= Windows XP/Server 2003
764 ACE_SOCK_Dgram::make_multicast_ifaddr6 (ipv6_mreq *ret_mreq,
765 const ACE_INET_Addr &mcast_addr,
766 const ACE_TCHAR *net_if)
768 ACE_TRACE ("ACE_SOCK_Dgram::make_multicast_ifaddr6");
769 ipv6_mreq lmreq; // Scratch copy.
771 ACE_OS::memset (&lmreq,
773 sizeof (lmreq));
775 #if defined (ACE_WIN32) || !defined (ACE_LACKS_IF_NAMETOINDEX)
776 if (net_if != 0)
778 #if defined (ACE_WIN32)
779 int if_ix = 0;
780 bool const num_if =
781 ACE_OS::ace_isdigit (net_if[0]) &&
782 (if_ix = ACE_OS::atoi (net_if)) > 0;
784 ULONG bufLen = 15000; // Initial size as per Microsoft
785 char *buf = 0;
786 ACE_NEW_RETURN (buf, char[bufLen], -1);
787 DWORD dwRetVal = 0;
788 ULONG iterations = 0;
789 ULONG const maxTries = 3;
790 PIP_ADAPTER_ADDRESSES pAddrs;
793 pAddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES> (buf);
794 dwRetVal = ::GetAdaptersAddresses (AF_INET6, 0, 0, pAddrs, &bufLen);
795 if (dwRetVal == ERROR_BUFFER_OVERFLOW)
797 delete[] buf;
798 ACE_NEW_RETURN (buf, char[bufLen], -1);
799 ++iterations;
801 else
803 break;
805 } while (dwRetVal == ERROR_BUFFER_OVERFLOW && iterations < maxTries);
807 if (dwRetVal != NO_ERROR)
809 delete[] buf;
810 errno = EINVAL;
811 return -1;
814 while (pAddrs)
816 if ((num_if && pAddrs->Ipv6IfIndex == static_cast<unsigned int>(if_ix))
817 || (!num_if &&
818 (ACE_OS::strcmp (ACE_TEXT_ALWAYS_CHAR (net_if), pAddrs->AdapterName) == 0
819 || ACE_OS::strcmp (ACE_TEXT_ALWAYS_WCHAR (net_if), pAddrs->FriendlyName) == 0)))
821 lmreq.ipv6mr_interface = pAddrs->Ipv6IfIndex;
822 break;
825 pAddrs = pAddrs->Next;
828 delete[] buf; // clean up
830 #else /* ACE_WIN32 */
831 #ifndef ACE_LACKS_IF_NAMETOINDEX
832 lmreq.ipv6mr_interface = ACE_OS::if_nametoindex (ACE_TEXT_ALWAYS_CHAR (net_if));
833 #endif /* ACE_LACKS_IF_NAMETOINDEX */
834 #endif /* ACE_WIN32 */
835 if (lmreq.ipv6mr_interface == 0)
837 errno = EINVAL;
838 return -1;
841 #else /* ACE_WIN32 || !ACE_LACKS_IF_NAMETOINDEX */
842 ACE_UNUSED_ARG(net_if);
843 #endif /* ACE_WIN32 || !ACE_LACKS_IF_NAMETOINDEX */
845 // now set the multicast address
846 ACE_OS::memcpy (&lmreq.ipv6mr_multiaddr,
847 &((sockaddr_in6 *) mcast_addr.get_addr ())->sin6_addr,
848 sizeof (in6_addr));
850 // Set return info, if requested.
851 if (ret_mreq)
852 *ret_mreq = lmreq;
854 return 0;
856 #endif /* ACE_HAS_IPV6 */
858 ACE_END_VERSIONED_NAMESPACE_DECL