#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


int guard(int n, char *err)
{
  if (n == -1)
  {
    perror(err);
    exit(1);
  }
  return n;
}


int g_fd = 0;

void printflag()
{
  printf("Hello!");
  char *flag = getenv("IG_FLAG");
  send(g_fd, flag, strlen(flag), 0);
  send(g_fd, "\n", 1, 0);
}

int login(int fd)
{
  g_fd = fd;
  char pw[32] = {0};
  char *pwd = "Enter the password:\n";
  char *correct = "Correct!\n";

  printf("%x\n",(long)*(&pw + 32 + 8));
  sprintf(pw, "%s\r\n", getenv("IG_PASSWORD"));


  char buf[32];

  send(fd, pwd, strlen(pwd), 0);

  ssize_t num_bytes_received = guard(recv(fd, buf, 96, 0), "Could not recv on TCP connection");
  if (num_bytes_received <2)
    return 0;

  //buf[num_bytes_received-2] = 0;

  if (strcmp(buf, pw))
  {
    return 0; 
  }
  else
  {
    send(fd, correct, strlen(correct), 0);
    printflag(fd);
    return 1;
  }
}

int main(void)
{
   char *wrong = "Wrong!\n";
  int opt = 1;
  int listen_fd = guard(socket(AF_INET, SOCK_STREAM, 0), "Could not create TCP socket");
  printf("Created new socket %d\n", listen_fd);

  struct sockaddr_in listen_addr = {0};

  listen_addr.sin_family = AF_INET;
  listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  listen_addr.sin_port = htons(2345);

  guard(setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
                   &opt, sizeof(opt)),
        "could not set opt");
  guard(bind(listen_fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)), "Could not bind");
  guard(listen(listen_fd, 100), "Could not listen on TCP socket");

  printf("Listening for connections on port %d\n", ntohs(listen_addr.sin_port));
  for (;;)
  {
    int conn_fd = accept(listen_fd, NULL, NULL);
    printf("Got new connection %d\n", conn_fd);
    if (guard(fork(), "Could not fork") == 0)
    {
      pid_t my_pid = getpid();
      printf("%d: forked\n", my_pid);
      char buf[100];

      sprintf(buf, "Pointer to printflag is %p\n", printflag);	
      guard(send(conn_fd, buf, strlen(buf), 0), "Could not send to TCP connection");

      if (!login(conn_fd)) {
        send(conn_fd, wrong, strlen(wrong), 0);
      }
      
      printf("%d: received end-of-connection; closing connection and exiting\n", my_pid);
      guard(shutdown(conn_fd, SHUT_WR), "Could not shutdown TCP connection");
      guard(close(conn_fd), "Could not close TCP connection");
      exit(0);
    }
    else
    {
      // Child takes over connection; close it in parent
      close(conn_fd);
    }
  }
  return 0;
}
