/*
** client.c - a small demo client for the UDP version of the Ident protocl
**
** Author: Peter Eriksson <pen@lysator.liu.se>
*/

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "ident.h"


Perror(str)
  char *str;
{
  perror(str);
  exit(1);
}

    
main(argc,argv)
  int argc;
  char *argv[];
{
  struct uident_request request;
  struct uident_reply   reply;
  int fd, nfds;
  struct sockaddr_in addr;
  int addrlen;
  int tries;
  struct timeval wait;
  fd_set read_set;
  
  if (argc != 4)
  {
    puts("usage: query_ident {host-ip-address} {local-port] {foreign-port}");
    exit(0);
  }
  
  fd = socket(AF_INET, SOCK_DGRAM, 0);
  if (fd == -1)
    Perror("socket");
  
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = inet_addr(argv[1]);
  addr.sin_port = htons(113);
  addrlen = sizeof(addr);
  
  request.version = UIDENT_VERSION;
  request.lport = atoi(argv[2]);
  request.fport = atoi(argv[3]);
  request.laddr = addr.sin_addr.s_addr;
  
  request.reqno = 1;
  
  if (connect(fd, &addr, addrlen) == -1)
    Perror("connect");

  tries = 0;
  while (tries++ < 10)
  {
    if (send(fd, &request, sizeof(request), 0) == -1)
      Perror("send");
    putchar('.');
    fflush(stdout);
    
    FD_ZERO(&read_set);
    FD_SET(fd, &read_set);

    wait.tv_sec = 1;      /* one second between timeouts */
    wait.tv_usec = 0;

    nfds = select(FD_SETSIZE, &read_set, 0, 0, &wait);
    if (nfds < 0)
      Perror("select");

    if (nfds == 0)
    {
      putchar('-');
      fflush(stdout);
      request.reqno++;
      continue;
    }
    
    if (recv(fd, &reply, sizeof(reply), 0) == -1)
      Perror("recv");
    else
    {
      putchar('+');
      fflush(stdout);
      if (reply.reqno >= 1 && reply.reqno <= request.reqno &&
	  request.lport == reply.lport &&
	  request.fport == reply.fport &&
	  request.laddr == reply.laddr)
	break;
    }
  }

  if (tries >= 10)
  {
    puts("Request timed out");
    exit(0);
  }
  
  printf("reply.version = %d\n",  reply.version);
  printf("reply.reqno   = %d\n",  reply.reqno);
  printf("reply.lport   = %d\n",  reply.lport);
  printf("reply.fport   = %d\n",  reply.fport);
  printf("reply.laddr   = %08x\n", reply.laddr);
  
  if (reply.type == UIDENT_T_ERROR)
  {
    switch (reply.u.error.code)
    {
      case UIDENT_E_ILLEGAL_VERSION:
        printf("Error: Illegal protocol version: %d\n", reply.version);
        break;
      case UIDENT_E_INVALID_PORT:
	printf("Error: Invalid port(s): %d, %d\n", reply.lport, reply.fport);
        break;
      case UIDENT_E_NO_USER:
	printf("Error: No user\n");
        break;
      case UIDENT_E_UNKNOWN_ERROR:
	printf("Error: Unknown error\n");
        break;
      default:
        printf("Error: Unknow error code: %d\n", reply.u.error.code);
    }
    exit(1);
  }
  else
    printf("Reply: %.*s\n", reply.u.userid.idlen, reply.u.userid.buf);

  exit(0);
}
