#include #include #include #include #include #include #include #include #include #include // debug /////////// struct s_client { int fd; int id; struct s_client *next; } typedef t_client; t_client *g_clients = NULL; int g_id = 0; int lsocket = -1; fd_set rfds; fd_set wfds; //////////// int extract_message(char **buf, char **msg); char *str_join(char *buf, char *add); void init(int port); t_client *new_client(int fd); t_client *close_client(t_client *client_to_close); void broadcast(t_client *client, char *str); int read_client(t_client *client); void free_all(); void fatal_error(); ssize_t ft_print(int fd, char *buf); //////////// int main(int argc, char** argv) { // int count = 0; // force exit debug int fd_max; t_client *clients; int new_fd; int client_id; t_client *last_connected; char announce_msg[420]; int ret; if (argc != 2) { ft_print(STDERR_FILENO, "Wrong number of arguments\n"); exit(1); } init(atoi(argv[1])); fcntl(lsocket, F_SETFL, O_NONBLOCK); // debug while (1) { // reset rfds and wfds fd_max = lsocket; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_SET(lsocket, &rfds); clients = g_clients; while (clients) { if (clients->fd > fd_max) fd_max = clients->fd; FD_SET(clients->fd, &rfds); FD_SET(clients->fd, &wfds); clients = clients->next; } // multiplexing (select) select(fd_max + 1, &rfds, &wfds, NULL, NULL); // accept new connection if (FD_ISSET(lsocket, &rfds)) { new_fd = accept(lsocket, NULL, NULL); fcntl(new_fd, F_SETFL, O_NONBLOCK); // debug last_connected = new_client(new_fd); sprintf(announce_msg, "server: client %d just arrived\n", last_connected->id); broadcast(last_connected, announce_msg); // debug // ++count; // printf("count: %d\n", count); // if (count == 7) // break; } // read incoming clients messages clients = g_clients; while (clients) { ret = 1; if (FD_ISSET(clients->fd, &rfds)) ret = read_client(clients); if (ret == 0) { client_id = clients->id; clients = close_client(clients); sprintf(announce_msg, "server: client %d just left\n", client_id); broadcast(NULL, announce_msg); } else clients = clients->next; } } free_all(); return (0); } void init(int port) { struct sockaddr_in servaddr; lsocket = socket(AF_INET, SOCK_STREAM, 0); if (lsocket == -1) fatal_error(); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(2130706433); //127.0.0.1 servaddr.sin_port = htons(port); if (bind(lsocket, (const struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) fatal_error(); if (listen(lsocket, 10) != 0) fatal_error(); } t_client *new_client(int fd) { t_client *new; new = calloc(1, sizeof (t_client)); if (!new) fatal_error(); new->fd = fd; new->id = g_id++; if (!g_clients) g_clients = new; else { t_client *last = g_clients; while (last->next) last = last->next; last->next = new; } return (new); } t_client *close_client(t_client *client_to_close) { t_client *next_client = client_to_close->next; t_client *clients = g_clients; if (g_clients == client_to_close) { g_clients = next_client; } else { while (clients->next != client_to_close) clients = clients->next; clients->next = next_client; } close(client_to_close->fd); free(client_to_close); return (next_client); } void broadcast(t_client *client, char *str) { t_client *clients = g_clients; while (clients) { if (clients != client && FD_ISSET(clients->fd, &wfds)) { send(clients->fd, str, strlen(str), 0); } clients = clients->next; } } int read_client(t_client *client) { char *buf; int recv_ret; buf = malloc(420000); if (!buf) fatal_error(); recv_ret = recv(client->fd, buf, 420000, 0); if (recv_ret > 0) { buf[recv_ret] = '\0'; if (recv_ret == 420000) // debug ft_print(STDERR_FILENO, "Oupsi, ca depasse. Il faut malloc mon petit\n"); char buf_sprintf[420]; char *msg; char *final_msg; int ret = 1; while (ret == 1) { msg = NULL; ret = extract_message(&buf, &msg); if (ret == -1) { free(buf); fatal_error(); } if (!msg) msg = buf; if (msg && msg[0] != 0) { sprintf(buf_sprintf, "client %d: ", client->id); final_msg = str_join(buf_sprintf, msg); free(msg); if (!final_msg) { free(buf); fatal_error(); } broadcast(client, final_msg); free(final_msg); } else free(msg); } } else { free(buf); } return (recv_ret); } void free_all() { if (lsocket != -1) close(lsocket); while (g_clients) close_client(g_clients); } void fatal_error() { ft_print(STDERR_FILENO, "Fatal error\n"); free_all(); exit(1); } ssize_t ft_print(int fd, char *buf) { return write(fd, buf, strlen(buf)); } // Base example function int extract_message(char **buf, char **msg) { char *newbuf; int i; *msg = 0; if (*buf == 0) return (0); i = 0; while ((*buf)[i]) { if ((*buf)[i] == '\n') { newbuf = calloc(1, sizeof(*newbuf) * (strlen(*buf + i + 1) + 1)); if (newbuf == 0) return (-1); strcpy(newbuf, *buf + i + 1); *msg = *buf; (*msg)[i + 1] = 0; *buf = newbuf; return (1); } i++; } return (0); } // Base example function, minus the commented free() char *str_join(char *buf, char *add) { char *newbuf; int len; if (buf == 0) len = 0; else len = strlen(buf); newbuf = malloc(sizeof(*newbuf) * (len + strlen(add) + 1)); if (newbuf == 0) return (0); newbuf[0] = 0; if (buf != 0) strcat(newbuf, buf); // free(buf); strcat(newbuf, add); return (newbuf); }