/* ping -- Uses socket-based datagram packet to measure round-trip msg time
 *
 * Jerod Weinman
 * 27 June 2008
 */

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


#define MAX_BUF_SZ 65536

/* Convert a hostname string (ie "www.cs.grinnell.edu") to an IP address string
 *
 * Parameters:
 *  hostname, null-terminated host name string
 *
 * Postconditions: 
 *  returns a null-terminated IP address string, or NULL if a failure occurs
 */
char * host_address(char* hostname)
{
  struct addrinfo* res;
  struct sockaddr_in* saddr;

  /* Resolve the hostname to an addrinfo structure */
  if (0 != getaddrinfo(hostname, NULL, NULL, &res)) {
       return (char*)NULL;
  }

  /* Extract the sockaddr and cast to sockaddr_in */
  saddr = (struct sockaddr_in*)res->ai_addr;

  /* Convert the address to numbers-and-dots notation (a char * string)
   * (This is only necessary if a human being will read the address.)
   * Note that the string returned comes from a static memory area.
   */
  return inet_ntoa(saddr->sin_addr);

}


/* Create a connectionless datagram socket by opening a descriptor and
 * filling in address fields for a particular host
 *
 * Parameters:
 *  addr, pointer to an address structure that will be filled in
 *  hostname, null-terminated host name string containing the destination host
 *  port, port number used to connect to host on
 *
 * Postconditions:
 *  Returns a socket descriptor, or -1 on failure
 */
int mksocket(struct sockaddr_in *addr, char* hostname, int port)
{

     /* Attempt to transalte the hostname to an IP address */
     char *host_addr = host_address (hostname);

     if (host_addr == NULL)
          return -1;


     /* Set socket descriptor */
     int sock = socket(AF_INET, SOCK_DGRAM, 0);

     if (sock<0)
          return -1;

     /* Set the physical address of the socket descriptor */
     bzero(addr, sizeof(*addr));
     addr->sin_family = AF_INET;
     addr->sin_addr.s_addr = inet_addr ( host_address (hostname) );
     addr->sin_port = htons(port);

     return sock;
}

int main(int argc, char* argv[])
{
     int msgLen;                  /* Length of message we are to send */
     int sndLen,rcvLen;           /* Msg tx/rx length */
     char msg[MAX_BUF_SZ];        /* Msg sent */

     char *hostname;              /* Server we're sending ping to */
     int port;                    /* Port we want to connect on */
     int sock;                    /* Socket file descriptor */
     struct sockaddr_in addrName; /* Socket address structure */
     socklen_t addrLen;           /* Size of address structure */
     
     /* Check usage */
     if (argc!=4)
     {
          fprintf(stderr,"Usage: %s host port msgsize\n",argv[0]);
          exit (1);
     }

     /* Process arguments */
     hostname = argv[1];
     port = atoi(argv[2]);
     msgLen = atoi(argv[3]);
     
     if (msgLen > MAX_BUF_SZ)
     {
          fprintf(stderr,"%s: msgsize cannot exceed %d\n",argv[0], MAX_BUF_SZ);
          exit (1);
     }

     /* Set up socket */
     sock = mksocket (&addrName, hostname, port);
          
     if (-1 == sock)
     {
          perror("Error creating socket");
          exit (1);
     }
          
     /* Send "message" */
     sndLen = sendto (sock, &msg, msgLen, 0, 
                      (struct sockaddr*)&addrName, 
                      sizeof(addrName) );
          
     if (sndLen!= msgLen)
     {
          if (-1 == sndLen)
               perror("Error sending message");
          else
               fprintf(stderr,"Unable to send complete message");
          
          close(sock);
          exit (1);
     }
     
     /* Read return message */
     rcvLen = recvfrom (sock, msg, msgLen, 0, (struct sockaddr*) &addrName, 
                        &addrLen );
                        
          
     if (rcvLen != msgLen)
          fprintf(stderr,"Received message different length than sent\n");
     else
       printf("pong!\n");
     
     close(sock);
					
     exit (0);

          
}
