123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- #include <string.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netdb.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/select.h>
- #include <signal.h>
- #include <stdbool.h>
- #include <errno.h>
- #include "common.h"
- #include "network.h"
- char FIELD[(WIDTH+1)*HEIGHT];
- volatile sig_atomic_t running;
- void int_handler(int s) {
- (void)s;
- running = false;
- }
- void put_char_net(int y, int x, char ch) {
- FIELD[y*(WIDTH+1)+x] = ch;
- }
- int main(int argc, char *argv[]) {
- (void) argc;
- (void) argv;
- int sock_listener;
- struct addrinfo hints, *result, *rp;
- int s;
- char hoststr[NI_MAXHOST], servstr[NI_MAXSERV];
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET6;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
- if ((s = getaddrinfo(NULL, PORT, &hints, &result)) != 0) {
- fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
- exit(EXIT_FAILURE);
- }
- for (rp = result; rp != NULL; rp = rp->ai_next) {
- if ((sock_listener = socket(rp->ai_family, rp->ai_socktype,
- rp->ai_protocol)) == -1) {
- perror("socket");
- continue;
- }
- int yes = 1;
- int no = 0;
- if (setsockopt(sock_listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
- perror("setsockopt(SO_REUSEADDR)");
- // ignore
- }
- if (setsockopt(sock_listener, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(int)) == -1) {
- perror("setsockopt(IPV6_V6ONLY)");
- // ignore
- }
- if (bind(sock_listener, rp->ai_addr, rp->ai_addrlen) == -1) {
- close(sock_listener);
- perror("bind");
- continue;
- }
- break;
- }
- if (rp == NULL) {
- exit(EXIT_FAILURE);
- }
- freeaddrinfo(result);
- if (listen(sock_listener, 10) == -1) {
- perror("listen");
- exit(EXIT_FAILURE);
- }
- puts("Listening for connections.");
- memset(FIELD, ' ', (WIDTH+1)*HEIGHT);
- for (int i = 0; i < HEIGHT; ++i) {
- FIELD[i*(WIDTH+1)+WIDTH] = '\0';
- }
- fd_set fds_master, fds_select;
- FD_ZERO(&fds_master);
- FD_ZERO(&fds_select);
- FD_SET(sock_listener, &fds_master);
- int maxfd = sock_listener;
- running = true;
- struct sigaction act;
- act.sa_handler = int_handler;
- sigaction(SIGINT, &act, NULL);
- if (sigaction(SIGINT, &act, NULL) == -1) {
- perror("sigaction");
- }
- while (running) {
- fds_select = fds_master;
- if (select(maxfd+1, &fds_select, NULL, NULL, NULL) == -1) {
- if (errno == EINTR) {
- continue;
- }
- perror("select");
- exit(EXIT_FAILURE);
- }
- for (int fd = 0; fd <= maxfd; fd++) {
- if (!FD_ISSET(fd, &fds_select))
- continue;
- if (fd == sock_listener) {
- // new client
- struct sockaddr_storage remoteaddr;
- socklen_t addrlen = sizeof remoteaddr;
- int newfd = accept(sock_listener, (struct sockaddr *)&remoteaddr, &addrlen);
- if (newfd == -1) {
- perror("accept");
- } else {
- FD_SET(newfd, &fds_master);
- if (newfd > maxfd) maxfd = newfd;
- if (getnameinfo((struct sockaddr *)&remoteaddr, addrlen, hoststr, sizeof(hoststr),
- servstr, sizeof(servstr), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
- printf("Accepted connection from %s:%s as fd %d.\n", hoststr, servstr, newfd);
- } else {
- printf("Accepted connection at fd %d.\n", newfd);
- }
- }
- } else {
- // existing client
- uint8_t buf[PKT_SIZE_MAX];
- size_t len = sizeof buf;
- int type;
- if ((type = recv_packet(fd, buf, &len)) <= 0) {
- if (type == 0) {
- printf("Connection closed by fd %d.\n", fd);
- } else {
- perror("recv_packet");
- }
- close(fd);
- FD_CLR(fd, &fds_master);
- } else {
- if (type == PKT_TYPE_HELLO) {
- struct packet_init_t pkt_init = {
- .size = htons(sizeof(struct packet_init_t)),
- .type = PKT_TYPE_INIT
- };
- memcpy(&pkt_init.data, FIELD, sizeof(pkt_init.data));
- printf("sending init\n");
- size_t pkt_len = sizeof(struct packet_init_t);
- if (send_packet(fd, (uint8_t*)&pkt_init, pkt_len) < pkt_len) {
- perror("send_packet");
- }
- } else if (type == PKT_TYPE_UPDATE) {
- struct packet_update_t *pkt = (struct packet_update_t *)buf;
- if (pkt->x >= WIDTH || pkt->y >= HEIGHT) {
- printf("recvd oob update from fd %d, ignoring.\n", fd);
- continue;
- }
- put_char_net(pkt->y, pkt->x, pkt->ch);
- for (int j = 0; j <= maxfd; j++) {
- if (j == sock_listener || j == fd) {
- continue;
- }
- if (FD_ISSET(j, &fds_master)) {
- if (send_packet(j, buf, len) < len) {
- perror("send_packet");
- }
- }
- }
- }
- }
- }
- }
- }
- puts("Shutting down");
- if (close(sock_listener) == -1) {
- perror("close");
- }
- FD_CLR(sock_listener, &fds_master);
- int scount = 0;
- for (int fd = 0; fd <= maxfd; fd++) {
- if (!FD_ISSET(fd, &fds_master))
- continue;
- scount++;
- if (shutdown(fd, SHUT_WR) == -1) {
- perror("shutdown");
- }
- }
- while(scount) {
- scount = 0;
- fds_select = fds_master;
- if (select(maxfd+1, &fds_select, NULL, NULL, NULL) == -1) {
- perror("select");
- exit(EXIT_FAILURE);
- }
- for (int fd = 0; fd <= maxfd; fd++) {
- if (!FD_ISSET(fd, &fds_select))
- continue;
- int s = recv_dump(fd);
- if (s <= 0) {
- if (s != 0) {
- perror("recv_dump");
- }
- close(fd);
- FD_CLR(fd, &fds_master);
- } else {
- scount++;
- }
- }
- }
- return EXIT_SUCCESS;
- }
|