...
 
Commits (24)
variables:
UPSTREAM_REPO: mstoeckl/waypipe
DEBIAN_TAG: '2019-06-25.1'
DEBIAN_TAG: '2019-06-25.1'
DEBIAN_VERSION: buster
DEBIAN_EXEC: 'bash .gitlab-ci/debian-install.sh'
DEBIAN_CONTAINER_IMAGE: $CI_REGISTRY_IMAGE/debian/$DEBIAN_VERSION:$DEBIAN_TAG
DEBIAN32_TAG: 'deb32-2019-07-04.2'
DEBIAN32_VERSION: buster
DEBIAN32_EXEC: 'bash .gitlab-ci/debian32-install.sh'
DEBIAN32_CONTAINER_IMAGE: $CI_REGISTRY_IMAGE/debian/$DEBIAN32_VERSION:$DEBIAN32_TAG
include:
- project: 'wayland/ci-templates'
ref: 96912c7331cbc6da41fbf22c4217aa541176f063
file: '/templates/debian.yml'
- project: 'mstoeckl/waypipe'
file: '/.gitlab-ci/debian32.yml'
ref: master
stages:
- container_prep
- build
container_prep:
debian_container_prep:
extends: .debian@container-ifnot-exists
stage: container_prep
build:
debian32_container_prep:
extends: .debian32@container-ifnot-exists
stage: container_prep
.build-debian-all:
stage: build
image: $DEBIAN_CONTAINER_IMAGE
before_script:
- export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
- export BUILD_ID="$CI_COMMIT_SHA-$CI_JOB_ID"
- export PREFIX="$(pwd)/p-$BUILD_ID"
- export BUILDDIR="$(pwd)/b-$BUILD_ID"
- mkdir "$BUILDDIR" "$PREFIX"
script:
- export PATH=~/.local/bin:$PATH
- cd "$BUILDDIR"
......@@ -41,4 +47,29 @@ build:
when: always
paths:
- b-*/meson-logs
- b-*/test
- p-*
debian-build:
before_script:
- export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
- export BUILD_ID="$CI_COMMIT_SHA-$CI_JOB_ID"
- export PREFIX="$(pwd)/p-$BUILD_ID"
- export BUILDDIR="$(pwd)/b-$BUILD_ID"
- mkdir "$BUILDDIR" "$PREFIX"
- export CC=gcc
extends: .build-debian-all
image: $DEBIAN_CONTAINER_IMAGE
debian32-build:
before_script:
- export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
- export BUILD_ID="$CI_COMMIT_SHA-$CI_JOB_ID"
- export PREFIX="$(pwd)/p-$BUILD_ID"
- export BUILDDIR="$(pwd)/b-$BUILD_ID"
- mkdir "$BUILDDIR" "$PREFIX"
- export CC=/usr/bin/gcc-8
- export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig/
extends: .build-debian-all
image: $DEBIAN32_CONTAINER_IMAGE
#!/bin/bash
set -o xtrace
set -e -o xtrace
apt-get update
apt-get -y --no-install-recommends install \
......
#!/bin/bash
set -e -o xtrace
dpkg --print-foreign-architectures
dpkg --add-architecture i386
apt-get update
# Actual package dependencies
apt-get -y --no-install-recommends install wayland-protocols:i386 pkg-config:i386 libwayland-dev:i386 libgbm-dev:i386 liblz4-dev:i386 libzstd-dev:i386 libavcodec-dev:i386 libavutil-dev:i386 libswscale-dev:i386 weston:i386 libdrm-dev:i386
apt-get -y --no-install-recommends install gcc-8-multilib:i386 gcc-8:i386 make:i386
# Build scripts, architecture doesn't matter
apt-get -y --no-install-recommends install git python3-pip python3-wheel python3-setuptools ninja-build scdoc
pip3 install --user git+https://github.com/mesonbuild/meson.git@0.47
# vim: set expandtab shiftwidth=2 tabstop=8 textwidth=0:
# This template will create a debian image based on the following variables:
#
# - DEBIAN_VERSION: the debian version (stretch, sid, etc...)
# - DEBIAN_DEBS: if set, list of packages that needs to be installed
# - DEBIAN_EXEC: if set, this command will be run once the packages have
# been installed
# - UPSTREAM_REPO: the upstream project on this gitlab instance where we might
# find the given tag (for example: `wayland/weston`)
# - DEBIAN_TAG: tag to copy the image from the upstream registry. If the
# tag does not exist, create a new build and tag it
#
# The resulting image will be pushed in the local registry, under:
# $CI_REGISTRY_IMAGE/debian/$DEBIAN_VERSION:$DEBIAN_TAG
#
# Two flavors of templates are available:
# - `.debian32@container-build`: this will force rebuild a new container
# and tag it with $DEBIAN_TAG without checks
# - `.debian32@container-ifnot-exists`: this will rebuild a new container
# only if $DEBIAN_TAG is not available in the local registry or
# in the $UPSTREAM_REPO registry
# we can not reuse exported variables in after_script,
# so have a common definition
.debian32_vars: &distro_vars |
# exporting templates variables
# https://gitlab.com/gitlab-com/support-forum/issues/4349
export BUILDAH_FORMAT=docker
# The '32' version should run multilib
export DISTRO=debian
export DISTRO_TAG=$DEBIAN32_TAG
export DISTRO_VERSION=$DEBIAN32_VERSION
export DISTRO_EXEC=$DEBIAN32_EXEC
# Do not use this template directly, you can not reuse the produced image
# as it is tagged with $CI_JOB_ID
..debian32@container-template:
image: $CI_REGISTRY/wayland/ci-templates/buildah:latest
stage: build
before_script:
# log in to the registry
- podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- *distro_vars
script:
- *distro_vars
- echo Building $DISTRO/$DISTRO_VERSION:$DISTRO_TAG from $DISTRO:$DISTRO_VERSION
# initial set up: take the base image, update it and install the packages
- buildcntr=$(buildah from $DISTRO:$DISTRO_VERSION)
- buildmnt=$(buildah mount $buildcntr)
- buildah run $buildcntr cat /etc/apt/sources.list
- echo 'path-exclude=/usr/share/doc/*' > $buildmnt/etc/dpkg/dpkg.cfg.d/99-exclude-cruft
- echo 'path-exclude=/usr/share/locale/*' >> $buildmnt/etc/dpkg/dpkg.cfg.d/99-exclude-cruft
- echo 'path-exclude=/usr/share/man/*' >> $buildmnt/etc/dpkg/dpkg.cfg.d/99-exclude-cruft
- echo 'APT::Install-Recommends "false";' > $buildmnt/etc/apt/apt.conf
- echo '#!/bin/sh' > $buildmnt/usr/sbin/policy-rc.d
- echo 'exit 101' >> $buildmnt/usr/sbin/policy-rc.d
- chmod +x $buildmnt/usr/sbin/policy-rc.d
- buildah run $buildcntr env DEBIAN_FRONTEND=noninteractive apt-get update
- buildah run $buildcntr env DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade
- if [[ x"$DEBIAN_DEBS" != x"" ]] ;
then
buildah run $buildcntr env DEBIAN_FRONTEND=noninteractive apt-get -y install $DEBIAN_DEBS ;
fi
# check if there is an optional post install script and run it
- if [[ x"$DISTRO_EXEC" != x"" ]] ;
then
echo Running $DISTRO_EXEC ;
set -x ;
mkdir $buildmnt/tmp/clone ;
pushd $buildmnt/tmp/clone ;
git init ;
git remote add origin $CI_REPOSITORY_URL ;
git fetch --depth 1 origin $CI_COMMIT_SHA ;
git checkout FETCH_HEAD > /dev/null;
buildah config --workingdir /tmp/clone $buildcntr ;
buildah run $buildcntr bash -c "set -x ; $DISTRO_EXEC" ;
popd ;
rm -rf $buildmnt/tmp/clone ;
set +x ;
fi
# do not store the packages database, it's pointless
- buildah run $buildcntr env DEBIAN_FRONTEND=noninteractive apt-get clean
- rm -f $buildmnt/var/lib/apt/lists/*.lz4
# set up the working directory
- buildah config --workingdir /app $buildcntr
# umount the container, not required, but, heh
- buildah unmount $buildcntr
# tag the current container
- buildah commit $buildcntr $CI_REGISTRY_IMAGE/$DISTRO/$DISTRO_VERSION:$CI_JOB_ID
# clean up the working container
- buildah rm $buildcntr
# push the container image to the registry
# There is a bug when pushing 2 tags in the same repo with the same base:
# this may fail. Just retry it after.
- podman push $CI_REGISTRY_IMAGE/$DISTRO/$DISTRO_VERSION:$CI_JOB_ID || true
- sleep 2
- podman push $CI_REGISTRY_IMAGE/$DISTRO/$DISTRO_VERSION:$CI_JOB_ID
# mark the current stage as successed, to get the result in after_script
- touch .success
.debian32@container-build:
extends: ..debian32@container-template
after_script:
# if we did not build, or if there was a failure, exit
# (the exit status does not matter here)
- if [[ ! -e .success ]] ;
then
exit 0;
fi
- *distro_vars
- skopeo copy docker://$CI_REGISTRY_IMAGE/$DISTRO/$DISTRO_VERSION:$CI_JOB_ID
docker://$CI_REGISTRY_IMAGE/$DISTRO/$DISTRO_VERSION:$DISTRO_TAG
.debian32@container-ifnot-exists:
extends: .debian32@container-build
before_script:
# log in to the registry
- podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- *distro_vars
# check if our image is already in the current registry
- skopeo inspect docker://$CI_REGISTRY_IMAGE/$DISTRO/$DISTRO_VERSION:$DISTRO_TAG > /dev/null && exit 0 || true
# copy the original image into the current project registry namespace
- skopeo copy docker://$CI_REGISTRY/$UPSTREAM_REPO/$DISTRO/$DISTRO_VERSION:$DISTRO_TAG
docker://$CI_REGISTRY_IMAGE/$DISTRO/$DISTRO_VERSION:$DISTRO_TAG && exit 0 || true
......@@ -41,12 +41,11 @@ Build with meson[0]. A typical incantation is
Requirements:
* libffi
* meson (build, >= 0.47. and its dependencies `ninja` and `pkg-config`)
* wayland (build, >= 1.15, to support absolute paths in WAYLAND_DISPLAY)
* meson (build, >= 0.47. with dependencies `ninja`, `pkg-config`, `python3`)
* wayland (build, >= 1.10 for the `wl_surface::damage_buffer` request)
* wayland-protocols (build, >= 1.12, for the xdg-shell protocol, and others)
* libzstd (optional)
* liblz4 (optional)
* libzstd (optional, >= 1.4.0)
* libgbm (optional, to support programs using OpenGL via DMABUFs)
* libdrm (optional, same as for libgbm)
* ffmpeg (optional, >=3.1, needs avcodec/avutil/swscale for lossy video encoding)
......
......@@ -2,5 +2,6 @@
clang-format -style=file --assume-filename=C -i \
util.h \
waypipe.c server.c handlers.c client.c util.c parsing.c dmabuf.c shadow.c mainloop.c interval.c video.c \
test/diff_roundtrip.c test/damage_merge.c test/fd_mirror.c test/wire_parse.c
black -q test/headless.py test/startup_failure.py
test/diff_roundtrip.c test/damage_merge.c test/fd_mirror.c test/wire_parse.c test/fuzz_hook.c
black -q test/headless.py test/startup_failure.py \
protocols/symgen.py
......@@ -169,7 +169,7 @@ static long get_dmabuf_fd_size(int fd)
strerror(errno));
return -1;
}
if (lseek(fd, SEEK_SET, 0) == -1) {
if (lseek(fd, 0, SEEK_SET) == -1) {
wp_log(WP_ERROR, "Failed to reset dmabuf offset with lseek: %s",
strerror(errno));
return -1;
......@@ -283,6 +283,11 @@ struct gbm_bo *make_dmabuf(struct render_data *rd, const char *data,
/* Set modifiers to linear, the most likely/portable format */
bo = gbm_bo_create(rd->dev, width, height, format,
GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING);
if (!bo) {
wp_log(WP_ERROR, "Failed to make dmabuf: %s",
strerror(errno));
return NULL;
}
} else {
uint64_t modifiers[2] = {info->modifier, GBM_BO_USE_RENDERING};
// assuming the format is a very standard one which can be
......@@ -304,6 +309,12 @@ struct gbm_bo *make_dmabuf(struct render_data *rd, const char *data,
*/
bo = gbm_bo_create_with_modifiers(rd->dev, info->width,
info->height, info->format, modifiers, 2);
if (!bo) {
wp_log(WP_ERROR,
"Failed to make dmabuf (with modifier %lx): %s",
info->modifier, strerror(errno));
return NULL;
}
int tfd = gbm_bo_get_fd(bo);
long csize = get_dmabuf_fd_size(tfd);
close(tfd);
......@@ -337,10 +348,6 @@ struct gbm_bo *make_dmabuf(struct render_data *rd, const char *data,
}
}
}
if (!bo) {
wp_log(WP_ERROR, "Failed to make dmabuf: %s", strerror(errno));
return NULL;
}
void *handle = NULL;
// unfortunately, there is no easy way to estimate the writeable region
......
This diff is collapsed.
......@@ -128,7 +128,9 @@ void merge_mergesort(const int old_count, struct interval *old_list,
for (int jn = 0; jn < new_count; jn++) {
struct ext_interval e = new_list[jn];
if (e.width == 0 || e.rep == 0) {
/* ignore invalid intervals -- also, if e.start is close to
* INT32_MIN, the stream merge breaks */
if (e.width <= 0 || e.rep <= 0 || e.start < 0) {
continue;
}
/* To limit CPU time, if it is very likely that an interval
......@@ -138,6 +140,12 @@ void merge_mergesort(const int old_count, struct interval *old_list,
bool force_combine = (absorbed > 10000) ||
10 * remaining < src_count;
long end = e.start + e.stride * (long)(e.rep - 1) + e.width;
if (end >= INT32_MAX) {
/* overflow protection */
e.width = INT32_MAX - 1 - e.start;
e.rep = 1;
}
/* Remove internal gaps are smaller than the margin and hence
* would need to be merged away anyway. */
if (e.width > e.stride - merge_margin || force_combine) {
......
This diff is collapsed.
......@@ -8,7 +8,7 @@ project(
'warning_level=3',
'werror=true',
],
version: '0.2.0',
version: '0.3.0',
)
cc = meson.get_compiler('c')
......@@ -38,16 +38,11 @@ else
)
endif
wayland_client = dependency('wayland-client', version: '>=1.15') # scanner headers
wayland_server = dependency('wayland-server', version: '>=1.15') # scanner headers
wayland_scanner = dependency('wayland-scanner', native: true, version: '>=1.15') # public-code
wayland_protos = dependency('wayland-protocols', version: '>=1.12') # xdg-shell
libgbm = dependency('gbm', required: get_option('with_dmabuf'))
libdrm = dependency('libdrm', required: get_option('with_dmabuf'))
if libgbm.found() and libdrm.found()
add_project_arguments('-DHAS_DMABUF=1', language: 'c')
endif
libffi = dependency('libffi')
pthreads = dependency('threads')
rt = cc.find_library('rt')
# XXX dtrace -G (Solaris, FreeBSD, NetBSD) isn't supported yet
......@@ -76,14 +71,12 @@ subdir('protocols')
waypipe_source_files = ['client.c', 'dmabuf.c', 'handlers.c', 'mainloop.c', 'parsing.c', 'server.c', 'shadow.c', 'interval.c', 'util.c', 'video.c']
waypipe_dependencies = [
libgbm, # General GPU buffer creation, aligned with dmabuf proto
libffi, # To call wayland protocol functions
liblz4, # Fast compression option
libzstd, # Slow compression option
libavcodec,libavutil,libswscale, # Video encoding
pthreads, # To run expensive computations in parallel
protos, # Wayland protocol data
rt, # For shared memory
wayland_client.partial_dependency(compile_args: true), # protocol headers need these
]
waypipe_includes = []
......@@ -144,29 +137,72 @@ test_mirror = executable(
)
# disable leak checking, because library code is often responsible
test('How well file descriptors are replicated', test_mirror, env: ['ASAN_OPTIONS=detect_leaks=0'])
gen_path = join_paths(meson.current_source_dir(), 'protocols/symgen.py')
test_fnlist = files('test/test_fnlist.txt')
testproto_src = custom_target(
'test-proto code',
output: '@BASENAME@-data.c',
input: 'test/test-proto.xml',
command: [python3, gen_path, 'data', test_fnlist, '@INPUT@', '@OUTPUT@'],
)
testproto_header = custom_target(
'test-proto client-header',
output: '@BASENAME@-defs.h',
input: 'test/test-proto.xml',
command: [python3, gen_path, 'header', test_fnlist, '@INPUT@', '@OUTPUT@'],
)
test_parse = executable(
'wire_parse',
['test/wire_parse.c'],
['test/wire_parse.c', testproto_src, testproto_header],
link_with: lib_waypipe_src,
dependencies: [libffi, wayland_client.partial_dependency(compile_args: true)]
dependencies: [protos]
)
test('That protocol parsing fails cleanly', test_parse)
weston_dep = dependency('weston', required: false)
testprog_paths = []
if weston_dep.found()
# Sometimes weston's test clients are installed here instead
testprog_paths += weston_dep.get_pkgconfig_variable('libexecdir')
endif
weston_prog = find_program('weston', required: false)
weston_shm_prog = find_program('weston-simple-shm', required: false)
weston_egl_prog = find_program('weston-simple-egl', required: false)
weston_dma_prog = find_program('weston-simple-dmabuf-drm', required: false)
envlist = [
'TEST_WAYPIPE_PATH=@0@'.format(waypipe_prog.full_path()),
]
if weston_prog.found() and weston_shm_prog.found() and weston_egl_prog.found()
modenv = envlist
modenv += 'TEST_WESTON_PATH=@0@'.format(weston_prog.path())
modenv += 'TEST_WESTON_SHM_PATH=@0@'.format(weston_shm_prog.path())
modenv += 'TEST_WESTON_EGL_PATH=@0@'.format(weston_egl_prog.path())
modenv += 'TEST_WESTON_DMA_PATH=@0@'.format(weston_dma_prog.path())
test_headless = join_paths(meson.current_source_dir(), 'test/headless.py')
test('If clients crash when run with weston via waypipe', python3, args: test_headless, env: modenv)
if weston_prog.found()
envlist += 'TEST_WESTON_PATH=@0@'.format(weston_prog.path())
endif
test_programs = [
['TEST_WESTON_SHM_PATH', 'weston-simple-shm'],
['TEST_WESTON_EGL_PATH', 'weston-simple-egl'],
['TEST_WESTON_DMA_PATH', 'weston-simple-dmabuf-drm'],
['TEST_WESTON_TERM_PATH', 'weston-terminal'],
['TEST_WESTON_PRES_PATH', 'weston-presentation-shm'],
['TEST_WESTON_SUBSURF_PATH', 'weston-subsurfaces'],
]
have_test_progs = false
foreach t : test_programs
test_prog = find_program(t[1], required: false)
foreach p : testprog_paths
if not test_prog.found()
test_prog = find_program(join_paths(p, t[1]), required: false)
endif
endforeach
if test_prog.found()
have_test_progs = true
envlist += '@0@=@1@'.format(t[0], test_prog.path())
endif
endforeach
if weston_prog.found() and have_test_progs
test_headless = join_paths(meson.current_source_dir(), 'test/headless.py')
test('If clients crash when run with weston via waypipe', python3, args: test_headless, env: envlist)
endif
test_startup = join_paths(meson.current_source_dir(), 'test/startup_failure.py')
test('That waypipe exits cleanly given a bad setup', python3, args: test_startup, env: envlist)
fuzz_hook = executable(
'fuzz_hook',
['test/fuzz_hook.c'],
link_with: lib_waypipe_src,
dependencies: [pthreads]
)
This diff is collapsed.
gtk_primary_selection_offer_req_receive
gtk_primary_selection_source_evt_send
wl_buffer_evt_release
wl_data_offer_req_receive
wl_data_source_evt_send
wl_display_evt_delete_id
wl_display_evt_error
wl_display_req_get_registry
wl_display_req_sync
wl_drm_evt_device
wl_drm_req_create_prime_buffer
wl_keyboard_evt_keymap
wl_registry_evt_global
wl_registry_evt_global_remove
wl_registry_req_bind
wl_shm_req_create_pool
wl_shm_pool_req_create_buffer
wl_shm_pool_req_resize
wl_surface_req_attach
wl_surface_req_commit
wl_surface_req_damage
wl_surface_req_damage_buffer
wl_surface_req_set_buffer_transform
wl_surface_req_set_buffer_scale
wp_presentation_evt_clock_id
wp_presentation_feedback_evt_presented
wp_presentation_req_feedback
zwlr_data_control_offer_v1_req_receive
zwlr_data_control_source_v1_evt_send
zwlr_export_dmabuf_frame_v1_evt_frame
zwlr_export_dmabuf_frame_v1_evt_object
zwlr_export_dmabuf_frame_v1_evt_ready
zwlr_screencopy_frame_v1_evt_ready
zwlr_screencopy_frame_v1_req_copy
zwp_linux_buffer_params_v1_evt_created
zwp_linux_buffer_params_v1_req_add
zwp_linux_buffer_params_v1_req_create
zwp_linux_buffer_params_v1_req_create_immed
zwp_linux_dmabuf_v1_evt_modifier
wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
wayland_dir = wayland_client.get_pkgconfig_variable('pkgdatadir')
wayland_scanner_prog = find_program(wayland_scanner.get_pkgconfig_variable('wayland_scanner'))
# todo: make function list dependency explicit
gen_path = join_paths(meson.current_source_dir(), 'symgen.py')
fn_list = join_paths(meson.current_source_dir(), 'function_list.txt')
wayland_protos = dependency('wayland-protocols', version: '>=1.12') # xdg-shell
wayland_dep = dependency('wayland-client', required: false)
if not wayland_dep.found()
wayland_dep = dependency('wayland-server', required: true)
endif
wayland_dir = wayland_dep.get_pkgconfig_variable('pkgdatadir')
wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir')
protocols = [
wayland_dir + '/wayland.xml',
......@@ -19,24 +28,19 @@ protocols = [
protocols_src = []
protocols_headers = []
protocols_headers += configure_file(input: 'symgen_types.h', copy: true, output: 'symgen_types.h')
foreach xml : protocols
protocols_src += custom_target(
'@0@ code'.format(xml.underscorify()),
output: '@BASENAME@-data.c',
input: xml,
command: [wayland_scanner_prog, 'private-code', '@INPUT@', '@OUTPUT@'],
command: [python3, gen_path, 'data', fn_list, '@INPUT@', '@OUTPUT@'],
)
protocols_headers += custom_target(
'@0@ client-header'.format(xml.underscorify()),
output: '@BASENAME@-client-defs.h',
input: xml,
command: [wayland_scanner_prog, 'client-header', '@INPUT@', '@OUTPUT@'],
)
protocols_headers += custom_target(
'@0@ server-header'.format(xml.underscorify()),
output: '@BASENAME@-server-defs.h',
output: '@BASENAME@-defs.h',
input: xml,
command: [wayland_scanner_prog, 'server-header', '@INPUT@', '@OUTPUT@'],
command: [python3, gen_path, 'header', fn_list, '@INPUT@', '@OUTPUT@'],
)
endforeach
......@@ -44,7 +48,6 @@ endforeach
lib_protocols = static_library(
'protocols',
protocols_src,
dependencies: wayland_client.partial_dependency(compile_args: true),
)
protos = declare_dependency(
link_with: lib_protocols,
......
This diff is collapsed.
#ifndef SYMGEN_TYPES_H
#define SYMGEN_TYPES_H
#include <stdbool.h>
#include <stdint.h>
struct context;
struct message_tracker;
struct wp_object;
typedef void (*wp_callfn_t)(struct context *ctx, const uint32_t *payload, const int *fds, struct message_tracker *mt);
struct msg_data {
const char *name;
const int n_stretch;
const unsigned int base_gap;
const unsigned int *trail_gap;
const bool *stretch_is_string;
const int n_fds;
const int new_vec_len;
const unsigned int *new_obj_idxs;/* there are special 'spacer' fields at each string/arr, =-1*/
const struct wp_interface **new_obj_types;
};
struct wp_interface {
const char *name;
/* 0=request, 1=event */
const struct msg_data *funcs[2];
const int nfuncs[2];
};
/* User should define this function. */
struct wp_object *get_object(struct message_tracker *mt, uint32_t id, const struct wp_interface *intf);
#endif /* SYMGEN_TYPES_H */
......@@ -38,8 +38,9 @@
#include <sys/wait.h>
#include <unistd.h>
int run_server(const char *socket_path, const struct main_config *config,
bool oneshot, bool unlink_at_end, const char *application,
int run_server(const char *socket_path, const char *wayland_display,
const struct main_config *config, bool oneshot,
bool unlink_at_end, const char *application,
char *const app_argv[])
{
wp_log(WP_DEBUG, "I'm a server on %s, running: %s", socket_path,
......@@ -52,10 +53,24 @@ int run_server(const char *socket_path, const struct main_config *config,
socket_path);
return EXIT_FAILURE;
}
char display_path[256];
if (!oneshot) {
if (wayland_display[0] == '/') {
snprintf(display_path, 256, "%s", wayland_display);
} else {
const char *xdg_dir = getenv("XDG_RUNTIME_DIR");
if (!xdg_dir) {
wp_log(WP_ERROR,
"Env. var XDG_RUNTIME_DIR not available, cannot place display socket for WAYLAND_DISPLAY=\"%s\"",
wayland_display);
return EXIT_FAILURE;
}
snprintf(display_path, 256, "%s/%s", xdg_dir,
wayland_display);
}
}
// Setup connection to program
char displaypath[256];
sprintf(displaypath, "%s.disp.sock", socket_path);
int wayland_socket = -1, server_link = -1, wdisplay_socket = -1;
if (oneshot) {
int csockpair[2];
......@@ -69,7 +84,7 @@ int run_server(const char *socket_path, const struct main_config *config,
} else {
// Bind a socket for WAYLAND_DISPLAY, and listen
int nmaxclients = 128;
wdisplay_socket = setup_nb_socket(displaypath, nmaxclients);
wdisplay_socket = setup_nb_socket(display_path, nmaxclients);
if (wdisplay_socket == -1) {
// Error messages already made
return EXIT_FAILURE;
......@@ -81,7 +96,7 @@ int run_server(const char *socket_path, const struct main_config *config,
if (pid == -1) {
wp_log(WP_ERROR, "Fork failed");
if (!oneshot) {
unlink(displaypath);
unlink(display_path);
}
return EXIT_FAILURE;
} else if (pid == 0) {
......@@ -98,7 +113,7 @@ int run_server(const char *socket_path, const struct main_config *config,
// Since Wayland 1.15, absolute paths are supported in
// WAYLAND_DISPLAY
unsetenv("WAYLAND_SOCKET");
setenv("WAYLAND_DISPLAY", displaypath, 1);
setenv("WAYLAND_DISPLAY", wayland_display, 1);
close(wdisplay_socket);
}
......@@ -205,7 +220,7 @@ int run_server(const char *socket_path, const struct main_config *config,
if (unlink_at_end) {
unlink(socket_path);
}
unlink(displaypath);
unlink(display_path);
close(wdisplay_socket);
// Wait for child processes to exit
......
This diff is collapsed.
......@@ -78,7 +78,7 @@ static int update_file(int file_fd, struct gbm_bo *bo, size_t sz, int seqno)
memset((char *)data + start, seqno, end - start);
munmap(data, sz);
return end - start;
return (int)(end - start);
}
static int update_dmabuf(int file_fd, struct gbm_bo *bo, size_t sz, int seqno)
......@@ -105,25 +105,26 @@ static int update_dmabuf(int file_fd, struct gbm_bo *bo, size_t sz, int seqno)
memset((char *)data + start, seqno, end - start);
unmap_dmabuf(bo, map_handle);
return end - start;
return (int)(end - start);
}
static void combine_transfer_blocks(struct transfer *transfer,
struct bytebuf *ret_block, int nblocks, struct bytebuf *blocks)
static void combine_transfer_blocks(struct bytebuf_stack *blocks)
{
size_t net_size = 0;
for (int i = 0; i < nblocks; i++) {
net_size += blocks[i].size;
for (int i = 0; i < blocks->count; i++) {
net_size += blocks->data[i].size;
}
ret_block->size = net_size;
ret_block->data = malloc(net_size);
struct bytebuf ret_block;
ret_block.size = net_size;
ret_block.data = malloc(net_size);
size_t pos = 0;
for (int i = 0; i < nblocks; i++) {
memcpy(ret_block->data + pos, blocks[i].data, blocks[i].size);
pos += blocks[i].size;
for (int i = 0; i < blocks->count; i++) {
memcpy(ret_block.data + pos, blocks->data[i].data,
blocks->data[i].size);
pos += blocks->data[i].size;
}
transfer->subtransfers = ret_block;
transfer->nblocks = 1;
blocks->data[0] = ret_block;
blocks->count = 1;
}
static bool check_match(int orig_fd, int copy_fd, struct gbm_bo *orig_bo,
......@@ -184,35 +185,44 @@ static bool test_transfer(struct fd_translation_map *src_map,
struct fd_translation_map *dst_map, int rid, int ndiff,
struct render_data *render_data)
{
int ntransfers = 0, nblocks = 0;
struct transfer transfers[10];
struct bytebuf blocks[20];
struct transfer_stack transfers;
transfers.size = 1;
transfers.count = 0;
transfers.data = calloc(1, sizeof(struct transfer));
struct bytebuf_stack blocks;
blocks.size = 1;
blocks.count = 0;
blocks.data = calloc(1, sizeof(struct bytebuf));
struct shadow_fd *src_shadow = get_shadow_for_rid(src_map, rid);
collect_update(src_map, src_shadow, &ntransfers, transfers, &nblocks,
blocks);
collect_update(src_map, src_shadow, &transfers, &blocks);
if (ndiff == 0) {
if (ntransfers > 0) {
free(transfers.data);
free(blocks.data);
if (transfers.count > 0) {
wp_log(WP_ERROR,
"Collecting updates gave a transfer when none was expected",
ntransfers);
transfers.count);
return false;
}
return true;
}
if (ntransfers != 1) {
if (transfers.count != 1) {
wp_log(WP_ERROR,
"Collecting updates gave a unexpected number (%d) of transfers",
ntransfers);
transfers.count);
free(transfers.data);
free(blocks.data);
return false;
}
struct transfer res_transfer = transfers[0];
struct bytebuf ret_block;
combine_transfer_blocks(&res_transfer, &ret_block, nblocks, blocks);
apply_update(dst_map, render_data, &res_transfer);
free(ret_block.data);
combine_transfer_blocks(&blocks);
apply_update(dst_map, render_data, &transfers.data[0], &blocks.data[0]);
free(blocks.data[0].data);
free(transfers.data);
free(blocks.data);
/* first round, this only exists after the transfer */
struct shadow_fd *dst_shadow = get_shadow_for_rid(dst_map, rid);
......
/*
* Copyright © 2019 Manuel Stoeckl
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#define _GNU_SOURCE
#include "util.h"
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
struct copy_setup {
int conn;
int wayl;
bool is_display_side;
struct main_config *mc;
};
void *start_looper(void *data)
{
struct copy_setup *setup = (struct copy_setup *)data;
main_interface_loop(setup->conn, setup->wayl, setup->mc,
setup->is_display_side);
return NULL;
}
static void atomic_logger(const char *file, int line, enum log_level level,
const char *fmt, ...)
{
pthread_t tid = pthread_self();
char msg[1024];
int nwri = 0;
nwri += sprintf(msg + nwri, "%lx [%s:%3d] ", (long)tid, file, line);
va_list args;
va_start(args, fmt);
nwri += vsnprintf(msg + nwri, (size_t)(1022 - nwri), fmt, args);
va_end(args);
msg[nwri++] = '\n';
msg[nwri] = 0;
write(STDOUT_FILENO, msg, (size_t)nwri);
(void)level;
}
log_handler_func_t log_funcs[2] = {NULL, NULL};
int main(int argc, char **argv)
{
if (argc == 1 || !strcmp(argv[1], "--help")) {
printf("Usage: ./fuzz_hook [--log] {input_file}\n");
printf("A program to run and control inputs for a linked client/server pair, from a file.\n");
return EXIT_FAILURE;
}
if (argc > 1 && !strcmp(argv[1], "--log")) {
log_funcs[0] = atomic_logger;
log_funcs[1] = atomic_logger;
argc--;
argv++;
}
int fd = open(argv[1], O_RDONLY);
if (fd == -1) {
printf("Failed to open '%s'", argv[1]);
return EXIT_FAILURE;
}
long len = lseek(fd, 0, SEEK_END);
if (len == 0) {
close(fd);
return EXIT_SUCCESS;
}
lseek(fd, 0, SEEK_SET);
char *buf = malloc(len);
read(fd, buf, len);
close(fd);
printf("Loaded %ld bytes\n", len);
int srv_fds[2], cli_fds[2], conn_fds[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, srv_fds) == -1 ||
socketpair(AF_UNIX, SOCK_STREAM, 0, cli_fds) == -1 ||
socketpair(AF_UNIX, SOCK_STREAM, 0, conn_fds) == -1) {
printf("Socketpair failed\n");
return EXIT_FAILURE;
}
struct main_config config = {.drm_node = NULL,
.n_worker_threads = 1,
.compression = COMP_NONE,
.no_gpu = true, /* until we can construct dmabufs here
*/
.linear_dmabuf = false,
.video_if_possible = true};
pthread_t thread_a, thread_b;
struct copy_setup server_conf = {.conn = conn_fds[0],
.wayl = srv_fds[1],
.is_display_side = true,
.mc = &config};
struct copy_setup client_conf = {.conn = conn_fds[1],
.wayl = cli_fds[1],
.is_display_side = false,
.mc = &config};
if (pthread_create(&thread_a, NULL, start_looper, &server_conf) == -1) {
printf("Thread failed\n");
}
if (pthread_create(&thread_b, NULL, start_looper, &client_conf) == -1) {
printf("Thread failed\n");
}
char *ignore_buf = malloc(65536);
/* Main loop: RW from socketpairs with sendmsg, with short wait */
long file_nwords = len / 4;
long cursor = 0;
uint32_t *data = (uint32_t *)buf;
char template[256];
while (cursor < file_nwords) {
uint32_t header = data[cursor++];
bool to_server = header & 0x1;
bool add_file = header & 0x2;
int new_fileno = -1;
if (add_file && cursor < file_nwords) {
uint32_t fsize = data[cursor++];
if (fsize == 0) {
/* 'copy' sink */
new_fileno = open("/dev/null", O_WRONLY);
if (new_fileno == -1) {
wp_log(WP_ERROR,
"Failed to open /dev/null");
}
} else {
/* avoid buffer overflow */
fsize = fsize > 1000000 ? 1000000 : fsize;
/* This should be a tmpfs */
#if defined(__linux__)
sprintf(template, "%x:%x", (uint32_t)cursor,
fsize);
new_fileno = memfd_create(template, 0);
#else
/* WARNING: this can be rather file-system
* intensive */
strcpy(template, "/tmp/fuzz_hook_XXXXXX");
new_fileno = mkstemp(template);
unlink(template);
#endif
if (new_fileno == -1) {
wp_log(WP_ERROR, "Failed to mkstemp");
} else if (ftruncate(new_fileno, fsize) == -1) {
wp_log(WP_ERROR,
"Failed to resize tempfile");
close(new_fileno);
new_fileno = -1;
}
}
}
uint32_t packet_size = header >> 2;
if ((long)packet_size > file_nwords - cursor) {
packet_size = (uint32_t)(file_nwords - cursor);
}
if (packet_size > 2048) {
packet_size = 2048;
}
/* 2 msec max delay for 8KB of data, assuming no system
* interference, should be easily attainable */
int max_write_delay_ms = 1;
int max_read_delay_ms = 2;
int send_fd = to_server ? srv_fds[0] : cli_fds[0];
/* Write packet to stream */
struct pollfd write_pfd;
write_pfd.fd = send_fd;
write_pfd.events = POLLOUT;
int nw;
retry_poll:
nw = poll(&write_pfd, 1, max_write_delay_ms);
if (nw == -1) {
if (new_fileno != -1) {
close(new_fileno);
}
if (errno == EINTR) {
goto retry_poll;
}
printf("Poll error\n");
break;
} else if (nw == 1) {
/* Send message */
struct iovec the_iovec;
the_iovec.iov_len = packet_size * 4;
the_iovec.iov_base = (char *)&data[cursor];
struct msghdr msg;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &the_iovec;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
union {
char buf[CMSG_SPACE(sizeof(int))];
struct cmsghdr align;
} uc;
memset(uc.buf, 0, sizeof(uc.buf));
if (new_fileno != -1) {
msg.msg_control = uc.buf;
msg.msg_controllen = sizeof(uc.buf);
struct cmsghdr *frst = CMSG_FIRSTHDR(&msg);
frst->cmsg_level = SOL_SOCKET;
frst->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(frst), &new_fileno,
sizeof(int));
frst->cmsg_len = CMSG_LEN(sizeof(int));
msg.msg_controllen = CMSG_SPACE(sizeof(int));
}
int target_fd = to_server ? srv_fds[0] : cli_fds[0];
ssize_t ret = sendmsg(target_fd, &msg, 0);
if (ret == -1) {
wp_log(WP_ERROR, "Error in sendmsg");
break;
}
} else {
wp_log(WP_ERROR,
"Failed to send message before timeout");
}
if (new_fileno != -1) {
close(new_fileno);
}
/* Wait up to max_delay for a response. Almost all packets
* should be passed on unmodified; a very small fraction
* are dropped */
struct pollfd read_pfds[2];
read_pfds[0].fd = srv_fds[0];
read_pfds[1].fd = cli_fds[0];
read_pfds[0].events = POLLIN;
read_pfds[1].events = POLLIN;
int nr = poll(read_pfds, 2,
packet_size > 0 ? max_read_delay_ms : 0);
if (nr == -1) {
if (errno == EINTR) {
continue;
}
printf("Poll error\n");
break;
} else if (nr == 0) {
wp_log(WP_DEBUG, "No reply to sent packet %d",
packet_size);
}
for (int i = 0; i < 2; i++) {
if (read_pfds[i].revents & POLLIN) {
char cmsgdata[(CMSG_LEN(28 * sizeof(int32_t)))];
struct iovec the_iovec;
the_iovec.iov_len = 65536;
the_iovec.iov_base = ignore_buf;
struct msghdr msg;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &the_iovec;
msg.msg_iovlen = 1;
msg.msg_control = &cmsgdata;
msg.msg_controllen = sizeof(cmsgdata);
msg.msg_flags = 0;
ssize_t ret = recvmsg(read_pfds[i].fd, &msg, 0);
if (ret == -1) {
wp_log(WP_ERROR, "Error in recvmsg");
}
}
}
cursor += packet_size;
}
close(srv_fds[0]);
close(cli_fds[0]);
pthread_join(thread_a, NULL);
pthread_join(thread_b, NULL);
free(buf);
free(ignore_buf);
return EXIT_SUCCESS;
}
......@@ -41,14 +41,25 @@ def safe_cleanup(process):
weston_path = os.environ["TEST_WESTON_PATH"]
weston_shm_path = os.environ["TEST_WESTON_SHM_PATH"]
weston_egl_path = os.environ["TEST_WESTON_EGL_PATH"]
weston_dma_path = os.environ["TEST_WESTON_DMA_PATH"]
waypipe_path = os.environ["TEST_WAYPIPE_PATH"]
ld_library_path = (
os.environ["LD_LIBRARY_PATH"] if "LD_LIBRARY_PATH" in os.environ else ""
)
sub_tests = {
"SHM": ["TEST_WESTON_SHM_PATH"],
"EGL": ["TEST_WESTON_EGL_PATH", "-o"],
"DMABUF": ["TEST_WESTON_DMA_PATH"],
"TERM": ["TEST_WESTON_TERM_PATH"],
"PRES": ["TEST_WESTON_PRES_PATH"],
"SUBSURF": ["TEST_WESTON_SUBSURF_PATH"],
}
for k, v in list(sub_tests.items()):
if v[0] in os.environ:
v[0] = os.environ[v[0]]
else:
del sub_tests[k]
xdg_runtime_dir = os.path.abspath("./test/")
os.makedirs(xdg_runtime_dir, mode=0o700, exist_ok=True)
os.chmod(xdg_runtime_dir, 0o700)
......@@ -107,12 +118,6 @@ if not wait_until_exists(abs_socket_path):
"weston failed to create expected display socket path, " + abs_socket_path
)
sub_tests = {
"SHM": [weston_shm_path],
"EGL": [weston_egl_path, "-o"],
"DMABUF": [weston_dma_path],
}
processes = {}
try:
......@@ -158,13 +163,16 @@ for sub_test_name, command in sub_tests.items():
)
if len(kids) == 1:
wp_child = kids[0]
if wp_child.name() != os.path.basename(command[0]):
print(
"Unusual child process name",
wp_child.name(),
"does not match",
command[0],
)
try:
if wp_child.name() != os.path.basename(command[0]):
print(
"Unusual child process name",
wp_child.name(),
"does not match",
command[0],
)
except psutil.NoSuchProcess:
pass
processes[sub_test_name] = (
ref_proc,
......
......@@ -163,12 +163,19 @@ run_test(
False,
False,
)
run_test(
"b_server_no_env",
[waypipe_path, "-s", server_socket_path, "server", "sleep", "0.26"],
base_env,
False,
False,
)
# Configurations that should succeed
run_test(
"g_server_no_env",
"g_server_std_env",
[waypipe_path, "-s", server_socket_path, "server", "sleep", "0.26"],
base_env,
standard_env,
False,
True,
)
......
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="test_proto">
<copyright>
Copyright © 2019 Manuel Stoeckl
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that\n the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="xtype" version="1">
<request name="blue">
<arg name="a" type="new_id"/><!-- no type specified -->
<arg name="b" type="fd"/>
<arg name="c" type="int"/>
<arg name="d" type="uint"/>
<arg name="e" type="object"/>
<arg name="f" type="string"/>
<arg name="g" type="uint"/>
</request>
<event name="yellow">
<arg name="c" type="fixed"/>
</event>
</interface>
<interface name="ytype" version="9">
<request name="green">
<arg name="a" type="uint"/>
<arg name="b" type="string"/>
<arg name="c" type="string"/>
<arg name="d" type="fd"/>
<arg name="e" type="string"/>
<arg name="f" type="new_id" interface="xtype"/>
<arg name="g" type="array"/>
</request>
<event name="red">
<arg name="a" type="new_id" interface="xtype"/>
<arg name="b" type="int"/>
<arg name="c" type="fd"/>
<arg name="d" type="new_id" interface="ytype"/>
<arg name="e" type="int"/>
<arg name="f" type="int"/>
<arg name="g" type="new_id" interface="xtype"/>
<arg name="h" type="int"/>
<arg name="i" type="uint"/>
<arg name="j" type="string"/>
<arg name="k" type="fd"/>
<arg name="l" type="array"/>
<arg name="n" type="fixed"/>
<arg name="m" type="string"/>
<arg name="o" type="object" interface="ytype"/>
<arg name="p" type="fd"/>
<arg name="q" type="object" interface="xtype"/>
</event>
</interface>
</protocol>
......@@ -29,74 +29,80 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/mman.h>
#include <ffi.h>
#include <wayland-util.h>
#include "test-proto-defs.h"
#include "util.h"
void invoke_msg_handler(ffi_cif *cif, const struct wl_interface *intf,
const struct wl_message *msg, bool is_event,
const uint32_t *const payload, const int paylen,
const int *const fd_list, const int fdlen, int *fds_used,
void (*const func)(void), struct context *ctx,
struct message_tracker *mt, struct fd_translation_map *map);
/* from parsing.c */
bool size_check(const struct msg_data *data, const uint32_t *payload,
unsigned int true_length, int fd_length);
static bool called = false;
static void testfn_client(struct context *ctx, void *noop, struct wp_object *a0,
int a1, int32_t a2, uint32_t a3, struct wp_object *a4,
const char *a5, uint32_t a6)
void do_xtype_req_blue(struct context *ctx, const char *interface,
uint32_t version, struct wp_object *id, int b, int32_t c,
uint32_t d, struct wp_object *e, const char *f, uint32_t g)
{
char buf[256];
sprintf(buf, "%s %u %u %d %d %d %u %s %d", interface, version,
id ? id->obj_id : 0, b, c, d, e ? e->obj_id : 0, f, g);
printf("%s\n", buf);
ctx->drop_this_msg =
strcmp(buf, "babacba 4441 992 7771 3331 4442 991 (null) 4443") !=
0;
}
void do_xtype_evt_yellow(struct context *ctx, uint32_t c)
{
called = true;
printf("%d called with: a0=%u, a1=%d, a2=%d, a3=%u, a4=%u, a5=\"%s\", a6=%u\n",
ctx->obj->obj_id, a0->obj_id, a1, a2, a3, a4->obj_id,
a5, a6);
(void)noop;
char buf[256];
sprintf(buf, "%u", c);
printf("%s\n", buf);
ctx->drop_this_msg = strcmp(buf, "4441") != 0;
}
static void testfn_server(struct context *ctx, void *noop, uint32_t a0, int a1,
int32_t a2, uint32_t a3, struct wp_object *a4, const char *a5,
uint32_t a6)
void do_ytype_req_green(struct context *ctx, uint32_t a, const char *b,
const char *c, int d, const char *e, struct wp_object *f,
int g_count, const uint8_t *g_val)
{
called = true;
printf("%d called with: a0=%u, a1=%d, a2=%d, a3=%u, a4=%u, a5=\"%s\", a6=%u\n",
ctx->obj->obj_id, a0, a1, a2, a3, a4->obj_id, a5, a6);
(void)noop;
char buf[256];
sprintf(buf, "%u %s %s %d %s %u %d %x|%x|%x|%x|%x|%x|%x|%x", a, b, c, d,
e, f ? f->obj_id : 0, g_count, g_val[0], g_val[1],
g_val[2], g_val[3], g_val[4], g_val[5], g_val[6],
g_val[7]);
printf("%s\n", buf);
ctx->drop_this_msg =
strcmp(buf, "4441 bea (null) 7771 cbbc 991 8 81|80|81|80|90|99|99|99") !=
0;
}
void do_ytype_evt_red(struct context *ctx, struct wp_object *a, int32_t b,
int c, struct wp_object *d, int32_t e, int32_t f,
struct wp_object *g, int32_t h, uint32_t i, const char *j,
int k, int l_count, const uint8_t *l_val, uint32_t n,
const char *m, struct wp_object *o, int p, struct wp_object *q)
{
char buf[256];
sprintf(buf, "%u %d %d %u %d %d %u %d %u %s %d %d %x|%x|%x %u %s %u %d %u",
a ? a->obj_id : 0, b, c, d ? d->obj_id : 0, e, f,
g ? g->obj_id : 0, h, i, j, k, l_count, l_val[0],
l_val[1], l_val[2], n, m, o ? o->obj_id : 0, p,
q ? q->obj_id : 0);
printf("%s\n", buf);
ctx->drop_this_msg =
strcmp(buf, "0 33330 8881 0 33331 33332 0 33333 44440 bcaba 8882 3 80|80|80 99990 (null) 992 8883 991") !=
0;
}
struct wire_test {
const wp_callfn_t func;
const struct msg_data *data;
int fds[4];
uint32_t words[50];
int nfds;
int nwords;
};
log_handler_func_t log_funcs[2] = {test_log_handler, test_log_handler};
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
struct wl_interface dummy_intf = {0};
dummy_intf.name = "test";
struct wl_interface result_intf = {0};
result_intf.name = "result";
struct wl_message msg;
msg.name = "test";
msg.signature = "2nhiu?osu";
const struct wl_interface *typevec[] = {&result_intf, NULL, NULL, NULL,
&result_intf, NULL, NULL};
msg.types = typevec;
ffi_type *types_client[] = {&ffi_type_pointer, &ffi_type_pointer,
&ffi_type_pointer, &ffi_type_sint, &ffi_type_sint32,
&ffi_type_uint32, &ffi_type_pointer, &ffi_type_pointer,
&ffi_type_uint32};
ffi_type *types_server[] = {&ffi_type_pointer, &ffi_type_pointer,
&ffi_type_uint32, &ffi_type_sint, &ffi_type_sint32,
&ffi_type_uint32, &ffi_type_pointer, &ffi_type_pointer,
&ffi_type_uint32};
ffi_cif cif_client;
ffi_cif cif_server;
ffi_prep_cif(&cif_client, FFI_DEFAULT_ABI, 8, &ffi_type_void,
types_client);
ffi_prep_cif(&cif_server, FFI_DEFAULT_ABI, 8, &ffi_type_void,
types_server);
struct message_tracker mt;
init_message_tracker(&mt);
struct wp_object *old_display = listset_get(&mt.objects, 1);
......@@ -105,78 +111,88 @@ int main(int argc, char **argv)
struct fd_translation_map map;
setup_translation_map(&map, false, COMP_NONE, 1);
struct wp_object arg_obj;
arg_obj.type = &dummy_intf;
arg_obj.is_zombie = false;
arg_obj.obj_id = 1;
listset_insert(&map, &mt.objects, &arg_obj);
struct wp_object obj;
obj.type = &dummy_intf;
obj.is_zombie = false;
obj.obj_id = 0;
struct context ctx = {.obj = &obj, .g = NULL};
int actual_fdlen = 1;
int fds[1] = {99};
uint32_t new_id = 51;
uint32_t payload[] = {new_id, 11, (uint32_t)-1, arg_obj.obj_id, 13,
0x61626162, 0x61626162, 0x61626162, 0x00000061, 777};
int actual_length = (int)(sizeof(payload) / sizeof(uint32_t));
bool all_success = true;
int fds_used;
for (int fdlen = actual_fdlen; fdlen >= 0; fdlen--) {
for (int length = actual_length; length >= 0; length--) {
bool expect_success = fdlen == actual_fdlen &&
length == actual_length;
printf("Trying: %d/%d %d/%d\n", length, actual_length,
fdlen, actual_fdlen);
called = false;
fds_used = 0;
invoke_msg_handler(&cif_client, &dummy_intf, &msg, true,
payload, length, fds, fdlen, &fds_used,
(void (*)(void))testfn_client, &ctx,
&mt, &map);
all_success &= called == expect_success;
if (called != expect_success) {
wp_log(WP_ERROR,
"client FAIL at %d/%d chars, %d/%d fds",
length, actual_length, fdlen,
actual_fdlen);
}
struct wp_object xobj;
xobj.type = &intf_xtype;
xobj.is_zombie = false;
xobj.obj_id = 991;
listset_insert(&map, &mt.objects, &xobj);
struct wp_object yobj;
yobj.type = &intf_ytype;
yobj.is_zombie = false;
yobj.obj_id = 992;
listset_insert(&map, &mt.objects, &yobj);
struct context ctx = {.obj = &xobj, .g = NULL};
struct wire_test tests[] = {
{call_xtype_req_blue, &intf_xtype.funcs[0][0], {7771},
{8, 0x61626162, 0x00616263, 4441,
yobj.obj_id, 3331, 4442,
xobj.obj_id, 0, 4443},
1, 10},
{call_xtype_evt_yellow, &intf_xtype.funcs[1][0], {0},
{4441}, 0, 1},
{call_ytype_req_green, &intf_ytype.funcs[0][0], {7771},
{4441, 4, 0x00616562, 0, 5, 0x63626263,
0x99999900, xobj.obj_id,
8, 0x80818081,
0x99999990},
1, 11},
{call_ytype_evt_red, &intf_ytype.funcs[1][0],
{8881, 8882, 8883},
{7770, 33330, 7771, 33331, 33332, 7773,
33333, 44440, 6,
0x62616362, 0x99990061,
3, 0x11808080, 99990, 0,
yobj.obj_id,
xobj.obj_id},
3, 17}};
struct wp_object *new_obj =
listset_get(&mt.objects, new_id);