apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pque...@apache.org
Subject svn commit: r123883 - /apr/apr/trunk/CHANGES /apr/apr/trunk/configure.in /apr/apr/trunk/include/apr_network_io.h /apr/apr/trunk/network_io/unix/multicast.c
Date Sun, 02 Jan 2005 06:04:08 GMT
Author: pquerna
Date: Sat Jan  1 22:04:07 2005
New Revision: 123883

URL: http://svn.apache.org/viewcvs?view=rev&rev=123883
Log:
Adding an initial Multicast API.

Tested On: OS X, FreeBSD, NetBSD and Linux.

Needs more Platform Specific Code: Netware, Windows


Added:
   apr/apr/trunk/network_io/unix/multicast.c   (contents, props changed)
Modified:
   apr/apr/trunk/CHANGES
   apr/apr/trunk/configure.in
   apr/apr/trunk/include/apr_network_io.h

Modified: apr/apr/trunk/CHANGES
Url: http://svn.apache.org/viewcvs/apr/apr/trunk/CHANGES?view=diff&rev=123883&p1=apr/apr/trunk/CHANGES&r1=123882&p2=apr/apr/trunk/CHANGES&r2=123883
==============================================================================
--- apr/apr/trunk/CHANGES	(original)
+++ apr/apr/trunk/CHANGES	Sat Jan  1 22:04:07 2005
@@ -1,5 +1,7 @@
 Changes for APR 1.1.0
 
+  *) Add APR Multicast Functions [Paul Querna]
+
   *) Add a build script to create a solaris package. [Graham Leggett]
   
   *) Add support for APR_TCP_DEFER_ACCEPT.

Modified: apr/apr/trunk/configure.in
Url: http://svn.apache.org/viewcvs/apr/apr/trunk/configure.in?view=diff&rev=123883&p1=apr/apr/trunk/configure.in&r1=123882&p2=apr/apr/trunk/configure.in&r2=123883
==============================================================================
--- apr/apr/trunk/configure.in	(original)
+++ apr/apr/trunk/configure.in	Sat Jan  1 22:04:07 2005
@@ -1898,6 +1898,9 @@
 
 AC_CHECK_FUNCS(set_h_errno)
 
+dnl Used in the Multicast Code
+AC_CHECK_FUNCS(getifaddrs)
+
 echo "${nl}Checking for IPv6 Networking support..."
 dnl Start of checking for IPv6 support...
 

Modified: apr/apr/trunk/include/apr_network_io.h
Url: http://svn.apache.org/viewcvs/apr/apr/trunk/include/apr_network_io.h?view=diff&rev=123883&p1=apr/apr/trunk/include/apr_network_io.h&r1=123882&p2=apr/apr/trunk/include/apr_network_io.h&r2=123883
==============================================================================
--- apr/apr/trunk/include/apr_network_io.h	(original)
+++ apr/apr/trunk/include/apr_network_io.h	Sat Jan  1 22:04:07 2005
@@ -747,6 +747,63 @@
  */
 APR_DECLARE_INHERIT_UNSET(socket);
 
+/**
+ * @defgroup apr_mcast IP Multicast
+ * @{
+ */
+
+/**
+ * Join a Multicast Group
+ * @param sock The socket to join a multicast group
+ * @param join The address of the multicast group to join
+ * @param iface Address of the interface to use.  If NULL is passed, the 
+ *              default multicast interface will be used. (OS Dependent)
+ */
+APR_DECLARE(apr_status_t) apr_mcast_join(apr_socket_t *sock,
+                                         apr_sockaddr_t *join,
+                                         apr_sockaddr_t *iface);
+
+/**
+ * Leave a Multicast Group.  All arguments must be the same as
+ * apr_mcast_join.
+ * @param sock The socket to leave a multicast group
+ * @param leave The address of the multicast group to leave
+ * @param iface Address of the interface to use.  If NULL is passed, the 
+ *              default multicast interface will be used. (OS Dependent)
+ */
+APR_DECLARE(apr_status_t) apr_mcast_leave(apr_socket_t *sock,
+                                          apr_sockaddr_t *leave,
+                                          apr_sockaddr_t *iface);
+
+/**
+ * Set the Multicast Time to Live (ttl) for a multicast transmission.
+ * @param sock The socket to set the multicast ttl
+ * @param ttl Time to live to Assign. 0-255, default=1
+ * @remark If the TTL is 0, packets will only be seen by sockets on 
+ * the local machine, and only when multicast loopback is enabled.
+ */
+APR_DECLARE(apr_status_t) apr_mcast_hops(apr_socket_t *sock,
+                                         apr_byte_t ttl);
+
+/**
+ * Toggle IP Multicast Loopback
+ * @param sock The socket to set multicast loopback
+ * @param opt 0=disable, 1=enable
+ */
+APR_DECLARE(apr_status_t) apr_mcast_loopback(apr_socket_t *sock,
+                                             apr_byte_t opt);
+
+
+/**
+ * Set the Interface to be used for outgoing Multicast Transmissions.
+ * @param sock The socket to set the multicast interface on
+ * @param iface Address of the interface to use for Multicast
+ */
+APR_DECLARE(apr_status_t) apr_mcast_interface(apr_socket_t *sock,
+                                              apr_sockaddr_t *iface);
+
+/** @} */
+
 /** @} */
 
 #ifdef __cplusplus

