1
0
mirror of https://github.com/php/php-src.git synced 2026-04-04 22:52:40 +02:00

Merge branch 'PHP-5.5' of ssh://git.php.net/php-src into PHP-5.5

This commit is contained in:
Andrey Hristov
2013-02-04 14:15:29 +01:00
47 changed files with 3812 additions and 716 deletions

17
NEWS
View File

@@ -1,15 +1,32 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 201?, PHP 5.5.0 Beta 1
- Core:
. Fixed bug #60833 (self, parent, static behave inconsistently
case-sensitive). (Stas, mario at include-once dot org)
. Implemented FR #60524 (specify temp dir by php.ini). (ALeX Kazik).
. Fixed bug #63830 (Segfault on undefined function call in nested generator).
(Nikita Popov)
- CLI server:
. Fixed bug #64128 (buit-in web server is broken on ppc64). (Remi)
- cURL:
. Implemented FR #46439 - added CURLFile for safer file uploads.
(Stas)
- Intl:
. Cherry-picked UConverter wrapper, which had accidentaly been committed only
to master.
- Sockets:
. Added recvmsg() and sendmsg() wrappers. (Gustavo)
See https://wiki.php.net/rfc/sendrecvmsg
- Filter:
. Implemented FR #49180 - added MAC address validation. (Martin)
24 Jan 2013, PHP 5.5.0 Alpha 4
- Core:

View File

