[libvirt] More coverage for networking API v4

I wasn't setting return values to GTask correctly in the v3. Fixed now.

Make use of virConnectListAll* functions to avoid making 4 calls and hence avoid race conditions and complicated code. --- libvirt-gobject/libvirt-gobject-connection.c | 203 ++++----------------------- 1 file changed, 28 insertions(+), 175 deletions(-) diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index cf073a5..1576906 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -680,48 +680,6 @@ void gvir_connection_close(GVirConnection *conn) g_signal_emit(conn, signals[VIR_CONNECTION_CLOSED], 0); } -typedef gint (* CountFunction) (virConnectPtr vconn); -typedef gint (* ListFunction) (virConnectPtr vconn, gchar **lst, gint max); - -static gchar ** fetch_list(virConnectPtr vconn, - const char *name, - CountFunction count_func, - ListFunction list_func, - GCancellable *cancellable, - gint *length, - GError **err) -{ - gchar **lst = NULL; - gint n = 0; - - if ((n = count_func(vconn)) < 0) { - gvir_set_error(err, GVIR_CONNECTION_ERROR, - 0, - _("Unable to count %s"), name); - goto error; - } - - if (n) { - if (g_cancellable_set_error_if_cancelled(cancellable, err)) - goto error; - - lst = g_new0(gchar *, n); - if ((n = list_func(vconn, lst, n)) < 0) { - gvir_set_error(err, GVIR_CONNECTION_ERROR, - 0, - _("Unable to list %s %d"), name, n); - goto error; - } - } - - *length = n; - return lst; - -error: - g_free(lst); - return NULL; -} - /** * gvir_connection_fetch_domains: * @conn: a #GVirConnection @@ -733,14 +691,11 @@ gboolean gvir_connection_fetch_domains(GVirConnection *conn, { GVirConnectionPrivate *priv; GHashTable *doms; - gchar **inactive = NULL; - gint ninactive = 0; - gint *active = NULL; - gint nactive = 0; + virDomainPtr *domains = NULL; + gint ndomains = 0; gboolean ret = FALSE; gint i; virConnectPtr vconn = NULL; - GError *lerr = NULL; g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); g_return_val_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable), @@ -761,81 +716,28 @@ gboolean gvir_connection_fetch_domains(GVirConnection *conn, virConnectRef(vconn); g_mutex_unlock(priv->lock); - if (g_cancellable_set_error_if_cancelled(cancellable, err)) - goto cleanup; - - if ((nactive = virConnectNumOfDomains(vconn)) < 0) { - gvir_set_error_literal(err, GVIR_CONNECTION_ERROR, - 0, - _("Unable to count domains")); + ndomains = virConnectListAllDomains(vconn, &domains, 0); + if (ndomains < 0) { + gvir_set_error(err, GVIR_CONNECTION_ERROR, + 0, + _("Failed to fetch list of domains")); goto cleanup; } - if (nactive) { - if (g_cancellable_set_error_if_cancelled(cancellable, err)) - goto cleanup; - - active = g_new(gint, nactive); - if ((nactive = virConnectListDomains(vconn, active, nactive)) < 0) { - gvir_set_error_literal(err, GVIR_CONNECTION_ERROR, - 0, - _("Unable to list domains")); - goto cleanup; - } - } if (g_cancellable_set_error_if_cancelled(cancellable, err)) goto cleanup; - inactive = fetch_list(vconn, - "Domains", - virConnectNumOfDefinedDomains, - virConnectListDefinedDomains, - cancellable, - &ninactive, - &lerr); - if (lerr) { - g_propagate_error(err, lerr); - lerr = NULL; - goto cleanup; - } - doms = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref); - for (i = 0 ; i < nactive ; i++) { - if (g_cancellable_set_error_if_cancelled(cancellable, err)) - goto cleanup; - - virDomainPtr vdom = virDomainLookupByID(vconn, active[i]); + for (i = 0 ; i < ndomains; i++) { GVirDomain *dom; - if (!vdom) - continue; dom = GVIR_DOMAIN(g_object_new(GVIR_TYPE_DOMAIN, - "handle", vdom, + "handle", domains[i], NULL)); - virDomainFree(vdom); - - g_hash_table_insert(doms, - (gpointer)gvir_domain_get_uuid(dom), - dom); - } - - for (i = 0 ; i < ninactive ; i++) { - if (g_cancellable_set_error_if_cancelled(cancellable, err)) - goto cleanup; - - virDomainPtr vdom = virDomainLookupByName(vconn, inactive[i]); - GVirDomain *dom; - if (!vdom) - continue; - - dom = GVIR_DOMAIN(g_object_new(GVIR_TYPE_DOMAIN, - "handle", vdom, - NULL)); - virDomainFree(vdom); g_hash_table_insert(doms, (gpointer)gvir_domain_get_uuid(dom), @@ -852,10 +754,11 @@ gboolean gvir_connection_fetch_domains(GVirConnection *conn, ret = TRUE; cleanup: - g_free(active); - for (i = 0 ; i < ninactive ; i++) - g_free(inactive[i]); - g_free(inactive); + if (ndomains > 0) { + for (i = 0 ; i < ndomains; i++) + virDomainFree(domains[i]); + free(domains); + } return ret; } @@ -870,14 +773,11 @@ gboolean gvir_connection_fetch_storage_pools(GVirConnection *conn, { GVirConnectionPrivate *priv; GHashTable *pools; - gchar **inactive = NULL; - gint ninactive = 0; - gchar **active = NULL; - gint nactive = 0; + virStoragePoolPtr *vpools = NULL; + gint npools = 0; gboolean ret = FALSE; gint i; virConnectPtr vconn = NULL; - GError *lerr = NULL; g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); g_return_val_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable), @@ -901,77 +801,31 @@ gboolean gvir_connection_fetch_storage_pools(GVirConnection *conn, if (g_cancellable_set_error_if_cancelled(cancellable, err)) goto cleanup; - active = fetch_list(vconn, - "Storage Pools", - virConnectNumOfStoragePools, - virConnectListStoragePools, - cancellable, - &nactive, - &lerr); - if (lerr) { - g_propagate_error(err, lerr); - lerr = NULL; + npools = virConnectListAllStoragePools(vconn, &vpools, 0); + if (npools < 0) { + gvir_set_error(err, GVIR_CONNECTION_ERROR, + 0, + _("Failed to fetch list of pools")); goto cleanup; } if (g_cancellable_set_error_if_cancelled(cancellable, err)) goto cleanup; - inactive = fetch_list(vconn, - "Storage Pools", - virConnectNumOfDefinedStoragePools, - virConnectListDefinedStoragePools, - cancellable, - &ninactive, - &lerr); - if (lerr) { - g_propagate_error(err, lerr); - lerr = NULL; - goto cleanup; - } - pools = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref); - for (i = 0 ; i < nactive ; i++) { + for (i = 0 ; i < npools; i++) { if (g_cancellable_set_error_if_cancelled(cancellable, err)) goto cleanup; - virStoragePoolPtr vpool; GVirStoragePool *pool; - vpool = virStoragePoolLookupByName(vconn, active[i]); - if (!vpool) - continue; - - pool = GVIR_STORAGE_POOL(g_object_new(GVIR_TYPE_STORAGE_POOL, - "handle", vpool, - NULL)); - virStoragePoolFree(vpool); - - g_hash_table_insert(pools, - (gpointer)gvir_storage_pool_get_uuid(pool), - pool); - } - - for (i = 0 ; i < ninactive ; i++) { - if (g_cancellable_set_error_if_cancelled(cancellable, err)) - goto cleanup; - - virStoragePoolPtr vpool; - GVirStoragePool *pool; - - vpool = virStoragePoolLookupByName(vconn, inactive[i]); - if (!vpool) - continue; - pool = GVIR_STORAGE_POOL(g_object_new(GVIR_TYPE_STORAGE_POOL, - "handle", vpool, + "handle", vpools[i], NULL)); - virStoragePoolFree(vpool); - g_hash_table_insert(pools, (gpointer)gvir_storage_pool_get_uuid(pool), pool); @@ -987,12 +841,11 @@ gboolean gvir_connection_fetch_storage_pools(GVirConnection *conn, ret = TRUE; cleanup: - for (i = 0 ; i < nactive ; i++) - g_free(active[i]); - g_free(active); - for (i = 0 ; i < ninactive ; i++) - g_free(inactive[i]); - g_free(inactive); + if (npools > 0) { + for (i = 0 ; i < npools; i++) + virStoragePoolFree(vpools[i]); + free(vpools); + } return ret; } -- 2.4.3

On Wed, Jul 01, 2015 at 09:40:45PM +0100, Zeeshan Ali (Khattak) wrote:
Make use of virConnectListAll* functions to avoid making 4 calls and hence avoid race conditions and complicated code.
Fwiw, I would have split this in 2, one for domains, and one for pools, but fine this way too, ACK. Christophe

On Wed, Jul 01, 2015 at 09:40:45PM +0100, Zeeshan Ali (Khattak) wrote:
@@ -901,77 +801,31 @@ gboolean gvir_connection_fetch_storage_pools(GVirConnection *conn, if (g_cancellable_set_error_if_cancelled(cancellable, err)) goto cleanup;
- active = fetch_list(vconn, - "Storage Pools", - virConnectNumOfStoragePools, - virConnectListStoragePools, - cancellable, - &nactive, - &lerr); - if (lerr) { - g_propagate_error(err, lerr); - lerr = NULL; + npools = virConnectListAllStoragePools(vconn, &vpools, 0); + if (npools < 0) { + gvir_set_error(err, GVIR_CONNECTION_ERROR, + 0, + _("Failed to fetch list of pools")); goto cleanup; }
if (g_cancellable_set_error_if_cancelled(cancellable, err)) goto cleanup;
- inactive = fetch_list(vconn, - "Storage Pools", - virConnectNumOfDefinedStoragePools, - virConnectListDefinedStoragePools, - cancellable, - &ninactive, - &lerr); - if (lerr) { - g_propagate_error(err, lerr); - lerr = NULL; - goto cleanup; - } - pools = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref);
- for (i = 0 ; i < nactive ; i++) { + for (i = 0 ; i < npools; i++) { if (g_cancellable_set_error_if_cancelled(cancellable, err)) goto cleanup;
- virStoragePoolPtr vpool; GVirStoragePool *pool;
While touching this code, you could move 'pool' declaration to the beginning of the 'for' block. Christophe

--- libvirt-gobject/libvirt-gobject-connection.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index 1576906..dddbd3a 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -748,7 +748,6 @@ gboolean gvir_connection_fetch_domains(GVirConnection *conn, if (priv->domains) g_hash_table_unref(priv->domains); priv->domains = doms; - virConnectClose(vconn); g_mutex_unlock(priv->lock); ret = TRUE; @@ -759,6 +758,8 @@ cleanup: virDomainFree(domains[i]); free(domains); } + if (vconn != NULL) + virConnectClose(vconn); return ret; } @@ -835,7 +836,6 @@ gboolean gvir_connection_fetch_storage_pools(GVirConnection *conn, if (priv->pools) g_hash_table_unref(priv->pools); priv->pools = pools; - virConnectClose(vconn); g_mutex_unlock(priv->lock); ret = TRUE; @@ -846,6 +846,8 @@ cleanup: virStoragePoolFree(vpools[i]); free(vpools); } + if (vconn != NULL) + virConnectClose(vconn); return ret; } -- 2.4.3

Please be a bit more verbose in the commit log as to what the leak is. (a virConnect reference is leaked in error cases, the unref is moved after the label we jump to on errors to avoid the leak) Looks good otherwise, Christophe On Wed, Jul 01, 2015 at 09:40:46PM +0100, Zeeshan Ali (Khattak) wrote:
--- libvirt-gobject/libvirt-gobject-connection.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index 1576906..dddbd3a 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -748,7 +748,6 @@ gboolean gvir_connection_fetch_domains(GVirConnection *conn, if (priv->domains) g_hash_table_unref(priv->domains); priv->domains = doms; - virConnectClose(vconn); g_mutex_unlock(priv->lock);
ret = TRUE; @@ -759,6 +758,8 @@ cleanup: virDomainFree(domains[i]); free(domains); } + if (vconn != NULL) + virConnectClose(vconn); return ret; }
@@ -835,7 +836,6 @@ gboolean gvir_connection_fetch_storage_pools(GVirConnection *conn, if (priv->pools) g_hash_table_unref(priv->pools); priv->pools = pools; - virConnectClose(vconn); g_mutex_unlock(priv->lock);
ret = TRUE; @@ -846,6 +846,8 @@ cleanup: virStoragePoolFree(vpools[i]); free(vpools); } + if (vconn != NULL) + virConnectClose(vconn); return ret; }
-- 2.4.3
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

GSimpleAsyncResult has been deprecated in favour of GTask and with latest glib headers, we get tons of warnings about use of deprecated API. This patch ports the GVirConnection class to GTask. --- libvirt-gobject/libvirt-gobject-connection.c | 246 ++++++++++++--------------- 1 file changed, 110 insertions(+), 136 deletions(-) diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index dddbd3a..f7a6066 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -497,17 +497,18 @@ gboolean gvir_connection_open_read_only(GVirConnection *conn, } static void -gvir_connection_open_helper(GSimpleAsyncResult *res, - GObject *object, +gvir_connection_open_helper(GTask *res, + gpointer object, + gpointer task_data G_GNUC_UNUSED, GCancellable *cancellable) { GVirConnection *conn = GVIR_CONNECTION(object); GError *err = NULL; - if (!gvir_connection_open(conn, cancellable, &err)) { - g_simple_async_result_set_from_error(res, err); - g_error_free(err); - } + if (!gvir_connection_open(conn, cancellable, &err)) + g_task_return_error(res, err); + else + g_task_return_boolean(res, TRUE); } @@ -523,19 +524,19 @@ void gvir_connection_open_async(GVirConnection *conn, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; + GTask *res; g_return_if_fail(GVIR_IS_CONNECTION(conn)); g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); - res = g_simple_async_result_new(G_OBJECT(conn), - callback, - user_data, - gvir_connection_open_async); - g_simple_async_result_run_in_thread(res, - gvir_connection_open_helper, - G_PRIORITY_DEFAULT, - cancellable); + res = g_task_new(G_OBJECT(conn), + cancellable, + callback, + user_data); + g_task_set_source_tag(res, + gvir_connection_open_async); + g_task_run_in_thread(res, + gvir_connection_open_helper); g_object_unref(res); } @@ -550,28 +551,25 @@ gboolean gvir_connection_open_finish(GVirConnection *conn, GError **err) { g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); - g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(conn), - gvir_connection_open_async), + g_return_val_if_fail(g_task_is_valid(result, G_OBJECT(conn)), FALSE); - if (g_simple_async_result_propagate_error(G_SIMPLE_ASYNC_RESULT(result), err)) - return FALSE; - - return TRUE; + return g_task_propagate_boolean(G_TASK(result), err); } static void -gvir_connection_open_read_only_helper(GSimpleAsyncResult *res, - GObject *object, - GCancellable *cancellable) +gvir_connection_open_read_only_helper(GTask *res, + gpointer object, + gpointer task_data G_GNUC_UNUSED, + GCancellable *cancellable) { GVirConnection *conn = GVIR_CONNECTION(object); GError *err = NULL; - if (!gvir_connection_open_read_only(conn, cancellable, &err)) { - g_simple_async_result_set_from_error(res, err); - g_error_free(err); - } + if (!gvir_connection_open_read_only(conn, cancellable, &err)) + g_task_return_error(res, err); + else + g_task_return_boolean(res, TRUE); } @@ -587,19 +585,19 @@ void gvir_connection_open_read_only_async(GVirConnection *conn, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; + GTask *res; g_return_if_fail(GVIR_IS_CONNECTION(conn)); g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); - res = g_simple_async_result_new(G_OBJECT(conn), - callback, - user_data, - gvir_connection_open_read_only_async); - g_simple_async_result_run_in_thread(res, - gvir_connection_open_read_only_helper, - G_PRIORITY_DEFAULT, - cancellable); + res = g_task_new(G_OBJECT(conn), + cancellable, + callback, + user_data); + g_task_set_source_tag(res, + gvir_connection_open_read_only_async); + g_task_run_in_thread(res, + gvir_connection_open_read_only_helper); g_object_unref(res); } @@ -614,14 +612,10 @@ gboolean gvir_connection_open_read_only_finish(GVirConnection *conn, GError **err) { g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); - g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(conn), - gvir_connection_open_read_only_async), + g_return_val_if_fail(g_task_is_valid(result, G_OBJECT(conn)), FALSE); - if (g_simple_async_result_propagate_error(G_SIMPLE_ASYNC_RESULT(result), err)) - return FALSE; - - return TRUE; + return g_task_propagate_boolean(G_TASK(result), err); } gboolean gvir_connection_is_open(GVirConnection *conn) @@ -852,17 +846,18 @@ cleanup: } static void -gvir_connection_fetch_domains_helper(GSimpleAsyncResult *res, - GObject *object, +gvir_connection_fetch_domains_helper(GTask *res, + gpointer object, + gpointer task_data G_GNUC_UNUSED, GCancellable *cancellable) { GVirConnection *conn = GVIR_CONNECTION(object); GError *err = NULL; - if (!gvir_connection_fetch_domains(conn, cancellable, &err)) { - g_simple_async_result_set_from_error(res, err); - g_error_free(err); - } + if (!gvir_connection_fetch_domains(conn, cancellable, &err)) + g_task_return_error(res, err); + else + g_task_return_boolean(res, TRUE); } @@ -878,19 +873,19 @@ void gvir_connection_fetch_domains_async(GVirConnection *conn, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; + GTask *res; g_return_if_fail(GVIR_IS_CONNECTION(conn)); g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); - res = g_simple_async_result_new(G_OBJECT(conn), - callback, - user_data, - gvir_connection_fetch_domains_async); - g_simple_async_result_run_in_thread(res, - gvir_connection_fetch_domains_helper, - G_PRIORITY_DEFAULT, - cancellable); + res = g_task_new(G_OBJECT(conn), + cancellable, + callback, + user_data); + g_task_set_source_tag(res, + gvir_connection_fetch_domains_async); + g_task_run_in_thread(res, + gvir_connection_fetch_domains_helper); g_object_unref(res); } @@ -904,28 +899,25 @@ gboolean gvir_connection_fetch_domains_finish(GVirConnection *conn, GError **err) { g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); - g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(conn), - gvir_connection_fetch_domains_async), + g_return_val_if_fail(g_task_is_valid(result, G_OBJECT(conn)), FALSE); - if (g_simple_async_result_propagate_error(G_SIMPLE_ASYNC_RESULT(result), err)) - return FALSE; - - return TRUE; + return g_task_propagate_boolean(G_TASK(result), err); } static void -gvir_connection_fetch_pools_helper(GSimpleAsyncResult *res, - GObject *object, +gvir_connection_fetch_pools_helper(GTask *res, + gpointer object, + gpointer task_data G_GNUC_UNUSED, GCancellable *cancellable) { GVirConnection *conn = GVIR_CONNECTION(object); GError *err = NULL; - if (!gvir_connection_fetch_storage_pools(conn, cancellable, &err)) { - g_simple_async_result_set_from_error(res, err); - g_error_free(err); - } + if (!gvir_connection_fetch_storage_pools(conn, cancellable, &err)) + g_task_return_error(res, err); + else + g_task_return_boolean(res, TRUE); } /** @@ -940,19 +932,19 @@ void gvir_connection_fetch_storage_pools_async(GVirConnection *conn, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; + GTask *res; g_return_if_fail(GVIR_IS_CONNECTION(conn)); g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); - res = g_simple_async_result_new(G_OBJECT(conn), - callback, - user_data, - gvir_connection_fetch_storage_pools_async); - g_simple_async_result_run_in_thread(res, - gvir_connection_fetch_pools_helper, - G_PRIORITY_DEFAULT, - cancellable); + res = g_task_new(G_OBJECT(conn), + cancellable, + callback, + user_data); + g_task_set_source_tag(res, + gvir_connection_fetch_storage_pools_async); + g_task_run_in_thread(res, + gvir_connection_fetch_pools_helper); g_object_unref(res); } @@ -966,14 +958,10 @@ gboolean gvir_connection_fetch_storage_pools_finish(GVirConnection *conn, GError **err) { g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); - g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(conn), - gvir_connection_fetch_storage_pools_async), + g_return_val_if_fail(g_task_is_valid(result, G_OBJECT(conn)), FALSE); - if (g_simple_async_result_propagate_error(G_SIMPLE_ASYNC_RESULT(result), err)) - return FALSE; - - return TRUE; + return g_task_propagate_boolean(G_TASK(result), err); } const gchar *gvir_connection_get_uri(GVirConnection *conn) @@ -1568,8 +1556,9 @@ GVirConfigCapabilities *gvir_connection_get_capabilities(GVirConnection *conn, } static void -gvir_connection_get_capabilities_helper(GSimpleAsyncResult *res, - GObject *object, +gvir_connection_get_capabilities_helper(GTask *res, + gpointer object, + gpointer task_data G_GNUC_UNUSED, GCancellable *cancellable G_GNUC_UNUSED) { GVirConnection *conn = GVIR_CONNECTION(object); @@ -1578,12 +1567,12 @@ gvir_connection_get_capabilities_helper(GSimpleAsyncResult *res, caps = gvir_connection_get_capabilities(conn, &err); if (caps == NULL) { - g_simple_async_result_take_error(res, err); + g_task_return_error(res, err); return; } - g_simple_async_result_set_op_res_gpointer(res, caps, g_object_unref); + g_task_return_pointer(res, caps, g_object_unref); } /** @@ -1598,19 +1587,19 @@ void gvir_connection_get_capabilities_async(GVirConnection *conn, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; + GTask *res; g_return_if_fail(GVIR_IS_CONNECTION(conn)); g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); - res = g_simple_async_result_new(G_OBJECT(conn), - callback, - user_data, - gvir_connection_get_capabilities_async); - g_simple_async_result_run_in_thread(res, - gvir_connection_get_capabilities_helper, - G_PRIORITY_DEFAULT, - cancellable); + res = g_task_new(G_OBJECT(conn), + cancellable, + callback, + user_data); + g_task_set_source_tag(res, + gvir_connection_get_capabilities_async); + g_task_run_in_thread(res, + gvir_connection_get_capabilities_helper); g_object_unref(res); } @@ -1628,19 +1617,11 @@ gvir_connection_get_capabilities_finish(GVirConnection *conn, GAsyncResult *result, GError **err) { - GVirConfigCapabilities *caps; - g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); - g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(conn), - gvir_connection_get_capabilities_async), + g_return_val_if_fail(g_task_is_valid(result, G_OBJECT(conn)), NULL); - if (g_simple_async_result_propagate_error(G_SIMPLE_ASYNC_RESULT(result), err)) - return NULL; - - caps = g_simple_async_result_get_op_res_gpointer(G_SIMPLE_ASYNC_RESULT(result)); - - return g_object_ref(caps); + return g_task_propagate_pointer(G_TASK(result), err); } /** @@ -1708,22 +1689,25 @@ static void restore_domain_from_file_data_free(RestoreDomainFromFileData *data) static void gvir_connection_restore_domain_from_file_helper - (GSimpleAsyncResult *res, - GObject *object, + (GTask *res, + gpointer object, + gpointer task_data, GCancellable *cancellable G_GNUC_UNUSED) { GVirConnection *conn = GVIR_CONNECTION(object); RestoreDomainFromFileData *data; GError *err = NULL; - data = g_simple_async_result_get_op_res_gpointer(res); + data = (RestoreDomainFromFileData *)task_data; if (!gvir_connection_restore_domain_from_file(conn, data->filename, data->custom_conf, data->flags, &err)) - g_simple_async_result_take_error(res, err); + g_task_return_error(res, err); + else + g_task_return_boolean(res, TRUE); } /** @@ -1747,7 +1731,7 @@ gvir_connection_restore_domain_from_file_async(GVirConnection *conn, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; + GTask *res; RestoreDomainFromFileData *data; g_return_if_fail(GVIR_IS_CONNECTION(conn)); @@ -1760,21 +1744,18 @@ gvir_connection_restore_domain_from_file_async(GVirConnection *conn, data->custom_conf = g_object_ref(custom_conf); data->flags = flags; - res = g_simple_async_result_new - (G_OBJECT(conn), - callback, - user_data, + res = g_task_new (G_OBJECT(conn), + cancellable, + callback, + user_data); + g_task_set_source_tag(res, gvir_connection_restore_domain_from_file_async); - g_simple_async_result_set_op_res_gpointer - (res, - data, - (GDestroyNotify)restore_domain_from_file_data_free); + g_task_set_task_data(res, + data, + (GDestroyNotify)restore_domain_from_file_data_free); - g_simple_async_result_run_in_thread - (res, - gvir_connection_restore_domain_from_file_helper, - G_PRIORITY_DEFAULT, - cancellable); + g_task_run_in_thread(res, + gvir_connection_restore_domain_from_file_helper); g_object_unref(res); } @@ -1795,15 +1776,8 @@ gvir_connection_restore_domain_from_file_finish(GVirConnection *conn, GError **err) { g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); - g_return_val_if_fail(g_simple_async_result_is_valid - (result, - G_OBJECT(conn), - gvir_connection_restore_domain_from_file_async), - FALSE); - - if (g_simple_async_result_propagate_error(G_SIMPLE_ASYNC_RESULT(result), - err)) - return FALSE; + g_return_val_if_fail(g_task_is_valid(result, G_OBJECT(conn)), + FALSE); - return TRUE; + return g_task_propagate_boolean(G_TASK(result), err); } -- 2.4.3

On Wed, Jul 01, 2015 at 09:40:47PM +0100, Zeeshan Ali (Khattak) wrote:
GSimpleAsyncResult has been deprecated in favour of GTask and with latest glib headers, we get tons of warnings about use of deprecated API. This patch ports the GVirConnection class to GTask. --- libvirt-gobject/libvirt-gobject-connection.c | 246 ++++++++++++--------------- 1 file changed, 110 insertions(+), 136 deletions(-)
diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index dddbd3a..f7a6066 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -497,17 +497,18 @@ gboolean gvir_connection_open_read_only(GVirConnection *conn, }
static void -gvir_connection_open_helper(GSimpleAsyncResult *res, - GObject *object, +gvir_connection_open_helper(GTask *res,
I'd have a strong preference for "GTask *task" throughout the patch rather than "GTask *res"
+ gpointer object, + gpointer task_data G_GNUC_UNUSED, GCancellable *cancellable) { GVirConnection *conn = GVIR_CONNECTION(object); GError *err = NULL;
- if (!gvir_connection_open(conn, cancellable, &err)) { - g_simple_async_result_set_from_error(res, err); - g_error_free(err); - } + if (!gvir_connection_open(conn, cancellable, &err)) + g_task_return_error(res, err); + else + g_task_return_boolean(res, TRUE); }
@@ -523,19 +524,19 @@ void gvir_connection_open_async(GVirConnection *conn, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; + GTask *res;
g_return_if_fail(GVIR_IS_CONNECTION(conn)); g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable));
- res = g_simple_async_result_new(G_OBJECT(conn), - callback, - user_data, - gvir_connection_open_async); - g_simple_async_result_run_in_thread(res, - gvir_connection_open_helper, - G_PRIORITY_DEFAULT, - cancellable); + res = g_task_new(G_OBJECT(conn), + cancellable, + callback, + user_data); + g_task_set_source_tag(res, + gvir_connection_open_async);
You set the source tag, but never use it, you're missing a g_task_get_source_tag() check if the async complete callback. [snip]
@@ -1760,21 +1744,18 @@ gvir_connection_restore_domain_from_file_async(GVirConnection *conn, data->custom_conf = g_object_ref(custom_conf); data->flags = flags;
- res = g_simple_async_result_new - (G_OBJECT(conn), - callback, - user_data, + res = g_task_new (G_OBJECT(conn),
Nit: Extra space before opening parens Christophe

Add API to query network interfaces from a connection. --- libvirt-gobject/libvirt-gobject-connection.c | 265 +++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-connection.h | 13 +- libvirt-gobject/libvirt-gobject.sym | 7 + 3 files changed, 283 insertions(+), 2 deletions(-) diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index f7a6066..47b6861 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -44,6 +44,7 @@ struct _GVirConnectionPrivate GHashTable *domains; GHashTable *pools; + GHashTable *interfaces; }; G_DEFINE_TYPE(GVirConnection, gvir_connection, G_TYPE_OBJECT); @@ -252,6 +253,10 @@ static void gvir_connection_init(GVirConnection *conn) g_str_equal, NULL, g_object_unref); + priv->interfaces = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); } @@ -662,6 +667,11 @@ void gvir_connection_close(GVirConnection *conn) priv->pools = NULL; } + if (priv->interfaces) { + g_hash_table_unref(priv->interfaces); + priv->interfaces = NULL; + } + if (priv->conn) { virConnectDomainEventDeregister(priv->conn, domain_event_cb); virConnectClose(priv->conn); @@ -1431,6 +1441,261 @@ GVirDomain *gvir_connection_start_domain(GVirConnection *conn, } /** + * gvir_connection_fetch_interfaces: + * @conn: a #GVirConnection + * @cancellable: (allow-none)(transfer none): cancellation object + * @err: return location for any errors + * + * Use this method to fetch information on all network interfaces + * managed by connection @conn on host machine. Use + * #gvir_connection_get_interfaces or #gvir_connection_get_interface after + * wards to query the fetched interfaces. + * + * Return value: %TRUE on success, %FALSE otherwise and @err is set. + */ +gboolean gvir_connection_fetch_interfaces(GVirConnection *conn, + GCancellable *cancellable, + GError **err) +{ + GVirConnectionPrivate *priv; + GHashTable *interfaces; + virInterfacePtr *ifaces = NULL; + gint ninterfaces = 0; + gboolean ret = FALSE; + gint i; + virConnectPtr vconn = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable), + FALSE); + g_return_val_if_fail((err == NULL) || (*err == NULL), FALSE); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (!priv->conn) { + g_set_error_literal(err, GVIR_CONNECTION_ERROR, + 0, + _("Connection is not open")); + g_mutex_unlock(priv->lock); + goto cleanup; + } + vconn = priv->conn; + /* Stop another thread closing the connection just at the minute */ + virConnectRef(vconn); + g_mutex_unlock(priv->lock); + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + ninterfaces = virConnectListAllInterfaces(vconn, &ifaces, 0); + if (ninterfaces < 0) { + gvir_set_error(err, GVIR_CONNECTION_ERROR, + 0, + _("Failed to fetch list of interfaces")); + goto cleanup; + } + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + interfaces = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); + + for (i = 0 ; i < ninterfaces; i++) { + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + GVirInterface *iface; + + iface = GVIR_INTERFACE(g_object_new(GVIR_TYPE_INTERFACE, + "handle", ifaces[i], + NULL)); + + g_hash_table_insert(interfaces, + (gpointer)gvir_interface_get_name(iface), + iface); + } + + g_mutex_lock(priv->lock); + if (priv->interfaces) + g_hash_table_unref(priv->interfaces); + priv->interfaces = interfaces; + g_mutex_unlock(priv->lock); + + ret = TRUE; + +cleanup: + if (ninterfaces > 0) { + for (i = 0 ; i < ninterfaces; i++) + virInterfaceFree(ifaces[i]); + free(ifaces); + } + if (vconn != NULL) + virConnectClose(vconn); + return ret; +} + +static void +gvir_connection_fetch_interfaces_helper(GTask *res, + gpointer object, + gpointer task_data G_GNUC_UNUSED, + GCancellable *cancellable) +{ + GVirConnection *conn = GVIR_CONNECTION(object); + GError *err = NULL; + + if (!gvir_connection_fetch_interfaces(conn, cancellable, &err)) + g_task_return_error(res, err); + else + g_task_return_boolean(res, TRUE); +} + + +/** + * gvir_connection_fetch_interfaces_async: + * @conn: a #GVirConnection + * @cancellable: (allow-none)(transfer none): cancellation object + * @callback: (scope async): completion callback + * @user_data: (closure): opaque data for callback + */ +void gvir_connection_fetch_interfaces_async(GVirConnection *conn, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *res; + + g_return_if_fail(GVIR_IS_CONNECTION(conn)); + g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); + + res = g_task_new(G_OBJECT(conn), + cancellable, + callback, + user_data); + g_task_set_source_tag(res, + gvir_connection_fetch_interfaces_async); + g_task_run_in_thread(res, + gvir_connection_fetch_interfaces_helper); + g_object_unref(res); +} + +/** + * gvir_connection_fetch_interfaces_finish: + * @conn: a #GVirConnection + * @result: (transfer none): async method result + * @err: return location for any errors + */ +gboolean gvir_connection_fetch_interfaces_finish(GVirConnection *conn, + GAsyncResult *result, + GError **err) +{ + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail(g_task_is_valid(result, G_OBJECT(conn)), + FALSE); + + return g_task_propagate_boolean(G_TASK(result), err); +} + +/** + * gvir_connection_get_interfaces: + * @conn: a #GVirConnection + * + * Gets a list of all the network interfaces managed by connection @conn on + * host machine. + * + * Return value: (element-type LibvirtGObject.Interface) (transfer full): List + * of #GVirInterface. The returned list should be freed with g_list_free(), + * after its elements have been unreffed with g_object_unref(). + */ +GList *gvir_connection_get_interfaces(GVirConnection *conn) +{ + GVirConnectionPrivate *priv; + GList *interfaces = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (priv->interfaces != NULL) { + interfaces = g_hash_table_get_values(priv->interfaces); + g_list_foreach(interfaces, gvir_domain_ref, NULL); + } + g_mutex_unlock(priv->lock); + + return interfaces; +} + +/** + * gvir_connection_get_interface: + * @conn: a #GVirConnection + * + * Get a particular interface which has name @name. + * + * Return value: (transfer full): A new reference to a #GVirInterface, or NULL + * if no interface exists with name @name. The returned object must be unreffed + * using g_object_unref() once used. + */ +GVirInterface *gvir_connection_get_interface(GVirConnection *conn, + const gchar *name) +{ + GVirConnectionPrivate *priv; + GVirInterface *iface; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(name != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + iface = g_hash_table_lookup(priv->interfaces, name); + if (iface) + g_object_ref(iface); + g_mutex_unlock(priv->lock); + + return iface; +} + +/** + * gvir_connection_find_interface_by_mac: + * @conn: a #GVirConnection + * + * Get a particular interface which has MAC address @mac. + * + * Return value: (transfer full): A new reference to a #GVirInterface, or NULL + * if no interface exists with MAC address @mac. The returned object must be + * unreffed using g_object_unref() once used. + */ +GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, + const gchar *mac) +{ + GVirConnectionPrivate *priv; + GHashTableIter iter; + gpointer key, value; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(mac != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + g_hash_table_iter_init(&iter, priv->interfaces); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + GVirInterface *iface = value; + const gchar *thismac = gvir_interface_get_mac(iface); + + if (g_strcmp0(thismac, mac) == 0) { + g_object_ref(iface); + g_mutex_unlock(priv->lock); + return iface; + } + } + g_mutex_unlock(priv->lock); + + return NULL; +} + +/** * gvir_connection_create_storage_pool: * @conn: a #GVirConnection on which to create the pool * @conf: the configuration for the new storage pool diff --git a/libvirt-gobject/libvirt-gobject-connection.h b/libvirt-gobject/libvirt-gobject-connection.h index 8bca8d4..0c22a58 100644 --- a/libvirt-gobject/libvirt-gobject-connection.h +++ b/libvirt-gobject/libvirt-gobject-connection.h @@ -144,14 +144,23 @@ GVirDomain *gvir_connection_start_domain(GVirConnection *conn, guint flags, GError **err); -#if 0 +gboolean gvir_connection_fetch_interfaces(GVirConnection *conn, + GCancellable *cancellable, + GError **err); +void gvir_connection_fetch_interfaces_async(GVirConnection *conn, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean gvir_connection_fetch_interfaces_finish(GVirConnection *conn, + GAsyncResult *result, + GError **err); GList *gvir_connection_get_interfaces(GVirConnection *conn); GVirInterface *gvir_connection_get_interface(GVirConnection *conn, const gchar *name); GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, const gchar *macaddr); - +#if 0 GList *gvir_connection_get_networks(GVirConnection *conn); GVirNetwork *gvir_connection_get_network(GVirConnection *conn, const gchar *uuid); diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 29c4349..1effcda 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -273,6 +273,13 @@ LIBVIRT_GOBJECT_0.2.1 { LIBVIRT_GOBJECT_0.2.2 { global: + gvir_connection_fetch_interfaces; + gvir_connection_fetch_interfaces_async; + gvir_connection_fetch_interfaces_finish; + gvir_connection_find_interface_by_mac; + gvir_connection_get_interface; + gvir_connection_get_interfaces; + gvir_interface_get_mac; } LIBVIRT_GOBJECT_0.2.1; -- 2.4.3

On Wed, Jul 01, 2015 at 09:40:48PM +0100, Zeeshan Ali (Khattak) wrote:
Add API to query network interfaces from a connection. --- libvirt-gobject/libvirt-gobject-connection.c | 265 +++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-connection.h | 13 +- libvirt-gobject/libvirt-gobject.sym | 7 + 3 files changed, 283 insertions(+), 2 deletions(-)
diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index f7a6066..47b6861 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -44,6 +44,7 @@ struct _GVirConnectionPrivate
GHashTable *domains; GHashTable *pools; + GHashTable *interfaces; };
G_DEFINE_TYPE(GVirConnection, gvir_connection, G_TYPE_OBJECT); @@ -252,6 +253,10 @@ static void gvir_connection_init(GVirConnection *conn) g_str_equal, NULL, g_object_unref); + priv->interfaces = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); }
@@ -662,6 +667,11 @@ void gvir_connection_close(GVirConnection *conn) priv->pools = NULL; }
+ if (priv->interfaces) { + g_hash_table_unref(priv->interfaces); + priv->interfaces = NULL; + } + if (priv->conn) { virConnectDomainEventDeregister(priv->conn, domain_event_cb); virConnectClose(priv->conn); @@ -1431,6 +1441,261 @@ GVirDomain *gvir_connection_start_domain(GVirConnection *conn, }
/** + * gvir_connection_fetch_interfaces: + * @conn: a #GVirConnection + * @cancellable: (allow-none)(transfer none): cancellation object + * @err: return location for any errors + * + * Use this method to fetch information on all network interfaces
s/on/about ?
+ * managed by connection @conn on host machine. Use + * #gvir_connection_get_interfaces or #gvir_connection_get_interface after + * wards to query the fetched interfaces.
'afterwards' is a single word
+ * + * Return value: %TRUE on success, %FALSE otherwise and @err is set. + */ +gboolean gvir_connection_fetch_interfaces(GVirConnection *conn, + GCancellable *cancellable, + GError **err) +{ + GVirConnectionPrivate *priv; + GHashTable *interfaces; + virInterfacePtr *ifaces = NULL; + gint ninterfaces = 0; + gboolean ret = FALSE; + gint i; + virConnectPtr vconn = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable), + FALSE); + g_return_val_if_fail((err == NULL) || (*err == NULL), FALSE); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (!priv->conn) { + g_set_error_literal(err, GVIR_CONNECTION_ERROR, + 0, + _("Connection is not open")); + g_mutex_unlock(priv->lock); + goto cleanup; + } + vconn = priv->conn; + /* Stop another thread closing the connection just at the minute */ + virConnectRef(vconn); + g_mutex_unlock(priv->lock); + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + ninterfaces = virConnectListAllInterfaces(vconn, &ifaces, 0); + if (ninterfaces < 0) { + gvir_set_error(err, GVIR_CONNECTION_ERROR, + 0, + _("Failed to fetch list of interfaces")); + goto cleanup; + } + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + interfaces = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); + + for (i = 0 ; i < ninterfaces; i++) { + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + GVirInterface *iface; +
I'd put this before the cancellable check.
+ iface = GVIR_INTERFACE(g_object_new(GVIR_TYPE_INTERFACE, + "handle", ifaces[i], + NULL)); +
parameter alignment is off here
+ g_hash_table_insert(interfaces, + (gpointer)gvir_interface_get_name(iface), + iface); + } + + g_mutex_lock(priv->lock); + if (priv->interfaces) + g_hash_table_unref(priv->interfaces); + priv->interfaces = interfaces; + g_mutex_unlock(priv->lock); + + ret = TRUE; + +cleanup: + if (ninterfaces > 0) { + for (i = 0 ; i < ninterfaces; i++) + virInterfaceFree(ifaces[i]); + free(ifaces); + } + if (vconn != NULL) + virConnectClose(vconn); + return ret; +} + +static void +gvir_connection_fetch_interfaces_helper(GTask *res, + gpointer object, + gpointer task_data G_GNUC_UNUSED, + GCancellable *cancellable) +{ + GVirConnection *conn = GVIR_CONNECTION(object); + GError *err = NULL; + + if (!gvir_connection_fetch_interfaces(conn, cancellable, &err)) + g_task_return_error(res, err); + else + g_task_return_boolean(res, TRUE); +} + + +/** + * gvir_connection_fetch_interfaces_async: + * @conn: a #GVirConnection + * @cancellable: (allow-none)(transfer none): cancellation object + * @callback: (scope async): completion callback + * @user_data: (closure): opaque data for callback + */ +void gvir_connection_fetch_interfaces_async(GVirConnection *conn, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *res;
GTask *task; would be great
+ + g_return_if_fail(GVIR_IS_CONNECTION(conn)); + g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); + + res = g_task_new(G_OBJECT(conn), + cancellable, + callback, + user_data); + g_task_set_source_tag(res, + gvir_connection_fetch_interfaces_async);
Same comment as in the other patch regarding unneeded g_task_set_source_tag() (or adding a check in gvir_connection_fetch_interfaces_helper)
+ g_task_run_in_thread(res, + gvir_connection_fetch_interfaces_helper); + g_object_unref(res); +} + +/** + * gvir_connection_fetch_interfaces_finish: + * @conn: a #GVirConnection + * @result: (transfer none): async method result + * @err: return location for any errors + */ +gboolean gvir_connection_fetch_interfaces_finish(GVirConnection *conn, + GAsyncResult *result, + GError **err) +{ + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail(g_task_is_valid(result, G_OBJECT(conn)), + FALSE); + + return g_task_propagate_boolean(G_TASK(result), err); +} + +/** + * gvir_connection_get_interfaces: + * @conn: a #GVirConnection + * + * Gets a list of all the network interfaces managed by connection @conn on + * host machine.
I think most other documentation blocks in this patch use "Get a list" rather than "Gets a list"
+ * + * Return value: (element-type LibvirtGObject.Interface) (transfer full): List + * of #GVirInterface. The returned list should be freed with g_list_free(), + * after its elements have been unreffed with g_object_unref(). + */ +GList *gvir_connection_get_interfaces(GVirConnection *conn) +{ + GVirConnectionPrivate *priv; + GList *interfaces = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (priv->interfaces != NULL) { + interfaces = g_hash_table_get_values(priv->interfaces); + g_list_foreach(interfaces, gvir_domain_ref, NULL); + } + g_mutex_unlock(priv->lock); + + return interfaces; +} + +/** + * gvir_connection_get_interface: + * @conn: a #GVirConnection
+ * @name: interface name to lookup
+ * + * Get a particular interface which has name @name. + * + * Return value: (transfer full): A new reference to a #GVirInterface, or NULL + * if no interface exists with name @name. The returned object must be unreffed + * using g_object_unref() once used. + */ +GVirInterface *gvir_connection_get_interface(GVirConnection *conn, + const gchar *name) +{ + GVirConnectionPrivate *priv; + GVirInterface *iface; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(name != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + iface = g_hash_table_lookup(priv->interfaces, name); + if (iface) + g_object_ref(iface); + g_mutex_unlock(priv->lock); + + return iface; +} + +/** + * gvir_connection_find_interface_by_mac: + * @conn: a #GVirConnection
+ * @mac: MAC address to lookup
+ * + * Get a particular interface which has MAC address @mac. + * + * Return value: (transfer full): A new reference to a #GVirInterface, or NULL + * if no interface exists with MAC address @mac. The returned object must be + * unreffed using g_object_unref() once used. + */ +GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, + const gchar *mac) +{ + GVirConnectionPrivate *priv; + GHashTableIter iter; + gpointer key, value; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(mac != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + g_hash_table_iter_init(&iter, priv->interfaces); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + GVirInterface *iface = value; + const gchar *thismac = gvir_interface_get_mac(iface); + + if (g_strcmp0(thismac, mac) == 0) { + g_object_ref(iface); + g_mutex_unlock(priv->lock); + return iface; + } + } + g_mutex_unlock(priv->lock); + + return NULL; +} + +/** * gvir_connection_create_storage_pool: * @conn: a #GVirConnection on which to create the pool * @conf: the configuration for the new storage pool diff --git a/libvirt-gobject/libvirt-gobject-connection.h b/libvirt-gobject/libvirt-gobject-connection.h index 8bca8d4..0c22a58 100644 --- a/libvirt-gobject/libvirt-gobject-connection.h +++ b/libvirt-gobject/libvirt-gobject-connection.h @@ -144,14 +144,23 @@ GVirDomain *gvir_connection_start_domain(GVirConnection *conn, guint flags, GError **err);
-#if 0 +gboolean gvir_connection_fetch_interfaces(GVirConnection *conn, + GCancellable *cancellable, + GError **err); +void gvir_connection_fetch_interfaces_async(GVirConnection *conn, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean gvir_connection_fetch_interfaces_finish(GVirConnection *conn, + GAsyncResult *result, + GError **err); GList *gvir_connection_get_interfaces(GVirConnection *conn); GVirInterface *gvir_connection_get_interface(GVirConnection *conn, const gchar *name); GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, const gchar *macaddr);
- +#if 0 GList *gvir_connection_get_networks(GVirConnection *conn); GVirNetwork *gvir_connection_get_network(GVirConnection *conn, const gchar *uuid); diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 29c4349..1effcda 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -273,6 +273,13 @@ LIBVIRT_GOBJECT_0.2.1 {
LIBVIRT_GOBJECT_0.2.2 { global: + gvir_connection_fetch_interfaces; + gvir_connection_fetch_interfaces_async; + gvir_connection_fetch_interfaces_finish; + gvir_connection_find_interface_by_mac; + gvir_connection_get_interface; + gvir_connection_get_interfaces; + gvir_interface_get_mac; } LIBVIRT_GOBJECT_0.2.1;
All in all looks good apart from these minor comments, ACK.
-- 2.4.3
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

Add API to query networks from a connection. --- libvirt-gobject/libvirt-gobject-connection.c | 257 +++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-connection.h | 13 +- libvirt-gobject/libvirt-gobject.sym | 6 + 3 files changed, 274 insertions(+), 2 deletions(-) diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index 47b6861..a055a86 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -45,6 +45,7 @@ struct _GVirConnectionPrivate GHashTable *domains; GHashTable *pools; GHashTable *interfaces; + GHashTable *networks; }; G_DEFINE_TYPE(GVirConnection, gvir_connection, G_TYPE_OBJECT); @@ -257,6 +258,10 @@ static void gvir_connection_init(GVirConnection *conn) g_str_equal, NULL, g_object_unref); + priv->networks = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); } @@ -672,6 +677,11 @@ void gvir_connection_close(GVirConnection *conn) priv->interfaces = NULL; } + if (priv->networks) { + g_hash_table_unref(priv->networks); + priv->networks = NULL; + } + if (priv->conn) { virConnectDomainEventDeregister(priv->conn, domain_event_cb); virConnectClose(priv->conn); @@ -1696,6 +1706,253 @@ GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, } /** + * gvir_connection_fetch_networks: + * @conn: a #GVirConnection + * @cancellable: (allow-none)(transfer none): cancellation object + */ +gboolean gvir_connection_fetch_networks(GVirConnection *conn, + GCancellable *cancellable, + GError **err) +{ + GVirConnectionPrivate *priv; + GHashTable *networks; + virNetworkPtr *vnetworks = NULL; + gint nnetworks = 0; + gboolean ret = FALSE; + gint i; + virConnectPtr vconn = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable), + FALSE); + g_return_val_if_fail((err == NULL) || (*err == NULL), FALSE); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (!priv->conn) { + g_set_error_literal(err, GVIR_CONNECTION_ERROR, + 0, + _("Connection is not open")); + g_mutex_unlock(priv->lock); + goto cleanup; + } + vconn = priv->conn; + /* Stop another thread closing the connection just at the minute */ + virConnectRef(vconn); + g_mutex_unlock(priv->lock); + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + nnetworks = virConnectListAllNetworks(vconn, &vnetworks, 0); + if (nnetworks < 0) { + gvir_set_error(err, GVIR_CONNECTION_ERROR, + 0, + _("Failed to fetch list of networks")); + goto cleanup; + } + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + networks = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); + + for (i = 0 ; i < nnetworks; i++) { + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + GVirNetwork *network; + + network = GVIR_NETWORK(g_object_new(GVIR_TYPE_NETWORK, + "handle", vnetworks[i], + NULL)); + g_hash_table_insert(networks, + (gpointer)gvir_network_get_uuid(network), + network); + } + + g_mutex_lock(priv->lock); + if (priv->networks) + g_hash_table_unref(priv->networks); + priv->networks = networks; + g_mutex_unlock(priv->lock); + + ret = TRUE; + +cleanup: + if (nnetworks > 0) { + for (i = 0 ; i < nnetworks; i++) + virNetworkFree(vnetworks[i]); + free(vnetworks); + } + if (vconn != NULL) + virConnectClose(vconn); + return ret; +} + +static void +gvir_connection_fetch_networks_helper(GTask *res, + gpointer object, + gpointer task_data G_GNUC_UNUSED, + GCancellable *cancellable) +{ + GVirConnection *conn = GVIR_CONNECTION(object); + GError *err = NULL; + + if (!gvir_connection_fetch_networks(conn, cancellable, &err)) + g_task_return_error(res, err); + else + g_task_return_boolean(res, TRUE); +} + +/** + * gvir_connection_fetch_networks_async: + * @conn: a #GVirConnection + * @cancellable: (allow-none)(transfer none): cancellation object + * @callback: (scope async): completion callback + * @user_data: (closure): opaque data for callback + */ +void gvir_connection_fetch_networks_async(GVirConnection *conn, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *res; + + g_return_if_fail(GVIR_IS_CONNECTION(conn)); + g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); + + res = g_task_new(G_OBJECT(conn), + cancellable, + callback, + user_data); + g_task_set_source_tag(res, + gvir_connection_fetch_networks_async); + g_task_run_in_thread(res, + gvir_connection_fetch_networks_helper); + g_object_unref(res); +} + +/** + * gvir_connection_fetch_networks_finish: + * @conn: a #GVirConnection + * @result: (transfer none): async method result + * @err: return location for any errors + */ +gboolean gvir_connection_fetch_networks_finish(GVirConnection *conn, + GAsyncResult *result, + GError **err) +{ + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail(g_task_is_valid(result, G_OBJECT(conn)), + FALSE); + + return g_task_propagate_boolean(G_TASK(result), err); +} + +/** + * gvir_connection_get_networks: + * @conn: a #GVirConnection + * + * Gets a list of all the network networks available through @conn. + * + * Return value: (element-type LibvirtGObject.Network) (transfer full): List + * of #GVirNetwork. The returned list should be freed with g_list_free(), + * after its elements have been unreffed with g_object_unref(). + */ +GList *gvir_connection_get_networks(GVirConnection *conn) +{ + GVirConnectionPrivate *priv; + GList *networks = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (priv->networks != NULL) { + networks = g_hash_table_get_values(priv->networks); + g_list_foreach(networks, gvir_domain_ref, NULL); + } + g_mutex_unlock(priv->lock); + + return networks; +} + +/** + * gvir_connection_get_network: + * @conn: a #GVirConnection + * + * Get a particular network which has UUID @uuid. + * + * Return value: (transfer full): A new reference to a #GVirNetwork, or NULL if + * no network exists with UUID @uuid. The returned object must be unreffed using + * g_object_unref() once used. + */ +GVirNetwork *gvir_connection_get_network(GVirConnection *conn, + const gchar *uuid) +{ + GVirConnectionPrivate *priv; + GVirNetwork *network; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(uuid != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + network = g_hash_table_lookup(priv->networks, uuid); + if (network) + g_object_ref(network); + g_mutex_unlock(priv->lock); + + return network; +} + +/** + * gvir_connection_find_network_by_name: + * @conn: a #GVirConnection + * + * Get a particular network which has name @name. + * + * Return value: (transfer full): A new reference to a #GVirNetwork, or NULL if + * no network exists with name @name. The returned object must be unreffed using + * g_object_unref() once used. + */ +GVirNetwork *gvir_connection_find_network_by_name(GVirConnection *conn, + const gchar *name) +{ + GVirConnectionPrivate *priv; + GHashTableIter iter; + gpointer key, value; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(name != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + g_hash_table_iter_init(&iter, priv->networks); + + while (g_hash_table_iter_next(&iter, &key, &value)) { + GVirNetwork *network = value; + const gchar *thisname = gvir_network_get_name(network); + + if (thisname == NULL) + continue; + + if (strcmp(thisname, name) == 0) { + g_object_ref(network); + g_mutex_unlock(priv->lock); + return network; + } + } + g_mutex_unlock(priv->lock); + + return NULL; +} + +/** * gvir_connection_create_storage_pool: * @conn: a #GVirConnection on which to create the pool * @conf: the configuration for the new storage pool diff --git a/libvirt-gobject/libvirt-gobject-connection.h b/libvirt-gobject/libvirt-gobject-connection.h index 0c22a58..f3d2cb8 100644 --- a/libvirt-gobject/libvirt-gobject-connection.h +++ b/libvirt-gobject/libvirt-gobject-connection.h @@ -160,14 +160,23 @@ GVirInterface *gvir_connection_get_interface(GVirConnection *conn, GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, const gchar *macaddr); -#if 0 +gboolean gvir_connection_fetch_networks(GVirConnection *conn, + GCancellable *cancellable, + GError **err); +void gvir_connection_fetch_networks_async(GVirConnection *conn, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean gvir_connection_fetch_networks_finish(GVirConnection *conn, + GAsyncResult *result, + GError **err); GList *gvir_connection_get_networks(GVirConnection *conn); GVirNetwork *gvir_connection_get_network(GVirConnection *conn, const gchar *uuid); GVirNetwork *gvir_connection_find_network_by_name(GVirConnection *conn, const gchar *name); - +#if 0 GList *gvir_connection_get_network_filters(GVirConnection *conn); GVirNetworkFilter *gvir_connection_get_network_filter(GVirConnection *conn, const gchar *uuid); diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 1effcda..88ca271 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -276,9 +276,15 @@ LIBVIRT_GOBJECT_0.2.2 { gvir_connection_fetch_interfaces; gvir_connection_fetch_interfaces_async; gvir_connection_fetch_interfaces_finish; + gvir_connection_fetch_networks; + gvir_connection_fetch_networks_async; + gvir_connection_fetch_networks_finish; gvir_connection_find_interface_by_mac; + gvir_connection_find_network_by_name; gvir_connection_get_interface; gvir_connection_get_interfaces; + gvir_connection_get_network; + gvir_connection_get_networks; gvir_interface_get_mac; } LIBVIRT_GOBJECT_0.2.1; -- 2.4.3

On Wed, Jul 01, 2015 at 09:40:49PM +0100, Zeeshan Ali (Khattak) wrote:
Add API to query networks from a connection. --- libvirt-gobject/libvirt-gobject-connection.c | 257 +++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-connection.h | 13 +- libvirt-gobject/libvirt-gobject.sym | 6 + 3 files changed, 274 insertions(+), 2 deletions(-)
diff --git a/libvirt-gobject/libvirt-gobject-connection.c b/libvirt-gobject/libvirt-gobject-connection.c index 47b6861..a055a86 100644 --- a/libvirt-gobject/libvirt-gobject-connection.c +++ b/libvirt-gobject/libvirt-gobject-connection.c @@ -45,6 +45,7 @@ struct _GVirConnectionPrivate GHashTable *domains; GHashTable *pools; GHashTable *interfaces; + GHashTable *networks; };
G_DEFINE_TYPE(GVirConnection, gvir_connection, G_TYPE_OBJECT); @@ -257,6 +258,10 @@ static void gvir_connection_init(GVirConnection *conn) g_str_equal, NULL, g_object_unref); + priv->networks = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); }
@@ -672,6 +677,11 @@ void gvir_connection_close(GVirConnection *conn) priv->interfaces = NULL; }
+ if (priv->networks) { + g_hash_table_unref(priv->networks); + priv->networks = NULL; + } + if (priv->conn) { virConnectDomainEventDeregister(priv->conn, domain_event_cb); virConnectClose(priv->conn); @@ -1696,6 +1706,253 @@ GVirInterface *gvir_connection_find_interface_by_mac(GVirConnection *conn, }
/** + * gvir_connection_fetch_networks: + * @conn: a #GVirConnection + * @cancellable: (allow-none)(transfer none): cancellation object + */ +gboolean gvir_connection_fetch_networks(GVirConnection *conn, + GCancellable *cancellable, + GError **err) +{ + GVirConnectionPrivate *priv; + GHashTable *networks; + virNetworkPtr *vnetworks = NULL; + gint nnetworks = 0; + gboolean ret = FALSE; + gint i; + virConnectPtr vconn = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable), + FALSE); + g_return_val_if_fail((err == NULL) || (*err == NULL), FALSE); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (!priv->conn) { + g_set_error_literal(err, GVIR_CONNECTION_ERROR, + 0, + _("Connection is not open")); + g_mutex_unlock(priv->lock); + goto cleanup; + } + vconn = priv->conn; + /* Stop another thread closing the connection just at the minute */ + virConnectRef(vconn); + g_mutex_unlock(priv->lock); + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + nnetworks = virConnectListAllNetworks(vconn, &vnetworks, 0); + if (nnetworks < 0) { + gvir_set_error(err, GVIR_CONNECTION_ERROR, + 0, + _("Failed to fetch list of networks")); + goto cleanup; + } + + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + networks = g_hash_table_new_full(g_str_hash, + g_str_equal, + NULL, + g_object_unref); + + for (i = 0 ; i < nnetworks; i++) { + if (g_cancellable_set_error_if_cancelled(cancellable, err)) + goto cleanup; + + GVirNetwork *network; + + network = GVIR_NETWORK(g_object_new(GVIR_TYPE_NETWORK, + "handle", vnetworks[i], + NULL)); + g_hash_table_insert(networks, + (gpointer)gvir_network_get_uuid(network), + network); + } + + g_mutex_lock(priv->lock); + if (priv->networks) + g_hash_table_unref(priv->networks); + priv->networks = networks; + g_mutex_unlock(priv->lock); + + ret = TRUE; + +cleanup: + if (nnetworks > 0) { + for (i = 0 ; i < nnetworks; i++) + virNetworkFree(vnetworks[i]); + free(vnetworks); + } + if (vconn != NULL) + virConnectClose(vconn); + return ret; +} + +static void +gvir_connection_fetch_networks_helper(GTask *res, + gpointer object, + gpointer task_data G_GNUC_UNUSED, + GCancellable *cancellable) +{ + GVirConnection *conn = GVIR_CONNECTION(object); + GError *err = NULL; + + if (!gvir_connection_fetch_networks(conn, cancellable, &err)) + g_task_return_error(res, err); + else + g_task_return_boolean(res, TRUE); +} + +/** + * gvir_connection_fetch_networks_async: + * @conn: a #GVirConnection + * @cancellable: (allow-none)(transfer none): cancellation object + * @callback: (scope async): completion callback + * @user_data: (closure): opaque data for callback + */ +void gvir_connection_fetch_networks_async(GVirConnection *conn, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *res; + + g_return_if_fail(GVIR_IS_CONNECTION(conn)); + g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable)); + + res = g_task_new(G_OBJECT(conn), + cancellable, + callback, + user_data); + g_task_set_source_tag(res, + gvir_connection_fetch_networks_async); + g_task_run_in_thread(res, + gvir_connection_fetch_networks_helper); + g_object_unref(res); +} + +/** + * gvir_connection_fetch_networks_finish: + * @conn: a #GVirConnection + * @result: (transfer none): async method result + * @err: return location for any errors + */ +gboolean gvir_connection_fetch_networks_finish(GVirConnection *conn, + GAsyncResult *result, + GError **err) +{ + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), FALSE); + g_return_val_if_fail(g_task_is_valid(result, G_OBJECT(conn)), + FALSE); + + return g_task_propagate_boolean(G_TASK(result), err); +} + +/** + * gvir_connection_get_networks: + * @conn: a #GVirConnection + * + * Gets a list of all the network networks available through @conn. + * + * Return value: (element-type LibvirtGObject.Network) (transfer full): List + * of #GVirNetwork. The returned list should be freed with g_list_free(), + * after its elements have been unreffed with g_object_unref(). + */ +GList *gvir_connection_get_networks(GVirConnection *conn) +{ + GVirConnectionPrivate *priv; + GList *networks = NULL; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + if (priv->networks != NULL) { + networks = g_hash_table_get_values(priv->networks); + g_list_foreach(networks, gvir_domain_ref, NULL); + } + g_mutex_unlock(priv->lock); + + return networks; +} + +/** + * gvir_connection_get_network: + * @conn: a #GVirConnection
+ * @uuid: UUID of the network to lookup
+ * + * Get a particular network which has UUID @uuid. + * + * Return value: (transfer full): A new reference to a #GVirNetwork, or NULL if + * no network exists with UUID @uuid. The returned object must be unreffed using + * g_object_unref() once used. + */ +GVirNetwork *gvir_connection_get_network(GVirConnection *conn, + const gchar *uuid) +{ + GVirConnectionPrivate *priv; + GVirNetwork *network; + + g_return_val_if_fail(GVIR_IS_CONNECTION(conn), NULL); + g_return_val_if_fail(uuid != NULL, NULL); + + priv = conn->priv; + g_mutex_lock(priv->lock); + network = g_hash_table_lookup(priv->networks, uuid); + if (network) + g_object_ref(network); + g_mutex_unlock(priv->lock); + + return network; +} + +/** + * gvir_connection_find_network_by_name: + * @conn: a #GVirConnection
+ * @name: name of the network to search for Same minor comments as in the previous patch apply here, looks all good otherwise. Christophe

--- libvirt-gobject/Makefile.am | 5 +- .../libvirt-gobject-network-dhcp-lease-private.h | 34 +++ .../libvirt-gobject-network-dhcp-lease.c | 252 +++++++++++++++++++++ .../libvirt-gobject-network-dhcp-lease.h | 85 +++++++ libvirt-gobject/libvirt-gobject.h | 1 + libvirt-gobject/libvirt-gobject.sym | 13 ++ 6 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h create mode 100644 libvirt-gobject/libvirt-gobject-network-dhcp-lease.c create mode 100644 libvirt-gobject/libvirt-gobject-network-dhcp-lease.h diff --git a/libvirt-gobject/Makefile.am b/libvirt-gobject/Makefile.am index 7163c7d..8464f04 100644 --- a/libvirt-gobject/Makefile.am +++ b/libvirt-gobject/Makefile.am @@ -13,6 +13,7 @@ GOBJECT_HEADER_FILES = \ libvirt-gobject-domain.h \ libvirt-gobject-interface.h \ libvirt-gobject-network.h \ + libvirt-gobject-network-dhcp-lease.h \ libvirt-gobject-network-filter.h \ libvirt-gobject-node-device.h \ libvirt-gobject-secret.h \ @@ -22,7 +23,8 @@ GOBJECT_HEADER_FILES = \ libvirt-gobject-connection.h \ libvirt-gobject-manager.h noinst_HEADERS = \ - libvirt-gobject-storage-pool-private.h + libvirt-gobject-storage-pool-private.h \ + libvirt-gobject-network-dhcp-lease-private.h GOBJECT_SOURCE_FILES = \ libvirt-gobject-main.c \ libvirt-gobject-domain-snapshot.c \ @@ -32,6 +34,7 @@ GOBJECT_SOURCE_FILES = \ libvirt-gobject-domain.c \ libvirt-gobject-interface.c \ libvirt-gobject-network.c \ + libvirt-gobject-network-dhcp-lease.c \ libvirt-gobject-network-filter.c \ libvirt-gobject-node-device.c \ libvirt-gobject-secret.c \ diff --git a/libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h b/libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h new file mode 100644 index 0000000..eaf6c2f --- /dev/null +++ b/libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h @@ -0,0 +1,34 @@ +/* + * libvirt-gobject-network-dhcp-lease-private.h: libvirt gobject integration + * + * Copyright (C) 2010-2011 Red Hat, Inc. + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_PRIVATE_H__ +#define __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_PRIVATE_H__ + +G_BEGIN_DECLS + +GVirNetworkDHCPLease *gvir_network_dhcp_lease_new(virNetworkDHCPLeasePtr handle); + +G_END_DECLS + +#endif /* __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_PRIVATE_H__ */ diff --git a/libvirt-gobject/libvirt-gobject-network-dhcp-lease.c b/libvirt-gobject/libvirt-gobject-network-dhcp-lease.c new file mode 100644 index 0000000..b284453 --- /dev/null +++ b/libvirt-gobject/libvirt-gobject-network-dhcp-lease.c @@ -0,0 +1,252 @@ +/* + * libvirt-gobject-network-dhcp-lease.c: libvirt glib integration + * + * Copyright (C) 2008 Daniel P. Berrange + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include <libvirt/virterror.h> +#include <string.h> + +#include "libvirt-glib/libvirt-glib.h" +#include "libvirt-gobject/libvirt-gobject.h" +#include "libvirt-gobject-compat.h" +#include "libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h" + +#define GVIR_NETWORK_DHCP_LEASE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_TYPE_NETWORK_DHCP_LEASE, GVirNetworkDHCPLeasePrivate)) + +struct _GVirNetworkDHCPLeasePrivate +{ + virNetworkDHCPLeasePtr handle; +}; + +G_DEFINE_TYPE(GVirNetworkDHCPLease, gvir_network_dhcp_lease, G_TYPE_OBJECT); + +enum { + PROP_0, + PROP_HANDLE, +}; + +static void gvir_network_dhcp_lease_get_property(GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GVirNetworkDHCPLease *lease = GVIR_NETWORK_DHCP_LEASE(object); + GVirNetworkDHCPLeasePrivate *priv = lease->priv; + + switch (prop_id) { + case PROP_HANDLE: + g_value_set_pointer(value, priv->handle); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static void gvir_network_dhcp_lease_set_property(GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GVirNetworkDHCPLease *lease = GVIR_NETWORK_DHCP_LEASE(object); + GVirNetworkDHCPLeasePrivate *priv = lease->priv; + + switch (prop_id) { + case PROP_HANDLE: + if (priv->handle) + virNetworkDHCPLeaseFree(priv->handle); + priv->handle = g_value_get_pointer(value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + + +static void gvir_network_dhcp_lease_finalize(GObject *object) +{ + GVirNetworkDHCPLease *lease = GVIR_NETWORK_DHCP_LEASE(object); + GVirNetworkDHCPLeasePrivate *priv = lease->priv; + + g_debug("Finalize GVirNetworkDHCPLease=%p", lease); + + virNetworkDHCPLeaseFree(priv->handle); + + G_OBJECT_CLASS(gvir_network_dhcp_lease_parent_class)->finalize(object); +} + +static void gvir_network_dhcp_lease_class_init(GVirNetworkDHCPLeaseClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gvir_network_dhcp_lease_finalize; + object_class->get_property = gvir_network_dhcp_lease_get_property; + object_class->set_property = gvir_network_dhcp_lease_set_property; + + g_object_class_install_property(object_class, + PROP_HANDLE, + g_param_spec_pointer("handle", + "Handle", + "The lease handle", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_PRIVATE | + G_PARAM_STATIC_STRINGS)); + + g_type_class_add_private(klass, sizeof(GVirNetworkDHCPLeasePrivate)); +} + + +static void gvir_network_dhcp_lease_init(GVirNetworkDHCPLease *lease) +{ + g_debug("Init GVirNetworkDHCPLease=%p", lease); + + lease->priv = GVIR_NETWORK_DHCP_LEASE_GET_PRIVATE(lease); +} + +GVirNetworkDHCPLease *gvir_network_dhcp_lease_new(virNetworkDHCPLeasePtr handle) +{ + return g_object_new(GVIR_TYPE_NETWORK_DHCP_LEASE, + "handle", handle, + NULL); +} + +/** + * gvir_network_dhcp_lease_get_iface: + * @lease: the lease + * + * Returns: (transfer none): The network interface name. + */ +const gchar *gvir_network_dhcp_lease_get_iface(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->iface; +} + +/** + * gvir_network_dhcp_lease_get_expirytime: + * @lease: the lease + * + * Returns: The expiry time of this lease, as seconds since epoch. + */ +gint64 gvir_network_dhcp_lease_get_expirytime(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), -1); + + return lease->priv->handle->expirytime; +} + +/** + * gvir_network_dhcp_lease_get_ip_type: + * @lease: the lease + * + * Returns: The type of IP, see %GVirIPAddrType for possible values. + */ +gint gvir_network_dhcp_lease_get_ip_type(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), -1); + + return lease->priv->handle->type; +} + +/** + * gvir_network_dhcp_lease_get_mac: + * @lease: the lease + * + * Returns: (transfer none): The MAC address. + */ +const gchar *gvir_network_dhcp_lease_get_mac(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->mac; +} + +/** + * gvir_network_dhcp_lease_get_iaid: + * @lease: the lease + * + * Returns: (transfer none): The IAID. + */ +const gchar *gvir_network_dhcp_lease_get_iaid(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->iaid; +} + +/** + * gvir_network_dhcp_lease_get_ip: + * @lease: the lease + * + * Returns: (transfer none): The IP address. + */ +const gchar *gvir_network_dhcp_lease_get_ip(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->ipaddr; +} + +/** + * gvir_network_dhcp_lease_get_prefix: + * @lease: the lease + * + * Returns: The number of network address bits in the IP address. + */ +guint gvir_network_dhcp_lease_get_prefix(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), 0); + + return lease->priv->handle->prefix; +} + +/** + * gvir_network_dhcp_lease_get_hostname: + * @lease: the lease + * + * Returns: (transfer none): The hostname. + */ +const gchar *gvir_network_dhcp_lease_get_hostname(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->hostname; +} + +/** + * gvir_network_dhcp_lease_get_clientid: + * @lease: the lease + * + * Returns: (transfer none): The client ID or DUID. + */ +const gchar *gvir_network_dhcp_lease_get_clientid(GVirNetworkDHCPLease *lease) +{ + g_return_val_if_fail(GVIR_IS_NETWORK_DHCP_LEASE(lease), NULL); + + return lease->priv->handle->clientid; +} diff --git a/libvirt-gobject/libvirt-gobject-network-dhcp-lease.h b/libvirt-gobject/libvirt-gobject-network-dhcp-lease.h new file mode 100644 index 0000000..83f7da9 --- /dev/null +++ b/libvirt-gobject/libvirt-gobject-network-dhcp-lease.h @@ -0,0 +1,85 @@ +/* + * libvirt-gobject-network-dhcp-lease.h: libvirt gobject integration + * + * Copyright (C) 2010-2011 Red Hat, Inc. + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + * Daniel P. Berrange <berrange@redhat.com> + */ + +#if !defined(__LIBVIRT_GOBJECT_H__) && !defined(LIBVIRT_GOBJECT_BUILD) +#error "Only <libvirt-gobject/libvirt-gobject.h> can be included directly." +#endif + +#ifndef __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_H__ +#define __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_H__ + +G_BEGIN_DECLS + +/** + * GVirIPAddrType: + * @GVIR_IP_ADDR_TYPE_IPV4: IPv4 Address. + * @GVIR_IP_ADDR_TYPE_IPV6: IPv6 Address. + */ +typedef enum { + GVIR_IP_ADDR_TYPE_IPV4 = 0, + GVIR_IP_ADDR_TYPE_IPV6 = 1 +} GVirIPAddrType; + +#define GVIR_TYPE_NETWORK_DHCP_LEASE (gvir_network_dhcp_lease_get_type ()) +#define GVIR_NETWORK_DHCP_LEASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GVIR_TYPE_NETWORK_DHCP_LEASE, GVirNetworkDHCPLease)) +#define GVIR_NETWORK_DHCP_LEASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GVIR_TYPE_NETWORK_DHCP_LEASE, GVirNetworkDHCPLeaseClass)) +#define GVIR_IS_NETWORK_DHCP_LEASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GVIR_TYPE_NETWORK_DHCP_LEASE)) +#define GVIR_IS_NETWORK_DHCP_LEASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GVIR_TYPE_NETWORK_DHCP_LEASE)) +#define GVIR_NETWORK_DHCP_LEASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GVIR_TYPE_NETWORK_DHCP_LEASE, GVirNetworkDHCPLeaseClass)) + +typedef struct _GVirNetworkDHCPLease GVirNetworkDHCPLease; +typedef struct _GVirNetworkDHCPLeasePrivate GVirNetworkDHCPLeasePrivate; +typedef struct _GVirNetworkDHCPLeaseClass GVirNetworkDHCPLeaseClass; + +struct _GVirNetworkDHCPLease +{ + GObject parent; + + GVirNetworkDHCPLeasePrivate *priv; + + /* Do not add fields to this struct */ +}; + +struct _GVirNetworkDHCPLeaseClass +{ + GObjectClass parent_class; + + gpointer padding[7]; +}; + +GType gvir_network_dhcp_lease_get_type(void); + +const gchar *gvir_network_dhcp_lease_get_iface(GVirNetworkDHCPLease *lease); +gint64 gvir_network_dhcp_lease_get_expirytime(GVirNetworkDHCPLease *lease); +gint gvir_network_dhcp_lease_get_ip_type(GVirNetworkDHCPLease *lease); +const gchar *gvir_network_dhcp_lease_get_mac(GVirNetworkDHCPLease *lease); +const gchar *gvir_network_dhcp_lease_get_iaid(GVirNetworkDHCPLease *lease); +const gchar *gvir_network_dhcp_lease_get_ip(GVirNetworkDHCPLease *lease); +guint gvir_network_dhcp_lease_get_prefix(GVirNetworkDHCPLease *lease); +const gchar *gvir_network_dhcp_lease_get_hostname(GVirNetworkDHCPLease *lease); +const gchar *gvir_network_dhcp_lease_get_clientid(GVirNetworkDHCPLease *lease); + +G_END_DECLS + +#endif /* __LIBVIRT_GOBJECT_NETWORK_DHCP_LEASE_H__ */ diff --git a/libvirt-gobject/libvirt-gobject.h b/libvirt-gobject/libvirt-gobject.h index 2b95070..d542482 100644 --- a/libvirt-gobject/libvirt-gobject.h +++ b/libvirt-gobject/libvirt-gobject.h @@ -37,6 +37,7 @@ #include <libvirt-gobject/libvirt-gobject-domain.h> #include <libvirt-gobject/libvirt-gobject-interface.h> #include <libvirt-gobject/libvirt-gobject-network.h> +#include <libvirt-gobject/libvirt-gobject-network-dhcp-lease.h> #include <libvirt-gobject/libvirt-gobject-network-filter.h> #include <libvirt-gobject/libvirt-gobject-node-device.h> #include <libvirt-gobject/libvirt-gobject-secret.h> diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 88ca271..d345813 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -287,6 +287,19 @@ LIBVIRT_GOBJECT_0.2.2 { gvir_connection_get_networks; gvir_interface_get_mac; + + gvir_ip_addr_type_get_type; + + gvir_network_dhcp_lease_get_clientid; + gvir_network_dhcp_lease_get_expirytime; + gvir_network_dhcp_lease_get_hostname; + gvir_network_dhcp_lease_get_iaid; + gvir_network_dhcp_lease_get_iface; + gvir_network_dhcp_lease_get_ip; + gvir_network_dhcp_lease_get_ip_type; + gvir_network_dhcp_lease_get_mac; + gvir_network_dhcp_lease_get_prefix; + gvir_network_dhcp_lease_get_type; } LIBVIRT_GOBJECT_0.2.1; # .... define new API here using predicted next version number .... -- 2.4.3

