// from: http://beej.us/guide/bgnet/html/#a-simple-stream-client

/*
** client.c -- a stream socket client demo
*/

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

#include <arpa/inet.h>

#define PORT "3490" // the port client will be connecting to 

#define MAXDATASIZE 100 // max number of bytes we can get at once 

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

/*
  returns a socket FD if connection successful.

  return negative on error.
 */
int do_connection(int argc, char * argv[], unsigned short port) {
  int sockfd;
  
    struct addrinfo hints, *servinfo = NULL;
    int rv;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET; // AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM; // TCP
    //hints.ai_socktype = SOCK_DGRAM; // UDP

    char s_port[100]; // note: max port number is 65535
    snprintf(s_port, 99, "%u", port);
    
    if ((rv = getaddrinfo(argv[1], s_port, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
	freeaddrinfo(servinfo); // all done with this structure
        return -1;
    }

    // note: better to loop through servinfo...

    if ((sockfd = socket(servinfo->ai_family, servinfo->ai_socktype,
			 servinfo->ai_protocol)) == -1) {
      perror("client: socket");
      freeaddrinfo(servinfo); // all done with this structure
      return -1;
    }

    //printf("sockfd: %d\n", sockfd);

    // we do expect this to fail sometimes, most of the time actually
    if (connect(sockfd, servinfo->ai_addr, servinfo->ai_addrlen) == -1) {
      close(sockfd);
      // perror("client: connect");
      freeaddrinfo(servinfo); // all done with this structure
      return -1;
    }

    freeaddrinfo(servinfo); // all done with this structure

    // opened a socket to the other side. Can we send?
    // For UDP, it will always seems like it succeeded. We tried it.
    /*
    if (send(sockfd, "hello", 5, 0) == 5) {
      // success
      return sockfd;
    }
    else  {
      // could not send
      close(sockfd);
      return -1;
    }
    */
    
    return sockfd;
}

int main(int argc, char *argv[])
{
  int sockfd;

    if (argc != 2) {
        fprintf(stderr,"usage: ./port_scanner.o hostname\n");
	// ./port_scanner.o hostname low high
	//    low -  smallest port to try
	//    high - largest port to try
        exit(1);
    }

    // loop through all possible ports
    for(int port=0; port < (1 << 16)-1; port++) {
      sockfd = do_connection(argc, argv, port);
      if (sockfd >= 0) {
	printf("Port open: %u\n", port);
	close(sockfd);
      }
    }
    
    return 0;
}