|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v2 qemu-traditional] qemu: Fix race condition when opening ports
On Mon, 2013-12-09 at 13:27 +0000, Andrew Cooper wrote:
> Two Qemus can race to bind the same VNC port. It is valid for multiple
> bind()s on the same socket to succeed, but only the first listen() will
> succeed.
>
> In the case that two Qemus are starting at the same time, and both trying to
> grab the next free VNC port, the second one will fail with an EADDRINUSE, and
> bail with a fatal error which renders the domain functionally useless.
>
> In the case that listen() fails with EADDRINUSE, rebind the socket again and
> try for the next port.
Does this do the right thing if vncunused=0? In that case the user has
given a specific port which we want to bind to, so going to the next
port is not desired.
> Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
> CC: Ian Campbell <Ian.Campbell@xxxxxxxxxx>
> CC: Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx>
> CC: Stefano Stabellini <stefano.stabellini@xxxxxxxxxx>
> Release-acked-by: George Dunlap <george.dunlap@xxxxxxxxxxxxx>
>
> ---
>
> Changes in v2:
> * Fix commit message.
>
> This fix has been in XenServer for two and a half years
> ---
> qemu-sockets.c | 23 ++++++++++++++++-------
> 1 file changed, 16 insertions(+), 7 deletions(-)
>
> diff --git a/qemu-sockets.c b/qemu-sockets.c
> index 9b9fa77..e54f6ad 100644
> --- a/qemu-sockets.c
> +++ b/qemu-sockets.c
> @@ -163,6 +163,7 @@ int inet_listen(const char *str, char *ostr, int olen,
>
> /* create socket + bind */
> for (e = res; e != NULL; e = e->ai_next) {
> + rebind:
> getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
> uaddr,INET6_ADDRSTRLEN,uport,32,
> NI_NUMERICHOST | NI_NUMERICSERV);
> @@ -186,7 +187,20 @@ int inet_listen(const char *str, char *ostr, int olen,
> if (sockets_debug)
> fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
> inet_strfamily(e->ai_family), uaddr,
> inet_getport(e));
> - goto listen;
> + if (listen(slisten,1) == 0) {
> + goto listened;
> + } else {
> + int err = errno;
> +
> + perror("listen");
> + closesocket(slisten);
> +
> + if (err == EADDRINUSE)
> + goto rebind;
Does this code actually try for the next port? The try_next check is
after the goto here (you can see it in the context below). Won't it just
try to rebind the same port again and again?
> + freeaddrinfo(res);
> + return -1;
> + }
> +
> }
> try_next = to && (inet_getport(e) <= to + port_offset);
> if (!try_next || sockets_debug)
> @@ -205,12 +219,7 @@ int inet_listen(const char *str, char *ostr, int olen,
> freeaddrinfo(res);
> return -1;
>
> -listen:
> - if (listen(slisten,1) != 0) {
> - perror("listen");
> - closesocket(slisten);
> - return -1;
> - }
> +listened:
> if (ostr) {
> if (e->ai_family == PF_INET6) {
> snprintf(ostr, olen, "[%s]:%d%s", uaddr,
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |