/* COMPILE:     gcc server.c -o server -lsocket -lnsl
		gcc client.c -o client -lsocket -lnsl 
   NOTE:  -lsocket -lnsl  needed on SOLARIS, but can be omitted for other UNIX.
       RUN:     server 5100 &
		client localhost 5100
   (or accept default PORTNUM)
*/

#ifndef DATAGRAM
#define STREAM  /* default service (tcp protocol) */
#endif

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

#define SERVER_HOST "procyon.ccs.neu.edu" /* replace by yours */
#define PORTNUM 5100 /* replace by yours -- this is public part of protocol */

main(int argc, char ** argv)
{
  int socket_to_server;
  struct hostent *server_ent; /* holds return value of gethostbyname() */
  struct sockaddr_in server_addr;
#ifdef DATAGRAM
  int server_addr_len;
#endif
  int msglen;
  struct timezone time_zone;
  struct timeval time_val;
  long host_time, client_time, time_difference;
  char buffer[256];
  char *server_host;
  int portnum;

  server_host = ( argc == 3 ? argv[1] : SERVER_HOST );
  portnum = ( argc == 3 ? atoi(argv[2]) : PORTNUM );

  /* create socket */
#ifdef STREAM
  socket_to_server = socket(AF_INET, SOCK_STREAM, 0);
#else
  socket_to_server = socket(AF_INET, SOCK_DGRAM, 0);
#endif

  /* Construct server address.
     (Assumes remote server and port are public information.)
    This has three parts: protocol family, server internet address, and port */
  /* VERY IMPORTANT:  zero out ALL fields of server_addr before using it */
  bzero((char *)&server_addr, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_ent = gethostbyname(server_host); /* returns internet address */
  bcopy(server_ent->h_addr, (char *)&server_addr.sin_addr,
	server_ent->h_length);
  /* Alternative:  ( INET_NETWORK_NUMBER is string of form "129.xx.xx.xx" )
     server_addr.sin_addr.s_addr = inet_addr(INET_NETWORK_NUMBER);
     */
  server_addr.sin_port = htons(portnum); /* htons for CPU-indep byte order */

#ifdef STREAM
  /* connect socket to remote server address (including port) */
  if (connect( socket_to_server, (struct sockaddr *)&server_addr,
				 sizeof(server_addr) )
      == -1){
    perror("client(connect)");
    exit();
  }
#endif

#ifdef DATAGRAM
  sendto(socket_to_server, "initiate", 9, 0,
	 &server_addr, sizeof(server_addr));
#endif

  /* server sending host_time in network byte order for long;
     This is necessary, for example, when communicating between
      DECstations and SUN's, which have different byte order for long int.
     We could use XDR (eXternal Data Representation), but that is
       more complicated.
     */
#ifdef STREAM
  msglen = read(socket_to_server, (char *)&host_time, sizeof(host_time));
#else
  msglen = recvfrom(socket_to_server, (char *)&host_time, sizeof(host_time), 0,
		    &server_addr, &server_addr_len);
  if(msglen == -1) {
    perror("client(recvfrom)");
    exit();
  }
#endif
  if (msglen != sizeof(host_time)) {
    printf("client:  receiving buffer not a long int, like sending buffer\n");
    exit();
  }
  host_time = ntohl(host_time);  /* convert from network to host byte order */
  gettimeofday(&time_val, &time_zone);
  client_time = time_val.tv_sec;
  time_difference = host_time - client_time;
  printf("Time discrepancy = %d seconds.\n", time_difference);
  close(socket_to_server);

  exit(0);
}

