#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>


int
main(int argc, char **argv)
{
	int s;
	int r, t;
#define BUFLEN 1024
	char buf[BUFLEN + 1];

	struct hostent *info;
	struct sockaddr_in addr;
	socklen_t addrlen;

	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (s < 0) {
		perror("socket()");
		return EXIT_FAILURE;
	}

	r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) &t, sizeof(t));
	if (r < 0) {
		perror("setsockopt");
		close(s);
		return EXIT_FAILURE;
	}

	printf("bind %s\n", argv[1]);
	info = gethostbyname(argv[1]);
	if (info == NULL) {
		perror("gethostbyname(local)");
		close(s);
		return EXIT_FAILURE;
	}
	memcpy(&addr.sin_addr, info->h_addr, info->h_length);
	addr.sin_family = info->h_addrtype;

	r = bind(s, (struct sockaddr *) &addr, sizeof(addr));
	if (r < 0) {
		perror("bind()");
		close(s);
		return EXIT_FAILURE;
	}

	printf("connect to %s, port %d\n", argv[2], atoi(argv[3]));
	info = gethostbyname(argv[2]);
	if (info == NULL) {
		perror("gethostbyname(remote)");
		close(s);
		return EXIT_FAILURE;
	}
	memcpy(&addr.sin_addr, info->h_addr, info->h_length);
	addr.sin_family = info->h_addrtype;
	addr.sin_port = htons(atoi(argv[3]));

	r = connect(s, (struct sockaddr *) &addr, sizeof(addr));
	if (r < 0) {
		perror("connect()");
		close(s);
		return EXIT_FAILURE;
	}

	addrlen = sizeof(addr);
	r = getsockname(s, (struct sockaddr *) &addr, &addrlen);
	if (r < 0) {
		perror("getsockanem()");
		close(s);
		return EXIT_FAILURE;
	}

	info = gethostbyaddr(&addr.sin_addr.s_addr, sizeof(struct in_addr),
			AF_INET);
	if (info == NULL) {
		perror("gethostbyaddr()");
		close(s);
		return EXIT_FAILURE;
	}

	printf("sockname: %s\n", info->h_name);

	if (argv[4] != NULL) {
		r = send(s, argv[4], strlen(argv[4]), 0);
		if (r < 0) {
			perror("send()");
			close(s);
			return EXIT_FAILURE;
		}
		r = send(s, "\r\n\r\n", 4, 0);
		if (r < 0) {
			perror("send()");
			close(s);
			return EXIT_FAILURE;
		}

		buf[BUFLEN] = '\0';
		while (1) {
			r = recv(s, buf, 1024, 0);
			if (r < 0) {
				perror("recv()");
				break;
			} else if (r == 0) {
				break;
			}
			buf[r] = '\0';
			printf("%s", buf);
			fflush(stdout);
		}
	}

	close(s);

	return EXIT_SUCCESS;
}
