#include <stdio.h>
#include <stdlib.h>

#include <inttypes.h>

#include <string.h>

#include <assert.h>

#include <err.h>

#include <sys/types.h>

#if _WIN32
#include <winsock2.h>
#else
#include <netdb.h>
#endif

#include <event.h>

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

#define USE_TLS	1


static void main_gets_catch(struct bufio *io, void *line, size_t len, enum bufio_errno err, void *fd) {
	static char buf[1024];
	int n;

	if (len > 0) {
		for (n = len - 1; n > 0; n--)
			if (((char *)line)[n] != '\r' && ((char *)line)[n] != '\n')
				break;

		warnx("read %d bytes: %.*s", (int)len, n + 1, line);
	}

	if (err != 0) {
		if (BUFIO_EOF(err)) {
			bufio_close(io);

			warnx("got EOF");
		
			return /* void */;
		} else
			errx(EXIT_FAILURE, "bufio_gets: %s", bufio_errlist[err]);
	}

	bufio_gets(io, buf, sizeof buf, &main_gets_catch, io, &(struct timeval){ 2, 0 });

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


static void main_write_catch(struct bufio *io, void *request, size_t len, enum bufio_errno err, void *fd) {
	static char buf[1024];

	if (err != 0)
		errx(EXIT_FAILURE, "bufio_write: %s", bufio_errlist[err]);

	warnx("wrote %d bytes", (int)len);

	if (len != strlen(request)) {
		bufio_write(io, (char *)request + len, strlen((char *)request + len), &main_write_catch, io, &(struct timeval){ 2, 0 });

		return /* void */;
	}

	bufio_gets(io, buf, sizeof buf, &main_gets_catch, io, &(struct timeval){ 2, 0 });

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


static void main_connect_catch(struct socket *s, enum socket_errno so_errno, void *arg) {
	static const char request[]	= "GET / HTTP/1.0\n\n";
	static int caught;
	struct bufio *io;
	enum bufio_errno bio_errno;

	if (caught)
		return /* void */;

	caught	= 1;

	assert(so_errno == SOCKET_ESUCCESS);

	warnx("connected google.com");

	assert(io = bufio_open(0, 0, &bio_errno));

	bufio_set_source(io, socket_to_source(s));
	bufio_set_sink(io, socket_to_sink(s));

	bufio_write(io, request, sizeof request - 1, &main_write_catch, io, &(struct timeval){ 2, 0 });

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


int main(void) {
	struct socket *s;
	struct socket_name so_name;
	enum socket_errno so_errno;
#if USE_TLS
	struct tls_identity *tid;
#endif
#if _WIN32
	WSADATA wsaData;
#endif

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

	event_init();
	lookup_init(0, 0, 0);
	tls_init();

#if USE_TLS
#if _WIN32
	socket_name_init_host(&so_name, "google.com", "443", LOOKUP_IN_A|LOOKUP_IN_AAAA, 0);
#else
	socket_name_init_host(&so_name, "google.com", "https", LOOKUP_IN_A|LOOKUP_IN_AAAA, 0);
#endif

	assert(tid = tls_identity_open(0, 0, 0));
#else
#if _WIN32
	socket_name_init_host(&so_name, "google.com", "80", LOOKUP_IN_A|LOOKUP_IN_AAAA, 0);
#else
	socket_name_init_host(&so_name, "google.com", "http", LOOKUP_IN_A|LOOKUP_IN_AAAA, 0);
#endif
#endif

	if (0 == (s = socket_open(&so_name, 0, 0, 0, &so_errno)))
		err(EXIT_FAILURE, "socket_open");

#if USE_TLS
	socket_enable_tls(s, tid);
#endif

#if EARLY_IO
	main_connect_catch(s, 0, s);
#endif

	socket_connect(s, &main_connect_catch, s, 0);

	event_loop(0);

	warnx("exiting");

	return 0;
} /* main() */



syntax highlighted by Code2HTML, v. 0.9.1