Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 1 addition & 12 deletions include/ucode/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -575,18 +575,7 @@ ucv_to_unsigned(uc_value_t *v)
return u;
}

static inline bool
ucv_is_callable(uc_value_t *uv)
{
switch (ucv_type(uv)) {
case UC_CLOSURE:
case UC_CFUNCTION:
return true;

default:
return false;
}
}
bool ucv_is_callable(uc_value_t *uv);

static inline bool
ucv_is_arrowfn(uc_value_t *uv)
Expand Down
3 changes: 3 additions & 0 deletions include/ucode/vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,7 @@ uc_exception_type_t uc_vm_signal_dispatch(uc_vm_t *vm);
void uc_vm_signal_raise(uc_vm_t *vm, int signo);
int uc_vm_signal_notifyfd(uc_vm_t *vm);

__hidden uc_value_t *uc_vm_get_invoke_fn( uc_value_t *proto );


#endif /* UCODE_VM_H */
38 changes: 28 additions & 10 deletions lib/math.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,16 +372,20 @@ uc_pow(uc_vm_t *vm, size_t nargs)
}

/**
* Produces a pseudo-random positive integer.
*
* Returns the calculated pseuo-random value. The value is within the range
* `0` to `RAND_MAX` inclusive where `RAND_MAX` is a platform specific value
* guaranteed to be at least `32767`.
*
* Depending on the arguments, it produces a pseudo-random positive integer,
* or a pseudo-random number in a supplied range.
*
* Without arguments it returns the calculated pseuo-random value. The value
* is within the range `0` to `RAND_MAX` inclusive where `RAND_MAX` is a platform
* specific value guaranteed to be at least `32767`.
*
* With 2 arguments `a, b` it returns a number in the range `a` to `b` inclusive.
* With a single argument `a` it returns a number in the range `0` to `a` inclusive.
*
* The {@link module:math~srand `srand()`} function sets its argument as the
* seed for a new sequence of pseudo-random integers to be returned by `rand()`. These sequences are
* repeatable by calling {@link module:math~srand `srand()`} with the same
* seed value.
* seed for a new sequence of pseudo-random integers to be returned by `rand()`.
* These sequences are repeatable by calling {@link module:math~srand `srand()`}
* with the same seed value.
*
* If no seed value is explicitly set by calling
* {@link module:math~srand `srand()`} prior to the first call to `rand()`,
Expand All @@ -390,6 +394,12 @@ uc_pow(uc_vm_t *vm, size_t nargs)
*
* @function module:math#rand
*
* @param {number} [a]
* End of the desired range.
*
* @param {number} [b]
* The other end of the desired range.
*
* @returns {number}
*/
static uc_value_t *
Expand All @@ -404,7 +414,15 @@ uc_rand(uc_vm_t *vm, size_t nargs)
uc_vm_registry_set(vm, "math.srand_called", ucv_boolean_new(true));
}

return ucv_int64_new(rand());
if (nargs == 0)
return ucv_int64_new(rand());

double a = ucv_to_double(uc_fn_arg(0)), b = 0;

if (nargs > 1)
b = ucv_to_double(uc_fn_arg(1));

return ucv_double_new(a + ((b - a) * rand()) / RAND_MAX);
}