@@ -157,6 +157,8 @@ PHP 5.5 UPGRADE NOTES
Expires headers. (see https://wiki.php.net/rfc/cookie_max-age)
- curl_setopt now accepts new option CURLOPT_SAFE_UPLOAD and CURLFile object for
safer file uploads (see https://wiki.php.net/rfc/curl-file-upload)
- Functions in the socket extension now do not emit warnings when the errno is
EAGAIN, EWOULDBLOCK or EINPROGRESS.
========================================
5. New Functions
@@ -257,6 +259,11 @@ PHP 5.5 UPGRADE NOTES
- IntlDateFormatter::getTimeZone()
- IntlDateFormatter::setTimeZone()
- Sockets:
- socket_sendmsg()
- socket_recvmsg()
- socket_cmsg_space()
- SPL:
- SplFixedArray::__wakeup()
@@ -271,6 +278,7 @@ PHP 5.5 UPGRADE NOTES
- IntlBreakIterator
- IntlRuleBasedBreakIterator
- IntlCodePointBreakIterator
- UConverter
- cURL:
- CURLFile

View File

@@ -0,0 +1,18 @@
--TEST--
Tests cloning a generator with properties
--FILE--
<?php
function gen() { yield; }
$g1 = gen();
$g1->prop = 'val';
$g2 = clone $g1;
unset($g1);
var_dump($g2->prop);
?>
--EXPECT--
string(3) "val"

View File

@@ -0,0 +1,30 @@
--TEST--
Test nested calls with die() in a generator
--FILE--
<?php
function gen() {
die('Test');
yield; // force generator
}
function function_with_3_args() {
$gen = gen();
$gen->rewind();
}
function function_with_4_args() {
function_with_3_args(4, 5, 6);
}
function outerGen() {
function_with_4_args(0, 1, 2, 3);
yield; // force generator
}
$outerGen = outerGen();
$outerGen->rewind();
?>
--EXPECT--
Test

View File

@@ -27,6 +27,8 @@
ZEND_API zend_class_entry *zend_ce_generator;
static zend_object_handlers zend_generator_handlers;
static zend_object_value zend_generator_create(zend_class_entry *class_type TSRMLS_DC);
ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished_execution TSRMLS_DC) /* {{{ */
{
if (generator->value) {
@@ -92,10 +94,16 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
/* Clear any backed up stack arguments */
if (generator->stack != EG(argument_stack)) {
void **stack_frame = zend_vm_stack_frame_base(execute_data);
while (generator->stack->top != stack_frame) {
zval_ptr_dtor((zval**)stack_frame);
stack_frame++;
void **ptr = generator->stack->top - 1;
void **end = zend_vm_stack_frame_base(execute_data);
/* If the top stack element is the argument count, skip it */
if (execute_data->function_state.arguments) {
ptr--;
}
for (; ptr >= end; --ptr) {
zval_ptr_dtor((zval**) ptr);
}
}
@@ -188,10 +196,19 @@ static void zend_generator_free_storage(zend_generator *generator TSRMLS_DC) /*
}
/* }}} */
static void zend_generator_clone_storage(zend_generator *orig, zend_generator **clone_ptr TSRMLS_DC) /* {{{ */
static zend_object_value zend_generator_clone(zval *object TSRMLS_DC) /* {{{ */
{
zend_generator *clone = emalloc(sizeof(zend_generator));
memcpy(clone, orig, sizeof(zend_generator));
zend_generator *orig = zend_object_store_get_object(object TSRMLS_CC);
zend_object_value clone_val = zend_generator_create(Z_OBJCE_P(object) TSRMLS_CC);
zend_generator *clone = zend_object_store_get_object_by_handle(clone_val.handle TSRMLS_CC);
zend_objects_clone_members(
&clone->std, clone_val, &orig->std, Z_OBJ_HANDLE_P(object) TSRMLS_CC
);
clone->execute_data = orig->execute_data;
clone->largest_used_integer_key = orig->largest_used_integer_key;
clone->flags = orig->flags;
if (orig->execute_data) {
/* Create a few shorter aliases to the old execution data */
@@ -335,14 +352,16 @@ static void zend_generator_clone_storage(zend_generator *orig, zend_generator **
/* The value and key are known not to be references, so simply add refs */
if (orig->value) {
clone->value = orig->value;
Z_ADDREF_P(orig->value);
}
if (orig->key) {
clone->key = orig->key;
Z_ADDREF_P(orig->key);
}
*clone_ptr = clone;
return clone_val;
}
/* }}} */
@@ -362,8 +381,7 @@ static zend_object_value zend_generator_create(zend_class_entry *class_type TSRM
object.handle = zend_objects_store_put(generator,
(zend_objects_store_dtor_t) zend_generator_dtor_storage,
(zend_objects_free_object_storage_t) zend_generator_free_storage,
(zend_objects_store_clone_t) zend_generator_clone_storage
TSRMLS_CC
NULL TSRMLS_CC
);
object.handlers = &zend_generator_handlers;
@@ -863,7 +881,7 @@ void zend_register_generator_ce(TSRMLS_D) /* {{{ */
memcpy(&zend_generator_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
zend_generator_handlers.get_constructor = zend_generator_get_constructor;
zend_generator_handlers.clone_obj = zend_objects_store_clone_obj;
zend_generator_handlers.clone_obj = zend_generator_clone;
}
/* }}} */

View File

@@ -23,6 +23,7 @@
#endif
#include "php.h"
#include "Zend/zend_exceptions.h"
#include "php_curl.h"
#if HAVE_CURL

View File

@@ -23,10 +23,10 @@
#include "config.h"
#endif
#include <enchant.h>
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include <enchant.h>
#include "php_enchant.h"
typedef EnchantBroker * EnchantBrokerPtr;

View File

@@ -47,6 +47,7 @@ static const filter_list_entry filter_list[] = {
{ "validate_url", FILTER_VALIDATE_URL, php_filter_validate_url },
{ "validate_email", FILTER_VALIDATE_EMAIL, php_filter_validate_email },
{ "validate_ip", FILTER_VALIDATE_IP, php_filter_validate_ip },
{ "validate_mac", FILTER_VALIDATE_MAC, php_filter_validate_mac },
{ "string", FILTER_SANITIZE_STRING, php_filter_string },
{ "stripped", FILTER_SANITIZE_STRING, php_filter_string },
@@ -233,6 +234,7 @@ PHP_MINIT_FUNCTION(filter)
REGISTER_LONG_CONSTANT("FILTER_VALIDATE_URL", FILTER_VALIDATE_URL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FILTER_VALIDATE_EMAIL", FILTER_VALIDATE_EMAIL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FILTER_VALIDATE_IP", FILTER_VALIDATE_IP, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FILTER_VALIDATE_MAC", FILTER_VALIDATE_MAC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FILTER_DEFAULT", FILTER_DEFAULT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FILTER_UNSAFE_RAW", FILTER_UNSAFE_RAW, CONST_CS | CONST_PERSISTENT);

View File

@@ -63,7 +63,8 @@
#define FILTER_VALIDATE_URL 0x0111
#define FILTER_VALIDATE_EMAIL 0x0112
#define FILTER_VALIDATE_IP 0x0113
#define FILTER_VALIDATE_LAST 0x0113
#define FILTER_VALIDATE_MAC 0x0114
#define FILTER_VALIDATE_LAST 0x0114
#define FILTER_VALIDATE_ALL 0x0100

View File

@@ -784,6 +784,67 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
}
/* }}} */
void php_filter_validate_mac(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
{
char *input = Z_STRVAL_P(value);
int input_len = Z_STRLEN_P(value);
int tokens, length, i, offset, exp_separator_set, exp_separator_len;
char separator;
char *exp_separator;
long ret = 0;
zval **option_val;
FETCH_STRING_OPTION(exp_separator, "separator");
if (exp_separator_set && exp_separator_len != 1) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Separator must be exactly one character long");
RETURN_VALIDATION_FAILED;
}
if (14 == input_len) {
/* EUI-64 format: Four hexadecimal digits separated by dots. Less
* commonly used but valid nonetheless.
*/
tokens = 3;
length = 4;
separator = '.';
} else if (17 == input_len && input[2] == '-') {
/* IEEE 802 format: Six hexadecimal digits separated by hyphens. */
tokens = 6;
length = 2;
separator = '-';
} else if (17 == input_len && input[2] == ':') {
/* IEEE 802 format: Six hexadecimal digits separated by colons. */
tokens = 6;
length = 2;
separator = ':';
} else {
RETURN_VALIDATION_FAILED;
}
if (exp_separator_set && separator != exp_separator[0]) {
RETURN_VALIDATION_FAILED;
}
/* Essentially what we now have is a set of tokens each consisting of
* a hexadecimal number followed by a separator character. (With the
* exception of the last token which does not have the separator.)
*/
for (i = 0; i < tokens; i++) {
offset = i * (length + 1);
if (i < tokens - 1 && input[offset + length] != separator) {
/* The current token did not end with e.g. a "." */
RETURN_VALIDATION_FAILED
}
if (php_filter_parse_hex(input + offset, length, &ret TSRMLS_CC) < 0) {
/* The current token is no valid hexadecimal digit */
RETURN_VALIDATION_FAILED
}
}
}
/* }}} */
/*
* Local variables:
* tab-width: 4

View File

@@ -78,6 +78,7 @@ void php_filter_validate_regexp(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_validate_email(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_validate_mac(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_string(PHP_INPUT_FILTER_PARAM_DECL);
void php_filter_encoded(PHP_INPUT_FILTER_PARAM_DECL);

View File

@@ -11,7 +11,7 @@ var_dump(filter_list(array()));
echo "Done\n";
?>
--EXPECTF--
array(19) {
array(20) {
[0]=>
string(3) "int"
[1]=>
@@ -27,28 +27,30 @@ array(19) {
[6]=>
string(11) "validate_ip"
[7]=>
string(6) "string"
string(12) "validate_mac"
[8]=>
string(8) "stripped"
string(6) "string"
[9]=>
string(7) "encoded"
string(8) "stripped"
[10]=>
string(13) "special_chars"
string(7) "encoded"
[11]=>
string(18) "full_special_chars"
string(13) "special_chars"
[12]=>
string(10) "unsafe_raw"
string(18) "full_special_chars"
[13]=>
string(5) "email"
string(10) "unsafe_raw"
[14]=>
string(3) "url"
string(5) "email"
[15]=>
string(10) "number_int"
string(3) "url"
[16]=>
string(12) "number_float"
string(10) "number_int"
[17]=>
string(12) "magic_quotes"
string(12) "number_float"
[18]=>
string(12) "magic_quotes"
[19]=>
string(8) "callback"
}

View File

@@ -10,22 +10,23 @@ default_charset=UTF-8
include dirname(__FILE__) . '/033_run.inc';
?>
--EXPECT--
int 1 123
boolean 1
float 1 123
validate_regexp O'Henry
validate_url http://a.b.c
validate_email foo@bar.com
validate_ip 1.2.3.4
string PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc() O&#39;Henry 하퍼
stripped PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc() O&#39;Henry 하퍼
encoded PHP 1 foo%40bar.com http%3A%2F%2Fa.b.c 1.2.3.4 123 123abc%3C%3E%28%29 O%27Henry %ED%95%98%ED%8D%BC
special_chars PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc&#60;&#62;() O&#39;Henry 하퍼
full_special_chars PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc&lt;&gt;() O&#039;Henry 하퍼
unsafe_raw PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc<>() O'Henry 하퍼
email PHP 1 foo@bar.com httpa.b.c 1.2.3.4 123 123abc O'Henry
url PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc<>() O'Henry
number_int 1 1234 123 123
number_float 1 1234 123 123
magic_quotes PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc<>() O\'Henry 하퍼
callback PHP 1 FOO@BAR.COM HTTP://A.B.C 1.2.3.4 123 123ABC<>() O'HENRY 하퍼
int 1 123
boolean 1
float 1 123
validate_regexp O'Henry
validate_url http://a.b.c
validate_email foo@bar.com
validate_ip 1.2.3.4
validate_mac aa:bb:cc:dd:ee:ff
string PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc() O&#39;Henry 하퍼 aa:bb:cc:dd:ee:ff
stripped PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc() O&#39;Henry 하퍼 aa:bb:cc:dd:ee:ff
encoded PHP 1 foo%40bar.com http%3A%2F%2Fa.b.c 1.2.3.4 123 123abc%3C%3E%28%29 O%27Henry %ED%95%98%ED%8D%BCaa%3Abb%3Acc%3Add%3Aee%3Aff
special_chars PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc&#60;&#62;() O&#39;Henry 하퍼 aa:bb:cc:dd:ee:ff
full_special_chars PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc&lt;&gt;() O&#039;Henry 하퍼 aa:bb:cc:dd:ee:ff
unsafe_raw PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc<>() O'Henry 하퍼 aa:bb:cc:dd:ee:ff
email PHP 1 foo@bar.com httpa.b.c 1.2.3.4 123 123abc O'Henry aabbccddeeff
url PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc<>() O'Henry aa:bb:cc:dd:ee:ff
number_int 1 1234 123 123
number_float 1 1234 123 123
magic_quotes PHP 1 foo@bar.com http://a.b.c 1.2.3.4 123 123abc<>() O\'Henry 하퍼 aa:bb:cc:dd:ee:ff
callback PHP 1 FOO@BAR.COM HTTP://A.B.C 1.2.3.4 123 123ABC<>() O'HENRY 하퍼 AA:BB:CC:DD:EE:FF

View File

@@ -16,7 +16,8 @@ $data = array(
"123",
"123abc<>()",
"O'Henry",
"하퍼"
"하퍼",
"aa:bb:cc:dd:ee:ff",
);
@@ -35,6 +36,7 @@ foreach(filter_list() as $filter) {
printf("%-5s",$result[5]);
printf("%-20s",$result[6]);
printf("%-15s",$result[7]);
printf("%-10s\n",$result[8]);
printf("%-10s",$result[8]);
printf("%-10s\n",$result[9]);
}
?>

48
ext/filter/tests/055.phpt Normal file
View File

@@ -0,0 +1,48 @@
--TEST--
filter_var() and FILTER_VALIDATE_MAC
--SKIPIF--
<?php if (!extension_loaded("filter")) die("skip"); ?>
--FILE--
<?php
$values = Array(
array("01-23-45-67-89-ab", null),
array("01-23-45-67-89-ab", array("options" => array("separator" => "-"))),
array("01-23-45-67-89-ab", array("options" => array("separator" => "."))),
array("01-23-45-67-89-ab", array("options" => array("separator" => ":"))),
array("01-23-45-67-89-AB", null),
array("01-23-45-67-89-aB", null),
array("01:23:45:67:89:ab", null),
array("01:23:45:67:89:AB", null),
array("01:23:45:67:89:aB", null),
array("01:23:45-67:89:aB", null),
array("xx:23:45:67:89:aB", null),
array("0123.4567.89ab", null),
array("01-23-45-67-89-ab", array("options" => array("separator" => "--"))),
array("01-23-45-67-89-ab", array("options" => array("separator" => ""))),
);
foreach ($values as $value) {
var_dump(filter_var($value[0], FILTER_VALIDATE_MAC, $value[1]));
}
echo "Done\n";
?>
--EXPECTF--
string(17) "01-23-45-67-89-ab"
string(17) "01-23-45-67-89-ab"
bool(false)
bool(false)
string(17) "01-23-45-67-89-AB"
string(17) "01-23-45-67-89-aB"
string(17) "01:23:45:67:89:ab"
string(17) "01:23:45:67:89:AB"
string(17) "01:23:45:67:89:aB"
bool(false)
bool(false)
string(14) "0123.4567.89ab"
Warning: filter_var(): Separator must be exactly one character long in %s055.php on line %d
bool(false)
Warning: filter_var(): Separator must be exactly one character long in %s055.php on line %d
bool(false)
Done

View File

@@ -1150,7 +1150,7 @@ static int netsnmp_session_init(php_snmp_session **session_p, int version, char
}
*pptr = '\0';
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "mailformed IPv6 address, closing square bracket missing");
php_error_docref(NULL TSRMLS_CC, E_WARNING, "malformed IPv6 address, closing square bracket missing");
return (-1);
}
} else { /* IPv4 address */

View File

@@ -43,6 +43,6 @@ if test "$PHP_SOCKETS" != "no"; then
AC_DEFINE(HAVE_SA_SS_FAMILY,1,[Whether you have sockaddr_storage.ss_family])
fi
PHP_NEW_EXTENSION([sockets], [sockets.c multicast.c], [$ext_shared])
PHP_NEW_EXTENSION([sockets], [sockets.c multicast.c conversions.c sockaddr_conv.c sendrecvmsg.c], [$ext_shared])
PHP_INSTALL_HEADERS([ext/sockets/], [php_sockets.h])
fi

View File

@@ -7,7 +7,7 @@ if (PHP_SOCKETS != "no") {
if (CHECK_LIB("ws2_32.lib", "sockets", PHP_SOCKETS)
&& CHECK_LIB("Iphlpapi.lib", "sockets", PHP_SOCKETS)
&& CHECK_HEADER_ADD_INCLUDE("winsock.h", "CFLAGS_SOCKETS")) {
EXTENSION('sockets', 'sockets.c multicast.c');
EXTENSION('sockets', 'sockets.c multicast.c conversions.c sockaddr_conv.c sendrecvmsg.c');
AC_DEFINE('HAVE_SOCKETS', 1);
PHP_INSTALL_HEADERS("ext/sockets", "php_sockets.h");
} else {

1528
ext/sockets/conversions.c Normal file

File diff suppressed because it is too large Load Diff

84
ext/sockets/conversions.h Normal file
View File

@@ -0,0 +1,84 @@
#ifndef PHP_SOCK_CONVERSIONS_H
#define PHP_SOCK_CONVERSIONS_H 1
#include <php.h>
#ifndef PHP_WIN32
# include <netinet/in.h>
# include <sys/socket.h>
#else
# include <Ws2tcpip.h>
#endif
#include "php_sockets.h"
/* TYPE DEFINITIONS */
struct err_s {
int has_error;
char *msg;
int level;
int should_free;
};
struct key_value {
const char *key;
unsigned key_size;
void *value;
};
/* the complete types of these two are not relevant to the outside */
typedef struct _ser_context ser_context;
typedef struct _res_context res_context;
#define KEY_RECVMSG_RET "recvmsg_ret"
typedef void (from_zval_write_field)(const zval *arr_value, char *field, ser_context *ctx);
typedef void (to_zval_read_field)(const char *data, zval *zv, res_context *ctx);
/* VARIABLE DECLARATIONS */
extern const struct key_value empty_key_value_list[];
/* AUX FUNCTIONS */
void err_msg_dispose(struct err_s *err TSRMLS_DC);
void allocations_dispose(zend_llist **allocations);
/* CONVERSION FUNCTIONS */
void from_zval_write_int(const zval *arr_value, char *field, ser_context *ctx);
void to_zval_read_int(const char *data, zval *zv, res_context *ctx);
#ifdef IPV6_PKTINFO
void from_zval_write_in6_pktinfo(const zval *container, char *in6_pktinfo_c, ser_context *ctx);
void to_zval_read_in6_pktinfo(const char *data, zval *zv, res_context *ctx);
#endif
#ifdef SO_PASSCRED
void from_zval_write_ucred(const zval *container, char *ucred_c, ser_context *ctx);
void to_zval_read_ucred(const char *data, zval *zv, res_context *ctx);
#endif
#ifdef SCM_RIGHTS
size_t calculate_scm_rights_space(const zval *arr, ser_context *ctx);
void from_zval_write_fd_array(const zval *arr, char *int_arr, ser_context *ctx);
void to_zval_read_fd_array(const char *data, zval *zv, res_context *ctx);
#endif
void from_zval_write_msghdr_send(const zval *container, char *msghdr_c, ser_context *ctx);
void from_zval_write_msghdr_recv(const zval *container, char *msghdr_c, ser_context *ctx);
void to_zval_read_msghdr(const char *msghdr_c, zval *zv, res_context *ctx);
/* ENTRY POINTS FOR CONVERSIONS */
void *from_zval_run_conversions(const zval *container,
php_socket *sock,
from_zval_write_field *writer,
size_t struct_size,
const char *top_name,
zend_llist **allocations /* out */,
struct err_s *err /* in/out */);
zval *to_zval_run_conversions(const char *structure,
to_zval_read_field *reader,
const char *top_name,
const struct key_value *key_value_pairs,
struct err_s *err);
#endif

View File

@@ -28,19 +28,7 @@
#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
# if _WIN32_WINNT >= 0x0600
# define HAVE_IF_NAMETOINDEX 1
# endif
# include "windows_common.h"
#else
#include <sys/socket.h>
#include <sys/ioctl.h>
@@ -54,6 +42,7 @@
#include "php_sockets.h"
#include "multicast.h"
#include "sockaddr_conv.h"
#include "main/php_network.h"
@@ -76,6 +65,309 @@ 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
static int php_get_if_index_from_zval(zval *val, unsigned *out TSRMLS_DC)
{
int ret;
if (Z_TYPE_P(val) == IS_LONG) {
if (Z_LVAL_P(val) < 0 || Z_LVAL_P(val) > UINT_MAX) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"the interface index cannot be negative or larger than %u;"
" given %ld", UINT_MAX, Z_LVAL_P(val));
ret = FAILURE;
} else {
*out = Z_LVAL_P(val);
ret = SUCCESS;
}
} else {
#if HAVE_IF_NAMETOINDEX
unsigned int ind;
zval_add_ref(&val);
convert_to_string_ex(&val);
ind = if_nametoindex(Z_STRVAL_P(val));
if (ind == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"no interface with name \"%s\" could be found", Z_STRVAL_P(val));
ret = FAILURE;
} else {
*out = ind;
ret = SUCCESS;
}
zval_ptr_dtor(&val);
#else
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"this platform does not support looking up an interface by "
"name, an integer interface index must be supplied instead");
ret = FAILURE;
#endif
}
return ret;
}
static int php_get_if_index_from_array(const HashTable *ht, const char *key,
php_socket *sock, unsigned int *if_index TSRMLS_DC)
{
zval **val;
if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE) {
*if_index = 0; /* default: 0 */
return SUCCESS;
}
return php_get_if_index_from_zval(*val, if_index TSRMLS_CC);
}
static int php_get_address_from_array(const HashTable *ht, const char *key,
php_socket *sock, php_sockaddr_storage *ss, socklen_t *ss_len TSRMLS_DC)
{
zval **val,
*valcp;
if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", key);
return FAILURE;
}
valcp = *val;
zval_add_ref(&valcp);
convert_to_string_ex(val);
if (!php_set_inet46_addr(ss, ss_len, Z_STRVAL_P(valcp), sock TSRMLS_CC)) {
zval_ptr_dtor(&valcp);
return FAILURE;
}
zval_ptr_dtor(&valcp);
return SUCCESS;
}
static int php_do_mcast_opt(php_socket *php_sock, int level, int optname, zval **arg4 TSRMLS_DC)
{
HashTable *opt_ht;
unsigned int if_index;
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:
mcast_req_fun = &php_mcast_join;
goto mcast_req_fun;
case MCAST_LEAVE_GROUP:
{
php_sockaddr_storage group = {0};
socklen_t glen;
mcast_req_fun = &php_mcast_leave;
mcast_req_fun:
convert_to_array_ex(arg4);
opt_ht = HASH_OF(*arg4);
if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
&glen TSRMLS_CC) == FAILURE) {
return FAILURE;
}
if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
&if_index TSRMLS_CC) == FAILURE) {
return FAILURE;
}
retval = mcast_req_fun(php_sock, level, (struct sockaddr*)&group,
glen, if_index TSRMLS_CC);
break;
}
#ifdef HAS_MCAST_EXT
case MCAST_BLOCK_SOURCE:
mcast_sreq_fun = &php_mcast_block_source;
goto mcast_sreq_fun;
case MCAST_UNBLOCK_SOURCE:
mcast_sreq_fun = &php_mcast_unblock_source;
goto mcast_sreq_fun;
case MCAST_JOIN_SOURCE_GROUP:
mcast_sreq_fun = &php_mcast_join_source;
goto mcast_sreq_fun;
case MCAST_LEAVE_SOURCE_GROUP:
{
php_sockaddr_storage group = {0},
source = {0};
socklen_t glen,
slen;
mcast_sreq_fun = &php_mcast_leave_source;
mcast_sreq_fun:
convert_to_array_ex(arg4);
opt_ht = HASH_OF(*arg4);
if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
&glen TSRMLS_CC) == FAILURE) {
return FAILURE;
}
if (php_get_address_from_array(opt_ht, "source", php_sock, &source,
&slen TSRMLS_CC) == FAILURE) {
return FAILURE;
}
if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
&if_index TSRMLS_CC) == FAILURE) {
return FAILURE;
}
retval = mcast_sreq_fun(php_sock, level, (struct sockaddr*)&group,
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). "
"This is a bug.", level, optname);
return FAILURE;
}
if (retval != 0) {
if (retval != -2) { /* error, but message already emitted */
PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
}
return FAILURE;
}
return SUCCESS;
}
int php_do_setsockopt_ip_mcast(php_socket *php_sock,
int level,
int optname,
zval **arg4 TSRMLS_DC)
{
unsigned int if_index;
struct in_addr if_addr;
void *opt_ptr;
socklen_t optlen;
unsigned char ipv4_mcast_ttl_lback;
int retval;
switch (optname) {
case MCAST_JOIN_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 FAILURE;
} else {
return SUCCESS;
}
case IP_MULTICAST_IF:
if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) == FAILURE) {
return FAILURE;
}
if (php_if_index_to_addr4(if_index, php_sock, &if_addr TSRMLS_CC) == FAILURE) {
return FAILURE;
}
opt_ptr = &if_addr;
optlen = sizeof(if_addr);
goto dosockopt;
case IP_MULTICAST_LOOP:
convert_to_boolean_ex(arg4);
goto ipv4_loop_ttl;
case IP_MULTICAST_TTL:
convert_to_long_ex(arg4);
if (Z_LVAL_PP(arg4) < 0L || Z_LVAL_PP(arg4) > 255L) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Expected a value between 0 and 255");
return FAILURE;
}
ipv4_loop_ttl:
ipv4_mcast_ttl_lback = (unsigned char) Z_LVAL_PP(arg4);
opt_ptr = &ipv4_mcast_ttl_lback;
optlen = sizeof(ipv4_mcast_ttl_lback);
goto dosockopt;
}
return 1;
dosockopt:
retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
if (retval != 0) {
PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
return FAILURE;
}
return SUCCESS;
}
int php_do_setsockopt_ipv6_mcast(php_socket *php_sock,
int level,
int optname,
zval **arg4 TSRMLS_DC)
{
unsigned int if_index;
void *opt_ptr;
socklen_t optlen;
int ov;
int retval;
switch (optname) {
case MCAST_JOIN_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 FAILURE;
} else {
return SUCCESS;
}
case IPV6_MULTICAST_IF:
if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) == FAILURE) {
return FAILURE;
}
opt_ptr = &if_index;
optlen = sizeof(if_index);
goto dosockopt;
case IPV6_MULTICAST_LOOP:
convert_to_boolean_ex(arg4);
goto ipv6_loop_hops;
case IPV6_MULTICAST_HOPS:
convert_to_long_ex(arg4);
if (Z_LVAL_PP(arg4) < -1L || Z_LVAL_PP(arg4) > 255L) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Expected a value between -1 and 255");
return FAILURE;
}
ipv6_loop_hops:
ov = (int) Z_LVAL_PP(arg4);
opt_ptr = &ov;
optlen = sizeof(ov);
goto dosockopt;
}
return 1; /* not handled */
dosockopt:
retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
if (retval != 0) {
PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
return FAILURE;
}
return SUCCESS;
}
int php_mcast_join(
php_socket *sock,
int level,
@@ -157,21 +449,21 @@ static int _php_mcast_join_leave(
{
#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));
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)
@@ -188,12 +480,12 @@ static int _php_mcast_join_leave(
#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));
@@ -221,26 +513,26 @@ static int _php_mcast_source_op(
{
#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)
@@ -249,7 +541,7 @@ static int _php_mcast_source_op(
} 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));
}
@@ -283,7 +575,7 @@ static int _php_source_op_to_rfc3678_op(enum source_op sop)
case UNBLOCK_SOURCE:
return MCAST_UNBLOCK_SOURCE;
}
assert(0);
return 0;
}
@@ -300,7 +592,7 @@ static const char *_php_source_op_to_string(enum source_op sop)
case UNBLOCK_SOURCE:
return "MCAST_UNBLOCK_SOURCE";
}
assert(0);
return "";
}
@@ -317,7 +609,7 @@ static int _php_source_op_to_ipv4_op(enum source_op sop)
case UNBLOCK_SOURCE:
return IP_UNBLOCK_SOURCE;
}
assert(0);
return 0;
}
@@ -416,16 +708,16 @@ retry:
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 !defined(ifr_ifindex) && defined(ifr_index)
#define ifr_ifindex ifr_index
#endif
#if defined(SIOCGIFNAME)
if_req.ifr_ifindex = if_index;
if (ioctl(php_sock->bsd_socket, SIOCGIFNAME, &if_req) == -1) {
@@ -438,13 +730,13 @@ int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_add
"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;
@@ -458,25 +750,25 @@ int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *i
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;
@@ -486,15 +778,15 @@ int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *i
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
@@ -502,7 +794,7 @@ int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *i
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)) {
@@ -537,7 +829,7 @@ int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *i
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);

