Skip to content

Commit

Permalink
qemu-sockets: add nonblocking connect for Unix sockets
Browse files Browse the repository at this point in the history
This patch mostly mimics what was done to TCP sockets, but simpler
because there is only one address to try.  It also includes a free EINTR
bug fix.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
bonzini committed Oct 23, 2012
1 parent 0c81470 commit 1fc05ad
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 15 deletions.
2 changes: 1 addition & 1 deletion qemu-char.c
Expand Up @@ -2450,7 +2450,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
if (is_listen) {
fd = unix_listen_opts(opts, NULL);
} else {
fd = unix_connect_opts(opts, NULL);
fd = unix_connect_opts(opts, NULL, NULL, NULL);
}
} else {
if (is_listen) {
Expand Down
77 changes: 64 additions & 13 deletions qemu-sockets.c
Expand Up @@ -252,16 +252,19 @@ static void wait_for_connect(void *opaque)
}

/* try to connect to the next address on the list */
while (s->current_addr->ai_next != NULL && s->fd < 0) {
s->current_addr = s->current_addr->ai_next;
s->fd = inet_connect_addr(s->current_addr, &in_progress, s);
/* connect in progress */
if (in_progress) {
return;
if (s->current_addr) {
while (s->current_addr->ai_next != NULL && s->fd < 0) {
s->current_addr = s->current_addr->ai_next;
s->fd = inet_connect_addr(s->current_addr, &in_progress, s);
/* connect in progress */
if (in_progress) {
return;
}
}

freeaddrinfo(s->addr_list);
}

freeaddrinfo(s->addr_list);
if (s->callback) {
s->callback(s->fd, s->opaque);
}
Expand Down Expand Up @@ -701,11 +704,13 @@ int unix_listen_opts(QemuOpts *opts, Error **errp)
return -1;
}

int unix_connect_opts(QemuOpts *opts, Error **errp)
int unix_connect_opts(QemuOpts *opts, Error **errp,
NonBlockingConnectHandler *callback, void *opaque)
{
struct sockaddr_un un;
const char *path = qemu_opt_get(opts, "path");
int sock;
ConnectState *connect_state = NULL;
int sock, rc;

if (NULL == path) {
fprintf(stderr, "unix connect: no path specified\n");
Expand All @@ -717,16 +722,44 @@ int unix_connect_opts(QemuOpts *opts, Error **errp)
perror("socket(unix)");
return -1;
}
if (callback != NULL) {
connect_state = g_malloc0(sizeof(*connect_state));
connect_state->callback = callback;
connect_state->opaque = opaque;
socket_set_nonblock(sock);
}

memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {

/* connect to peer */
do {
rc = 0;
if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) {
rc = -socket_error();
}
} while (rc == -EINTR);

if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) {
connect_state->fd = sock;
qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect,
connect_state);
return sock;
} else if (rc >= 0) {
/* non blocking socket immediate success, call callback */
if (callback != NULL) {
callback(sock, opaque);
}
}

if (rc < 0) {
fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno));
close(sock);
return -1;
sock = -1;
}

g_free(connect_state);
return sock;
}

Expand All @@ -739,7 +772,8 @@ int unix_listen_opts(QemuOpts *opts, Error **errp)
return -1;
}

int unix_connect_opts(QemuOpts *opts, Error **errp)
int unix_connect_opts(QemuOpts *opts, Error **errp,
NonBlockingConnectHandler *callback, void *opaque)
{
fprintf(stderr, "unix sockets are not available on windows\n");
errno = ENOTSUP;
Expand Down Expand Up @@ -784,7 +818,24 @@ int unix_connect(const char *path, Error **errp)

opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL);
qemu_opt_set(opts, "path", path);
sock = unix_connect_opts(opts, errp);
sock = unix_connect_opts(opts, errp, NULL, NULL);
qemu_opts_del(opts);
return sock;
}


int unix_nonblocking_connect(const char *path,
NonBlockingConnectHandler *callback,
void *opaque, Error **errp)
{
QemuOpts *opts;
int sock = -1;

g_assert(callback != NULL);

opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL);
qemu_opt_set(opts, "path", path);
sock = unix_connect_opts(opts, errp, callback, opaque);
qemu_opts_del(opts);
return sock;
}
Expand Down
6 changes: 5 additions & 1 deletion qemu_socket.h
Expand Up @@ -58,8 +58,12 @@ const char *inet_strfamily(int family);

int unix_listen_opts(QemuOpts *opts, Error **errp);
int unix_listen(const char *path, char *ostr, int olen, Error **errp);
int unix_connect_opts(QemuOpts *opts, Error **errp);
int unix_connect_opts(QemuOpts *opts, Error **errp,
NonBlockingConnectHandler *callback, void *opaque);
int unix_connect(const char *path, Error **errp);
int unix_nonblocking_connect(const char *str,
NonBlockingConnectHandler *callback,
void *opaque, Error **errp);

/* Old, ipv4 only bits. Don't use for new code. */
int parse_host_port(struct sockaddr_in *saddr, const char *str);
Expand Down

0 comments on commit 1fc05ad

Please sign in to comment.