diff --git a/src/cacaserver.c b/src/cacaserver.c index d875c05..f66ee3a 100644 --- a/src/cacaserver.c +++ b/src/cacaserver.c @@ -31,6 +31,7 @@ #endif #include #include +#include #include #include #include @@ -94,13 +95,19 @@ struct client int start, stop; }; +#define MAXSOCKS 16 + +struct sock { + int sockfd; + struct sockaddr_in my_addr; +}; + struct server { unsigned int width, height; unsigned int port; - int sockfd; - struct sockaddr_in my_addr; - socklen_t sin_size; + int sock_count; + struct sock socks[MAXSOCKS]; /* Input buffer */ uint8_t *input; @@ -118,14 +125,17 @@ struct server void (*sigpipe_handler)(int); }; -static void manage_connections(struct server *server); +void print_ip(struct sockaddr *ai); +static void manage_connections(struct server *server, int sockfd); static int send_data(struct server *server, struct client *c); ssize_t nonblock_write(int fd, void *buf, size_t len); int main(void) { - int i, yes = 1, flags; + int i, yes = 1, flags, fd, error; struct server *server; + struct addrinfo ai_hints, *ai, *res; + char port_str[6]; char *tmp; #if USE_WINSOCK @@ -152,38 +162,61 @@ int main(void) tmp[2] = (uint8_t) (server->height & 0xff00) >> 8; tmp[3] = (uint8_t) server->height & 0xff; - if((server->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) + memset(&ai_hints, 0, sizeof(ai_hints)); + ai_hints.ai_family = AF_UNSPEC; + ai_hints.ai_socktype = SOCK_STREAM; + ai_hints.ai_flags = AI_PASSIVE; + memset(port_str, 0, sizeof(port_str)); + snprintf(port_str, 6, "%d", server->port); + error = getaddrinfo(NULL, port_str, &ai_hints, &ai); + if (error) { - perror("socket"); - return -1; + perror("getaddrinfo"); + return -1; } - if(setsockopt(server->sockfd, SOL_SOCKET, - SO_REUSEADDR, &yes, sizeof(int)) == -1) + for (res = ai; res && server->sock_count < MAXSOCKS; res = res->ai_next) { - perror("setsockopt SO_REUSEADDR"); - return -1; - } - - server->my_addr.sin_family = AF_INET; - server-> my_addr.sin_port = htons(server->port); - server->my_addr.sin_addr.s_addr = INADDR_ANY; - memset(&(server->my_addr.sin_zero), '\0', 8); + if ((fd = socket(res->ai_addr->sa_family, SOCK_STREAM, 0)) == -1) + { + perror("socket"); + continue; + } + if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) + { + perror("setsockopt: SO_REUSEADDR"); + continue; + } + if (res->ai_addr->sa_family == AF_INET6) + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) == -1) + { + perror("setsockopt: IPV6_V6ONLY"); + continue; + } + if (bind(fd, res->ai_addr, res->ai_addrlen) == -1) + { + perror("bind"); + continue; + } + flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if(listen(fd, BACKLOG) == -1) + { + perror("listen"); + continue; + } - if(bind(server->sockfd, (struct sockaddr *)&server->my_addr, - sizeof(struct sockaddr)) == -1) - { - perror("bind"); - return -1; + server->socks[server->sock_count].sockfd = fd; + server->sock_count++; + fprintf(stderr, "listening on "); + print_ip(res->ai_addr); + fprintf(stderr, "\n"); } + freeaddrinfo(ai); - /* Non blocking socket */ - flags = fcntl(server->sockfd, F_GETFL, 0); - fcntl(server->sockfd, F_SETFL, flags | O_NONBLOCK); - - if(listen(server->sockfd, BACKLOG) == -1) + if (server->sock_count == 0) { - perror("listen"); + fprintf(stderr, "Not listening\n"); return -1; } @@ -202,7 +235,8 @@ int main(void) restart: /* Manage new connections as this function will be called sometimes * more often than display */ - manage_connections(server); + for (i = 0; i < server->sock_count; i++) + manage_connections(server, server->socks[i].sockfd); /* Read data from stdin */ if(server->read < 12) @@ -288,6 +322,9 @@ restart: /* Restore SIGPIPE handler */ signal(SIGPIPE, server->sigpipe_handler); + for (i = 0; i < server->sock_count; i++) + close(server->socks[i].sockfd); + free(server); #if USE_WINSOCK @@ -300,18 +337,36 @@ restart: * XXX: The following functions are local */ -static void manage_connections(struct server *server) +void print_ip(struct sockaddr *ai) +{ + char buffer[INET6_ADDRSTRLEN]; + socklen_t len = sizeof(struct sockaddr_in6); + + if (ai->sa_family == AF_INET) + len = sizeof(struct sockaddr_in); + + int err = getnameinfo(ai, len, buffer, sizeof(buffer), NULL, 0, + NI_NUMERICHOST); + if (err != 0) { + fprintf(stderr, "n/a"); + } + fprintf(stderr, "%s",buffer); +} + + +static void manage_connections(struct server *server, int sockfd) { int fd, flags; - struct sockaddr_in remote_addr; - socklen_t len = sizeof(struct sockaddr_in); + struct sockaddr_in6 remote_addr; + socklen_t len = sizeof(struct sockaddr_in6); - fd = accept(server->sockfd, (struct sockaddr *)&remote_addr, &len); + fd = accept(sockfd, (struct sockaddr*)&remote_addr, &len); if(fd == -1) return; - fprintf(stderr, "[%i] connected from %s\n", - fd, inet_ntoa(remote_addr.sin_addr)); + fprintf(stderr, "[%i] connected from ", fd); + print_ip((struct sockaddr*)&remote_addr); + fprintf(stderr, "\n"); /* Non blocking socket */ flags = fcntl(fd, F_SETFL, 0);