#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
typedef struct user {
  int socket;
  struct user *next, *prev;
} User;

int masterSocket;
User *userList;

main(int argc, char **argv)
{
  struct sockaddr_in serverAddress;
  
  masterSocket = socket(AF_INET, SOCK_STREAM, 0);
  if (masterSocket == -1) {
    perror("server");
    exit(-1);
  }
  serverAddress.sin_family = AF_INET;
  serverAddress.sin_addr.s_addr = INADDR_ANY;
  serverAddress.sin_port = htons(9001);
  if (bind(masterSocket, (struct sockaddr *)&serverAddress,
           sizeof(struct sockaddr_in))) {
    perror("server");
    exit(-1);
  }
  listen(masterSocket, 5);
  
  userList = NULL;
  for (;;) {
    int numReady;
    fd_set ready;
    User *user;
    int maxSocket = 0;
    
    FD_ZERO(&ready);
    FD_SET(masterSocket, &ready);
    maxSocket = masterSocket;
    for (user = userList; user; user = user->next) {
      int socket = user->socket;
    
      FD_SET(socket, &ready);
      if (socket > maxSocket) maxSocket = socket;
    }
    numReady = select(maxSocket+1, &ready, NULL, NULL, NULL);
    if (numReady < 0) {
      perror("server");
      exit(-1);
    }
    if (numReady > 0) {
      if (FD_ISSET(masterSocket, &ready)) {
        struct sockaddr_in addr;
        int addrLength = sizeof(addr);
        int userSocket = accept(masterSocket, (struct sockaddr *)&addr, &addrLength);
        User *user = (User *) malloc(sizeof(User));
      
        user->socket = userSocket;
        user->prev = NULL;
        user->next = userList;
        if (userList) userList->prev = user;
        userList = user;
      }
      user = userList;
      while (user) {
        User *nextUser = user->next;
        int socket = user->socket;
        if (FD_ISSET(socket, &ready)) {
          char buf[1025];
          int bytes;
          
          bytes = read(socket, buf, 1024);
          
          if (bytes < 0) {
            perror("server");
          } else if (bytes == 0) {
            if (user->next) user->next->prev = user->prev;
            if (user->prev) user->prev->next = user->next;
            else userList = user->next;
            close(user->socket);
            free(user);
          } else {
            User *otherUser;
            
            buf[bytes] = '\0';
            for (otherUser = userList; otherUser; otherUser = otherUser->next) {
              if (otherUser != user) write(otherUser->socket, buf, bytes);
            }
          }
        }
        user = nextUser;
      }
    }
  }
}