/**
Expand Down
80 changes: 73 additions & 7 deletions lib/resolv.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ typedef struct {
uint32_t retries;
uint32_t timeout;
uint16_t edns_maxsize;
bool txt_as_array;
} resolve_ctx_t;


Expand Down Expand Up @@ -369,7 +370,7 @@ init_obj(uc_vm_t *vm, uc_value_t *obj, const char *key, uc_type_t type)
}

static int
parse_reply(uc_vm_t *vm, uc_value_t *res_obj, const unsigned char *msg, size_t len)
parse_reply(uc_vm_t *vm, uc_value_t *res_obj, const unsigned char *msg, size_t len, bool txt_as_array)
{
ns_msg handle;
ns_rr rr;
Expand Down Expand Up @@ -484,15 +485,54 @@ parse_reply(uc_vm_t *vm, uc_value_t *res_obj, const unsigned char *msg, size_t l
return -1;
}

n = *(unsigned char *)ns_rr_rdata(rr);
if (txt_as_array) {
uc_value_t *values = ucv_array_new(vm);

if (n > 0) {
memset(dname, 0, sizeof(dname));
memcpy(dname, ns_rr_rdata(rr) + 1, n);
for (const unsigned char *p = ns_rr_rdata(rr); rdlen > 0; ) {
n = *p++;
rdlen--;

if (n > rdlen) {
set_error(EBADMSG, "TXT string exceeds record length");

return -1;
}

ucv_array_push(values,
ucv_string_new_length((const char *)p, n));

rdlen -= n;
p += n;
}

type_arr = init_obj(vm, name_obj, "TXT", UC_ARRAY);
ucv_array_push(type_arr, ucv_string_new(dname));
ucv_array_push(type_arr, values);
}
else {
uc_stringbuf_t *buf = ucv_stringbuf_new();

for (const unsigned char *p = ns_rr_rdata(rr); rdlen > 0; ) {
n = *p++;
rdlen--;

if (n > rdlen) {
set_error(EBADMSG, "TXT string exceeds record length");

return -1;
}

if (buf->bpos > 0)
ucv_stringbuf_append(buf, " ");

ucv_stringbuf_addstr(buf, (const char *)p, n);
rdlen -= n;
p += n;
}

type_arr = init_obj(vm, name_obj, "TXT", UC_ARRAY);
ucv_array_push(type_arr, ucv_stringbuf_finish(buf));
}

break;

case ns_t_srv:
Expand Down Expand Up @@ -908,7 +948,7 @@ send_queries(resolve_ctx_t *ctx, uc_vm_t *vm, uc_value_t *res_obj)

ctx->queries[qn].rlen = recvlen;

parse_reply(vm, res_obj, reply_buf.buf, recvlen);
parse_reply(vm, res_obj, reply_buf.buf, recvlen, ctx->txt_as_array);

if (qn == next_query) {
while (next_query < ctx->n_queries) {
Expand Down Expand Up @@ -1156,6 +1196,13 @@ parse_options(resolve_ctx_t *ctx, uc_value_t *opts)
else if (v)
err_return(EINVAL, "EDNS max size not an integer");

v = ucv_object_get(opts, "txt_as_array", NULL);

if (ucv_type(v) == UC_BOOLEAN)
ctx->txt_as_array = ucv_boolean_get(v);
else if (v)
err_return(EINVAL, "Array TXT record flag not a boolean");

return true;
}

Expand Down Expand Up @@ -1206,6 +1253,10 @@ parse_options(resolve_ctx_t *ctx, uc_value_t *opts)
* Maximum UDP packet size for EDNS (Extension Mechanisms for DNS). Set to 0
* to disable EDNS.
*
* @param {boolean} [options.txt_as_array=false]
* Return TXT record strings as array elements instead of space-joining all
* record strings into one single string per record.
*
* @returns {object}
* Object containing DNS query results. Keys are domain names, values are
* objects containing arrays of records grouped by type, or error information
Expand Down Expand Up @@ -1254,6 +1305,21 @@ parse_options(resolve_ctx_t *ctx, uc_value_t *opts)
* // }
*
* @example
* // TXT record with multiple elements
* const txtResult = query(['_spf.facebook.com'], { type: ['TXT'], txt_as_array: true });
* printf(txtResult, "\n");
* // {
* // "_spf.facebook.com": {
* // "TXT": [
* // [
* // "v=spf1 ip4:66.220.144.128/25 ip4:66.220.155.0/24 ip4:66.220.157.0/25 ip4:69.63.178.128/25 ip4:69.63.181.0/24 ip4:69.63.184.0/25",
* // " ip4:69.171.232.0/24 ip4:69.171.244.0/23 -all"
* // ]
* // ]
* // }
* // }
*
* @example
* // Handling errors
* const errorResult = query(['nonexistent.example.com']);
* print(errorResult, "\n");
Expand Down
110 changes: 110 additions & 0 deletions lib/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -3282,6 +3282,114 @@ uc_socket_create(uc_vm_t *vm, size_t nargs)
ok_return(ucv_socket_new(vm, sockfd));
}

/**
* Creates a network socket instance from an existing file descriptor.
*
* Returns a socket descriptor representing the newly created socket.
*
* Returns `null` if an error occurred during socket creation.
*
* @function module:socket#open
*
* @param {number} [fd]
* The file descriptor number
*
* @returns {?module:socket.socket}
* A socket instance representing the socket.
*/
static uc_value_t *
uc_socket_open(uc_vm_t *vm, size_t nargs)
{
uc_value_t *fd;

args_get(vm, nargs, NULL,
"fd", UC_INTEGER, false, &fd);

ok_return(ucv_socket_new(vm, ucv_int64_get(fd)));
}

