#include #include #include #include #include #include #include #include #include #include #include #include #include #include "../include/better_string.h" #include "../include/hash_table.h" #include "../include/helpers.h" #include "../include/list.h" #include "../include/opcodes.h" #include "../include/protocol.h" #include "../include/tsv.h" #include "../include/opcodes.h" int PORT = DEFAULT_PORT; int nfds = 1; struct pollfd fds[MAX_CONNECTIONS * 2]; ht_t *CHAN; ht_t *USERS; void handle_sigint(int sig) { for (int i = 0; i < nfds; i++) { if (fds[i].fd >= 0) { close(fds[i].fd); } } exit(0); } list_t *tokenize_buf(char *buf) { tsv_t *tsv = init_tsv(buf); string_t *s = tsv_next(tsv); list_t *a = init_list(); while (s) { list_push_back(a, s); s = tsv_next(tsv); } return a; } void set_non_blocking(int sock) { int flags = fcntl(sock, F_GETFL, 0); int code = fcntl(sock, F_SETFL, flags | O_NONBLOCK); die_lz(code, "fcntl()"); } int main(int argc, char **argv) { char buffer[MAX_BUFSIZE]; char res_buffer[MAX_BUFSIZE]; struct pollfd *local_fds1 = fds; struct pollfd *local_fds2 = fds + MAX_CONNECTIONS; struct pollfd *local_fds = local_fds1; /* We start by initializing our net-related structs */ signal(SIGINT, handle_sigint); int listen_sd = socket(AF_INET6, SOCK_STREAM, 0); int optval = 1; die_lz(listen_sd, "socket()"); int reuse = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)); die_lz(reuse, "setsockopt()"); int nonblock = ioctl(listen_sd, FIONBIO, (char *)&optval); die_lz(nonblock, "ioctl()"); set_non_blocking(listen_sd); /* Make new address */ struct sockaddr_in6 addr; alloc_zero(&addr, sizeof(addr)); addr.sin6_family = AF_INET6; memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any)); addr.sin6_port = htons(DEFAULT_PORT); int sock_bind = bind(listen_sd, (struct sockaddr *)&addr, sizeof(addr)); die_lz(sock_bind, "bind()"); int sock_listen = listen(listen_sd, 32); die_lz(sock_listen, "listen()"); /* The first fd entry is the listening socket for new connections; all the rest are sockets we read from and write to. Whenever a client connects, we know from the listening socket. */ alloc_zero(fds, sizeof(fds)); fds[0].fd = listen_sd; fds[0].events = POLLIN; int timeout = 6000; int sock_poll; bool end_server = false; /* mainloop */ do { bool compress_array = false; /* if an fd loses connection, we want to remove all -1's from the fds array */ sock_poll = poll(local_fds, nfds, timeout); die_lz(sock_poll, "poll()"); for (int i = 0; i < nfds; i++) { if (local_fds[i].revents == 0) continue; if (local_fds[i].revents != POLLIN) { end_server = true; break; } if (local_fds[i].fd == listen_sd) { printf("socket is readable\n"); int new_sd; do { new_sd = accept(listen_sd, NULL, NULL); if (new_sd < 0 && errno != EWOULDBLOCK) { perror("accept() failed"); end_server = true; break; } local_fds[nfds].fd = new_sd; local_fds[nfds].events = POLLIN; nfds++; } while (new_sd >= 0); } else { bool close_conn = false; int fd_recv; int fd_send; fd_recv = recv(local_fds[i].fd, buffer, sizeof(buffer), 0); if (fd_recv < 0 && errno != EWOULDBLOCK) { perror("recv() failed"); close_conn = true; } else if (fd_recv == 0) { printf("Connection closed\n"); close_conn = true; } else { list_t *tokens = tokenize_buf(buffer); string_t *opcode = list_pop_front(tokens); int op = encode_server_opcode(opcode->buf); switch (op) { case CO_NCK: break; case CO_JN: break; case CO_NOP: break; case CO_PST: break; case CO_DM: break; case CO_QT: break; case CO_LVE: break; default: break; } fd_send = send(local_fds[i].fd, buffer, fd_recv, 0); if (fd_send < 0) { perror("send()"); close_conn = true; } } if (close_conn) { close(local_fds[i].fd); local_fds[i].fd = 0; compress_array = true; } } } if (compress_array) { int cur_nfds = nfds; nfds = 0; for (int i = 0; i < cur_nfds; i++) { if (local_fds[i].fd != 0) { local_fds2[nfds] = local_fds[i]; nfds++; } } local_fds1 = local_fds2; local_fds2 = local_fds; local_fds = local_fds1; alloc_zero(local_fds2, MAX_CONNECTIONS); } } while (!end_server); for (int i = 0; i < nfds; i++) { if (fds[i].fd >= 0) { close(fds[i].fd); } } return 0; }