diff --git a/a.out b/a.out index d6d0239..7605ae2 100755 Binary files a/a.out and b/a.out differ diff --git a/mini_serv.c b/mini_serv.c index 8cca707..c9aee6d 100644 --- a/mini_serv.c +++ b/mini_serv.c @@ -5,6 +5,8 @@ #include #include #include +#include //sprintf + // accept // atoi @@ -31,12 +33,8 @@ #define BUFSIZE 1024 -void putstr(int fd, char *str) { - write(fd, str, strlen(str)); -} - void error(char *str) { - putstr(2, str); + write(2, str, strlen(str)); exit(1); } @@ -44,50 +42,114 @@ int init_socket(struct sockaddr_in *addr, int len, int port) { int server_fd; if ( (server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) - error("Fatal error\n"); + error("Fatal error2\n"); bzero(addr, len); addr->sin_family = AF_INET; addr->sin_addr.s_addr = htonl(2130706433); //127.0.0.1 addr->sin_port = htons(port); if (bind(server_fd, (const struct sockaddr *)addr, len) == -1) - error("Fatal error\n"); + error("Fatal error3\n"); if (listen(server_fd, 10) == -1) - error("Fatal error\n"); + error("Fatal error4\n"); return server_fd; } +void broadcast(char *buf, fd_set *set, int max_fd, int server_fd, int sender_fd) { + write(1, "---\n", 4); + for(int i = 0; i <= max_fd; ++i) { + printf("[%d]\n", i); + if (i == server_fd) + { + write(1, "is server\n", 10); + continue; + } + if (i == sender_fd) + { + write(1, "is sender\n", 10); + continue; + } + if (FD_ISSET(i, set)) + { + send(i, buf, strlen(buf), 0); + write(1, buf, strlen(buf)); + } + } +} + int main(int ac, char **av) { int port; int server_fd; int client_fd; + int max_fd; + int client_id; char buf[BUFSIZE]; struct sockaddr_in addr; socklen_t addr_len; fd_set fdset; + fd_set rdset; + int clients[FD_SETSIZE]; + int ret; if (ac != 2) error("Wrong number of arguments\n"); if ( (port = atoi(av[1])) == -1) - error("Fatal error\n"); + error("Fatal error1\n"); addr_len = sizeof(addr); server_fd = init_socket(&addr, addr_len, port); + FD_ZERO(&fdset); + FD_SET(server_fd, &fdset); + max_fd = server_fd; + client_id = 0; +/* +*/ while (1) { - if ( (client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len)) == -1) - error("Fatal error\n"); - FD_ZERO(&fdset); - FD_SET(client_fd, &fdset); - select(client_fd + 1, &fdset, NULL, NULL, NULL); - if (FD_ISSET(client_fd, &fdset)) - recv(client_fd, buf, BUFSIZE, 0); - // "server: client %d just arrived\n" +// FD_ZERO(&rdset); + rdset = fdset; + + select(max_fd + 1, &rdset, NULL, NULL, NULL); + + // new connection + if (FD_ISSET(server_fd, &rdset)) + { + client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); + FD_SET(client_fd, &fdset); + clients[client_fd] = client_id; + if (client_fd > max_fd) + max_fd = client_fd; + sprintf(buf, "server: client %d just arrived\n", client_id); + broadcast(buf, &fdset, max_fd, server_fd, client_fd); + client_id++; + } + + // new message + client_fd = 0; + while(client_fd <= max_fd) { + ret = 1; + if (FD_ISSET(client_fd, &rdset)) + ret = recv(client_fd, buf, BUFSIZE, 0); + if (ret == 0) { + sprintf(buf, "server: client %d just left\n", clients[client_fd]); + write(1, buf, strlen(buf)); + broadcast(buf, &fdset, max_fd, server_fd, client_fd); + FD_CLR(client_fd, &fdset); + } + else { + sprintf(buf, "client %d: %s\n", clients[client_fd], buf); + write(1, buf, strlen(buf)); + broadcast(buf, &fdset, max_fd, server_fd, client_fd); + } + client_fd++; + } + + // "client %d: " // "server: client %d just left\n" - //while () } + return (0); } diff --git a/mini_serv_eric.c b/mini_serv_eric.c new file mode 100644 index 0000000..84cf340 --- /dev/null +++ b/mini_serv_eric.c @@ -0,0 +1,143 @@ +// #include +#include +#include +#include +#include +#include +#include +#include + +typedef struct s_clients { + int id; + char msg[1024]; +} t_clients; + +// so we just have a table of clients, no need to worry about linked lists, yea sounds good to me +t_clients clients[1024]; // 1024 otherwise would have to change FD_SETSIZE and why bother +fd_set readfds, writefds, active; +int fd_Max = 0; +int id_Next = 0; +char bufread[120000]; +char bufwrite[120000]; + +void ft_error(char *str) +{ + // 2 is stderr i guess + if (str) + write(2, str, strlen(str)); + else + write(2, "Fatal error", strlen("Fatal error")); + write(2, "\n", 1); + exit(1); +} + +// not is the fd that send the message meaning you should not send that message to that fd +void send_to_all(int not) +{ + for(int i = 0; i <= fd_Max; i++) + { + // have to check cuz we use an array not a linked list + if (FD_ISSET(i, &writefds) && i != not) + send(i, bufwrite, strlen(bufwrite), 0); // man send explains things well + } +} + + +int main(int ac, char **av) +{ + + if (ac != 2) + ft_error("Wrong number of arguments"); + + // just like in main.c + // all this is explained in the man socket, cool + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + ft_error(NULL); + + // like bzeroing i guess but for the struct fd_set, yea it clears the set, none are active + FD_ZERO(&active); + // i think this gets all the contents of the structs as well ? yes cuz it's an array not a linked list so easy to bzero + bzero(&clients, sizeof(clients)); + fd_Max = sockfd; // not sure what that does, none of this is in main.c + FD_SET(sockfd, &active); // we add sockfd to active, ok cool + + struct sockaddr_in servaddr; // like in main.c + socklen_t len; // not in main.c, i mean it kinda is but i prefer doing it this way, not even that important + bzero(&servaddr, sizeof(servaddr)); // in main.c + servaddr.sin_family = AF_INET; // like main.c + servaddr.sin_addr.s_addr = htonl(2130706433); // like main.c + servaddr.sin_port = htons(atoi(av[1])); // slightly different than main.c cuz have to get the right port + + // just like main.c, we bind and listen, normal stuff that requres specific numbers + if ((bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr))) < 0) + ft_error(NULL); + if (listen(sockfd, 10) < 0) + ft_error(NULL); + + // no longer like main.c + while(1) + { + readfds = active; + writefds = active; + + // so like if it didn't add a new one? it continues? yea idk something about making sure select has happened + if (select(fd_Max + 1, &readfds, &writefds, NULL, NULL) < 0) + continue; + + // we cycle through all the FDs we've assigned at one point so far (they may not all be active) + for (int fd_i = 0; fd_i <= fd_Max; fd_i++) + { + // for each one we check if it's set, and check if is or isn't sockfd + // ohhh this is if a client just arrived + if (FD_ISSET(fd_i, &readfds) && fd_i == sockfd) + { + // try to accept a new connection + int connfd = accept(sockfd, (struct sockaddr*)&servaddr, &len); // more or less in main.c + if (connfd < 0) + continue; // non blocking but this one didn't work + // reset fd_max + fd_Max = connfd > fd_Max ? connfd : fd_Max; // whichever is larger is the new max + clients[connfd].id = id_Next++; // we add the new client + FD_SET(connfd, &active); // add it to the list + sprintf(bufwrite, "server: client %d just arrived\n", clients[connfd].id); // create message to send out + send_to_all(connfd); + break; + } + // things other than a new connection i guess + if (FD_ISSET(fd_i, &readfds) && fd_i != sockfd) + { + // 65536 is just a big number i think + int res = recv(fd_i, bufread, 65536, 0); // similar to send, also see man recv, it's good + // something happened to a client so we tell the others this one is gone and handle clears and prevent leaks and such + if (res <= 0) // -1 is error and 0 is end of file + { + sprintf(bufwrite, "server: client %d just left\n", clients[fd_i].id); + send_to_all(fd_i); + FD_CLR(fd_i, &active); + close(fd_i); + break; + } + else + { + // we read the whole message we just received and then send it out + for(int i = 0, j = strlen(clients[fd_i].msg); i < res; i++, j++) + { + clients[fd_i].msg[j] = bufread[i]; + if (clients[fd_i].msg[j] == '\n') + { + clients[fd_i].msg[j] = '\0'; + sprintf(bufwrite, "client %d: %s\n", clients[fd_i].id, clients[fd_i].msg); + send_to_all(fd_i); + bzero(clients[fd_i].msg, strlen(clients[fd_i].msg)); + j = -1; // becomes 0 right after this at the end of the loop, i think + } + } + break; + } + } + } + } + + return (0); +} diff --git a/mini_serv_luke.c b/mini_serv_luke.c new file mode 100644 index 0000000..b44da10 --- /dev/null +++ b/mini_serv_luke.c @@ -0,0 +1,316 @@ +#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); +}