Added: apr/apr/trunk/network_io/unix/multicast.c
Url: http://svn.apache.org/viewcvs/apr/apr/trunk/network_io/unix/multicast.c?view=auto&rev=123883
==============================================================================
--- (empty file)
+++ apr/apr/trunk/network_io/unix/multicast.c	Sat Jan  1 22:04:07 2005
@@ -0,0 +1,295 @@
+/* Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_arch_networkio.h"
+#include "apr_network_io.h"
+#include "apr_support.h"
+#include "apr_portable.h"
+#include "apr_arch_inherit.h"
+
+#if HAVE_GETIFADDRS
+#include <net/if.h>
+#include <ifaddrs.h>
+#endif
+
+/* Only UDP and Raw Sockets can be used for Multicast */
+static apr_status_t mcast_check_type(apr_socket_t* sock)
+{
+    int type;
+    apr_status_t rv;
+
+    rv = apr_socket_type_get(sock, &type);
+
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
+    else if (type == SOCK_DGRAM || type == SOCK_RAW) {
+        return APR_SUCCESS;
+    }
+    else {
+        return APR_ENOTIMPL;
+    }
+}
+
+static void fill_mip_v4(struct ip_mreq *mip, apr_sockaddr_t *mcast, 
+                        apr_sockaddr_t *iface)
+{
+    mip->imr_multiaddr = mcast->sa.sin.sin_addr;
+    if (iface == NULL) {
+        mip->imr_interface.s_addr = INADDR_ANY;
+    }
+    else {
+        mip->imr_interface = iface->sa.sin.sin_addr;
+    }
+}
+
+#if APR_HAVE_IPV6
+static unsigned int find_if_index(const apr_sockaddr_t *iface) 
+{
+    unsigned int index = 0;
+    struct ifaddrs *ifp, *ifs;
+
+    /**
+     * TODO: getifaddrs is only portable to *BSD and OS X. Using ioctl 
+     *       and SIOCGIFCONF is needed for Linux/Solaris support.
+     *       
+     *       There is a wrapper that takes the messy ioctl interface into 
+     *       getifaddrs. The license is acceptable, but, It is a fairly large 
+     *       chunk of code.
+     */
+#if HAVE_GETIFADDRS
+    if (getifaddrs(&ifs) != 0) {
+        return 0;
+    }
+
+    for (ifp = ifs; ifp; ifp = ifp->ifa_next) {
+        if (ifp->ifa_addr != NULL && 
+            ifp->ifa_addr->sa_family == AF_INET6) {
+            /* TODO: Is this correct? */
+            if (memcmp(&iface->sa.sin6.sin6_addr,
+                       &ifp->ifa_addr->sa_data[0],
+                       sizeof(ifp->ifa_addr)) == 0) {
+                index = if_nametoindex(ifp->ifa_name);
+                break;
+            }
+        }
+    }
+
+    freeifaddrs(ifs);
+#endif
+    return index;
+}
+
+static void fill_mip_v6(struct ipv6_mreq *mip, const apr_sockaddr_t *mcast, 
+                        const apr_sockaddr_t *iface)
+{
+    memcpy(&mip->ipv6mr_multiaddr, mcast->ipaddr_ptr,
+           sizeof(mip->ipv6mr_multiaddr));
+
+    if (iface == NULL) {
+        mip->ipv6mr_interface = 0;
+    }
+    else {
+        mip->ipv6mr_interface = find_if_index(iface);
+    }
+}
+
+#endif
+
+static int sock_is_ipv4(apr_socket_t* sock) 
+{
+    if (sock->local_addr->family == APR_INET)
+        return 1;
+    return 0;
+}
+
+#if APR_HAVE_IPV6
+static int sock_is_ipv6(apr_socket_t* sock)
+{
+    if (sock->local_addr->family == APR_INET6)
+        return 1;
+    return 0;
+}
+#endif
+
+static apr_status_t do_mcast(int type, apr_socket_t *sock, 
+                             apr_sockaddr_t *mcast, apr_sockaddr_t *iface)
+{
+    struct ip_mreq mip4;
+    apr_status_t rv = APR_SUCCESS;
+#if APR_HAVE_IPV6
+    struct ipv6_mreq mip6;
+#endif
+    
+    rv = mcast_check_type(sock);
+
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
+
+    if (sock_is_ipv4(sock)) {
+
+        fill_mip_v4(&mip4, mcast, iface);
+
+        if (setsockopt(sock->socketdes, IPPROTO_IP, type,
+                       &mip4, sizeof(mip4)) == -1) {
+            rv = errno;
+        }
+    }
+#if APR_HAVE_IPV6
+    else if (sock_is_ipv6(sock)) {
+        if (type == IP_ADD_MEMBERSHIP) {
+            type = IPV6_JOIN_GROUP;
+        }
+        else if (type == IP_DROP_MEMBERSHIP) {
+            type = IPV6_LEAVE_GROUP;
+        }
+        else {
+            return APR_ENOTIMPL;
+        }
+
+        fill_mip_v6(&mip6, mcast, iface);
+
+        if (setsockopt(sock->socketdes, IPPROTO_IPV6, type,
+                       &mip6, sizeof(mip6)) == -1) {
+            rv = errno;
+        }
+    }
+#endif
+    else {
+        rv = APR_ENOTIMPL;
+    }
+    return rv;
+}
+
+static apr_status_t do_mcast_opt(int type, apr_socket_t *sock,
+                                 apr_byte_t value)
+{
+    apr_status_t rv = APR_SUCCESS;
+    
+    rv = mcast_check_type(sock);
+
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
+
+    if (sock_is_ipv4(sock)) {
+        if (setsockopt(sock->socketdes, IPPROTO_IP, type,
+                      &value, sizeof(value)) == -1) {
+            rv = errno;
+        }
+    }
+#if APR_HAVE_IPV6
+    else if (sock_is_ipv6(sock) && type == IP_MULTICAST_LOOP) {
+        unsigned int loopopt = value;
+        type = IPV6_MULTICAST_LOOP;
+        if (setsockopt(sock->socketdes, IPPROTO_IPV6, type,
+                      &loopopt, sizeof(loopopt)) == -1) {
+            rv = errno;
+        }
+    }
+    else if (sock_is_ipv6(sock)) {
+        if (type == IP_MULTICAST_TTL) {
+            type = IPV6_MULTICAST_HOPS;
+        }
+        else {
+            return APR_ENOTIMPL;
+        }
+
+        if (setsockopt(sock->socketdes, IPPROTO_IPV6, type, 
+                      &value, sizeof(value)) == -1) {
+            rv = errno;
+        }
+    }
+#endif
+    else {
+        rv = APR_ENOTIMPL;
+    }
+
+    return rv;
+}
+
+APR_DECLARE(apr_status_t) apr_mcast_join(apr_socket_t *sock,
+                                         apr_sockaddr_t *join,
+                                         apr_sockaddr_t *iface)
+{
+#ifdef IP_ADD_MEMBERSHIP
+    return do_mcast(IP_ADD_MEMBERSHIP, sock, join, iface);
+#else
+    return APR_ENOTIMPL;
+#endif
+}
+
+APR_DECLARE(apr_status_t) apr_mcast_leave(apr_socket_t *sock,
+                                          apr_sockaddr_t *leave,
+                                          apr_sockaddr_t *iface)
+{
+#ifdef IP_DROP_MEMBERSHIP
+    return do_mcast(IP_DROP_MEMBERSHIP, sock, leave, iface);
+#else
+    return APR_ENOTIMPL;
+#endif
+}
+
+APR_DECLARE(apr_status_t) apr_mcast_hops(apr_socket_t *sock,
+                                         apr_byte_t ttl)
+{
+#ifdef IP_MULTICAST_TTL
+    return do_mcast_opt(IP_MULTICAST_TTL, sock, ttl);
+#else
+    return APR_ENOTIMPL;
+#endif
+}
+
+APR_DECLARE(apr_status_t) apr_mcast_loopback(apr_socket_t *sock,        
+                                             apr_byte_t opt)
+{
+#ifdef IP_MULTICAST_LOOP
+    return do_mcast_opt(IP_MULTICAST_LOOP, sock, opt);
+#else
+    return APR_ENOTIMPL;
+#endif
+}
+
+APR_DECLARE(apr_status_t) apr_mcast_interface(apr_socket_t *sock,
+                                              apr_sockaddr_t *iface)
+{
+#ifdef IP_MULTICAST_IF
+    apr_status_t rv = APR_SUCCESS;
+
+    if (sock_is_ipv4(sock)) {
+        if (setsockopt(sock->socketdes, IPPROTO_IP, IP_MULTICAST_IF,
+                      &iface->sa.sin.sin_addr,
+                      sizeof(iface->sa.sin.sin_addr)) == -1) {
+            rv = errno;
+        }
+    }
+#if APR_HAVE_IPV6
+    else if (sock_is_ipv6(sock)) {
+        unsigned int idx = find_if_index(iface);
+        if (setsockopt(sock->socketdes,  IPPROTO_IPV6, IPV6_MULTICAST_IF,
+                      &idx, sizeof(idx)) == -1) {
+            rv = errno;
+        }
+    }
+#endif
+    else {
+        rv = APR_ENOTIMPL;
+    }
+    return rv;
+#else
+    return APR_ENOTIMPL;
+#endif
+}

Mime
View raw message