/* This code was written by Carson Gaspar, I've put it here just in case */
/* anyone else has problems with non-blocking code...                    */
#include "config.h"
#include <sys/types.h>
#include <sys/signal.h>

#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
#endif

extern int h_errno;

int main(int argc, char **argv)
{
  int mysock,status,numfds;
  short port;
  struct hostent *hent;
  struct sockaddr_in mysa;
  fd_set rfds,wfds,efds;
  struct timeval mytv;
  char buf;

  if (argc < 3) {
    fprintf(stderr, "Usage: %s hostname port\n", argv[0]);
    exit(255);
  }

  signal(SIGPIPE, SIG_IGN);

  while ((hent = gethostbyname(argv[1])) == NULL) {
    switch(h_errno) {
    case HOST_NOT_FOUND:
    case NO_RECOVERY:
    case NO_DATA:
      fprintf(stderr,"Host %s not found\n", argv[1]);
      exit(255);
      break;
    case TRY_AGAIN:
      fprintf(stderr,"Failed to get address of %s, retrying\n", argv[1]);
      break;
    }
  }

  mysa.sin_family = AF_INET;
  memcpy(&mysa.sin_addr, hent->h_addr, hent->h_length);

  errno = 0;
  port = (short) strtol(argv[2], NULL, 10);
  if (errno != 0) {
    perror("invalid port");
    exit(255);
  }
  mysa.sin_port = htons(port);

  if ((mysock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
    perror("socket failed");
    exit(255);
  }

  if (fcntl(mysock, F_SETFL, FNDELAY)) {
    perror("fcntl F_SETFL O_NONBLOCK failed");
    exit(255);
  }

  status = 0;
  if ((connect(mysock,(struct sockaddr *) &mysa, sizeof(mysa))) < 0) {
    if ((errno != EALREADY) && (errno != EINPROGRESS)) {
      perror("connect failed");
      exit(255);
    } else {
      status = 1;
      perror("connect status");
    }
  } else {
    fprintf(stderr, "connection succeeded!\n");
    exit(0);
  }

  fprintf(stderr, "first connect cancelled (intentionally!)\n");
  close(mysock);

  if ((mysock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
    perror("socket failed");
    exit(255);
  }

  if (fcntl(mysock, F_SETFL, FNDELAY)) {
    perror("fcntl F_SETFL O_NONBLOCK failed");
    exit(255);
  }

  status = 0;
  if ((connect(mysock,(struct sockaddr *) &mysa, sizeof(mysa))) < 0) {
    if ((errno != EALREADY) && (errno != EINPROGRESS)) {
      perror("connect failed");
      exit(255);
    } else {
      status = 1;
      perror("connect status");
    }
  } else {
    fprintf(stderr, "connection succeeded!\n");
    exit(0);
  }

  while(status < 2) {

    FD_ZERO(&rfds);
    FD_ZERO(&wfds);
    FD_ZERO(&efds);
    FD_SET(mysock, &rfds);
    FD_SET(mysock, &wfds);

    mytv.tv_sec = 2;
    mytv.tv_usec = 0;

    while ((numfds = select(FD_SETSIZE - 1, &rfds, &wfds, &efds, &mytv)) < 0) {
	if (errno != EINTR) {
	    perror("select failed");
	    exit(255);
	}

	FD_ZERO(&rfds);
	FD_ZERO(&wfds);
	FD_ZERO(&efds);

	FD_SET(mysock, &rfds);
	FD_SET(mysock, &wfds);
    }

    if (numfds == 0) {
	fprintf(stderr, "select returned with no fds\n");
    } else {
	if (FD_ISSET(mysock, &rfds)) {
	    fprintf(stderr, "select returned socket readable\n");
	    if (argc > 3) {
		if (read(mysock, &buf, 1) < 0) {
		    perror("connect failed: read");
		    exit(255);
		} else {
		    fprintf(stderr, "read returned ok?!?\n");
		    exit(255);
		}
	    }
		
	    if ((connect(mysock,(struct sockaddr *) &mysa, sizeof(mysa))) < 0) {
		fprintf(stderr, "connection is closed\n");
		switch (errno) {
		    case ETIMEDOUT:
			fprintf(stderr, "connect() again\n");
			exit(0);
		    case EISCONN:
			fprintf(stderr, "connection succeeded!?!\n");
			exit(0);
		    case EINVAL:
		    case EPIPE:
			perror("connect()");
			if (read(mysock, &buf, 1) < 0) {
			    perror("connect failed: read");
			    exit(255);
			} else {
			    fprintf(stderr, "read returned ok?!?\n");
			    exit(255);
			}
		    default:
			perror("connect failed");
			exit(255);
		}
	    }
	    fprintf(stderr, "connection succeeded?\n");
	}

	if (FD_ISSET(mysock, &wfds)) {
	    fprintf(stderr, "select returned socket writeble - trying to connect\n");
	    if ((connect(mysock,(struct sockaddr *) &mysa, sizeof(mysa))) < 0) {
		switch (errno) {
		    case EALREADY:
		    case EINPROGRESS:
			status = 1;
			perror("connect status");
			break;
		    case EISCONN:
			fprintf(stderr, "connection succeeded!\n");
			exit(0);
			break;
		    default:
			perror("connect failed");
			exit(255);
		}
	    } else {
		fprintf(stderr, "connection succeeded!\n");
		exit(0);
	    }
	}
    }
  }
  /* we should never get here */
  exit(1);
}
