diff --git a/ChangeLog b/ChangeLog index 7a02d58b8a..d90a12833b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Tue Mar 06 17:02:12 EST 2007 Daniel P. Berrange <berrange@redhat.com> + + * src/hash.c: virGetDomain and virGetNetwork require that both + name and UUID are non-NULL. (Patch from Rich Jones) + Tue Mar 06 16:52:12 EST 2007 Daniel P. Berrange <berrange@redhat.com> * include/libvirt/libvirt.h.in, python/libvir.c, src/driver.h diff --git a/src/hash.c b/src/hash.c index b0f4785419..0427f06bfd 100644 --- a/src/hash.c +++ b/src/hash.c @@ -617,7 +617,7 @@ virHashError(virConnectPtr conn, virErrorNumber error, const char *info) return; errmsg = __virErrorMsg(error, info); - __virRaiseError(conn, NULL, VIR_FROM_NONE, error, VIR_ERR_ERROR, + __virRaiseError(conn, NULL, NULL, VIR_FROM_NONE, error, VIR_ERR_ERROR, errmsg, info, NULL, 0, 0, errmsg, info); } @@ -636,6 +636,20 @@ virDomainFreeName(virDomainPtr domain, const char *name ATTRIBUTE_UNUSED) return (virDomainFree(domain)); } +/** + * virNetworkFreeName: + * @network: a network object + * + * Destroy the network object, this is just used by the network hash callback. + * + * Returns 0 in case of success and -1 in case of failure. + */ +static int +virNetworkFreeName(virNetworkPtr network, const char *name ATTRIBUTE_UNUSED) +{ + return (virNetworkFree(network)); +} + /** * virGetConnect: * @@ -660,6 +674,9 @@ virGetConnect(void) { ret->domains = virHashCreate(20); if (ret->domains == NULL) goto failed; + ret->networks = virHashCreate(20); + if (ret->networks == NULL) + goto failed; ret->hashes_mux = xmlNewMutex(); if (ret->hashes_mux == NULL) goto failed; @@ -671,6 +688,8 @@ failed: if (ret != NULL) { if (ret->domains != NULL) virHashFree(ret->domains, (virHashDeallocator) virDomainFreeName); + if (ret->networks != NULL) + virHashFree(ret->networks, (virHashDeallocator) virNetworkFreeName); if (ret->hashes_mux != NULL) xmlFreeMutex(ret->hashes_mux); free(ret); @@ -705,6 +724,8 @@ virFreeConnect(virConnectPtr conn) { if (conn->domains != NULL) virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName); + if (conn->networks != NULL) + virHashFree(conn->networks, (virHashDeallocator) virNetworkFreeName); if (conn->hashes_mux != NULL) xmlFreeMutex(conn->hashes_mux); free(conn); @@ -714,8 +735,8 @@ virFreeConnect(virConnectPtr conn) { /** * virGetDomain: * @conn: the hypervisor connection - * @name: pointer to the domain name or NULL - * @uuid: pointer to the uuid or NULL + * @name: pointer to the domain name + * @uuid: pointer to the uuid * * Lookup if the domain is already registered for that connection, * if yes return a new pointer to it, if no allocate a new structure, @@ -728,7 +749,7 @@ virDomainPtr virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) { virDomainPtr ret = NULL; - if ((!VIR_IS_CONNECT(conn)) || ((name == NULL) && (uuid == NULL)) || + if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL) || (conn->hashes_mux == NULL)) { virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(NULL); @@ -893,6 +914,139 @@ done: xmlMutexUnlock(conn->hashes_mux); return(ret); } + +/** + * virGetNetwork: + * @conn: the hypervisor connection + * @name: pointer to the network name + * @uuid: pointer to the uuid + * + * Lookup if the network is already registered for that connection, + * if yes return a new pointer to it, if no allocate a new structure, + * and register it in the table. In any case a corresponding call to + * virFreeNetwork() is needed to not leak data. + * + * Returns a pointer to the network, or NULL in case of failure + */ +virNetworkPtr +virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) { + virNetworkPtr ret = NULL; + + if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL) || + (conn->hashes_mux == NULL)) { + virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(NULL); + } + xmlMutexLock(conn->hashes_mux); + + /* TODO search by UUID first as they are better differenciators */ + + ret = (virNetworkPtr) virHashLookup(conn->networks, name); + if (ret != NULL) { + /* TODO check the UUID */ + goto done; + } + + /* + * not found, allocate a new one + */ + ret = (virNetworkPtr) malloc(sizeof(virNetwork)); + if (ret == NULL) { + virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating network")); + goto error; + } + memset(ret, 0, sizeof(virNetwork)); + ret->name = strdup(name); + if (ret->name == NULL) { + virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating network")); + goto error; + } + ret->magic = VIR_NETWORK_MAGIC; + ret->conn = conn; + if (uuid != NULL) + memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN); + + if (virHashAddEntry(conn->networks, name, ret) < 0) { + virHashError(conn, VIR_ERR_INTERNAL_ERROR, + _("failed to add network to connection hash table")); + goto error; + } + conn->uses++; +done: + ret->uses++; + xmlMutexUnlock(conn->hashes_mux); + return(ret); + +error: + xmlMutexUnlock(conn->hashes_mux); + if (ret != NULL) { + if (ret->name != NULL) + free(ret->name ); + free(ret); + } + return(NULL); +} + +/** + * virFreeNetwork: + * @conn: the hypervisor connection + * @network: the network to release + * + * Release the given network, if the reference count drops to zero, then + * the network is really freed. + * + * Returns the reference count or -1 in case of failure. + */ +int +virFreeNetwork(virConnectPtr conn, virNetworkPtr network) { + int ret = 0; + + if ((!VIR_IS_CONNECT(conn)) || (!VIR_IS_CONNECTED_NETWORK(network)) || + (network->conn != conn) || (conn->hashes_mux == NULL)) { + virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + xmlMutexLock(conn->hashes_mux); + + /* + * decrement the count for the network + */ + network->uses--; + ret = network->uses; + if (ret > 0) + goto done; + + /* TODO search by UUID first as they are better differenciators */ + + if (virHashRemoveEntry(conn->networks, network->name, NULL) < 0) { + virHashError(conn, VIR_ERR_INTERNAL_ERROR, + _("network missing from connection hash table")); + goto done; + } + network->magic = -1; + if (network->name) + free(network->name); + free(network); + + /* + * decrement the count for the connection + */ + conn->uses--; + if (conn->uses > 0) + goto done; + + if (conn->networks != NULL) + virHashFree(conn->networks, (virHashDeallocator) virNetworkFreeName); + if (conn->hashes_mux != NULL) + xmlFreeMutex(conn->hashes_mux); + free(conn); + return(0); + +done: + xmlMutexUnlock(conn->hashes_mux); + return(ret); +} + /* * Local variables: * indent-tabs-mode: nil