/**
* Creates a connected socket instance with a pair file descriptor.
*
* This function creates new network sockets with the specified type,
* determined by one of the `SOCK_*` constants, and returns resulting socket
* instances for use in subsequent socket operations.
*
* The type argument specifies the socket type, such as SOCK_STREAM or
* SOCK_DGRAM, and defaults to SOCK_STREAM if not provided. It may also
* be bitwise OR-ed with SOCK_NONBLOCK to enable non-blocking mode or
* SOCK_CLOEXEC to enable close-on-exec semantics.
*
* Returns an array of socket descriptors.
*
* Returns `null` if an error occurred during socket creation.
*
* @function module:socket#pair
*
* @param {number} [type=SOCK_STREAM]
* The socket type, e.g., SOCK_STREAM or SOCK_DGRAM. It may also be
* bitwise OR-ed with SOCK_NONBLOCK or SOCK_CLOEXEC.
*
* @returns {Array.<?module:socket.socket>}
* Socket instances representing the newly created sockets.
*
* @example
* // Create a TCP socket pair
* const tcp_sockets = pair(SOCK_STREAM);
*
* // Create a nonblocking IPv6 UDP socket pair
* const udp_sockets = pair(SOCK_DGRAM | SOCK_NONBLOCK);
*/
static uc_value_t *
uc_socket_pair(uc_vm_t *vm, size_t nargs)
{
uc_value_t *type, *res;
int sockfds[2], socktype;

args_get(vm, nargs, NULL,
"type", UC_INTEGER, true, &type);

socktype = type ? (int)ucv_int64_get(type) : SOCK_STREAM;

if (socketpair(AF_UNIX,
#if defined(__APPLE__)
socktype & ~(SOCK_NONBLOCK|SOCK_CLOEXEC),
#else
socktype,
#endif
0, sockfds) < 0)
err_return(errno, "socketpair()");

#if defined(__APPLE__)
if (socktype & SOCK_NONBLOCK) {
int flags = fcntl(sockfds[0], F_GETFL);

if (flags == -1)
goto error;

if (fcntl(sockfds[0], F_SETFL, flags | O_NONBLOCK) == -1)
goto error;
}

if (socktype & SOCK_CLOEXEC) {
if (fcntl(sockfds[0], F_SETFD, FD_CLOEXEC) == -1)
goto error;
}
#endif

res = ucv_array_new(vm);
ucv_array_set(res, 0, ucv_socket_new(vm, sockfds[0]));
ucv_array_set(res, 1, ucv_socket_new(vm, sockfds[1]));
ok_return(res);

#if defined(__APPLE__)
error:
#endif
close(sockfds[0]);
close(sockfds[1]);
err_return(errno, "fcntl");
}

/**
* Connects the socket to a remote address.
*
Expand Down Expand Up @@ -4791,6 +4899,8 @@ static const uc_function_list_t socket_fns[] = {
static const uc_function_list_t global_fns[] = {
{ "sockaddr", uc_socket_sockaddr },
{ "create", uc_socket_create },
{ "pair", uc_socket_pair },
{ "open", uc_socket_open },
{ "nameinfo", uc_socket_nameinfo },
{ "addrinfo", uc_socket_addrinfo },
{ "poll", uc_socket_poll },
Expand Down
Loading
Loading