#include <stdio.h>
#include <stdlib.h>	/* EXIT_FAILURE */

#include <string.h>	/* memset(3) */

#include <errno.h>

#include <assert.h>

#include <fcntl.h>	/* close(2) */

#if _WIN32
#include <winsock2.h>
#else
#include <sys/time.h>	/* struct timeval */
#include <sys/socket.h>	/* AF_INET socklen_t struct sockaddr
			 * struct sockaddr_storage */

#include <netinet/in.h>	/* struct sockaddr_in */
#endif

#include <unistd.h>	/* close(2) */

#include <err.h>	/* err(3) errx(3) */

#include <event.h>	/* struct event struct event_base event_init(3)
			 * event_base_loop(3) */

#include <arena/proto.h>

#include "socket.h"
#include "lookup.h"
#include "tls.h"


static int pending	= 2;


static void main_catch_accept(struct socket *s, struct socket *p, enum socket_errno so_errno, void *arg) {
	struct tls *tls;

	if (so_errno == SOCKET_ECANCELLED)
		return; /* void */;

	if (so_errno != SOCKET_ESUCCESS)
		err(EXIT_FAILURE, "socket_accept: %s", socket_errlist[so_errno]);

	socket_getsockinfo(p, 0, &tls);

	if (tls != 0)
		warnx("caught TLS accept");
	else
		warnx("caught accept");

	socket_close(s);
	socket_close(p);

	return /* void */;
} /* main_catch_accept() */


static void main_catch_connect(struct socket *s, enum socket_errno so_errno, void *arg) {
	struct tls *tls	= 0;

	assert(so_errno == SOCKET_ESUCCESS);

	socket_getsockinfo(s, 0, &tls);

	if (tls != 0)
		warnx("caught TLS connect");
	else
		warnx("caught connect");

	socket_close(s);

	return /* void */;
} /* main_catch_connect() */


int main(int argc, char *argv[]) {
	struct event_base *ev_base;
	struct tls_identity *tid;
	enum tls_errno tls_errno;
	enum socket_errno so_errno;
	struct socket *server, *client;
	struct socket_name so_name;
	struct sockaddr_in sin;
	struct socket_options opts;
#if _WIN32
	WSADATA wsaData;
#endif

#if _WIN32
	if (NO_ERROR != WSAStartup(MAKEWORD(2, 2), &wsaData))
		err(EXIT_FAILURE, "WSAStartup");
#endif

	if (!(ev_base = event_init()))
		err(EXIT_FAILURE, "event_init");

	(void)memset(&sin, '\0', sizeof sin);

	sin.sin_family		= AF_INET;
	sin.sin_port		= htons(4000);
	sin.sin_addr.s_addr	= htonl(INADDR_LOOPBACK);

	(void)socket_name_init_addr(&so_name, (struct sockaddr *)&sin, sizeof sin);

	opts			= socket_defaults;
	opts.sa_reuseaddr	= 1;
	opts.sin_resolv		= 1;

	if (0 == (server = socket_open(&so_name, &opts, ev_base, ARENA_STDLIB, &so_errno)))
		err(EXIT_FAILURE, "socket_open");

	(void)socket_name_init_host(&so_name, "localhost", "4000", LOOKUP_IN_A, 0);

	if (0 == (client = socket_open(&so_name, &socket_defaults, ev_base, ARENA_STDLIB, &so_errno)))
		err(EXIT_FAILURE, "socket_open");

	if (argc > 2) {
		assert(0 == tls_init());

		if (!(tid = tls_identity_open(&tls_defaults, 0, &tls_errno)))
			errx(EXIT_FAILURE, "tls_context_open: %s", tls_errlist[tls_errno]);

		assert(argc > 2);

		assert(0 == tls_identity_certify(tid, argv[1], argv[2]));

		socket_enable_tls(server, tid);
		socket_enable_tls(client, tid);
	}

	socket_accept(server, &main_catch_accept, server, 0);

	socket_connect(client, &main_catch_connect, client, 0);

	event_base_loop(ev_base, 0);

	return 0;
} /* main() */



syntax highlighted by Code2HTML, v. 0.9.1