chat

idk what is
git clone git://git.evenfri.xyz/chat.git
Log | Files | Refs

server.c (3485B)


      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <unistd.h>
      4 #include <poll.h>
      5 #include <signal.h>
      6 #include <errno.h>
      7 
      8 #include <sys/socket.h>
      9 #include <netinet/in.h>
     10 
     11 #define MAX_CLIENTS 16
     12 #define BUFFER_SIZE 1024
     13 
     14 void remove_client(struct pollfd *fds, int *client_count, int index) {
     15   int i;
     16 
     17   close(fds[index].fd);
     18 
     19   for (i = index; i < *client_count; i++) {
     20     fds[i] = fds[i + 1];
     21   }
     22 
     23   (*client_count)--;
     24 }
     25 
     26 int main() {
     27   int server_fd;
     28   int client_fd;
     29   int client_count;
     30   int i;
     31   int j;
     32   int n;
     33   int result;
     34   int opt;
     35   struct sockaddr_in addr;
     36   struct pollfd fds[MAX_CLIENTS + 1];
     37   char buffer[BUFFER_SIZE];
     38 
     39   signal(SIGPIPE, SIG_IGN);
     40 
     41   server_fd = socket(AF_INET, SOCK_STREAM, 0);
     42   if (server_fd == -1) {
     43     perror("socket");
     44     return 1;
     45   }
     46 
     47   opt = 1;
     48 
     49   if (setsockopt(
     50     server_fd,
     51     SOL_SOCKET,
     52     SO_REUSEADDR,
     53     &opt,
     54     sizeof(opt)
     55   ) == -1) {
     56     perror("setsockopt");
     57     close(server_fd);
     58     return 1;
     59   }
     60 
     61   memset(&addr, 0, sizeof(addr));
     62 
     63   addr.sin_family = AF_INET;
     64   addr.sin_port = htons(8080);
     65   addr.sin_addr.s_addr = htonl(INADDR_ANY);
     66 
     67   if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
     68     perror("bind");
     69     close(server_fd);
     70     return 1;
     71   }
     72 
     73   if (listen(server_fd, 16) == -1) {
     74     perror("listen");
     75     close(server_fd);
     76     return 1;
     77   }
     78 
     79   memset(fds, 0, sizeof(fds));
     80 
     81   fds[0].fd = server_fd;
     82   fds[0].events = POLLIN;
     83 
     84   client_count = 0;
     85 
     86   printf("listening on port 8080\n");
     87 
     88   while (1) {
     89     result = poll(fds, client_count + 1, -1);
     90 
     91     if (result == -1) {
     92       if (errno == EINTR) {
     93         continue;
     94       }
     95 
     96       perror("poll");
     97       break;
     98     }
     99 
    100     /*
    101      * New client.
    102      */
    103     if (fds[0].revents & POLLIN) {
    104       client_fd = accept(server_fd, NULL, NULL);
    105 
    106       if (client_fd == -1) {
    107         perror("accept");
    108       } else if (client_count >= MAX_CLIENTS) {
    109         printf("too many clients\n");
    110         close(client_fd);
    111       } else {
    112         client_count++;
    113 
    114         fds[client_count].fd = client_fd;
    115         fds[client_count].events = POLLIN;
    116 
    117         printf("client %d connected\n", client_fd);
    118       }
    119     }
    120 
    121     /*
    122      * Existing clients.
    123      */
    124     for (i = 1; i <= client_count; i++) {
    125       /*
    126        * Error or disconnect.
    127        */
    128       if (fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) {
    129         printf("client %d disconnected\n", fds[i].fd);
    130 
    131         remove_client(fds, &client_count, i);
    132         i--;
    133 
    134         continue;
    135       }
    136 
    137       if (!(fds[i].revents & POLLIN)) {
    138         continue;
    139       }
    140 
    141       n = recv(
    142         fds[i].fd,
    143         buffer,
    144         sizeof(buffer),
    145         0
    146       );
    147 
    148       if (n == -1) {
    149         if (errno == EINTR) {
    150           continue;
    151         }
    152 
    153         perror("recv");
    154 
    155         remove_client(fds, &client_count, i);
    156         i--;
    157 
    158         continue;
    159       }
    160 
    161       if (n == 0) {
    162         printf("client %d disconnected\n", fds[i].fd);
    163 
    164         remove_client(fds, &client_count, i);
    165         i--;
    166 
    167         continue;
    168       }
    169 
    170       printf(
    171         "client %d sent %d bytes\n",
    172         fds[i].fd,
    173         n
    174       );
    175 
    176       /*
    177        * Broadcast.
    178        */
    179       for (j = 1; j <= client_count; j++) {
    180         if (j == i) {
    181           continue;
    182         }
    183 
    184         if (send(
    185           fds[j].fd,
    186           buffer,
    187           n,
    188           MSG_NOSIGNAL
    189         ) == -1) {
    190           perror("send");
    191         }
    192       }
    193     }
    194   }
    195 
    196   for (i = 1; i <= client_count; i++) {
    197     close(fds[i].fd);
    198   }
    199 
    200   close(server_fd);
    201 
    202   return 0;
    203 }