mirror of
https://github.com/php/php-src.git
synced 2026-04-02 05:32:28 +02:00
Merge branch 'PHP-5.5'
* PHP-5.5: (40 commits) php_strerror in ext/sockets renamed in 5.5 Move macro back to .c file Fix multicast.c not defining errno on Windows Fix non-Windows build send/recvmsg() support for Windows Remove some pre-vista code Revert "Payload of HOPLIMIT/TCLASS are 8-bit" Ensure memory is initialized Payload of HOPLIMIT/TCLASS are 8-bit Fix buf in string -> int conv. Build fixes; accept names for if_index Refactoring: move stuff to new conversions.c Support sticky IPV6_PKTINFO Rename some functions for consistency Destroy ancillary registry on shutdown Move some multicast stuff to multicast.c Fix mcast_ipv6_send test Check return of fstat() Fix build on Mac OS X Register extra MSG_* constants ...
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
1528
ext/sockets/conversions.c
Normal file
File diff suppressed because it is too large
Load Diff
84
ext/sockets/conversions.h
Normal file
84
ext/sockets/conversions.h
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -26,52 +26,19 @@
|
||||
|
||||
#if HAVE_SOCKETS
|
||||
|
||||
#include <php.h>
|
||||
|
||||
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 +66,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 +87,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
|
||||
|
||||
448
ext/sockets/sendrecvmsg.c
Normal file
448
ext/sockets/sendrecvmsg.c
Normal file
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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
|
||||
|
||||
PUT_ENTRY(sizeof(int), 0, 0, from_zval_write_int,
|
||||
to_zval_read_int, IPPROTO_IPV6, IPV6_TCLASS);
|
||||
|
||||
#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);
|
||||
*/
|
||||
REGISTER_LONG_CONSTANT("IPV6_RECVTCLASS", IPV6_RECVTCLASS, CONST_CS | CONST_PERSISTENT);
|
||||
|
||||
/*
|
||||
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);
|
||||
*/
|
||||
REGISTER_LONG_CONSTANT("IPV6_TCLASS", IPV6_TCLASS, 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
36
ext/sockets/sendrecvmsg.h
Normal 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
119
ext/sockets/sockaddr_conv.c
Normal 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;
|
||||
}
|
||||
31
ext/sockets/sockaddr_conv.h
Normal file
31
ext/sockets/sockaddr_conv.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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--
|
||||
|
||||
89
ext/sockets/tests/socket_cmsg_credentials.phpt
Normal file
89
ext/sockets/tests/socket_cmsg_credentials.phpt
Normal 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)
|
||||
100
ext/sockets/tests/socket_cmsg_rights.phpt
Normal file
100
ext/sockets/tests/socket_cmsg_rights.phpt
Normal 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
|
||||
)
|
||||
@@ -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
|
||||
|
||||
|
||||
86
ext/sockets/tests/socket_recvmsg.phpt
Normal file
86
ext/sockets/tests/socket_recvmsg.phpt
Normal 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
|
||||
)
|
||||
110
ext/sockets/tests/socket_sendrecvmsg_multi_msg-win32.phpt
Normal file
110
ext/sockets/tests/socket_sendrecvmsg_multi_msg-win32.phpt
Normal 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
|
||||
)
|
||||
106
ext/sockets/tests/socket_sendrecvmsg_multi_msg.phpt
Normal file
106
ext/sockets/tests/socket_sendrecvmsg_multi_msg.phpt
Normal 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
|
||||
)
|
||||
@@ -14,7 +14,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 = '127.0.0.1';
|
||||
socket_sendto($socket, '', 1, 0, $address); // cause warning
|
||||
if (!socket_bind($socket, $address, 1223)) {
|
||||
@@ -44,7 +44,7 @@ if (!extension_loaded('sockets')) {
|
||||
|
||||
socket_close($socket);
|
||||
--EXPECTF--
|
||||
Warning: socket_recvfrom(): unable to recvfrom [%d]: %a in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Warning: Wrong parameter count for socket_sendto() in %s on line %d
|
||||
|
||||
|
||||
62
ext/sockets/tests/socket_sentto_recvfrom_ipv6_udp-win32.phpt
Normal file
62
ext/sockets/tests/socket_sentto_recvfrom_ipv6_udp-win32.phpt
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
32
ext/sockets/tests/socket_set_option_in6_pktinfo.phpt
Normal file
32
ext/sockets/tests/socket_set_option_in6_pktinfo.phpt
Normal 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)
|
||||
|
||||
43
ext/sockets/windows_common.h
Normal file
43
ext/sockets/windows_common.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| 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 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)
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#ifndef _PHP_NETWORK_H
|
||||
#define _PHP_NETWORK_H
|
||||
|
||||
#include <php.h>
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
# include "win32/inet.h"
|
||||
#else
|
||||
|
||||
79
win32/inet.c
79
win32/inet.c
@@ -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);
|
||||
|
||||
11
win32/inet.h
11
win32/inet.h
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user