summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/debian.yml2
-rw-r--r--.github/workflows/jsdoc.yml2
-rw-r--r--.github/workflows/macos.yml2
-rw-r--r--.github/workflows/openwrt-ci-master.yml2
-rw-r--r--.github/workflows/openwrt-ci-pull-request.yml2
-rw-r--r--docs/README.md6
-rw-r--r--lib/rtnl.c10
-rw-r--r--lib/socket.c114
-rw-r--r--main.c4
9 files changed, 118 insertions, 26 deletions
diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml
index 52c6f9e..6286185 100644
--- a/.github/workflows/debian.yml
+++ b/.github/workflows/debian.yml
@@ -29,7 +29,7 @@ jobs:
dpkg-buildpackage -b -us -uc
- name: Archive code coverage results
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: deb
path: '*ucode*.deb'
diff --git a/.github/workflows/jsdoc.yml b/.github/workflows/jsdoc.yml
index 9d9d394..427250b 100644
--- a/.github/workflows/jsdoc.yml
+++ b/.github/workflows/jsdoc.yml
@@ -20,7 +20,7 @@ jobs:
run: npm run doc
- name: Archive docs as artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: docs
path: ./docs/
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index 72f3454..f8eb43b 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -31,7 +31,7 @@ jobs:
make
- name: Upload build artifacts
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: failure()
with:
name: minimal-build
diff --git a/.github/workflows/openwrt-ci-master.yml b/.github/workflows/openwrt-ci-master.yml
index f95c924..53ded7c 100644
--- a/.github/workflows/openwrt-ci-master.yml
+++ b/.github/workflows/openwrt-ci-master.yml
@@ -24,7 +24,7 @@ jobs:
- uses: ynezz/gh-actions-openwrt-ci-native@v0.0.2
- name: Upload build artifacts
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: failure()
with:
name: native-build-artifacts
diff --git a/.github/workflows/openwrt-ci-pull-request.yml b/.github/workflows/openwrt-ci-pull-request.yml
index 8d6ad34..4db2cb8 100644
--- a/.github/workflows/openwrt-ci-pull-request.yml
+++ b/.github/workflows/openwrt-ci-pull-request.yml
@@ -26,7 +26,7 @@ jobs:
CI_CLANG_VERSION_LIST: 11
- name: Upload build artifacts
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: failure()
with:
name: native-build-artifacts
diff --git a/docs/README.md b/docs/README.md
index 016c7f5..92ab103 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -69,14 +69,14 @@ command.
### MacOS
-To build on MacOS, first install *cmake* and *json-c* via
+To build on MacOS, first install *cmake*, *json-c* and *libmd* via
[Homebrew](https://brew.sh/), then clone the ucode repository and execute
*cmake* followed by *make*:
- $ brew install cmake json-c
+ $ brew install cmake json-c libmd
$ git clone https://github.com/jow-/ucode.git
$ cd ucode/
- $ cmake -DUBUS_SUPPORT=OFF -DUCI_SUPPORT=OFF -DULOOP_SUPPORT=OFF .
+ $ cmake -DUBUS_SUPPORT=OFF -DUCI_SUPPORT=OFF -DULOOP_SUPPORT=OFF -DCMAKE_BUILD_RPATH=/usr/local/lib -DCMAKE_INSTALL_RPATH=/usr/local/lib .
$ make
$ sudo make install
diff --git a/lib/rtnl.c b/lib/rtnl.c
index 6d2c819..f11a653 100644
--- a/lib/rtnl.c
+++ b/lib/rtnl.c
@@ -3612,6 +3612,10 @@ cb_listener_event(struct nl_msg *msg, void *arg)
if (uc_vm_call(vm, true, 1) != EXCEPTION_NONE) {
uloop_end();
+ set_error(NLE_FAILURE, "Runtime exception in callback");
+
+ errno = EINVAL;
+
return NL_STOP;
}
@@ -3631,12 +3635,8 @@ uc_nl_listener_cb(struct uloop_fd *fd, unsigned int events)
nl_recvmsgs_default(nl_conn.evsock);
- if (errno != 0) {
- if (errno != EAGAIN && errno != EWOULDBLOCK)
- set_error(errno, NULL);
-
+ if (errno != 0)
break;
- }
}
}
diff --git a/lib/socket.c b/lib/socket.c
index db77188..f4b10de 100644
--- a/lib/socket.c
+++ b/lib/socket.c
@@ -78,6 +78,7 @@
#if defined(__linux__)
# include <linux/if_packet.h>
+# include <linux/filter.h>
# ifndef SO_TIMESTAMP_OLD
# define SO_TIMESTAMP_OLD SO_TIMESTAMP
@@ -306,13 +307,16 @@ hwaddr_to_uv(uint8_t *addr, size_t alen)
char buf[sizeof("FF:FF:FF:FF:FF:FF:FF:FF")], *p = buf;
const char *hex = "0123456789ABCDEF";
- for (size_t i = 0; i < alen && i < 8; i++) {
+ if (alen > 8)
+ alen = 8;
+
+ for (size_t i = 0; i < alen; i++) {
if (i) *p++ = ':';
*p++ = hex[addr[i] / 16];
*p++ = hex[addr[i] % 16];
}
- return ucv_string_new(buf);
+ return ucv_string_new_length(buf, alen);
}
static bool
@@ -966,6 +970,90 @@ static struct_t st_timeval = {
};
#if defined(__linux__)
+static bool
+filter_to_c(void *st, uc_value_t *uv)
+{
+ struct sock_fprog **fpp = st;
+ struct sock_fprog *fp = *fpp;
+ size_t i, len;
+
+ if (ucv_type(uv) == UC_STRING) {
+ size_t len = ucv_string_length(uv);
+
+ if (len == 0 || (len % sizeof(struct sock_filter)) != 0)
+ err_return(EINVAL, "Filter program length not a multiple of %zu",
+ sizeof(struct sock_filter));
+
+ fp = *fpp = xrealloc(fp, sizeof(struct sock_fprog) + len);
+ fp->filter = memcpy((char *)fp + sizeof(struct sock_fprog), ucv_string_get(uv), len);
+
+ if (fp->len == 0)
+ fp->len = len / sizeof(struct sock_filter);
+ }
+ else if (ucv_type(uv) == UC_ARRAY) {
+ /* Opcode array of array. Each sub-array is a 4 element tuple */
+ if (ucv_type(ucv_array_get(uv, 0)) == UC_ARRAY) {
+ len = ucv_array_length(uv);
+
+ fp = *fpp = xrealloc(fp, sizeof(struct sock_fprog)
+ + (len * sizeof(struct sock_filter)));
+
+ fp->filter = (struct sock_filter *)((char *)fp + sizeof(struct sock_fprog));
+
+ for (i = 0; i < len; i++) {
+ uc_value_t *op = ucv_array_get(uv, i);
+
+ if (ucv_type(op) != UC_ARRAY)
+ continue;
+
+ fp->filter[i].code = ucv_to_unsigned(ucv_array_get(op, 0));
+ fp->filter[i].jt = ucv_to_unsigned(ucv_array_get(op, 1));
+ fp->filter[i].jf = ucv_to_unsigned(ucv_array_get(op, 2));
+ fp->filter[i].k = ucv_to_unsigned(ucv_array_get(op, 3));
+ }
+ }
+
+ /* Flat opcode array, must be a multiple of 4 */
+ else {
+ len = ucv_array_length(uv);
+
+ if (len % 4)
+ err_return(EINVAL, "Opcode array length not a multiple of 4");
+
+ len /= 4;
+
+ fp = *fpp = xrealloc(fp, sizeof(struct sock_fprog)
+ + (len * sizeof(struct sock_filter)));
+
+ fp->filter = (struct sock_filter *)((char *)fp + sizeof(struct sock_fprog));
+
+ for (i = 0; i < len; i++) {
+ fp->filter[i].code = ucv_to_unsigned(ucv_array_get(uv, i * 4 + 0));
+ fp->filter[i].jt = ucv_to_unsigned(ucv_array_get(uv, i * 4 + 1));
+ fp->filter[i].jf = ucv_to_unsigned(ucv_array_get(uv, i * 4 + 2));
+ fp->filter[i].k = ucv_to_unsigned(ucv_array_get(uv, i * 4 + 3));
+ }
+ }
+
+ if (fp->len == 0)
+ fp->len = i;
+ }
+ else {
+ err_return(EINVAL, "Expecting either BPF bytecode string or array of opcodes");
+ }
+
+ return true;
+}
+
+static struct_t st_sock_fprog = {
+ .size = sizeof(struct sock_fprog),
+ .members = (member_t []){
+ STRUCT_MEMBER_NP(sock_fprog, len, DT_UNSIGNED),
+ STRUCT_MEMBER_CB(filter, filter_to_c, NULL),
+ { 0 }
+ }
+};
+
static struct_t st_ucred = {
.size = sizeof(struct ucred),
.members = (member_t []){
@@ -1048,7 +1136,7 @@ in6_ifindex_to_uv(void *st)
static bool
in6_ifindex_to_c(void *st, uc_value_t *uv)
{
- struct ipv6_mreq *mr = st;
+ struct ipv6_mreq *mr = *(struct ipv6_mreq **)st;
if (ucv_type(uv) == UC_STRING) {
mr->ipv6mr_interface = if_nametoindex(ucv_string_get(uv));
@@ -1186,7 +1274,9 @@ rcv_wscale_to_uv(void *st)
static bool
snd_wscale_to_c(void *st, uc_value_t *uv)
{
- ((struct tcp_info *)st)->tcpi_snd_wscale = ucv_to_unsigned(uv);
+ struct tcp_info *ti = *(struct tcp_info **)st;
+
+ ti->tcpi_snd_wscale = ucv_to_unsigned(uv);
if (errno)
err_return(errno, "Unable to convert field snd_wscale to unsigned");
@@ -1197,7 +1287,9 @@ snd_wscale_to_c(void *st, uc_value_t *uv)
static bool
rcv_wscale_to_c(void *st, uc_value_t *uv)
{
- ((struct tcp_info *)st)->tcpi_rcv_wscale = ucv_to_unsigned(uv);
+ struct tcp_info *ti = *(struct tcp_info **)st;
+
+ ti->tcpi_rcv_wscale = ucv_to_unsigned(uv);
if (errno)
err_return(errno, "Unable to convert field rcv_wscale to unsigned");
@@ -1311,7 +1403,7 @@ mr_ifindex_to_uv(void *st)
static bool
mr_ifindex_to_c(void *st, uc_value_t *uv)
{
- struct packet_mreq *mr = st;
+ struct packet_mreq *mr = *(struct packet_mreq **)st;
if (ucv_type(uv) == UC_STRING) {
mr->mr_ifindex = if_nametoindex(ucv_string_get(uv));
@@ -1341,7 +1433,7 @@ mr_address_to_uv(void *st)
static bool
mr_address_to_c(void *st, uc_value_t *uv)
{
- struct packet_mreq *mr = st;
+ struct packet_mreq *mr = *(struct packet_mreq **)st;
size_t len;
if (!uv_to_hwaddr(uv, mr->mr_address, &len))
@@ -1504,7 +1596,7 @@ static sockopt_t sockopts[] = {
{ SOL_SOCKET, SO_TIMESTAMP, SV_BOOL },
{ SOL_SOCKET, SO_TYPE, SV_INT },
#if defined(__linux__)
- { SOL_SOCKET, SO_ATTACH_FILTER, SV_STRING },
+ { SOL_SOCKET, SO_ATTACH_FILTER, &st_sock_fprog },
{ SOL_SOCKET, SO_ATTACH_BPF, SV_INT },
{ SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, SV_STRING },
{ SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, SV_INT },
@@ -1789,7 +1881,7 @@ uv_to_struct(uc_value_t *uv, struct_t *spec)
break;
case DT_CALLBACK:
- if (m->u1.to_c && !m->u1.to_c(st, fv)) {
+ if (m->u1.to_c && !m->u1.to_c(&st, fv)) {
free(st);
return NULL;
}
@@ -3920,10 +4012,6 @@ uc_socket_inst_recvmsg(uc_vm_t *vm, size_t nargs)
flagval = flags ? ucv_int64_get(flags) : 0;
-#if defined(__linux__)
- flagval |= MSG_CMSG_CLOEXEC;
-#endif
-
/* prepare ancillary data buffer */
if (anclength) {
size_t sz = ucv_to_unsigned(anclength);
diff --git a/main.c b/main.c
index 1faaba5..bca1e5f 100644
--- a/main.c
+++ b/main.c
@@ -506,6 +506,7 @@ main(int argc, char **argv)
FILE *precompile = NULL;
char *outfile = NULL;
uc_vm_t vm = { 0 };
+ const char *argv0;
int opt, rv = 0;
const char *app;
uc_value_t *o;
@@ -558,6 +559,7 @@ main(int argc, char **argv)
uc_search_path_init(&config.module_search_path);
+ argv0 = argv[optind];
optind = 1;
uc_vm_init(&vm, &config);
@@ -569,6 +571,8 @@ main(int argc, char **argv)
o = ucv_array_new(&vm);
ucv_object_add(uc_vm_scope_get(&vm), "ARGV", ucv_get(o));
+ if (argv0)
+ ucv_object_add(uc_vm_scope_get(&vm), "SCRIPT_NAME", ucv_string_new(argv0));
/* parse options iteration 2: process remaining options */
while ((opt = getopt(argc, argv, optspec)) != -1)