#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "../host_info.h" /* host info struct, TCP_HOSTS */

int main(int argc, char **argv) {
  int sock, fd, len;
  struct sockaddr_in sa;
  struct sockaddr saddr;
  struct in_addr inaddr;
  char buf[1024];
  int n;
  struct host_info hosti;
  socklen_t optlen = sizeof(struct host_info);

  if (argc != 3) {
    printf("Usage: %s svc_name port\n", argv[0]);
    exit(1);
  }

  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    printf("socket create error (%m)\n");
    return -1;
  }

  inaddr.s_addr = 0;

  sa.sin_family = AF_INET;
  sa.sin_addr = inaddr;
  sa.sin_port = htons(atoi(argv[2]));

  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&sock, sizeof(sock)) < 0)
    printf("can't set SO_REUSEADDR (%m), continuing\n");

  if (bind(sock, (struct sockaddr*)&sa, sizeof sa) < 0) {
    printf("bind error (%m)\n");
    close(sock);
    exit(1);
  }

  if (listen(sock, 0) == -1) {
    printf("listen error (%m)\n");
    close(sock);
    exit(1);
  }

  if ((fd = accept(sock, &saddr, &len)) < 0) {
    printf("accept error (%m)\n");
    close(sock);
    exit(1);
  }

  if (getsockopt(fd, SOL_TCP, TCP_HOSTS, &hosti, &optlen) < 0) {
    printf("getsockopt error (%m)\n");
  } else {
    memcpy(buf, hosti.snd_host, hosti.snd_host_len);
    buf[hosti.snd_host_len] = 0;
    printf("sockopt: snd_host = \"%s\"\n", buf);

    memcpy(buf, hosti.rcv_host, hosti.rcv_host_len);
    buf[hosti.rcv_host_len] = 0;
    printf("sockopt: rcv_host = \"%s\"\n", buf);
  }

  sa = *((struct sockaddr_in*)&saddr);

  printf("Connected from %s:%d.\n", inet_ntoa(sa.sin_addr), sa.sin_port);

  n = snprintf(buf, sizeof(buf), "Welcome!  This is %s.\n", argv[1]);

  if (send(fd, buf, n+1, 0) == -1) {
    printf("send error (%m)\n");
    close(fd);
    close(sock);
    exit(1);
  }

  for(;;){
    n = recv(fd, buf, sizeof buf, 0);

    if (n < 0) {
      printf("recv error (%m)\n");
      close(fd);
      close(sock);
      exit(1);
    }

    if (n == 0) {
      printf("socket closed (%m)\n");
      close(fd);
      close(sock);
      exit(0);
    }

    buf[n] = '\0';
    printf("%s", buf);

    /* Network convention is CRLF */
    if (n == 3 && buf[0] == '.' && buf[1] == '\r' && buf[2] == '\n') {
      close(fd);
      close(sock);
      exit(0);
    }
  }
}
