Refactor inet_connect_opts function
refactor address resolution code to fix nonblocking connect remove getnameinfo call Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Amos Kong <akong@redhat.com> Signed-off-by: Orit Wasserman <owasserm@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
		
							parent
							
								
									8bdd3d499f
								
							
						
					
					
						commit
						05bc1d8a4b
					
				
							
								
								
									
										148
									
								
								qemu-sockets.c
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								qemu-sockets.c
									
									
									
									
									
								
							@ -209,96 +209,118 @@ listen:
 | 
			
		||||
    return slisten;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    struct addrinfo ai,*res,*e;
 | 
			
		||||
    const char *addr;
 | 
			
		||||
    const char *port;
 | 
			
		||||
    char uaddr[INET6_ADDRSTRLEN+1];
 | 
			
		||||
    char uport[33];
 | 
			
		||||
    int sock,rc;
 | 
			
		||||
    bool block;
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define QEMU_SOCKET_RC_INPROGRESS(rc) \
 | 
			
		||||
    ((rc) == -EINPROGRESS || (rc) == -EWOULDBLOCK || (rc) == -WSAEALREADY)
 | 
			
		||||
#else
 | 
			
		||||
#define QEMU_SOCKET_RC_INPROGRESS(rc) \
 | 
			
		||||
    ((rc) == -EINPROGRESS)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    memset(&ai,0, sizeof(ai));
 | 
			
		||||
    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
 | 
			
		||||
    ai.ai_family = PF_UNSPEC;
 | 
			
		||||
    ai.ai_socktype = SOCK_STREAM;
 | 
			
		||||