View File

@@ -27,6 +27,16 @@
#define HAS_MCAST_EXT 1
#endif
int php_do_setsockopt_ip_mcast(php_socket *php_sock,
int level,
int optname,
zval **arg4 TSRMLS_DC);
int php_do_setsockopt_ipv6_mcast(php_socket *php_sock,
int level,
int optname,
zval **arg4 TSRMLS_DC);
int php_if_index_to_addr4(
unsigned if_index,
php_socket *php_sock,

View File

@@ -26,52 +26,22 @@
#if HAVE_SOCKETS
#include <php.h>
#ifdef PHP_WIN32
# include "windows_common.h"
#endif
extern zend_module_entry sockets_module_entry;
#define phpext_sockets_ptr &sockets_module_entry
#ifdef PHP_WIN32
#include <winsock.h>
#include <Winsock2.h>
#else
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#endif
PHP_MINIT_FUNCTION(sockets);
PHP_MINFO_FUNCTION(sockets);
PHP_RSHUTDOWN_FUNCTION(sockets);
PHP_FUNCTION(socket_select);
PHP_FUNCTION(socket_create_listen);
#ifdef HAVE_SOCKETPAIR
PHP_FUNCTION(socket_create_pair);
#endif
PHP_FUNCTION(socket_accept);
PHP_FUNCTION(socket_set_nonblock);
PHP_FUNCTION(socket_set_block);
PHP_FUNCTION(socket_listen);
PHP_FUNCTION(socket_close);
PHP_FUNCTION(socket_write);
PHP_FUNCTION(socket_read);
PHP_FUNCTION(socket_getsockname);
PHP_FUNCTION(socket_getpeername);
PHP_FUNCTION(socket_create);
PHP_FUNCTION(socket_connect);
PHP_FUNCTION(socket_strerror);
PHP_FUNCTION(socket_bind);
PHP_FUNCTION(socket_recv);
PHP_FUNCTION(socket_send);
PHP_FUNCTION(socket_recvfrom);
PHP_FUNCTION(socket_sendto);
PHP_FUNCTION(socket_get_option);
PHP_FUNCTION(socket_set_option);
#ifdef HAVE_SHUTDOWN
PHP_FUNCTION(socket_shutdown);
#endif
PHP_FUNCTION(socket_last_error);
PHP_FUNCTION(socket_clear_error);
PHP_FUNCTION(socket_import_stream);
#ifndef PHP_WIN32
typedef int PHP_SOCKET;
# define PHP_SOCKETS_API PHPAPI
@@ -99,13 +69,15 @@ PHP_SOCKETS_API int php_sockets_le_socket(void);
#define php_sockets_le_socket_name "Socket"
/* Prototypes */
#ifdef ilia_0 /* not needed, only causes a compiler warning */
static int php_open_listen_sock(php_socket **php_sock, int port, int backlog TSRMLS_DC);
static int php_accept_connect(php_socket *in_sock, php_socket **new_sock, struct sockaddr *la TSRMLS_DC);
static int php_read(php_socket *sock, void *buf, size_t maxlen, int flags);
static char *php_strerror(int error TSRMLS_DC);
#endif
#define PHP_SOCKET_ERROR(socket, msg, errn) \
do { \
int _err = (errn); /* save value to avoid repeated calls to WSAGetLastError() on Windows */ \
(socket)->error = _err; \
SOCKETS_G(last_error) = _err; \
if (_err != EAGAIN && _err != EWOULDBLOCK && _err != EINPROGRESS) { \
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s [%d]: %s", msg, _err, sockets_strerror(_err TSRMLS_CC)); \
} \
} while (0)
ZEND_BEGIN_MODULE_GLOBALS(sockets)
int last_error;
@@ -118,6 +90,17 @@ ZEND_END_MODULE_GLOBALS(sockets)
#define SOCKETS_G(v) (sockets_globals.v)
#endif
ZEND_EXTERN_MODULE_GLOBALS(sockets);
enum sockopt_return {
SOCKOPT_ERROR,
SOCKOPT_CONTINUE,
SOCKOPT_SUCCESS
};
char *sockets_strerror(int error TSRMLS_DC);
php_socket *socket_import_file_descriptor(PHP_SOCKET sock TSRMLS_DC);
#else
#define phpext_sockets_ptr NULL
#endif

452
ext/sockets/sendrecvmsg.c Normal file
View File

@@ -0,0 +1,452 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2012 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> |
+----------------------------------------------------------------------+
*/
#include <php.h>
#include "php_sockets.h"
#include "sendrecvmsg.h"
#include "conversions.h"
#include <limits.h>
#include <Zend/zend_llist.h>
#ifdef ZTS
#include <TSRM/TSRM.h>
#endif
#define MAX_USER_BUFF_SIZE ((size_t)(100*1024*1024))
#define DEFAULT_BUFF_SIZE 8192
#define MAX_ARRAY_KEY_SIZE 128
#ifdef PHP_WIN32
#include "windows_common.h"
#include <Mswsock.h>
#define IPV6_RECVPKTINFO IPV6_PKTINFO
#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
#define msghdr _WSAMSG
static GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
static __declspec(thread) LPFN_WSARECVMSG WSARecvMsg = NULL;
inline ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
{
DWORD recvd = 0,
bytesReturned;
if (WSARecvMsg == NULL) {
int res = WSAIoctl((SOCKET) sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
&WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID),
&WSARecvMsg, sizeof(WSARecvMsg),
&bytesReturned, NULL, NULL);
if (res != 0) {
return -1;
}
}
msg->dwFlags = (DWORD)flags;
return WSARecvMsg((SOCKET)sockfd, msg, &recvd, NULL, NULL) == 0
? (ssize_t)recvd
: -1;
}
inline ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
{
DWORD sent = 0;
return WSASendMsg((SOCKET)sockfd, (struct msghdr*)msg, (DWORD)flags, &sent, NULL, NULL) == 0
? (ssize_t)sent
: -1;
}
#endif
#define LONG_CHECK_VALID_INT(l) \
do { \
if ((l) < INT_MIN && (l) > INT_MAX) { \
php_error_docref0(NULL TSRMLS_CC, E_WARNING, "The value %ld does not fit inside " \
"the boundaries of a native integer", (l)); \
return; \
} \
} while (0)
static struct {
int initialized;
HashTable ht;
} ancillary_registry;
#ifdef ZTS
static MUTEX_T ancillary_mutex;
#endif
static void init_ancillary_registry(void)
{
ancillary_reg_entry entry;
anc_reg_key key;
ancillary_registry.initialized = 1;
zend_hash_init(&ancillary_registry.ht, 32, NULL, NULL, 1);
#define PUT_ENTRY(sizev, var_size, calc, from, to, level, type) \
entry.size = sizev; \
entry.var_el_size = var_size; \
entry.calc_space = calc; \
entry.from_array = from; \
entry.to_array = to; \
key.cmsg_level = level; \
key.cmsg_type = type; \
zend_hash_update(&ancillary_registry.ht, (char*)&key, sizeof(key), \
(void*)&entry, sizeof(entry), NULL)
#ifdef IPV6_PKTINFO
PUT_ENTRY(sizeof(struct in6_pktinfo), 0, 0, from_zval_write_in6_pktinfo,
to_zval_read_in6_pktinfo, IPPROTO_IPV6, IPV6_PKTINFO);
#endif
#ifdef IPV6_HOPLIMIT
PUT_ENTRY(sizeof(int), 0, 0, from_zval_write_int,
to_zval_read_int, IPPROTO_IPV6, IPV6_HOPLIMIT);
#endif
#ifdef IPV6_TCLASS
PUT_ENTRY(sizeof(int), 0, 0, from_zval_write_int,
to_zval_read_int, IPPROTO_IPV6, IPV6_TCLASS);
#endif
#ifdef SO_PASSCRED
PUT_ENTRY(sizeof(struct ucred), 0, 0, from_zval_write_ucred,
to_zval_read_ucred, SOL_SOCKET, SCM_CREDENTIALS);
#endif
#ifdef SCM_RIGHTS
PUT_ENTRY(0, sizeof(int), calculate_scm_rights_space, from_zval_write_fd_array,
to_zval_read_fd_array, SOL_SOCKET, SCM_RIGHTS);
#endif
}
static void destroy_ancillary_registry(void)
{
if (ancillary_registry.initialized) {
zend_hash_destroy(&ancillary_registry.ht);
ancillary_registry.initialized = 0;
}
}
ancillary_reg_entry *get_ancillary_reg_entry(int cmsg_level, int msg_type)
{
anc_reg_key key = { cmsg_level, msg_type };
ancillary_reg_entry *entry;
#ifdef ZTS
tsrm_mutex_lock(ancillary_mutex);
#endif
if (!ancillary_registry.initialized) {
init_ancillary_registry();
}
#ifdef ZTS
tsrm_mutex_unlock(ancillary_mutex);
#endif
if (zend_hash_find(&ancillary_registry.ht, (char*)&key, sizeof(key),
(void**)&entry) == SUCCESS) {
return entry;
} else {
return NULL;
}
}
PHP_FUNCTION(socket_sendmsg)
{
zval *zsocket,
*zmsg;
long flags = 0;
php_socket *php_sock;
struct msghdr *msghdr;
zend_llist *allocations;
struct err_s err = {0};
ssize_t res;
/* zmsg should be passed by ref */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra|l", &zsocket, &zmsg, &flags) == FAILURE) {
return;
}
LONG_CHECK_VALID_INT(flags);
ZEND_FETCH_RESOURCE(php_sock, php_socket *, &zsocket, -1,
php_sockets_le_socket_name, php_sockets_le_socket());
msghdr = from_zval_run_conversions(zmsg, php_sock, from_zval_write_msghdr_send,
sizeof(*msghdr), "msghdr", &allocations, &err);
if (err.has_error) {
err_msg_dispose(&err TSRMLS_CC);
RETURN_FALSE;
}
res = sendmsg(php_sock->bsd_socket, msghdr, (int)flags);
if (res != -1) {
zend_llist_destroy(allocations);
efree(allocations);
RETURN_LONG((long)res);
} else {
PHP_SOCKET_ERROR(php_sock, "error in sendmsg", errno);
RETURN_FALSE;
}
}
PHP_FUNCTION(socket_recvmsg)
{
zval *zsocket,
*zmsg;
long flags = 0;
php_socket *php_sock;
ssize_t res;
struct msghdr *msghdr;
zend_llist *allocations;
struct err_s err = {0};
//ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra|l",
&zsocket, &zmsg, &flags) == FAILURE) {
return;
}
LONG_CHECK_VALID_INT(flags);
ZEND_FETCH_RESOURCE(php_sock, php_socket *, &zsocket, -1,
php_sockets_le_socket_name, php_sockets_le_socket());
msghdr = from_zval_run_conversions(zmsg, php_sock, from_zval_write_msghdr_recv,
sizeof(*msghdr), "msghdr", &allocations, &err);
if (err.has_error) {
err_msg_dispose(&err TSRMLS_CC);
RETURN_FALSE;
}
res = recvmsg(php_sock->bsd_socket, msghdr, (int)flags);
if (res != -1) {
zval *zres;
struct key_value kv[] = {
{KEY_RECVMSG_RET, sizeof(KEY_RECVMSG_RET), &res},
{0}
};
zres = to_zval_run_conversions((char *)msghdr, to_zval_read_msghdr,
"msghdr", kv, &err);
/* we don;t need msghdr anymore; free it */
msghdr = NULL;
allocations_dispose(&allocations);
zval_dtor(zmsg);
if (!err.has_error) {
ZVAL_COPY_VALUE(zmsg, zres);
efree(zres); /* only shallow destruction */
} else {
err_msg_dispose(&err TSRMLS_CC);
ZVAL_FALSE(zmsg);
/* no need to destroy/free zres -- it's NULL in this circumstance */
assert(zres == NULL);
}
} else {
SOCKETS_G(last_error) = errno;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "error in recvmsg [%d]: %s",
errno, sockets_strerror(errno TSRMLS_CC));
RETURN_FALSE;
}
RETURN_LONG((long)res);
}
PHP_FUNCTION(socket_cmsg_space)
{
long level,
type,
n = 0;
ancillary_reg_entry *entry;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|l",
&level, &type, &n) == FAILURE) {
return;
}
LONG_CHECK_VALID_INT(level);
LONG_CHECK_VALID_INT(type);
LONG_CHECK_VALID_INT(n);
if (n < 0) {
php_error_docref0(NULL TSRMLS_CC, E_WARNING, "The third argument "
"cannot be negative");
return;
}
entry = get_ancillary_reg_entry(level, type);
if (entry == NULL) {
php_error_docref0(NULL TSRMLS_CC, E_WARNING, "The pair level %ld/type %ld is "
"not supported by PHP", level, type);
return;
}
if (entry->var_el_size > 0 && n > (LONG_MAX - (long)entry->size -
(long)CMSG_SPACE(0) - 15L) / entry->var_el_size) {
/* the -15 is to account for any padding CMSG_SPACE may add after the data */
php_error_docref0(NULL TSRMLS_CC, E_WARNING, "The value for the "
"third argument (%ld) is too large", n);
return;
}
RETURN_LONG((long)CMSG_SPACE(entry->size + n * entry->var_el_size));
}
int php_do_setsockopt_ipv6_rfc3542(php_socket *php_sock, int level, int optname, zval **arg4 TSRMLS_DC)
{
struct err_s err = {0};
zend_llist *allocations = NULL;
void *opt_ptr;
socklen_t optlen;
int retval;
assert(level == IPPROTO_IPV6);
switch (optname) {
#ifdef IPV6_PKTINFO
case IPV6_PKTINFO:
#ifdef PHP_WIN32
if (Z_TYPE_PP(arg4) == IS_ARRAY) {
php_error_docref0(NULL TSRMLS_CC, E_WARNING, "Windows does not "
"support sticky IPV6_PKTINFO");
return FAILURE;
} else {
/* windows has no IPV6_RECVPKTINFO, and uses IPV6_PKTINFO
* for the same effect. We define IPV6_RECVPKTINFO to be
* IPV6_PKTINFO, so assume the assume user used IPV6_RECVPKTINFO */
return 1;
}
#endif
opt_ptr = from_zval_run_conversions(*arg4, php_sock, from_zval_write_in6_pktinfo,
sizeof(struct in6_pktinfo), "in6_pktinfo", &allocations, &err);
if (err.has_error) {
err_msg_dispose(&err TSRMLS_CC);
return FAILURE;
}
optlen = sizeof(struct in6_pktinfo);
goto dosockopt;
#endif
}
/* we also support IPV6_TCLASS, but that can be handled by the default
* integer optval handling in the caller */
return 1;
dosockopt:
retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
if (retval != 0) {
PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
}
allocations_dispose(&allocations);
return retval != 0 ? FAILURE : SUCCESS;
}
int php_do_getsockopt_ipv6_rfc3542(php_socket *php_sock, int level, int optname, zval *result TSRMLS_DC)
{
struct err_s err = {0};
void *buffer;
socklen_t size;
int res;
to_zval_read_field *reader;
assert(level == IPPROTO_IPV6);
switch (optname) {
#ifdef IPV6_PKTINFO
case IPV6_PKTINFO:
size = sizeof(struct in6_pktinfo);
reader = &to_zval_read_in6_pktinfo;
break;
#endif
default:
return 1;
}
buffer = ecalloc(1, size);
res = getsockopt(php_sock->bsd_socket, level, optname, buffer, &size);
if (res != 0) {
PHP_SOCKET_ERROR(php_sock, "unable to get socket option", errno);
} else {
zval *zv = to_zval_run_conversions(buffer, reader, "in6_pktinfo",
empty_key_value_list, &err);
if (err.has_error) {
err_msg_dispose(&err TSRMLS_CC);
res = -1;
} else {
ZVAL_COPY_VALUE(result, zv);
efree(zv);
}
}
efree(buffer);
return res == 0 ? SUCCESS : FAILURE;
}
void php_socket_sendrecvmsg_init(INIT_FUNC_ARGS)
{
/* IPv6 ancillary data */
#ifdef IPV6_RECVPKTINFO
REGISTER_LONG_CONSTANT("IPV6_RECVPKTINFO", IPV6_RECVPKTINFO, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("IPV6_PKTINFO", IPV6_PKTINFO, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef IPV6_RECVHOPLIMIT
REGISTER_LONG_CONSTANT("IPV6_RECVHOPLIMIT", IPV6_RECVHOPLIMIT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("IPV6_HOPLIMIT", IPV6_HOPLIMIT, CONST_CS | CONST_PERSISTENT);
#endif
/* would require some effort:
REGISTER_LONG_CONSTANT("IPV6_RECVRTHDR", IPV6_RECVRTHDR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("IPV6_RECVHOPOPTS", IPV6_RECVHOPOPTS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("IPV6_RECVDSTOPTS", IPV6_RECVDSTOPTS, CONST_CS | CONST_PERSISTENT);
*/
#ifdef IPV6_RECVTCLASS
REGISTER_LONG_CONSTANT("IPV6_RECVTCLASS", IPV6_RECVTCLASS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("IPV6_TCLASS", IPV6_TCLASS, CONST_CS | CONST_PERSISTENT);
#endif
/*
REGISTER_LONG_CONSTANT("IPV6_RTHDR", IPV6_RTHDR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("IPV6_HOPOPTS", IPV6_HOPOPTS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("IPV6_DSTOPTS", IPV6_DSTOPTS, CONST_CS | CONST_PERSISTENT);
*/
#ifdef SCM_RIGHTS
REGISTER_LONG_CONSTANT("SCM_RIGHTS", SCM_RIGHTS, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef SO_PASSCRED
REGISTER_LONG_CONSTANT("SCM_CREDENTIALS", SCM_CREDENTIALS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SO_PASSCRED", SO_PASSCRED, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef ZTS
ancillary_mutex = tsrm_mutex_alloc();
#endif
}
void php_socket_sendrecvmsg_shutdown(SHUTDOWN_FUNC_ARGS)
{
#ifdef ZTS
tsrm_mutex_free(ancillary_mutex);
#endif
destroy_ancillary_registry();
}

36
ext/sockets/sendrecvmsg.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef PHP_SENDRECVMSG_H
#define PHP_SENDRECVMSG_H 1
#include <php.h>
#include "conversions.h"
/* for sockets.c */
PHP_FUNCTION(socket_sendmsg);
PHP_FUNCTION(socket_recvmsg);
PHP_FUNCTION(socket_cmsg_space);
void php_socket_sendrecvmsg_init(INIT_FUNC_ARGS);
void php_socket_sendrecvmsg_shutdown(SHUTDOWN_FUNC_ARGS);
int php_do_setsockopt_ipv6_rfc3542(php_socket *php_sock, int level, int optname, zval **arg4 TSRMLS_DC);
int php_do_getsockopt_ipv6_rfc3542(php_socket *php_sock, int level, int optname, zval *result TSRMLS_DC);
/* for conversions.c */
typedef struct {
int cmsg_level; /* originating protocol */
int cmsg_type; /* protocol-specific type */
} anc_reg_key;
typedef size_t (calculate_req_space)(const zval *value, ser_context *ctx);
typedef struct {
socklen_t size; /* size of native structure */
socklen_t var_el_size; /* size of repeatable component */
calculate_req_space *calc_space;
from_zval_write_field *from_array;
to_zval_read_field *to_array;
} ancillary_reg_entry;
ancillary_reg_entry *get_ancillary_reg_entry(int cmsg_level, int msg_type);
#endif

119
ext/sockets/sockaddr_conv.c Normal file
View File

@@ -0,0 +1,119 @@
#include <php.h>
#include <php_network.h>
#include "php_sockets.h"
#ifdef PHP_WIN32
#include "windows_common.h"
#else
#include <netdb.h>
#include <arpa/inet.h>
#endif
#if HAVE_IPV6
/* Sets addr by hostname, or by ip in string form (AF_INET6) */
int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
{
struct in6_addr tmp;
#if HAVE_GETADDRINFO
struct addrinfo hints;
struct addrinfo *addrinfo = NULL;
#endif
if (inet_pton(AF_INET6, string, &tmp)) {
memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr), sizeof(struct in6_addr));
} else {
#if HAVE_GETADDRINFO
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET6;
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
getaddrinfo(string, NULL, &hints, &addrinfo);
if (!addrinfo) {
#ifdef PHP_WIN32
PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
#else
PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
#endif
return 0;
}
if (addrinfo->ai_family != PF_INET6 || addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET6 domain returned on AF_INET6 socket");
freeaddrinfo(addrinfo);
return 0;
}
memcpy(&(sin6->sin6_addr.s6_addr), ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, sizeof(struct in6_addr));
freeaddrinfo(addrinfo);
#else
/* No IPv6 specific hostname resolution is available on this system? */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: getaddrinfo() not available on this system");
return 0;
#endif
}
return 1;
}
/* }}} */
#endif
/* Sets addr by hostname, or by ip in string form (AF_INET) */
int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
{
struct in_addr tmp;
struct hostent *host_entry;
if (inet_aton(string, &tmp)) {
sin->sin_addr.s_addr = tmp.s_addr;
} else {
if (! (host_entry = gethostbyname(string))) {
/* Note: < -10000 indicates a host lookup error */
#ifdef PHP_WIN32
PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
#else
PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
#endif
return 0;
}
if (host_entry->h_addrtype != AF_INET) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET domain returned on AF_INET socket");
return 0;
}
memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0], host_entry->h_length);
}
return 1;
}
/* }}} */
/* Sets addr by hostname or by ip in string form (AF_INET or AF_INET6,
* depending on the socket) */
int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
{
if (php_sock->type == AF_INET) {
struct sockaddr_in t = {0};
if (php_set_inet_addr(&t, string, php_sock TSRMLS_CC)) {
memcpy(ss, &t, sizeof t);
ss->ss_family = AF_INET;
*ss_len = sizeof(t);
return 1;
}
}
#if HAVE_IPV6
else if (php_sock->type == AF_INET6) {
struct sockaddr_in6 t = {0};
if (php_set_inet6_addr(&t, string, php_sock TSRMLS_CC)) {
memcpy(ss, &t, sizeof t);
ss->ss_family = AF_INET6;
*ss_len = sizeof(t);
return 1;
}
}
#endif
else {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"IP address used in the context of an unexpected type of socket");
}
return 0;
}

