Пример #1
0
		/* error already emitted, but let's emit another more relevant */
		do_from_zval_err(ctx, "could not resolve address '%s' to get an AF_INET6 "
				"address", Z_STRVAL_P(zaddr_str));
	}

	zend_string_release(addr_str);
}
static void to_zval_read_sin6_addr(const char *data, zval *zv, res_context *ctx)
{
	const struct in6_addr *addr = (const struct in6_addr *)data;
	socklen_t size = INET6_ADDRSTRLEN;
	zend_string *str = zend_string_alloc(size - 1, 0);

	memset(str->val, '\0', size);

	ZVAL_NEW_STR(zv, str);

	if (inet_ntop(AF_INET6, addr, Z_STRVAL_P(zv), size) == NULL) {
		do_to_zval_err(ctx, "could not convert IPv6 address to string "
				"(errno %d)", errno);
		return;
	}

	Z_STRLEN_P(zv) = strlen(Z_STRVAL_P(zv));
}
static const field_descriptor descriptors_sockaddr_in6[] = {
		{"family", sizeof("family"), 0, offsetof(struct sockaddr_in6, sin6_family), from_zval_write_sa_family, to_zval_read_sa_family},
		{"addr", sizeof("addr"), 0, offsetof(struct sockaddr_in6, sin6_addr), from_zval_write_sin6_addr, to_zval_read_sin6_addr},
		{"port", sizeof("port"), 0, offsetof(struct sockaddr_in6, sin6_port), from_zval_write_net_uint16, to_zval_read_net_uint16},
		{"flowinfo", sizeof("flowinfo"), 0, offsetof(struct sockaddr_in6, sin6_flowinfo), from_zval_write_uint32, to_zval_read_uint32},
		{"scope_id", sizeof("scope_id"), 0, offsetof(struct sockaddr_in6, sin6_scope_id), from_zval_write_uint32, to_zval_read_uint32},
		{0}
};
static void from_zval_write_sockaddr_in6(const zval *container, char *sockaddr6, ser_context *ctx)
{
	from_zval_write_aggregation(container, sockaddr6, descriptors_sockaddr_in6, ctx);
}
static void to_zval_read_sockaddr_in6(const char *data, zval *zv, res_context *ctx)
{
	to_zval_read_aggregation(data, zv, descriptors_sockaddr_in6, ctx);
}
#endif /* HAVE_IPV6 */
static void from_zval_write_sun_path(const zval *path, char *sockaddr_un_c, ser_context *ctx)
{
	zend_string			*path_str;
	struct sockaddr_un	*saddr = (struct sockaddr_un*)sockaddr_un_c;

	path_str = zval_get_string((zval *) path);

	/* code in this file relies on the path being nul terminated, even though
	 * this is not required, at least on linux for abstract paths. It also
	 * assumes that the path is not empty */
	if (path_str->len == 0) {
		do_from_zval_err(ctx, "%s", "the path is cannot be empty");
		return;
	}
	if (path_str->len >= sizeof(saddr->sun_path)) {
		do_from_zval_err(ctx, "the path is too long, the maximum permitted "
				"length is %ld", sizeof(saddr->sun_path) - 1);
		return;
	}

	memcpy(&saddr->sun_path, path_str->val, path_str->len);
	saddr->sun_path[path_str->len] = '\0';

	zend_string_release(path_str);
}
Пример #2
0
static void from_zval_write_uid_t(const zval *arr_value, char *field, ser_context *ctx)
{
	zend_long lval;
	uid_t ival;

	lval = from_zval_integer_common(arr_value, ctx);
	if (ctx->err.has_error) {
		return;
	}

	/* uid_t can be signed or unsigned (generally unsigned) */
	if ((uid_t)-1 > (uid_t)0) {
		if (sizeof(zend_long) > sizeof(uid_t) && (lval < 0 || (uid_t)lval != lval)) {
			do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
					"for a uid_t value");
			return;
		}
	} else {
		if (sizeof(zend_long) > sizeof(uid_t) && (uid_t)lval != lval) {
			do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
					"for a uid_t value");
			return;
		}
	}

	ival = (uid_t)lval;
	memcpy(field, &ival, sizeof(ival));
}
Пример #3
0
/* Generic Aggregated conversions */
static void from_zval_write_aggregation(const zval *container,
										char *structure,
										const field_descriptor *descriptors,
										ser_context *ctx)
{
	const field_descriptor	*descr;
	zval					*elem;

	if (Z_TYPE_P(container) != IS_ARRAY) {
		do_from_zval_err(ctx, "%s", "expected an array here");
	}

	for (descr = descriptors; descr->name != NULL && !ctx->err.has_error; descr++) {
		if ((elem = zend_hash_str_find(Z_ARRVAL_P(container),
				descr->name, descr->name_size - 1)) != NULL) {

			if (descr->from_zval == NULL) {
				do_from_zval_err(ctx, "No information on how to convert value "
						"of key '%s'", descr->name);
				break;
			}

			zend_llist_add_element(&ctx->keys, (void*)&descr->name);
			descr->from_zval(elem, ((char*)structure) + descr->field_offset, ctx);
			zend_llist_remove_tail(&ctx->keys);

		} else if (descr->required) {
			do_from_zval_err(ctx, "The key '%s' is required", descr->name);
			break;
		}
	}
}
Пример #4
0
/* CONVERSIONS for integers */
static zend_long from_zval_integer_common(const zval *arr_value, ser_context *ctx)
{
	zend_long ret = 0;
	zval lzval;

	ZVAL_NULL(&lzval);
	if (Z_TYPE_P(arr_value) != IS_LONG) {
		ZVAL_COPY(&lzval, (zval *)arr_value);
		arr_value = &lzval;
	}

	switch (Z_TYPE_P(arr_value)) {
	case IS_LONG:
long_case:
		ret = Z_LVAL_P(arr_value);
		break;

	/* if not long we're operating on lzval */
	case IS_DOUBLE:
double_case:
		convert_to_long(&lzval);
		goto long_case;

	case IS_OBJECT:
	case IS_STRING: {
		zend_long lval;
		double dval;

		convert_to_string(&lzval);

		switch (is_numeric_string(Z_STRVAL(lzval), Z_STRLEN(lzval), &lval, &dval, 0)) {
		case IS_DOUBLE:
			zval_dtor(&lzval);
			ZVAL_DOUBLE(&lzval, dval);
			goto double_case;

		case IS_LONG:
			zval_dtor(&lzval);
			ZVAL_LONG(&lzval, lval);
			goto long_case;
		}

		/* if we get here, we don't have a numeric string */
		do_from_zval_err(ctx, "expected an integer, but got a non numeric "
				"string (possibly from a converted object): '%s'", Z_STRVAL_P(arr_value));
		break;
	}

	default:
		do_from_zval_err(ctx, "%s", "expected an integer, either of a PHP "
				"integer type or of a convertible type");
		break;
	}

	zval_dtor(&lzval);

	return ret;
}
Пример #5
0
static void from_zval_write_sin6_addr(const zval *zaddr_str, char *addr6, ser_context *ctx)
{
	int					res;
	struct sockaddr_in6	saddr6 = {0};
	zend_string			*addr_str;

	addr_str = zval_get_string((zval *) zaddr_str);
	res = php_set_inet6_addr(&saddr6, addr_str->val, ctx->sock);
	if (res) {
		memcpy(addr6, &saddr6.sin6_addr, sizeof saddr6.sin6_addr);
	} else {
		/* error already emitted, but let's emit another more relevant */
		do_from_zval_err(ctx, "could not resolve address '%s' to get an AF_INET6 "
				"address", Z_STRVAL_P(zaddr_str));
	}

	zend_string_release(addr_str);
}
Пример #6
0
/* CONVERSIONS for sockaddr */
static void from_zval_write_sin_addr(const zval *zaddr_str, char *inaddr, ser_context *ctx)
{
	int					res;
	struct sockaddr_in	saddr = {0};
	zend_string			*addr_str, *tmp_addr_str;

	addr_str = zval_get_tmp_string((zval *) zaddr_str, &tmp_addr_str);
	res = php_set_inet_addr(&saddr, ZSTR_VAL(addr_str), ctx->sock);
	if (res) {
		memcpy(inaddr, &saddr.sin_addr, sizeof saddr.sin_addr);
	} else {
		/* error already emitted, but let's emit another more relevant */
		do_from_zval_err(ctx, "could not resolve address '%s' to get an AF_INET "
				"address", ZSTR_VAL(addr_str));
	}

	zend_tmp_string_release(tmp_addr_str);
}
Пример #7
0
static void from_zval_write_pid_t(const zval *arr_value, char *field, ser_context *ctx)
{
	zend_long lval;
	pid_t ival;

	lval = from_zval_integer_common(arr_value, ctx);
	if (ctx->err.has_error) {
		return;
	}

	if (lval < 0 || (pid_t)lval != lval) { /* pid_t is signed */
		do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
				"for a pid_t value");
		return;
	}

	ival = (pid_t)lval;
	memcpy(field, &ival, sizeof(ival));
}
Пример #8
0
static void from_zval_write_sa_family(const zval *arr_value, char *field, ser_context *ctx)
{
	zend_long lval;
	sa_family_t ival;

	lval = from_zval_integer_common(arr_value, ctx);
	if (ctx->err.has_error) {
		return;
	}

	if (lval < 0 || lval > (sa_family_t)-1) { /* sa_family_t is unsigned */
		do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
				"for a sa_family_t value");
		return;
	}

	ival = (sa_family_t)lval;
	memcpy(field, &ival, sizeof(ival));
}
Пример #9
0
static void from_zval_write_net_uint16(const zval *arr_value, char *field, ser_context *ctx)
{
	zend_long lval;
	uint16_t ival;

	lval = from_zval_integer_common(arr_value, ctx);
	if (ctx->err.has_error) {
		return;
	}

	if (lval < 0 || lval > 0xFFFF) {
		do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
				"for an unsigned 16-bit integer");
		return;
	}

	ival = htons((uint16_t)lval);
	memcpy(field, &ival, sizeof(ival));
}
Пример #10
0
void from_zval_write_int(const zval *arr_value, char *field, ser_context *ctx)
{
	zend_long lval;
	int ival;

	lval = from_zval_integer_common(arr_value, ctx);
	if (ctx->err.has_error) {
		return;
	}

	if (lval > INT_MAX || lval < INT_MIN) {
		do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
				"for a native int");
		return;
	}

	ival = (int)lval;
	memcpy(field, &ival, sizeof(ival));
}
Пример #11
0
static void from_zval_write_sockaddr_aux(const zval *container,
										 struct sockaddr **sockaddr_ptr,
										 socklen_t *sockaddr_len,
										 ser_context *ctx)
{
	int		family;
	zval	*elem;
	int		fill_sockaddr;

	if (Z_TYPE_P(container) != IS_ARRAY) {
		do_from_zval_err(ctx, "%s", "expected an array here");
		return;
	}

	fill_sockaddr = param_get_bool(ctx, KEY_FILL_SOCKADDR, 1);

	if ((elem = zend_hash_str_find(Z_ARRVAL_P(container), "family", sizeof("family") - 1)) != NULL
			&& Z_TYPE_P(elem) != IS_NULL) {
		const char *node = "family";
		zend_llist_add_element(&ctx->keys, &node);
		from_zval_write_int(elem, (char*)&family, ctx);
		zend_llist_remove_tail(&ctx->keys);
	} else {
		family = ctx->sock->type;
	}

	switch (family) {
	case AF_INET:
		/* though not all OSes support sockaddr_in used in IPv6 sockets */
		if (ctx->sock->type != AF_INET && ctx->sock->type != AF_INET6) {
			do_from_zval_err(ctx, "the specified family (number %d) is not "
					"supported on this socket", family);
			return;
		}
		*sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_in), ctx);
		*sockaddr_len = sizeof(struct sockaddr_in);
		if (fill_sockaddr) {
			from_zval_write_sockaddr_in(container, (char*)*sockaddr_ptr, ctx);
			(*sockaddr_ptr)->sa_family = AF_INET;
		}
		break;

