/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* Copyright (c) 2025 Brett A C Sheffield <bacs@librecast.net> */

#include "test.h"
#include <assert.h>
#include <librecast/net.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>

void handle_sigint(int signo, siginfo_t *info, void *context)
{
	(void)signo, (void) info, (void)context;
}

static pid_t fork_and_recv(void)
{
	pid_t pid = fork();
	if (pid) return pid;

	/* child continues */
	char buf[BUFSIZ];
	ssize_t byt;
	int ret = EXIT_FAILURE;

	struct sigaction act = {0};
	act.sa_sigaction = &handle_sigint;
	if (sigaction(SIGINT, &act, NULL) == -1) {
		perror("sigaction");
		_exit(EXIT_FAILURE);
	}

	lc_ctx_t *lctx;
	lc_socket_t *sock;
	lc_channel_t *chan;

	lctx = lc_ctx_new();
	if (!(test_assert(lctx != NULL, "lc_ctx_new()"))) _exit(EXIT_FAILURE);
	sock = lc_socket_new(lctx);
	if (!(test_assert(sock != NULL, "lc_socket_new()"))) goto free_lctx;
	chan = lc_channel_new(lctx, "0000-0090");
	if (!(test_assert(chan != NULL, "lc_channel_new()"))) goto free_lctx;
	lc_channel_bind(sock, chan);

	/* wait for signal */
	assert(chan);
	byt = lc_channel_recv(chan, buf, sizeof buf, 0);
	test_assert(errno == EINTR, "EINTR");
	test_assert(byt == -1, "lc_channel_recv() returned %zi", byt);

	ret = EXIT_SUCCESS;
free_lctx:
	lc_ctx_free(lctx);
	_exit(ret);
}

int main(void)
{
	char name[] = "EINTR: recv calls can be interupted with signals";
	pid_t pid;
	int wstatus;
	int rc;

	test_name(name);
	if (RUNNING_ON_VALGRIND) return TEST_WARN;

	pid = fork_and_recv();
	if (!test_assert(pid != -1, "fork returned %i", pid)) return test_status;

	usleep(10000);
	test_log("sending SIGINT to pid %i\n", pid);
	kill(pid, SIGINT);

	rc = waitpid(pid, &wstatus, 0);
	if (!test_assert(WIFEXITED(wstatus), "WIFEXITED")) return test_status;
	rc = WEXITSTATUS(wstatus);
	if (!test_assert(rc == EXIT_SUCCESS, "child exited with %i", rc)) return test_status;


	return test_status;
}