View File

@@ -0,0 +1,31 @@
#ifndef PHP_SOCKADR_CONV_H
#define PHP_SOCKADR_CONV_H
#include <php_network.h>
#include "php_sockets.h" /* php_socket */
#ifndef PHP_WIN32
# include <netinet/in.h>
#else
# include <Winsock2.h>
#endif
/*
* Convert an IPv6 literal or a hostname info a sockaddr_in6.
* The IPv6 literal can be a IPv4 mapped address (like ::ffff:127.0.0.1).
* If the hostname yields no IPv6 addresses, a mapped IPv4 address may be returned (AI_V4MAPPED)
*/
int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock TSRMLS_DC);
/*
* Convert an IPv4 literal or a hostname into a sockaddr_in.
*/
int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock TSRMLS_DC);
/*
* Calls either php_set_inet6_addr() or php_set_inet_addr(), depending on the type of the socket.
*/
int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock TSRMLS_DC);
#endif

View File

@@ -35,32 +35,12 @@
#include "ext/standard/info.h"
#include "php_ini.h"
#ifdef PHP_WIN32
# include "win32/inet.h"
# include <winsock2.h>
# include "windows_common.h"
# include <win32/inet.h>
# include <windows.h>
# include <Ws2tcpip.h>
# include "php_sockets.h"
# include "win32/sockets.h"
# define IS_INVALID_SOCKET(a) (a->bsd_socket == INVALID_SOCKET)
# ifdef EPROTONOSUPPORT
# undef EPROTONOSUPPORT
# endif
# ifdef ECONNRESET
# undef ECONNRESET
# endif
# define EPROTONOSUPPORT WSAEPROTONOSUPPORT
# define ECONNRESET WSAECONNRESET
# ifdef errno
# undef errno
# endif
# define errno WSAGetLastError()
# define h_errno WSAGetLastError()
# define set_errno(a) WSASetLastError(a)
# define close(a) closesocket(a)
# include <IPHlpApi.h>
# if _WIN32_WINNT >= 0x0600
# define HAVE_IF_NAMETOINDEX 1
# endif
# include <win32/sockets.h>
#else
# include <sys/types.h>
# include <sys/socket.h>
@@ -86,7 +66,9 @@
# endif
#endif
#include "sockaddr_conv.h"
#include "multicast.h"
#include "sendrecvmsg.h"
ZEND_DECLARE_MODULE_GLOBALS(sockets)
static PHP_GINIT_FUNCTION(sockets);
@@ -113,15 +95,9 @@ static PHP_GINIT_FUNCTION(sockets);
#define PF_INET AF_INET
#endif
static char *php_strerror(int error TSRMLS_DC);
#define PHP_NORMAL_READ 0x0001
#define PHP_BINARY_READ 0x0002
#define PHP_SOCKET_ERROR(socket,msg,errn) socket->error = errn; \
SOCKETS_G(last_error) = errn; \
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s [%d]: %s", msg, errn, php_strerror(errn TSRMLS_CC))
static int le_socket;
#define le_socket_name php_sockets_le_socket_name
@@ -274,12 +250,64 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_clear_error, 0, 0, 0)
ZEND_ARG_INFO(0, socket)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_import_stream, 0, 0, 1)
ZEND_ARG_INFO(0, stream)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_sendmsg, 0, 0, 3)
ZEND_ARG_INFO(0, socket)
ZEND_ARG_INFO(0, msghdr)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_recvmsg, 0, 0, 3)
ZEND_ARG_INFO(0, socket)
ZEND_ARG_INFO(1, msghdr)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_socket_cmsg_space, 0, 0, 2)
ZEND_ARG_INFO(0, level)
ZEND_ARG_INFO(0, type)
ZEND_END_ARG_INFO()
/* }}} */
PHP_MINIT_FUNCTION(sockets);
PHP_MINFO_FUNCTION(sockets);
PHP_RSHUTDOWN_FUNCTION(sockets);
PHP_FUNCTION(socket_select);
PHP_FUNCTION(socket_create_listen);
#ifdef HAVE_SOCKETPAIR
PHP_FUNCTION(socket_create_pair);
#endif
PHP_FUNCTION(socket_accept);
PHP_FUNCTION(socket_set_nonblock);
PHP_FUNCTION(socket_set_block);
PHP_FUNCTION(socket_listen);
PHP_FUNCTION(socket_close);
PHP_FUNCTION(socket_write);
PHP_FUNCTION(socket_read);
PHP_FUNCTION(socket_getsockname);
PHP_FUNCTION(socket_getpeername);
PHP_FUNCTION(socket_create);
PHP_FUNCTION(socket_connect);
PHP_FUNCTION(socket_strerror);
PHP_FUNCTION(socket_bind);
PHP_FUNCTION(socket_recv);
PHP_FUNCTION(socket_send);
PHP_FUNCTION(socket_recvfrom);
PHP_FUNCTION(socket_sendto);
PHP_FUNCTION(socket_get_option);
PHP_FUNCTION(socket_set_option);
#ifdef HAVE_SHUTDOWN
PHP_FUNCTION(socket_shutdown);
#endif
PHP_FUNCTION(socket_last_error);
PHP_FUNCTION(socket_clear_error);
PHP_FUNCTION(socket_import_stream);
/* {{{ sockets_functions[]
*/
const zend_function_entry sockets_functions[] = {
@@ -313,6 +341,9 @@ const zend_function_entry sockets_functions[] = {
PHP_FE(socket_last_error, arginfo_socket_last_error)
PHP_FE(socket_clear_error, arginfo_socket_clear_error)
PHP_FE(socket_import_stream, arginfo_socket_import_stream)
PHP_FE(socket_sendmsg, arginfo_socket_sendmsg)
PHP_FE(socket_recvmsg, arginfo_socket_recvmsg)
PHP_FE(socket_cmsg_space, arginfo_socket_cmsg_space)
/* for downwards compatability */
PHP_FALIAS(socket_getopt, socket_get_option, arginfo_socket_get_option)
@@ -358,13 +389,13 @@ PHP_SOCKETS_API int php_sockets_le_socket(void) /* {{{ */
static php_socket *php_create_socket(void) /* {{{ */
{
php_socket *php_sock = emalloc(sizeof *php_sock);
php_sock->bsd_socket = -1; /* invalid socket */
php_sock->type = PF_UNSPEC;
php_sock->error = 0;
php_sock->blocking = 1;
php_sock->zstream = NULL;
return php_sock;
}
/* }}} */
@@ -521,7 +552,7 @@ static int php_read(php_socket *sock, void *buf, size_t maxlen, int flags)
}
/* }}} */
static char *php_strerror(int error TSRMLS_DC) /* {{{ */
char *sockets_strerror(int error TSRMLS_DC) /* {{{ */
{
const char *buf;
@@ -568,188 +599,6 @@ static char *php_strerror(int error TSRMLS_DC) /* {{{ */
}
/* }}} */
#if HAVE_IPV6
/* Sets addr by hostname, or by ip in string form (AF_INET6) */
static int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
{
struct in6_addr tmp;
#if HAVE_GETADDRINFO
struct addrinfo hints;
struct addrinfo *addrinfo = NULL;
#endif
if (inet_pton(AF_INET6, string, &tmp)) {
memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr), sizeof(struct in6_addr));
} else {
#if HAVE_GETADDRINFO
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = PF_INET6;
getaddrinfo(string, NULL, &hints, &addrinfo);
if (!addrinfo) {
#ifdef PHP_WIN32
PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
#else
PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
#endif
return 0;
}
if (addrinfo->ai_family != PF_INET6 || addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET6 domain returned on AF_INET6 socket");
freeaddrinfo(addrinfo);
return 0;
}
memcpy(&(sin6->sin6_addr.s6_addr), ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, sizeof(struct in6_addr));
freeaddrinfo(addrinfo);
#else
/* No IPv6 specific hostname resolution is available on this system? */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: getaddrinfo() not available on this system");
return 0;
#endif
}
return 1;
}
/* }}} */
#endif
/* Sets addr by hostname, or by ip in string form (AF_INET) */
static int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
{
struct in_addr tmp;
struct hostent *host_entry;
if (inet_aton(string, &tmp)) {
sin->sin_addr.s_addr = tmp.s_addr;
} else {
if (! (host_entry = gethostbyname(string))) {
/* Note: < -10000 indicates a host lookup error */
#ifdef PHP_WIN32
PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
#else
PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
#endif
return 0;
}
if (host_entry->h_addrtype != AF_INET) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup failed: Non AF_INET domain returned on AF_INET socket");
return 0;
}
memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0], host_entry->h_length);
}
return 1;
}
/* }}} */
/* Sets addr by hostname or by ip in string form (AF_INET or AF_INET6,
* depending on the socket) */
static int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock TSRMLS_DC) /* {{{ */
{
if (php_sock->type == AF_INET) {
struct sockaddr_in t = {0};
if (php_set_inet_addr(&t, string, php_sock TSRMLS_CC)) {
memcpy(ss, &t, sizeof t);
ss->ss_family = AF_INET;
*ss_len = sizeof(t);
return 1;
}
}
#if HAVE_IPV6
else if (php_sock->type == AF_INET6) {
struct sockaddr_in6 t = {0};
if (php_set_inet6_addr(&t, string, php_sock TSRMLS_CC)) {
memcpy(ss, &t, sizeof t);
ss->ss_family = AF_INET6;
*ss_len = sizeof(t);
return 1;
}
}
#endif
else {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"IP address used in the context of an unexpected type of socket");
}
return 0;
}
static int php_get_if_index_from_zval(zval *val, unsigned *out TSRMLS_DC)
{
int ret;
if (Z_TYPE_P(val) == IS_LONG) {
if (Z_LVAL_P(val) < 0 || Z_LVAL_P(val) > UINT_MAX) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"the interface index cannot be negative or larger than %u;"
" given %ld", UINT_MAX, Z_LVAL_P(val));
ret = FAILURE;
} else {
*out = Z_LVAL_P(val);
ret = SUCCESS;
}
} else {
#if HAVE_IF_NAMETOINDEX
unsigned int ind;
zval_add_ref(&val);
convert_to_string_ex(&val);
ind = if_nametoindex(Z_STRVAL_P(val));
if (ind == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"no interface with name \"%s\" could be found", Z_STRVAL_P(val));
ret = FAILURE;
} else {
*out = ind;
ret = SUCCESS;
}
zval_ptr_dtor(&val);
#else
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"this platform does not support looking up an interface by "
"name, an integer interface index must be supplied instead");
ret = FAILURE;
#endif
}
return ret;
}
static int php_get_if_index_from_array(const HashTable *ht, const char *key,
php_socket *sock, unsigned int *if_index TSRMLS_DC)
{
zval **val;
if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE) {
*if_index = 0; /* default: 0 */
return SUCCESS;
}
return php_get_if_index_from_zval(*val, if_index TSRMLS_CC);
}
static int php_get_address_from_array(const HashTable *ht, const char *key,
php_socket *sock, php_sockaddr_storage *ss, socklen_t *ss_len TSRMLS_DC)
{
zval **val,
*valcp;
if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", key);
return FAILURE;
}
valcp = *val;
zval_add_ref(&valcp);
convert_to_string_ex(val);
if (!php_set_inet46_addr(ss, ss_len, Z_STRVAL_P(valcp), sock TSRMLS_CC)) {
zval_ptr_dtor(&valcp);
return FAILURE;
}
zval_ptr_dtor(&valcp);
return SUCCESS;
}
/* {{{ PHP_GINIT_FUNCTION */
static PHP_GINIT_FUNCTION(sockets)
{
@@ -774,11 +623,11 @@ PHP_MINIT_FUNCTION(sockets)
REGISTER_LONG_CONSTANT("SOCK_RAW", SOCK_RAW, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOCK_SEQPACKET",SOCK_SEQPACKET, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOCK_RDM", SOCK_RDM, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MSG_OOB", MSG_OOB, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MSG_WAITALL", MSG_WAITALL, CONST_CS | CONST_PERSISTENT);
#ifdef MSG_DONTWAIT
REGISTER_LONG_CONSTANT("MSG_DONTWAIT", MSG_DONTWAIT, CONST_CS | CONST_PERSISTENT);
#endif
REGISTER_LONG_CONSTANT("MSG_CTRUNC", MSG_CTRUNC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MSG_TRUNC", MSG_TRUNC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MSG_PEEK", MSG_PEEK, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("MSG_DONTROUTE", MSG_DONTROUTE, CONST_CS | CONST_PERSISTENT);
#ifdef MSG_EOR
@@ -787,6 +636,29 @@ PHP_MINIT_FUNCTION(sockets)
#ifdef MSG_EOF
REGISTER_LONG_CONSTANT("MSG_EOF", MSG_EOF, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef MSG_CONFIRM
REGISTER_LONG_CONSTANT("MSG_CONFIRM", MSG_CONFIRM, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef MSG_ERRQUEUE
REGISTER_LONG_CONSTANT("MSG_ERRQUEUE", MSG_ERRQUEUE, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef MSG_NOSIGNAL
REGISTER_LONG_CONSTANT("MSG_NOSIGNAL", MSG_NOSIGNAL, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef MSG_DONTWAIT
REGISTER_LONG_CONSTANT("MSG_DONTWAIT", MSG_DONTWAIT, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef MSG_MORE
REGISTER_LONG_CONSTANT("MSG_MORE", MSG_MORE, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef MSG_WAITFORONE
REGISTER_LONG_CONSTANT("MSG_WAITFORONE",MSG_WAITFORONE, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef MSG_CMSG_CLOEXEC
REGISTER_LONG_CONSTANT("MSG_CMSG_CLOEXEC",MSG_CMSG_CLOEXEC,CONST_CS | CONST_PERSISTENT);
#endif
REGISTER_LONG_CONSTANT("SO_DEBUG", SO_DEBUG, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SO_REUSEADDR", SO_REUSEADDR, CONST_CS | CONST_PERSISTENT);
#ifdef SO_REUSEPORT
@@ -804,6 +676,9 @@ PHP_MINIT_FUNCTION(sockets)
REGISTER_LONG_CONSTANT("SO_SNDTIMEO", SO_SNDTIMEO, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SO_RCVTIMEO", SO_RCVTIMEO, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SO_TYPE", SO_TYPE, CONST_CS | CONST_PERSISTENT);
#ifdef SO_FAMILY
REGISTER_LONG_CONSTANT("SO_FAMILY", SO_FAMILY, CONST_CS | CONST_PERSISTENT);
#endif
REGISTER_LONG_CONSTANT("SO_ERROR", SO_ERROR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOL_SOCKET", SOL_SOCKET, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOMAXCONN", SOMAXCONN, CONST_CS | CONST_PERSISTENT);
@@ -823,7 +698,7 @@ PHP_MINIT_FUNCTION(sockets)
#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
@@ -856,6 +731,12 @@ PHP_MINIT_FUNCTION(sockets)
REGISTER_LONG_CONSTANT("SOL_TCP", IPPROTO_TCP, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("SOL_UDP", IPPROTO_UDP, CONST_CS | CONST_PERSISTENT);
#if HAVE_IPV6
REGISTER_LONG_CONSTANT("IPV6_UNICAST_HOPS", IPV6_UNICAST_HOPS, CONST_CS | CONST_PERSISTENT);
#endif
php_socket_sendrecvmsg_init(INIT_FUNC_ARGS_PASSTHRU);
return SUCCESS;
}
/* }}} */
@@ -877,6 +758,7 @@ PHP_RSHUTDOWN_FUNCTION(sockets)
efree(SOCKETS_G(strerror_buf));
SOCKETS_G(strerror_buf) = NULL;
}
php_socket_sendrecvmsg_shutdown(SHUTDOWN_FUNC_ARGS_PASSTHRU);
return SUCCESS;
}
@@ -1018,7 +900,7 @@ PHP_FUNCTION(socket_select)
if (retval == -1) {
SOCKETS_G(last_error) = errno;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s", errno, sockets_strerror(errno TSRMLS_CC));
RETURN_FALSE;
}
@@ -1087,7 +969,7 @@ PHP_FUNCTION(socket_set_nonblock)
}
ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
if (php_sock->zstream != NULL) {
php_stream *stream;
/* omit notice if resource doesn't exist anymore */
@@ -1096,7 +978,7 @@ PHP_FUNCTION(socket_set_nonblock)
if (stream != NULL) {
if (php_stream_set_option(stream, PHP_STREAM_OPTION_BLOCKING, 0,
NULL) != -1) {
php_sock->blocking = 1;
php_sock->blocking = 0;
RETURN_TRUE;
}
}
@@ -1124,7 +1006,7 @@ PHP_FUNCTION(socket_set_block)
}
ZEND_FETCH_RESOURCE(php_sock, php_socket *, &arg1, -1, le_socket_name, le_socket);
/* if socket was created from a stream, give the stream a chance to take
* care of the operation itself, thereby allowing it to update its internal
* state */
@@ -1478,7 +1360,7 @@ PHP_FUNCTION(socket_create)
if (IS_INVALID_SOCKET(php_sock)) {
SOCKETS_G(last_error) = errno;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create socket [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create socket [%d]: %s", errno, sockets_strerror(errno TSRMLS_CC));
efree(php_sock);
RETURN_FALSE;
}
@@ -1511,7 +1393,7 @@ PHP_FUNCTION(socket_connect)
#if HAVE_IPV6
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;
@@ -1532,7 +1414,7 @@ PHP_FUNCTION(socket_connect)
#endif
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;
@@ -1551,7 +1433,7 @@ PHP_FUNCTION(socket_connect)
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;
@@ -1588,7 +1470,7 @@ PHP_FUNCTION(socket_strerror)
return;
}
RETURN_STRING(php_strerror(arg1 TSRMLS_CC), 1);
RETURN_STRING(sockets_strerror(arg1 TSRMLS_CC), 1);
}
/* }}} */
@@ -1979,8 +1861,15 @@ PHP_FUNCTION(socket_get_option)
}
}
}
} else if (level == IPPROTO_IPV6) {
int ret = php_do_getsockopt_ipv6_rfc3542(php_sock, level, optname, return_value TSRMLS_CC);
if (ret == SUCCESS) {
return;
} else if (ret == FAILURE) {
RETURN_FALSE;
} /* else continue */
}
/* sol_socket options and general case */
switch(optname) {
case SO_LINGER:
@@ -2022,7 +1911,7 @@ PHP_FUNCTION(socket_get_option)
add_assoc_long(return_value, "sec", tv.tv_sec);
add_assoc_long(return_value, "usec", tv.tv_usec);
break;
default:
optlen = sizeof(other_val);
@@ -2039,102 +1928,6 @@ PHP_FUNCTION(socket_get_option)
}
/* }}} */
static int php_do_mcast_opt(php_socket *php_sock, int level, int optname, zval **arg4 TSRMLS_DC)
{
HashTable *opt_ht;
unsigned int if_index;
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:
mcast_req_fun = &php_mcast_join;
goto mcast_req_fun;
case MCAST_LEAVE_GROUP:
{
php_sockaddr_storage group = {0};
socklen_t glen;
mcast_req_fun = &php_mcast_leave;
mcast_req_fun:
convert_to_array_ex(arg4);
opt_ht = HASH_OF(*arg4);
if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
&glen TSRMLS_CC) == FAILURE) {
return FAILURE;
}
if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
&if_index TSRMLS_CC) == FAILURE) {
return FAILURE;
}
retval = mcast_req_fun(php_sock, level, (struct sockaddr*)&group,
glen, if_index TSRMLS_CC);
break;
}
#ifdef HAS_MCAST_EXT
case MCAST_BLOCK_SOURCE:
mcast_sreq_fun = &php_mcast_block_source;
goto mcast_sreq_fun;
case MCAST_UNBLOCK_SOURCE:
mcast_sreq_fun = &php_mcast_unblock_source;
goto mcast_sreq_fun;
case MCAST_JOIN_SOURCE_GROUP:
mcast_sreq_fun = &php_mcast_join_source;
goto mcast_sreq_fun;
case MCAST_LEAVE_SOURCE_GROUP:
{
php_sockaddr_storage group = {0},
source = {0};
socklen_t glen,
slen;
mcast_sreq_fun = &php_mcast_leave_source;
mcast_sreq_fun:
convert_to_array_ex(arg4);
opt_ht = HASH_OF(*arg4);
if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
&glen TSRMLS_CC) == FAILURE) {
return FAILURE;
}
if (php_get_address_from_array(opt_ht, "source", php_sock, &source,
&slen TSRMLS_CC) == FAILURE) {
return FAILURE;
}
if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
&if_index TSRMLS_CC) == FAILURE) {
return FAILURE;
}
retval = mcast_sreq_fun(php_sock, level, (struct sockaddr*)&group,
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). "
"This is a bug.", level, optname);
return FAILURE;
}
if (retval != 0) {
if (retval != -2) { /* error, but message already emitted */
PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
}
return FAILURE;
}
return SUCCESS;
}
/* {{{ proto bool socket_set_option(resource socket, int level, int optname, int|array optval)
Sets socket options for the socket */
PHP_FUNCTION(socket_set_option)
@@ -2153,12 +1946,8 @@ PHP_FUNCTION(socket_set_option)
HashTable *opt_ht;
zval **l_onoff, **l_linger;
zval **sec, **usec;
/* Multicast */
unsigned int if_index;
struct in_addr if_addr;
unsigned char ipv4_mcast_ttl_lback;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllZ", &arg1, &level, &optname, &arg4) == FAILURE) {
return;
}
@@ -2167,94 +1956,26 @@ PHP_FUNCTION(socket_set_option)
set_errno(0);
#define HANDLE_SUBCALL(res) \
do { \
if (res == 1) { goto default_case; } \
else if (res == SUCCESS) { RETURN_TRUE; } \
else { RETURN_FALSE; } \
} while (0)
if (level == IPPROTO_IP) {
switch (optname) {
case MCAST_JOIN_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 {
RETURN_TRUE;
}
case IP_MULTICAST_IF:
if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
if (php_if_index_to_addr4(if_index, php_sock, &if_addr TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
opt_ptr = &if_addr;
optlen = sizeof(if_addr);
goto dosockopt;
case IP_MULTICAST_LOOP:
convert_to_boolean_ex(arg4);
goto ipv4_loop_ttl;
case IP_MULTICAST_TTL:
convert_to_long_ex(arg4);
if (Z_LVAL_PP(arg4) < 0L || Z_LVAL_PP(arg4) > 255L) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Expected a value between 0 and 255");
RETURN_FALSE;
}
ipv4_loop_ttl:
ipv4_mcast_ttl_lback = (unsigned char) Z_LVAL_PP(arg4);
opt_ptr = &ipv4_mcast_ttl_lback;
optlen = sizeof(ipv4_mcast_ttl_lback);
goto dosockopt;
}
int res = php_do_setsockopt_ip_mcast(php_sock, level, optname, arg4 TSRMLS_CC);
HANDLE_SUBCALL(res);
}
#if HAVE_IPV6
else if (level == IPPROTO_IPV6) {
switch (optname) {
case MCAST_JOIN_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 {
RETURN_TRUE;
}
case IPV6_MULTICAST_IF:
if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
opt_ptr = &if_index;
optlen = sizeof(if_index);
goto dosockopt;
case IPV6_MULTICAST_LOOP:
convert_to_boolean_ex(arg4);
goto ipv6_loop_hops;
case IPV6_MULTICAST_HOPS:
convert_to_long_ex(arg4);
if (Z_LVAL_PP(arg4) < -1L || Z_LVAL_PP(arg4) > 255L) {
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Expected a value between -1 and 255");
RETURN_FALSE;
}
ipv6_loop_hops:
ov = (int) Z_LVAL_PP(arg4);
opt_ptr = &ov;
optlen = sizeof(ov);
goto dosockopt;
int res = php_do_setsockopt_ipv6_mcast(php_sock, level, optname, arg4 TSRMLS_CC);
if (res == 1) {
res = php_do_setsockopt_ipv6_rfc3542(php_sock, level, optname, arg4 TSRMLS_CC);
}
HANDLE_SUBCALL(res);
}
#endif
@@ -2317,8 +2038,9 @@ ipv6_loop_hops:
#endif
break;
}
default:
default_case:
convert_to_long_ex(arg4);
ov = Z_LVAL_PP(arg4);
@@ -2327,12 +2049,9 @@ ipv6_loop_hops:
break;
}
dosockopt:
retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
if (retval != 0) {
if (retval != -2) { /* error, but message already emitted */
PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
}
PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
RETURN_FALSE;
}
@@ -2373,7 +2092,7 @@ PHP_FUNCTION(socket_create_pair)
if (socketpair(domain, type, protocol, fds_array) != 0) {
SOCKETS_G(last_error) = errno;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create socket pair [%d]: %s", errno, php_strerror(errno TSRMLS_CC));
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create socket pair [%d]: %s", errno, sockets_strerror(errno TSRMLS_CC));
efree(php_sock[0]);
efree(php_sock[1]);
RETURN_FALSE;
@@ -2472,6 +2191,53 @@ PHP_FUNCTION(socket_clear_error)
}
/* }}} */
php_socket *socket_import_file_descriptor(PHP_SOCKET socket TSRMLS_DC)
{
#ifdef SO_DOMAIN
int type;
socklen_t type_len = sizeof(type);
#endif
php_socket *retsock;
php_sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
#ifndef PHP_WIN32
int t;
#endif
retsock = php_create_socket();
retsock->bsd_socket = socket;
/* determine family */
#ifdef SO_DOMAIN
if (getsockopt(socket, SOL_SOCKET, SO_DOMAIN, &type, &type_len) == 0) {
retsock->type = type;
} else
#endif
if (getsockname(socket, (struct sockaddr*)&addr, &addr_len) == 0) {
retsock->type = addr.ss_family;
} else {
PHP_SOCKET_ERROR(retsock, "unable to obtain socket family", errno);
goto error;
}
/* determine blocking mode */
#ifndef PHP_WIN32
t = fcntl(socket, F_GETFL);
if (t == -1) {
PHP_SOCKET_ERROR(retsock, "unable to obtain blocking state", errno);
goto error;
} else {
retsock->blocking = !(t & O_NONBLOCK);
}
#endif
return retsock;
error:
efree(retsock);
return NULL;
}
/* {{{ proto void socket_import_stream(resource stream)
Imports a stream that encapsulates a socket into a socket extension resource. */
PHP_FUNCTION(socket_import_stream)
@@ -2480,44 +2246,23 @@ PHP_FUNCTION(socket_import_stream)
php_stream *stream;
php_socket *retsock = NULL;
PHP_SOCKET socket; /* fd */
php_sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
#ifndef PHP_WIN32
int t;
#endif
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstream) == FAILURE) {
return;
}
php_stream_from_zval(stream, &zstream);
if (php_stream_cast(stream, PHP_STREAM_AS_SOCKETD, (void**)&socket, 1)) {
/* error supposedly already shown */
RETURN_FALSE;
}
retsock = php_create_socket();
retsock->bsd_socket = socket;
/* determine family */
if (getsockname(socket, (struct sockaddr*)&addr, &addr_len) == 0) {
retsock->type = addr.ss_family;
} else {
PHP_SOCKET_ERROR(retsock, "unable to obtain socket family", errno);
goto error;
retsock = socket_import_file_descriptor(socket TSRMLS_CC);
if (retsock == NULL) {
RETURN_FALSE;
}
/* determine blocking mode */
#ifndef PHP_WIN32
t = fcntl(socket, F_GETFL);
if(t == -1) {
PHP_SOCKET_ERROR(retsock, "unable to obtain blocking state", errno);
goto error;
} else {
retsock->blocking = !(t & O_NONBLOCK);
}
#else
#ifdef PHP_WIN32
/* on windows, check if the stream is a socket stream and read its
* private data; otherwise assume it's in non-blocking mode */
if (php_stream_is(stream, PHP_STREAM_IS_SOCKET)) {
@@ -2527,7 +2272,7 @@ PHP_FUNCTION(socket_import_stream)
retsock->blocking = 1;
}
#endif
/* hold a zval reference to the stream (holding a php_stream* directly could
* also be done, but this might be slightly better if in the future we want
* to provide a socket_export_stream) */
@@ -2536,16 +2281,11 @@ PHP_FUNCTION(socket_import_stream)
zval_copy_ctor(retsock->zstream);
Z_UNSET_ISREF_P(retsock->zstream);
Z_SET_REFCOUNT_P(retsock->zstream, 1);
php_stream_set_option(stream, PHP_STREAM_OPTION_READ_BUFFER,
PHP_STREAM_BUFFER_NONE, NULL);
ZEND_REGISTER_RESOURCE(return_value, retsock, le_socket);
return;
error:
if (retsock != NULL)
efree(retsock);
RETURN_FALSE;
}
/* }}} */

