From 497adba2d432d37f236495b2309c469886dbbd33 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 20 Oct 2010 15:13:00 +0100 Subject: [PATCH] Expand virSocketFormat to be more flexible The getnameinfo() function is more flexible than inet_ntop() avoiding the need to if/else the code based on socket family. Also make it support UNIX socket addrs and allow inclusion of a port (service) address. Finally do proper error reporting via normal APIs. * src/conf/domain_conf.c, src/nwfilter/nwfilter_ebiptables_driver.c, src/qemu/qemu_conf.c: Fix error handling with virSocketFormat * src/util/network.c: Rewrite virSocketFormat to use getnameinfo and cope with UNIX socket addrs. --- po/POTFILES.in | 1 + src/conf/domain_conf.c | 5 +- src/libvirt_private.syms | 1 + src/nwfilter/nwfilter_ebiptables_driver.c | 12 +--- src/qemu/qemu_conf.c | 2 + src/util/network.c | 82 +++++++++++++++++------ src/util/network.h | 5 ++ 7 files changed, 75 insertions(+), 33 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index e30fea0269..60ba68b95c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -83,6 +83,7 @@ src/util/hostusb.c src/util/interface.c src/util/json.c src/util/macvtap.c +src/util/network.c src/util/pci.c src/util/processinfo.c src/util/stats_linux.c diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 53c8d0940a..945c1f4a37 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -5960,11 +5960,8 @@ virDomainChrDefFormat(virBufferPtr buf, } const char *addr = virSocketFormatAddr(def->target.addr); - if (addr == NULL) { - virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to format guestfwd address")); + if (addr == NULL) return -1; - } virBufferVSprintf(buf, " address='%s' port='%d'", addr, port); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index edfb254f64..1a71e79b8e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -501,6 +501,7 @@ virReallocN; virSocketAddrIsNetmask; virSocketCheckNetmask; virSocketFormatAddr; +virSocketFormatAddrFull; virSocketGetPort; virSocketGetRange; virSocketParseAddr; diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c index caa37cba79..21b1b5122b 100644 --- a/src/nwfilter/nwfilter_ebiptables_driver.c +++ b/src/nwfilter/nwfilter_ebiptables_driver.c @@ -190,12 +190,8 @@ _printDataType(virNWFilterHashTablePtr vars, switch (item->datatype) { case DATATYPE_IPADDR: data = virSocketFormatAddr(&item->u.ipaddr); - if (!data) { - virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("internal IPv4 address representation " - "is bad")); + if (!data) return 1; - } if (snprintf(buf, bufsize, "%s", data) >= bufsize) { virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("buffer too small for IP address")); @@ -207,12 +203,8 @@ _printDataType(virNWFilterHashTablePtr vars, case DATATYPE_IPV6ADDR: data = virSocketFormatAddr(&item->u.ipaddr); - if (!data) { - virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("internal IPv6 address representation " - "is bad")); + if (!data) return 1; - } if (snprintf(buf, bufsize, "%s", data) >= bufsize) { virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s", diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 67195784da..e2c67a31a3 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -4727,6 +4727,8 @@ int qemudBuildCommandLine(virConnectPtr conn, ADD_ARG(devstr); char *addr = virSocketFormatAddr(channel->target.addr); + if (!addr) + goto error; int port = virSocketGetPort(channel->target.addr); ADD_ARG_LIT("-netdev"); diff --git a/src/util/network.c b/src/util/network.c index de22ded6b8..0c7cb63356 100644 --- a/src/util/network.c +++ b/src/util/network.c @@ -13,6 +13,13 @@ #include "memory.h" #include "network.h" +#include "util.h" +#include "virterror_internal.h" + +#define VIR_FROM_THIS VIR_FROM_NONE +#define virSocketError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_THIS, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) /* * Helpers to extract the IP arrays from the virSocketAddrPtr @@ -129,38 +136,75 @@ virSocketParseIpv6Addr(const char *val, virSocketAddrPtr addr) { */ char * virSocketFormatAddr(virSocketAddrPtr addr) { - char *out; - size_t outlen; - void *inaddr; + return virSocketFormatAddrFull(addr, false, NULL); +} - if (addr == NULL) - return NULL; - if (addr->data.stor.ss_family == AF_INET) { - outlen = INET_ADDRSTRLEN; - inaddr = &addr->data.inet4.sin_addr; - } +/* + * virSocketFormatAddrFull: + * @addr: an initialized virSocketAddrPtr + * @withService: if true, then service info is appended + * @separator: separator between hostname & service. + * + * Returns a string representation of the given address + * Returns NULL on any error + * Caller must free the returned string + */ +char * +virSocketFormatAddrFull(virSocketAddrPtr addr, + bool withService, + const char *separator) +{ + char host[NI_MAXHOST], port[NI_MAXSERV]; + char *addrstr; + int err; - else if (addr->data.stor.ss_family == AF_INET6) { - outlen = INET6_ADDRSTRLEN; - inaddr = &addr->data.inet6.sin6_addr; + if (addr == NULL) { + virSocketError(VIR_ERR_INVALID_ARG, _("Missing address")); + return NULL; } - else { - return NULL; + /* Short-circuit since getnameinfo doesn't work + * nicely for UNIX sockets */ + if (addr->data.sa.sa_family == AF_UNIX) { + if (withService) { + if (virAsprintf(&addrstr, "127.0.0.1%s0", + separator ? separator : ":") < 0) + goto no_memory; + } else { + if (!(addrstr = strdup("127.0.0.1"))) + goto no_memory; + } + return addrstr; } - if (VIR_ALLOC_N(out, outlen) < 0) + if ((err = getnameinfo(&addr->data.sa, + addr->len, + host, sizeof(host), + port, sizeof(port), + NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { + virSocketError(VIR_ERR_SYSTEM_ERROR, + _("Cannot convert socket address to string: %s"), + gai_strerror(err)); return NULL; + } - if (inet_ntop(addr->data.stor.ss_family, inaddr, out, outlen) == NULL) { - VIR_FREE(out); - return NULL; + if (withService) { + if (virAsprintf(&addrstr, "%s%s%s", host, separator, port) == -1) + goto no_memory; + } else { + if (!(addrstr = strdup(host))) + goto no_memory; } - return out; + return addrstr; + +no_memory: + virReportOOMError(); + return NULL; } + /* * virSocketSetPort: * @addr: an initialized virSocketAddrPtr diff --git a/src/util/network.h b/src/util/network.h index ef92c9b38d..5147ea5227 100644 --- a/src/util/network.h +++ b/src/util/network.h @@ -16,9 +16,11 @@ # include # include # include +# include typedef struct { union { + struct sockaddr sa; struct sockaddr_storage stor; struct sockaddr_in inet4; struct sockaddr_in6 inet6; @@ -39,6 +41,9 @@ int virSocketParseIpv6Addr(const char *val, virSocketAddrPtr addr); char * virSocketFormatAddr(virSocketAddrPtr addr); +char * virSocketFormatAddrFull(virSocketAddrPtr addr, + bool withService, + const char *separator); int virSocketSetPort(virSocketAddrPtr addr, int port); -- GitLab