From 3a9ef3f6cff9048124535a398c5d5b17de5d8614 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 4 Mar 2010 10:57:04 +0100 Subject: new libspice api: configure listen addr, add ipv6 support Signed-off-by: Gerd Hoffmann --- server/reds.c | 109 ++++++++++++++++++++++++++++++++++++--------------------- server/spice.h | 4 +++ 2 files changed, 74 insertions(+), 39 deletions(-) diff --git a/server/reds.c b/server/reds.c index 30dc7c0a..cbea17c5 100644 --- a/server/reds.c +++ b/server/reds.c @@ -76,8 +76,9 @@ static VDIPortInterface *vdagent = NULL; static int spice_port = -1; static int spice_secure_port = -1; +static char spice_addr[256]; +static int spice_family = PF_UNSPEC; -static struct in_addr spice_addr = {INADDR_ANY}; static int ticketing_enabled = 1; //Ticketing is enabled by default static pthread_mutex_t *lock_cs; static long *lock_count; @@ -3103,54 +3104,76 @@ static void reds_accept(void *data) reds_handle_new_link(link); } -static int reds_init_socket(uint16_t port) +static int reds_init_socket(const char *addr, int portnr, int family) { - struct sockaddr_in addr; - int sock; - int flags; - - if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - red_error("socket failed, %s", strerror(errno)); - } + static const int on=1, off=0; + struct addrinfo ai,*res,*e; + char port[33]; + char uaddr[INET6_ADDRSTRLEN+1]; + char uport[33]; + int slisten,rc; - flags = 1; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)) < 0) { - red_error("socket set sockopt failed, %s", strerror(errno)); - } + memset(&ai,0, sizeof(ai)); + ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + ai.ai_socktype = SOCK_STREAM; + ai.ai_family = family; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = spice_addr.s_addr; - if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { - red_error("bind failed, %s", strerror(errno)); + snprintf(port, sizeof(port), "%d", portnr); + rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); + if (rc != 0) { + red_error("getaddrinfo(%s,%s): %s\n", addr, port, + gai_strerror(rc)); } - if ((flags = fcntl(sock, F_GETFL)) == -1) { - red_error("fcntl get failed, %s", strerror(errno)); - } - - if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) { - red_error("fcntl set failed, %s", strerror(errno)); - } + for (e = res; e != NULL; e = e->ai_next) { + getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, + uaddr,INET6_ADDRSTRLEN, uport,32, + NI_NUMERICHOST | NI_NUMERICSERV); + slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol); + if (slisten < 0) { + continue; + } - if (listen(sock, 2) == -1) { - red_error("listen failed, %s", strerror(errno)); + setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); +#ifdef IPV6_V6ONLY + if (e->ai_family == PF_INET6) { + /* listen on both ipv4 and ipv6 */ + setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off, + sizeof(off)); + } +#endif + if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { + goto listen; + } + close(slisten); + } + red_error("%s: binding socket to %s:%d failed\n", __FUNCTION__, + addr, portnr); + freeaddrinfo(res); + return -1; + +listen: + freeaddrinfo(res); + if (listen(slisten,1) != 0) { + red_error("%s: listen: %s", __FUNCTION__, strerror(errno)); + close(slisten); + return -1; } - - return sock; + return slisten; } static void reds_init_net() { if (spice_port != -1) { - reds->listen_socket = reds_init_socket(spice_port); + reds->listen_socket = reds_init_socket(spice_addr, spice_port, spice_family); if (core->set_file_handlers(core, reds->listen_socket, reds_accept, NULL, NULL)) { red_error("set fd handle failed"); } } if (spice_secure_port != -1) { - reds->secure_listen_socket = reds_init_socket(spice_secure_port); + reds->secure_listen_socket = reds_init_socket(spice_addr, spice_secure_port, + spice_family); if (core->set_file_handlers(core, reds->secure_listen_socket, reds_accept_ssl_connection, NULL, NULL)) { red_error("set fd handle failed"); @@ -3953,15 +3976,11 @@ int __attribute__ ((visibility ("default"))) spice_parse_args(const char *in_arg break; } case SPICE_OPTION_HOST: { - struct hostent* host_addr; - if (!val) { - goto error; - } - if ((host_addr = gethostbyname(val)) == NULL || host_addr->h_addrtype != AF_INET) { - goto error; + if (val) { + strncpy(spice_addr, val, sizeof(spice_addr)); + /* force ipv4 here for backward compatibility */ + spice_family = PF_INET; } - ASSERT(host_addr->h_length == sizeof(spice_addr)); - memcpy(&spice_addr, host_addr->h_addr, sizeof(spice_addr)); break; } case SPICE_OPTION_IMAGE_COMPRESSION: @@ -5513,6 +5532,18 @@ int spice_server_set_port(SpiceServer *s, int port) return 0; } +void spice_server_set_addr(SpiceServer *s, const char *addr, int flags) +{ + ASSERT(reds == s); + strncpy(spice_addr, addr, sizeof(spice_addr)); + if (flags & SPICE_ADDR_FLAG_IPV4_ONLY) { + spice_family = PF_INET; + } + if (flags & SPICE_ADDR_FLAG_IPV6_ONLY) { + spice_family = PF_INET6; + } +} + int spice_server_set_noauth(SpiceServer *s) { ASSERT(reds == s); diff --git a/server/spice.h b/server/spice.h index 015ed895..be0df427 100644 --- a/server/spice.h +++ b/server/spice.h @@ -32,7 +32,11 @@ SpiceServer *spice_server_new(void); int spice_server_init(SpiceServer *s, CoreInterface *core); void spice_server_destroy(SpiceServer *s); +#define SPICE_ADDR_FLAG_IPV4_ONLY (1 << 0) +#define SPICE_ADDR_FLAG_IPV6_ONLY (1 << 1) + int spice_server_set_port(SpiceServer *s, int port); +void spice_server_set_addr(SpiceServer *s, const char *addr, int flags); int spice_server_set_noauth(SpiceServer *s); int spice_server_set_ticket(SpiceServer *s, const char *passwd, int lifetime, int fail_if_connected, int disconnect_if_connected); -- cgit