View File

@@ -2,7 +2,5 @@
if (!defined("AF_INET6")) {
die('skip no IPv6 support');
}
/* If IPv6 is supported on the platform this will error out with code 111 - Connection refused.
If IPv6 is NOT supported, $errno will be set to something else (indicating parse/getaddrinfo error) */
@stream_socket_client('tcp://[::1]:0', $errno);
if ($errno != 111) die('skip no IPv6 support');
if (@stream_socket_client('udp://[::1]:8888') === false)
die('skip no IPv6 support');

View File

@@ -9,8 +9,8 @@ if (!defined('IPPROTO_IPV6')) {
die('skip IPv6 not available.');
}
$level = IPPROTO_IPV6;
$s = socket_create($domain, SOCK_DGRAM, SOL_UDP) or die("skip Can not create socket");
if (socket_set_option($s, $level, IP_MULTICAST_IF, 1) === false) {
$s = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP) or die("skip Can not create socket");
if (socket_set_option($s, $level, IPV6_MULTICAST_IF, 1) === false) {
die("skip interface 1 either doesn't exist or has no ipv6 address");
}
--FILE--

View File

@@ -0,0 +1,89 @@
--TEST--
recvmsg(): receive SCM_CREDENTIALS messages
--SKIPIF--
<?php
if (!extension_loaded('sockets')) {
die('skip sockets extension not available.');
}
if (strtolower(substr(PHP_OS, 0, 3)) == 'win') {
die('skip not for Microsoft Windows');
}
--CLEAN--
<?php
$path = __DIR__ . "/unix_sock";
@unlink($path);
--FILE--
<?php
include __DIR__."/mcast_helpers.php.inc";
$path = __DIR__ . "/unix_sock";
@unlink($path);
echo "creating send socket\n";
$sends1 = socket_create(AF_UNIX, SOCK_DGRAM, 0) or die("err");
var_dump($sends1);
socket_set_nonblock($sends1) or die("Could not put in non-blocking mode");
echo "creating receive socket\n";
$s = socket_create(AF_UNIX, SOCK_DGRAM, 0) or die("err");
var_dump($s);
$br = socket_bind($s, $path) or die("err");
var_dump($br);
socket_set_nonblock($sends1) or die("Could not put in non-blocking mode");
socket_set_option($s, SOL_SOCKET, SO_PASSCRED, 1) or die("could not set SO_PASSCRED");
//$r = socket_sendmsg($sends1, [
// "iov" => ["test ", "thing", "\n"],
//], 0);
$r = socket_sendto($sends1, $msg = "dread", strlen($msg), 0, $path);
var_dump($r);
checktimeout($s, 500);
$data = [
"name" => [],
"buffer_size" => 2000,
"controllen" => socket_cmsg_space(SOL_SOCKET, SCM_CREDENTIALS)
];
if (!socket_recvmsg($s, $data, 0)) die("recvmsg");
print_r($data);
$pid = getmypid();
var_dump($data['control'][0]['data']['pid'] === $pid);
--EXPECTF--
creating send socket
resource(%d) of type (Socket)
creating receive socket
resource(%d) of type (Socket)
bool(true)
int(5)
Array
(
[name] =>
[control] => Array
(
[0] => Array
(
[level] => %d
[type] => %d
[data] => Array
(
[pid] => %d
[uid] => %d
[gid] => %d
)
)
)
[iov] => Array
(
[0] => dread
)
[flags] => 0
)
bool(true)