On Wed, Jul 01, 2015 at 09:40:50PM +0100, Zeeshan Ali (Khattak) wrote:
diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index 88ca271..d345813 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -287,6 +287,19 @@ LIBVIRT_GOBJECT_0.2.2 { gvir_connection_get_networks;
gvir_interface_get_mac; + + gvir_ip_addr_type_get_type; + + gvir_network_dhcp_lease_get_clientid; + gvir_network_dhcp_lease_get_expirytime; + gvir_network_dhcp_lease_get_hostname; + gvir_network_dhcp_lease_get_iaid; + gvir_network_dhcp_lease_get_iface; + gvir_network_dhcp_lease_get_ip; + gvir_network_dhcp_lease_get_ip_type; + gvir_network_dhcp_lease_get_mac; + gvir_network_dhcp_lease_get_prefix; + gvir_network_dhcp_lease_get_type;
What about the second paragraph from https://www.redhat.com/archives/libvir-list/2015-June/msg01649.html: « [snip] Just realized now, but wouldn't we be better off with gvir_network_dhcp_lease_get_client_id; gvir_network_dhcp_lease_get_expiry_time; instead of gvir_network_dhcp_lease_get_clientid; gvir_network_dhcp_lease_get_expirytime; » Christophe

--- libvirt-gobject/libvirt-gobject-network.c | 54 +++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-network.h | 4 +++ libvirt-gobject/libvirt-gobject.sym | 2 ++ 3 files changed, 60 insertions(+) diff --git a/libvirt-gobject/libvirt-gobject-network.c b/libvirt-gobject/libvirt-gobject-network.c index b1b38a0..b29be36 100644 --- a/libvirt-gobject/libvirt-gobject-network.c +++ b/libvirt-gobject/libvirt-gobject-network.c @@ -29,6 +29,7 @@ #include "libvirt-glib/libvirt-glib.h" #include "libvirt-gobject/libvirt-gobject.h" #include "libvirt-gobject-compat.h" +#include "libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h" #define GVIR_NETWORK_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_TYPE_NETWORK, GVirNetworkPrivate)) @@ -224,3 +225,56 @@ GVirConfigNetwork *gvir_network_get_config(GVirNetwork *network, free(xml); return conf; } + +/** + * gvir_network_get_dhcp_leases: + * @network: the network + * @mac: (allow-none): The optional ASCII formatted MAC address of an interface + * @flags: placeholder for flags, pass 0 + * + * @err: Place-holder for possible errors + * + * This function fetches leases info of guests in the specified network. If the + * optional parameter @mac is specified, the returned list will contain only + * lease info about a specific guest interface with @mac. There can be multiple + * leases for a single @mac because this API supports DHCPv6 too. + * + * Returns: (element-type LibvirtGObject.NetworkDHCPLease) (transfer full): the + * list of network leases. Each object in the returned list should be unreffed + * with g_object_unref() and the list itself using g_list_free, when no longer + * needed. + */ +GList *gvir_network_get_dhcp_leases(GVirNetwork *network, + const char* mac, + guint flags, + GError **err) +{ + virNetworkDHCPLeasePtr *leases; + GList *ret = NULL; + int num_leases, i; + + g_return_val_if_fail(GVIR_IS_NETWORK(network), NULL); + g_return_val_if_fail(err == NULL || *err == NULL, NULL); + + num_leases = virNetworkGetDHCPLeases(network->priv->handle, mac, &leases, flags); + if (num_leases < 0) { + gvir_set_error_literal(err, GVIR_NETWORK_ERROR, + 0, + "Unable to get network DHCP leases"); + return NULL; + } + + if (num_leases == 0) + return NULL; + + for (i = 0; i < num_leases; i++) { + GVirNetworkDHCPLease *lease; + + lease = gvir_network_dhcp_lease_new(leases[i]); + ret = g_list_prepend(ret, lease); + } + ret = g_list_reverse(ret); + free(leases); + + return ret; +} diff --git a/libvirt-gobject/libvirt-gobject-network.h b/libvirt-gobject/libvirt-gobject-network.h index 9f746c0..5617ed6 100644 --- a/libvirt-gobject/libvirt-gobject-network.h +++ b/libvirt-gobject/libvirt-gobject-network.h @@ -71,6 +71,10 @@ const gchar *gvir_network_get_uuid(GVirNetwork *network); GVirConfigNetwork *gvir_network_get_config(GVirNetwork *network, guint flags, GError **err); +GList *gvir_network_get_dhcp_leases(GVirNetwork *network, + const char* mac, + guint flags, + GError **err); G_END_DECLS diff --git a/libvirt-gobject/libvirt-gobject.sym b/libvirt-gobject/libvirt-gobject.sym index d345813..13f35e5 100644 --- a/libvirt-gobject/libvirt-gobject.sym +++ b/libvirt-gobject/libvirt-gobject.sym @@ -300,6 +300,8 @@ LIBVIRT_GOBJECT_0.2.2 { gvir_network_dhcp_lease_get_mac; gvir_network_dhcp_lease_get_prefix; gvir_network_dhcp_lease_get_type; + + gvir_network_get_dhcp_leases; } LIBVIRT_GOBJECT_0.2.1; # .... define new API here using predicted next version number .... -- 2.4.3

On Wed, Jul 01, 2015 at 09:40:51PM +0100, Zeeshan Ali (Khattak) wrote:
--- libvirt-gobject/libvirt-gobject-network.c | 54 +++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-network.h | 4 +++ libvirt-gobject/libvirt-gobject.sym | 2 ++ 3 files changed, 60 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-network.c b/libvirt-gobject/libvirt-gobject-network.c index b1b38a0..b29be36 100644 --- a/libvirt-gobject/libvirt-gobject-network.c +++ b/libvirt-gobject/libvirt-gobject-network.c @@ -29,6 +29,7 @@ #include "libvirt-glib/libvirt-glib.h" #include "libvirt-gobject/libvirt-gobject.h" #include "libvirt-gobject-compat.h" +#include "libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h"
#define GVIR_NETWORK_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_TYPE_NETWORK, GVirNetworkPrivate)) @@ -224,3 +225,56 @@ GVirConfigNetwork *gvir_network_get_config(GVirNetwork *network, free(xml); return conf; } + +/** + * gvir_network_get_dhcp_leases: + * @network: the network + * @mac: (allow-none): The optional ASCII formatted MAC address of an interface + * @flags: placeholder for flags, pass 0
"must be 0" rather than "pass 0" ?
+ * + * @err: Place-holder for possible errors + * + * This function fetches leases info of guests in the specified network. If the + * optional parameter @mac is specified, the returned list will contain only + * lease info about a specific guest interface with @mac. There can be multiple + * leases for a single @mac because this API supports DHCPv6 too. + * + * Returns: (element-type LibvirtGObject.NetworkDHCPLease) (transfer full): the + * list of network leases. Each object in the returned list should be unreffed + * with g_object_unref() and the list itself using g_list_free, when no longer + * needed. + */ +GList *gvir_network_get_dhcp_leases(GVirNetwork *network, + const char* mac, + guint flags, + GError **err) +{ + virNetworkDHCPLeasePtr *leases; + GList *ret = NULL; + int num_leases, i; + + g_return_val_if_fail(GVIR_IS_NETWORK(network), NULL); + g_return_val_if_fail(err == NULL || *err == NULL, NULL);
I'd add a g_return_val_if_fail(flags != 0, NULL); ACK. Christophe

On Mon, Jul 6, 2015 at 6:05 PM, Christophe Fergeau <cfergeau@redhat.com> wrote:
On Wed, Jul 01, 2015 at 09:40:51PM +0100, Zeeshan Ali (Khattak) wrote:
--- libvirt-gobject/libvirt-gobject-network.c | 54 +++++++++++++++++++++++++++++++ libvirt-gobject/libvirt-gobject-network.h | 4 +++ libvirt-gobject/libvirt-gobject.sym | 2 ++ 3 files changed, 60 insertions(+)
diff --git a/libvirt-gobject/libvirt-gobject-network.c b/libvirt-gobject/libvirt-gobject-network.c index b1b38a0..b29be36 100644 --- a/libvirt-gobject/libvirt-gobject-network.c +++ b/libvirt-gobject/libvirt-gobject-network.c @@ -29,6 +29,7 @@ #include "libvirt-glib/libvirt-glib.h" #include "libvirt-gobject/libvirt-gobject.h" #include "libvirt-gobject-compat.h" +#include "libvirt-gobject/libvirt-gobject-network-dhcp-lease-private.h"
#define GVIR_NETWORK_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), GVIR_TYPE_NETWORK, GVirNetworkPrivate)) @@ -224,3 +225,56 @@ GVirConfigNetwork *gvir_network_get_config(GVirNetwork *network, free(xml); return conf; } + +/** + * gvir_network_get_dhcp_leases: + * @network: the network + * @mac: (allow-none): The optional ASCII formatted MAC address of an interface + * @flags: placeholder for flags, pass 0
"must be 0" rather than "pass 0" ?
I just copy&pasted from another place in code. :) -- Regards, Zeeshan Ali (Khattak) ________________________________________ Befriend GNOME: http://www.gnome.org/friends/
participants (2)
-
Christophe Fergeau
-
Zeeshan Ali (Khattak)