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.
This commit is contained in:
Daniel P. Berrange 2010-10-20 15:13:00 +01:00
parent 7ab7d17bfb
commit 497adba2d4
7 changed files with 86 additions and 44 deletions

View File

@ -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

View File

@ -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);

View File

@ -501,6 +501,7 @@ virReallocN;
virSocketAddrIsNetmask;
virSocketCheckNetmask;
virSocketFormatAddr;
virSocketFormatAddrFull;
virSocketGetPort;
virSocketGetRange;
virSocketParseAddr;

View File

@ -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",

View File

@ -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");

View File

@ -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;
if (addr == NULL)
return NULL;
if (addr->data.stor.ss_family == AF_INET) {
outlen = INET_ADDRSTRLEN;
inaddr = &addr->data.inet4.sin_addr;
}
else if (addr->data.stor.ss_family == AF_INET6) {
outlen = INET6_ADDRSTRLEN;
inaddr = &addr->data.inet6.sin6_addr;
}
else {
return NULL;
}
if (VIR_ALLOC_N(out, outlen) < 0)
return NULL;
if (inet_ntop(addr->data.stor.ss_family, inaddr, out, outlen) == NULL) {
VIR_FREE(out);
return NULL;
}
return out;
return virSocketFormatAddrFull(addr, false, NULL);
}
/*
* 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;
if (addr == NULL) {
virSocketError(VIR_ERR_INVALID_ARG, _("Missing address"));
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 ((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 (withService) {
if (virAsprintf(&addrstr, "%s%s%s", host, separator, port) == -1)
goto no_memory;
} else {
if (!(addrstr = strdup(host)))
goto no_memory;
}
return addrstr;
no_memory:
virReportOOMError();
return NULL;
}
/*
* virSocketSetPort:
* @addr: an initialized virSocketAddrPtr

View File

@ -16,9 +16,11 @@
# include <sys/types.h>
# include <sys/socket.h>
# include <netdb.h>
# include <stdbool.h>
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);