#include <stdio.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>

#define PRINTTIME(_string) \
	{\
		struct timeval now;\
		gettimeofday(&now, NULL);\
		fprintf(stdout, "time %s: %d.%06d \n", (_string), now.tv_sec, now.tv_usec);\
	}

int main(int argc, char **argv) {
	int sock_fd;
	long arg;
	int ret;
	struct timeval tv;
	fd_set myset;
	struct sockaddr_in address;
	address.sin_family = AF_INET;
	address.sin_port = htons(80);
	int delay = 1000; //1ms

	if (argc < 2) {
		fprintf(stdout, "usage: %s <ipaddr> [delay <us>]\n", argv[0]);
		return -1;
	}
	
	if (inet_pton(AF_INET, argv[1], &address.sin_addr) <= 0) {
		fprintf(stdout, "Bad address\nusage: %s <ipaddr> [delay <us>]\n", argv[0]);
		return -1;
	}

	if (argc > 2) {
		delay = atoi(argv[2]);
	}
	fprintf(stdout, "delay %dus\n", delay);

	sock_fd = socket(AF_INET,SOCK_STREAM,0);
	fprintf(stdout, "sock_fd - %d\n", sock_fd); 

	arg = fcntl(sock_fd , F_GETFL, NULL); 
	arg |= O_NONBLOCK; 
	fcntl(sock_fd, F_SETFL, arg);

	PRINTTIME("before connect");
	ret = connect(sock_fd, (struct sockaddr *)&address, sizeof(address));
	PRINTTIME(" after connect");
	fprintf(stdout, "connect ret - %d %s\n", ret, strerror(errno)); 

	if (ret < 0)
	{ 
		if (errno == EINPROGRESS) 
		{ 
			tv.tv_sec = 0; 
			tv.tv_usec = delay;

			FD_ZERO(&myset); 
			FD_SET(sock_fd , &myset); 
			
			PRINTTIME(" before select");
			ret = select(sock_fd +1, NULL, &myset, NULL, &tv);
			PRINTTIME("  after select");
			fprintf(stdout, "select ret - %d\n", ret); 
			if (ret > 0) 
			{ 
				socklen_t lon = sizeof(int); 
				int valopt = 0;
				ret = getsockopt(sock_fd , SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon); 
				fprintf(stdout, "getsockopt SO_ERROR ret - %d\n", ret); 
				
				if (valopt) 
				{ 
					fprintf(stderr, " SO_ERROR in connection %d - %s\n", valopt, strerror(valopt)); 
					exit(0); 
				} 
			}	 
			else 
			{ 
			   fprintf(stderr, "Select Timedout or error - %s\n", strerror(errno)); 
			   exit(0); 
			}
		}
	}
	return 0;
}
