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

int s;				/* connected socket descriptor */

struct hostent *hp;		/* pointer to host info for remote host */
struct servent *sp;		/* pointer to service information */

long timevar;			/* contains time returned by time() */
char *ctime();			/* declare time formatting routine */
     
struct sockaddr_in myaddr;	/* for local socket address */
struct sockaddr_in peeraddr;	/* for peer socket address */

int main(argc, argv)
     int argc;
     char *argv[];
{
  int addrlen, i;
  
  /* This example uses 10 byte messages. */
  char buf[10];
  
  if (argc != 5) {
    fprintf(stderr, "Usage:  %s <local address> <port> <remote address> <port>\n", argv[0]);
    exit(1);
  }
  
  /* clear out address structures */
  memset ((char *)&myaddr, 0, sizeof(struct sockaddr_in));
  memset ((char *)&peeraddr, 0, sizeof(struct sockaddr_in));
  
  /* Get the host information for our local endpoint */
  myaddr.sin_family = AF_INET;
  hp = gethostbyname (argv[1]);
  if (hp == NULL) {
    fprintf(stderr, "%s: %s not found in /etc/hosts\n",
	    argv[0], argv[1]);
    exit(1);
  }
  myaddr.sin_addr =*(struct in_addr *)(hp->h_addr);
  myaddr.sin_port=htons(atoi(argv[2]));

  /* Get the host information for the remote endpoint */
  peeraddr.sin_family = AF_INET;
  hp = gethostbyname (argv[3]);
  if (hp == NULL) {
    fprintf(stderr, "%s: %s not found in /etc/hosts\n",
	    argv[0], argv[3]);
    exit(1);
  }
  peeraddr.sin_addr =*(struct in_addr *)(hp->h_addr);
  peeraddr.sin_port=htons(atoi(argv[4]));

  
  s = socket (AF_INET, SOCK_DGRAM, 0);
  if (s == -1) {
    perror(argv[0]);
    fprintf(stderr, "%s: unable to create socket\n", argv[0]);
    exit(1);
  }

  /* Set SO_REUSEADDR */
  i = 1;
  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));

  /* Try to bind to the port built up in myaddr
   */
  if (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1) {
    perror(argv[0]);
    fprintf(stderr, "%s: unable to bind to %s:%s\n", argv[0], argv[1], argv[2]);
    exit(1);
  }

  /* Try to connect to the peer */
  if (connect(s, (struct sockaddr *)&peeraddr, sizeof(peeraddr)) != 0) {
    perror(argv[0]);
    fprintf(stderr, "%s: unable to bind to %s:%s\n", argv[0], argv[1], argv[2]);
    exit(1);
  }

  /*
   * Receive a UDP message. The remote (and local) address will be available
   * in peeraddr.
   */
  addrlen = sizeof(peeraddr);
  i = recvfrom(s, &buf, sizeof(buf), MSG_PROXY, (struct sockaddr *)&peeraddr, &addrlen );
  if ( i < 0) {
    perror("recvfrom:");
    exit(1);
  }
  /* Copy the local address to myaddr, for easier decoding */
  memcpy(&myaddr, &peeraddr.sin_zero, sizeof(peeraddr.sin_zero));

  /* Print what we receiver (one line address info, then message content)*/
  printf("Got message from: %s:%d length %d to %s:%d\n",
      inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port),i,
      inet_ntoa(myaddr.sin_addr),ntohs(myaddr.sin_port));
  fwrite(buf,i,1,stdout);
  printf("\n");
  close(s);
  return 0;
}