View File

@@ -0,0 +1,100 @@
--TEST--
recvmsg(): receive SCM_CREDENTIALS messages
--SKIPIF--
<?php
if (!extension_loaded('sockets')) {
die('skip sockets extension not available.');
}
if (strtolower(substr(PHP_OS, 0, 3)) == 'win') {
die('skip not for Microsoft Windows');
}
--CLEAN--
<?php
$path = __DIR__ . "/unix_sock";
@unlink($path);
--FILE--
<?php
include __DIR__."/mcast_helpers.php.inc";
$path = __DIR__ . "/unix_sock";
@unlink($path);
echo "creating send socket\n";
$sends1 = socket_create(AF_UNIX, SOCK_DGRAM, 0) or die("err");
var_dump($sends1);
socket_set_nonblock($sends1) or die("Could not put in non-blocking mode");
echo "creating receive socket\n";
$s = socket_create(AF_UNIX, SOCK_DGRAM, 0) or die("err");
var_dump($s);
$br = socket_bind($s, $path) or die("err");
var_dump($br);
socket_set_nonblock($s) or die("Could not put in non-blocking mode");
$r = socket_sendmsg($sends1, [
"name" => [ "path" => $path ],
"iov" => ["test ", "thing", "\n"],
"control" => [
[
"level" => SOL_SOCKET,
"type" => SCM_RIGHTS,
"data" => [$sends1, STDIN, STDOUT, STDERR],
]
]
], 0);
var_dump($r);
checktimeout($s, 500);
$data = [
"name" => [],
"buffer_size" => 2000,
"controllen" => socket_cmsg_space(SOL_SOCKET, SCM_RIGHTS, 3)
];
var_dump($data);
if (!socket_recvmsg($s, $data, 0)) die("recvmsg");
print_r($data);
--EXPECTF--
creating send socket
resource(%d) of type (Socket)
creating receive socket
resource(%d) of type (Socket)
bool(true)
int(11)
array(3) {
["name"]=>
array(0) {
}
["buffer_size"]=>
int(2000)
["controllen"]=>
int(32)
}
Array
(
[name] =>
[control] => Array
(
[0] => Array
(
[level] => %d
[type] => %d
[data] => Array
(
[0] => Resource id #%d
[1] => Resource id #%d
[2] => Resource id #%d
)
)
)
[iov] => Array
(
[0] => test thing
)
[flags] => 0
)

