/* This thing checks buffered i/o for basic functionality */

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "bufio.h"
#include "select.h"
#include "socket.h"

#define	TEST_STR "wwzzzoooooooooooooooooommmmm"

sockset_t *sockset;
int c = 0;


void
die(char *fmt, ...) {
	va_list ap;

	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	va_end(ap);

	exit(1);
}


/* server */

void
write_now(sock_t *sock, void *data) {
	if (++c == 2) {
		printf("bye\n");
		pause(); /* yawn */

		exit(0);
	}
}

void
connection_available(sock_t *sock, void *data) {
	sock_t *talksock = sock_accept(sock);

	if (! talksock)
		return;

	if (! bufio_init(talksock))
		die("s bufio_init() failed: (%d) %s\n", errno, strerror(errno));

	if (! sockset_add(sockset, talksock))
		die("s sockset_add() failed: (%d) %s\n", errno, strerror(errno));

	if (! bufio_write(talksock, strlen(TEST_STR), TEST_STR, write_now, NULL))
		die("s bufio_write() failed: (%d) %s\n", errno, strerror(errno));
}


/* client */

void
read_now(sock_t *sock, int len, char *buf, void *data) {
	if (len != strlen(TEST_STR) || strncmp(buf, TEST_STR, len)) {
		die("%.*s doesn't match with %s.. wrong, man!\n", len, buf, TEST_STR);
	}

	if (++c == 2) {
		printf("bye\n");

		exit(0);
	}
}

void
connection_done(sock_t *sock, void *data) {
	sock->state = SS_IDLE;

	if (! bufio_init(sock))
		die("c bufio_init() failed: (%d) %s\n", errno, strerror(errno));

	if (! bufio_read(sock, strlen(TEST_STR), read_now, NULL))
		die("c bufio_read() failed: (%d) %s\n", errno, strerror(errno));
}


int
main(int argc, char *argv[]) {
	sock_t *sock1, *sock2;

	/* server */
	if (strstr(argv[0], "test3-srv")) {
		/* open two listening sockets */

		sock1 = sock_listen("", 65432, 1);
		if (! sock1)
			die("s sock_listen() failed: (%d) %s\n", errno, strerror(errno));

		sock_sethandler_r(sock1, connection_available, NULL);

		sock2 = sock_listen("", 65433, 1);
		if (! sock2)
			die("s sock_listen() failed: (%d) %s\n", errno, strerror(errno));

		sock_sethandler_r(sock2, connection_available, NULL);

		/* make a sockset from them */

		sockset = sockset_get();
		if (! sockset)
			die("s sockset_get() failed: (%d) %s\n", errno, strerror(errno));

		if (! sockset_add(sockset, sock1))
			die("s sockset_add(sock1) failed: (%d) %s\n", errno, strerror(errno));

		if (! sockset_add(sockset, sock2))
			die("s sockset_add(sock2) failed: (%d) %s\n", errno, strerror(errno));

		/* and select */

		while (sockset_check(sockset));

		die("s sockset_check() failed: (%d) %s\n", errno, strerror(errno));

		/* client */
	} else {
		sleep(1);

		/* open two connecting sockets */

		sock1 = sock_connect("127.0.0.1", 65432, 1);
		if (! sock1)
			die("c sock_connect() failed: (%d) %s\n", errno, strerror(errno));

		sock_sethandler_r(sock1, connection_done, NULL);

		sock2 = sock_connect("127.0.0.1", 65433, 1);
		if (! sock2)
			die("c sock_connect() failed: (%d) %s\n", errno, strerror(errno));

		sock_sethandler_r(sock2, connection_done, NULL);

		/* make a sockset from them */

		sockset = sockset_get();
		if (! sockset)
			die("c sockset_get() failed: (%d) %s\n", errno, strerror(errno));

		if (! sockset_add(sockset, sock1))
			die("c sockset_add(sock1) failed: (%d) %s\n", errno, strerror(errno));

		if (! sockset_add(sockset, sock2))
			die("c sockset_add(sock2) failed: (%d) %s\n", errno, strerror(errno));

		/* and select */

		while (sockset_check(sockset));

		die("c sockset_check() failed: (%d) %s\n", errno, strerror(errno));
	}

	return 0;
}
