mirror of https://github.com/xemu-project/xemu.git
qemu-sockets: add nonblocking connect for Unix sockets
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>
This commit is contained in:
parent
0c81470947
commit
1fc05adfa0
|
@ -2450,7 +2450,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
|
||||||
if (is_listen) {
|
if (is_listen) {
|
||||||
fd = unix_listen_opts(opts, NULL);
|
fd = unix_listen_opts(opts, NULL);
|
||||||
} else {
|
} else {
|
||||||
fd = unix_connect_opts(opts, NULL);
|
fd = unix_connect_opts(opts, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_listen) {
|
if (is_listen) {
|
||||||
|
|
|
@ -252,16 +252,19 @@ static void wait_for_connect(void *opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to connect to the next address on the list */
|
/* try to connect to the next address on the list */
|
||||||
while (s->current_addr->ai_next != NULL && s->fd < 0) {
|
if (s->current_addr) {
|
||||||
s->current_addr = s->current_addr->ai_next;
|
while (s->current_addr->ai_next != NULL && s->fd < 0) {
|
||||||
s->fd = inet_connect_addr(s->current_addr, &in_progress, s);
|
s->current_addr = s->current_addr->ai_next;
|
||||||
/* connect in progress */
|
s->fd = inet_connect_addr(s->current_addr, &in_progress, s);
|
||||||
if (in_progress) {
|
/* connect in progress */
|
||||||
return;
|
if (in_progress) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(s->addr_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
freeaddrinfo(s->addr_list);
|
|
||||||
if (s->callback) {
|
if (s->callback) {
|
||||||
s->callback(s->fd, s->opaque);
|
s->callback(s->fd, s->opaque);
|
||||||
}
|
}
|
||||||
|
@ -701,11 +704,13 @@ err:
|
||||||
return -1;
|
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;
|
struct sockaddr_un un;
|
||||||
const char *path = qemu_opt_get(opts, "path");
|
const char *path = qemu_opt_get(opts, "path");
|
||||||
int sock;
|
ConnectState *connect_state = NULL;
|
||||||
|
int sock, rc;
|
||||||
|
|
||||||
if (NULL == path) {
|
if (NULL == path) {
|
||||||
fprintf(stderr, "unix connect: no path specified\n");
|
fprintf(stderr, "unix connect: no path specified\n");
|
||||||
|
@ -717,16 +722,44 @@ int unix_connect_opts(QemuOpts *opts, Error **errp)
|
||||||
perror("socket(unix)");
|
perror("socket(unix)");
|
||||||
return -1;
|
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));
|
memset(&un, 0, sizeof(un));
|
||||||
un.sun_family = AF_UNIX;
|
un.sun_family = AF_UNIX;
|
||||||
snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
|
snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
|
||||||
if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
|
|
||||||
fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno));
|
/* connect to peer */
|
||||||
close(sock);
|
do {
|
||||||
return -1;
|
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);
|
||||||
|
sock = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(connect_state);
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,7 +772,8 @@ int unix_listen_opts(QemuOpts *opts, Error **errp)
|
||||||
return -1;
|
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");
|
fprintf(stderr, "unix sockets are not available on windows\n");
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
|
@ -784,7 +818,24 @@ int unix_connect(const char *path, Error **errp)
|
||||||
|
|
||||||
opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL);
|
opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL);
|
||||||
qemu_opt_set(opts, "path", path);
|
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);
|
qemu_opts_del(opts);
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,8 +58,12 @@ const char *inet_strfamily(int family);
|
||||||
|
|
||||||
int unix_listen_opts(QemuOpts *opts, Error **errp);
|
int unix_listen_opts(QemuOpts *opts, Error **errp);
|
||||||
int unix_listen(const char *path, char *ostr, int olen, 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_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. */
|
/* Old, ipv4 only bits. Don't use for new code. */
|
||||||
int parse_host_port(struct sockaddr_in *saddr, const char *str);
|
int parse_host_port(struct sockaddr_in *saddr, const char *str);
|
||||||
|
|
Loading…
Reference in New Issue