]> granicus.if.org Git - php/commitdiff
- Normalized line endings, added native eol-style.
authorGustavo André dos Santos Lopes <cataphract@php.net>
Sun, 20 Mar 2011 02:05:41 +0000 (02:05 +0000)
committerGustavo André dos Santos Lopes <cataphract@php.net>
Sun, 20 Mar 2011 02:05:41 +0000 (02:05 +0000)
ext/sockets/multicast.c
ext/sockets/multicast.h

index 9c54d3f6f1f250afd3a2c2205ff456ca8e95e8a7..cf5d56afb2a0c65f4da25f359a8dfd095a3dd384 100644 (file)
-/*\r
-   +----------------------------------------------------------------------+\r
-   | PHP Version 5                                                        |\r
-   +----------------------------------------------------------------------+\r
-   | Copyright (c) 1997-2011 The PHP Group                                |\r
-   +----------------------------------------------------------------------+\r
-   | This source file is subject to version 3.01 of the PHP license,      |\r
-   | that is bundled with this package in the file LICENSE, and is        |\r
-   | available through the world-wide-web at the following url:           |\r
-   | http://www.php.net/license/3_01.txt                                  |\r
-   | If you did not receive a copy of the PHP license and are unable to   |\r
-   | obtain it through the world-wide-web, please send a note to          |\r
-   | license@php.net so we can mail you a copy immediately.               |\r
-   +----------------------------------------------------------------------+\r
-   | Authors: Gustavo Lopes    <cataphract@php.net>                       |\r
-   +----------------------------------------------------------------------+\r
- */\r
-\r
-/* $Id$ */\r
-\r
-#ifdef HAVE_CONFIG_H\r
-#include "config.h"\r
-#endif\r
-\r
-#include "php.h"\r
-\r
-#if HAVE_SOCKETS\r
-\r
-#include "php_network.h"\r
-#ifdef PHP_WIN32\r
-# include "win32/inet.h"\r
-# include <winsock2.h>\r
-# include <windows.h>\r
-# include <Ws2tcpip.h>\r
-# include <Ws2ipdef.h>\r
-# include "php_sockets.h"\r
-# include "win32/sockets.h"\r
-# define NTDDI_XP NTDDI_WINXP /* bug in SDK */\r
-# include <IPHlpApi.h>\r
-# undef NTDDI_XP\r
-#else\r
-#include <sys/socket.h>\r
-#include <sys/ioctl.h>\r
-#include <net/if.h>\r
-#include <netinet/in.h>\r
-#include <arpa/inet.h>\r
-#endif\r
-\r
-#include "php_sockets.h"\r
-#include "multicast.h"\r
-#include "main/php_network.h"\r
-\r
-#if defined(MCAST_JOIN_GROUP) && 1 &&\\r
-       (!defined(PHP_WIN32) || (_WIN32_WINNT >= 0x600 && SOCKETS_ENABLE_VISTA_API))\r
-#define RFC3678_API 1\r
-#endif\r
-\r
-\r
-enum source_op {\r
-       JOIN_SOURCE,\r
-       LEAVE_SOURCE,\r
-       BLOCK_SOURCE,\r
-       UNBLOCK_SOURCE\r
-};\r
-\r
-static int _php_mcast_join_leave(php_socket *sock, int level, struct sockaddr *group, socklen_t group_len, unsigned int if_index, int join TSRMLS_DC);\r
-static int _php_mcast_source_op(php_socket *sock, int level, struct sockaddr *group, socklen_t group_len, struct sockaddr *source, socklen_t source_len, unsigned int if_index, enum source_op sop TSRMLS_DC);\r
-#if RFC3678_API\r
-static int _php_source_op_to_rfc3678_op(enum source_op sop);\r
-#else\r
-static const char *_php_source_op_to_string(enum source_op sop);\r
-static int _php_source_op_to_ipv4_op(enum source_op sop);\r
-#endif\r
-\r
-int php_mcast_join(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       unsigned int if_index TSRMLS_DC)\r
-{\r
-       return _php_mcast_join_leave(sock, level, group, group_len, if_index, 1 TSRMLS_CC);\r
-}\r
-\r
-int php_mcast_leave(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       unsigned int if_index TSRMLS_DC)\r
-{\r
-       return _php_mcast_join_leave(sock, level, group, group_len, if_index, 0 TSRMLS_CC);\r
-}\r
-\r
-int php_mcast_join_source(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       struct sockaddr *source,\r
-       socklen_t source_len,\r
-       unsigned int if_index TSRMLS_DC)\r
-{\r
-       return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, JOIN_SOURCE TSRMLS_CC);\r
-}\r
-\r
-int php_mcast_leave_source(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       struct sockaddr *source,\r
-       socklen_t source_len,\r
-       unsigned int if_index TSRMLS_DC)\r
-{\r
-       return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, LEAVE_SOURCE TSRMLS_CC);\r
-}\r
-\r
-int php_mcast_block_source(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       struct sockaddr *source,\r
-       socklen_t source_len,\r
-       unsigned int if_index TSRMLS_DC)\r
-{\r
-       return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, BLOCK_SOURCE TSRMLS_CC);\r
-}\r
-\r
-int php_mcast_unblock_source(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       struct sockaddr *source,\r
-       socklen_t source_len,\r
-       unsigned int if_index TSRMLS_DC)\r
-{\r
-       return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, UNBLOCK_SOURCE TSRMLS_CC);\r
-}\r
-\r
-static int _php_mcast_join_leave(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group, /* struct sockaddr_in/sockaddr_in6 */\r
-       socklen_t group_len,\r
-       unsigned int if_index,\r
-       int join TSRMLS_DC)\r
-{\r
-#ifdef RFC3678_API\r
-       struct group_req greq = {0};\r
-       \r
-       memcpy(&greq.gr_group, group, group_len);\r
-       assert(greq.gr_group.ss_family != 0); /* the caller has set this */\r
-       greq.gr_interface = if_index;\r
-\r
-       return setsockopt(sock->bsd_socket, level,\r
-                       join ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (char*)&greq,\r
-                       sizeof(greq));  \r
-#else\r
-       if (sock->type == AF_INET) {\r
-               struct ip_mreq mreq = {0};\r
-               struct in_addr addr;\r
-               \r
-               assert(group_len == sizeof(struct sockaddr_in));\r
-               \r
-               if (if_index != 0) {\r
-                       if (php_if_index_to_addr4(if_index, sock, &addr TSRMLS_CC) ==\r
-                                       FAILURE)\r
-                               return -2; /* failure, but notice already emitted */\r
-                       mreq.imr_interface = addr;\r
-               } else {\r
-                       mreq.imr_interface.s_addr = htonl(INADDR_ANY);\r
-               }\r
-               mreq.imr_multiaddr = ((struct sockaddr_in*)group)->sin_addr;\r
-               return setsockopt(sock->bsd_socket, level,\r
-                               join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, (char*)&mreq,\r
-                               sizeof(mreq));\r
-       }\r
-#if HAVE_IPV6\r
-       else if (sock->type == AF_INET6) {\r
-               struct ipv6_mreq mreq = {0};\r
-               \r
-               assert(group_len == sizeof(struct sockaddr_in6));\r
-\r
-               mreq.ipv6mr_multiaddr = ((struct sockaddr_in6*)group)->sin6_addr;\r
-               mreq.ipv6mr_interface = if_index;\r
-               \r
-               return setsockopt(sock->bsd_socket, level,\r
-                               join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP, (char*)&mreq,\r
-                               sizeof(mreq));\r
-       }\r
-#endif\r
-       else {\r
-               php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-                       "Option %s is inapplicable to this socket type",\r
-                       join ? "MCAST_JOIN_GROUP" : "MCAST_LEAVE_GROUP");\r
-               return -2;\r
-       }\r
-#endif\r
-}\r
-\r
-static int _php_mcast_source_op(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       struct sockaddr *source,\r
-       socklen_t source_len,\r
-       unsigned int if_index,\r
-       enum source_op sop TSRMLS_DC)\r
-{\r
-#ifdef RFC3678_API\r
-       struct group_source_req gsreq = {0};\r
-       \r
-       memcpy(&gsreq.gsr_group, group, group_len);\r
-       assert(gsreq.gsr_group.ss_family != 0);\r
-       memcpy(&gsreq.gsr_source, source, source_len);\r
-       assert(gsreq.gsr_source.ss_family != 0);\r
-       gsreq.gsr_interface = if_index;\r
-       \r
-       return setsockopt(sock->bsd_socket, level,\r
-                       _php_source_op_to_rfc3678_op(sop), (char*)&gsreq, sizeof(gsreq));\r
-#else\r
-       if (sock->type == AF_INET) {\r
-               struct ip_mreq_source mreqs = {0};\r
-               struct in_addr addr;\r
-               \r
-               mreqs.imr_multiaddr = ((struct sockaddr_in*)group)->sin_addr;\r
-               mreqs.imr_sourceaddr =  ((struct sockaddr_in*)source)->sin_addr;\r
-               \r
-               assert(group_len == sizeof(struct sockaddr_in));\r
-               assert(source_len == sizeof(struct sockaddr_in));\r
-               \r
-               if (if_index != 0) {\r
-                       if (php_if_index_to_addr4(if_index, sock, &addr TSRMLS_CC) ==\r
-                                       FAILURE)\r
-                               return -2; /* failure, but notice already emitted */\r
-                       mreqs.imr_interface = addr;\r
-               } else {\r
-                       mreqs.imr_interface.s_addr = htonl(INADDR_ANY);\r
-               }\r
-               \r
-               return setsockopt(sock->bsd_socket, level,\r
-                               _php_source_op_to_ipv4_op(sop), (char*)&mreqs, sizeof(mreqs));\r
-       }\r
-#if HAVE_IPV6\r
-       else if (sock->type == AF_INET6) {\r
-               php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-                       "This platform does not support %s for IPv6 sockets",\r
-                       _php_source_op_to_string(sop));\r
-               return -2;\r
-       }\r
-#endif\r
-       else {\r
-               php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-                       "Option %s is inapplicable to this socket type",\r
-                       _php_source_op_to_string(sop));\r
-               return -2;\r
-       }\r
-#endif\r
-}\r
-\r
-#if RFC3678_API\r
-static int _php_source_op_to_rfc3678_op(enum source_op sop)\r
-{\r
-       switch (sop) {\r
-       case JOIN_SOURCE:\r
-               return MCAST_JOIN_SOURCE_GROUP;\r
-       case LEAVE_SOURCE:\r
-               return MCAST_LEAVE_SOURCE_GROUP;\r
-       case BLOCK_SOURCE:\r
-               return MCAST_BLOCK_SOURCE;\r
-       case UNBLOCK_SOURCE:\r
-               return MCAST_UNBLOCK_SOURCE;\r
-       }\r
-       \r
-       assert(0);\r
-       return 0;\r
-}\r
-#else\r
-static const char *_php_source_op_to_string(enum source_op sop)\r
-{\r
-       switch (sop) {\r
-       case JOIN_SOURCE:\r
-               return "MCAST_JOIN_SOURCE_GROUP";\r
-       case LEAVE_SOURCE:\r
-               return "MCAST_LEAVE_SOURCE_GROUP";\r
-       case BLOCK_SOURCE:\r
-               return "MCAST_BLOCK_SOURCE";\r
-       case UNBLOCK_SOURCE:\r
-               return "MCAST_UNBLOCK_SOURCE";\r
-       }\r
-       \r
-       assert(0);\r
-       return "";\r
-}\r
-\r
-static int _php_source_op_to_ipv4_op(enum source_op sop)\r
-{\r
-       switch (sop) {\r
-       case JOIN_SOURCE:\r
-               return IP_ADD_SOURCE_MEMBERSHIP;\r
-       case LEAVE_SOURCE:\r
-               return IP_DROP_SOURCE_MEMBERSHIP;\r
-       case BLOCK_SOURCE:\r
-               return IP_BLOCK_SOURCE;\r
-       case UNBLOCK_SOURCE:\r
-               return IP_UNBLOCK_SOURCE;\r
-       }\r
-       \r
-       assert(0);\r
-       return 0;\r
-}\r
-#endif\r
-\r
-#if PHP_WIN32\r
-int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr TSRMLS_DC)\r
-{\r
-       MIB_IPADDRTABLE *addr_table;\r
-    ULONG size;\r
-    DWORD retval;\r
-       DWORD i;\r
-\r
-       (void) php_sock; /* not necessary */\r
-\r
-       if (if_index == 0) {\r
-               out_addr->s_addr = INADDR_ANY;\r
-               return SUCCESS;\r
-       }\r
-\r
-       size = 4 * (sizeof *addr_table);\r
-       addr_table = emalloc(size);\r
-retry:\r
-       retval = GetIpAddrTable(addr_table, &size, 0);\r
-       if (retval == ERROR_INSUFFICIENT_BUFFER) {\r
-               efree(addr_table);\r
-               addr_table = emalloc(size);\r
-               goto retry;\r
-       }\r
-       if (retval != NO_ERROR) {\r
-               php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-                       "GetIpAddrTable failed with error %lu", retval);\r
-               return FAILURE;\r
-       }\r
-       for (i = 0; i < addr_table->dwNumEntries; i++) {\r
-               MIB_IPADDRROW r = addr_table->table[i];\r
-               if (r.dwIndex == if_index) {\r
-                       out_addr->s_addr = r.dwAddr;\r
-                       return SUCCESS;\r
-               }\r
-       }\r
-       php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-               "No interface with index %u was found", if_index);\r
-       return FAILURE;\r
-}\r
-\r
-int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index TSRMLS_DC)\r
-{\r
-       MIB_IPADDRTABLE *addr_table;\r
-    ULONG size;\r
-    DWORD retval;\r
-       DWORD i;\r
-\r
-       (void) php_sock; /* not necessary */\r
-\r
-       if (addr->s_addr == INADDR_ANY) {\r
-               *if_index = 0;\r
-               return SUCCESS;\r
-       }\r
-\r
-       size = 4 * (sizeof *addr_table);\r
-       addr_table = emalloc(size);\r
-retry:\r
-       retval = GetIpAddrTable(addr_table, &size, 0);\r
-       if (retval == ERROR_INSUFFICIENT_BUFFER) {\r
-               efree(addr_table);\r
-               addr_table = emalloc(size);\r
-               goto retry;\r
-       }\r
-       if (retval != NO_ERROR) {\r
-               php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-                       "GetIpAddrTable failed with error %lu", retval);\r
-               return FAILURE;\r
-       }\r
-       for (i = 0; i < addr_table->dwNumEntries; i++) {\r
-               MIB_IPADDRROW r = addr_table->table[i];\r
-               if (r.dwAddr == addr->s_addr) {\r
-                       *if_index = r.dwIndex;\r
-                       return SUCCESS;\r
-               }\r
-       }\r
-\r
-       {\r
-               char addr_str[17] = {0};\r
-               inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str));\r
-               php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-                       "The interface with IP address %s was not found", addr_str);\r
-       }\r
-       return FAILURE;\r
-}\r
-\r
-#else\r
-\r
-int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr TSRMLS_DC)\r
-{\r
-       struct ifreq if_req;\r
-       \r
-       if (if_index == 0) {\r
-               out_addr->s_addr = INADDR_ANY;\r
-               return SUCCESS;\r
-       }\r
-\r
-       if_req.ifr_ifindex = if_index;\r
-       if (ioctl(php_sock->bsd_socket, SIOCGIFNAME, &if_req) == -1) {\r
-               php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-                       "Failed obtaining address for interface %u: error %d", if_index, errno);\r
-               return FAILURE;\r
-       }\r
-       if (ioctl(php_sock->bsd_socket, SIOCGIFADDR, &if_req) == -1) {\r
-               php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-                       "Failed obtaining address for interface %u: error %d", if_index, errno);\r
-               return FAILURE;\r
-       }\r
-       \r
-       memcpy(out_addr, &((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr,\r
-               sizeof *out_addr);\r
-       return SUCCESS;\r
-}\r
-\r
-int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index TSRMLS_DC)\r
-{\r
-       struct ifconf   if_conf = {0};\r
-       char                    *buf = NULL,\r
-                                       *p;\r
-       int                             size = 0,\r
-                                       lastsize = 0;\r
-       size_t                  entry_len;\r
-       \r
-       if (addr->s_addr == INADDR_ANY) {\r
-               *if_index = 0;\r
-               return SUCCESS;\r
-       }\r
-       \r
-       for(;;) {\r
-               size += 5 * sizeof(struct ifreq);\r
-               buf = ecalloc(size, 1);\r
-               if_conf.ifc_len = size;\r
-               if_conf.ifc_buf = buf;\r
-               \r
-               if (ioctl(php_sock->bsd_socket, SIOCGIFCONF, (char*)&if_conf) == -1 &&\r
-                               (errno != EINVAL || lastsize != 0)) {\r
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-                               "Failed obtaining interfaces list: error %d", errno);\r
-                       goto err;\r
-               }\r
-               \r
-               if (if_conf.ifc_len == lastsize)\r
-                       /* not increasing anymore */\r
-                       break;\r
-               else {\r
-                       lastsize = if_conf.ifc_len;\r
-                       efree(buf);\r
-                       buf = NULL;\r
-               }\r
-       }\r
-       \r
-       for (p = if_conf.ifc_buf;\r
-                p < if_conf.ifc_buf + if_conf.ifc_len;\r
-                p += entry_len) {\r
-               struct ifreq *cur_req;\r
-               \r
-               /* let's hope the pointer is aligned */\r
-               cur_req = (struct ifreq*) p;\r
-               \r
-#ifdef HAVE_SOCKADDR_SA_LEN\r
-               entry_len = cur_req->ifr_addr.sa_len + sizeof(cur_req->ifr_name);\r
-#else\r
-               /* if there's no sa_len, assume the ifr_addr field is a sockaddr */\r
-               entry_len = sizeof(struct sockaddr) + sizeof(cur_req->ifr_name);\r
-#endif\r
-               entry_len = MAX(entry_len, sizeof(*cur_req));\r
-               \r
-               if ((((struct sockaddr*)&cur_req->ifr_addr)->sa_family == AF_INET) &&\r
-                               (((struct sockaddr_in*)&cur_req->ifr_addr)->sin_addr.s_addr ==\r
-                                       addr->s_addr)) {\r
-                       if (ioctl(php_sock->bsd_socket, SIOCGIFINDEX, (char*)cur_req)\r
-                                       == -1) {\r
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-                                       "Error converting interface name to index: error %d",\r
-                                       errno);\r
-                               goto err;\r
-                       } else {\r
-                               *if_index = cur_req->ifr_ifindex;\r
-                               efree(buf);\r
-                               return SUCCESS;\r
-                       }\r
-               }\r
-       }\r
-\r
-       {\r
-               char addr_str[17] = {0};\r
-               inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str));\r
-               php_error_docref(NULL TSRMLS_CC, E_WARNING,\r
-                       "The interface with IP address %s was not found", addr_str);\r
-       }\r
-       \r
-err:\r
-       if (buf != NULL)\r
-               efree(buf);\r
-       return FAILURE;\r
-}\r
-#endif\r
-\r
-#endif /* HAVE_SOCKETS */\r
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2011 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Gustavo Lopes    <cataphract@php.net>                       |
+   +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+
+#if HAVE_SOCKETS
+
+#include "php_network.h"
+#ifdef PHP_WIN32
+# include "win32/inet.h"
+# include <winsock2.h>
+# include <windows.h>
+# include <Ws2tcpip.h>
+# include <Ws2ipdef.h>
+# include "php_sockets.h"
+# include "win32/sockets.h"
+# define NTDDI_XP NTDDI_WINXP /* bug in SDK */
+# include <IPHlpApi.h>
+# undef NTDDI_XP
+#else
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include "php_sockets.h"
+#include "multicast.h"
+#include "main/php_network.h"
+
+#if defined(MCAST_JOIN_GROUP) && 1 &&\
+       (!defined(PHP_WIN32) || (_WIN32_WINNT >= 0x600 && SOCKETS_ENABLE_VISTA_API))
+#define RFC3678_API 1
+#endif
+
+
+enum source_op {
+       JOIN_SOURCE,
+       LEAVE_SOURCE,
+       BLOCK_SOURCE,
+       UNBLOCK_SOURCE
+};
+
+static int _php_mcast_join_leave(php_socket *sock, int level, struct sockaddr *group, socklen_t group_len, unsigned int if_index, int join TSRMLS_DC);
+static int _php_mcast_source_op(php_socket *sock, int level, struct sockaddr *group, socklen_t group_len, struct sockaddr *source, socklen_t source_len, unsigned int if_index, enum source_op sop TSRMLS_DC);
+#if RFC3678_API
+static int _php_source_op_to_rfc3678_op(enum source_op sop);
+#else
+static const char *_php_source_op_to_string(enum source_op sop);
+static int _php_source_op_to_ipv4_op(enum source_op sop);
+#endif
+
+int php_mcast_join(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       unsigned int if_index TSRMLS_DC)
+{
+       return _php_mcast_join_leave(sock, level, group, group_len, if_index, 1 TSRMLS_CC);
+}
+
+int php_mcast_leave(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       unsigned int if_index TSRMLS_DC)
+{
+       return _php_mcast_join_leave(sock, level, group, group_len, if_index, 0 TSRMLS_CC);
+}
+
+int php_mcast_join_source(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       struct sockaddr *source,
+       socklen_t source_len,
+       unsigned int if_index TSRMLS_DC)
+{
+       return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, JOIN_SOURCE TSRMLS_CC);
+}
+
+int php_mcast_leave_source(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       struct sockaddr *source,
+       socklen_t source_len,
+       unsigned int if_index TSRMLS_DC)
+{
+       return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, LEAVE_SOURCE TSRMLS_CC);
+}
+
+int php_mcast_block_source(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       struct sockaddr *source,
+       socklen_t source_len,
+       unsigned int if_index TSRMLS_DC)
+{
+       return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, BLOCK_SOURCE TSRMLS_CC);
+}
+
+int php_mcast_unblock_source(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       struct sockaddr *source,
+       socklen_t source_len,
+       unsigned int if_index TSRMLS_DC)
+{
+       return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, UNBLOCK_SOURCE TSRMLS_CC);
+}
+
+static int _php_mcast_join_leave(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group, /* struct sockaddr_in/sockaddr_in6 */
+       socklen_t group_len,
+       unsigned int if_index,
+       int join TSRMLS_DC)
+{
+#ifdef RFC3678_API
+       struct group_req greq = {0};
+       
+       memcpy(&greq.gr_group, group, group_len);
+       assert(greq.gr_group.ss_family != 0); /* the caller has set this */
+       greq.gr_interface = if_index;
+
+       return setsockopt(sock->bsd_socket, level,
+                       join ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (char*)&greq,
+                       sizeof(greq));  
+#else
+       if (sock->type == AF_INET) {
+               struct ip_mreq mreq = {0};
+               struct in_addr addr;
+               
+               assert(group_len == sizeof(struct sockaddr_in));
+               
+               if (if_index != 0) {
+                       if (php_if_index_to_addr4(if_index, sock, &addr TSRMLS_CC) ==
+                                       FAILURE)
+                               return -2; /* failure, but notice already emitted */
+                       mreq.imr_interface = addr;
+               } else {
+                       mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+               }
+               mreq.imr_multiaddr = ((struct sockaddr_in*)group)->sin_addr;
+               return setsockopt(sock->bsd_socket, level,
+                               join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, (char*)&mreq,
+                               sizeof(mreq));
+       }
+#if HAVE_IPV6
+       else if (sock->type == AF_INET6) {
+               struct ipv6_mreq mreq = {0};
+               
+               assert(group_len == sizeof(struct sockaddr_in6));
+
+               mreq.ipv6mr_multiaddr = ((struct sockaddr_in6*)group)->sin6_addr;
+               mreq.ipv6mr_interface = if_index;
+               
+               return setsockopt(sock->bsd_socket, level,
+                               join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP, (char*)&mreq,
+                               sizeof(mreq));
+       }
+#endif
+       else {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "Option %s is inapplicable to this socket type",
+                       join ? "MCAST_JOIN_GROUP" : "MCAST_LEAVE_GROUP");
+               return -2;
+       }
+#endif
+}
+
+static int _php_mcast_source_op(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       struct sockaddr *source,
+       socklen_t source_len,
+       unsigned int if_index,
+       enum source_op sop TSRMLS_DC)
+{
+#ifdef RFC3678_API
+       struct group_source_req gsreq = {0};
+       
+       memcpy(&gsreq.gsr_group, group, group_len);
+       assert(gsreq.gsr_group.ss_family != 0);
+       memcpy(&gsreq.gsr_source, source, source_len);
+       assert(gsreq.gsr_source.ss_family != 0);
+       gsreq.gsr_interface = if_index;
+       
+       return setsockopt(sock->bsd_socket, level,
+                       _php_source_op_to_rfc3678_op(sop), (char*)&gsreq, sizeof(gsreq));
+#else
+       if (sock->type == AF_INET) {
+               struct ip_mreq_source mreqs = {0};
+               struct in_addr addr;
+               
+               mreqs.imr_multiaddr = ((struct sockaddr_in*)group)->sin_addr;
+               mreqs.imr_sourceaddr =  ((struct sockaddr_in*)source)->sin_addr;
+               
+               assert(group_len == sizeof(struct sockaddr_in));
+               assert(source_len == sizeof(struct sockaddr_in));
+               
+               if (if_index != 0) {
+                       if (php_if_index_to_addr4(if_index, sock, &addr TSRMLS_CC) ==
+                                       FAILURE)
+                               return -2; /* failure, but notice already emitted */
+                       mreqs.imr_interface = addr;
+               } else {
+                       mreqs.imr_interface.s_addr = htonl(INADDR_ANY);
+               }
+               
+               return setsockopt(sock->bsd_socket, level,
+                               _php_source_op_to_ipv4_op(sop), (char*)&mreqs, sizeof(mreqs));
+       }
+#if HAVE_IPV6
+       else if (sock->type == AF_INET6) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "This platform does not support %s for IPv6 sockets",
+                       _php_source_op_to_string(sop));
+               return -2;
+       }
+#endif
+       else {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "Option %s is inapplicable to this socket type",
+                       _php_source_op_to_string(sop));
+               return -2;
+       }
+#endif
+}
+
+#if RFC3678_API
+static int _php_source_op_to_rfc3678_op(enum source_op sop)
+{
+       switch (sop) {
+       case JOIN_SOURCE:
+               return MCAST_JOIN_SOURCE_GROUP;
+       case LEAVE_SOURCE:
+               return MCAST_LEAVE_SOURCE_GROUP;
+       case BLOCK_SOURCE:
+               return MCAST_BLOCK_SOURCE;
+       case UNBLOCK_SOURCE:
+               return MCAST_UNBLOCK_SOURCE;
+       }
+       
+       assert(0);
+       return 0;
+}
+#else
+static const char *_php_source_op_to_string(enum source_op sop)
+{
+       switch (sop) {
+       case JOIN_SOURCE:
+               return "MCAST_JOIN_SOURCE_GROUP";
+       case LEAVE_SOURCE:
+               return "MCAST_LEAVE_SOURCE_GROUP";
+       case BLOCK_SOURCE:
+               return "MCAST_BLOCK_SOURCE";
+       case UNBLOCK_SOURCE:
+               return "MCAST_UNBLOCK_SOURCE";
+       }
+       
+       assert(0);
+       return "";
+}
+
+static int _php_source_op_to_ipv4_op(enum source_op sop)
+{
+       switch (sop) {
+       case JOIN_SOURCE:
+               return IP_ADD_SOURCE_MEMBERSHIP;
+       case LEAVE_SOURCE:
+               return IP_DROP_SOURCE_MEMBERSHIP;
+       case BLOCK_SOURCE:
+               return IP_BLOCK_SOURCE;
+       case UNBLOCK_SOURCE:
+               return IP_UNBLOCK_SOURCE;
+       }
+       
+       assert(0);
+       return 0;
+}
+#endif
+
+#if PHP_WIN32
+int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr TSRMLS_DC)
+{
+       MIB_IPADDRTABLE *addr_table;
+    ULONG size;
+    DWORD retval;
+       DWORD i;
+
+       (void) php_sock; /* not necessary */
+
+       if (if_index == 0) {
+               out_addr->s_addr = INADDR_ANY;
+               return SUCCESS;
+       }
+
+       size = 4 * (sizeof *addr_table);
+       addr_table = emalloc(size);
+retry:
+       retval = GetIpAddrTable(addr_table, &size, 0);
+       if (retval == ERROR_INSUFFICIENT_BUFFER) {
+               efree(addr_table);
+               addr_table = emalloc(size);
+               goto retry;
+       }
+       if (retval != NO_ERROR) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "GetIpAddrTable failed with error %lu", retval);
+               return FAILURE;
+       }
+       for (i = 0; i < addr_table->dwNumEntries; i++) {
+               MIB_IPADDRROW r = addr_table->table[i];
+               if (r.dwIndex == if_index) {
+                       out_addr->s_addr = r.dwAddr;
+                       return SUCCESS;
+               }
+       }
+       php_error_docref(NULL TSRMLS_CC, E_WARNING,
+               "No interface with index %u was found", if_index);
+       return FAILURE;
+}
+
+int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index TSRMLS_DC)
+{
+       MIB_IPADDRTABLE *addr_table;
+    ULONG size;
+    DWORD retval;
+       DWORD i;
+
+       (void) php_sock; /* not necessary */
+
+       if (addr->s_addr == INADDR_ANY) {
+               *if_index = 0;
+               return SUCCESS;
+       }
+
+       size = 4 * (sizeof *addr_table);
+       addr_table = emalloc(size);
+retry:
+       retval = GetIpAddrTable(addr_table, &size, 0);
+       if (retval == ERROR_INSUFFICIENT_BUFFER) {
+               efree(addr_table);
+               addr_table = emalloc(size);
+               goto retry;
+       }
+       if (retval != NO_ERROR) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "GetIpAddrTable failed with error %lu", retval);
+               return FAILURE;
+       }
+       for (i = 0; i < addr_table->dwNumEntries; i++) {
+               MIB_IPADDRROW r = addr_table->table[i];
+               if (r.dwAddr == addr->s_addr) {
+                       *if_index = r.dwIndex;
+                       return SUCCESS;
+               }
+       }
+
+       {
+               char addr_str[17] = {0};
+               inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str));
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "The interface with IP address %s was not found", addr_str);
+       }
+       return FAILURE;
+}
+
+#else
+
+int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr TSRMLS_DC)
+{
+       struct ifreq if_req;
+       
+       if (if_index == 0) {
+               out_addr->s_addr = INADDR_ANY;
+               return SUCCESS;
+       }
+
+       if_req.ifr_ifindex = if_index;
+       if (ioctl(php_sock->bsd_socket, SIOCGIFNAME, &if_req) == -1) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "Failed obtaining address for interface %u: error %d", if_index, errno);
+               return FAILURE;
+       }
+       if (ioctl(php_sock->bsd_socket, SIOCGIFADDR, &if_req) == -1) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "Failed obtaining address for interface %u: error %d", if_index, errno);
+               return FAILURE;
+       }
+       
+       memcpy(out_addr, &((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr,
+               sizeof *out_addr);
+       return SUCCESS;
+}
+
+int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index TSRMLS_DC)
+{
+       struct ifconf   if_conf = {0};
+       char                    *buf = NULL,
+                                       *p;
+       int                             size = 0,
+                                       lastsize = 0;
+       size_t                  entry_len;
+       
+       if (addr->s_addr == INADDR_ANY) {
+               *if_index = 0;
+               return SUCCESS;
+       }
+       
+       for(;;) {
+               size += 5 * sizeof(struct ifreq);
+               buf = ecalloc(size, 1);
+               if_conf.ifc_len = size;
+               if_conf.ifc_buf = buf;
+               
+               if (ioctl(php_sock->bsd_socket, SIOCGIFCONF, (char*)&if_conf) == -1 &&
+                               (errno != EINVAL || lastsize != 0)) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                               "Failed obtaining interfaces list: error %d", errno);
+                       goto err;
+               }
+               
+               if (if_conf.ifc_len == lastsize)
+                       /* not increasing anymore */
+                       break;
+               else {
+                       lastsize = if_conf.ifc_len;
+                       efree(buf);
+                       buf = NULL;
+               }
+       }
+       
+       for (p = if_conf.ifc_buf;
+                p < if_conf.ifc_buf + if_conf.ifc_len;
+                p += entry_len) {
+               struct ifreq *cur_req;
+               
+               /* let's hope the pointer is aligned */
+               cur_req = (struct ifreq*) p;
+               
+#ifdef HAVE_SOCKADDR_SA_LEN
+               entry_len = cur_req->ifr_addr.sa_len + sizeof(cur_req->ifr_name);
+#else
+               /* if there's no sa_len, assume the ifr_addr field is a sockaddr */
+               entry_len = sizeof(struct sockaddr) + sizeof(cur_req->ifr_name);
+#endif
+               entry_len = MAX(entry_len, sizeof(*cur_req));
+               
+               if ((((struct sockaddr*)&cur_req->ifr_addr)->sa_family == AF_INET) &&
+                               (((struct sockaddr_in*)&cur_req->ifr_addr)->sin_addr.s_addr ==
+                                       addr->s_addr)) {
+                       if (ioctl(php_sock->bsd_socket, SIOCGIFINDEX, (char*)cur_req)
+                                       == -1) {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                                       "Error converting interface name to index: error %d",
+                                       errno);
+                               goto err;
+                       } else {
+                               *if_index = cur_req->ifr_ifindex;
+                               efree(buf);
+                               return SUCCESS;
+                       }
+               }
+       }
+
+       {
+               char addr_str[17] = {0};
+               inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str));
+               php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                       "The interface with IP address %s was not found", addr_str);
+       }
+       
+err:
+       if (buf != NULL)
+               efree(buf);
+       return FAILURE;
+}
+#endif
+
+#endif /* HAVE_SOCKETS */
index 45003c9cc262acc57095e9909667c25b00760a43..5b63cf03815cb69d7d01e282dc7ff9ab39d82957 100644 (file)
@@ -1,79 +1,79 @@
-/*\r
-   +----------------------------------------------------------------------+\r
-   | PHP Version 5                                                        |\r
-   +----------------------------------------------------------------------+\r
-   | Copyright (c) 1997-2011 The PHP Group                                |\r
-   +----------------------------------------------------------------------+\r
-   | This source file is subject to version 3.01 of the PHP license,      |\r
-   | that is bundled with this package in the file LICENSE, and is        |\r
-   | available through the world-wide-web at the following url:           |\r
-   | http://www.php.net/license/3_01.txt                                  |\r
-   | If you did not receive a copy of the PHP license and are unable to   |\r
-   | obtain it through the world-wide-web, please send a note to          |\r
-   | license@php.net so we can mail you a copy immediately.               |\r
-   +----------------------------------------------------------------------+\r
-   | Authors: Gustavo Lopes    <cataphract@php.net>                       |\r
-   +----------------------------------------------------------------------+\r
- */\r
-\r
-/* $Id$ */\r
-\r
-int php_if_index_to_addr4(\r
-        unsigned if_index,\r
-        php_socket *php_sock,\r
-        struct in_addr *out_addr TSRMLS_DC);\r
-\r
-int php_add4_to_if_index(\r
-        struct in_addr *addr,\r
-        php_socket *php_sock,\r
-        unsigned *if_index TSRMLS_DC);\r
-\r
-int php_mcast_join(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       unsigned int if_index TSRMLS_DC);\r
-\r
-int php_mcast_leave(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       unsigned int if_index TSRMLS_DC);\r
-\r
-int php_mcast_join_source(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       struct sockaddr *source,\r
-       socklen_t source_len,\r
-       unsigned int if_index TSRMLS_DC);\r
-\r
-int php_mcast_leave_source(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       struct sockaddr *source,\r
-       socklen_t source_len,\r
-       unsigned int if_index TSRMLS_DC);\r
-\r
-int php_mcast_block_source(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       struct sockaddr *source,\r
-       socklen_t source_len,\r
-       unsigned int if_index TSRMLS_DC);\r
-\r
-int php_mcast_unblock_source(\r
-       php_socket *sock,\r
-       int level,\r
-       struct sockaddr *group,\r
-       socklen_t group_len,\r
-       struct sockaddr *source,\r
-       socklen_t source_len,\r
-       unsigned int if_index TSRMLS_DC);\r
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2011 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Gustavo Lopes    <cataphract@php.net>                       |
+   +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+int php_if_index_to_addr4(
+        unsigned if_index,
+        php_socket *php_sock,
+        struct in_addr *out_addr TSRMLS_DC);
+
+int php_add4_to_if_index(
+        struct in_addr *addr,
+        php_socket *php_sock,
+        unsigned *if_index TSRMLS_DC);
+
+int php_mcast_join(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       unsigned int if_index TSRMLS_DC);
+
+int php_mcast_leave(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       unsigned int if_index TSRMLS_DC);
+
+int php_mcast_join_source(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       struct sockaddr *source,
+       socklen_t source_len,
+       unsigned int if_index TSRMLS_DC);
+
+int php_mcast_leave_source(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       struct sockaddr *source,
+       socklen_t source_len,
+       unsigned int if_index TSRMLS_DC);
+
+int php_mcast_block_source(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       struct sockaddr *source,
+       socklen_t source_len,
+       unsigned int if_index TSRMLS_DC);
+
+int php_mcast_unblock_source(
+       php_socket *sock,
+       int level,
+       struct sockaddr *group,
+       socklen_t group_len,
+       struct sockaddr *source,
+       socklen_t source_len,
+       unsigned int if_index TSRMLS_DC);