16# include <sys/types.h>
17# include <sys/socket.h>
18# include <arpa/inet.h>
19# include <netinet/in.h>
21# include <sys/ioctl.h>
32typedef unsigned short sa_family_t;
33# define msghdr _WSAMSG
45# define msg_namelen namelen
46# define msg_iov lpBuffers
47# define msg_iovlen dwBufferCount
48# define msg_control Control.buf
49# define msg_controllen Control.len
50# define msg_flags dwFlags
57# define CMSG_DATA WSA_CMSG_DATA
60#define MAX_USER_BUFF_SIZE ((size_t)(100*1024*1024))
61#define DEFAULT_BUFF_SIZE 8192
65# if __has_feature(undefined_behavior_sanitizer)
67# define CMSG_DATA(cmsg) ((unsigned char *) ((uintptr_t) (cmsg) + sizeof(struct cmsghdr)))
101#define KEY_FILL_SOCKADDR "fill_sockaddr"
102#define KEY_RECVMSG_RET "recvmsg_ret"
103#define KEY_CMSG_LEN "cmsg_len"
108static int param_get_bool(
void *ctx,
const char *
key,
int def)
119static inline void *accounted_emalloc(
size_t alloc_size,
ser_context *ctx)
125static inline void *accounted_ecalloc(
size_t nmemb,
size_t alloc_size,
ser_context *ctx)
131static inline void *accounted_safe_ecalloc(
size_t nmemb,
size_t alloc_size,
size_t offset,
ser_context *ctx)
140static void do_from_to_zval_err(
struct err_s *
err,
142 const char *what_conv,
152 if (
err->has_error) {
159 smart_str_appends(&path, *node);
160 smart_str_appends(&path,
" > ");
168 user_msg_size =
vspprintf(&user_msg, 0, fmt, ap);
172 spprintf(&
err->msg, 0,
"error converting %s data (path: %s): %.*s",
175 user_msg_size, user_msg);
176 err->should_free = 1;
179 smart_str_free(&path);
182static
void do_from_zval_err(
ser_context *ctx, const
char *fmt, ...)
187 do_from_to_zval_err(&ctx->err, &ctx->keys,
"user", fmt, ap);
191static
void do_to_zval_err(
res_context *ctx, const
char *fmt, ...)
196 do_from_to_zval_err(&ctx->err, &ctx->keys,
"native", fmt, ap);
204 if (
err->should_free) {
216static unsigned from_array_iterate(
const zval *arr,
223 char buf[
sizeof(
"element #4294967295")];
230 memcpy(
buf,
"element",
sizeof(
"element"));
247static void from_zval_write_aggregation(
const zval *
container,
256 do_from_zval_err(ctx,
"%s",
"expected an array here");
264 do_from_zval_err(ctx,
"No information on how to convert value "
265 "of key '%s'", descr->
name);
274 do_from_zval_err(ctx,
"The key '%s' is required", descr->
name);
279static void to_zval_read_aggregation(
const char *structure,
293 do_to_zval_err(ctx,
"No information on how to convert native "
294 "field into value for key '%s'", descr->
name);
336 if (!try_convert_to_string(&lzval)) {
343 zval_ptr_dtor_str(&lzval);
348 zval_ptr_dtor_str(&lzval);
354 do_from_zval_err(ctx,
"expected an integer, but got a non numeric "
355 "string (possibly from a converted object): '%s'",
Z_STRVAL_P(arr_value));
360 do_from_zval_err(ctx,
"%s",
"expected an integer, either of a PHP "
361 "integer type or of a convertible type");
374 lval = from_zval_integer_common(arr_value, ctx);
380 do_from_zval_err(ctx,
"%s",
"given PHP integer is out of bounds "
386 memcpy(field, &ival,
sizeof(ival));
388static void from_zval_write_uint32(
const zval *arr_value,
char *field,
ser_context *ctx)
393 lval = from_zval_integer_common(arr_value, ctx);
398 if (
sizeof(
zend_long) >
sizeof(uint32_t) && (lval < 0 || lval > 0xFFFFFFFF)) {
399 do_from_zval_err(ctx,
"%s",
"given PHP integer is out of bounds "
400 "for an unsigned 32-bit integer");
404 ival = (uint32_t)lval;
405 memcpy(field, &ival,
sizeof(ival));
407static void from_zval_write_net_uint16(
const zval *arr_value,
char *field,
ser_context *ctx)
412 lval = from_zval_integer_common(arr_value, ctx);
417 if (lval < 0 || lval > 0xFFFF) {
418 do_from_zval_err(ctx,
"%s",
"given PHP integer is out of bounds "
419 "for an unsigned 16-bit integer");
423 ival = htons((uint16_t)lval);
424 memcpy(field, &ival,
sizeof(ival));
426static void from_zval_write_sa_family(
const zval *arr_value,
char *field,
ser_context *ctx)
431 lval = from_zval_integer_common(arr_value, ctx);
436 if (lval < 0 || lval > (sa_family_t)-1) {
437 do_from_zval_err(ctx,
"%s",
"given PHP integer is out of bounds "
438 "for a sa_family_t value");
442 ival = (sa_family_t)lval;
443 memcpy(field, &ival,
sizeof(ival));
446#if defined(SO_PASSCRED) || defined(LOCAL_CREDS_PERSISTENT) || defined(LOCAL_CREDS)
447static void from_zval_write_pid_t(
const zval *arr_value,
char *field,
ser_context *ctx)
452 lval = from_zval_integer_common(arr_value, ctx);
457 if (lval < 0 || (pid_t)lval != lval) {
458 do_from_zval_err(ctx,
"%s",
"given PHP integer is out of bounds "
459 "for a pid_t value");
464 memcpy(field, &ival,
sizeof(ival));
466static void from_zval_write_uid_t(
const zval *arr_value,
char *field,
ser_context *ctx)
471 lval = from_zval_integer_common(arr_value, ctx);
477 if ((uid_t)-1 > (uid_t)0) {
478 if (
sizeof(
zend_long) >
sizeof(uid_t) && (lval < 0 || (uid_t)lval != lval)) {
479 do_from_zval_err(ctx,
"%s",
"given PHP integer is out of bounds "
480 "for a uid_t value");
484 if (
sizeof(
zend_long) >
sizeof(uid_t) && (uid_t)lval != lval) {
485 do_from_zval_err(ctx,
"%s",
"given PHP integer is out of bounds "
486 "for a uid_t value");
492 memcpy(field, &ival,
sizeof(ival));
533#if defined(SO_PASSCRED) || defined(LOCAL_CREDS_PERSISTENT) || defined(LOCAL_CREDS)
551static void from_zval_write_sin_addr(
const zval *zaddr_str,
char *inaddr,
ser_context *ctx)
554 struct sockaddr_in saddr = {0};
557 addr_str = zval_get_tmp_string((
zval *) zaddr_str, &tmp_addr_str);
560 memcpy(inaddr, &saddr.sin_addr,
sizeof saddr.sin_addr);
563 do_from_zval_err(ctx,
"could not resolve address '%s' to get an AF_INET "
567 zend_tmp_string_release(tmp_addr_str);
571 const struct in_addr *
addr = (
const struct in_addr *)
data;
579 do_to_zval_err(ctx,
"could not convert IPv4 address to string "
580 "(errno %d)",
errno);
587 {
"family",
sizeof(
"family"), 0,
offsetof(
struct sockaddr_in, sin_family), from_zval_write_sa_family, to_zval_read_sa_family},
588 {
"addr",
sizeof(
"addr"), 0,
offsetof(
struct sockaddr_in, sin_addr), from_zval_write_sin_addr, to_zval_read_sin_addr},
589 {
"port",
sizeof(
"port"), 0,
offsetof(
struct sockaddr_in, sin_port), from_zval_write_net_uint16, to_zval_read_net_uint16},
594 from_zval_write_aggregation(
container, sockaddr, descriptors_sockaddr_in, ctx);
598 to_zval_read_aggregation(
data,
zv, descriptors_sockaddr_in, ctx);
601static void from_zval_write_sin6_addr(
const zval *zaddr_str,
char *addr6,
ser_context *ctx)
604 struct sockaddr_in6 saddr6 = {0};
607 addr_str = zval_get_tmp_string((
zval *) zaddr_str, &tmp_addr_str);
610 memcpy(addr6, &saddr6.sin6_addr,
sizeof saddr6.sin6_addr);
613 do_from_zval_err(ctx,
"could not resolve address '%s' to get an AF_INET6 "
617 zend_tmp_string_release(tmp_addr_str);
621 const struct in6_addr *
addr = (
const struct in6_addr *)
data;
630 do_to_zval_err(ctx,
"could not convert IPv6 address to string "
631 "(errno %d)",
errno);
638 {
"family",
sizeof(
"family"), 0,
offsetof(
struct sockaddr_in6, sin6_family), from_zval_write_sa_family, to_zval_read_sa_family},
639 {
"addr",
sizeof(
"addr"), 0,
offsetof(
struct sockaddr_in6, sin6_addr), from_zval_write_sin6_addr, to_zval_read_sin6_addr},
640 {
"port",
sizeof(
"port"), 0,
offsetof(
struct sockaddr_in6, sin6_port), from_zval_write_net_uint16, to_zval_read_net_uint16},
641 {
"flowinfo",
sizeof(
"flowinfo"), 0,
offsetof(
struct sockaddr_in6, sin6_flowinfo), from_zval_write_uint32, to_zval_read_uint32},
642 {
"scope_id",
sizeof(
"scope_id"), 0,
offsetof(
struct sockaddr_in6, sin6_scope_id), from_zval_write_uint32, to_zval_read_uint32},
647 from_zval_write_aggregation(
container, sockaddr6, descriptors_sockaddr_in6, ctx);
651 to_zval_read_aggregation(
data,
zv, descriptors_sockaddr_in6, ctx);
654static void from_zval_write_sun_path(
const zval *path,
char *sockaddr_un_c,
ser_context *ctx)
657 struct sockaddr_un *saddr = (
struct sockaddr_un*)sockaddr_un_c;
659 path_str = zval_get_tmp_string((
zval *) path, &tmp_path_str);
665 do_from_zval_err(ctx,
"%s",
"the path is must not be empty");
666 zend_tmp_string_release(tmp_path_str);
669 if (
ZSTR_LEN(path_str) >=
sizeof(saddr->sun_path)) {
670 do_from_zval_err(ctx,
"the path is too long, the maximum permitted "
671 "length is %zd",
sizeof(saddr->sun_path) - 1);
672 zend_tmp_string_release(tmp_path_str);
677 saddr->sun_path[
ZSTR_LEN(path_str)] =
'\0';
679 zend_tmp_string_release(tmp_path_str);
682 struct sockaddr_un *saddr = (
struct sockaddr_un*)
data;
685 nul_pos = memchr(&saddr->sun_path,
'\0',
sizeof(saddr->sun_path));
686 if (nul_pos ==
NULL) {
687 do_to_zval_err(ctx,
"could not find a NUL in the path");
691 ZVAL_STRINGL(
zv, saddr->sun_path, nul_pos - (
char*)&saddr->sun_path);
694 {
"family",
sizeof(
"family"), 0,
offsetof(
struct sockaddr_un, sun_family), from_zval_write_sa_family, to_zval_read_sa_family},
695 {
"path",
sizeof(
"path"), 0, 0, from_zval_write_sun_path, to_zval_read_sun_path},
700 from_zval_write_aggregation(
container, sockaddr, descriptors_sockaddr_un, ctx);
704 to_zval_read_aggregation(
data,
zv, descriptors_sockaddr_un, ctx);
706static void from_zval_write_sockaddr_aux(
const zval *
container,
707 struct sockaddr **sockaddr_ptr,
715 *sockaddr_ptr =
NULL;
719 do_from_zval_err(ctx,
"%s",
"expected an array here");
727 const char *node =
"family";
737 family = ctx->
sock->type;
744 do_from_zval_err(ctx,
"the specified family (number %d) is not "
745 "supported on this socket", family);
748 *sockaddr_ptr = accounted_ecalloc(1,
sizeof(
struct sockaddr_in), ctx);
749 *sockaddr_len =
sizeof(
struct sockaddr_in);
751 from_zval_write_sockaddr_in(
container, (
char*)*sockaddr_ptr, ctx);
752 (*sockaddr_ptr)->sa_family =
AF_INET;
759 do_from_zval_err(ctx,
"the specified family (AF_INET6) is not "
760 "supported on this socket");
763 *sockaddr_ptr = accounted_ecalloc(1,
sizeof(
struct sockaddr_in6), ctx);
764 *sockaddr_len =
sizeof(
struct sockaddr_in6);
766 from_zval_write_sockaddr_in6(
container, (
char*)*sockaddr_ptr, ctx);
767 (*sockaddr_ptr)->sa_family =
AF_INET6;
774 do_from_zval_err(ctx,
"the specified family (AF_UNIX) is not "
775 "supported on this socket");
778 *sockaddr_ptr = accounted_ecalloc(1,
sizeof(
struct sockaddr_un), ctx);
780 struct sockaddr_un *sock_un = (
struct sockaddr_un*)*sockaddr_ptr;
782 from_zval_write_sockaddr_un(
container, (
char*)*sockaddr_ptr, ctx);
783 (*sockaddr_ptr)->sa_family =
AF_UNIX;
789 *sockaddr_len =
offsetof(
struct sockaddr_un, sun_path) +
790 (sock_un->sun_path[0] ==
'\0'
791 ? (1 +
strlen(&sock_un->sun_path[1]))
792 :
strlen(sock_un->sun_path));
794 *sockaddr_len =
sizeof(
struct sockaddr_un);
799 do_from_zval_err(ctx,
"%s",
"the only families currently supported are "
800 "AF_INET, AF_INET6 and AF_UNIX");
804static void to_zval_read_sockaddr_aux(
const char *sockaddr_c,
zval *
zv,
res_context *ctx)
806 const struct sockaddr *saddr = (
struct sockaddr *)sockaddr_c;
808 if (saddr->sa_family == 0) {
815 switch (saddr->sa_family) {
817 to_zval_read_sockaddr_in(sockaddr_c,
zv, ctx);
822 to_zval_read_sockaddr_in6(sockaddr_c,
zv, ctx);
827 to_zval_read_sockaddr_un(sockaddr_c,
zv, ctx);
831 do_to_zval_err(ctx,
"cannot read struct sockaddr with family %d; "
833 (
int)saddr->sa_family);
848static void from_zval_write_control(
const zval *arr,
855 struct cmsghdr *cmsghdr;
872 {
"data",
sizeof(
"data"), 0, 0, 0, 0},
876 from_zval_write_aggregation(arr, (
char *)&level, descriptor_level, ctx);
880 from_zval_write_aggregation(arr, (
char *)&
type, descriptor_type, ctx);
887 do_from_zval_err(ctx,
"cmsghdr with level %d and type %d not supported",
896 do_from_zval_err(ctx,
"cmsghdr should have a 'data' element here");
904 data_len = entry->
size;
906 req_space = CMSG_SPACE(data_len);
907 space_left = *control_len - *
offset;
910 if (space_left < req_space) {
911 *control_buf =
safe_erealloc(*control_buf, 2, req_space, *control_len);
912 *control_len += 2 * req_space;
914 memcpy(&alloc->
data, control_buf,
sizeof *control_buf);
917 cmsghdr = (
struct cmsghdr*)(((
char*)*control_buf) + *
offset);
918 cmsghdr->cmsg_level = level;
919 cmsghdr->cmsg_type =
type;
920 cmsghdr->cmsg_len = CMSG_LEN(data_len);
923 from_zval_write_aggregation(arr, (
char*)CMSG_DATA(cmsghdr), descriptor_data, ctx);
927static void from_zval_write_control_array(
const zval *arr,
char *msghdr_c,
ser_context *ctx)
929 char buf[
sizeof(
"element #4294967295")];
938 struct msghdr *
msg = (
struct msghdr*)msghdr_c;
941 do_from_zval_err(ctx,
"%s",
"expected an array here");
945 num_elems = zend_hash_num_elements(
Z_ARRVAL_P(arr));
946 if (num_elems == 0) {
951 control_buf = accounted_safe_ecalloc(num_elems, CMSG_SPACE(20), 0, ctx);
953 control_len = (size_t)num_elems * CMSG_SPACE(20);
961 if ((
size_t)
snprintf(
buf,
sizeof(
buf),
"element #%u", (
unsigned)i++) >=
sizeof(
buf)) {
962 memcpy(
buf,
"element",
sizeof(
"element"));
966 from_zval_write_control(elem, &control_buf, alloc, &control_len, &cur_offset, ctx);
971 msg->msg_control = control_buf;
972 msg->msg_controllen = cur_offset;
974static void to_zval_read_cmsg_data(
const char *cmsghdr_c,
zval *
zv,
res_context *ctx)
976 const struct cmsghdr *cmsg = (
const struct cmsghdr *)cmsghdr_c;
983 do_to_zval_err(ctx,
"cmsghdr with level %d and type %d not supported",
984 cmsg->cmsg_level, cmsg->cmsg_type);
987 if (CMSG_LEN(entry->
size) > cmsg->cmsg_len) {
988 do_to_zval_err(ctx,
"the cmsghdr structure is unexpectedly small; "
994 len = (size_t)cmsg->cmsg_len;
997 do_to_zval_err(ctx,
"%s",
"could not set parameter " KEY_CMSG_LEN);
1001 entry->
to_array((
const char *)CMSG_DATA(cmsg),
zv, ctx);
1005static void to_zval_read_control(
const char *cmsghdr_c,
zval *
zv,
res_context *ctx)
1011 {
"data",
sizeof(
"data"), 0, 0 , 0, to_zval_read_cmsg_data},
1016 to_zval_read_aggregation(cmsghdr_c,
zv, descriptors, ctx);
1018static void to_zval_read_control_array(
const char *msghdr_c,
zval *
zv,
res_context *ctx)
1020 struct msghdr *
msg = (
struct msghdr *)msghdr_c;
1021 struct cmsghdr *cmsg;
1022 char buf[
sizeof(
"element #4294967295")];
1028 for (cmsg = CMSG_FIRSTHDR(
msg);
1030 cmsg = CMSG_NXTHDR(
msg, cmsg)) {
1036 if ((
size_t)
snprintf(
buf,
sizeof(
buf),
"element #%u", (
unsigned)i++) >=
sizeof(
buf)) {
1037 memcpy(
buf,
"element",
sizeof(
"element"));
1041 to_zval_read_control((
const char *)cmsg, elem, ctx);
1048static void from_zval_write_name(
const zval *zname_arr,
char *msghdr_c,
ser_context *ctx)
1050 struct sockaddr *sockaddr;
1052 struct msghdr *msghdr = (
struct msghdr *)msghdr_c;
1054 from_zval_write_sockaddr_aux(zname_arr, &sockaddr, &sockaddr_len, ctx);
1056 msghdr->msg_name = sockaddr;
1057 msghdr->msg_namelen = sockaddr_len;
1059static void to_zval_read_name(
const char *sockaddr_p,
zval *
zv,
res_context *ctx)
1061 void *
name = (
void*)*(
void**)sockaddr_p;
1065 to_zval_read_sockaddr_aux(
name,
zv, ctx);
1068static void from_zval_write_msghdr_buffer_size(
const zval *elem,
char *msghdr_c,
ser_context *ctx)
1071 struct msghdr *msghdr = (
struct msghdr *)msghdr_c;
1073 lval = from_zval_integer_common(elem, ctx);
1079 do_from_zval_err(ctx,
"the buffer size must be between 1 and " ZEND_LONG_FMT "; "
1084 msghdr->msg_iovlen = 1;
1085 msghdr->msg_iov = accounted_emalloc(
sizeof(*msghdr->msg_iov) * 1, ctx);
1086 msghdr->msg_iov[0].iov_base = accounted_emalloc((
size_t)lval, ctx);
1087 msghdr->msg_iov[0].iov_len = (size_t)lval;
1089static void from_zval_write_iov_array_aux(
zval *elem,
unsigned i,
void **
args,
ser_context *ctx)
1094 str = zval_get_tmp_string(elem, &tmp_str);
1096 msg->msg_iov[i - 1].iov_base = accounted_emalloc(
ZSTR_LEN(str), ctx);
1100 zend_tmp_string_release(tmp_str);
1102static void from_zval_write_iov_array(
const zval *arr,
char *msghdr_c,
ser_context *ctx)
1105 struct msghdr *
msg = (
struct msghdr*)msghdr_c;
1108 do_from_zval_err(ctx,
"%s",
"expected an array here");
1112 num_elem = zend_hash_num_elements(
Z_ARRVAL_P(arr));
1113 if (num_elem == 0) {
1117 msg->msg_iov = accounted_safe_ecalloc(num_elem,
sizeof *
msg->msg_iov, 0, ctx);
1118 msg->msg_iovlen = (size_t)num_elem;
1120 from_array_iterate(arr, from_zval_write_iov_array_aux, (
void**)&
msg, ctx);
1122static void from_zval_write_controllen(
const zval *elem,
char *msghdr_c,
ser_context *ctx)
1124 struct msghdr *msghdr = (
struct msghdr *)msghdr_c;
1130 from_zval_write_uint32(elem, (
char*)&
len, ctx);
1135 do_from_zval_err(ctx,
"controllen cannot be 0");
1138 msghdr->msg_control = accounted_emalloc(
len, ctx);
1139 msghdr->msg_controllen =
len;
1144 {
"name",
sizeof(
"name"), 0, 0, from_zval_write_name, 0},
1145 {
"iov",
sizeof(
"iov"), 0, 0, from_zval_write_iov_array, 0},
1146 {
"control",
sizeof(
"control"), 0, 0, from_zval_write_control_array, 0},
1150 from_zval_write_aggregation(
container, msghdr_c, descriptors, ctx);
1169 {
"name",
sizeof(
"name"), 0, 0, from_zval_write_name, 0},
1170 {
"buffer_size",
sizeof(
"buffer_size"), 0, 0, from_zval_write_msghdr_buffer_size, 0},
1171 {
"controllen",
sizeof(
"controllen"), 1, 0, from_zval_write_controllen, 0},
1174 struct msghdr *msghdr = (
struct msghdr *)msghdr_c;
1175 const int falsev = 0,
1179 do_from_zval_err(ctx,
"could not add fill_sockaddr; this is a bug");
1183 from_zval_write_aggregation(
container, msghdr_c, descriptors, ctx);
1190 if (msghdr->msg_iovlen == 0) {
1191 msghdr->msg_iovlen = 1;
1192 msghdr->msg_iov = accounted_emalloc(
sizeof(*msghdr->msg_iov) * 1, ctx);
1193 msghdr->msg_iov[0].iov_base = accounted_emalloc((
size_t)
DEFAULT_BUFF_SIZE, ctx);
1200 const struct msghdr *msghdr = (
const struct msghdr *)msghdr_c;
1201 size_t iovlen = msghdr->msg_iovlen;
1202 ssize_t *recvmsg_ret,
1206 if (iovlen > UINT_MAX) {
1207 do_to_zval_err(ctx,
"unexpectedly large value for iov_len: %lu",
1208 (
unsigned long)iovlen);
1213 do_to_zval_err(ctx,
"recvmsg_ret not found in params. This is a bug");
1216 bytes_left = *recvmsg_ret;
1218 for (i = 0; bytes_left > 0 && i < (uint32_t)iovlen; i++) {
1220 size_t len =
MIN(msghdr->msg_iov[i].iov_len, (
size_t)bytes_left);
1227 add_next_index_zval(
zv, &elem);
1234 {
"name",
sizeof(
"name"), 0,
offsetof(
struct msghdr, msg_name), 0, to_zval_read_name},
1235 {
"control",
sizeof(
"control"), 0, 0, 0, to_zval_read_control_array},
1236 {
"iov",
sizeof(
"iov"), 0, 0, 0, to_zval_read_iov},
1243 to_zval_read_aggregation(msghdr_c,
zv, descriptors, ctx);
1246#if defined(IPV6_PKTINFO) && defined(HAVE_IPV6)
1248static void from_zval_write_ifindex(
const zval *
zv,
char *uinteger,
ser_context *ctx)
1254 do_from_zval_err(ctx,
"the interface index cannot be negative or "
1262 str = zval_get_tmp_string((
zval *)
zv, &tmp_str);
1264#ifdef HAVE_IF_NAMETOINDEX
1267 do_from_zval_err(ctx,
"no interface with name \"%s\" could be found",
ZSTR_VAL(str));
1269#elif defined(SIOCGIFINDEX)
1273 >=
sizeof(ifr.ifr_name)) {
1274 do_from_zval_err(ctx,
"the interface name \"%s\" is too large ",
ZSTR_VAL(str));
1275 }
else if (ioctl(ctx->
sock->bsd_socket, SIOCGIFINDEX, &ifr) < 0) {
1276 if (
errno == ENODEV) {
1277 do_from_zval_err(ctx,
"no interface with name \"%s\" could be "
1280 do_from_zval_err(ctx,
"error fetching interface index for "
1281 "interface with name \"%s\" (errno %d)",
1285 ret = (unsigned)ifr.ifr_ifindex;
1289 do_from_zval_err(ctx,
1290 "this platform does not support looking up an interface by "
1291 "name, an integer interface index must be supplied instead");
1294 zend_tmp_string_release(tmp_str);
1304 {
"addr",
sizeof(
"addr"), 1,
offsetof(
struct in6_pktinfo, ipi6_addr), from_zval_write_sin6_addr, to_zval_read_sin6_addr},
1305 {
"ifindex",
sizeof(
"ifindex"), 1,
offsetof(
struct in6_pktinfo, ipi6_ifindex), from_zval_write_ifindex, to_zval_read_unsigned},
1310 from_zval_write_aggregation(
container, in6_pktinfo_c, descriptors_in6_pktinfo, ctx);
1316 to_zval_read_aggregation(
data,
zv, descriptors_in6_pktinfo, ctx);
1321#if defined(SO_PASSCRED) || defined(LOCAL_CREDS_PERSISTENT) || defined(LOCAL_CREDS)
1323#if defined(LOCAL_CREDS_PERSISTENT)
1324 {
"pid",
sizeof(
"pid"), 1,
offsetof(
struct sockcred2, sc_pid), from_zval_write_pid_t, to_zval_read_pid_t},
1325 {
"uid",
sizeof(
"uid"), 1,
offsetof(
struct sockcred2, sc_euid), from_zval_write_uid_t, to_zval_read_uid_t},
1327 {
"gid",
sizeof(
"gid"), 1,
offsetof(
struct sockcred2, sc_egid), from_zval_write_uid_t, to_zval_read_uid_t},
1328#elif defined(LOCAL_CREDS)
1329 {
"pid",
sizeof(
"pid"), 1,
offsetof(
struct sockcred, sc_pid), from_zval_write_pid_t, to_zval_read_pid_t},
1330 {
"uid",
sizeof(
"uid"), 1,
offsetof(
struct sockcred, sc_euid), from_zval_write_uid_t, to_zval_read_uid_t},
1332 {
"gid",
sizeof(
"gid"), 1,
offsetof(
struct sockcred, sc_egid), from_zval_write_uid_t, to_zval_read_uid_t},
1333#elif defined(HAVE_STRUCT_CMSGCRED)
1334 {
"pid",
sizeof(
"pid"), 1,
offsetof(
struct cmsgcred, cmcred_pid), from_zval_write_pid_t, to_zval_read_pid_t},
1335 {
"uid",
sizeof(
"uid"), 1,
offsetof(
struct cmsgcred, cmcred_uid), from_zval_write_uid_t, to_zval_read_uid_t},
1337 {
"gid",
sizeof(
"gid"), 1,
offsetof(
struct cmsgcred, cmcred_gid), from_zval_write_uid_t, to_zval_read_uid_t},
1338#elif defined(SO_PASSCRED)
1339 {
"pid",
sizeof(
"pid"), 1,
offsetof(
struct ucred, pid), from_zval_write_pid_t, to_zval_read_pid_t},
1340 {
"uid",
sizeof(
"uid"), 1,
offsetof(
struct ucred, uid), from_zval_write_uid_t, to_zval_read_uid_t},
1342 {
"gid",
sizeof(
"gid"), 1,
offsetof(
struct ucred, gid), from_zval_write_uid_t, to_zval_read_uid_t},
1348 from_zval_write_aggregation(
container, ucred_c, descriptors_ucred, ctx);
1354 to_zval_read_aggregation(
data,
zv, descriptors_ucred, ctx);
1365 do_from_zval_err(ctx,
"%s",
"expected an array here");
1369 num_elems = zend_hash_num_elements(
Z_ARRVAL_P(arr));
1370 if (num_elems == 0) {
1371 do_from_zval_err(ctx,
"%s",
"expected at least one element in this array");
1375 return zend_hash_num_elements(
Z_ARRVAL_P(arr)) *
sizeof(int);
1377static void from_zval_write_fd_array_aux(
zval *elem,
unsigned i,
void **
args,
ser_context *ctx)
1379 int *iarr =
args[0];
1382 php_socket *sock = Z_SOCKET_P(elem);
1384 do_from_zval_err(ctx,
"socket is already closed");
1388 iarr[i] = sock->bsd_socket;
1396 if (stream ==
NULL) {
1397 do_from_zval_err(ctx,
"resource is not a stream");
1402 do_from_zval_err(ctx,
"cast stream to file descriptor failed");
1406 do_from_zval_err(ctx,
"expected a Socket object or a stream resource");
1409void from_zval_write_fd_array(
const zval *arr,
char *int_arr,
ser_context *ctx)
1412 do_from_zval_err(ctx,
"%s",
"expected an array here");
1416 from_array_iterate(arr, &from_zval_write_fd_array_aux, (
void**)&int_arr, ctx);
1423 struct cmsghdr *dummy_cmsg = 0;
1426 data_offset = (
unsigned char *)CMSG_DATA(dummy_cmsg)
1427 - (
unsigned char *)dummy_cmsg;
1430 do_to_zval_err(ctx,
"could not get value of parameter " KEY_CMSG_LEN);
1434 if (*cmsg_len < data_offset) {
1435 do_to_zval_err(ctx,
"length of cmsg is smaller than its data member "
1439 num_elems = (*cmsg_len - data_offset) /
sizeof(
int);
1443 for (i = 0; i < num_elems; i++) {
1446 struct stat statbuf;
1451 if (
fstat(
fd, &statbuf) == -1) {
1452 do_to_zval_err(ctx,
"error creating resource for received file "
1453 "descriptor %d: fstat() call failed with errno %d",
fd,
errno);
1456 if (S_ISSOCK(statbuf.st_mode)) {
1458 php_socket *sock = Z_SOCKET_P(&elem);
1466 add_next_index_zval(
zv, &elem);
1472static void free_from_zval_allocation(
void *alloc_ptr_ptr)
1474 efree(*(
void**)alloc_ptr_ptr);
1480 const char *top_name,
1487 *allocations =
NULL;
1489 if (
err->has_error) {
1493 memset(&ctx, 0,
sizeof(ctx));
1499 structure =
ecalloc(1, struct_size);
1512 *allocations =
emalloc(
sizeof **allocations);
1523 const char *top_name,
1524 const struct key_value *key_value_pairs,
1530 if (
err->has_error) {
1534 memset(&ctx, 0,
sizeof(ctx));
1539 for (kv = key_value_pairs; kv->
key !=
NULL; kv++) {
1545 reader(structure,
zv, &ctx);
printf(string $format, mixed ... $values)
assert(mixed $assertion, Throwable|string|null $description=null)
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, struct err_s *err)
#define KEY_FILL_SOCKADDR
void to_zval_read_msghdr(const char *msghdr_c, zval *zv, res_context *ctx)
#define MAX_USER_BUFF_SIZE
void from_zval_write_msghdr_recv(const zval *container, char *msghdr_c, ser_context *ctx)
void allocations_dispose(zend_llist **allocations)
const struct key_value empty_key_value_list[]
#define DEFAULT_BUFF_SIZE
void from_zval_write_int(const zval *arr_value, char *field, ser_context *ctx)
void err_msg_dispose(struct err_s *err)
void from_zval_write_msghdr_send(const zval *container, char *msghdr_c, ser_context *ctx)
void to_zval_read_int(const char *data, zval *zv, res_context *ctx)
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, zval *zv)
struct _ser_context ser_context
struct _res_context res_context
void to_zval_read_field(const char *data, zval *zv, res_context *ctx)
void from_zval_write_field(const zval *arr_value, char *field, ser_context *ctx)
zend_class_entry * socket_ce
bool socket_import_file_descriptor(PHP_SOCKET socket, php_socket *retsock)
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str))
unsigned const char * pos
#define offsetof(STRUCTURE, FIELD)
unsigned char key[REFLECTION_KEY_LEN]
#define php_stream_fopen_from_fd(fd, mode, persistent_id)
#define php_stream_cast(stream, as, ret, show_err)
struct _php_stream php_stream
#define php_stream_to_zval(stream, zval)
PHPAPI int php_file_le_pstream(void)
PHPAPI int php_file_le_stream(void)
ancillary_reg_entry * get_ancillary_reg_entry(int cmsg_level, int msg_type)
int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock)
int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock)
zend_llist_element * tail
from_zval_write_field * from_array
calculate_req_space * calc_space
to_zval_read_field * to_array
from_zval_write_field * from_zval
to_zval_read_field * to_zval
#define IS_INVALID_SOCKET(a)
ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type)
#define array_init_size(arg, size)
#define ZVAL_STRINGL(z, s, l)
#define safe_erealloc(ptr, nmemb, size, offset)
#define ecalloc(nmemb, size)
#define safe_emalloc(nmemb, size, offset)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
ZEND_API zval *ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData)
ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char *str, size_t len)
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
#define ZEND_HASH_FOREACH_END()
#define ZEND_HASH_FOREACH_VAL(ht, _val)
ZEND_API void * zend_fetch_resource2_ex(zval *res, const char *resource_type_name, int resource_type1, int resource_type2)
ZEND_API void zend_llist_destroy(zend_llist *l)
ZEND_API void zend_llist_add_element(zend_llist *l, const void *element)
ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent)
ZEND_API void * zend_llist_get_next_ex(zend_llist *l, zend_llist_position *pos)
ZEND_API void zend_llist_remove_tail(zend_llist *l)
ZEND_API void * zend_llist_get_first_ex(zend_llist *l, zend_llist_position *pos)
struct _zend_llist_element zend_llist_element
zend_llist_element * zend_llist_position
struct _zend_llist zend_llist
struct _zend_string zend_string
ZEND_API void ZEND_FASTCALL convert_to_long(zval *op)
#define ZEND_ATTRIBUTE_FORMAT(type, idx, first)
#define UNEXPECTED(condition)
#define Z_STRVAL_P(zval_p)
#define Z_ISUNDEF_P(zval_p)
#define Z_ARRVAL_P(zval_p)
struct _zend_array HashTable
#define Z_STRLEN_P(zval_p)
#define Z_OBJCE_P(zval_p)
#define ZVAL_NEW_STR(z, s)
#define ZVAL_DOUBLE(z, d)
ZEND_API void zval_ptr_dtor(zval *zval_ptr)