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

#define PORT	47350
#define K	1024

#define MAXCLIENTS	1024

int nfds = 0;

struct  client {
  int dead;
} clients[MAXCLIENTS];

struct pollfd fds[MAXCLIENTS];

void newclient(int sock) {
  int i, fd;

  fd = accept(sock, NULL, NULL);
  if (fd < 0) {
    perror("accept");
    return;
  }

  printf("New connection on %d\n", fd);
  clients[fd].dead = 0;

  fds[nfds].fd = fd;
  fds[nfds].events = POLLIN;
  fds[nfds++].revents = 0;
}

struct client *disconnect(int idx)
{
  printf("Disconnecting %d\n", fds[idx].fd);
  close(fds[idx].fd);
  for(; idx < nfds-1; idx++) {
    fds[idx].fd = fds[idx+1].fd;
    fds[idx].events = fds[idx+1].events;
  }
  nfds--;
}

void broadcast(int from, char *msg, int len) {
  int i;

  printf("->%d) %.*s", from, len, msg);

  for(i=1; i < nfds; i++) {
    if (write(fds[i].fd, msg, len) < 0) clients[fds[i].fd].dead = 1;
  }
}

int main(int argc, char *argv[])
{
  struct sockaddr_in server;
  char buf[K];
  int sock, r, i;

  sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0) {
    perror("socket");
    exit(1);
  }
  r = 1;
  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &r, sizeof(r));
  
  server.sin_family = AF_INET;
  server.sin_addr.s_addr = INADDR_ANY;
  server.sin_port = htons(PORT);
  if (bind(sock, (struct sockaddr *)&server, sizeof(server))) {
    perror("bind");
    exit(1);
  }
  if (listen(sock, 5) < 0) {
    perror("listen");
    exit(1);
  }

  fds[nfds].fd = sock;
  fds[nfds].events = POLLIN;
  fds[nfds++].revents = 0;

  for(;;) {
    r = poll(fds, nfds, -1);
    if (r <= 0) continue;

    if (fds[0].revents & POLLIN) newclient(sock);
    for(i=1; i<nfds;) {
      if ((fds[i].revents & (POLLERR|POLLHUP)) || clients[fds[i].fd].dead) {
	disconnect(i);
	continue;
      }
      if (fds[i].revents & POLLIN) {
	r = read(fds[i].fd, buf, K);
	if (r <= 0) {
	  disconnect(i);
	  continue;
	}
	broadcast(fds[i].fd, buf, r);
      }
      i++;
    }
  }
  // Not reached:
  return 0;
}
