#include "testnet.h"
#include <librecast/net.h>
#include <librecast_pvt.h>
#include <semaphore.h>
#include <time.h>
#include <unistd.h>

#define WAITS 1
static sem_t timeout;

void msg_received(lc_message_t *msg)
{
	(void)msg;
	test_log("message received\n");
	sem_post(&timeout);
}

int main(void)
{
	lc_ctx_t *lctx;
	lc_socket_t *sock;
	lc_channel_t *chan;
	lc_message_t msg;
	ssize_t byt;
	struct timespec ts;
	int op = LC_OP_PING;
	int opt = 1;

	test_name("multicast ping (loopback)");
	test_require_net(TEST_NET_BASIC);

	lctx = lc_ctx_new();
	test_assert(lctx != NULL, "lctx != NULL");

	sock = lc_socket_new(lctx);
	test_assert(sock != NULL, "sock != NULL");

	chan = lc_channel_new(lctx, "example.com");
	test_assert(chan != NULL, "chan != NULL");

	test_assert(!lc_socket_setopt(sock, IPV6_MULTICAST_LOOP, &opt, sizeof(opt)),
			"set IPV6_MULTICAST_LOOP");

	test_assert(!lc_channel_bind(sock, chan), "lc_channel_bind()");
	test_assert(!lc_channel_join(chan), "lc_channel_join()");
	test_assert(!lc_socket_listen(sock, &msg_received, NULL), "lc_socket_listen()");

	/* send packet and receive on loopback */
	lc_msg_init(&msg);
	lc_msg_set(&msg, LC_ATTR_OPCODE, &op);

	byt = lc_msg_send(chan, &msg);
	test_assert((size_t)byt == msg.len + sizeof(lc_message_head_t), "%zi bytes sent", byt);
	if (byt == -1) {
		perror("lc_msg_send");
	}

	sem_init(&timeout, 0, 0);
	clock_gettime(CLOCK_REALTIME, &ts);
	ts.tv_sec += WAITS;
	test_assert(!sem_timedwait(&timeout, &ts), "timeout");
	sem_destroy(&timeout);

	test_assert(!lc_socket_listen_cancel(sock), "lc_socket_listen_cancel()");
	lc_channel_free(chan);
	lc_socket_close(sock);
	lc_ctx_free(lctx);

	return test_status;
}