View File

@@ -80,9 +80,6 @@ stream_set_blocking
Warning: stream_set_blocking(): %d is not a valid stream resource in %s on line %d
socket_set_block
Warning: socket_set_block(): An operation was attempted on something that is not a socket.
in %ssocket_import_stream-4-win.php on line %d
Warning: socket_set_block(): unable to set blocking mode [%d]: An operation was attempted on something that is not a socket.
in %ssocket_import_stream-4-win.php on line %d

View File

@@ -0,0 +1,86 @@
--TEST--
recvmsg(): basic test
--SKIPIF--
<?php
if (!extension_loaded('sockets')) {
die('skip sockets extension not available.');
}
if (!defined('IPPROTO_IPV6')) {
die('skip IPv6 not available.');
}
--FILE--
<?php
include __DIR__."/mcast_helpers.php.inc";
$addr = '::1';
echo "creating send socket\n";
$sends1 = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP) or die("err");
var_dump($sends1);
$br = socket_bind($sends1, '::', 7001) or die("err");
var_dump($br);
socket_set_nonblock($sends1) or die("Could not put in non-blocking mode");
echo "creating receive socket\n";
$s = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP) or die("err");
var_dump($s);
$br = socket_bind($s, '::0', 3000) or die("err");
var_dump($br);
socket_set_option($s, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1) or die("err");
$r = socket_sendto($sends1, $m = "testing packet", strlen($m), 0, $addr, 3000);
var_dump($r);
if ($r < 12) die;
checktimeout($s, 500);
$data = [
"name" => ["family" => AF_INET6, "addr" => "::1"],
"buffer_size" => 2000,
"controllen" => socket_cmsg_space(IPPROTO_IPV6, IPV6_PKTINFO),
];
if (!socket_recvmsg($s, $data, 0)) die("recvmsg");
print_r($data);
--EXPECTF--
creating send socket
resource(%d) of type (Socket)
bool(true)
creating receive socket
resource(%d) of type (Socket)
bool(true)
int(14)
Array
(
[name] => Array
(
[family] => %d
[addr] => ::1
[port] => 7001
[flowinfo] => 0
[scope_id] => 0
)
[control] => Array
(
[0] => Array
(
[level] => %d
[type] => %d
[data] => Array
(
[addr] => ::1
[ifindex] => %d
)
)
)
[iov] => Array
(
[0] => testing packet
)
[flags] => 0
)

View File

@@ -0,0 +1,110 @@
--TEST--
sendmsg()/recvmsg(): test ability to receive multiple messages (WIN32)
--SKIPIF--
<?php
if (!extension_loaded('sockets'))
die('skip sockets extension not available.');
if (!defined('IPPROTO_IPV6'))
die('skip IPv6 not available.');
if (substr(PHP_OS, 0, 3) != 'WIN')
die('skip Only for Windows!');
/* Windows supports IPV6_RECVTCLASS and is able to receive the tclass via
* WSARecvMsg (though only the top 6 bits seem to reported), but WSASendMsg
* does not accept IPV6_TCLASS messages. We still test that sendmsg() works
* corectly by sending an IPV6_PKTINFO message that will have no effect */
--FILE--
<?php
include __DIR__."/mcast_helpers.php.inc";
$addr = '::1';
echo "creating send socket\n";
$sends1 = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP) or die("err");
var_dump($sends1);
$br = socket_bind($sends1, '::', 7001) or die("err");
var_dump($br);
socket_set_nonblock($sends1) or die("Could not put in non-blocking mode");
echo "creating receive socket\n";
$s = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP) or die("err");
var_dump($s);
$br = socket_bind($s, '::0', 3000) or die("err");
var_dump($br);
socket_set_option($s, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1) or die("err");
socket_set_option($s, IPPROTO_IPV6, IPV6_RECVTCLASS, 1) or die("err");
$r = socket_sendmsg($sends1, [
"name" => [ "addr" => "::1", "port" => 3000],
"iov" => ["test ", "thing", "\n"],
"control" => [[
"level" => IPPROTO_IPV6,
"type" => IPV6_PKTINFO,
"data" => [
'addr' => '::1',
'ifindex' => 1 /* we're assuming loopback is 1. Is this a safe assumption? */
],
]]
], 0);
var_dump($r);
checktimeout($s, 500);
$data = [
"name" => ["family" => AF_INET6, "addr" => "::1"],
"buffer_size" => 2000,
"controllen" => socket_cmsg_space(IPPROTO_IPV6, IPV6_PKTINFO) +
socket_cmsg_space(IPPROTO_IPV6, IPV6_TCLASS),
];
if (!socket_recvmsg($s, $data, 0)) die("recvmsg");
print_r($data);
--EXPECTF--
creating send socket
resource(5) of type (Socket)
bool(true)
creating receive socket
resource(6) of type (Socket)
bool(true)
int(11)
Array
(
[name] => Array
(
[family] => %d
[addr] => ::1
[port] => 7001
[flowinfo] => 0
[scope_id] => 0
)
[control] => Array
(
[0] => Array
(
[level] => %d
[type] => %d
[data] => Array
(
[addr] => ::1
[ifindex] => %d
)
)
[1] => Array
(
[level] => %d
[type] => %d
[data] => 0
)
)
[iov] => Array
(
[0] => test thing
)
[flags] => 0
)

View File

@@ -0,0 +1,106 @@
--TEST--
sendmsg()/recvmsg(): test ability to receive multiple messages
--SKIPIF--
<?php
if (!extension_loaded('sockets'))
die('skip sockets extension not available.');
if (!defined('IPPROTO_IPV6'))
die('skip IPv6 not available.');
if (substr(PHP_OS, 0, 3) == 'WIN')
die('skip Not for the Windows!');
/* Windows supports IPV6_RECVTCLASS and is able to receive the tclass via
* WSARecvMsg (though only the top 6 bits seem to reported), but WSASendMsg
* does not accept IPV6_TCLASS messages */
--FILE--
<?php
include __DIR__."/mcast_helpers.php.inc";
$addr = '::1';
echo "creating send socket\n";
$sends1 = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP) or die("err");
var_dump($sends1);
$br = socket_bind($sends1, '::', 7001) or die("err");
var_dump($br);
socket_set_nonblock($sends1) or die("Could not put in non-blocking mode");
echo "creating receive socket\n";
$s = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP) or die("err");
var_dump($s);
$br = socket_bind($s, '::0', 3000) or die("err");
var_dump($br);
socket_set_option($s, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1) or die("err");
socket_set_option($s, IPPROTO_IPV6, IPV6_RECVTCLASS, 1) or die("err");
$r = socket_sendmsg($sends1, [
"name" => [ "addr" => "::1", "port" => 3000],
"iov" => ["test ", "thing", "\n"],
"control" => [[
"level" => IPPROTO_IPV6,
"type" => IPV6_TCLASS,
"data" => 40,
]]
], 0);
var_dump($r);
checktimeout($s, 500);
$data = [
"name" => ["family" => AF_INET6, "addr" => "::1"],
"buffer_size" => 2000,
"controllen" => socket_cmsg_space(IPPROTO_IPV6, IPV6_PKTINFO) +
socket_cmsg_space(IPPROTO_IPV6, IPV6_TCLASS),
];
if (!socket_recvmsg($s, $data, 0)) die("recvmsg");
print_r($data);
--EXPECTF--
creating send socket
resource(5) of type (Socket)
bool(true)
creating receive socket
resource(6) of type (Socket)
bool(true)
int(11)
Array
(
[name] => Array
(
[family] => %d
[addr] => ::1
[port] => 7001
[flowinfo] => 0
[scope_id] => 0
)
[control] => Array
(
[0] => Array
(
[level] => %d
[type] => %d
[data] => Array
(
[addr] => ::1
[ifindex] => %d
)
)
[1] => Array
(
[level] => %d
[type] => %d
[data] => 40
)
)
[iov] => Array
(
[0] => test thing
)
[flags] => 0
)

View File

