root/ext/sockets/conversions.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. param_get_bool
  2. accounted_emalloc
  3. accounted_ecalloc
  4. accounted_safe_ecalloc
  5. do_from_to_zval_err
  6. ZEND_ATTRIBUTE_FORMAT
  7. ZEND_ATTRIBUTE_FORMAT
  8. err_msg_dispose
  9. allocations_dispose
  10. from_array_iterate
  11. from_zval_write_aggregation
  12. to_zval_read_aggregation
  13. from_zval_integer_common
  14. from_zval_write_int
  15. from_zval_write_uint32
  16. from_zval_write_net_uint16
  17. from_zval_write_sa_family
  18. from_zval_write_pid_t
  19. from_zval_write_uid_t
  20. to_zval_read_int
  21. to_zval_read_unsigned
  22. to_zval_read_net_uint16
  23. to_zval_read_uint32
  24. to_zval_read_sa_family
  25. to_zval_read_pid_t
  26. to_zval_read_uid_t
  27. from_zval_write_sin_addr
  28. to_zval_read_sin_addr
  29. from_zval_write_sockaddr_in
  30. to_zval_read_sockaddr_in
  31. from_zval_write_sin6_addr
  32. to_zval_read_sin6_addr
  33. from_zval_write_sockaddr_in6
  34. to_zval_read_sockaddr_in6
  35. from_zval_write_sun_path
  36. to_zval_read_sun_path
  37. from_zval_write_sockaddr_un
  38. to_zval_read_sockaddr_un
  39. from_zval_write_sockaddr_aux
  40. to_zval_read_sockaddr_aux
  41. from_zval_write_control
  42. from_zval_write_control_array
  43. to_zval_read_cmsg_data
  44. to_zval_read_control
  45. to_zval_read_control_array
  46. from_zval_write_name
  47. to_zval_read_name
  48. from_zval_write_msghdr_buffer_size
  49. from_zval_write_iov_array_aux
  50. from_zval_write_iov_array
  51. from_zval_write_controllen
  52. from_zval_write_msghdr_send
  53. from_zval_write_msghdr_recv
  54. to_zval_read_iov
  55. to_zval_read_msghdr
  56. from_zval_write_ifindex
  57. from_zval_write_in6_pktinfo
  58. to_zval_read_in6_pktinfo
  59. from_zval_write_ucred
  60. to_zval_read_ucred
  61. calculate_scm_rights_space
  62. from_zval_write_fd_array_aux
  63. from_zval_write_fd_array
  64. to_zval_read_fd_array
  65. free_from_zval_allocation
  66. from_zval_run_conversions
  67. to_zval_run_conversions

   1 #include "sockaddr_conv.h"
   2 #include "conversions.h"
   3 #include "sendrecvmsg.h" /* for ancillary registry */
   4 #ifdef PHP_WIN32
   5 # include "windows_common.h"
   6 #endif
   7 
   8 #include <Zend/zend_llist.h>
   9 #include <ext/standard/php_smart_str.h>
  10 
  11 #ifndef PHP_WIN32
  12 # include <sys/types.h>
  13 # include <sys/socket.h>
  14 # include <arpa/inet.h>
  15 # include <netinet/in.h>
  16 # include <sys/un.h>
  17 # include <sys/ioctl.h>
  18 # include <net/if.h>
  19 #else
  20 # include <win32/php_stdint.h>
  21 #endif
  22 
  23 #include <limits.h>
  24 #include <stdarg.h>
  25 #include <stddef.h>
  26 
  27 #ifdef PHP_WIN32
  28 typedef unsigned short sa_family_t;
  29 # define msghdr                 _WSAMSG
  30 /*
  31 struct _WSAMSG {
  32     LPSOCKADDR       name;                              //void *msg_name
  33     INT              namelen;                   //socklen_t msg_namelen
  34     LPWSABUF         lpBuffers;                 //struct iovec *msg_iov
  35     ULONG            dwBufferCount;             //size_t msg_iovlen
  36     WSABUF           Control;                   //void *msg_control, size_t msg_controllen
  37     DWORD            dwFlags;                   //int msg_flags
  38 }
  39 struct __WSABUF {
  40   u_long                        len;                            //size_t iov_len (2nd member)
  41   char FAR                      *buf;                           //void *iov_base (1st member)
  42 }
  43 struct _WSACMSGHDR {
  44   UINT        cmsg_len;                                 //socklen_t cmsg_len
  45   INT         cmsg_level;                               //int       cmsg_level
  46   INT         cmsg_type;                                //int       cmsg_type;
  47   followed by UCHAR cmsg_data[]
  48 }
  49 */
  50 # define msg_name               name
  51 # define msg_namelen    namelen
  52 # define msg_iov                lpBuffers
  53 # define msg_iovlen             dwBufferCount
  54 # define msg_control    Control.buf
  55 # define msg_controllen Control.len
  56 # define msg_flags              dwFlags
  57 # define iov_base               buf
  58 # define iov_len                len
  59 
  60 # define cmsghdr                _WSACMSGHDR
  61 # ifdef CMSG_DATA
  62 #  undef CMSG_DATA
  63 # endif
  64 # define CMSG_DATA              WSA_CMSG_DATA
  65 #endif
  66 
  67 #define MAX_USER_BUFF_SIZE ((size_t)(100*1024*1024))
  68 #define DEFAULT_BUFF_SIZE 8192
  69 
  70 struct _ser_context {
  71         HashTable               params; /* stores pointers; has to be first */
  72         struct err_s    err;
  73         zend_llist              keys,
  74         /* common part to res_context ends here */
  75                                         allocations;
  76         php_socket              *sock;
  77 };
  78 struct _res_context {
  79         HashTable               params; /* stores pointers; has to be first */
  80         struct err_s    err;
  81         zend_llist              keys;
  82 };
  83 
  84 typedef struct {
  85         /* zval info */
  86         const char *name;
  87         unsigned name_size;
  88         int required;
  89 
  90         /* structure info */
  91         size_t field_offset; /* 0 to pass full structure, e.g. when more than
  92                                                         one field is to be changed; in that case the
  93                                                         callbacks need to know the name of the fields */
  94 
  95         /* callbacks */
  96         from_zval_write_field *from_zval;
  97         to_zval_read_field *to_zval;
  98 } field_descriptor;
  99 
 100 #define KEY_FILL_SOCKADDR "fill_sockaddr"
 101 #define KEY_RECVMSG_RET   "recvmsg_ret"
 102 #define KEY_CMSG_LEN      "cmsg_len"
 103 
 104 const struct key_value empty_key_value_list[] = {{0}};
 105 
 106 /* PARAMETERS */
 107 static int param_get_bool(void *ctx, const char *key, int def)
 108 {
 109         int **elem;
 110         if (zend_hash_find(ctx, key, strlen(key) + 1, (void**)&elem) == SUCCESS) {
 111                 return **elem;
 112         } else {
 113                 return def;
 114         }
 115 }
 116 
 117 /* MEMORY */
 118 static inline void *accounted_emalloc(size_t alloc_size, ser_context *ctx)
 119 {
 120         void *ret = emalloc(alloc_size);
 121         zend_llist_add_element(&ctx->allocations, &ret);
 122         return ret;
 123 }
 124 static inline void *accounted_ecalloc(size_t nmemb, size_t alloc_size, ser_context *ctx)
 125 {
 126         void *ret = ecalloc(nmemb, alloc_size);
 127         zend_llist_add_element(&ctx->allocations, &ret);
 128         return ret;
 129 }
 130 static inline void *accounted_safe_ecalloc(size_t nmemb, size_t alloc_size, size_t offset, ser_context *ctx)
 131 {
 132         void *ret = safe_emalloc(nmemb, alloc_size, offset);
 133         memset(ret, '\0', nmemb * alloc_size + offset);
 134         zend_llist_add_element(&ctx->allocations, &ret);
 135         return ret;
 136 }
 137 
 138 /* ERRORS */
 139 static void do_from_to_zval_err(struct err_s *err,
 140                                                                 zend_llist *keys,
 141                                                                 const char *what_conv,
 142                                                                 const char *fmt,
 143                                                                 va_list ap)
 144 {
 145         smart_str                       path = {0};
 146         const char                      **node;
 147         char                            *user_msg;
 148         int                                     user_msg_size;
 149         zend_llist_position     pos;
 150 
 151         if (err->has_error) {
 152                 return;
 153         }
 154 
 155         for (node = zend_llist_get_first_ex(keys, &pos);
 156                         node != NULL;
 157                         node = zend_llist_get_next_ex(keys, &pos)) {
 158                 smart_str_appends(&path, *node);
 159                 smart_str_appends(&path, " > ");
 160         }
 161 
 162         if (path.len > 3) {
 163                 path.len -= 3;
 164         }
 165         smart_str_0(&path);
 166 
 167         user_msg_size = vspprintf(&user_msg, 0, fmt, ap);
 168 
 169         err->has_error = 1;
 170         err->level = E_WARNING;
 171         spprintf(&err->msg, 0, "error converting %s data (path: %s): %.*s",
 172                         what_conv,
 173                         path.c && path.c != '\0' ? path.c : "unavailable",
 174                         user_msg_size, user_msg);
 175         err->should_free = 1;
 176 
 177         efree(user_msg);
 178         smart_str_free_ex(&path, 0);
 179 }
 180 ZEND_ATTRIBUTE_FORMAT(printf, 2 ,3)
 181 static void do_from_zval_err(ser_context *ctx, const char *fmt, ...)
 182 {
 183         va_list ap;
 184 
 185         va_start(ap, fmt);
 186         do_from_to_zval_err(&ctx->err, &ctx->keys, "user", fmt, ap);
 187         va_end(ap);
 188 }
 189 ZEND_ATTRIBUTE_FORMAT(printf, 2 ,3)
 190 static void do_to_zval_err(res_context *ctx, const char *fmt, ...)
 191 {
 192         va_list ap;
 193 
 194         va_start(ap, fmt);
 195         do_from_to_zval_err(&ctx->err, &ctx->keys, "native", fmt, ap);
 196         va_end(ap);
 197 }
 198 
 199 void err_msg_dispose(struct err_s *err TSRMLS_DC)
 200 {
 201         if (err->msg != NULL) {
 202                 php_error_docref0(NULL TSRMLS_CC, err->level, "%s", err->msg);
 203                 if (err->should_free) {
 204                         efree(err->msg);
 205                 }
 206         }
 207 }
 208 void allocations_dispose(zend_llist **allocations)
 209 {
 210         zend_llist_destroy(*allocations);
 211         efree(*allocations);
 212         *allocations = NULL;
 213 }
 214 
 215 static unsigned from_array_iterate(const zval *arr,
 216                                                                    void (*func)(zval **elem, unsigned i, void **args, ser_context *ctx),
 217                                                                    void **args,
 218                                                                    ser_context *ctx)
 219 {
 220         HashPosition    pos;
 221         unsigned                i;
 222         zval                    **elem;
 223         char                    buf[sizeof("element #4294967295")];
 224         char                    *bufp = buf;
 225 
 226         /* Note i starts at 1, not 0! */
 227     for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos), i = 1;
 228                         !ctx->err.has_error
 229                         && zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **)&elem, &pos) == SUCCESS;
 230                         zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos), i++) {
 231                 if (snprintf(buf, sizeof(buf), "element #%u", i) >= sizeof(buf)) {
 232                         memcpy(buf, "element", sizeof("element"));
 233                 }
 234                 zend_llist_add_element(&ctx->keys, &bufp);
 235 
 236                 func(elem, i, args, ctx);
 237 
 238                 zend_llist_remove_tail(&ctx->keys);
 239     }
 240 
 241     return i -1;
 242 }
 243 
 244 /* Generic Aggregated conversions */
 245 static void from_zval_write_aggregation(const zval *container,
 246                                                                                 char *structure,
 247                                                                                 const field_descriptor *descriptors,
 248                                                                                 ser_context *ctx)
 249 {
 250         const field_descriptor  *descr;
 251         zval                                    **elem;
 252 
 253         if (Z_TYPE_P(container) != IS_ARRAY) {
 254                 do_from_zval_err(ctx, "%s", "expected an array here");
 255         }
 256 
 257         for (descr = descriptors; descr->name != NULL && !ctx->err.has_error; descr++) {
 258                 if (zend_hash_find(Z_ARRVAL_P(container),
 259                                 descr->name, descr->name_size, (void**)&elem) == SUCCESS) {
 260 
 261                         if (descr->from_zval == NULL) {
 262                                 do_from_zval_err(ctx, "No information on how to convert value "
 263                                                 "of key '%s'", descr->name);
 264                                 break;
 265                         }
 266 
 267                         zend_llist_add_element(&ctx->keys, (void*)&descr->name);
 268                         descr->from_zval(*elem, ((char*)structure) + descr->field_offset, ctx);
 269                         zend_llist_remove_tail(&ctx->keys);
 270 
 271                 } else if (descr->required) {
 272                         do_from_zval_err(ctx, "The key '%s' is required", descr->name);
 273                         break;
 274                 }
 275         }
 276 }
 277 static void to_zval_read_aggregation(const char *structure,
 278                                                                          zval *zarr, /* initialized array */
 279                                                                          const field_descriptor *descriptors,
 280                                                                          res_context *ctx)
 281 {
 282         const field_descriptor  *descr;
 283 
 284         assert(Z_TYPE_P(zarr) == IS_ARRAY);
 285         assert(Z_ARRVAL_P(zarr) != NULL);
 286 
 287         for (descr = descriptors; descr->name != NULL && !ctx->err.has_error; descr++) {
 288                 zval *new_zv;
 289 
 290                 if (descr->to_zval == NULL) {
 291                         do_to_zval_err(ctx, "No information on how to convert native "
 292                                         "field into value for key '%s'", descr->name);
 293                         break;
 294                 }
 295 
 296                 ALLOC_INIT_ZVAL(new_zv);
 297                 add_assoc_zval_ex(zarr, descr->name, descr->name_size, new_zv);
 298 
 299                 zend_llist_add_element(&ctx->keys, (void*)&descr->name);
 300                 descr->to_zval(structure + descr->field_offset, new_zv, ctx);
 301                 zend_llist_remove_tail(&ctx->keys);
 302         }
 303 }
 304 
 305 /* CONVERSIONS for integers */
 306 static long from_zval_integer_common(const zval *arr_value, ser_context *ctx)
 307 {
 308         long ret = 0;
 309         zval lzval = zval_used_for_init;
 310 
 311         if (Z_TYPE_P(arr_value) != IS_LONG) {
 312                 ZVAL_COPY_VALUE(&lzval, arr_value);
 313                 zval_copy_ctor(&lzval);
 314                 arr_value = &lzval;
 315         }
 316 
 317         switch (Z_TYPE_P(arr_value)) {
 318         case IS_LONG:
 319 long_case:
 320                 ret = Z_LVAL_P(arr_value);
 321                 break;
 322 
 323         /* if not long we're operating on lzval */
 324         case IS_DOUBLE:
 325 double_case:
 326                 convert_to_long(&lzval);
 327                 goto long_case;
 328 
 329         case IS_OBJECT:
 330         case IS_STRING: {
 331                 long lval;
 332                 double dval;
 333 
 334                 convert_to_string(&lzval);
 335 
 336                 switch (is_numeric_string(Z_STRVAL(lzval), Z_STRLEN(lzval), &lval, &dval, 0)) {
 337                 case IS_DOUBLE:
 338                         zval_dtor(&lzval);
 339                         Z_TYPE(lzval) = IS_DOUBLE;
 340                         Z_DVAL(lzval) = dval;
 341                         goto double_case;
 342 
 343                 case IS_LONG:
 344                         zval_dtor(&lzval);
 345                         Z_TYPE(lzval) = IS_LONG;
 346                         Z_LVAL(lzval) = lval;
 347                         goto long_case;
 348                 }
 349 
 350                 /* if we get here, we don't have a numeric string */
 351                 do_from_zval_err(ctx, "expected an integer, but got a non numeric "
 352                                 "string (possibly from a converted object): '%s'", Z_STRVAL_P(arr_value));
 353                 break;
 354         }
 355 
 356         default:
 357                 do_from_zval_err(ctx, "%s", "expected an integer, either of a PHP "
 358                                 "integer type or of a convertible type");
 359                 break;
 360         }
 361 
 362         zval_dtor(&lzval);
 363 
 364         return ret;
 365 }
 366 void from_zval_write_int(const zval *arr_value, char *field, ser_context *ctx)
 367 {
 368         long lval;
 369         int ival;
 370 
 371         lval = from_zval_integer_common(arr_value, ctx);
 372         if (ctx->err.has_error) {
 373                 return;
 374         }
 375 
 376         if (lval > INT_MAX || lval < INT_MIN) {
 377                 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
 378                                 "for a native int");
 379                 return;
 380         }
 381 
 382         ival = (int)lval;
 383         memcpy(field, &ival, sizeof(ival));
 384 }
 385 static void from_zval_write_uint32(const zval *arr_value, char *field, ser_context *ctx)
 386 {
 387         long lval;
 388         uint32_t ival;
 389 
 390         lval = from_zval_integer_common(arr_value, ctx);
 391         if (ctx->err.has_error) {
 392                 return;
 393         }
 394 
 395         if (sizeof(long) > sizeof(uint32_t) && (lval < 0 || lval > 0xFFFFFFFF)) {
 396                 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
 397                                 "for an unsigned 32-bit integer");
 398                 return;
 399         }
 400 
 401         ival = (uint32_t)lval;
 402         memcpy(field, &ival, sizeof(ival));
 403 }
 404 static void from_zval_write_net_uint16(const zval *arr_value, char *field, ser_context *ctx)
 405 {
 406         long lval;
 407         uint16_t ival;
 408 
 409         lval = from_zval_integer_common(arr_value, ctx);
 410         if (ctx->err.has_error) {
 411                 return;
 412         }
 413 
 414         if (lval < 0 || lval > 0xFFFF) {
 415                 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
 416                                 "for an unsigned 16-bit integer");
 417                 return;
 418         }
 419 
 420         ival = htons((uint16_t)lval);
 421         memcpy(field, &ival, sizeof(ival));
 422 }
 423 static void from_zval_write_sa_family(const zval *arr_value, char *field, ser_context *ctx)
 424 {
 425         long lval;
 426         sa_family_t ival;
 427 
 428         lval = from_zval_integer_common(arr_value, ctx);
 429         if (ctx->err.has_error) {
 430                 return;
 431         }
 432 
 433         if (lval < 0 || lval > (sa_family_t)-1) { /* sa_family_t is unsigned */
 434                 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
 435                                 "for a sa_family_t value");
 436                 return;
 437         }
 438 
 439         ival = (sa_family_t)lval;
 440         memcpy(field, &ival, sizeof(ival));
 441 }
 442 static void from_zval_write_pid_t(const zval *arr_value, char *field, ser_context *ctx)
 443 {
 444         long lval;
 445         pid_t ival;
 446 
 447         lval = from_zval_integer_common(arr_value, ctx);
 448         if (ctx->err.has_error) {
 449                 return;
 450         }
 451 
 452         if (lval < 0 || (pid_t)lval != lval) { /* pid_t is signed */
 453                 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
 454                                 "for a pid_t value");
 455                 return;
 456         }
 457 
 458         ival = (pid_t)lval;
 459         memcpy(field, &ival, sizeof(ival));
 460 }
 461 static void from_zval_write_uid_t(const zval *arr_value, char *field, ser_context *ctx)
 462 {
 463         long lval;
 464         uid_t ival;
 465 
 466         lval = from_zval_integer_common(arr_value, ctx);
 467         if (ctx->err.has_error) {
 468                 return;
 469         }
 470 
 471         /* uid_t can be signed or unsigned (generally unsigned) */
 472         if ((uid_t)-1 > (uid_t)0) {
 473                 if (sizeof(long) > sizeof(uid_t) && (lval < 0 || (uid_t)lval != lval)) {
 474                         do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
 475                                         "for a uid_t value");
 476                         return;
 477                 }
 478         } else {
 479                 if (sizeof(long) > sizeof(uid_t) && (uid_t)lval != lval) {
 480                         do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
 481                                         "for a uid_t value");
 482                         return;
 483                 }
 484         }
 485 
 486         ival = (uid_t)lval;
 487         memcpy(field, &ival, sizeof(ival));
 488 }
 489 
 490 void to_zval_read_int(const char *data, zval *zv, res_context *ctx)
 491 {
 492         int ival;
 493         memcpy(&ival, data, sizeof(ival));
 494 
 495         ZVAL_LONG(zv, (long)ival);
 496 }
 497 static void to_zval_read_unsigned(const char *data, zval *zv, res_context *ctx)
 498 {
 499         unsigned ival;
 500         memcpy(&ival, data, sizeof(ival));
 501 
 502         ZVAL_LONG(zv, (long)ival);
 503 }
 504 static void to_zval_read_net_uint16(const char *data, zval *zv, res_context *ctx)
 505 {
 506         uint16_t ival;
 507         memcpy(&ival, data, sizeof(ival));
 508 
 509         ZVAL_LONG(zv, (long)ntohs(ival));
 510 }
 511 static void to_zval_read_uint32(const char *data, zval *zv, res_context *ctx)
 512 {
 513         uint32_t ival;
 514         memcpy(&ival, data, sizeof(ival));
 515 
 516         ZVAL_LONG(zv, (long)ival);
 517 }
 518 static void to_zval_read_sa_family(const char *data, zval *zv, res_context *ctx)
 519 {
 520         sa_family_t ival;
 521         memcpy(&ival, data, sizeof(ival));
 522 
 523         ZVAL_LONG(zv, (long)ival);
 524 }
 525 static void to_zval_read_pid_t(const char *data, zval *zv, res_context *ctx)
 526 {
 527         pid_t ival;
 528         memcpy(&ival, data, sizeof(ival));
 529 
 530         ZVAL_LONG(zv, (long)ival);
 531 }
 532 static void to_zval_read_uid_t(const char *data, zval *zv, res_context *ctx)
 533 {
 534         uid_t ival;
 535         memcpy(&ival, data, sizeof(ival));
 536 
 537         ZVAL_LONG(zv, (long)ival);
 538 }
 539 
 540 /* CONVERSIONS for sockaddr */
 541 static void from_zval_write_sin_addr(const zval *zaddr_str, char *inaddr, ser_context *ctx)
 542 {
 543         int                                     res;
 544         struct sockaddr_in      saddr = {0};
 545         zval                            lzval = zval_used_for_init;
 546         TSRMLS_FETCH();
 547 
 548         if (Z_TYPE_P(zaddr_str) != IS_STRING) {
 549                 ZVAL_COPY_VALUE(&lzval, zaddr_str);
 550                 zval_copy_ctor(&lzval);
 551                 convert_to_string(&lzval);
 552                 zaddr_str = &lzval;
 553         }
 554 
 555         res = php_set_inet_addr(&saddr, Z_STRVAL_P(zaddr_str), ctx->sock TSRMLS_CC);
 556         if (res) {
 557                 memcpy(inaddr, &saddr.sin_addr, sizeof saddr.sin_addr);
 558         } else {
 559                 /* error already emitted, but let's emit another more relevant */
 560                 do_from_zval_err(ctx, "could not resolve address '%s' to get an AF_INET "
 561                                 "address", Z_STRVAL_P(zaddr_str));
 562         }
 563 
 564         zval_dtor(&lzval);
 565 }
 566 static void to_zval_read_sin_addr(const char *data, zval *zv, res_context *ctx)
 567 {
 568         const struct in_addr *addr = (const struct in_addr *)data;
 569         socklen_t size = INET_ADDRSTRLEN;
 570 
 571         Z_TYPE_P(zv) = IS_STRING;
 572         Z_STRVAL_P(zv) = ecalloc(1, size);
 573         Z_STRLEN_P(zv) = 0;
 574 
 575         if (inet_ntop(AF_INET, addr, Z_STRVAL_P(zv), size) == NULL) {
 576                 do_to_zval_err(ctx, "could not convert IPv4 address to string "
 577                                 "(errno %d)", errno);
 578                 return;
 579         }
 580 
 581         Z_STRLEN_P(zv) = strlen(Z_STRVAL_P(zv));
 582 }
 583 static const field_descriptor descriptors_sockaddr_in[] = {
 584                 {"family", sizeof("family"), 0, offsetof(struct sockaddr_in, sin_family), from_zval_write_sa_family, to_zval_read_sa_family},
 585                 {"addr", sizeof("addr"), 0, offsetof(struct sockaddr_in, sin_addr), from_zval_write_sin_addr, to_zval_read_sin_addr},
 586                 {"port", sizeof("port"), 0, offsetof(struct sockaddr_in, sin_port), from_zval_write_net_uint16, to_zval_read_net_uint16},
 587                 {0}
 588 };
 589 static void from_zval_write_sockaddr_in(const zval *container, char *sockaddr, ser_context *ctx)
 590 {
 591         from_zval_write_aggregation(container, sockaddr, descriptors_sockaddr_in, ctx);
 592 }
 593 static void to_zval_read_sockaddr_in(const char *data, zval *zv, res_context *ctx)
 594 {
 595         to_zval_read_aggregation(data, zv, descriptors_sockaddr_in, ctx);
 596 }
 597 #if HAVE_IPV6
 598 static void from_zval_write_sin6_addr(const zval *zaddr_str, char *addr6, ser_context *ctx)
 599 {
 600         int                                     res;
 601         struct sockaddr_in6     saddr6 = {0};
 602         zval                            lzval = zval_used_for_init;
 603         TSRMLS_FETCH();
 604 
 605         if (Z_TYPE_P(zaddr_str) != IS_STRING) {
 606                 ZVAL_COPY_VALUE(&lzval, zaddr_str);
 607                 zval_copy_ctor(&lzval);
 608                 convert_to_string(&lzval);
 609                 zaddr_str = &lzval;
 610         }
 611 
 612         res = php_set_inet6_addr(&saddr6,
 613                         Z_STRVAL_P(zaddr_str), ctx->sock TSRMLS_CC);
 614         if (res) {
 615                 memcpy(addr6, &saddr6.sin6_addr, sizeof saddr6.sin6_addr);
 616         } else {
 617                 /* error already emitted, but let's emit another more relevant */
 618                 do_from_zval_err(ctx, "could not resolve address '%s' to get an AF_INET6 "
 619                                 "address", Z_STRVAL_P(zaddr_str));
 620         }
 621 
 622         zval_dtor(&lzval);
 623 }
 624 static void to_zval_read_sin6_addr(const char *data, zval *zv, res_context *ctx)
 625 {
 626         const struct in6_addr *addr = (const struct in6_addr *)data;
 627         socklen_t size = INET6_ADDRSTRLEN;
 628 
 629         Z_TYPE_P(zv) = IS_STRING;
 630         Z_STRVAL_P(zv) = ecalloc(1, size);
 631         Z_STRLEN_P(zv) = 0;
 632 
 633         if (inet_ntop(AF_INET6, addr, Z_STRVAL_P(zv), size) == NULL) {
 634                 do_to_zval_err(ctx, "could not convert IPv6 address to string "
 635                                 "(errno %d)", errno);
 636                 return;
 637         }
 638 
 639         Z_STRLEN_P(zv) = strlen(Z_STRVAL_P(zv));
 640 }
 641 static const field_descriptor descriptors_sockaddr_in6[] = {
 642                 {"family", sizeof("family"), 0, offsetof(struct sockaddr_in6, sin6_family), from_zval_write_sa_family, to_zval_read_sa_family},
 643                 {"addr", sizeof("addr"), 0, offsetof(struct sockaddr_in6, sin6_addr), from_zval_write_sin6_addr, to_zval_read_sin6_addr},
 644                 {"port", sizeof("port"), 0, offsetof(struct sockaddr_in6, sin6_port), from_zval_write_net_uint16, to_zval_read_net_uint16},
 645                 {"flowinfo", sizeof("flowinfo"), 0, offsetof(struct sockaddr_in6, sin6_flowinfo), from_zval_write_uint32, to_zval_read_uint32},
 646                 {"scope_id", sizeof("scope_id"), 0, offsetof(struct sockaddr_in6, sin6_scope_id), from_zval_write_uint32, to_zval_read_uint32},
 647                 {0}
 648 };
 649 static void from_zval_write_sockaddr_in6(const zval *container, char *sockaddr6, ser_context *ctx)
 650 {
 651         from_zval_write_aggregation(container, sockaddr6, descriptors_sockaddr_in6, ctx);
 652 }
 653 static void to_zval_read_sockaddr_in6(const char *data, zval *zv, res_context *ctx)
 654 {
 655         to_zval_read_aggregation(data, zv, descriptors_sockaddr_in6, ctx);
 656 }
 657 #endif /* HAVE_IPV6 */
 658 static void from_zval_write_sun_path(const zval *path, char *sockaddr_un_c, ser_context *ctx)
 659 {
 660         zval                            lzval = zval_used_for_init;
 661         struct sockaddr_un      *saddr = (struct sockaddr_un*)sockaddr_un_c;
 662 
 663         if (Z_TYPE_P(path) != IS_STRING) {
 664                 ZVAL_COPY_VALUE(&lzval, path);
 665                 zval_copy_ctor(&lzval);
 666                 convert_to_string(&lzval);
 667                 path = &lzval;
 668         }
 669 
 670         /* code in this file relies on the path being nul terminated, even though
 671          * this is not required, at least on linux for abstract paths. It also
 672          * assumes that the path is not empty */
 673         if (Z_STRLEN_P(path) == 0) {
 674                 do_from_zval_err(ctx, "%s", "the path is cannot be empty");
 675                 return;
 676         }
 677         if (Z_STRLEN_P(path) >= sizeof(saddr->sun_path)) {
 678                 do_from_zval_err(ctx, "the path is too long, the maximum permitted "
 679                                 "length is %ld", sizeof(saddr->sun_path) - 1);
 680                 return;
 681         }
 682 
 683         memcpy(&saddr->sun_path, Z_STRVAL_P(path), Z_STRLEN_P(path));
 684         saddr->sun_path[Z_STRLEN_P(path)] = '\0';
 685 
 686         zval_dtor(&lzval);
 687 }
 688 static void to_zval_read_sun_path(const char *data, zval *zv, res_context *ctx) {
 689         struct sockaddr_un      *saddr = (struct sockaddr_un*)data;
 690         char *nul_pos;
 691 
 692         nul_pos = memchr(&saddr->sun_path, '\0', sizeof(saddr->sun_path));
 693         if (nul_pos == NULL) {
 694                 do_to_zval_err(ctx, "could not find a NUL in the path");
 695                 return;
 696         }
 697 
 698         ZVAL_STRINGL(zv, saddr->sun_path, nul_pos - (char*)&saddr->sun_path, 1);
 699 }
 700 static const field_descriptor descriptors_sockaddr_un[] = {
 701                 {"family", sizeof("family"), 0, offsetof(struct sockaddr_un, sun_family), from_zval_write_sa_family, to_zval_read_sa_family},
 702                 {"path", sizeof("path"), 0, 0, from_zval_write_sun_path, to_zval_read_sun_path},
 703                 {0}
 704 };
 705 static void from_zval_write_sockaddr_un(const zval *container, char *sockaddr, ser_context *ctx)
 706 {
 707         from_zval_write_aggregation(container, sockaddr, descriptors_sockaddr_un, ctx);
 708 }
 709 static void to_zval_read_sockaddr_un(const char *data, zval *zv, res_context *ctx)
 710 {
 711         to_zval_read_aggregation(data, zv, descriptors_sockaddr_un, ctx);
 712 }
 713 static void from_zval_write_sockaddr_aux(const zval *container,
 714                                                                                  struct sockaddr **sockaddr_ptr,
 715                                                                                  socklen_t *sockaddr_len,
 716                                                                                  ser_context *ctx)
 717 {
 718         int             family;
 719         zval    **elem;
 720         int             fill_sockaddr;
 721 
 722         if (Z_TYPE_P(container) != IS_ARRAY) {
 723                 do_from_zval_err(ctx, "%s", "expected an array here");
 724                 return;
 725         }
 726 
 727         fill_sockaddr = param_get_bool(ctx, KEY_FILL_SOCKADDR, 1);
 728 
 729         if (zend_hash_find(Z_ARRVAL_P(container), "family", sizeof("family"), (void**)&elem) == SUCCESS
 730                         && Z_TYPE_PP(elem) != IS_NULL) {
 731                 const char *node = "family";
 732                 zend_llist_add_element(&ctx->keys, &node);
 733                 from_zval_write_int(*elem, (char*)&family, ctx);
 734                 zend_llist_remove_tail(&ctx->keys);
 735         } else {
 736                 family = ctx->sock->type;
 737         }
 738 
 739         switch (family) {
 740         case AF_INET:
 741                 /* though not all OSes support sockaddr_in used in IPv6 sockets */
 742                 if (ctx->sock->type != AF_INET && ctx->sock->type != AF_INET6) {
 743                         do_from_zval_err(ctx, "the specified family (number %d) is not "
 744                                         "supported on this socket", family);
 745                         return;
 746                 }
 747                 *sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_in), ctx);
 748                 *sockaddr_len = sizeof(struct sockaddr_in);
 749                 if (fill_sockaddr) {
 750                         from_zval_write_sockaddr_in(container, (char*)*sockaddr_ptr, ctx);
 751                         (*sockaddr_ptr)->sa_family = AF_INET;
 752                 }
 753                 break;
 754 
 755 #if HAVE_IPV6
 756         case AF_INET6:
 757                 if (ctx->sock->type != AF_INET6) {
 758                         do_from_zval_err(ctx, "the specified family (AF_INET6) is not "
 759                                         "supported on this socket");
 760                         return;
 761                 }
 762                 *sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_in6), ctx);
 763                 *sockaddr_len = sizeof(struct sockaddr_in6);
 764                 if (fill_sockaddr) {
 765                         from_zval_write_sockaddr_in6(container, (char*)*sockaddr_ptr, ctx);
 766                         (*sockaddr_ptr)->sa_family = AF_INET6;
 767                 }
 768                 break;
 769 #endif /* HAVE_IPV6 */
 770 
 771         case AF_UNIX:
 772                 if (ctx->sock->type != AF_UNIX) {
 773                         do_from_zval_err(ctx, "the specified family (AF_UNIX) is not "
 774                                         "supported on this socket");
 775                         return;
 776                 }
 777                 *sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_un), ctx);
 778                 if (fill_sockaddr) {
 779                         struct sockaddr_un *sock_un = (struct sockaddr_un*)*sockaddr_ptr;
 780 
 781                         from_zval_write_sockaddr_un(container, (char*)*sockaddr_ptr, ctx);
 782                         (*sockaddr_ptr)->sa_family = AF_UNIX;
 783 
 784                         /* calculating length is more complicated here. Giving the size of
 785                          * struct sockaddr_un here and relying on the nul termination of
 786                          * sun_path does not work for paths in the abstract namespace. Note
 787                          * that we always assume the path is not empty and nul terminated */
 788                         *sockaddr_len = offsetof(struct sockaddr_un, sun_path) +
 789                                         (sock_un->sun_path[0] == '\0'
 790                                         ? (1 + strlen(&sock_un->sun_path[1]))
 791                                         : strlen(sock_un->sun_path));
 792                 } else {
 793                         *sockaddr_len = sizeof(struct sockaddr_un);
 794                 }
 795                 break;
 796 
 797         default:
 798                 do_from_zval_err(ctx, "%s", "the only families currently supported are "
 799                                 "AF_INET, AF_INET6 and AF_UNIX");
 800                 break;
 801         }
 802 }
 803 static void to_zval_read_sockaddr_aux(const char *sockaddr_c, zval *zv, res_context *ctx)
 804 {
 805         const struct sockaddr *saddr = (struct sockaddr *)sockaddr_c;
 806 
 807         if (saddr->sa_family == 0) {
 808                 ZVAL_NULL(zv);
 809                 return;
 810         }
 811 
 812         array_init(zv);
 813 
 814         switch (saddr->sa_family) {
 815         case AF_INET:
 816                 to_zval_read_sockaddr_in(sockaddr_c, zv, ctx);
 817                 break;
 818 
 819 #if HAVE_IPV6
 820         case AF_INET6:
 821                 to_zval_read_sockaddr_in6(sockaddr_c, zv, ctx);
 822                 break;
 823 #endif /* HAVE_IPV6 */
 824 
 825         case AF_UNIX:
 826                 to_zval_read_sockaddr_un(sockaddr_c, zv, ctx);
 827                 break;
 828 
 829         default:
 830                 do_to_zval_err(ctx, "cannot read struct sockaddr with family %d; "
 831                                 "not supported",
 832                                 (int)saddr->sa_family);
 833                 break;
 834         }
 835 }
 836 
 837 /* CONVERSIONS for cmsghdr */
 838 /*
 839  * [ level => , type => , data => [],]
 840  * struct cmsghdr {
 841  *  socklen_t cmsg_len;    // data byte count, including header
 842  *  int       cmsg_level;  // originating protocol
 843  *  int       cmsg_type;   // protocol-specific type
 844  *  // followed by unsigned char cmsg_data[];
 845  * };
 846  */
 847 static void from_zval_write_control(const zval                  *arr,
 848                                                                         void                            **control_buf,
 849                                                                         zend_llist_element      *alloc,
 850                                                                         size_t                          *control_len,
 851                                                                         size_t                          *offset,
 852                                                                         ser_context                     *ctx)
 853 {
 854         struct cmsghdr          *cmsghdr;
 855         int                                     level,
 856                                                 type;
 857         size_t                          data_len,
 858                                                 req_space,
 859                                                 space_left;
 860         ancillary_reg_entry     *entry;
 861 
 862         static const field_descriptor descriptor_level[] = {
 863                         {"level", sizeof("level"), 0, 0, from_zval_write_int, 0},
 864                         {0}
 865         };
 866         static const field_descriptor descriptor_type[] = {
 867                         {"type", sizeof("type"), 0, 0, from_zval_write_int, 0},
 868                         {0}
 869         };
 870         field_descriptor descriptor_data[] = {
 871                         {"data", sizeof("data"), 0, 0, 0, 0},
 872                         {0}
 873         };
 874 
 875         from_zval_write_aggregation(arr, (char *)&level, descriptor_level, ctx);
 876         if (ctx->err.has_error) {
 877                 return;
 878         }
 879         from_zval_write_aggregation(arr, (char *)&type, descriptor_type, ctx);
 880         if (ctx->err.has_error) {
 881                 return;
 882         }
 883 
 884         entry = get_ancillary_reg_entry(level, type);
 885         if (entry == NULL) {
 886                 do_from_zval_err(ctx, "cmsghdr with level %d and type %d not supported",
 887                                 level, type);
 888                 return;
 889         }
 890 
 891         if (entry->calc_space) {
 892                 zval **data_elem;
 893                 /* arr must be an array at this point */
 894                 if (zend_hash_find(Z_ARRVAL_P(arr), "data", sizeof("data"),
 895                                 (void**)&data_elem) == FAILURE) {
 896                         do_from_zval_err(ctx, "cmsghdr should have a 'data' element here");
 897                         return;
 898                 }
 899                 data_len = entry->calc_space(*data_elem, ctx);
 900                 if (ctx->err.has_error) {
 901                         return;
 902                 }
 903         } else {
 904                 data_len = entry->size;
 905         }
 906         req_space = CMSG_SPACE(data_len);
 907         space_left = *control_len - *offset;
 908         assert(*control_len >= *offset);
 909 
 910         if (space_left < req_space) {
 911                 *control_buf = safe_erealloc(*control_buf, 2, req_space, *control_len);
 912                 *control_len += 2 * req_space;
 913                 memset((char *)*control_buf + *offset, '\0', *control_len - *offset);
 914                 memcpy(&alloc->data, control_buf, sizeof *control_buf);
 915         }
 916 
 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);
 921 
 922         descriptor_data[0].from_zval = entry->from_array;
 923         from_zval_write_aggregation(arr, (char*)CMSG_DATA(cmsghdr), descriptor_data, ctx);
 924 
 925         *offset += req_space;
 926 }
 927 static void from_zval_write_control_array(const zval *arr, char *msghdr_c, ser_context *ctx)
 928 {
 929         HashPosition            pos;
 930         char                            buf[sizeof("element #4294967295")];
 931         char                            *bufp = buf;
 932         zval                            **elem;
 933         uint32_t                        i;
 934         int                                     num_elems;
 935         void                            *control_buf;
 936         zend_llist_element      *alloc;
 937         size_t                          control_len,
 938                                                 cur_offset;
 939         struct msghdr           *msg = (struct msghdr*)msghdr_c;
 940 
 941         if (Z_TYPE_P(arr) != IS_ARRAY) {
 942                 do_from_zval_err(ctx, "%s", "expected an array here");
 943                 return;
 944         }
 945 
 946         num_elems = zend_hash_num_elements(Z_ARRVAL_P(arr));
 947         if (num_elems == 0) {
 948                 return;
 949         }
 950 
 951         /* estimate each message at 20 bytes */
 952         control_buf     = accounted_safe_ecalloc(num_elems, CMSG_SPACE(20), 0, ctx);
 953         alloc           = ctx->allocations.tail;
 954         control_len = (size_t)num_elems * CMSG_SPACE(20);
 955         cur_offset      = 0;
 956 
 957     for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos), i = 0;
 958                         !ctx->err.has_error
 959                         && zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **)&elem, &pos) == SUCCESS;
 960                         zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos)) {
 961 
 962                 if (snprintf(buf, sizeof(buf), "element #%u", (unsigned)i++) >= sizeof(buf)) {
 963                         memcpy(buf, "element", sizeof("element"));
 964                 }
 965                 zend_llist_add_element(&ctx->keys, &bufp);
 966 
 967                 from_zval_write_control(*elem, &control_buf, alloc, &control_len,
 968                                 &cur_offset, ctx);
 969 
 970                 zend_llist_remove_tail(&ctx->keys);
 971     }
 972 
 973     msg->msg_control = control_buf;
 974     msg->msg_controllen = cur_offset; /* not control_len, which may be larger */
 975 }
 976 static void to_zval_read_cmsg_data(const char *cmsghdr_c, zval *zv, res_context *ctx)
 977 {
 978         const struct cmsghdr    *cmsg = (const struct cmsghdr *)cmsghdr_c;
 979         ancillary_reg_entry             *entry;
 980         size_t                                  len,
 981                                                         *len_p = &len;
 982 
 983         entry = get_ancillary_reg_entry(cmsg->cmsg_level, cmsg->cmsg_type);
 984         if (entry == NULL) {
 985                 do_to_zval_err(ctx, "cmsghdr with level %d and type %d not supported",
 986                                 cmsg->cmsg_level, cmsg->cmsg_type);
 987                 return;
 988         }
 989         if (CMSG_LEN(entry->size) > cmsg->cmsg_len) {
 990                 do_to_zval_err(ctx, "the cmsghdr structure is unexpectedly small; "
 991                                 "expected a length of at least %ld, but got %ld",
 992                                 (long)CMSG_LEN(entry->size), (long)cmsg->cmsg_len);
 993                 return;
 994         }
 995 
 996         len = (size_t)cmsg->cmsg_len; /* use another var because type of cmsg_len varies */
 997         if (zend_hash_add(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN),
 998                         &len_p, sizeof(len_p), NULL) == FAILURE) {
 999                 do_to_zval_err(ctx, "%s", "could not set parameter " KEY_CMSG_LEN);
1000                 return;
1001         }
1002 
1003         entry->to_array((const char *)CMSG_DATA(cmsg), zv, ctx);
1004 
1005         zend_hash_del(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN));
1006 }
1007 static void to_zval_read_control(const char *cmsghdr_c, zval *zv, res_context *ctx)
1008 {
1009         /* takes a cmsghdr, not a msghdr like from_zval_write_control */
1010         static const field_descriptor descriptors[] = {
1011                         {"level", sizeof("level"), 0, offsetof(struct cmsghdr, cmsg_level), 0, to_zval_read_int},
1012                         {"type", sizeof("type"), 0, offsetof(struct cmsghdr, cmsg_type), 0, to_zval_read_int},
1013                         {"data", sizeof("data"), 0, 0 /* cmsghdr passed */, 0, to_zval_read_cmsg_data},
1014                         {0}
1015         };
1016 
1017         array_init_size(zv, 3);
1018         to_zval_read_aggregation(cmsghdr_c, zv, descriptors, ctx);
1019 }
1020 static void to_zval_read_control_array(const char *msghdr_c, zval *zv, res_context *ctx)
1021 {
1022         struct msghdr   *msg = (struct msghdr *)msghdr_c;
1023         struct cmsghdr  *cmsg;
1024         char                    buf[sizeof("element #4294967295")];
1025         char                    *bufp = buf;
1026         uint32_t                i = 1;
1027 
1028         /*if (msg->msg_flags & MSG_CTRUNC) {
1029                 php_error_docref0(NULL, E_WARNING, "The MSG_CTRUNC flag is present; will not "
1030                                 "attempt to read control messages");
1031                 ZVAL_FALSE(zv);
1032                 return;
1033         }*/
1034 
1035         array_init(zv);
1036 
1037         for (cmsg = CMSG_FIRSTHDR(msg);
1038                         cmsg != NULL && !ctx->err.has_error;
1039                         cmsg = CMSG_NXTHDR(msg, cmsg)) {
1040                 zval *elem;
1041 
1042                 ALLOC_INIT_ZVAL(elem);
1043                 add_next_index_zval(zv, elem);
1044 
1045                 if (snprintf(buf, sizeof(buf), "element #%u", (unsigned)i++) >= sizeof(buf)) {
1046                         memcpy(buf, "element", sizeof("element"));
1047                 }
1048                 zend_llist_add_element(&ctx->keys, &bufp);
1049 
1050                 to_zval_read_control((const char *)cmsg, elem, ctx);
1051 
1052                 zend_llist_remove_tail(&ctx->keys);
1053         }
1054 }
1055 
1056 /* CONVERSIONS for msghdr */
1057 static void from_zval_write_name(const zval *zname_arr, char *msghdr_c, ser_context *ctx)
1058 {
1059         struct sockaddr *sockaddr;
1060         socklen_t               sockaddr_len;
1061         struct msghdr   *msghdr = (struct msghdr *)msghdr_c;
1062 
1063         from_zval_write_sockaddr_aux(zname_arr, &sockaddr, &sockaddr_len, ctx);
1064 
1065         msghdr->msg_name = sockaddr;
1066         msghdr->msg_namelen = sockaddr_len;
1067 }
1068 static void to_zval_read_name(const char *sockaddr_p, zval *zv, res_context *ctx)
1069 {
1070         void *name = (void*)*(void**)sockaddr_p;
1071         if (name == NULL) {
1072                 ZVAL_NULL(zv);
1073         } else {
1074                 to_zval_read_sockaddr_aux(name, zv, ctx);
1075         }
1076 }
1077 static void from_zval_write_msghdr_buffer_size(const zval *elem, char *msghdr_c, ser_context *ctx)
1078 {
1079         long lval;
1080         struct msghdr *msghdr = (struct msghdr *)msghdr_c;
1081 
1082         lval = from_zval_integer_common(elem, ctx);
1083         if (ctx->err.has_error) {
1084                 return;
1085         }
1086 
1087         if (lval < 0 || lval > MAX_USER_BUFF_SIZE) {
1088                 do_from_zval_err(ctx, "the buffer size must be between 1 and %ld; "
1089                                 "given %ld", (long)MAX_USER_BUFF_SIZE, lval);
1090                 return;
1091         }
1092 
1093         msghdr->msg_iovlen = 1;
1094         msghdr->msg_iov = accounted_emalloc(sizeof(*msghdr->msg_iov) * 1, ctx);
1095         msghdr->msg_iov[0].iov_base = accounted_emalloc((size_t)lval, ctx);
1096         msghdr->msg_iov[0].iov_len = (size_t)lval;
1097 }
1098 static void from_zval_write_iov_array_aux(zval **elem, unsigned i, void **args, ser_context *ctx)
1099 {
1100         struct msghdr   *msg = args[0];
1101         size_t                  len;
1102 
1103         zval_add_ref(elem);
1104         convert_to_string_ex(elem);
1105 
1106         len = Z_STRLEN_PP(elem);
1107         msg->msg_iov[i - 1].iov_base = accounted_emalloc(len, ctx);
1108         msg->msg_iov[i - 1].iov_len = len;
1109         memcpy(msg->msg_iov[i - 1].iov_base, Z_STRVAL_PP(elem), len);
1110 
1111         zval_ptr_dtor(elem);
1112 }
1113 static void from_zval_write_iov_array(const zval *arr, char *msghdr_c, ser_context *ctx)
1114 {
1115         int                             num_elem;
1116         struct msghdr   *msg = (struct msghdr*)msghdr_c;
1117 
1118         if (Z_TYPE_P(arr) != IS_ARRAY) {
1119                 do_from_zval_err(ctx, "%s", "expected an array here");
1120                 return;
1121         }
1122 
1123         num_elem = zend_hash_num_elements(Z_ARRVAL_P(arr));
1124         if (num_elem == 0) {
1125                 return;
1126         }
1127 
1128         msg->msg_iov = accounted_safe_ecalloc(num_elem, sizeof *msg->msg_iov, 0, ctx);
1129         msg->msg_iovlen = (size_t)num_elem;
1130 
1131     from_array_iterate(arr, from_zval_write_iov_array_aux, (void**)&msg, ctx);
1132 }
1133 static void from_zval_write_controllen(const zval *elem, char *msghdr_c, ser_context *ctx)
1134 {
1135         struct msghdr *msghdr = (struct msghdr *)msghdr_c;
1136         uint32_t len;
1137 
1138         /* controllen should be an unsigned with at least 32-bit. Let's assume
1139          * this least common denominator
1140          */
1141         from_zval_write_uint32(elem, (char*)&len, ctx);
1142         if (!ctx->err.has_error && len == 0) {
1143                 do_from_zval_err(ctx, "controllen cannot be 0");
1144                 return;
1145         }
1146         msghdr->msg_control = accounted_emalloc(len, ctx);
1147         msghdr->msg_controllen = len;
1148 }
1149 void from_zval_write_msghdr_send(const zval *container, char *msghdr_c, ser_context *ctx)
1150 {
1151         static const field_descriptor descriptors[] = {
1152                         {"name", sizeof("name"), 0, 0, from_zval_write_name, 0},
1153                         {"iov", sizeof("iov"), 0, 0, from_zval_write_iov_array, 0},
1154                         {"control", sizeof("control"), 0, 0, from_zval_write_control_array, 0},
1155                         {0}
1156         };
1157 
1158         from_zval_write_aggregation(container, msghdr_c, descriptors, ctx);
1159 }
1160 void from_zval_write_msghdr_recv(const zval *container, char *msghdr_c, ser_context *ctx)
1161 {
1162         /* zval to struct msghdr, version for recvmsg(). It differs from the version
1163          * for sendmsg() in that it:
1164          *      - has a buffer_size instead of an iov array;
1165          *      - has no control element; has a controllen element instead
1166          * struct msghdr {
1167          *    void *msg_name;
1168          *    socklen_t msg_namelen;
1169          *    struct iovec *msg_iov;
1170          *    size_t msg_iovlen;
1171          *    void *msg_control;
1172          *    size_t msg_controllen; //can also be socklen_t
1173          *    int msg_flags;
1174          * };
1175          */
1176         static const field_descriptor descriptors[] = {
1177                         {"name", sizeof("name"), 0, 0, from_zval_write_name, 0},
1178                         {"buffer_size", sizeof("buffer_size"), 0, 0, from_zval_write_msghdr_buffer_size, 0},
1179                         {"controllen", sizeof("controllen"), 1, 0, from_zval_write_controllen, 0},
1180                         {0}
1181         };
1182         struct msghdr   *msghdr = (struct msghdr *)msghdr_c;
1183         const int               falsev = 0,
1184                                         *falsevp = &falsev;
1185 
1186         if (zend_hash_add(&ctx->params, KEY_FILL_SOCKADDR, sizeof(KEY_FILL_SOCKADDR),
1187                         (void*)&falsevp, sizeof(falsevp), NULL) == FAILURE) {
1188                 do_from_zval_err(ctx, "could not add fill_sockaddr; this is a bug");
1189                 return;
1190         }
1191 
1192         from_zval_write_aggregation(container, msghdr_c, descriptors, ctx);
1193 
1194         zend_hash_del(&ctx->params, KEY_FILL_SOCKADDR, sizeof(KEY_FILL_SOCKADDR));
1195         if (ctx->err.has_error) {
1196                 return;
1197         }
1198 
1199         if (msghdr->msg_iovlen == 0) {
1200                 msghdr->msg_iovlen = 1;
1201                 msghdr->msg_iov = accounted_emalloc(sizeof(*msghdr->msg_iov) * 1, ctx);
1202                 msghdr->msg_iov[0].iov_base = accounted_emalloc((size_t)DEFAULT_BUFF_SIZE, ctx);
1203                 msghdr->msg_iov[0].iov_len = (size_t)DEFAULT_BUFF_SIZE;
1204         }
1205 }
1206 
1207 static void to_zval_read_iov(const char *msghdr_c, zval *zv, res_context *ctx)
1208 {
1209         const struct msghdr     *msghdr = (const struct msghdr *)msghdr_c;
1210         size_t                          iovlen = msghdr->msg_iovlen;
1211         ssize_t                         **recvmsg_ret,
1212                                                 bytes_left;
1213         uint                            i;
1214 
1215         if (iovlen > UINT_MAX) {
1216                 do_to_zval_err(ctx, "unexpectedly large value for iov_len: %lu",
1217                                 (unsigned long)iovlen);
1218         }
1219         array_init_size(zv, (uint)iovlen);
1220 
1221         if (zend_hash_find(&ctx->params, KEY_RECVMSG_RET, sizeof(KEY_RECVMSG_RET),
1222                         (void**)&recvmsg_ret) == FAILURE) {
1223                 do_to_zval_err(ctx, "recvmsg_ret not found in params. This is a bug");
1224                 return;
1225         }
1226         bytes_left = **recvmsg_ret;
1227 
1228         for (i = 0; bytes_left > 0 && i < (uint)iovlen; i++) {
1229                 zval    *elem;
1230                 size_t  len             = MIN(msghdr->msg_iov[i].iov_len, (size_t)bytes_left);
1231                 char    *buf    = safe_emalloc(1, len, 1);
1232 
1233                 MAKE_STD_ZVAL(elem);
1234                 memcpy(buf, msghdr->msg_iov[i].iov_base, len);
1235                 buf[len] = '\0';
1236 
1237                 ZVAL_STRINGL(elem, buf, len, 0);
1238                 add_next_index_zval(zv, elem);
1239                 bytes_left -= len;
1240         }
1241 }
1242 void to_zval_read_msghdr(const char *msghdr_c, zval *zv, res_context *ctx)
1243 {
1244         static const field_descriptor descriptors[] = {
1245                         {"name", sizeof("name"), 0, offsetof(struct msghdr, msg_name), 0, to_zval_read_name},
1246                         {"control", sizeof("control"), 0, 0, 0, to_zval_read_control_array},
1247                         {"iov", sizeof("iov"), 0, 0, 0, to_zval_read_iov},
1248                         {"flags", sizeof("flags"), 0, offsetof(struct msghdr, msg_flags), 0, to_zval_read_int},
1249                         {0}
1250         };
1251 
1252         array_init_size(zv, 4);
1253 
1254         to_zval_read_aggregation(msghdr_c, zv, descriptors, ctx);
1255 }
1256 
1257 /* CONVERSIONS for if_index */
1258 static void from_zval_write_ifindex(const zval *zv, char *uinteger, ser_context *ctx)
1259 {
1260         unsigned        ret = 0;
1261         zval            lzval = zval_used_for_init;
1262 
1263         if (Z_TYPE_P(zv) == IS_LONG) {
1264                 if (Z_LVAL_P(zv) < 0 || Z_LVAL_P(zv) > UINT_MAX) { /* allow 0 (unspecified interface) */
1265                         do_from_zval_err(ctx, "the interface index cannot be negative or "
1266                                         "larger than %u; given %ld", UINT_MAX, Z_LVAL_P(zv));
1267                 } else {
1268                         ret = (unsigned)Z_LVAL_P(zv);
1269                 }
1270         } else {
1271                 if (Z_TYPE_P(zv) != IS_STRING) {
1272                         ZVAL_COPY_VALUE(&lzval, zv);
1273                         zval_copy_ctor(&lzval);
1274                         convert_to_string(&lzval);
1275                         zv = &lzval;
1276                 }
1277 
1278 #if HAVE_IF_NAMETOINDEX
1279                 ret = if_nametoindex(Z_STRVAL_P(zv));
1280                 if (ret == 0) {
1281                         do_from_zval_err(ctx, "no interface with name \"%s\" could be "
1282                                         "found", Z_STRVAL_P(zv));
1283                 }
1284 #elif defined(SIOCGIFINDEX)
1285                 {
1286                         struct ifreq ifr;
1287                         if (strlcpy(ifr.ifr_name, Z_STRVAL_P(zv), sizeof(ifr.ifr_name))
1288                                         >= sizeof(ifr.ifr_name)) {
1289                                 do_from_zval_err(ctx, "the interface name \"%s\" is too large ",
1290                                                 Z_STRVAL_P(zv));
1291                         } else if (ioctl(ctx->sock->bsd_socket, SIOCGIFINDEX, &ifr) < 0) {
1292                                 if (errno == ENODEV) {
1293                                         do_from_zval_err(ctx, "no interface with name \"%s\" could be "
1294                                                         "found", Z_STRVAL_P(zv));
1295                                 } else {
1296                                         do_from_zval_err(ctx, "error fetching interface index for "
1297                                                         "interface with name \"%s\" (errno %d)",
1298                                                         Z_STRVAL_P(zv), errno);
1299                                 }
1300                         } else {
1301                                 ret = (unsigned)ifr.ifr_ifindex;
1302                         }
1303                 }
1304 #else
1305                 do_from_zval_err(ctx,
1306                                 "this platform does not support looking up an interface by "
1307                                 "name, an integer interface index must be supplied instead");
1308 #endif
1309         }
1310 
1311         if (!ctx->err.has_error) {
1312                 memcpy(uinteger, &ret, sizeof(ret));
1313         }
1314 
1315         zval_dtor(&lzval);
1316 }
1317 
1318 /* CONVERSIONS for struct in6_pktinfo */
1319 #if defined(IPV6_PKTINFO) && HAVE_IPV6
1320 static const field_descriptor descriptors_in6_pktinfo[] = {
1321                 {"addr", sizeof("addr"), 1, offsetof(struct in6_pktinfo, ipi6_addr), from_zval_write_sin6_addr, to_zval_read_sin6_addr},
1322                 {"ifindex", sizeof("ifindex"), 1, offsetof(struct in6_pktinfo, ipi6_ifindex), from_zval_write_ifindex, to_zval_read_unsigned},
1323                 {0}
1324 };
1325 void from_zval_write_in6_pktinfo(const zval *container, char *in6_pktinfo_c, ser_context *ctx)
1326 {
1327         from_zval_write_aggregation(container, in6_pktinfo_c, descriptors_in6_pktinfo, ctx);
1328 }
1329 void to_zval_read_in6_pktinfo(const char *data, zval *zv, res_context *ctx)
1330 {
1331         array_init_size(zv, 2);
1332 
1333         to_zval_read_aggregation(data, zv, descriptors_in6_pktinfo, ctx);
1334 }
1335 #endif
1336 
1337 /* CONVERSIONS for struct ucred */
1338 #ifdef SO_PASSCRED
1339 static const field_descriptor descriptors_ucred[] = {
1340                 {"pid", sizeof("pid"), 1, offsetof(struct ucred, pid), from_zval_write_pid_t, to_zval_read_pid_t},
1341                 {"uid", sizeof("uid"), 1, offsetof(struct ucred, uid), from_zval_write_uid_t, to_zval_read_uid_t},
1342                 /* assume the type gid_t is the same as uid_t: */
1343                 {"gid", sizeof("gid"), 1, offsetof(struct ucred, gid), from_zval_write_uid_t, to_zval_read_uid_t},
1344                 {0}
1345 };
1346 void from_zval_write_ucred(const zval *container, char *ucred_c, ser_context *ctx)
1347 {
1348         from_zval_write_aggregation(container, ucred_c, descriptors_ucred, ctx);
1349 }
1350 void to_zval_read_ucred(const char *data, zval *zv, res_context *ctx)
1351 {
1352         array_init_size(zv, 3);
1353 
1354         to_zval_read_aggregation(data, zv, descriptors_ucred, ctx);
1355 }
1356 #endif
1357 
1358 /* CONVERSIONS for SCM_RIGHTS */
1359 #ifdef SCM_RIGHTS
1360 size_t calculate_scm_rights_space(const zval *arr, ser_context *ctx)
1361 {
1362         int num_elems;
1363 
1364         if (Z_TYPE_P(arr) != IS_ARRAY) {
1365                 do_from_zval_err(ctx, "%s", "expected an array here");
1366                 return (size_t)-1;
1367         }
1368 
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");
1372                 return (size_t)-1;
1373         }
1374 
1375         return zend_hash_num_elements(Z_ARRVAL_P(arr)) * sizeof(int);
1376 }
1377 static void from_zval_write_fd_array_aux(zval **elem, unsigned i, void **args, ser_context *ctx)
1378 {
1379         int *iarr = args[0];
1380         TSRMLS_FETCH();
1381 
1382         if (Z_TYPE_PP(elem) == IS_RESOURCE) {
1383                 php_stream *stream;
1384                 php_socket *sock;
1385 
1386                 ZEND_FETCH_RESOURCE_NO_RETURN(sock, php_socket *, elem, -1,
1387                                 NULL, php_sockets_le_socket());
1388                 if (sock) {
1389                         iarr[i] = sock->bsd_socket;
1390                         return;
1391                 }
1392 
1393                 ZEND_FETCH_RESOURCE2_NO_RETURN(stream, php_stream *, elem, -1,
1394                                 NULL, php_file_le_stream(), php_file_le_pstream());
1395                 if (stream == NULL) {
1396                         do_from_zval_err(ctx, "resource is not a stream or a socket");
1397                         return;
1398                 }
1399 
1400                 if (php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&iarr[i - 1],
1401                                 REPORT_ERRORS) == FAILURE) {
1402                         do_from_zval_err(ctx, "cast stream to file descriptor failed");
1403                         return;
1404                 }
1405         } else {
1406                 do_from_zval_err(ctx, "expected a resource variable");
1407         }
1408 }
1409 void from_zval_write_fd_array(const zval *arr, char *int_arr, ser_context *ctx)
1410 {
1411         if (Z_TYPE_P(arr) != IS_ARRAY) {
1412                 do_from_zval_err(ctx, "%s", "expected an array here");
1413                 return;
1414         }
1415 
1416    from_array_iterate(arr, &from_zval_write_fd_array_aux, (void**)&int_arr, ctx);
1417 }
1418 void to_zval_read_fd_array(const char *data, zval *zv, res_context *ctx)
1419 {
1420         size_t                  **cmsg_len;
1421         int                             num_elems,
1422                                         i;
1423         struct cmsghdr  *dummy_cmsg = 0;
1424         size_t                  data_offset;
1425         TSRMLS_FETCH();
1426 
1427         data_offset = (unsigned char *)CMSG_DATA(dummy_cmsg)
1428                         - (unsigned char *)dummy_cmsg;
1429 
1430         if (zend_hash_find(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN),
1431                         (void **)&cmsg_len) == FAILURE) {
1432                 do_to_zval_err(ctx, "could not get value of parameter " KEY_CMSG_LEN);
1433                 return;
1434         }
1435 
1436         if (**cmsg_len < data_offset) {
1437                 do_to_zval_err(ctx, "length of cmsg is smaller than its data member "
1438                                 "offset (%ld vs %ld)", (long)**cmsg_len, (long)data_offset);
1439                 return;
1440         }
1441         num_elems = (**cmsg_len - data_offset) / sizeof(int);
1442 
1443         array_init_size(zv, num_elems);
1444 
1445         for (i = 0; i < num_elems; i++) {
1446                 zval            *elem;
1447                 int                     fd;
1448                 struct stat     statbuf;
1449 
1450                 MAKE_STD_ZVAL(elem);
1451 
1452                 fd = *((int *)data + i);
1453 
1454                 /* determine whether we have a socket */
1455                 if (fstat(fd, &statbuf) == -1) {
1456                         do_to_zval_err(ctx, "error creating resource for received file "
1457                                         "descriptor %d: fstat() call failed with errno %d", fd, errno);
1458                         efree(elem);
1459                         return;
1460                 }
1461                 if (S_ISSOCK(statbuf.st_mode)) {
1462                         php_socket *sock = socket_import_file_descriptor(fd TSRMLS_CC);
1463                         zend_register_resource(elem, sock, php_sockets_le_socket() TSRMLS_CC);
1464                 } else {
1465                         php_stream *stream = php_stream_fopen_from_fd(fd, "rw", NULL);
1466                         php_stream_to_zval(stream, elem);
1467                 }
1468 
1469                 add_next_index_zval(zv, elem);
1470         }
1471 }
1472 #endif
1473 
1474 /* ENTRY POINT for conversions */
1475 static void free_from_zval_allocation(void *alloc_ptr_ptr)
1476 {
1477         efree(*(void**)alloc_ptr_ptr);
1478 }
1479 void *from_zval_run_conversions(const zval                      *container,
1480                                                                 php_socket                      *sock,
1481                                                                 from_zval_write_field   *writer,
1482                                                                 size_t                          struct_size,
1483                                                                 const char                      *top_name,
1484                                                                 zend_llist                      **allocations /* out */,
1485                                                                 struct err_s                    *err /* in/out */)
1486 {
1487         ser_context ctx = {{0}};
1488         char *structure = NULL;
1489 
1490         *allocations = NULL;
1491 
1492         if (err->has_error) {
1493                 return NULL;
1494         }
1495 
1496         zend_hash_init(&ctx.params, 8, NULL, NULL, 0);
1497         zend_llist_init(&ctx.keys, sizeof(const char *), NULL, 0);
1498         zend_llist_init(&ctx.allocations, sizeof(void *), &free_from_zval_allocation, 0);
1499         ctx.sock = sock;
1500 
1501         structure = ecalloc(1, struct_size);
1502 
1503         zend_llist_add_element(&ctx.keys, &top_name);
1504         zend_llist_add_element(&ctx.allocations, &structure);
1505 
1506         /* main call */
1507         writer(container, structure, &ctx);
1508 
1509         if (ctx.err.has_error) {
1510                 zend_llist_destroy(&ctx.allocations); /* deallocates structure as well */
1511                 structure = NULL;
1512                 *err = ctx.err;
1513         } else {
1514                 *allocations = emalloc(sizeof **allocations);
1515                 **allocations = ctx.allocations;
1516         }
1517 
1518         zend_llist_destroy(&ctx.keys);
1519         zend_hash_destroy(&ctx.params);
1520 
1521         return structure;
1522 }
1523 zval *to_zval_run_conversions(const char *structure,
1524                                                           to_zval_read_field *reader,
1525                                                           const char *top_name,
1526                                                           const struct key_value *key_value_pairs,
1527                                                           struct err_s *err)
1528 {
1529         res_context                             ctx = {{0}, {0}};
1530         const struct key_value  *kv;
1531         zval                                    *zv = NULL;
1532 
1533         if (err->has_error) {
1534                 return NULL;
1535         }
1536 
1537         ALLOC_INIT_ZVAL(zv);
1538 
1539         zend_llist_init(&ctx.keys, sizeof(const char *), NULL, 0);
1540         zend_llist_add_element(&ctx.keys, &top_name);
1541 
1542         zend_hash_init(&ctx.params, 8, NULL, NULL, 0);
1543         for (kv = key_value_pairs; kv->key != NULL; kv++) {
1544                 zend_hash_update(&ctx.params, kv->key, kv->key_size,
1545                                 (void*)&kv->value, sizeof(kv->value), NULL);
1546         }
1547 
1548         /* main call */
1549         reader(structure, zv, &ctx);
1550 
1551         if (ctx.err.has_error) {
1552                 zval_ptr_dtor(&zv);
1553                 zv = NULL;
1554                 *err = ctx.err;
1555         }
1556 
1557         zend_llist_destroy(&ctx.keys);
1558         zend_hash_destroy(&ctx.params);
1559 
1560         return zv;
1561 }

/* [<][>][^][v][top][bottom][index][help] */