- Improvements in the multicast tests.
- Very light refactoring in sockets.c.
#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,
};
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);
+#ifdef HAS_MCAST_EXT
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
+#endif
+
+#ifdef RFC3678_API
static int _php_source_op_to_rfc3678_op(enum source_op sop);
-#else
+#elif HAS_MCAST_EXT
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
return _php_mcast_join_leave(sock, level, group, group_len, if_index, 0 TSRMLS_CC);
}
+#ifdef HAS_MCAST_EXT
int php_mcast_join_source(
php_socket *sock,
int level,
{
return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, UNBLOCK_SOURCE TSRMLS_CC);
}
+#endif /* HAS_MCAST_EXT */
+
static int _php_mcast_join_leave(
php_socket *sock,
#endif
}
+#ifdef HAS_MCAST_EXT
static int _php_mcast_source_op(
php_socket *sock,
int level,
}
#endif
+#endif /* HAS_MCAST_EXT */
+
#if PHP_WIN32
int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr TSRMLS_DC)
{
/* $Id$ */
+#if defined(MCAST_JOIN_GROUP) && \
+ (!defined(PHP_WIN32) || (_WIN32_WINNT >= 0x600 && SOCKETS_ENABLE_VISTA_API))
+#define RFC3678_API 1
+/* has block/unblock and source membership, in this case for both IPv4 and IPv6 */
+#define HAS_MCAST_EXT 1
+#elif defined(IP_ADD_SOURCE_MEMBERSHIP)
+/* has block/unblock and source membership, but only for IPv4 */
+#define HAS_MCAST_EXT 1
+#endif
+
int php_if_index_to_addr4(
unsigned if_index,
php_socket *php_sock,
socklen_t group_len,
unsigned int if_index TSRMLS_DC);
+#ifdef HAS_MCAST_EXT
int php_mcast_join_source(
php_socket *sock,
int level,
struct sockaddr *source,
socklen_t source_len,
unsigned int if_index TSRMLS_DC);
+#endif
REGISTER_LONG_CONSTANT("PHP_NORMAL_READ", PHP_NORMAL_READ, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PHP_BINARY_READ", PHP_BINARY_READ, CONST_CS | CONST_PERSISTENT);
-#ifndef MCAST_JOIN_GROUP
+#ifndef RFC3678_API
#define MCAST_JOIN_GROUP IP_ADD_MEMBERSHIP
#define MCAST_LEAVE_GROUP IP_DROP_MEMBERSHIP
+#ifdef HAS_MCAST_EXT
#define MCAST_BLOCK_SOURCE IP_BLOCK_SOURCE
#define MCAST_UNBLOCK_SOURCE IP_UNBLOCK_SOURCE
#define MCAST_JOIN_SOURCE_GROUP IP_ADD_SOURCE_MEMBERSHIP
#define MCAST_LEAVE_SOURCE_GROUP IP_DROP_SOURCE_MEMBERSHIP
+#endif
#endif
REGISTER_LONG_CONSTANT("MCAST_JOIN_GROUP", MCAST_JOIN_GROUP, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MCAST_LEAVE_GROUP", MCAST_LEAVE_GROUP, CONST_CS | CONST_PERSISTENT);
+#ifdef HAS_MCAST_EXT
REGISTER_LONG_CONSTANT("MCAST_BLOCK_SOURCE", MCAST_BLOCK_SOURCE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MCAST_UNBLOCK_SOURCE", MCAST_UNBLOCK_SOURCE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MCAST_JOIN_SOURCE_GROUP", MCAST_JOIN_SOURCE_GROUP, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MCAST_LEAVE_SOURCE_GROUP", MCAST_LEAVE_SOURCE_GROUP, CONST_CS | CONST_PERSISTENT);
+#endif
REGISTER_LONG_CONSTANT("IP_MULTICAST_IF", IP_MULTICAST_IF, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("IP_MULTICAST_TTL", IP_MULTICAST_TTL, CONST_CS | CONST_PERSISTENT);
{
zval *arg1;
php_socket *php_sock;
- struct sockaddr_in sin;
-#if HAVE_IPV6
- struct sockaddr_in6 sin6;
-#endif
- struct sockaddr_un s_un;
char *addr;
int retval, addr_len;
long port = 0;
switch(php_sock->type) {
#if HAVE_IPV6
- case AF_INET6:
+ case AF_INET6: {
+ struct sockaddr_in6 sin6 = {0};
+
if (argc != 3) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET6 requires 3 arguments");
RETURN_FALSE;
retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin6, sizeof(struct sockaddr_in6));
break;
+ }
#endif
- case AF_INET:
+ case AF_INET: {
+ struct sockaddr_in sin = {0};
+
if (argc != 3) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Socket of type AF_INET requires 3 arguments");
RETURN_FALSE;
}
- memset(&sin, 0, sizeof(struct sockaddr_in));
-
sin.sin_family = AF_INET;
sin.sin_port = htons((unsigned short int)port);
retval = connect(php_sock->bsd_socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
break;
+ }
- case AF_UNIX:
+ case AF_UNIX: {
+ struct sockaddr_un s_un = {0};
+
if (addr_len >= sizeof(s_un.sun_path)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Path too long");
RETURN_FALSE;
}
-
- memset(&s_un, 0, sizeof(struct sockaddr_un));
s_un.sun_family = AF_UNIX;
memcpy(&s_un.sun_path, addr, addr_len);
- retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un, (socklen_t) XtOffsetOf(struct sockaddr_un, sun_path) + addr_len);
+ retval = connect(php_sock->bsd_socket, (struct sockaddr *) &s_un,
+ (socklen_t)(XtOffsetOf(struct sockaddr_un, sun_path) + addr_len));
break;
+ }
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported socket type %d", php_sock->type);
int retval;
int (*mcast_req_fun)(php_socket *, int, struct sockaddr *, socklen_t,
unsigned TSRMLS_DC);
+#ifdef HAS_MCAST_EXT
int (*mcast_sreq_fun)(php_socket *, int, struct sockaddr *, socklen_t,
struct sockaddr *, socklen_t, unsigned TSRMLS_DC);
+#endif
switch (optname) {
case MCAST_JOIN_GROUP:
break;
}
+#ifdef HAS_MCAST_EXT
case MCAST_BLOCK_SOURCE:
mcast_sreq_fun = &php_mcast_block_source;
goto mcast_sreq_fun;
glen, (struct sockaddr*)&source, slen, if_index TSRMLS_CC);
break;
}
+#endif
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"unexpected option in php_do_mcast_opt (level %d, option %d). "
if (level == IPPROTO_IP) {
switch (optname) {
case MCAST_JOIN_GROUP:
- case MCAST_LEAVE_GROUP:
+ case MCAST_LEAVE_GROUP:
+#ifdef HAS_MCAST_EXT
case MCAST_BLOCK_SOURCE:
case MCAST_UNBLOCK_SOURCE:
case MCAST_JOIN_SOURCE_GROUP:
case MCAST_LEAVE_SOURCE_GROUP:
+#endif
if (php_do_mcast_opt(php_sock, level, optname, arg4 TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
} else {
--- /dev/null
+<?php
+function checktimeout($sock, $limit) {
+ $readfs = array($sock);
+ $writefs = $exceptfs = array();
+ if (socket_select($readfs, $writefs, $exceptfs, 0, $limit*1000) != 1) {
+ die("Socket read timeout hit. Can be a bug, a test bug, or a firewall issue.");
+ }
+}
if ($so === false) {\r
die('skip interface \'lo\' is unavailable.');\r
}\r
+if (!defined("MCAST_BLOCK_SOURCE")) {\r
+ die('skip source operations are unavailable');\r
+}\r
--FILE--\r
<?php\r
+include __DIR__."/mcast_helpers.php.inc";\r
$domain = AF_INET;\r
$level = IPPROTO_IP;\r
$interface = "lo";\r
var_dump($r);\r
\r
$i = 0;\r
+checktimeout($s, 500);\r
while (($str = socket_read($s, 3000)) !== FALSE) {\r
$i++;\r
echo "$i> ", $str, "\n";\r
}\r
\r
}\r
---EXPECT--\r
+--EXPECTF--\r
creating send socket bound to 127.0.0.1\r
bool(true)\r
creating unbound socket and hoping the routing table causes an interface other than lo to be used for sending messages to 224.0.0.23\r
bool(true)\r
creating receive socket\r
-resource(6) of type (Socket)\r
+resource(%d) of type (Socket)\r
bool(true)\r
bool(true)\r
int(14)\r
if ($r === false) {\r
die('skip unable to send multicast packet.');\r
}\r
+\r
+if (!defined("MCAST_JOIN_SOURCE_GROUP"))\r
+ die('skip source operations are unavailable');\r
+\r
$so = socket_set_option($s, IPPROTO_IPV6, MCAST_LEAVE_GROUP, array(\r
"group" => 'ff01::114',\r
"interface" => 0,\r
\r
--FILE--\r
<?php\r
+include __DIR__."/mcast_helpers.php.inc";\r
$domain = AF_INET6;\r
$level = IPPROTO_IPV6;\r
$interface = 0;\r
\r
$r = socket_sendto($sends1, $m = "testing packet", strlen($m), 0, $mcastaddr, 3000);\r
var_dump($r);\r
+checktimeout($s, 500);\r
$r = socket_recvfrom($s, $str, 2000, 0, $from, $fromPort);\r
var_dump($r, $str, $from);\r
$sblock = $from;\r
var_dump($r);\r
\r
$i = 0;\r
+checktimeout($s, 500);\r
while (($str = socket_read($s, 3000)) !== FALSE) {\r
$i++;\r
echo "$i> ", $str, "\n";\r
}\r
--EXPECTF--\r
creating send socket\r
-resource(4) of type (Socket)\r
+resource(%d) of type (Socket)\r
creating receive socket\r
-resource(5) of type (Socket)\r
+resource(%d) of type (Socket)\r
bool(true)\r
bool(true)\r
int(14)\r
"group" => 'ff01::114',\r
"interface" => 0,\r
));\r
-$so = socket_set_option($s, IPPROTO_IPV6, MCAST_JOIN_SOURCE_GROUP, array(\r
- "group" => 'ff01::114',\r
- "interface" => 0,\r
- "source" => '2001::dead:beef',\r
-));\r
-if ($so !== false) {\r
- die('skip protocol independent multicast API is available.');\r
+if (defined("MCAST_JOIN_SOURCE_GROUP")) {\r
+ $so = socket_set_option($s, IPPROTO_IPV6, MCAST_JOIN_SOURCE_GROUP, array(\r
+ "group" => 'ff01::114',\r
+ "interface" => 0,\r
+ "source" => '2001::dead:beef',\r
+ ));\r
+ if ($so !== false) {\r
+ die('skip protocol independent multicast API is available.');\r
+ }\r
}\r
\r
--FILE--\r
<?php\r
+include __DIR__."/mcast_helpers.php.inc";\r
$domain = AF_INET6;\r
$level = IPPROTO_IPV6;\r
$interface = 0;\r
\r
$r = socket_sendto($sends1, $m = "testing packet", strlen($m), 0, $mcastaddr, 3000);\r
var_dump($r);\r
+checktimeout($s, 500);\r
$r = socket_recvfrom($s, $str, 2000, 0, $from, $fromPort);\r
var_dump($r, $str, $from);\r
$sblock = $from;\r
var_dump($r);\r
\r
$i = 0;\r
-while (($str = socket_read($s, 3000)) !== FALSE) {\r
+checktimeout($s, 500);\r
+while (($str = socket_read($s, 3000, 500)) !== FALSE) {\r
$i++;\r
echo "$i> ", $str, "\n";\r
\r
}\r
--EXPECTF--\r
creating send socket\r
-resource(4) of type (Socket)\r
+resource(%d) of type (Socket)\r
creating receive socket\r
-resource(5) of type (Socket)\r
+resource(%d) of type (Socket)\r
bool(true)\r
bool(true)\r
int(14)\r