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

#define K	1024

void handle(int sock)
{
  struct utsname un;
  time_t t;
  char buf[K];
  int m, r;

  printf("Accepted connect on descriptor %d\n", sock);
  uname(&un);
  while ((r = read(sock, &m, sizeof(m))) > 0) {
    m = ntohl(m);
    printf("msg = %d\n", m);
    switch(m) {
      case 0:
	t = time(NULL);
	snprintf(buf, K, "%s", ctime(&t));
	r = write(sock, buf, strlen(buf)-1);
	break;
      case 1:
	r = write(sock, un.sysname, strlen(un.sysname)+1);
	break;
      case 2:
	r = write(sock, un.nodename, strlen(un.nodename)+1);
	break;
      case 3:
	r = write(sock, un.release, strlen(un.release)+1);
	break;
      case 4:
	r = write(sock, un.version, strlen(un.version)+1);
	break;
      case 5:
	r = write(sock, un.machine, strlen(un.machine)+1);
	break;
      default:
	r = write(sock, "??", 2);
	break;
    }
    if (r < 0) break;
  }
  printf("Connection closed. %d\n", r);
}

int main(int argc, char *argv[])
{
  struct sockaddr_in server;
  int sock, msgsock, so = 1;

  sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0) {
    perror("socket");
    exit(1);
  }
  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &so, sizeof(so));
  
  server.sin_family = AF_INET;
  server.sin_addr.s_addr = INADDR_ANY;
  server.sin_port = htons(47350);
  if (bind(sock, (struct sockaddr *)&server, sizeof(server))) {
    perror("bind");
    exit(1);
  }
  /* Start accepting connections */
  /* Maximum backlog of: /proc/sys/net/core/somaxconn (128) */
  if (listen(sock, 5) < 0) {
    perror("listen");
    exit(1);
  }

  for(;;) {
    // Waits for a connection:
    msgsock = accept(sock, NULL, NULL);
    if (msgsock < 0) {
      perror("accept");
      continue;
    }
    handle(msgsock);
    close(msgsock);
  }
  // Not reached:
  return 0;
}
