#include "monitor/monitor.h"
#include "qemu/sockets.h"
-#include "qemu-common.h" /* for qemu_isdigit */
#include "qemu/main-loop.h"
#ifndef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0
#endif
-static const int on=1, off=0;
-
/* used temporarily until all users are converted to QemuOpts */
QemuOptsList socket_optslist = {
.name = "socket",
}
}
-const char *inet_strfamily(int family)
+NetworkAddressFamily inet_netfamily(int family)
{
switch (family) {
- case PF_INET6: return "ipv6";
- case PF_INET: return "ipv4";
- case PF_UNIX: return "unix";
+ case PF_INET6: return NETWORK_ADDRESS_FAMILY_IPV6;
+ case PF_INET: return NETWORK_ADDRESS_FAMILY_IPV4;
+ case PF_UNIX: return NETWORK_ADDRESS_FAMILY_UNIX;
}
- return "unknown";
+ return NETWORK_ADDRESS_FAMILY_UNKNOWN;
}
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
ai.ai_family = PF_INET6;
/* lookup */
- if (port_offset)
- snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
+ if (port_offset) {
+ unsigned long long baseport;
+ if (parse_uint_full(port, &baseport, 10) < 0) {
+ error_setg(errp, "can't convert to a number: %s", port);
+ return -1;
+ }
+ if (baseport > 65535 ||
+ baseport + port_offset > 65535) {
+ error_setg(errp, "port %s out of range", port);
+ return -1;
+ }
+ snprintf(port, sizeof(port), "%d", (int)baseport + port_offset);
+ }
rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
if (rc != 0) {
error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
continue;
}
- qemu_setsockopt(slisten, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ socket_set_fast_reuse(slisten);
#ifdef IPV6_V6ONLY
if (e->ai_family == PF_INET6) {
/* listen on both ipv4 and ipv6 */
+ const int off = 0;
qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &off,
sizeof(off));
}
error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
return -1;
}
- qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ socket_set_fast_reuse(sock);
if (connect_state != NULL) {
- socket_set_nonblock(sock);
+ qemu_set_nonblock(sock);
}
/* connect to peer */
do {
int inet_connect_opts(QemuOpts *opts, Error **errp,
NonBlockingConnectHandler *callback, void *opaque)
{
+ Error *local_err = NULL;
struct addrinfo *res, *e;
int sock = -1;
bool in_progress;
}
for (e = res; e != NULL; e = e->ai_next) {
- if (error_is_set(errp)) {
- error_free(*errp);
- *errp = NULL;
- }
+ error_free(local_err);
+ local_err = NULL;
if (connect_state != NULL) {
connect_state->current_addr = e;
}
- sock = inet_connect_addr(e, &in_progress, connect_state, errp);
- if (in_progress) {
- return sock;
- } else if (sock >= 0) {
- /* non blocking socket immediate success, call callback */
- if (callback != NULL) {
- callback(sock, opaque);
- }
+ sock = inet_connect_addr(e, &in_progress, connect_state, &local_err);
+ if (sock >= 0) {
break;
}
}
+
+ if (sock < 0) {
+ error_propagate(errp, local_err);
+ } else if (in_progress) {
+ /* wait_for_connect() will do the rest */
+ return sock;
+ } else {
+ if (callback) {
+ callback(sock, opaque);
+ }
+ }
g_free(connect_state);
freeaddrinfo(res);
return sock;
error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
goto err;
}
- qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ socket_set_fast_reuse(sock);
/* bind socket */
if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
goto fail;
}
addr->ipv6 = addr->has_ipv6 = true;
- } else if (qemu_isdigit(str[0])) {
- /* IPv4 addr */
- if (2 != sscanf(str, "%64[0-9.]:%32[^,]%n", host, port, &pos)) {
- error_setg(errp, "error parsing IPv4 address '%s'", str);
- goto fail;
- }
- addr->ipv4 = addr->has_ipv4 = true;
} else {
- /* hostname */
+ /* hostname or IPv4 addr */
if (2 != sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos)) {
error_setg(errp, "error parsing address '%s'", str);
goto fail;
}
+ if (host[strspn(host, "0123456789.")] == '\0') {
+ addr->ipv4 = addr->has_ipv4 = true;
+ }
}
addr->host = g_strdup(host);
addr = inet_parse(str, errp);
if (addr != NULL) {
- opts = qemu_opts_create_nofail(&socket_optslist);
+ opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
inet_addr_to_opts(opts, addr);
qapi_free_InetSocketAddress(addr);
sock = inet_listen_opts(opts, port_offset, errp);
addr = inet_parse(str, errp);
if (addr != NULL) {
- opts = qemu_opts_create_nofail(&socket_optslist);
+ opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
inet_addr_to_opts(opts, addr);
qapi_free_InetSocketAddress(addr);
sock = inet_connect_opts(opts, errp, NULL, NULL);
addr = inet_parse(str, errp);
if (addr != NULL) {
- opts = qemu_opts_create_nofail(&socket_optslist);
+ opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
inet_addr_to_opts(opts, addr);
qapi_free_InetSocketAddress(addr);
sock = inet_connect_opts(opts, errp, callback, opaque);
ConnectState *connect_state = NULL;
int sock, rc;
- if (NULL == path) {
+ if (path == NULL) {
error_setg(errp, "unix connect: no path specified");
return -1;
}
connect_state = g_malloc0(sizeof(*connect_state));
connect_state->callback = callback;
connect_state->opaque = opaque;
- socket_set_nonblock(sock);
+ qemu_set_nonblock(sock);
}
memset(&un, 0, sizeof(un));
char *path, *optstr;
int sock, len;
- opts = qemu_opts_create_nofail(&socket_optslist);
+ opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
optstr = strchr(str, ',');
if (optstr) {
QemuOpts *opts;
int sock;
- opts = qemu_opts_create_nofail(&socket_optslist);
+ opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
qemu_opt_set(opts, "path", path);
sock = unix_connect_opts(opts, errp, NULL, NULL);
qemu_opts_del(opts);
g_assert(callback != NULL);
- opts = qemu_opts_create_nofail(&socket_optslist);
+ opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
qemu_opt_set(opts, "path", path);
sock = unix_connect_opts(opts, errp, callback, opaque);
qemu_opts_del(opts);
SocketAddress *socket_parse(const char *str, Error **errp)
{
- SocketAddress *addr = NULL;
+ SocketAddress *addr;
- addr = g_new(SocketAddress, 1);
+ addr = g_new0(SocketAddress, 1);
if (strstart(str, "unix:", NULL)) {
if (str[5] == '\0') {
error_setg(errp, "invalid Unix socket address");
}
} else {
addr->kind = SOCKET_ADDRESS_KIND_INET;
- addr->inet = g_new(InetSocketAddress, 1);
addr->inet = inet_parse(str, errp);
if (addr->inet == NULL) {
goto fail;
QemuOpts *opts;
int fd;
- opts = qemu_opts_create_nofail(&socket_optslist);
+ opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
switch (addr->kind) {
case SOCKET_ADDRESS_KIND_INET:
inet_addr_to_opts(opts, addr->inet);
case SOCKET_ADDRESS_KIND_FD:
fd = monitor_get_fd(cur_mon, addr->fd->str, errp);
- if (callback) {
+ if (fd >= 0 && callback) {
+ qemu_set_nonblock(fd);
callback(fd, opaque);
}
break;
QemuOpts *opts;
int fd;
- opts = qemu_opts_create_nofail(&socket_optslist);
+ opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
switch (addr->kind) {
case SOCKET_ADDRESS_KIND_INET:
inet_addr_to_opts(opts, addr->inet);
QemuOpts *opts;
int fd;
- opts = qemu_opts_create_nofail(&socket_optslist);
+ opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
switch (remote->kind) {
case SOCKET_ADDRESS_KIND_INET:
- qemu_opt_set(opts, "host", remote->inet->host);
- qemu_opt_set(opts, "port", remote->inet->port);
+ inet_addr_to_opts(opts, remote->inet);
if (local) {
qemu_opt_set(opts, "localaddr", local->inet->host);
qemu_opt_set(opts, "localport", local->inet->port);
default:
error_setg(errp, "socket type unsupported for datagram");
- return -1;
+ fd = -1;
}
qemu_opts_del(opts);
return fd;
}
-
-#ifdef _WIN32
-static void socket_cleanup(void)
-{
- WSACleanup();
-}
-#endif
-
-int socket_init(void)
-{
-#ifdef _WIN32
- WSADATA Data;
- int ret, err;
-
- ret = WSAStartup(MAKEWORD(2,2), &Data);
- if (ret != 0) {
- err = WSAGetLastError();
- fprintf(stderr, "WSAStartup: %d\n", err);
- return -1;
- }
- atexit(socket_cleanup);
-#endif
- return 0;
-}