2012-11-02 03:38:42 +08:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
2014-09-20 00:33:14 +08:00
|
|
|
| PHP Version 7 |
|
2012-11-02 03:38:42 +08:00
|
|
|
+----------------------------------------------------------------------+
|
2018-01-02 12:57:58 +08:00
|
|
|
| Copyright (c) 1997-2018 The PHP Group |
|
2012-11-02 03:38:42 +08:00
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| 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"
|
2012-11-12 07:40:38 +08:00
|
|
|
#include "conversions.h"
|
2012-11-02 03:38:42 +08:00
|
|
|
#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
|
|
|
|
|
2013-01-31 21:01:31 +08:00
|
|
|
#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;
|
2013-05-09 01:51:39 +08:00
|
|
|
|
2013-01-31 21:01:31 +08:00
|
|
|
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
|
|
|
|
|
2012-11-02 03:38:42 +08:00
|
|
|
#define LONG_CHECK_VALID_INT(l) \
|
|
|
|
do { \
|
|
|
|
if ((l) < INT_MIN && (l) > INT_MAX) { \
|
2016-06-21 21:00:37 +08:00
|
|
|
php_error_docref0(NULL, E_WARNING, "The value " ZEND_LONG_FMT " does not fit inside " \
|
2012-11-02 03:38:42 +08:00
|
|
|
"the boundaries of a native integer", (l)); \
|
|
|
|
return; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
int initialized;
|
|
|
|
HashTable ht;
|
|
|
|
} ancillary_registry;
|
|
|
|
|
|
|
|
|
2014-05-17 10:23:46 +08:00
|
|
|
static void ancillary_registery_free_elem(zval *el) {
|
|
|
|
pefree(Z_PTR_P(el), 1);
|
|
|
|
}
|
|
|
|
|
2012-11-02 03:38:42 +08:00
|
|
|
#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;
|
|
|
|
|
2014-05-17 10:23:46 +08:00
|
|
|
zend_hash_init(&ancillary_registry.ht, 32, NULL, ancillary_registery_free_elem, 1);
|
2012-11-02 03:38:42 +08:00
|
|
|
|
2012-11-05 07:38:23 +08:00
|
|
|
#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; \
|
2014-05-17 10:23:46 +08:00
|
|
|
zend_hash_str_update_mem(&ancillary_registry.ht, (char*)&key, sizeof(key) - 1, (void*)&entry, sizeof(entry))
|
2012-11-03 00:54:31 +08:00
|
|
|
|
2013-05-09 01:51:39 +08:00
|
|
|
#if defined(IPV6_PKTINFO) && HAVE_IPV6
|
2012-11-05 07:38:23 +08:00
|
|
|
PUT_ENTRY(sizeof(struct in6_pktinfo), 0, 0, from_zval_write_in6_pktinfo,
|
|
|
|
to_zval_read_in6_pktinfo, IPPROTO_IPV6, IPV6_PKTINFO);
|
2012-11-06 00:10:10 +08:00
|
|
|
#endif
|
2012-11-05 07:38:23 +08:00
|
|
|
|
2013-05-09 01:51:39 +08:00
|
|
|
#if defined(IPV6_HOPLIMIT) && HAVE_IPV6
|
2013-01-31 22:26:10 +08:00
|
|
|
PUT_ENTRY(sizeof(int), 0, 0, from_zval_write_int,
|
|
|
|
to_zval_read_int, IPPROTO_IPV6, IPV6_HOPLIMIT);
|
2012-11-06 00:10:10 +08:00
|
|
|
#endif
|
2012-11-03 00:54:31 +08:00
|
|
|
|
2013-05-09 01:51:39 +08:00
|
|
|
#if defined(IPV6_TCLASS) && HAVE_IPV6
|
2013-01-31 22:26:10 +08:00
|
|
|
PUT_ENTRY(sizeof(int), 0, 0, from_zval_write_int,
|
|
|
|
to_zval_read_int, IPPROTO_IPV6, IPV6_TCLASS);
|
Fix bug and hopefully build on WinSDK 6.1
There build was failing on rmtools on the sockets extension for two reasons:
1. IPV6_TCLASS and IPV6_RECVTCLASS not being defined. These are probably
recent additions to SDK. Windows 7 doesn't event seem to have complete
support for IPV6_TCLASS, not accepting in WSASendMsg(). The parts that
needed this constant were not guarded by #ifdefs. They are now.
2. The constants EWOULDBLOCK and EINPROGRESS not being defined. These
were only defined in php_network.h, outside of the extension, and not
all source files included this header. Nevertheless, a macro defined in
php_sockets.h needed these constants. When this macro was used in files
that did not include php_network.h, the compilation would fail.
Surprisingly, the build did not fail when using the 7.1 Windows SDK
(more likely, the CRT headers used in VC10), as somehow errno.h was
being included through some other standard header. This would make the
constant EWOULDBLOCK defined; however, it would be defined to the wrong
value. In the winsock context, WSAEWOULDBLOCK should be used instead.
Because we have difficulty using Windows-only constants in the code, we
(re)define EWOULDBLOCK to WSAEWOULDBLOCK. This has the obvious
disavantage we may miss problems like this again in the future.
2013-02-03 08:22:44 +08:00
|
|
|
#endif
|
2012-11-03 00:54:31 +08:00
|
|
|
|
2012-11-06 00:10:10 +08:00
|
|
|
#ifdef SO_PASSCRED
|
2012-11-05 07:38:23 +08:00
|
|
|
PUT_ENTRY(sizeof(struct ucred), 0, 0, from_zval_write_ucred,
|
|
|
|
to_zval_read_ucred, SOL_SOCKET, SCM_CREDENTIALS);
|
2012-11-06 00:10:10 +08:00
|
|
|
#endif
|
2012-11-03 00:54:31 +08:00
|
|
|
|
2012-11-06 00:10:10 +08:00
|
|
|
#ifdef SCM_RIGHTS
|
2012-11-05 18:40:24 +08:00
|
|
|
PUT_ENTRY(0, sizeof(int), calculate_scm_rights_space, from_zval_write_fd_array,
|
|
|
|
to_zval_read_fd_array, SOL_SOCKET, SCM_RIGHTS);
|
2012-11-06 00:10:10 +08:00
|
|
|
#endif
|
2012-11-03 00:54:31 +08:00
|
|
|
|
2012-11-06 20:36:40 +08:00
|
|
|
}
|
|
|
|
static void destroy_ancillary_registry(void)
|
|
|
|
{
|
|
|
|
if (ancillary_registry.initialized) {
|
|
|
|
zend_hash_destroy(&ancillary_registry.ht);
|
|
|
|
ancillary_registry.initialized = 0;
|
|
|
|
}
|
2012-11-02 03:38:42 +08:00
|
|
|
}
|
2012-11-12 07:40:38 +08:00
|
|
|
ancillary_reg_entry *get_ancillary_reg_entry(int cmsg_level, int msg_type)
|
2012-11-02 03:38:42 +08:00
|
|
|
{
|
|
|
|
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
|
|
|
|
|
2014-05-17 10:23:46 +08:00
|
|
|
if ((entry = zend_hash_str_find_ptr(&ancillary_registry.ht, (char*)&key, sizeof(key) - 1)) != NULL) {
|
2012-11-02 03:38:42 +08:00
|
|
|
return entry;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PHP_FUNCTION(socket_sendmsg)
|
|
|
|
{
|
|
|
|
zval *zsocket,
|
|
|
|
*zmsg;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long flags = 0;
|
2012-11-02 03:38:42 +08:00
|
|
|
php_socket *php_sock;
|
|
|
|
struct msghdr *msghdr;
|
|
|
|
zend_llist *allocations;
|
|
|
|
struct err_s err = {0};
|
|
|
|
ssize_t res;
|
|
|
|
|
|
|
|
/* zmsg should be passed by ref */
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ra|l", &zsocket, &zmsg, &flags) == FAILURE) {
|
2012-11-02 03:38:42 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LONG_CHECK_VALID_INT(flags);
|
|
|
|
|
2015-02-02 13:23:16 +08:00
|
|
|
if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(zsocket),
|
|
|
|
php_sockets_le_socket_name, php_sockets_le_socket())) == NULL) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2012-11-02 03:38:42 +08:00
|
|
|
|
|
|
|
msghdr = from_zval_run_conversions(zmsg, php_sock, from_zval_write_msghdr_send,
|
|
|
|
sizeof(*msghdr), "msghdr", &allocations, &err);
|
|
|
|
|
|
|
|
if (err.has_error) {
|
2014-12-14 06:06:14 +08:00
|
|
|
err_msg_dispose(&err);
|
2012-11-02 03:38:42 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = sendmsg(php_sock->bsd_socket, msghdr, (int)flags);
|
|
|
|
|
|
|
|
if (res != -1) {
|
|
|
|
zend_llist_destroy(allocations);
|
|
|
|
efree(allocations);
|
|
|
|
|
2014-08-26 17:23:25 +08:00
|
|
|
RETURN_LONG((zend_long)res);
|
2012-11-02 03:38:42 +08:00
|
|
|
} else {
|
2013-01-31 21:01:31 +08:00
|
|
|
PHP_SOCKET_ERROR(php_sock, "error in sendmsg", errno);
|
2012-11-02 03:38:42 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PHP_FUNCTION(socket_recvmsg)
|
|
|
|
{
|
|
|
|
zval *zsocket,
|
|
|
|
*zmsg;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long flags = 0;
|
2012-11-02 03:38:42 +08:00
|
|
|
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);
|
2018-01-17 17:45:23 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ra|l",
|
2012-11-02 03:38:42 +08:00
|
|
|
&zsocket, &zmsg, &flags) == FAILURE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LONG_CHECK_VALID_INT(flags);
|
|
|
|
|
2015-02-02 13:23:16 +08:00
|
|
|
if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(zsocket),
|
|
|
|
php_sockets_le_socket_name, php_sockets_le_socket())) == NULL) {
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2012-11-02 03:38:42 +08:00
|
|
|
|
|
|
|
msghdr = from_zval_run_conversions(zmsg, php_sock, from_zval_write_msghdr_recv,
|
|
|
|
sizeof(*msghdr), "msghdr", &allocations, &err);
|
|
|
|
|
|
|
|
if (err.has_error) {
|
2014-12-14 06:06:14 +08:00
|
|
|
err_msg_dispose(&err);
|
2012-11-02 03:38:42 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = recvmsg(php_sock->bsd_socket, msghdr, (int)flags);
|
|
|
|
|
|
|
|
if (res != -1) {
|
2014-05-17 10:23:46 +08:00
|
|
|
zval *zres, tmp;
|
2012-11-02 03:38:42 +08:00
|
|
|
struct key_value kv[] = {
|
|
|
|
{KEY_RECVMSG_RET, sizeof(KEY_RECVMSG_RET), &res},
|
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
zres = to_zval_run_conversions((char *)msghdr, to_zval_read_msghdr,
|
2014-05-17 10:23:46 +08:00
|
|
|
"msghdr", kv, &err, &tmp);
|
2012-11-02 03:38:42 +08:00
|
|
|
|
|
|
|
/* we don;t need msghdr anymore; free it */
|
|
|
|
msghdr = NULL;
|
2012-11-07 00:27:08 +08:00
|
|
|
allocations_dispose(&allocations);
|
2012-11-02 03:38:42 +08:00
|
|
|
|
2018-01-17 17:45:23 +08:00
|
|
|
zval_ptr_dtor(zmsg);
|
2012-11-02 03:38:42 +08:00
|
|
|
if (!err.has_error) {
|
|
|
|
ZVAL_COPY_VALUE(zmsg, zres);
|
|
|
|
} else {
|
2014-12-14 06:06:14 +08:00
|
|
|
err_msg_dispose(&err);
|
2012-11-02 03:38:42 +08:00
|
|
|
ZVAL_FALSE(zmsg);
|
|
|
|
/* no need to destroy/free zres -- it's NULL in this circumstance */
|
|
|
|
assert(zres == NULL);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
SOCKETS_G(last_error) = errno;
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "error in recvmsg [%d]: %s",
|
|
|
|
errno, sockets_strerror(errno));
|
2012-11-02 03:38:42 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
RETURN_LONG((zend_long)res);
|
2012-11-02 03:38:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
PHP_FUNCTION(socket_cmsg_space)
|
|
|
|
{
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long level,
|
2012-11-05 07:38:23 +08:00
|
|
|
type,
|
|
|
|
n = 0;
|
2012-11-02 03:38:42 +08:00
|
|
|
ancillary_reg_entry *entry;
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll|l",
|
2012-11-05 07:38:23 +08:00
|
|
|
&level, &type, &n) == FAILURE) {
|
2012-11-02 03:38:42 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LONG_CHECK_VALID_INT(level);
|
|
|
|
LONG_CHECK_VALID_INT(type);
|
2012-11-05 07:38:23 +08:00
|
|
|
LONG_CHECK_VALID_INT(n);
|
|
|
|
|
|
|
|
if (n < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref0(NULL, E_WARNING, "The third argument "
|
2012-11-05 07:38:23 +08:00
|
|
|
"cannot be negative");
|
|
|
|
return;
|
|
|
|
}
|
2012-11-02 03:38:42 +08:00
|
|
|
|
|
|
|
entry = get_ancillary_reg_entry(level, type);
|
|
|
|
if (entry == NULL) {
|
2016-06-21 21:00:37 +08:00
|
|
|
php_error_docref0(NULL, E_WARNING, "The pair level " ZEND_LONG_FMT "/type " ZEND_LONG_FMT " is "
|
2012-11-02 03:38:42 +08:00
|
|
|
"not supported by PHP", level, type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-23 17:47:06 +08:00
|
|
|
if (entry->var_el_size > 0 && n > (zend_long)((ZEND_LONG_MAX - entry->size -
|
|
|
|
CMSG_SPACE(0) - 15L) / entry->var_el_size)) {
|
2012-11-05 07:38:23 +08:00
|
|
|
/* the -15 is to account for any padding CMSG_SPACE may add after the data */
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref0(NULL, E_WARNING, "The value for the "
|
2016-06-21 21:00:37 +08:00
|
|
|
"third argument (" ZEND_LONG_FMT ") is too large", n);
|
2012-11-05 07:38:23 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-26 17:23:25 +08:00
|
|
|
RETURN_LONG((zend_long)CMSG_SPACE(entry->size + n * entry->var_el_size));
|
2012-11-02 03:38:42 +08:00
|
|
|
}
|
|
|
|
|
2013-05-09 01:51:39 +08:00
|
|
|
#if HAVE_IPV6
|
2014-12-14 06:06:14 +08:00
|
|
|
int php_do_setsockopt_ipv6_rfc3542(php_socket *php_sock, int level, int optname, zval *arg4)
|
2012-11-07 00:27:08 +08:00
|
|
|
{
|
|
|
|
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:
|
2013-01-31 21:01:31 +08:00
|
|
|
#ifdef PHP_WIN32
|
2014-05-17 11:44:26 +08:00
|
|
|
if (Z_TYPE_P(arg4) == IS_ARRAY) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref0(NULL, E_WARNING, "Windows does not "
|
2013-01-31 21:01:31 +08:00
|
|
|
"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
|
2014-05-17 10:23:46 +08:00
|
|
|
opt_ptr = from_zval_run_conversions(arg4, php_sock, from_zval_write_in6_pktinfo,
|
2012-11-07 00:27:08 +08:00
|
|
|
sizeof(struct in6_pktinfo), "in6_pktinfo", &allocations, &err);
|
|
|
|
if (err.has_error) {
|
2014-12-14 06:06:14 +08:00
|
|
|
err_msg_dispose(&err);
|
2012-11-07 00:27:08 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
int php_do_getsockopt_ipv6_rfc3542(php_socket *php_sock, int level, int optname, zval *result)
|
2012-11-07 00:27:08 +08:00
|
|
|
{
|
|
|
|
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 {
|
2014-05-17 10:23:46 +08:00
|
|
|
zval tmp;
|
2012-11-07 00:27:08 +08:00
|
|
|
zval *zv = to_zval_run_conversions(buffer, reader, "in6_pktinfo",
|
2014-05-17 10:23:46 +08:00
|
|
|
empty_key_value_list, &err, &tmp);
|
2012-11-07 00:27:08 +08:00
|
|
|
if (err.has_error) {
|
2014-12-14 06:06:14 +08:00
|
|
|
err_msg_dispose(&err);
|
2012-11-07 00:27:08 +08:00
|
|
|
res = -1;
|
|
|
|
} else {
|
|
|
|
ZVAL_COPY_VALUE(result, zv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
efree(buffer);
|
|
|
|
|
|
|
|
return res == 0 ? SUCCESS : FAILURE;
|
|
|
|
}
|
2013-05-09 01:51:39 +08:00
|
|
|
#endif /* HAVE_IPV6 */
|
2012-11-07 00:27:08 +08:00
|
|
|
|
2012-11-06 20:38:57 +08:00
|
|
|
void php_socket_sendrecvmsg_init(INIT_FUNC_ARGS)
|
2012-11-02 03:38:42 +08:00
|
|
|
{
|
2013-01-02 06:38:19 +08:00
|
|
|
/* IPv6 ancillary data */
|
2013-05-09 01:51:39 +08:00
|
|
|
#if defined(IPV6_RECVPKTINFO) && HAVE_IPV6
|
2014-08-26 01:24:55 +08:00
|
|
|
REGISTER_LONG_CONSTANT("IPV6_RECVPKTINFO", IPV6_RECVPKTINFO, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("IPV6_PKTINFO", IPV6_PKTINFO, CONST_CS | CONST_PERSISTENT);
|
2012-11-06 00:10:10 +08:00
|
|
|
#endif
|
2013-05-09 01:51:39 +08:00
|
|
|
#if defined(IPV6_RECVHOPLIMIT) && HAVE_IPV6
|
2014-08-26 01:24:55 +08:00
|
|
|
REGISTER_LONG_CONSTANT("IPV6_RECVHOPLIMIT", IPV6_RECVHOPLIMIT, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("IPV6_HOPLIMIT", IPV6_HOPLIMIT, CONST_CS | CONST_PERSISTENT);
|
2012-11-06 00:10:10 +08:00
|
|
|
#endif
|
2012-11-03 00:54:31 +08:00
|
|
|
/* would require some effort:
|
2014-08-26 01:24:55 +08:00
|
|
|
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);
|
2012-11-03 00:54:31 +08:00
|
|
|
*/
|
2013-05-09 01:51:39 +08:00
|
|
|
#if defined(IPV6_RECVTCLASS) && HAVE_IPV6
|
2014-08-26 01:24:55 +08:00
|
|
|
REGISTER_LONG_CONSTANT("IPV6_RECVTCLASS", IPV6_RECVTCLASS, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("IPV6_TCLASS", IPV6_TCLASS, CONST_CS | CONST_PERSISTENT);
|
Fix bug and hopefully build on WinSDK 6.1
There build was failing on rmtools on the sockets extension for two reasons:
1. IPV6_TCLASS and IPV6_RECVTCLASS not being defined. These are probably
recent additions to SDK. Windows 7 doesn't event seem to have complete
support for IPV6_TCLASS, not accepting in WSASendMsg(). The parts that
needed this constant were not guarded by #ifdefs. They are now.
2. The constants EWOULDBLOCK and EINPROGRESS not being defined. These
were only defined in php_network.h, outside of the extension, and not
all source files included this header. Nevertheless, a macro defined in
php_sockets.h needed these constants. When this macro was used in files
that did not include php_network.h, the compilation would fail.
Surprisingly, the build did not fail when using the 7.1 Windows SDK
(more likely, the CRT headers used in VC10), as somehow errno.h was
being included through some other standard header. This would make the
constant EWOULDBLOCK defined; however, it would be defined to the wrong
value. In the winsock context, WSAEWOULDBLOCK should be used instead.
Because we have difficulty using Windows-only constants in the code, we
(re)define EWOULDBLOCK to WSAEWOULDBLOCK. This has the obvious
disavantage we may miss problems like this again in the future.
2013-02-03 08:22:44 +08:00
|
|
|
#endif
|
2012-11-03 00:54:31 +08:00
|
|
|
|
|
|
|
/*
|
2014-08-26 01:24:55 +08:00
|
|
|
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);
|
2012-11-03 00:54:31 +08:00
|
|
|
*/
|
2012-11-02 03:38:42 +08:00
|
|
|
|
2012-11-06 00:10:10 +08:00
|
|
|
#ifdef SCM_RIGHTS
|
2014-08-26 01:24:55 +08:00
|
|
|
REGISTER_LONG_CONSTANT("SCM_RIGHTS", SCM_RIGHTS, CONST_CS | CONST_PERSISTENT);
|
2012-11-06 00:10:10 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SO_PASSCRED
|
2014-08-26 01:24:55 +08:00
|
|
|
REGISTER_LONG_CONSTANT("SCM_CREDENTIALS", SCM_CREDENTIALS, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("SO_PASSCRED", SO_PASSCRED, CONST_CS | CONST_PERSISTENT);
|
2012-11-06 00:10:10 +08:00
|
|
|
#endif
|
2012-11-05 07:38:23 +08:00
|
|
|
|
2012-11-02 03:38:42 +08:00
|
|
|
#ifdef ZTS
|
|
|
|
ancillary_mutex = tsrm_mutex_alloc();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-11-06 20:38:57 +08:00
|
|
|
void php_socket_sendrecvmsg_shutdown(SHUTDOWN_FUNC_ARGS)
|
2012-11-02 03:38:42 +08:00
|
|
|
{
|
|
|
|
#ifdef ZTS
|
|
|
|
tsrm_mutex_free(ancillary_mutex);
|
|
|
|
#endif
|
2012-11-06 20:36:40 +08:00
|
|
|
|
|
|
|
destroy_ancillary_registry();
|
2012-11-02 03:38:42 +08:00
|
|
|
}
|