|
|
@@ -31,6 +31,7 @@ |
|
|
|
#endif |
|
|
|
#include <sys/types.h> |
|
|
|
#include <sys/socket.h> |
|
|
|
#include <netdb.h> |
|
|
|
#include <fcntl.h> |
|
|
|
#include <signal.h> |
|
|
|
#include <errno.h> |
|
|
@@ -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 |
|
|
|
RETSIGTYPE (*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,40 +162,39 @@ 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) |
|
|
|
{ |
|
|
|
perror("socket"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
if(setsockopt(server->sockfd, SOL_SOCKET, |
|
|
|
SO_REUSEADDR, &yes, sizeof(int)) == -1) |
|
|
|
{ |
|
|
|
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(bind(server->sockfd, (struct sockaddr *)&server->my_addr, |
|
|
|
sizeof(struct sockaddr)) == -1) |
|
|
|
{ |
|
|
|
perror("bind"); |
|
|
|
return -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("getaddrinfo"); |
|
|
|
|
|
|
|
for (res = ai; res && server->sock_count < MAXSOCKS; res = res->ai_next) { |
|
|
|
if ((fd = socket(res->ai_addr->sa_family, SOCK_STREAM, 0)) == -1) |
|
|
|
perror("socket"); |
|
|
|
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) |
|
|
|
perror("setsockopt: SO_REUSEADDR"); |
|
|
|
if (res->ai_addr->sa_family == AF_INET6) |
|
|
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) == -1) |
|
|
|
perror("setsockopt: IPV6_V6ONLY"); |
|
|
|
if (bind(fd, res->ai_addr, res->ai_addrlen) == -1) |
|
|
|
perror("bind"); |
|
|
|
flags = fcntl(fd, F_GETFL, 0); |
|
|
|
fcntl(fd, F_SETFL, flags | O_NONBLOCK); |
|
|
|
if(listen(fd, BACKLOG) == -1) |
|
|
|
perror("listen"); |
|
|
|
|
|
|
|
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) |
|
|
|
{ |
|
|
|
perror("listen"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
server->canvas = caca_create_canvas(0, 0); |
|
|
|
server->buffer = NULL; |
|
|
@@ -202,7 +211,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 +298,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 +313,30 @@ restart: |
|
|
|
* XXX: The following functions are local |
|
|
|
*/ |
|
|
|
|
|
|
|
static void manage_connections(struct server *server) |
|
|
|
void print_ip(struct sockaddr *ai) |
|
|
|
{ |
|
|
|
char buffer[INET6_ADDRSTRLEN]; |
|
|
|
int err = getnameinfo(ai, (ai->sa_family==AF_INET)?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6), 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); |
|
|
|