@@ -14,12 +14,14 @@ if (!extension_loaded('sockets')) {
if (!socket_set_nonblock($socket)) {
die('Unable to set nonblocking mode for socket');
}
socket_recvfrom($socket, $buf, 12, 0, $from, $port); // cause warning
$address = '127.0.0.1';
socket_sendto($socket, '', 1, 0, $address); // cause warning
if (!socket_bind($socket, $address, 1223)) {
die("Unable to bind to $address:1223");
}
var_dump(socket_recvfrom($socket, $buf, 12, 0, $from, $port)); //false (EAGAIN - no warning)
$msg = "Ping!";
$len = strlen($msg);
@@ -44,9 +46,9 @@ if (!extension_loaded('sockets')) {
socket_close($socket);
--EXPECTF--
Warning: socket_recvfrom(): unable to recvfrom [%d]: %a in %s on line %d
Warning: Wrong parameter count for socket_sendto() in %s on line %d
bool(false)
Warning: socket_recvfrom() expects at least 5 parameters, 4 given in %s on line %d

View File

@@ -0,0 +1,62 @@
--TEST--
Test if socket_recvfrom() receives data sent by socket_sendto() via IPv6 UDP (Win32)
--SKIPIF--
<?php
if (!extension_loaded('sockets')) {
die('SKIP The sockets extension is not loaded.');
}
if (substr(PHP_OS, 0, 3) != 'WIN') {
die('skip only for Windows');
}
require 'ipv6_skipif.inc';
--FILE--
<?php
$socket = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP);
if (!$socket) {
die('Unable to create AF_INET6 socket');
}
if (!socket_set_nonblock($socket)) {
die('Unable to set nonblocking mode for socket');
}
socket_recvfrom($socket, $buf, 12, 0, $from, $port); // cause warning
$address = '::1';
socket_sendto($socket, '', 1, 0, $address); // cause warning
if (!socket_bind($socket, $address, 1223)) {
die("Unable to bind to $address:1223");
}
$msg = "Ping!";
$len = strlen($msg);
$bytes_sent = socket_sendto($socket, $msg, $len, 0, $address, 1223);
if ($bytes_sent == -1) {
die('An error occurred while sending to the socket');
} else if ($bytes_sent != $len) {
die($bytes_sent . ' bytes have been sent instead of the ' . $len . ' bytes expected');
}
$from = "";
$port = 0;
socket_recvfrom($socket, $buf, 12, 0); // cause warning
socket_recvfrom($socket, $buf, 12, 0, $from); // cause warning
$bytes_received = socket_recvfrom($socket, $buf, 12, 0, $from, $port);
if ($bytes_received == -1) {
die('An error occurred while receiving from the socket');
} else if ($bytes_received != $len) {
die($bytes_received . ' bytes have been received instead of the ' . $len . ' bytes expected');
}
echo "Received $buf from remote address $from and remote port $port" . PHP_EOL;
socket_close($socket);
--EXPECTF--
Warning: socket_recvfrom(): unable to recvfrom [10022]: An invalid argument was supplied.
in %s on line %d
Warning: Wrong parameter count for socket_sendto() in %s on line %d
Warning: socket_recvfrom() expects at least 5 parameters, 4 given in %s on line %d
Warning: Wrong parameter count for socket_recvfrom() in %s on line %d
Received Ping! from remote address ::1 and remote port 1223
--CREDITS--
Falko Menge <mail at falko-menge dot de>
PHP Testfest Berlin 2009-05-09

View File

@@ -5,6 +5,9 @@ Test if socket_recvfrom() receives data sent by socket_sendto() via IPv6 UDP
if (!extension_loaded('sockets')) {
die('SKIP The sockets extension is not loaded.');
}
if (substr(PHP_OS, 0, 3) == 'WIN') {
die('skip Not valid for Windows');
}
require 'ipv6_skipif.inc';
--FILE--
<?php
@@ -15,7 +18,7 @@ require 'ipv6_skipif.inc';
if (!socket_set_nonblock($socket)) {
die('Unable to set nonblocking mode for socket');
}
socket_recvfrom($socket, $buf, 12, 0, $from, $port); // cause warning
var_dump(socket_recvfrom($socket, $buf, 12, 0, $from, $port)); // false (EAGAIN, no warning)
$address = '::1';
socket_sendto($socket, '', 1, 0, $address); // cause warning
if (!socket_bind($socket, $address, 1223)) {
@@ -45,7 +48,7 @@ require 'ipv6_skipif.inc';
socket_close($socket);
--EXPECTF--
Warning: socket_recvfrom(): unable to recvfrom [11]: Resource temporarily unavailable in %s on line %d
bool(false)
Warning: Wrong parameter count for socket_sendto() in %s on line %d

View File

@@ -18,7 +18,7 @@ if (!extension_loaded('sockets')) {
if (!socket_set_nonblock($socket)) {
die('Unable to set nonblocking mode for socket');
}
socket_recvfrom($socket, $buf, 12, 0, $from, $port); // cause warning
var_dump(socket_recvfrom($socket, $buf, 12, 0, $from, $port)); //false (EAGAIN, no warning)
$address = sprintf("/tmp/%s.sock", uniqid());
if (!socket_bind($socket, $address)) {
die("Unable to bind to $address");
@@ -53,8 +53,7 @@ if (!extension_loaded('sockets')) {
?>
--EXPECTF--
Warning: socket_create(): Unable to create socket [%d]: Protocol not supported in %s on line %d
Warning: socket_recvfrom(): unable to recvfrom [%d]: Resource temporarily unavailable in %s on line %d
bool(false)
Warning: socket_sendto() expects at least 5 parameters, 4 given in %s on line %d
bool(false)

View File

@@ -0,0 +1,32 @@
--TEST--
socket_set_option() with IPV6_PKTINFO
--SKIPIF--
<?php
if (!extension_loaded('sockets')) {
die('skip sockets extension not available.');
}
if (!defined('IPPROTO_IPV6')) {
die('skip IPv6 not available.');
}
if (substr(PHP_OS, 0, 3) == 'WIN')
die('skip Not for Windows!');
--FILE--
<?php
$s = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP) or die("err");
var_dump(socket_set_option($s, IPPROTO_IPV6, IPV6_PKTINFO, []));
var_dump(socket_set_option($s, IPPROTO_IPV6, IPV6_PKTINFO, [
"addr" => '::1',
"ifindex" => 0
]));
//Oddly, Linux does not support IPV6_PKTINFO in sockgetopt().
//See do_ipv6_getsockopt() on the kernel sources
//A work-around with is sort-of possible (with IPV6_2292PKTOPTIONS),
//but not worth it
//var_dump(socket_get_option($s, IPPROTO_IPV6, IPV6_PKTINFO));
--EXPECTF--
Warning: socket_set_option(): error converting user data (path: in6_pktinfo): The key 'addr' is required in %s on line %d
bool(false)
bool(true)

View File

@@ -0,0 +1,120 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2012 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. |
+----------------------------------------------------------------------+
*/
#ifndef WINDOWS_COMMON_H
#define WINDOWS_COMMON_H
#include <Winsock2.h>
#define NTDDI_XP NTDDI_WINXP /* bug in SDK */
#include <IPHlpApi.h> /* conflicting definition of CMSG_DATA */
#undef NTDDI_XP
#define HAVE_IF_NAMETOINDEX 1
#define IS_INVALID_SOCKET(a) (a->bsd_socket == INVALID_SOCKET)
#ifdef errno
# undef errno
#endif
#define errno WSAGetLastError()
#define h_errno WSAGetLastError()
#define set_errno(a) WSASetLastError(a)
#define close(a) closesocket(a)
#ifdef ENETUNREACH /* errno.h probably included */
# undef EWOULDBLOCK
# undef EINPROGRESS
# undef EALREADY
# undef ENOTSOCK
# undef EDESTADDRREQ
# undef EMSGSIZE
# undef EPROTOTYPE
# undef ENOPROTOOPT
# undef EPROTONOSUPPORT
# undef ESOCKTNOSUPPORT
# undef EOPNOTSUPP
# undef EPFNOSUPPORT
# undef EAFNOSUPPORT
# undef EADDRINUSE
# undef EADDRNOTAVAIL
# undef ENETDOWN
# undef ENETUNREACH
# undef ENETRESET
# undef ECONNABORTED
# undef ECONNRESET
# undef ENOBUFS
# undef EISCONN
# undef ENOTCONN
# undef ESHUTDOWN
# undef ETOOMANYREFS
# undef ETIMEDOUT
# undef ECONNREFUSED
# undef ELOOP
# undef ENAMETOOLONG
# undef EHOSTDOWN
# undef EHOSTUNREACH
# undef ENOTEMPTY
# undef EPROCLIM
# undef EUSERS
# undef EDQUOT
# undef ESTALE
# undef EREMOTE
# undef EAGAIN
#endif
/* section disabled in WinSock2.h */
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EINPROGRESS WSAEINPROGRESS
#define EALREADY WSAEALREADY
#define ENOTSOCK WSAENOTSOCK
#define EDESTADDRREQ WSAEDESTADDRREQ
#define EMSGSIZE WSAEMSGSIZE
#define EPROTOTYPE WSAEPROTOTYPE
#define ENOPROTOOPT WSAENOPROTOOPT
#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
#define EOPNOTSUPP WSAEOPNOTSUPP
#define EPFNOSUPPORT WSAEPFNOSUPPORT
#define EAFNOSUPPORT WSAEAFNOSUPPORT
#define EADDRINUSE WSAEADDRINUSE
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
#define ENETDOWN WSAENETDOWN
#define ENETUNREACH WSAENETUNREACH
#define ENETRESET WSAENETRESET
#define ECONNABORTED WSAECONNABORTED
#define ECONNRESET WSAECONNRESET
#define ENOBUFS WSAENOBUFS
#define EISCONN WSAEISCONN
#define ENOTCONN WSAENOTCONN
#define ESHUTDOWN WSAESHUTDOWN
#define ETOOMANYREFS WSAETOOMANYREFS
#define ETIMEDOUT WSAETIMEDOUT
#define ECONNREFUSED WSAECONNREFUSED
#define ELOOP WSAELOOP
#define ENAMETOOLONG WSAENAMETOOLONG
#define EHOSTDOWN WSAEHOSTDOWN
#define EHOSTUNREACH WSAEHOSTUNREACH
#define ENOTEMPTY WSAENOTEMPTY
#define EPROCLIM WSAEPROCLIM
#define EUSERS WSAEUSERS
#define EDQUOT WSAEDQUOT
#define ESTALE WSAESTALE
#define EREMOTE WSAEREMOTE
/* and an extra one */
#define EAGAIN WSAEWOULDBLOCK
#endif

View File

@@ -1079,11 +1079,6 @@ PHPAPI int php_set_sock_blocking(int socketd, int block TSRMLS_DC)
/* with ioctlsocket, a non-zero sets nonblocking, a zero sets blocking */
flags = !block;
if (ioctlsocket(socketd, FIONBIO, &flags) == SOCKET_ERROR) {
char *error_string;
error_string = php_socket_strerror(WSAGetLastError(), NULL, 0);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", error_string);
efree(error_string);
ret = FAILURE;
}
#else

View File

@@ -21,6 +21,8 @@
#ifndef _PHP_NETWORK_H
#define _PHP_NETWORK_H
#include <php.h>
#ifdef PHP_WIN32
# include "win32/inet.h"
#else

View File

@@ -712,10 +712,9 @@ static void php_cli_server_poller_remove(php_cli_server_poller *poller, int mode
if (fd == poller->max_fd) {
while (fd > 0) {
fd--;
if (((unsigned int *)&poller->rfds)[fd / (8 * sizeof(unsigned int))] || ((unsigned int *)&poller->wfds)[fd / (8 * sizeof(unsigned int))]) {
if (PHP_SAFE_FD_ISSET(fd, &poller->rfds) || PHP_SAFE_FD_ISSET(fd, &poller->wfds)) {
break;
}
fd -= fd % (8 * sizeof(unsigned int));
}
poller->max_fd = fd;
}
@@ -774,23 +773,20 @@ static int php_cli_server_poller_iter_on_active(php_cli_server_poller *poller, v
}
#else
php_socket_t fd = 0;
php_socket_t fd;
const php_socket_t max_fd = poller->max_fd;
const unsigned int *pr = (unsigned int *)&poller->active.rfds,
*pw = (unsigned int *)&poller->active.wfds,
*e = pr + (max_fd + (8 * sizeof(unsigned int)) - 1) / (8 * sizeof(unsigned int));
unsigned int mask;
while (pr < e && fd <= max_fd) {
for (mask = 1; mask; mask <<= 1, fd++) {
int events = (*pr & mask ? POLLIN: 0) | (*pw & mask ? POLLOUT: 0);
if (events) {
if (SUCCESS != callback(opaque, fd, events)) {
retval = FAILURE;
}
}
for (fd=0 ; fd<=max_fd ; fd++) {
if (PHP_SAFE_FD_ISSET(fd, &poller->active.rfds)) {
if (SUCCESS != callback(opaque, fd, POLLIN)) {
retval = FAILURE;
}
}
if (PHP_SAFE_FD_ISSET(fd, &poller->active.wfds)) {
if (SUCCESS != callback(opaque, fd, POLLOUT)) {
retval = FAILURE;
}
}
pr++;
pw++;
}
#endif
return retval;

View File

@@ -1,83 +1,4 @@
#include "config.w32.h"
#include "php.h"
#include <winsock2.h>
#include <windows.h>
#include <Ws2tcpip.h>
#include "inet.h"
#if (_WIN32_WINNT < 0x0600) /* Vista/2k8 have these functions */
PHPAPI int inet_pton(int af, const char* src, void* dst)
{
int address_length;
struct sockaddr_storage sa;
struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
switch (af) {
case AF_INET:
address_length = sizeof (struct sockaddr_in);
break;
case AF_INET6:
address_length = sizeof (struct sockaddr_in6);
break;
default:
return -1;
}
if (WSAStringToAddress ((LPTSTR) src, af, NULL, (LPSOCKADDR) &sa, &address_length) == 0) {
switch (af) {
case AF_INET:
memcpy (dst, &sin->sin_addr, sizeof (struct in_addr));
break;
case AF_INET6:
memcpy (dst, &sin6->sin6_addr, sizeof (struct in6_addr));
break;
}
return 1;
}
return 0;
}
PHPAPI const char* inet_ntop(int af, const void* src, char* dst, size_t size)
{
int address_length;
DWORD string_length = size;
struct sockaddr_storage sa;
struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
memset (&sa, 0, sizeof (sa));
switch (af) {
case AF_INET:
address_length = sizeof (struct sockaddr_in);
sin->sin_family = af;
memcpy (&sin->sin_addr, src, sizeof (struct in_addr));
break;
case AF_INET6:
address_length = sizeof (struct sockaddr_in6);
sin6->sin6_family = af;
memcpy (&sin6->sin6_addr, src, sizeof (struct in6_addr));
break;
default:
return NULL;
}
if (WSAAddressToString ((LPSOCKADDR) &sa, address_length, NULL, dst, &string_length) == 0) {
return dst;
}
return NULL;
}
#endif
int inet_aton(const char *cp, struct in_addr *inp) {
inp->s_addr = inet_addr(cp);

View File

@@ -1,11 +1,4 @@
#if _MSC_VER >= 1500
# include <In6addr.h>
#endif
#include <Ws2tcpip.h>
#if (_WIN32_WINNT <= 0x502)
PHPAPI int inet_pton(int af, const char* src, void* dst);
PHPAPI const char* inet_ntop(int af, const void* src, char* dst, size_t size);
#endif
#include <php.h>
#include <Winsock2.h>
PHPAPI int inet_aton(const char *cp, struct in_addr *inp);