#if HAVE_IPV6
	case AF_INET6:
		if (ctx->sock->type != AF_INET6) {
			do_from_zval_err(ctx, "the specified family (AF_INET6) is not "
					"supported on this socket");
			return;
		}
		*sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_in6), ctx);
		*sockaddr_len = sizeof(struct sockaddr_in6);
		if (fill_sockaddr) {
			from_zval_write_sockaddr_in6(container, (char*)*sockaddr_ptr, ctx);
			(*sockaddr_ptr)->sa_family = AF_INET6;
		}
		break;
#endif /* HAVE_IPV6 */

	case AF_UNIX:
		if (ctx->sock->type != AF_UNIX) {
			do_from_zval_err(ctx, "the specified family (AF_UNIX) is not "
					"supported on this socket");
			return;
		}
		*sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_un), ctx);
		if (fill_sockaddr) {
			struct sockaddr_un *sock_un = (struct sockaddr_un*)*sockaddr_ptr;

			from_zval_write_sockaddr_un(container, (char*)*sockaddr_ptr, ctx);
			(*sockaddr_ptr)->sa_family = AF_UNIX;

			/* calculating length is more complicated here. Giving the size of
			 * struct sockaddr_un here and relying on the nul termination of
			 * sun_path does not work for paths in the abstract namespace. Note
			 * that we always assume the path is not empty and nul terminated */
			*sockaddr_len = offsetof(struct sockaddr_un, sun_path) +
					(sock_un->sun_path[0] == '\0'
					? (1 + strlen(&sock_un->sun_path[1]))
					: strlen(sock_un->sun_path));
		} else {
			*sockaddr_len = sizeof(struct sockaddr_un);
		}
		break;

	default:
		do_from_zval_err(ctx, "%s", "the only families currently supported are "
				"AF_INET, AF_INET6 and AF_UNIX");
		break;
	}