/*
 * CSSE 132
 * Rose-Hulman Institute of Technology
 * Computer Science and Software Engineering
 *
 * whoconnected.c - basic socket server that prints information about incoming
 * connections, greets clients, then disconnects them.
 * 
 * Author: Sid Stamm <stammsl@rose-hulman.edu>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>

int
main(int argc, char** argv)
{
  // The first step is to create a server socket.
  int srv_sock;   // server socket (used for listening for clients)

  // Next, construct local address structure
  struct sockaddr_in serv_addr;     // for local address
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // accept on any interface
  serv_addr.sin_port = htons(20000);

  // Create a socket for listening.
  srv_sock =  socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (srv_sock < 1) {
    printf("Failed to create server socket\n");
    return;
  }

  // lets us reuse the port immediately after we kill the server
  int optval = 1;
  setsockopt(srv_sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int));


  // Bind to address and port
  int result = 0;
  result = bind(srv_sock, (struct sockaddr*) &serv_addr, sizeof(struct sockaddr_in));
  if (result < 0) {
    printf("Failed to bind to port.\n");
    return;
  }

  // Listen for incoming connections
  result = listen(srv_sock, 5);
  if (result < 0) {
    printf("Failed to listen.\n");
    return;
  }

 
  // some variables reused for each client.
  int cli_sock;
  struct hostent* hostname;
  unsigned int sock_addr_len;
  struct sockaddr_in client_addr;   // for remote address

  // Handle incoming clients forever
  while(1)
  {
    // WARNING: must initialize this length to an appropriate size or accept()
    // won't fill the address struct with information about the client.
    sock_addr_len = sizeof(struct sockaddr_in);

    // Accept one client (into cli_sock) and put client's address into client_addr.
    cli_sock = accept(srv_sock,
                      (struct sockaddr*)&client_addr,
                      &sock_addr_len);
    printf("Connected to client socket %d\n", cli_sock);
    printf("                      len: %d\n", sock_addr_len);
    printf("                     addr: %s\n", inet_ntoa(client_addr.sin_addr));

    // It's also fun to print out the remote host's name.
    hostname = gethostbyaddr(&(client_addr.sin_addr), sizeof(client_addr.sin_addr), AF_INET);
    printf("                    name: %s\n", hostname->h_name);


    // HANDLE ONE CLIENT
    send(cli_sock, "Sup, dude?\n", 11, 0);

    // Shutdown and close (this gracefully disconnects the client)
    shutdown(cli_sock, SHUT_RDWR);
    close(cli_sock);
  }

  // outside the loop, the server has nothing left to do.  Close the server socket.
  close(srv_sock);

  return 0;
}