static int inet_connect_addr(struct addrinfo *addr, bool block,
 | 
			
		||||
                             bool *in_progress)
 | 
			
		||||
{
 | 
			
		||||
    int sock, rc;
 | 
			
		||||
 | 
			
		||||
    if (in_progress) {
 | 
			
		||||
        *in_progress = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addr = qemu_opt_get(opts, "host");
 | 
			
		||||
    port = qemu_opt_get(opts, "port");
 | 
			
		||||
    block = qemu_opt_get_bool(opts, "block", 0);
 | 
			
		||||
    if (addr == NULL || port == NULL) {
 | 
			
		||||
        fprintf(stderr, "inet_connect: host and/or port not specified\n");
 | 
			
		||||
        error_set(errp, QERR_SOCKET_CREATE_FAILED);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (qemu_opt_get_bool(opts, "ipv4", 0))
 | 
			
		||||
        ai.ai_family = PF_INET;
 | 
			
		||||
    if (qemu_opt_get_bool(opts, "ipv6", 0))
 | 
			
		||||
        ai.ai_family = PF_INET6;
 | 
			
		||||
 | 
			
		||||
    /* lookup */
 | 
			
		||||
    if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
 | 
			
		||||
        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
 | 
			
		||||
                gai_strerror(rc));
 | 
			
		||||
        error_set(errp, QERR_SOCKET_CREATE_FAILED);
 | 
			
		||||
	return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (e = res; e != NULL; e = e->ai_next) {
 | 
			
		||||
        if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
 | 
			
		||||
                            uaddr,INET6_ADDRSTRLEN,uport,32,
 | 
			
		||||
                            NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
 | 
			
		||||
            fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
 | 
			
		||||
    sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
 | 
			
		||||
    if (sock < 0) {
 | 
			
		||||
            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
 | 
			
		||||
            inet_strfamily(e->ai_family), strerror(errno));
 | 
			
		||||
            continue;
 | 
			
		||||
        fprintf(stderr, "%s: socket(%s): %s\n", __func__,
 | 
			
		||||
                inet_strfamily(addr->ai_family), strerror(errno));
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
        setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
 | 
			
		||||
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
 | 
			
		||||
    if (!block) {
 | 
			
		||||
        socket_set_nonblock(sock);
 | 
			
		||||
    }
 | 
			
		||||
    /* connect to peer */
 | 
			
		||||
    do {
 | 
			
		||||
        rc = 0;
 | 
			
		||||
            if (connect(sock, e->ai_addr, e->ai_addrlen) < 0) {
 | 
			
		||||
        if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) {
 | 
			
		||||
            rc = -socket_error();
 | 
			
		||||
        }
 | 
			
		||||
    } while (rc == -EINTR);
 | 
			
		||||
 | 
			
		||||
  #ifdef _WIN32
 | 
			
		||||
        if (!block && (rc == -EINPROGRESS || rc == -EWOULDBLOCK
 | 
			
		||||
                       || rc == -WSAEALREADY)) {
 | 
			
		||||
  #else
 | 
			
		||||
        if (!block && (rc == -EINPROGRESS)) {
 | 
			
		||||
  #endif
 | 
			
		||||
    if (!block && QEMU_SOCKET_RC_INPROGRESS(rc)) {
 | 
			
		||||
        if (in_progress) {
 | 
			
		||||
            *in_progress = true;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (rc < 0) {
 | 
			
		||||
            if (NULL == e->ai_next)
 | 
			
		||||
                fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
 | 
			
		||||
                        inet_strfamily(e->ai_family),
 | 
			
		||||
                        e->ai_canonname, uaddr, uport, strerror(errno));
 | 
			
		||||
        closesocket(sock);
 | 
			
		||||
            continue;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    return sock;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    struct addrinfo ai, *res;
 | 
			
		||||
    int rc;
 | 
			
		||||
    const char *addr;
 | 
			
		||||
    const char *port;
 | 
			
		||||
 | 
			
		||||
    memset(&ai, 0, sizeof(ai));
 | 
			
		||||
    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
 | 
			
		||||
    ai.ai_family = PF_UNSPEC;
 | 
			
		||||
    ai.ai_socktype = SOCK_STREAM;
 | 
			
		||||
 | 
			
		||||
    addr = qemu_opt_get(opts, "host");
 | 
			
		||||
    port = qemu_opt_get(opts, "port");
 | 
			
		||||
    if (addr == NULL || port == NULL) {
 | 
			
		||||
        fprintf(stderr,
 | 
			
		||||
                "inet_parse_connect_opts: host and/or port not specified\n");
 | 
			
		||||
        error_set(errp, QERR_SOCKET_CREATE_FAILED);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (qemu_opt_get_bool(opts, "ipv4", 0)) {
 | 
			
		||||
        ai.ai_family = PF_INET;
 | 
			
		||||
    }
 | 
			
		||||
    if (qemu_opt_get_bool(opts, "ipv6", 0)) {
 | 
			
		||||
        ai.ai_family = PF_INET6;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* lookup */
 | 
			
		||||
    rc = getaddrinfo(addr, port, &ai, &res);
 | 
			
		||||
    if (rc != 0) {
 | 
			
		||||
        fprintf(stderr, "getaddrinfo(%s,%s): %s\n", addr, port,
 | 
			
		||||
                gai_strerror(rc));
 | 
			
		||||
        error_set(errp, QERR_SOCKET_CREATE_FAILED);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    struct addrinfo *res, *e;
 | 
			
		||||
    int sock = -1;
 | 
			
		||||
    bool block = qemu_opt_get_bool(opts, "block", 0);
 | 
			
		||||
 | 
			
		||||
    res = inet_parse_connect_opts(opts, errp);
 | 
			
		||||
    if (!res) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (in_progress) {
 | 
			
		||||
        *in_progress = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (e = res; e != NULL; e = e->ai_next) {
 | 
			
		||||
        sock = inet_connect_addr(e, block, in_progress);
 | 
			
		||||
        if (sock >= 0) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (sock < 0) {
 | 
			
		||||
        error_set(errp, QERR_SOCKET_CONNECT_FAILED);
 | 
			
		||||
    }
 | 
			
		||||
    freeaddrinfo(res);
 | 
			
		||||
    return sock;
 | 
			
		||||
}
 | 
			
		||||
    error_set(errp, QERR_SOCKET_CONNECT_FAILED);
 | 
			
		||||
    freeaddrinfo(res);
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int inet_dgram_opts(QemuOpts *opts)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user