PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/sockets - conversions.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 449 663 67.7 %
Date: 2014-07-21 Functions: 56 67 83.6 %
Legend: Lines: hit not hit

          Line data    Source code
       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           7 : static int param_get_bool(void *ctx, const char *key, int def)
     108             : {
     109             :         int **elem;
     110           7 :         if (zend_hash_find(ctx, key, strlen(key) + 1, (void**)&elem) == SUCCESS) {
     111           4 :                 return **elem;
     112             :         } else {
     113           3 :                 return def;
     114             :         }
     115             : }
     116             : 
     117             : /* MEMORY */
     118          24 : static inline void *accounted_emalloc(size_t alloc_size, ser_context *ctx)
     119             : {
     120          24 :         void *ret = emalloc(alloc_size);
     121          24 :         zend_llist_add_element(&ctx->allocations, &ret);
     122          24 :         return ret;
     123             : }
     124           7 : static inline void *accounted_ecalloc(size_t nmemb, size_t alloc_size, ser_context *ctx)
     125             : {
     126           7 :         void *ret = ecalloc(nmemb, alloc_size);
     127           7 :         zend_llist_add_element(&ctx->allocations, &ret);
     128           7 :         return ret;
     129             : }
     130           6 : static inline void *accounted_safe_ecalloc(size_t nmemb, size_t alloc_size, size_t offset, ser_context *ctx)
     131             : {
     132           6 :         void *ret = safe_emalloc(nmemb, alloc_size, offset);
     133           6 :         memset(ret, '\0', nmemb * alloc_size + offset);
     134           6 :         zend_llist_add_element(&ctx->allocations, &ret);
     135           6 :         return ret;
     136             : }
     137             : 
     138             : /* ERRORS */
     139           1 : 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           1 :         smart_str                       path = {0};
     146             :         const char                      **node;
     147             :         char                            *user_msg;
     148             :         int                                     user_msg_size;
     149             :         zend_llist_position     pos;
     150             : 
     151           1 :         if (err->has_error) {
     152           0 :                 return;
     153             :         }
     154             : 
     155           3 :         for (node = zend_llist_get_first_ex(keys, &pos);
     156             :                         node != NULL;
     157           1 :                         node = zend_llist_get_next_ex(keys, &pos)) {
     158           1 :                 smart_str_appends(&path, *node);
     159           1 :                 smart_str_appends(&path, " > ");
     160             :         }
     161             : 
     162           1 :         if (path.len > 3) {
     163           1 :                 path.len -= 3;
     164             :         }
     165           1 :         smart_str_0(&path);
     166             : 
     167           1 :         user_msg_size = vspprintf(&user_msg, 0, fmt, ap);
     168             : 
     169           1 :         err->has_error = 1;
     170           1 :         err->level = E_WARNING;
     171           3 :         spprintf(&err->msg, 0, "error converting %s data (path: %s): %.*s",
     172             :                         what_conv,
     173           2 :                         path.c && path.c != '\0' ? path.c : "unavailable",
     174             :                         user_msg_size, user_msg);
     175           1 :         err->should_free = 1;
     176             : 
     177           1 :         efree(user_msg);
     178           1 :         smart_str_free_ex(&path, 0);
     179             : }
     180             : ZEND_ATTRIBUTE_FORMAT(printf, 2 ,3)
     181           1 : static void do_from_zval_err(ser_context *ctx, const char *fmt, ...)
     182             : {
     183             :         va_list ap;
     184             : 
     185           1 :         va_start(ap, fmt);
     186           1 :         do_from_to_zval_err(&ctx->err, &ctx->keys, "user", fmt, ap);
     187           1 :         va_end(ap);
     188           1 : }
     189             : ZEND_ATTRIBUTE_FORMAT(printf, 2 ,3)
     190           0 : static void do_to_zval_err(res_context *ctx, const char *fmt, ...)
     191             : {
     192             :         va_list ap;
     193             : 
     194           0 :         va_start(ap, fmt);
     195           0 :         do_from_to_zval_err(&ctx->err, &ctx->keys, "native", fmt, ap);
     196           0 :         va_end(ap);
     197           0 : }
     198             : 
     199           1 : void err_msg_dispose(struct err_s *err TSRMLS_DC)
     200             : {
     201           1 :         if (err->msg != NULL) {
     202           1 :                 php_error_docref0(NULL TSRMLS_CC, err->level, "%s", err->msg);
     203           1 :                 if (err->should_free) {
     204           1 :                         efree(err->msg);
     205             :                 }
     206             :         }
     207           1 : }
     208           5 : void allocations_dispose(zend_llist **allocations)
     209             : {
     210           5 :         zend_llist_destroy(*allocations);
     211           5 :         efree(*allocations);
     212           5 :         *allocations = NULL;
     213           5 : }
     214             : 
     215           5 : 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           5 :         char                    *bufp = buf;
     225             : 
     226             :         /* Note i starts at 1, not 0! */
     227          47 :     for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos), i = 1;
     228          21 :                         !ctx->err.has_error
     229          21 :                         && zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **)&elem, &pos) == SUCCESS;
     230          16 :                         zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos), i++) {
     231          16 :                 if (snprintf(buf, sizeof(buf), "element #%u", i) >= sizeof(buf)) {
     232           0 :                         memcpy(buf, "element", sizeof("element"));
     233             :                 }
     234          16 :                 zend_llist_add_element(&ctx->keys, &bufp);
     235             : 
     236          16 :                 func(elem, i, args, ctx);
     237             : 
     238          16 :                 zend_llist_remove_tail(&ctx->keys);
     239             :     }
     240             : 
     241           5 :     return i -1;
     242             : }
     243             : 
     244             : /* Generic Aggregated conversions */
     245          19 : 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          19 :         if (Z_TYPE_P(container) != IS_ARRAY) {
     254           0 :                 do_from_zval_err(ctx, "%s", "expected an array here");
     255             :         }
     256             : 
     257          60 :         for (descr = descriptors; descr->name != NULL && !ctx->err.has_error; descr++) {
     258          42 :                 if (zend_hash_find(Z_ARRVAL_P(container),
     259             :                                 descr->name, descr->name_size, (void**)&elem) == SUCCESS) {
     260             : 
     261          33 :                         if (descr->from_zval == NULL) {
     262           0 :                                 do_from_zval_err(ctx, "No information on how to convert value "
     263             :                                                 "of key '%s'", descr->name);
     264           0 :                                 break;
     265             :                         }
     266             : 
     267          33 :                         zend_llist_add_element(&ctx->keys, (void*)&descr->name);
     268          33 :                         descr->from_zval(*elem, ((char*)structure) + descr->field_offset, ctx);
     269          33 :                         zend_llist_remove_tail(&ctx->keys);
     270             : 
     271           9 :                 } else if (descr->required) {
     272           1 :                         do_from_zval_err(ctx, "The key '%s' is required", descr->name);
     273           1 :                         break;
     274             :                 }
     275             :         }
     276          19 : }
     277          14 : 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          62 :         for (descr = descriptors; descr->name != NULL && !ctx->err.has_error; descr++) {
     288             :                 zval *new_zv;
     289             : 
     290          48 :                 if (descr->to_zval == NULL) {
     291           0 :                         do_to_zval_err(ctx, "No information on how to convert native "
     292             :                                         "field into value for key '%s'", descr->name);
     293           0 :                         break;
     294             :                 }
     295             : 
     296          48 :                 ALLOC_INIT_ZVAL(new_zv);
     297          48 :                 add_assoc_zval_ex(zarr, descr->name, descr->name_size, new_zv);
     298             : 
     299          48 :                 zend_llist_add_element(&ctx->keys, (void*)&descr->name);
     300          48 :                 descr->to_zval(structure + descr->field_offset, new_zv, ctx);
     301          48 :                 zend_llist_remove_tail(&ctx->keys);
     302             :         }
     303          14 : }
     304             : 
     305             : /* CONVERSIONS for integers */
     306          16 : static long from_zval_integer_common(const zval *arr_value, ser_context *ctx)
     307             : {
     308          16 :         long ret = 0;
     309          16 :         zval lzval = zval_used_for_init;
     310             : 
     311          16 :         if (Z_TYPE_P(arr_value) != IS_LONG) {
     312           0 :                 ZVAL_COPY_VALUE(&lzval, arr_value);
     313             :                 zval_copy_ctor(&lzval);
     314           0 :                 arr_value = &lzval;
     315             :         }
     316             : 
     317          16 :         switch (Z_TYPE_P(arr_value)) {
     318             :         case IS_LONG:
     319             : long_case:
     320          16 :                 ret = Z_LVAL_P(arr_value);
     321          16 :                 break;
     322             : 
     323             :         /* if not long we're operating on lzval */
     324             :         case IS_DOUBLE:
     325             : double_case:
     326           0 :                 convert_to_long(&lzval);
     327           0 :                 goto long_case;
     328             : 
     329             :         case IS_OBJECT:
     330             :         case IS_STRING: {
     331             :                 long lval;
     332             :                 double dval;
     333             : 
     334           0 :                 convert_to_string(&lzval);
     335             : 
     336           0 :                 switch (is_numeric_string(Z_STRVAL(lzval), Z_STRLEN(lzval), &lval, &dval, 0)) {
     337             :                 case IS_DOUBLE:
     338             :                         zval_dtor(&lzval);
     339           0 :                         Z_TYPE(lzval) = IS_DOUBLE;
     340           0 :                         Z_DVAL(lzval) = dval;
     341           0 :                         goto double_case;
     342             : 
     343             :                 case IS_LONG:
     344             :                         zval_dtor(&lzval);
     345           0 :                         Z_TYPE(lzval) = IS_LONG;
     346           0 :                         Z_LVAL(lzval) = lval;
     347           0 :                         goto long_case;
     348             :                 }
     349             : 
     350             :                 /* if we get here, we don't have a numeric string */
     351           0 :                 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           0 :                 break;
     354             :         }
     355             : 
     356             :         default:
     357           0 :                 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          16 :         return ret;
     365             : }
     366           7 : void from_zval_write_int(const zval *arr_value, char *field, ser_context *ctx)
     367             : {
     368             :         long lval;
     369             :         int ival;
     370             : 
     371           7 :         lval = from_zval_integer_common(arr_value, ctx);
     372           7 :         if (ctx->err.has_error) {
     373           0 :                 return;
     374             :         }
     375             : 
     376           7 :         if (lval > INT_MAX || lval < INT_MIN) {
     377           0 :                 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
     378             :                                 "for a native int");
     379           0 :                 return;
     380             :         }
     381             : 
     382           7 :         ival = (int)lval;
     383           7 :         memcpy(field, &ival, sizeof(ival));
     384             : }
     385           4 : 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           4 :         lval = from_zval_integer_common(arr_value, ctx);
     391           4 :         if (ctx->err.has_error) {
     392           0 :                 return;
     393             :         }
     394             : 
     395           4 :         if (sizeof(long) > sizeof(uint32_t) && (lval < 0 || lval > 0xFFFFFFFF)) {
     396           0 :                 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
     397             :                                 "for an unsigned 32-bit integer");
     398           0 :                 return;
     399             :         }
     400             : 
     401           4 :         ival = (uint32_t)lval;
     402           4 :         memcpy(field, &ival, sizeof(ival));
     403             : }
     404           1 : 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           1 :         lval = from_zval_integer_common(arr_value, ctx);
     410           1 :         if (ctx->err.has_error) {
     411           0 :                 return;
     412             :         }
     413             : 
     414           1 :         if (lval < 0 || lval > 0xFFFF) {
     415           0 :                 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
     416             :                                 "for an unsigned 16-bit integer");
     417           0 :                 return;
     418             :         }
     419             : 
     420           1 :         ival = htons((uint16_t)lval);
     421           1 :         memcpy(field, &ival, sizeof(ival));
     422             : }
     423           0 : 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           0 :         lval = from_zval_integer_common(arr_value, ctx);
     429           0 :         if (ctx->err.has_error) {
     430           0 :                 return;
     431             :         }
     432             : 
     433           0 :         if (lval < 0 || lval > (sa_family_t)-1) { /* sa_family_t is unsigned */
     434           0 :                 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
     435             :                                 "for a sa_family_t value");
     436           0 :                 return;
     437             :         }
     438             : 
     439           0 :         ival = (sa_family_t)lval;
     440           0 :         memcpy(field, &ival, sizeof(ival));
     441             : }
     442           0 : 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           0 :         lval = from_zval_integer_common(arr_value, ctx);
     448           0 :         if (ctx->err.has_error) {
     449           0 :                 return;
     450             :         }
     451             : 
     452           0 :         if (lval < 0 || (pid_t)lval != lval) { /* pid_t is signed */
     453           0 :                 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
     454             :                                 "for a pid_t value");
     455           0 :                 return;
     456             :         }
     457             : 
     458           0 :         ival = (pid_t)lval;
     459           0 :         memcpy(field, &ival, sizeof(ival));
     460             : }
     461           0 : 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           0 :         lval = from_zval_integer_common(arr_value, ctx);
     467           0 :         if (ctx->err.has_error) {
     468           0 :                 return;
     469             :         }
     470             : 
     471             :         /* uid_t can be signed or unsigned (generally unsigned) */
     472             :         if ((uid_t)-1 > (uid_t)0) {
     473           0 :                 if (sizeof(long) > sizeof(uid_t) && (lval < 0 || (uid_t)lval != lval)) {
     474           0 :                         do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
     475             :                                         "for a uid_t value");
     476           0 :                         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           0 :         ival = (uid_t)lval;
     487           0 :         memcpy(field, &ival, sizeof(ival));
     488             : }
     489             : 
     490          15 : void to_zval_read_int(const char *data, zval *zv, res_context *ctx)
     491             : {
     492             :         int ival;
     493          15 :         memcpy(&ival, data, sizeof(ival));
     494             : 
     495          15 :         ZVAL_LONG(zv, (long)ival);
     496          15 : }
     497           2 : static void to_zval_read_unsigned(const char *data, zval *zv, res_context *ctx)
     498             : {
     499             :         unsigned ival;
     500           2 :         memcpy(&ival, data, sizeof(ival));
     501             : 
     502           2 :         ZVAL_LONG(zv, (long)ival);
     503           2 : }
     504           2 : static void to_zval_read_net_uint16(const char *data, zval *zv, res_context *ctx)
     505             : {
     506             :         uint16_t ival;
     507           2 :         memcpy(&ival, data, sizeof(ival));
     508             : 
     509           2 :         ZVAL_LONG(zv, (long)ntohs(ival));
     510           2 : }
     511           4 : static void to_zval_read_uint32(const char *data, zval *zv, res_context *ctx)
     512             : {
     513             :         uint32_t ival;
     514           4 :         memcpy(&ival, data, sizeof(ival));
     515             : 
     516           4 :         ZVAL_LONG(zv, (long)ival);
     517           4 : }
     518           2 : static void to_zval_read_sa_family(const char *data, zval *zv, res_context *ctx)
     519             : {
     520             :         sa_family_t ival;
     521           2 :         memcpy(&ival, data, sizeof(ival));
     522             : 
     523           2 :         ZVAL_LONG(zv, (long)ival);
     524           2 : }
     525           1 : static void to_zval_read_pid_t(const char *data, zval *zv, res_context *ctx)
     526             : {
     527             :         pid_t ival;
     528           1 :         memcpy(&ival, data, sizeof(ival));
     529             : 
     530           1 :         ZVAL_LONG(zv, (long)ival);
     531           1 : }
     532           2 : static void to_zval_read_uid_t(const char *data, zval *zv, res_context *ctx)
     533             : {
     534             :         uid_t ival;
     535           2 :         memcpy(&ival, data, sizeof(ival));
     536             : 
     537           2 :         ZVAL_LONG(zv, (long)ival);
     538           2 : }
     539             : 
     540             : /* CONVERSIONS for sockaddr */
     541           0 : static void from_zval_write_sin_addr(const zval *zaddr_str, char *inaddr, ser_context *ctx)
     542             : {
     543             :         int                                     res;
     544           0 :         struct sockaddr_in      saddr = {0};
     545           0 :         zval                            lzval = zval_used_for_init;
     546             :         TSRMLS_FETCH();
     547             : 
     548           0 :         if (Z_TYPE_P(zaddr_str) != IS_STRING) {
     549           0 :                 ZVAL_COPY_VALUE(&lzval, zaddr_str);
     550             :                 zval_copy_ctor(&lzval);
     551           0 :                 convert_to_string(&lzval);
     552           0 :                 zaddr_str = &lzval;
     553             :         }
     554             : 
     555           0 :         res = php_set_inet_addr(&saddr, Z_STRVAL_P(zaddr_str), ctx->sock TSRMLS_CC);
     556           0 :         if (res) {
     557           0 :                 memcpy(inaddr, &saddr.sin_addr, sizeof saddr.sin_addr);
     558             :         } else {
     559             :                 /* error already emitted, but let's emit another more relevant */
     560           0 :                 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           0 : }
     566           0 : static void to_zval_read_sin_addr(const char *data, zval *zv, res_context *ctx)
     567             : {
     568           0 :         const struct in_addr *addr = (const struct in_addr *)data;
     569           0 :         socklen_t size = INET_ADDRSTRLEN;
     570             : 
     571           0 :         Z_TYPE_P(zv) = IS_STRING;
     572           0 :         Z_STRVAL_P(zv) = ecalloc(1, size);
     573           0 :         Z_STRLEN_P(zv) = 0;
     574             : 
     575           0 :         if (inet_ntop(AF_INET, addr, Z_STRVAL_P(zv), size) == NULL) {
     576           0 :                 do_to_zval_err(ctx, "could not convert IPv4 address to string "
     577             :                                 "(errno %d)", errno);
     578           0 :                 return;
     579             :         }
     580             : 
     581           0 :         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           0 : static void from_zval_write_sockaddr_in(const zval *container, char *sockaddr, ser_context *ctx)
     590             : {
     591           0 :         from_zval_write_aggregation(container, sockaddr, descriptors_sockaddr_in, ctx);
     592           0 : }
     593           0 : static void to_zval_read_sockaddr_in(const char *data, zval *zv, res_context *ctx)
     594             : {
     595           0 :         to_zval_read_aggregation(data, zv, descriptors_sockaddr_in, ctx);
     596           0 : }
     597             : #if HAVE_IPV6
     598           2 : static void from_zval_write_sin6_addr(const zval *zaddr_str, char *addr6, ser_context *ctx)
     599             : {
     600             :         int                                     res;
     601           2 :         struct sockaddr_in6     saddr6 = {0};
     602           2 :         zval                            lzval = zval_used_for_init;
     603             :         TSRMLS_FETCH();
     604             : 
     605           2 :         if (Z_TYPE_P(zaddr_str) != IS_STRING) {
     606           0 :                 ZVAL_COPY_VALUE(&lzval, zaddr_str);
     607             :                 zval_copy_ctor(&lzval);
     608           0 :                 convert_to_string(&lzval);
     609           0 :                 zaddr_str = &lzval;
     610             :         }
     611             : 
     612           2 :         res = php_set_inet6_addr(&saddr6,
     613             :                         Z_STRVAL_P(zaddr_str), ctx->sock TSRMLS_CC);
     614           2 :         if (res) {
     615           2 :                 memcpy(addr6, &saddr6.sin6_addr, sizeof saddr6.sin6_addr);
     616             :         } else {
     617             :                 /* error already emitted, but let's emit another more relevant */
     618           0 :                 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           2 : }
     624           4 : static void to_zval_read_sin6_addr(const char *data, zval *zv, res_context *ctx)
     625             : {
     626           4 :         const struct in6_addr *addr = (const struct in6_addr *)data;
     627           4 :         socklen_t size = INET6_ADDRSTRLEN;
     628             : 
     629           4 :         Z_TYPE_P(zv) = IS_STRING;
     630           4 :         Z_STRVAL_P(zv) = ecalloc(1, size);
     631           4 :         Z_STRLEN_P(zv) = 0;
     632             : 
     633           4 :         if (inet_ntop(AF_INET6, addr, Z_STRVAL_P(zv), size) == NULL) {
     634           0 :                 do_to_zval_err(ctx, "could not convert IPv6 address to string "
     635             :                                 "(errno %d)", errno);
     636           0 :                 return;
     637             :         }
     638             : 
     639           4 :         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           1 : static void from_zval_write_sockaddr_in6(const zval *container, char *sockaddr6, ser_context *ctx)
     650             : {
     651           1 :         from_zval_write_aggregation(container, sockaddr6, descriptors_sockaddr_in6, ctx);
     652           1 : }
     653           2 : static void to_zval_read_sockaddr_in6(const char *data, zval *zv, res_context *ctx)
     654             : {
     655           2 :         to_zval_read_aggregation(data, zv, descriptors_sockaddr_in6, ctx);
     656           2 : }
     657             : #endif /* HAVE_IPV6 */
     658           2 : static void from_zval_write_sun_path(const zval *path, char *sockaddr_un_c, ser_context *ctx)
     659             : {
     660           2 :         zval                            lzval = zval_used_for_init;
     661           2 :         struct sockaddr_un      *saddr = (struct sockaddr_un*)sockaddr_un_c;
     662             : 
     663           2 :         if (Z_TYPE_P(path) != IS_STRING) {
     664           0 :                 ZVAL_COPY_VALUE(&lzval, path);
     665             :                 zval_copy_ctor(&lzval);
     666           0 :                 convert_to_string(&lzval);
     667           0 :                 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           2 :         if (Z_STRLEN_P(path) == 0) {
     674           0 :                 do_from_zval_err(ctx, "%s", "the path is cannot be empty");
     675           0 :                 return;
     676             :         }
     677           2 :         if (Z_STRLEN_P(path) >= sizeof(saddr->sun_path)) {
     678           0 :                 do_from_zval_err(ctx, "the path is too long, the maximum permitted "
     679             :                                 "length is %ld", sizeof(saddr->sun_path) - 1);
     680           0 :                 return;
     681             :         }
     682             : 
     683           2 :         memcpy(&saddr->sun_path, Z_STRVAL_P(path), Z_STRLEN_P(path));
     684           2 :         saddr->sun_path[Z_STRLEN_P(path)] = '\0';
     685             : 
     686             :         zval_dtor(&lzval);
     687             : }
     688           0 : static void to_zval_read_sun_path(const char *data, zval *zv, res_context *ctx) {
     689           0 :         struct sockaddr_un      *saddr = (struct sockaddr_un*)data;
     690             :         char *nul_pos;
     691             : 
     692           0 :         nul_pos = memchr(&saddr->sun_path, '\0', sizeof(saddr->sun_path));
     693           0 :         if (nul_pos == NULL) {
     694           0 :                 do_to_zval_err(ctx, "could not find a NUL in the path");
     695           0 :                 return;
     696             :         }
     697             : 
     698           0 :         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           2 : static void from_zval_write_sockaddr_un(const zval *container, char *sockaddr, ser_context *ctx)
     706             : {
     707           2 :         from_zval_write_aggregation(container, sockaddr, descriptors_sockaddr_un, ctx);
     708           2 : }
     709           0 : static void to_zval_read_sockaddr_un(const char *data, zval *zv, res_context *ctx)
     710             : {
     711           0 :         to_zval_read_aggregation(data, zv, descriptors_sockaddr_un, ctx);
     712           0 : }
     713           7 : 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           7 :         if (Z_TYPE_P(container) != IS_ARRAY) {
     723           0 :                 do_from_zval_err(ctx, "%s", "expected an array here");
     724           0 :                 return;
     725             :         }
     726             : 
     727           7 :         fill_sockaddr = param_get_bool(ctx, KEY_FILL_SOCKADDR, 1);
     728             : 
     729          18 :         if (zend_hash_find(Z_ARRVAL_P(container), "family", sizeof("family"), (void**)&elem) == SUCCESS
     730          16 :                         && Z_TYPE_PP(elem) != IS_NULL) {
     731           2 :                 const char *node = "family";
     732           2 :                 zend_llist_add_element(&ctx->keys, &node);
     733           2 :                 from_zval_write_int(*elem, (char*)&family, ctx);
     734           2 :                 zend_llist_remove_tail(&ctx->keys);
     735             :         } else {
     736           5 :                 family = ctx->sock->type;
     737             :         }
     738             : 
     739           7 :         switch (family) {
     740             :         case AF_INET:
     741             :                 /* though not all OSes support sockaddr_in used in IPv6 sockets */
     742           0 :                 if (ctx->sock->type != AF_INET && ctx->sock->type != AF_INET6) {
     743           0 :                         do_from_zval_err(ctx, "the specified family (number %d) is not "
     744             :                                         "supported on this socket", family);
     745           0 :                         return;
     746             :                 }
     747           0 :                 *sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_in), ctx);
     748           0 :                 *sockaddr_len = sizeof(struct sockaddr_in);
     749           0 :                 if (fill_sockaddr) {
     750           0 :                         from_zval_write_sockaddr_in(container, (char*)*sockaddr_ptr, ctx);
     751           0 :                         (*sockaddr_ptr)->sa_family = AF_INET;
     752             :                 }
     753           0 :                 break;
     754             : 
     755             : #if HAVE_IPV6
     756             :         case AF_INET6:
     757           3 :                 if (ctx->sock->type != AF_INET6) {
     758           0 :                         do_from_zval_err(ctx, "the specified family (AF_INET6) is not "
     759             :                                         "supported on this socket");
     760           0 :                         return;
     761             :                 }
     762           3 :                 *sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_in6), ctx);
     763           3 :                 *sockaddr_len = sizeof(struct sockaddr_in6);
     764           3 :                 if (fill_sockaddr) {
     765           1 :                         from_zval_write_sockaddr_in6(container, (char*)*sockaddr_ptr, ctx);
     766           1 :                         (*sockaddr_ptr)->sa_family = AF_INET6;
     767             :                 }
     768           3 :                 break;
     769             : #endif /* HAVE_IPV6 */
     770             : 
     771             :         case AF_UNIX:
     772           4 :                 if (ctx->sock->type != AF_UNIX) {
     773           0 :                         do_from_zval_err(ctx, "the specified family (AF_UNIX) is not "
     774             :                                         "supported on this socket");
     775           0 :                         return;
     776             :                 }
     777           4 :                 *sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_un), ctx);
     778           4 :                 if (fill_sockaddr) {
     779           2 :                         struct sockaddr_un *sock_un = (struct sockaddr_un*)*sockaddr_ptr;
     780             : 
     781           2 :                         from_zval_write_sockaddr_un(container, (char*)*sockaddr_ptr, ctx);
     782           2 :                         (*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           3 :                         *sockaddr_len = offsetof(struct sockaddr_un, sun_path) +
     789           2 :                                         (sock_un->sun_path[0] == '\0'
     790             :                                         ? (1 + strlen(&sock_un->sun_path[1]))
     791           1 :                                         : strlen(sock_un->sun_path));
     792             :                 } else {
     793           2 :                         *sockaddr_len = sizeof(struct sockaddr_un);
     794             :                 }
     795           4 :                 break;
     796             : 
     797             :         default:
     798           0 :                 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           4 : static void to_zval_read_sockaddr_aux(const char *sockaddr_c, zval *zv, res_context *ctx)
     804             : {
     805           4 :         const struct sockaddr *saddr = (struct sockaddr *)sockaddr_c;
     806             : 
     807           4 :         if (saddr->sa_family == 0) {
     808           2 :                 ZVAL_NULL(zv);
     809           2 :                 return;
     810             :         }
     811             : 
     812           2 :         array_init(zv);
     813             : 
     814           2 :         switch (saddr->sa_family) {
     815             :         case AF_INET:
     816           0 :                 to_zval_read_sockaddr_in(sockaddr_c, zv, ctx);
     817           0 :                 break;
     818             : 
     819             : #if HAVE_IPV6
     820             :         case AF_INET6:
     821           2 :                 to_zval_read_sockaddr_in6(sockaddr_c, zv, ctx);
     822           2 :                 break;
     823             : #endif /* HAVE_IPV6 */
     824             : 
     825             :         case AF_UNIX:
     826           0 :                 to_zval_read_sockaddr_un(sockaddr_c, zv, ctx);
     827           0 :                 break;
     828             : 
     829             :         default:
     830           0 :                 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           2 : 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           2 :         };
     874             : 
     875           2 :         from_zval_write_aggregation(arr, (char *)&level, descriptor_level, ctx);
     876           2 :         if (ctx->err.has_error) {
     877           0 :                 return;
     878             :         }
     879           2 :         from_zval_write_aggregation(arr, (char *)&type, descriptor_type, ctx);
     880           2 :         if (ctx->err.has_error) {
     881           0 :                 return;
     882             :         }
     883             : 
     884           2 :         entry = get_ancillary_reg_entry(level, type);
     885           2 :         if (entry == NULL) {
     886           0 :                 do_from_zval_err(ctx, "cmsghdr with level %d and type %d not supported",
     887             :                                 level, type);
     888           0 :                 return;
     889             :         }
     890             : 
     891           2 :         if (entry->calc_space) {
     892             :                 zval **data_elem;
     893             :                 /* arr must be an array at this point */
     894           1 :                 if (zend_hash_find(Z_ARRVAL_P(arr), "data", sizeof("data"),
     895             :                                 (void**)&data_elem) == FAILURE) {
     896           0 :                         do_from_zval_err(ctx, "cmsghdr should have a 'data' element here");
     897           0 :                         return;
     898             :                 }
     899           1 :                 data_len = entry->calc_space(*data_elem, ctx);
     900           1 :                 if (ctx->err.has_error) {
     901           0 :                         return;
     902             :                 }
     903             :         } else {
     904           1 :                 data_len = entry->size;
     905             :         }
     906           2 :         req_space = CMSG_SPACE(data_len);
     907           2 :         space_left = *control_len - *offset;
     908             :         assert(*control_len >= *offset);
     909             : 
     910           2 :         if (space_left < req_space) {
     911           0 :                 *control_buf = safe_erealloc(*control_buf, 2, req_space, *control_len);
     912           0 :                 *control_len += 2 * req_space;
     913           0 :                 memset(*control_buf, '\0', *control_len - *offset);
     914           0 :                 memcpy(&alloc->data, *control_buf, sizeof *control_buf);
     915             :         }
     916             : 
     917           2 :         cmsghdr = (struct cmsghdr*)(((char*)*control_buf) + *offset);
     918           2 :         cmsghdr->cmsg_level  = level;
     919           2 :         cmsghdr->cmsg_type   = type;
     920           2 :         cmsghdr->cmsg_len    = CMSG_LEN(data_len);
     921             : 
     922           2 :         descriptor_data[0].from_zval = entry->from_array;
     923           2 :         from_zval_write_aggregation(arr, (char*)CMSG_DATA(cmsghdr), descriptor_data, ctx);
     924             : 
     925           2 :         *offset += req_space;
     926             : }
     927           2 : 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           2 :         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           2 :         struct msghdr           *msg = (struct msghdr*)msghdr_c;
     940             : 
     941           2 :         if (Z_TYPE_P(arr) != IS_ARRAY) {
     942           0 :                 do_from_zval_err(ctx, "%s", "expected an array here");
     943           0 :                 return;
     944             :         }
     945             : 
     946           2 :         num_elems = zend_hash_num_elements(Z_ARRVAL_P(arr));
     947           2 :         if (num_elems == 0) {
     948           0 :                 return;
     949             :         }
     950             : 
     951             :         /* estimate each message at 20 bytes */
     952           2 :         control_buf     = accounted_safe_ecalloc(num_elems, CMSG_SPACE(20), 0, ctx);
     953           2 :         alloc           = ctx->allocations.tail;
     954           2 :         control_len = (size_t)num_elems * CMSG_SPACE(20);
     955           2 :         cur_offset      = 0;
     956             : 
     957          10 :     for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos), i = 0;
     958           4 :                         !ctx->err.has_error
     959           4 :                         && zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **)&elem, &pos) == SUCCESS;
     960           2 :                         zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos)) {
     961             : 
     962           2 :                 if (snprintf(buf, sizeof(buf), "element #%u", (unsigned)i++) >= sizeof(buf)) {
     963           0 :                         memcpy(buf, "element", sizeof("element"));
     964             :                 }
     965           2 :                 zend_llist_add_element(&ctx->keys, &bufp);
     966             : 
     967           2 :                 from_zval_write_control(*elem, &control_buf, alloc, &control_len,
     968             :                                 &cur_offset, ctx);
     969             : 
     970           2 :                 zend_llist_remove_tail(&ctx->keys);
     971             :     }
     972             : 
     973           2 :     msg->msg_control = control_buf;
     974           2 :     msg->msg_controllen = cur_offset; /* not control_len, which may be larger */
     975             : }
     976           5 : static void to_zval_read_cmsg_data(const char *cmsghdr_c, zval *zv, res_context *ctx)
     977             : {
     978           5 :         const struct cmsghdr    *cmsg = (const struct cmsghdr *)cmsghdr_c;
     979             :         ancillary_reg_entry             *entry;
     980             :         size_t                                  len,
     981           5 :                                                         *len_p = &len;
     982             : 
     983           5 :         entry = get_ancillary_reg_entry(cmsg->cmsg_level, cmsg->cmsg_type);
     984           5 :         if (entry == NULL) {
     985           0 :                 do_to_zval_err(ctx, "cmsghdr with level %d and type %d not supported",
     986             :                                 cmsg->cmsg_level, cmsg->cmsg_type);
     987           0 :                 return;
     988             :         }
     989           5 :         if (CMSG_LEN(entry->size) > cmsg->cmsg_len) {
     990           0 :                 do_to_zval_err(ctx, "the cmsghdr structure is unexpectedly small; "
     991             :                                 "expected a length of at least %ld, but got %ld",
     992           0 :                                 (long)CMSG_LEN(entry->size), (long)cmsg->cmsg_len);
     993           0 :                 return;
     994             :         }
     995             : 
     996           5 :         len = (size_t)cmsg->cmsg_len; /* use another var because type of cmsg_len varies */
     997           5 :         if (zend_hash_add(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN),
     998             :                         &len_p, sizeof(len_p), NULL) == FAILURE) {
     999           0 :                 do_to_zval_err(ctx, "%s", "could not set parameter " KEY_CMSG_LEN);
    1000           0 :                 return;
    1001             :         }
    1002             : 
    1003           5 :         entry->to_array((const char *)CMSG_DATA(cmsg), zv, ctx);
    1004             : 
    1005           5 :         zend_hash_del(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN));
    1006             : }
    1007           5 : 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           5 :         array_init_size(zv, 3);
    1018           5 :         to_zval_read_aggregation(cmsghdr_c, zv, descriptors, ctx);
    1019           5 : }
    1020           4 : static void to_zval_read_control_array(const char *msghdr_c, zval *zv, res_context *ctx)
    1021             : {
    1022           4 :         struct msghdr   *msg = (struct msghdr *)msghdr_c;
    1023             :         struct cmsghdr  *cmsg;
    1024             :         char                    buf[sizeof("element #4294967295")];
    1025           4 :         char                    *bufp = buf;
    1026           4 :         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           4 :         array_init(zv);
    1036             : 
    1037          18 :         for (cmsg = CMSG_FIRSTHDR(msg);
    1038           5 :                         cmsg != NULL && !ctx->err.has_error;
    1039           5 :                         cmsg = CMSG_NXTHDR(msg, cmsg)) {
    1040             :                 zval *elem;
    1041             : 
    1042           5 :                 ALLOC_INIT_ZVAL(elem);
    1043           5 :                 add_next_index_zval(zv, elem);
    1044             : 
    1045           5 :                 if (snprintf(buf, sizeof(buf), "element #%u", (unsigned)i++) >= sizeof(buf)) {
    1046           0 :                         memcpy(buf, "element", sizeof("element"));
    1047             :                 }
    1048           5 :                 zend_llist_add_element(&ctx->keys, &bufp);
    1049             : 
    1050           5 :                 to_zval_read_control((const char *)cmsg, elem, ctx);
    1051             : 
    1052           5 :                 zend_llist_remove_tail(&ctx->keys);
    1053             :         }
    1054           4 : }
    1055             : 
    1056             : /* CONVERSIONS for msghdr */
    1057           7 : 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           7 :         struct msghdr   *msghdr = (struct msghdr *)msghdr_c;
    1062             : 
    1063           7 :         from_zval_write_sockaddr_aux(zname_arr, &sockaddr, &sockaddr_len, ctx);
    1064             : 
    1065           7 :         msghdr->msg_name = sockaddr;
    1066           7 :         msghdr->msg_namelen = sockaddr_len;
    1067           7 : }
    1068           4 : static void to_zval_read_name(const char *sockaddr_p, zval *zv, res_context *ctx)
    1069             : {
    1070           4 :         void *name = (void*)*(void**)sockaddr_p;
    1071           4 :         if (name == NULL) {
    1072           0 :                 ZVAL_NULL(zv);
    1073             :         } else {
    1074           4 :                 to_zval_read_sockaddr_aux(name, zv, ctx);
    1075             :         }
    1076           4 : }
    1077           4 : static void from_zval_write_msghdr_buffer_size(const zval *elem, char *msghdr_c, ser_context *ctx)
    1078             : {
    1079             :         long lval;
    1080           4 :         struct msghdr *msghdr = (struct msghdr *)msghdr_c;
    1081             : 
    1082           4 :         lval = from_zval_integer_common(elem, ctx);
    1083           4 :         if (ctx->err.has_error) {
    1084           0 :                 return;
    1085             :         }
    1086             : 
    1087           4 :         if (lval < 0 || lval > MAX_USER_BUFF_SIZE) {
    1088           0 :                 do_from_zval_err(ctx, "the buffer size must be between 1 and %ld; "
    1089             :                                 "given %ld", (long)MAX_USER_BUFF_SIZE, lval);
    1090           0 :                 return;
    1091             :         }
    1092             : 
    1093           4 :         msghdr->msg_iovlen = 1;
    1094           4 :         msghdr->msg_iov = accounted_emalloc(sizeof(*msghdr->msg_iov) * 1, ctx);
    1095           4 :         msghdr->msg_iov[0].iov_base = accounted_emalloc((size_t)lval, ctx);
    1096           4 :         msghdr->msg_iov[0].iov_len = (size_t)lval;
    1097             : }
    1098          12 : static void from_zval_write_iov_array_aux(zval **elem, unsigned i, void **args, ser_context *ctx)
    1099             : {
    1100          12 :         struct msghdr   *msg = args[0];
    1101             :         size_t                  len;
    1102             : 
    1103          12 :         zval_add_ref(elem);
    1104          12 :         convert_to_string_ex(elem);
    1105             : 
    1106          12 :         len = Z_STRLEN_PP(elem);
    1107          12 :         msg->msg_iov[i - 1].iov_base = accounted_emalloc(len, ctx);
    1108          12 :         msg->msg_iov[i - 1].iov_len = len;
    1109          12 :         memcpy(msg->msg_iov[i - 1].iov_base, Z_STRVAL_PP(elem), len);
    1110             : 
    1111          12 :         zval_ptr_dtor(elem);
    1112          12 : }
    1113           4 : static void from_zval_write_iov_array(const zval *arr, char *msghdr_c, ser_context *ctx)
    1114             : {
    1115             :         int                             num_elem;
    1116           4 :         struct msghdr   *msg = (struct msghdr*)msghdr_c;
    1117             : 
    1118           4 :         if (Z_TYPE_P(arr) != IS_ARRAY) {
    1119           0 :                 do_from_zval_err(ctx, "%s", "expected an array here");
    1120           0 :                 return;
    1121             :         }
    1122             : 
    1123           4 :         num_elem = zend_hash_num_elements(Z_ARRVAL_P(arr));
    1124           4 :         if (num_elem == 0) {
    1125           0 :                 return;
    1126             :         }
    1127             : 
    1128           4 :         msg->msg_iov = accounted_safe_ecalloc(num_elem, sizeof *msg->msg_iov, 0, ctx);
    1129           4 :         msg->msg_iovlen = (size_t)num_elem;
    1130             : 
    1131           4 :     from_array_iterate(arr, from_zval_write_iov_array_aux, (void**)&msg, ctx);
    1132             : }
    1133           4 : static void from_zval_write_controllen(const zval *elem, char *msghdr_c, ser_context *ctx)
    1134             : {
    1135           4 :         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           4 :         from_zval_write_uint32(elem, (char*)&len, ctx);
    1142           4 :         if (!ctx->err.has_error && len == 0) {
    1143           0 :                 do_from_zval_err(ctx, "controllen cannot be 0");
    1144           0 :                 return;
    1145             :         }
    1146           4 :         msghdr->msg_control = accounted_emalloc(len, ctx);
    1147           4 :         msghdr->msg_controllen = len;
    1148             : }
    1149           4 : 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           4 :         from_zval_write_aggregation(container, msghdr_c, descriptors, ctx);
    1159           4 : }
    1160           4 : 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           4 :         struct msghdr   *msghdr = (struct msghdr *)msghdr_c;
    1183           4 :         const int               falsev = 0,
    1184           4 :                                         *falsevp = &falsev;
    1185             : 
    1186           4 :         if (zend_hash_add(&ctx->params, KEY_FILL_SOCKADDR, sizeof(KEY_FILL_SOCKADDR),
    1187             :                         (void*)&falsevp, sizeof(falsevp), NULL) == FAILURE) {
    1188           0 :                 do_from_zval_err(ctx, "could not add fill_sockaddr; this is a bug");
    1189           0 :                 return;
    1190             :         }
    1191             : 
    1192           4 :         from_zval_write_aggregation(container, msghdr_c, descriptors, ctx);
    1193             : 
    1194           4 :         zend_hash_del(&ctx->params, KEY_FILL_SOCKADDR, sizeof(KEY_FILL_SOCKADDR));
    1195           4 :         if (ctx->err.has_error) {
    1196           0 :                 return;
    1197             :         }
    1198             : 
    1199           4 :         if (msghdr->msg_iovlen == 0) {
    1200           0 :                 msghdr->msg_iovlen = 1;
    1201           0 :                 msghdr->msg_iov = accounted_emalloc(sizeof(*msghdr->msg_iov) * 1, ctx);
    1202           0 :                 msghdr->msg_iov[0].iov_base = accounted_emalloc((size_t)DEFAULT_BUFF_SIZE, ctx);
    1203           0 :                 msghdr->msg_iov[0].iov_len = (size_t)DEFAULT_BUFF_SIZE;
    1204             :         }
    1205             : }
    1206             : 
    1207           4 : static void to_zval_read_iov(const char *msghdr_c, zval *zv, res_context *ctx)
    1208             : {
    1209           4 :         const struct msghdr     *msghdr = (const struct msghdr *)msghdr_c;
    1210           4 :         size_t                          iovlen = msghdr->msg_iovlen;
    1211             :         ssize_t                         **recvmsg_ret,
    1212             :                                                 bytes_left;
    1213             :         uint                            i;
    1214             : 
    1215           4 :         if (iovlen > UINT_MAX) {
    1216           0 :                 do_to_zval_err(ctx, "unexpectedly large value for iov_len: %lu",
    1217             :                                 (unsigned long)iovlen);
    1218             :         }
    1219           4 :         array_init_size(zv, (uint)iovlen);
    1220             : 
    1221           4 :         if (zend_hash_find(&ctx->params, KEY_RECVMSG_RET, sizeof(KEY_RECVMSG_RET),
    1222             :                         (void**)&recvmsg_ret) == FAILURE) {
    1223           0 :                 do_to_zval_err(ctx, "recvmsg_ret not found in params. This is a bug");
    1224           0 :                 return;
    1225             :         }
    1226           4 :         bytes_left = **recvmsg_ret;
    1227             : 
    1228           8 :         for (i = 0; bytes_left > 0 && i < (uint)iovlen; i++) {
    1229             :                 zval    *elem;
    1230           4 :                 size_t  len             = MIN(msghdr->msg_iov[i].iov_len, (size_t)bytes_left);
    1231           4 :                 char    *buf    = safe_emalloc(1, len, 1);
    1232             : 
    1233           4 :                 MAKE_STD_ZVAL(elem);
    1234           4 :                 memcpy(buf, msghdr->msg_iov[i].iov_base, len);
    1235           4 :                 buf[len] = '\0';
    1236             : 
    1237           4 :                 ZVAL_STRINGL(elem, buf, len, 0);
    1238           4 :                 add_next_index_zval(zv, elem);
    1239           4 :                 bytes_left -= len;
    1240             :         }
    1241             : }
    1242           4 : 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           4 :         array_init_size(zv, 4);
    1253             : 
    1254           4 :         to_zval_read_aggregation(msghdr_c, zv, descriptors, ctx);
    1255           4 : }
    1256             : 
    1257             : /* CONVERSIONS for if_index */
    1258           1 : static void from_zval_write_ifindex(const zval *zv, char *uinteger, ser_context *ctx)
    1259             : {
    1260           1 :         unsigned        ret = 0;
    1261           1 :         zval            lzval = zval_used_for_init;
    1262             : 
    1263           1 :         if (Z_TYPE_P(zv) == IS_LONG) {
    1264           1 :                 if (Z_LVAL_P(zv) < 0 || Z_LVAL_P(zv) > UINT_MAX) { /* allow 0 (unspecified interface) */
    1265           0 :                         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           1 :                         ret = (unsigned)Z_LVAL_P(zv);
    1269             :                 }
    1270             :         } else {
    1271           0 :                 if (Z_TYPE_P(zv) != IS_STRING) {
    1272           0 :                         ZVAL_COPY_VALUE(&lzval, zv);
    1273             :                         zval_copy_ctor(&lzval);
    1274           0 :                         convert_to_string(&lzval);
    1275           0 :                         zv = &lzval;
    1276             :                 }
    1277             : 
    1278             : #if HAVE_IF_NAMETOINDEX
    1279           0 :                 ret = if_nametoindex(Z_STRVAL_P(zv));
    1280           0 :                 if (ret == 0) {
    1281           0 :                         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           1 :         if (!ctx->err.has_error) {
    1312           1 :                 memcpy(uinteger, &ret, sizeof(ret));
    1313             :         }
    1314             : 
    1315             :         zval_dtor(&lzval);
    1316           1 : }
    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           2 : void from_zval_write_in6_pktinfo(const zval *container, char *in6_pktinfo_c, ser_context *ctx)
    1326             : {
    1327           2 :         from_zval_write_aggregation(container, in6_pktinfo_c, descriptors_in6_pktinfo, ctx);
    1328           2 : }
    1329           2 : void to_zval_read_in6_pktinfo(const char *data, zval *zv, res_context *ctx)
    1330             : {
    1331           2 :         array_init_size(zv, 2);
    1332             : 
    1333           2 :         to_zval_read_aggregation(data, zv, descriptors_in6_pktinfo, ctx);
    1334           2 : }
    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           0 : void from_zval_write_ucred(const zval *container, char *ucred_c, ser_context *ctx)
    1347             : {
    1348           0 :         from_zval_write_aggregation(container, ucred_c, descriptors_ucred, ctx);
    1349           0 : }
    1350           1 : void to_zval_read_ucred(const char *data, zval *zv, res_context *ctx)
    1351             : {
    1352           1 :         array_init_size(zv, 3);
    1353             : 
    1354           1 :         to_zval_read_aggregation(data, zv, descriptors_ucred, ctx);
    1355           1 : }
    1356             : #endif
    1357             : 
    1358             : /* CONVERSIONS for SCM_RIGHTS */
    1359             : #ifdef SCM_RIGHTS
    1360           1 : size_t calculate_scm_rights_space(const zval *arr, ser_context *ctx)
    1361             : {
    1362             :         int num_elems;
    1363             : 
    1364           1 :         if (Z_TYPE_P(arr) != IS_ARRAY) {
    1365           0 :                 do_from_zval_err(ctx, "%s", "expected an array here");
    1366           0 :                 return (size_t)-1;
    1367             :         }
    1368             : 
    1369           1 :         num_elems = zend_hash_num_elements(Z_ARRVAL_P(arr));
    1370           1 :         if (num_elems == 0) {
    1371           0 :                 do_from_zval_err(ctx, "%s", "expected at least one element in this array");
    1372           0 :                 return (size_t)-1;
    1373             :         }
    1374             : 
    1375           1 :         return zend_hash_num_elements(Z_ARRVAL_P(arr)) * sizeof(int);
    1376             : }
    1377           4 : static void from_zval_write_fd_array_aux(zval **elem, unsigned i, void **args, ser_context *ctx)
    1378             : {
    1379           4 :         int *iarr = args[0];
    1380             :         TSRMLS_FETCH();
    1381             : 
    1382           4 :         if (Z_TYPE_PP(elem) == IS_RESOURCE) {
    1383             :                 php_stream *stream;
    1384             :                 php_socket *sock;
    1385             : 
    1386           4 :                 ZEND_FETCH_RESOURCE_NO_RETURN(sock, php_socket *, elem, -1,
    1387             :                                 NULL, php_sockets_le_socket());
    1388           4 :                 if (sock) {
    1389           1 :                         iarr[i] = sock->bsd_socket;
    1390           1 :                         return;
    1391             :                 }
    1392             : 
    1393           3 :                 ZEND_FETCH_RESOURCE2_NO_RETURN(stream, php_stream *, elem, -1,
    1394             :                                 NULL, php_file_le_stream(), php_file_le_pstream());
    1395           3 :                 if (stream == NULL) {
    1396           0 :                         do_from_zval_err(ctx, "resource is not a stream or a socket");
    1397           0 :                         return;
    1398             :                 }
    1399             : 
    1400           3 :                 if (php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&iarr[i - 1],
    1401             :                                 REPORT_ERRORS) == FAILURE) {
    1402           0 :                         do_from_zval_err(ctx, "cast stream to file descriptor failed");
    1403           0 :                         return;
    1404             :                 }
    1405             :         } else {
    1406           0 :                 do_from_zval_err(ctx, "expected a resource variable");
    1407             :         }
    1408             : }
    1409           1 : void from_zval_write_fd_array(const zval *arr, char *int_arr, ser_context *ctx)
    1410             : {
    1411           1 :         if (Z_TYPE_P(arr) != IS_ARRAY) {
    1412           0 :                 do_from_zval_err(ctx, "%s", "expected an array here");
    1413           0 :                 return;
    1414             :         }
    1415             : 
    1416           1 :    from_array_iterate(arr, &from_zval_write_fd_array_aux, (void**)&int_arr, ctx);
    1417             : }
    1418           1 : 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           1 :         struct cmsghdr  *dummy_cmsg = 0;
    1424             :         size_t                  data_offset;
    1425             :         TSRMLS_FETCH();
    1426             : 
    1427           1 :         data_offset = (unsigned char *)CMSG_DATA(dummy_cmsg)
    1428             :                         - (unsigned char *)dummy_cmsg;
    1429             : 
    1430           1 :         if (zend_hash_find(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN),
    1431             :                         (void **)&cmsg_len) == FAILURE) {
    1432           0 :                 do_to_zval_err(ctx, "could not get value of parameter " KEY_CMSG_LEN);
    1433           0 :                 return;
    1434             :         }
    1435             : 
    1436           1 :         if (**cmsg_len < data_offset) {
    1437           0 :                 do_to_zval_err(ctx, "length of cmsg is smaller than its data member "
    1438           0 :                                 "offset (%ld vs %ld)", (long)**cmsg_len, (long)data_offset);
    1439           0 :                 return;
    1440             :         }
    1441           1 :         num_elems = (**cmsg_len - data_offset) / sizeof(int);
    1442             : 
    1443           1 :         array_init_size(zv, num_elems);
    1444             : 
    1445           5 :         for (i = 0; i < num_elems; i++) {
    1446             :                 zval            *elem;
    1447             :                 int                     fd;
    1448             :                 struct stat     statbuf;
    1449             : 
    1450           4 :                 MAKE_STD_ZVAL(elem);
    1451             : 
    1452           4 :                 fd = *((int *)data + i);
    1453             : 
    1454             :                 /* determine whether we have a socket */
    1455           4 :                 if (fstat(fd, &statbuf) == -1) {
    1456           0 :                         do_to_zval_err(ctx, "error creating resource for received file "
    1457             :                                         "descriptor %d: fstat() call failed with errno %d", fd, errno);
    1458           0 :                         efree(elem);
    1459           0 :                         return;
    1460             :                 }
    1461           4 :                 if (S_ISSOCK(statbuf.st_mode)) {
    1462           0 :                         php_socket *sock = socket_import_file_descriptor(fd TSRMLS_CC);
    1463           0 :                         zend_register_resource(elem, sock, php_sockets_le_socket() TSRMLS_CC);
    1464             :                 } else {
    1465           4 :                         php_stream *stream = php_stream_fopen_from_fd(fd, "rw", NULL);
    1466           4 :                         php_stream_to_zval(stream, elem);
    1467             :                 }
    1468             : 
    1469           4 :                 add_next_index_zval(zv, elem);
    1470             :         }
    1471             : }
    1472             : #endif
    1473             : 
    1474             : /* ENTRY POINT for conversions */
    1475          47 : static void free_from_zval_allocation(void *alloc_ptr_ptr)
    1476             : {
    1477          47 :         efree(*(void**)alloc_ptr_ptr);
    1478          47 : }
    1479          10 : 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          10 :         ser_context ctx = {{0}};
    1488          10 :         char *structure = NULL;
    1489             : 
    1490          10 :         *allocations = NULL;
    1491             : 
    1492          10 :         if (err->has_error) {
    1493           0 :                 return NULL;
    1494             :         }
    1495             : 
    1496          10 :         zend_hash_init(&ctx.params, 8, NULL, NULL, 0);
    1497          10 :         zend_llist_init(&ctx.keys, sizeof(const char *), NULL, 0);
    1498          10 :         zend_llist_init(&ctx.allocations, sizeof(void *), &free_from_zval_allocation, 0);
    1499          10 :         ctx.sock = sock;
    1500             : 
    1501          10 :         structure = ecalloc(1, struct_size);
    1502             : 
    1503          10 :         zend_llist_add_element(&ctx.keys, &top_name);
    1504          10 :         zend_llist_add_element(&ctx.allocations, &structure);
    1505             : 
    1506             :         /* main call */
    1507          10 :         writer(container, structure, &ctx);
    1508             : 
    1509          10 :         if (ctx.err.has_error) {
    1510           1 :                 zend_llist_destroy(&ctx.allocations); /* deallocates structure as well */
    1511           1 :                 structure = NULL;
    1512           1 :                 *err = ctx.err;
    1513             :         } else {
    1514           9 :                 *allocations = emalloc(sizeof **allocations);
    1515           9 :                 **allocations = ctx.allocations;
    1516             :         }
    1517             : 
    1518          10 :         zend_llist_destroy(&ctx.keys);
    1519          10 :         zend_hash_destroy(&ctx.params);
    1520             : 
    1521          10 :         return structure;
    1522             : }
    1523           4 : 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           4 :         res_context                             ctx = {{0}, {0}};
    1530             :         const struct key_value  *kv;
    1531           4 :         zval                                    *zv = NULL;
    1532             : 
    1533           4 :         if (err->has_error) {
    1534           0 :                 return NULL;
    1535             :         }
    1536             : 
    1537           4 :         ALLOC_INIT_ZVAL(zv);
    1538             : 
    1539           4 :         zend_llist_init(&ctx.keys, sizeof(const char *), NULL, 0);
    1540           4 :         zend_llist_add_element(&ctx.keys, &top_name);
    1541             : 
    1542           4 :         zend_hash_init(&ctx.params, 8, NULL, NULL, 0);
    1543           8 :         for (kv = key_value_pairs; kv->key != NULL; kv++) {
    1544           4 :                 zend_hash_update(&ctx.params, kv->key, kv->key_size,
    1545             :                                 (void*)&kv->value, sizeof(kv->value), NULL);
    1546             :         }
    1547             : 
    1548             :         /* main call */
    1549           4 :         reader(structure, zv, &ctx);
    1550             : 
    1551           4 :         if (ctx.err.has_error) {
    1552           0 :                 zval_ptr_dtor(&zv);
    1553           0 :                 zv = NULL;
    1554           0 :                 *err = ctx.err;
    1555             :         }
    1556             : 
    1557           4 :         zend_llist_destroy(&ctx.keys);
    1558           4 :         zend_hash_destroy(&ctx.params);
    1559             : 
    1560           4 :         return zv;
    1561             : }

Generated by: LCOV version 1.10

Generated at Tue, 22 Jul 2014 01:33:18 +0000 (7 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.