All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/8] io: enable DNS resolving separately of socket create
@ 2017-01-09 15:39 Daniel P. Berrange
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 1/8] sockets: add ability to disable DNS resolution for InetSocketAddress Daniel P. Berrange
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: Daniel P. Berrange @ 2017-01-09 15:39 UTC (permalink / raw)
  To: qemu-devel

This is a followup of:

 v1: https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg00574.html

Currently DNS resolution of SocketAddress structs is done as
part of the socket connect/listen process. This is very
inflexible as it assumes that a single SocketAddress struct
will only ever require a single socket to be opened. While
true for connect(), it is not the case for listen() in two
scenarios

 - A name may resolve to both an IPv4 and IPv6 address. Currently
   we workaround that by clearing the IPV6_V6ONLY flag.

 - A name may resolve to multiple IP addresses of the same
   protocol. eg "myhostname" may return "192.168.122.1" and "10.0.0.2"
   when the host has multiple NICs, or multiple addresses per NIC.

The only way to deal with the latter problem is to open multiple
sockets and that requires the ability to separate DNS resolution
from socket creation.

This series thus enhances the I/O framework in QEMU to introduce
the "QIODNSResolver" concept. This (singleton) object allows the
caller to feed in a single SocketAddress struct, perform DNS
resolution, and get back out one or more new SocketAddress structs
for the results. The API allows both synchronous and asynchrounous
DNS lookups, the latter done by spawning a thread to do the
getaddrinfo call via the QIOTask framework.

In this series the InetSocketAddress struct gains a new field to
let the caller indicate that the address is providing a numeric
host value, thus skipping DNS altogether.

The QIOTask object had some refactoring to allow results to be
associated with it explicitly, so that the asynchronous DNS
results can be passed around. This triggered the code churn
across other files in QEMU using QIOTask.

This series will be utilized by a second series that will be
sent that updates the VNC server code to use this new feature.

Changed in v2:

 - Fix qapi schema version annotation (Eric)
 - Fix qapi schema optional status for "numeric" (Eric)
 - Use bool instead of gboolean (Eric)
 - Document that qio_task_set_error() accepts NULL (Eric)
 - Make qio_task_set_error() calls unconditional (Eric)
 - Fix leak of SocketAddress results (Eric)
 - Other misc typos (Eric)

Daniel P. Berrange (8):
  sockets: add ability to disable DNS resolution for InetSocketAddress
  io: stop incrementing reference in qio_task_get_source
  io: fix typo in docs for QIOTask
  io: add ability to associate an opaque "result" with with a task
  io: add ability to associate an error with a task
  io: change the QIOTask callback signature
  io: remove Error parameter from QIOTask thread worker
  io: introduce a DNS resolver API

 include/io/dns-resolver.h      | 228 +++++++++++++++++++++++++++++++++++
 include/io/task.h              | 154 +++++++++++++++++-------
 include/qemu/sockets.h         |   2 +
 io/Makefile.objs               |   1 +
 io/channel-socket.c            |  44 +++----
 io/channel-tls.c               |  16 +--
 io/channel-websock.c           |   8 +-
 io/dns-resolver.c              | 267 +++++++++++++++++++++++++++++++++++++++++
 io/task.c                      |  62 +++++++---
 io/trace-events                |   1 -
 migration/socket.c             |  11 +-
 migration/tls.c                |  19 +--
 nbd/common.c                   |   8 +-
 nbd/nbd-internal.h             |   3 +-
 qapi-schema.json               |   5 +
 qemu-char.c                    |  18 +--
 tests/test-io-channel-socket.c |   5 +-
 tests/test-io-channel-tls.c    |   5 +-
 tests/test-io-task.c           |  31 ++---
 ui/vnc-auth-vencrypt.c         |   7 +-
 ui/vnc-ws.c                    |  14 ++-
 util/qemu-sockets.c            |   7 +-
 22 files changed, 747 insertions(+), 169 deletions(-)
 create mode 100644 include/io/dns-resolver.h
 create mode 100644 io/dns-resolver.c

-- 
2.9.3

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH v2 1/8] sockets: add ability to disable DNS resolution for InetSocketAddress
  2017-01-09 15:39 [Qemu-devel] [PATCH v2 0/8] io: enable DNS resolving separately of socket create Daniel P. Berrange
@ 2017-01-09 15:39 ` Daniel P. Berrange
  2017-01-10 14:25   ` Eric Blake
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 2/8] io: stop incrementing reference in qio_task_get_source Daniel P. Berrange
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Daniel P. Berrange @ 2017-01-09 15:39 UTC (permalink / raw)
  To: qemu-devel

Add a 'numeric' flag to the InetSocketAddress struct to allow the
caller to indicate that DNS should be skipped for the host/port
fields. This is useful if the caller knows the address is already
numeric and wants to guarantee no (potentially blocking) DNS
lookups are attempted.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 qapi-schema.json    | 5 +++++
 util/qemu-sockets.c | 3 +++
 2 files changed, 8 insertions(+)

diff --git a/qapi-schema.json b/qapi-schema.json
index a0d3b5d..d59f8cc 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3070,6 +3070,10 @@
 #
 # @port: port part of the address, or lowest port if @to is present
 #
+# @numeric: #optional true if the host/port are guaranteed to be numeric,
+#           false if name resolution should be attempted. Defaults to false.
+#           (Since 2.9)
+#
 # @to: highest port to try
 #
 # @ipv4: whether to accept IPv4 addresses, default try both IPv4 and IPv6
@@ -3084,6 +3088,7 @@
   'data': {
     'host': 'str',
     'port': 'str',
+    '*numeric':  'bool',
     '*to': 'uint16',
     '*ipv4': 'bool',
     '*ipv6': 'bool' } }
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index fe1d07a..d63b011 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -141,6 +141,9 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
 
     memset(&ai,0, sizeof(ai));
     ai.ai_flags = AI_PASSIVE;
+    if (saddr->has_numeric && saddr->numeric) {
+        ai.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
+    }
     ai.ai_family = inet_ai_family_from_address(saddr, &err);
     ai.ai_socktype = SOCK_STREAM;
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH v2 2/8] io: stop incrementing reference in qio_task_get_source
  2017-01-09 15:39 [Qemu-devel] [PATCH v2 0/8] io: enable DNS resolving separately of socket create Daniel P. Berrange
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 1/8] sockets: add ability to disable DNS resolution for InetSocketAddress Daniel P. Berrange
@ 2017-01-09 15:39 ` Daniel P. Berrange
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 3/8] io: fix typo in docs for QIOTask Daniel P. Berrange
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Daniel P. Berrange @ 2017-01-09 15:39 UTC (permalink / raw)
  To: qemu-devel

Incrementing the reference in qio_task_get_source is
not necessary, since we're not running concurrently
with any other code touching the QIOTask. This
minimizes chances of further memory leaks.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/io/task.h    | 7 ++++---
 io/channel-socket.c  | 3 ---
 io/channel-tls.c     | 2 --
 io/task.c            | 1 -
 tests/test-io-task.c | 1 -
 5 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/include/io/task.h b/include/io/task.h
index 42028cb..c268eb0 100644
--- a/include/io/task.h
+++ b/include/io/task.h
@@ -244,9 +244,10 @@ void qio_task_abort(QIOTask *task,
  * @task: the task struct
  *
  * Get the source object associated with the background
- * task. This returns a new reference to the object,
- * which the caller must released with object_unref()
- * when no longer required.
+ * task. The caller does not own a reference on the
+ * returned Object, and so should call object_ref()
+ * if it wants to keep the object pointer outside the
+ * lifetime of the QIOTask object.
  *
  * Returns: the source object
  */
diff --git a/io/channel-socket.c b/io/channel-socket.c
index d7e03f6..45df819 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -168,7 +168,6 @@ static int qio_channel_socket_connect_worker(QIOTask *task,
                                           addr,
                                           errp);
 
-    object_unref(OBJECT(ioc));
     return ret;
 }
 
@@ -231,7 +230,6 @@ static int qio_channel_socket_listen_worker(QIOTask *task,
                                          addr,
                                          errp);
 
-    object_unref(OBJECT(ioc));
     return ret;
 }
 
@@ -309,7 +307,6 @@ static int qio_channel_socket_dgram_worker(QIOTask *task,
                                         data->remoteAddr,
                                         errp);
 
-    object_unref(OBJECT(ioc));
     return ret;
 }
 
diff --git a/io/channel-tls.c b/io/channel-tls.c
index d24dc8c..cf3bcca 100644
--- a/io/channel-tls.c
+++ b/io/channel-tls.c
@@ -200,8 +200,6 @@ static gboolean qio_channel_tls_handshake_io(QIOChannel *ioc,
     qio_channel_tls_handshake_task(
        tioc, task);
 
-    object_unref(OBJECT(tioc));
-
     return FALSE;
 }
 
diff --git a/io/task.c b/io/task.c
index c7f97a9..a763990 100644
--- a/io/task.c
+++ b/io/task.c
@@ -156,6 +156,5 @@ void qio_task_abort(QIOTask *task,
 
 Object *qio_task_get_source(QIOTask *task)
 {
-    object_ref(task->source);
     return task->source;
 }
diff --git a/tests/test-io-task.c b/tests/test-io-task.c
index e091c12..024eb58 100644
--- a/tests/test-io-task.c
+++ b/tests/test-io-task.c
@@ -76,7 +76,6 @@ static void test_task_complete(void)
     g_assert(obj == src);
 
     object_unref(obj);
-    object_unref(src);
 
     g_assert(data.source == obj);
     g_assert(data.err == NULL);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH v2 3/8] io: fix typo in docs for QIOTask
  2017-01-09 15:39 [Qemu-devel] [PATCH v2 0/8] io: enable DNS resolving separately of socket create Daniel P. Berrange
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 1/8] sockets: add ability to disable DNS resolution for InetSocketAddress Daniel P. Berrange
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 2/8] io: stop incrementing reference in qio_task_get_source Daniel P. Berrange
@ 2017-01-09 15:39 ` Daniel P. Berrange
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 4/8] io: add ability to associate an opaque "result" with with a task Daniel P. Berrange
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Daniel P. Berrange @ 2017-01-09 15:39 UTC (permalink / raw)
  To: qemu-devel

The GDestroyNotify parameter is already a pointer, so does
not need a '*' suffix on the type.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/io/task.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/io/task.h b/include/io/task.h
index c268eb0..1407747 100644
--- a/include/io/task.h
+++ b/include/io/task.h
@@ -49,7 +49,7 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
  *  void myobject_operation(QMyObject *obj,
  *                          QIOTaskFunc *func,
  *                          gpointer opaque,
- *                          GDestroyNotify *notify);
+ *                          GDestroyNotify notify);
  *   </programlisting>
  * </example>
  *
@@ -67,7 +67,7 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
  *    void myobject_operation(QMyObject *obj,
  *                            QIOTaskFunc *func,
  *                            gpointer opaque,
- *                            GDestroyNotify *notify)
+ *                            GDestroyNotify notify)
  *    {
  *      QIOTask *task;
  *
@@ -154,7 +154,7 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
  *                               SocketAddress *addr,
  *                               QIOTaskFunc *func,
  *                               gpointer opaque,
- *                               GDestroyNotify *notify)
+ *                               GDestroyNotify notify)
  *    {
  *      QIOTask *task;
  *      SocketAddress *addrCopy;
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH v2 4/8] io: add ability to associate an opaque "result" with with a task
  2017-01-09 15:39 [Qemu-devel] [PATCH v2 0/8] io: enable DNS resolving separately of socket create Daniel P. Berrange
                   ` (2 preceding siblings ...)
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 3/8] io: fix typo in docs for QIOTask Daniel P. Berrange
@ 2017-01-09 15:39 ` Daniel P. Berrange
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 5/8] io: add ability to associate an error " Daniel P. Berrange
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Daniel P. Berrange @ 2017-01-09 15:39 UTC (permalink / raw)
  To: qemu-devel

Currently there is no data associated with a successful
task completion. This adds an opaque pointer to the task
to store an arbitrary result.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/io/task.h | 27 +++++++++++++++++++++++++++
 io/task.c         | 20 ++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/include/io/task.h b/include/io/task.h
index 1407747..ece1372 100644
--- a/include/io/task.h
+++ b/include/io/task.h
@@ -240,6 +240,33 @@ void qio_task_abort(QIOTask *task,
 
 
 /**
+ * qio_task_set_result_pointer:
+ * @task: the task struct
+ * @result: pointer to the result data
+ *
+ * Associate an opaque result with the task,
+ * which can later be retrieved with the
+ * qio_task_get_result_pointer() method
+ *
+ */
+void qio_task_set_result_pointer(QIOTask *task,
+                                 gpointer result,
+                                 GDestroyNotify notify);
+
+
+/**
+ * qio_task_get_result_pointer:
+ * @task: the task struct
+ *
+ * Retrieve the opaque result data associated
+ * with the task, if any.
+ *
+ * Returns: the task result, or NULL
+ */
+gpointer qio_task_get_result_pointer(QIOTask *task);
+
+
+/**
  * qio_task_get_source:
  * @task: the task struct
  *
diff --git a/io/task.c b/io/task.c
index a763990..675e196 100644
--- a/io/task.c
+++ b/io/task.c
@@ -29,6 +29,8 @@ struct QIOTask {
     QIOTaskFunc func;
     gpointer opaque;
     GDestroyNotify destroy;
+    gpointer result;
+    GDestroyNotify destroyResult;
 };
 
 
@@ -57,6 +59,9 @@ static void qio_task_free(QIOTask *task)
     if (task->destroy) {
         task->destroy(task->opaque);
     }
+    if (task->destroyResult) {
+        task->destroyResult(task->result);
+    }
     object_unref(task->source);
 
     g_free(task);
@@ -154,6 +159,21 @@ void qio_task_abort(QIOTask *task,
 }
 
 
+void qio_task_set_result_pointer(QIOTask *task,
+                                 gpointer result,
+                                 GDestroyNotify destroy)
+{
+    task->result = result;
+    task->destroyResult = destroy;
+}
+
+
+gpointer qio_task_get_result_pointer(QIOTask *task)
+{
+    return task->result;
+}
+
+
 Object *qio_task_get_source(QIOTask *task)
 {
     return task->source;
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH v2 5/8] io: add ability to associate an error with a task
  2017-01-09 15:39 [Qemu-devel] [PATCH v2 0/8] io: enable DNS resolving separately of socket create Daniel P. Berrange
                   ` (3 preceding siblings ...)
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 4/8] io: add ability to associate an opaque "result" with with a task Daniel P. Berrange
@ 2017-01-09 15:39 ` Daniel P. Berrange
  2017-01-10 14:55   ` Eric Blake
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 6/8] io: change the QIOTask callback signature Daniel P. Berrange
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Daniel P. Berrange @ 2017-01-09 15:39 UTC (permalink / raw)
  To: qemu-devel

Currently when a task fails, the error is never explicitly
associated with the task object, it is just passed along
through the completion callback. This adds the ability to
explicitly associate an error with the task.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/io/task.h | 32 ++++++++++++++++++++++++++++++++
 io/task.c         | 23 +++++++++++++++++++++++
 2 files changed, 55 insertions(+)

diff --git a/include/io/task.h b/include/io/task.h
index ece1372..47daba9 100644
--- a/include/io/task.h
+++ b/include/io/task.h
@@ -240,6 +240,38 @@ void qio_task_abort(QIOTask *task,
 
 
 /**
+ * qio_task_set_error:
+ * @task: the task struct
+ * @err: pointer to the error, or NULL
+ *
+ * Associate an error with the task, which can later
+ * be retrieved with the qio_task_propagate_error()
+ * method. This method takes ownership of @err, so
+ * it is not valid to access it after this call
+ * completes. If @err is NULL this is a no-op. If
+ * this is call multiple times, only the first
+ * provided @err will be recorded, later ones will
+ * be discarded and freed.
+ */
+void qio_task_set_error(QIOTask *task,
+                        Error *err);
+
+
+/**
+ * qio_task_propagate_error:
+ * @task: the task struct
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Propagate the error associated with @task
+ * into @errp.
+ *
+ * Returns: true if an error was propagated, false otherwise
+ */
+bool qio_task_propagate_error(QIOTask *task,
+                              Error **errp);
+
+
+/**
  * qio_task_set_result_pointer:
  * @task: the task struct
  * @result: pointer to the result data
diff --git a/io/task.c b/io/task.c
index 675e196..1394e05 100644
--- a/io/task.c
+++ b/io/task.c
@@ -29,6 +29,7 @@ struct QIOTask {
     QIOTaskFunc func;
     gpointer opaque;
     GDestroyNotify destroy;
+    Error *err;
     gpointer result;
     GDestroyNotify destroyResult;
 };
@@ -62,6 +63,9 @@ static void qio_task_free(QIOTask *task)
     if (task->destroyResult) {
         task->destroyResult(task->result);
     }
+    if (task->err) {
+        error_free(task->err);
+    }
     object_unref(task->source);
 
     g_free(task);
@@ -159,6 +163,25 @@ void qio_task_abort(QIOTask *task,
 }
 
 
+void qio_task_set_error(QIOTask *task,
+                        Error *err)
+{
+    error_propagate(&task->err, err);
+}
+
+
+bool qio_task_propagate_error(QIOTask *task,
+                              Error **errp)
+{
+    if (task->err) {
+        error_propagate(errp, task->err);
+        return true;
+    }
+
+    return false;
+}
+
+
 void qio_task_set_result_pointer(QIOTask *task,
                                  gpointer result,
                                  GDestroyNotify destroy)
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH v2 6/8] io: change the QIOTask callback signature
  2017-01-09 15:39 [Qemu-devel] [PATCH v2 0/8] io: enable DNS resolving separately of socket create Daniel P. Berrange
                   ` (4 preceding siblings ...)
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 5/8] io: add ability to associate an error " Daniel P. Berrange
@ 2017-01-09 15:39 ` Daniel P. Berrange
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 7/8] io: remove Error parameter from QIOTask thread worker Daniel P. Berrange
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 8/8] io: introduce a DNS resolver API Daniel P. Berrange
  7 siblings, 0 replies; 12+ messages in thread
From: Daniel P. Berrange @ 2017-01-09 15:39 UTC (permalink / raw)
  To: qemu-devel

Currently the QIOTaskFunc signature takes an Object * for
the source, and an Error * for any error. We also need to
be able to provide a result pointer. Rather than continue
to add parameters to QIOTaskFunc, remove the existing
ones and simply pass the QIOTask object instead. This
has methods to access all the other data items required
in the callback impl.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/io/task.h              | 73 ++++++++++++++++++++++++------------------
 io/channel-tls.c               | 14 ++++----
 io/channel-websock.c           |  8 ++---
 io/task.c                      | 18 +++--------
 io/trace-events                |  1 -
 migration/socket.c             | 11 ++++---
 migration/tls.c                | 19 +++++------
 nbd/common.c                   |  8 ++---
 nbd/nbd-internal.h             |  3 +-
 qemu-char.c                    | 18 ++++++-----
 tests/test-io-channel-socket.c |  5 ++-
 tests/test-io-channel-tls.c    |  5 ++-
 tests/test-io-task.c           | 18 +++++------
 ui/vnc-auth-vencrypt.c         |  7 ++--
 ui/vnc-ws.c                    | 14 ++++----
 15 files changed, 110 insertions(+), 112 deletions(-)

diff --git a/include/io/task.h b/include/io/task.h
index 47daba9..ad90970 100644
--- a/include/io/task.h
+++ b/include/io/task.h
@@ -26,8 +26,7 @@
 
 typedef struct QIOTask QIOTask;
 
-typedef void (*QIOTaskFunc)(Object *source,
-                            Error *err,
+typedef void (*QIOTaskFunc)(QIOTask *task,
                             gpointer opaque);
 
 typedef int (*QIOTaskWorker)(QIOTask *task,
@@ -44,7 +43,7 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
  * a public API which accepts a task callback:
  *
  * <example>
- *   <title>Task callback function signature</title>
+ *   <title>Task function signature</title>
  *   <programlisting>
  *  void myobject_operation(QMyObject *obj,
  *                          QIOTaskFunc *func,
@@ -57,12 +56,36 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
  * is data to pass to it. The optional 'notify' function is used
  * to free 'opaque' when no longer needed.
  *
- * Now, lets say the implementation of this method wants to set
- * a timer to run once a second checking for completion of some
- * activity. It would do something like
+ * When the operation completes, the 'func' callback will be
+ * invoked, allowing the calling code to determine the result
+ * of the operation. An example QIOTaskFunc implementation may
+ * look like
  *
  * <example>
- *   <title>Task callback function implementation</title>
+ *   <title>Task callback implementation</title>
+ *   <programlisting>
+ *  static void myobject_operation_notify(QIOTask *task,
+ *                                        gpointer opaque)
+ *  {
+ *      Error *err = NULL;
+ *      if (qio_task_propagate_error(task, &err)) {
+ *          ...deal with the failure...
+ *          error_free(err);
+ *      } else {
+ *          QMyObject *src = QMY_OBJECT(qio_task_get_source(task));
+ *          ...deal with the completion...
+ *      }
+ *  }
+ *   </programlisting>
+ * </example>
+ *
+ * Now, lets say the implementation of the method using the
+ * task wants to set a timer to run once a second checking
+ * for completion of some activity. It would do something
+ * like
+ *
+ * <example>
+ *   <title>Task function implementation</title>
  *   <programlisting>
  *    void myobject_operation(QMyObject *obj,
  *                            QIOTaskFunc *func,
@@ -102,8 +125,8 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
  *
  *      ...check something important...
  *       if (err) {
- *           qio_task_abort(task, err);
- *           error_free(task);
+ *           qio_task_set_error(task, err);
+ *           qio_task_complete(task);
  *           return FALSE;
  *       } else if (...work is completed ...) {
  *           qio_task_complete(task);
@@ -115,6 +138,10 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
  *   </programlisting>
  * </example>
  *
+ * The 'qio_task_complete' call in this method will trigger
+ * the callback func 'myobject_operation_notify' shown
+ * earlier to deal with the results.
+ *
  * Once this function returns false, object_unref will be called
  * automatically on the task causing it to be released and the
  * ref on QMyObject dropped too.
@@ -187,8 +214,8 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
  * 'err' attribute in the task object to determine if
  * the operation was successful or not.
  *
- * The returned task will be released when one of
- * qio_task_abort() or qio_task_complete() are invoked.
+ * The returned task will be released when qio_task_complete()
+ * is invoked.
  *
  * Returns: the task struct
  */
@@ -204,10 +231,8 @@ QIOTask *qio_task_new(Object *source,
  * @opaque: opaque data to pass to @worker
  * @destroy: function to free @opaque
  *
- * Run a task in a background thread. If @worker
- * returns 0 it will call qio_task_complete() in
- * the main event thread context. If @worker
- * returns -1 it will call qio_task_abort() in
+ * Run a task in a background thread. When @worker
+ * returns it will call qio_task_complete() in
  * the main event thread context.
  */
 void qio_task_run_in_thread(QIOTask *task,
@@ -219,25 +244,11 @@ void qio_task_run_in_thread(QIOTask *task,
  * qio_task_complete:
  * @task: the task struct
  *
- * Mark the operation as successfully completed
- * and free the memory for @task.
+ * Invoke the completion callback for @task and
+ * then free its memory.
  */
 void qio_task_complete(QIOTask *task);
 
-/**
- * qio_task_abort:
- * @task: the task struct
- * @err: the error to record for the operation
- *
- * Mark the operation as failed, with @err providing
- * details about the failure. The @err may be freed
- * afer the function returns, as the notification
- * callback is invoked synchronously. The @task will
- * be freed when this call completes.
- */
-void qio_task_abort(QIOTask *task,
-                    Error *err);
-
 
 /**
  * qio_task_set_error:
diff --git a/io/channel-tls.c b/io/channel-tls.c
index cf3bcca..f25ab0a 100644
--- a/io/channel-tls.c
+++ b/io/channel-tls.c
@@ -153,8 +153,9 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
 
     if (qcrypto_tls_session_handshake(ioc->session, &err) < 0) {
         trace_qio_channel_tls_handshake_fail(ioc);
-        qio_task_abort(task, err);
-        goto cleanup;
+        qio_task_set_error(task, err);
+        qio_task_complete(task);
+        return;
     }
 
     status = qcrypto_tls_session_get_handshake_status(ioc->session);
@@ -163,10 +164,10 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
         if (qcrypto_tls_session_check_credentials(ioc->session,
                                                   &err) < 0) {
             trace_qio_channel_tls_credentials_deny(ioc);
-            qio_task_abort(task, err);
-            goto cleanup;
+            qio_task_set_error(task, err);
+        } else {
+            trace_qio_channel_tls_credentials_allow(ioc);
         }
-        trace_qio_channel_tls_credentials_allow(ioc);
         qio_task_complete(task);
     } else {
         GIOCondition condition;
@@ -183,9 +184,6 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
                               task,
                               NULL);
     }
-
- cleanup:
-    error_free(err);
 }
 
 
diff --git a/io/channel-websock.c b/io/channel-websock.c
index f45bced..e47279a 100644
--- a/io/channel-websock.c
+++ b/io/channel-websock.c
@@ -279,8 +279,8 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc,
 
     if (ret < 0) {
         trace_qio_channel_websock_handshake_fail(ioc);
-        qio_task_abort(task, err);
-        error_free(err);
+        qio_task_set_error(task, err);
+        qio_task_complete(task);
         return FALSE;
     }
 
@@ -307,8 +307,8 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc,
     ret = qio_channel_websock_handshake_read(wioc, &err);
     if (ret < 0) {
         trace_qio_channel_websock_handshake_fail(ioc);
-        qio_task_abort(task, err);
-        error_free(err);
+        qio_task_set_error(task, err);
+        qio_task_complete(task);
         return FALSE;
     }
     if (ret == 0) {
diff --git a/io/task.c b/io/task.c
index 1394e05..42e1a75 100644
--- a/io/task.c
+++ b/io/task.c
@@ -87,13 +87,11 @@ static gboolean gio_task_thread_result(gpointer opaque)
     struct QIOTaskThreadData *data = opaque;
 
     trace_qio_task_thread_result(data->task);
-    if (data->ret == 0) {
-        qio_task_complete(data->task);
-    } else {
-        qio_task_abort(data->task, data->err);
+    if (data->err) {
+        qio_task_set_error(data->task, data->err);
     }
+    qio_task_complete(data->task);
 
-    error_free(data->err);
     if (data->destroy) {
         data->destroy(data->opaque);
     }
@@ -149,19 +147,11 @@ void qio_task_run_in_thread(QIOTask *task,
 
 void qio_task_complete(QIOTask *task)
 {
-    task->func(task->source, NULL, task->opaque);
+    task->func(task, task->opaque);
     trace_qio_task_complete(task);
     qio_task_free(task);
 }
 
-void qio_task_abort(QIOTask *task,
-                    Error *err)
-{
-    task->func(task->source, err, task->opaque);
-    trace_qio_task_abort(task);
-    qio_task_free(task);
-}
-
 
 void qio_task_set_error(QIOTask *task,
                         Error *err)
diff --git a/io/trace-events b/io/trace-events
index e31b596..ff993be 100644
--- a/io/trace-events
+++ b/io/trace-events
@@ -3,7 +3,6 @@
 # io/task.c
 qio_task_new(void *task, void *source, void *func, void *opaque) "Task new task=%p source=%p func=%p opaque=%p"
 qio_task_complete(void *task) "Task complete task=%p"
-qio_task_abort(void *task) "Task abort task=%p"
 qio_task_thread_start(void *task, void *worker, void *opaque) "Task thread start task=%p worker=%p opaque=%p"
 qio_task_thread_run(void *task) "Task thread run task=%p"
 qio_task_thread_exit(void *task) "Task thread exit task=%p"
diff --git a/migration/socket.c b/migration/socket.c
index 11f80b1..13966f1 100644
--- a/migration/socket.c
+++ b/migration/socket.c
@@ -70,22 +70,23 @@ static void socket_connect_data_free(void *opaque)
     g_free(data);
 }
 
-static void socket_outgoing_migration(Object *src,
-                                      Error *err,
+static void socket_outgoing_migration(QIOTask *task,
                                       gpointer opaque)
 {
     struct SocketConnectData *data = opaque;
-    QIOChannel *sioc = QIO_CHANNEL(src);
+    QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task));
+    Error *err = NULL;
 
-    if (err) {
+    if (qio_task_propagate_error(task, &err)) {
         trace_migration_socket_outgoing_error(error_get_pretty(err));
         data->s->to_dst_file = NULL;
         migrate_fd_error(data->s, err);
+        error_free(err);
     } else {
         trace_migration_socket_outgoing_connected(data->hostname);
         migration_channel_connect(data->s, sioc, data->hostname);
     }
-    object_unref(src);
+    object_unref(OBJECT(sioc));
 }
 
 static void socket_start_outgoing_migration(MigrationState *s,
diff --git a/migration/tls.c b/migration/tls.c
index 49ca9a8..203c11d 100644
--- a/migration/tls.c
+++ b/migration/tls.c
@@ -61,15 +61,15 @@ migration_tls_get_creds(MigrationState *s,
 }
 
 
-static void migration_tls_incoming_handshake(Object *src,
-                                             Error *err,
+static void migration_tls_incoming_handshake(QIOTask *task,
                                              gpointer opaque)
 {
-    QIOChannel *ioc = QIO_CHANNEL(src);
+    QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task));
+    Error *err = NULL;
 
-    if (err) {
+    if (qio_task_propagate_error(task, &err)) {
         trace_migration_tls_incoming_handshake_error(error_get_pretty(err));
-        error_report("%s", error_get_pretty(err));
+        error_report_err(err);
     } else {
         trace_migration_tls_incoming_handshake_complete();
         migration_channel_process_incoming(migrate_get_current(), ioc);
@@ -107,17 +107,18 @@ void migration_tls_channel_process_incoming(MigrationState *s,
 }
 
 
-static void migration_tls_outgoing_handshake(Object *src,
-                                             Error *err,
+static void migration_tls_outgoing_handshake(QIOTask *task,
                                              gpointer opaque)
 {
     MigrationState *s = opaque;
-    QIOChannel *ioc = QIO_CHANNEL(src);
+    QIOChannel *ioc = QIO_CHANNEL(qio_task_get_source(task));
+    Error *err = NULL;
 
-    if (err) {
+    if (qio_task_propagate_error(task, &err)) {
         trace_migration_tls_outgoing_handshake_error(error_get_pretty(err));
         s->to_dst_file = NULL;
         migrate_fd_error(s, err);
+        error_free(err);
     } else {
         trace_migration_tls_outgoing_handshake_complete();
         migration_channel_connect(s, ioc, NULL);
diff --git a/nbd/common.c b/nbd/common.c
index b583a4f..a5f39ea 100644
--- a/nbd/common.c
+++ b/nbd/common.c
@@ -78,15 +78,13 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc,
 }
 
 
-void nbd_tls_handshake(Object *src,
-                       Error *err,
+void nbd_tls_handshake(QIOTask *task,
                        void *opaque)
 {
     struct NBDTLSHandshakeData *data = opaque;
 
-    if (err) {
-        TRACE("TLS failed %s", error_get_pretty(err));
-        data->error = error_copy(err);
+    if (qio_task_propagate_error(task, &data->error)) {
+        TRACE("TLS failed %s", error_get_pretty(data->error));
     }
     data->complete = true;
     g_main_loop_quit(data->loop);
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
index eee20ab..f43d990 100644
--- a/nbd/nbd-internal.h
+++ b/nbd/nbd-internal.h
@@ -120,8 +120,7 @@ struct NBDTLSHandshakeData {
 };
 
 
-void nbd_tls_handshake(Object *src,
-                       Error *err,
+void nbd_tls_handshake(QIOTask *task,
                        void *opaque);
 
 #endif
diff --git a/qemu-char.c b/qemu-char.c
index 2c9940c..502d50a 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3272,14 +3272,13 @@ static void tcp_chr_telnet_init(CharDriverState *chr)
 }
 
 
-static void tcp_chr_tls_handshake(Object *source,
-                                  Error *err,
+static void tcp_chr_tls_handshake(QIOTask *task,
                                   gpointer user_data)
 {
     CharDriverState *chr = user_data;
     TCPCharDriver *s = chr->opaque;
 
-    if (err) {
+    if (qio_task_propagate_error(task, NULL)) {
         tcp_chr_disconnect(chr);
     } else {
         if (s->do_telnetopt) {
@@ -3487,20 +3486,23 @@ static void tcp_chr_free(CharDriverState *chr)
 }
 
 
-static void qemu_chr_socket_connected(Object *src, Error *err, void *opaque)
+static void qemu_chr_socket_connected(QIOTask *task, void *opaque)
 {
-    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(src);
+    QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
     CharDriverState *chr = opaque;
     TCPCharDriver *s = chr->opaque;
+    Error *err = NULL;
 
-    if (err) {
+    if (qio_task_propagate_error(task, &err)) {
         check_report_connect_error(chr, err);
-        object_unref(src);
-        return;
+        error_free(err);
+        goto cleanup;
     }
 
     s->connect_err_reported = false;
     tcp_chr_new_client(chr, sioc);
+
+ cleanup:
     object_unref(OBJECT(sioc));
 }
 
diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c
index aa88c3c..aaa9116 100644
--- a/tests/test-io-channel-socket.c
+++ b/tests/test-io-channel-socket.c
@@ -156,12 +156,11 @@ struct TestIOChannelData {
 };
 
 
-static void test_io_channel_complete(Object *src,
-                                     Error *err,
+static void test_io_channel_complete(QIOTask *task,
                                      gpointer opaque)
 {
     struct TestIOChannelData *data = opaque;
-    data->err = err != NULL;
+    data->err = qio_task_propagate_error(task, NULL);
     g_main_loop_quit(data->loop);
 }
 
diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c
index bd3ae2b..8eaa208 100644
--- a/tests/test-io-channel-tls.c
+++ b/tests/test-io-channel-tls.c
@@ -53,14 +53,13 @@ struct QIOChannelTLSHandshakeData {
     bool failed;
 };
 
-static void test_tls_handshake_done(Object *source,
-                                    Error *err,
+static void test_tls_handshake_done(QIOTask *task,
                                     gpointer opaque)
 {
     struct QIOChannelTLSHandshakeData *data = opaque;
 
     data->finished = true;
-    data->failed = err != NULL;
+    data->failed = qio_task_propagate_error(task, NULL);
 }
 
 
diff --git a/tests/test-io-task.c b/tests/test-io-task.c
index 024eb58..84144c9 100644
--- a/tests/test-io-task.c
+++ b/tests/test-io-task.c
@@ -50,14 +50,13 @@ struct TestTaskData {
 };
 
 
-static void task_callback(Object *source,
-                          Error *err,
+static void task_callback(QIOTask *task,
                           gpointer opaque)
 {
     struct TestTaskData *data = opaque;
 
-    data->source = source;
-    data->err = err;
+    data->source = qio_task_get_source(task);
+    qio_task_propagate_error(task, &data->err);
 }
 
 
@@ -120,9 +119,9 @@ static void test_task_failure(void)
 
     error_setg(&err, "Some error");
 
-    qio_task_abort(task, err);
+    qio_task_set_error(task, err);
+    qio_task_complete(task);
 
-    error_free(err);
     object_unref(obj);
 
     g_assert(data.source == obj);
@@ -158,14 +157,13 @@ static int test_task_thread_worker(QIOTask *task,
 }
 
 
-static void test_task_thread_callback(Object *source,
-                                      Error *err,
+static void test_task_thread_callback(QIOTask *task,
                                       gpointer opaque)
 {
     struct TestThreadWorkerData *data = opaque;
 
-    data->source = source;
-    data->err = err;
+    data->source = qio_task_get_source(task);
+    qio_task_propagate_error(task, &data->err);
 
     data->complete = g_thread_self();
 
diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
index c0c29a5..ffaab57 100644
--- a/ui/vnc-auth-vencrypt.c
+++ b/ui/vnc-auth-vencrypt.c
@@ -65,16 +65,17 @@ static void start_auth_vencrypt_subauth(VncState *vs)
     }
 }
 
-static void vnc_tls_handshake_done(Object *source,
-                                   Error *err,
+static void vnc_tls_handshake_done(QIOTask *task,
                                    gpointer user_data)
 {
     VncState *vs = user_data;
+    Error *err = NULL;
 
-    if (err) {
+    if (qio_task_propagate_error(task, &err)) {
         VNC_DEBUG("Handshake failed %s\n",
                   error_get_pretty(err));
         vnc_client_error(vs);
+        error_free(err);
     } else {
         vs->ioc_tag = qio_channel_add_watch(
             vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL);
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
index bffb484..f530cd5 100644
--- a/ui/vnc-ws.c
+++ b/ui/vnc-ws.c
@@ -24,15 +24,16 @@
 #include "io/channel-websock.h"
 #include "qemu/bswap.h"
 
-static void vncws_tls_handshake_done(Object *source,
-                                     Error *err,
+static void vncws_tls_handshake_done(QIOTask *task,
                                      gpointer user_data)
 {
     VncState *vs = user_data;
+    Error *err = NULL;
 
-    if (err) {
+    if (qio_task_propagate_error(task, &err)) {
         VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err));
         vnc_client_error(vs);
+        error_free(err);
     } else {
         VNC_DEBUG("TLS handshake complete, starting websocket handshake\n");
         vs->ioc_tag = qio_channel_add_watch(
@@ -83,15 +84,16 @@ gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
 }
 
 
-static void vncws_handshake_done(Object *source,
-                                 Error *err,
+static void vncws_handshake_done(QIOTask *task,
                                  gpointer user_data)
 {
     VncState *vs = user_data;
+    Error *err = NULL;
 
-    if (err) {
+    if (qio_task_propagate_error(task, &err)) {
         VNC_DEBUG("Websock handshake failed %s\n", error_get_pretty(err));
         vnc_client_error(vs);
+        error_free(err);
     } else {
         VNC_DEBUG("Websock handshake complete, starting VNC protocol\n");
         vnc_start_protocol(vs);
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH v2 7/8] io: remove Error parameter from QIOTask thread worker
  2017-01-09 15:39 [Qemu-devel] [PATCH v2 0/8] io: enable DNS resolving separately of socket create Daniel P. Berrange
                   ` (5 preceding siblings ...)
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 6/8] io: change the QIOTask callback signature Daniel P. Berrange
@ 2017-01-09 15:39 ` Daniel P. Berrange
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 8/8] io: introduce a DNS resolver API Daniel P. Berrange
  7 siblings, 0 replies; 12+ messages in thread
From: Daniel P. Berrange @ 2017-01-09 15:39 UTC (permalink / raw)
  To: qemu-devel

Now that task objects have a directly associated error,
there's no need for an an Error **errp parameter to
the QIOTask thread worker function. It already has a
QIOTask object, so can directly set the error on it.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/io/task.h    | 19 ++++++++-----------
 io/channel-socket.c  | 41 ++++++++++++++++-------------------------
 io/task.c            | 10 +---------
 tests/test-io-task.c | 12 +++++-------
 4 files changed, 30 insertions(+), 52 deletions(-)

diff --git a/include/io/task.h b/include/io/task.h
index ad90970..6021f51 100644
--- a/include/io/task.h
+++ b/include/io/task.h
@@ -29,9 +29,8 @@ typedef struct QIOTask QIOTask;
 typedef void (*QIOTaskFunc)(QIOTask *task,
                             gpointer opaque);
 
-typedef int (*QIOTaskWorker)(QIOTask *task,
-                             Error **errp,
-                             gpointer opaque);
+typedef void (*QIOTaskWorker)(QIOTask *task,
+                              gpointer opaque);
 
 /**
  * QIOTask:
@@ -163,18 +162,16 @@ typedef int (*QIOTaskWorker)(QIOTask *task,
  * socket listen using QIOTask would require:
  *
  * <example>
- *    static int myobject_listen_worker(QIOTask *task,
- *                                      Error **errp,
- *                                      gpointer opaque)
+ *    static void myobject_listen_worker(QIOTask *task,
+ *                                       gpointer opaque)
  *    {
  *       QMyObject obj = QMY_OBJECT(qio_task_get_source(task));
  *       SocketAddress *addr = opaque;
+ *       Error *err = NULL;
  *
- *       obj->fd = socket_listen(addr, errp);
- *       if (obj->fd < 0) {
- *          return -1;
- *       }
- *       return 0;
+ *       obj->fd = socket_listen(addr, &err);
+ *
+         qio_task_set_error(task, err);
  *    }
  *
  *    void myobject_listen_async(QMyObject *obj,
diff --git a/io/channel-socket.c b/io/channel-socket.c
index 45df819..f385233 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -156,19 +156,16 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc,
 }
 
 
-static int qio_channel_socket_connect_worker(QIOTask *task,
-                                             Error **errp,
-                                             gpointer opaque)
+static void qio_channel_socket_connect_worker(QIOTask *task,
+                                              gpointer opaque)
 {
     QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
     SocketAddress *addr = opaque;
-    int ret;
+    Error *err = NULL;
 
-    ret = qio_channel_socket_connect_sync(ioc,
-                                          addr,
-                                          errp);
+    qio_channel_socket_connect_sync(ioc, addr, &err);
 
-    return ret;
+    qio_task_set_error(task, err);
 }
 
 
@@ -218,19 +215,16 @@ int qio_channel_socket_listen_sync(QIOChannelSocket *ioc,
 }
 
 
-static int qio_channel_socket_listen_worker(QIOTask *task,
-                                            Error **errp,
-                                            gpointer opaque)
+static void qio_channel_socket_listen_worker(QIOTask *task,
+                                             gpointer opaque)
 {
     QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
     SocketAddress *addr = opaque;
-    int ret;
+    Error *err = NULL;
 
-    ret = qio_channel_socket_listen_sync(ioc,
-                                         addr,
-                                         errp);
+    qio_channel_socket_listen_sync(ioc, addr, &err);
 
-    return ret;
+    qio_task_set_error(task, err);
 }
 
 
@@ -293,21 +287,18 @@ static void qio_channel_socket_dgram_worker_free(gpointer opaque)
     g_free(data);
 }
 
-static int qio_channel_socket_dgram_worker(QIOTask *task,
-                                           Error **errp,
-                                           gpointer opaque)
+static void qio_channel_socket_dgram_worker(QIOTask *task,
+                                            gpointer opaque)
 {
     QIOChannelSocket *ioc = QIO_CHANNEL_SOCKET(qio_task_get_source(task));
     struct QIOChannelSocketDGramWorkerData *data = opaque;
-    int ret;
+    Error *err = NULL;
 
     /* socket_dgram() blocks in DNS lookups, so we must use a thread */
-    ret = qio_channel_socket_dgram_sync(ioc,
-                                        data->localAddr,
-                                        data->remoteAddr,
-                                        errp);
+    qio_channel_socket_dgram_sync(ioc, data->localAddr,
+                                  data->remoteAddr, &err);
 
-    return ret;
+    qio_task_set_error(task, err);
 }
 
 
diff --git a/io/task.c b/io/task.c
index 42e1a75..60bf1a9 100644
--- a/io/task.c
+++ b/io/task.c
@@ -77,8 +77,6 @@ struct QIOTaskThreadData {
     QIOTaskWorker worker;
     gpointer opaque;
     GDestroyNotify destroy;
-    Error *err;
-    int ret;
 };
 
 
@@ -87,9 +85,6 @@ static gboolean gio_task_thread_result(gpointer opaque)
     struct QIOTaskThreadData *data = opaque;
 
     trace_qio_task_thread_result(data->task);
-    if (data->err) {
-        qio_task_set_error(data->task, data->err);
-    }
     qio_task_complete(data->task);
 
     if (data->destroy) {
@@ -107,10 +102,7 @@ static gpointer qio_task_thread_worker(gpointer opaque)
     struct QIOTaskThreadData *data = opaque;
 
     trace_qio_task_thread_run(data->task);
-    data->ret = data->worker(data->task, &data->err, data->opaque);
-    if (data->ret < 0 && data->err == NULL) {
-        error_setg(&data->err, "Task worker failed but did not set an error");
-    }
+    data->worker(data->task, data->opaque);
 
     /* We're running in the background thread, and must only
      * ever report the task results in the main event loop
diff --git a/tests/test-io-task.c b/tests/test-io-task.c
index 84144c9..ff62272 100644
--- a/tests/test-io-task.c
+++ b/tests/test-io-task.c
@@ -140,20 +140,18 @@ struct TestThreadWorkerData {
     GMainLoop *loop;
 };
 
-static int test_task_thread_worker(QIOTask *task,
-                                   Error **errp,
-                                   gpointer opaque)
+static void test_task_thread_worker(QIOTask *task,
+                                    gpointer opaque)
 {
     struct TestThreadWorkerData *data = opaque;
 
     data->worker = g_thread_self();
 
     if (data->fail) {
-        error_setg(errp, "Testing fail");
-        return -1;
+        Error *err = NULL;
+        error_setg(&err, "Testing fail");
+        qio_task_set_error(task, err);
     }
-
-    return 0;
 }
 
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [Qemu-devel] [PATCH v2 8/8] io: introduce a DNS resolver API
  2017-01-09 15:39 [Qemu-devel] [PATCH v2 0/8] io: enable DNS resolving separately of socket create Daniel P. Berrange
                   ` (6 preceding siblings ...)
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 7/8] io: remove Error parameter from QIOTask thread worker Daniel P. Berrange
@ 2017-01-09 15:39 ` Daniel P. Berrange
  2017-01-10 15:01   ` Eric Blake
  7 siblings, 1 reply; 12+ messages in thread
From: Daniel P. Berrange @ 2017-01-09 15:39 UTC (permalink / raw)
  To: qemu-devel

Currently DNS resolution is done automatically as part
of the creation of a QIOChannelSocket object instance.
This works ok for network clients where you just end
up a single network socket, but for servers, the results
of DNS resolution may require creation of multiple
sockets.

Introducing a DNS resolver API allows DNS resolution
to be separated from the socket object creation. This
will make it practical to create multiple QIOChannelSocket
instances for servers.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 include/io/dns-resolver.h | 228 +++++++++++++++++++++++++++++++++++++++
 include/qemu/sockets.h    |   2 +
 io/Makefile.objs          |   1 +
 io/dns-resolver.c         | 267 ++++++++++++++++++++++++++++++++++++++++++++++
 util/qemu-sockets.c       |   4 +-
 5 files changed, 500 insertions(+), 2 deletions(-)
 create mode 100644 include/io/dns-resolver.h
 create mode 100644 io/dns-resolver.c

diff --git a/include/io/dns-resolver.h b/include/io/dns-resolver.h
new file mode 100644
index 0000000..2f69c08
--- /dev/null
+++ b/include/io/dns-resolver.h
@@ -0,0 +1,228 @@
+/*
+ * QEMU DNS resolver
+ *
+ * Copyright (c) 2016-2017 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 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/>.
+ *
+ */
+
+#ifndef QIO_DNS_RESOLVER_H
+#define QIO_DNS_RESOLVER_H
+
+#include "qemu-common.h"
+#include "qom/object.h"
+#include "io/task.h"
+
+#define TYPE_QIO_DNS_RESOLVER "qio-dns-resolver"
+#define QIO_DNS_RESOLVER(obj)                                    \
+    OBJECT_CHECK(QIODNSResolver, (obj), TYPE_QIO_DNS_RESOLVER)
+#define QIO_DNS_RESOLVER_CLASS(klass)                                    \
+    OBJECT_CLASS_CHECK(QIODNSResolverClass, klass, TYPE_QIO_DNS_RESOLVER)
+#define QIO_DNS_RESOLVER_GET_CLASS(obj)                                  \
+    OBJECT_GET_CLASS(QIODNSResolverClass, obj, TYPE_QIO_DNS_RESOLVER)
+
+typedef struct QIODNSResolver QIODNSResolver;
+typedef struct QIODNSResolverClass QIODNSResolverClass;
+
+/**
+ * QIODNSResolver:
+ *
+ * The QIODNSResolver class provides a framework for doing
+ * DNS resolution on SocketAddress objects, independently
+ * of socket creation.
+ *
+ * <example>
+ *   <title>Resolving addresses synchronously</title>
+ *   <programlisting>
+ *    int mylisten(SocketAddress *addr, Error **errp) {
+ *      QIODNSResolver *resolver = qio_dns_resolver_get_instance();
+ *      SocketAddress **rawaddrs = NULL;
+ *      size_t nrawaddrs = 0;
+ *      Error *err = NULL;
+ *      QIOChannel **socks = NULL;
+ *      size_t nsocks = 0;
+ *
+ *      if (qio_dns_resolver_lookup_sync(dns, addr, &nrawaddrs,
+ *                                       &rawaddrs, errp) < 0) {
+ *          return -1;
+ *      }
+ *
+ *      for (i = 0; i < nrawaddrs; i++) {
+ *         QIOChannel *sock = qio_channel_new();
+ *         Error *local_err = NULL;
+ *         qio_channel_listen_sync(sock, rawaddrs[i], &local_err);
+ *         if (local_err) {
+ *            error_propagate(&err, local_err);
+ *         } else {
+ *            socks = g_renew(QIOChannelSocket *, socks, nsocks + 1);
+ *            socks[nsocks++] = sock;
+ *         }
+ *         qapi_free_SocketAddress(rawaddrs[i]);
+ *      }
+ *      g_free(rawaddrs);
+ *
+ *      if (nsocks == 0) {
+ *         error_propagate(errp, err);
+ *      } else {
+ *         error_free(err);
+ *      }
+ *   }
+ *   </programlisting>
+ * </example>
+ *
+ * <example>
+ *   <title>Resolving addresses asynchronously</title>
+ *   <programlisting>
+ *    typedef struct MyListenData {
+ *       Error *err;
+ *       QIOChannelSocket **socks;
+ *       size_t nsocks;
+ *    } MyListenData;
+ *
+ *    void mylistenresult(QIOTask *task, void *opaque) {
+ *      MyListenData *data = opaque;
+ *      QIODNSResolver *resolver =
+ *         QIO_DNS_RESOLVER(qio_task_get_source(task);
+ *      SocketAddress **rawaddrs = NULL;
+ *      size_t nrawaddrs = 0;
+ *      Error *err = NULL;
+ *
+ *      if (qio_task_propagate_error(task, &data->err)) {
+ *         return;
+ *      }
+ *
+ *      qio_dns_resolver_lookup_result(resolver, task,
+ *                                     &nrawaddrs, &rawaddrs);
+ *
+ *      for (i = 0; i < nrawaddrs; i++) {
+ *         QIOChannel *sock = qio_channel_new();
+ *         Error *local_err = NULL;
+ *         qio_channel_listen_sync(sock, rawaddrs[i], &local_err);
+ *         if (local_err) {
+ *            error_propagate(&err, local_err);
+ *         } else {
+ *            socks = g_renew(QIOChannelSocket *, socks, nsocks + 1);
+ *            socks[nsocks++] = sock;
+ *         }
+ *         qapi_free_SocketAddress(rawaddrs[i]);
+ *      }
+ *      g_free(rawaddrs);
+ *
+ *      if (nsocks == 0) {
+ *         error_propagate(&data->err, err);
+ *      } else {
+ *         error_free(err);
+ *      }
+ *    }
+ *
+ *    void mylisten(SocketAddress *addr, MyListenData *data) {
+ *      QIODNSResolver *resolver = qio_dns_resolver_get_instance();
+ *      qio_dns_resolver_lookup_async(dns, addr,
+ *                                    mylistenresult, data, NULL);
+ *    }
+ *   </programlisting>
+ * </example>
+ */
+struct QIODNSResolver {
+    Object parent;
+};
+
+struct QIODNSResolverClass {
+    ObjectClass parent;
+};
+
+
+/**
+ * qio_dns_resolver_get_instance:
+ *
+ * Get the singleton dns resolver instance. The caller
+ * does not own a reference on the returned object.
+ *
+ * Returns: the single dns resolver instance
+ */
+QIODNSResolver *qio_dns_resolver_get_instance(void);
+
+/**
+ * qio_dns_resolver_lookup_sync:
+ * @resolver: the DNS resolver instance
+ * @addr: the address to resolve
+ * @naddr: pointer to hold number of resolved addresses
+ * @addrs: pointer to hold resolved addresses
+ * @errp: pointer to NULL initialized error object
+ *
+ * This will attempt to resolve the address provided
+ * in @addr. If resolution succeeds, @addrs will be filled
+ * with all the resolved addresses. @naddrs will specify
+ * the number of entries allocated in @addrs. The caller
+ * is responsible for freeing each entry in @addrs, as
+ * well as @addrs itself. @naddrs is guaranteed to be
+ * greater than zero on success.
+ *
+ * DNS resolution will be done synchronously so execution
+ * of the caller may be blocked for an arbitrary length
+ * of time.
+ *
+ * Returns: 0 if resolution was successful, -1 on error
+ */
+int qio_dns_resolver_lookup_sync(QIODNSResolver *resolver,
+                                 SocketAddress *addr,
+                                 size_t *naddrs,
+                                 SocketAddress ***addrs,
+                                 Error **errp);
+
+/**
+ * qio_dns_resolver_lookup_async:
+ * @resolver: the DNS resolver instance
+ * @addr: the address to resolve
+ * @func: the callback to invoke on lookup completion
+ * @opaque: data blob to pass to @func
+ * @notify: the callback to free @opaque, or NULL
+ *
+ * This will attempt to resolve the address provided
+ * in @addr. The callback @func will be invoked when
+ * resolution has either completed or failed. On
+ * success, the @func should call the method
+ * qio_dns_resolver_lookup_result() to obtain the
+ * results.
+ *
+ * DNS resolution will be done asynchronously so execution
+ * of the caller will not be blocked.
+ */
+void qio_dns_resolver_lookup_async(QIODNSResolver *resolver,
+                                   SocketAddress *addr,
+                                   QIOTaskFunc func,
+                                   gpointer opaque,
+                                   GDestroyNotify notify);
+
+/**
+ * qio_dns_resolver_lookup_result:
+ * @resolver: the DNS resolver instance
+ * @task: the task object to get results for
+ * @naddr: pointer to hold number of resolved addresses
+ * @addrs: pointer to hold resolved addresses
+ *
+ * This method should be called from the callback passed
+ * to qio_dns_resolver_lookup_async() in order to obtain
+ * results.  @addrs will be filled with all the resolved
+ * addresses. @naddrs will specify the number of entries
+ * allocated in @addrs. The caller is responsible for
+ * freeing each entry in @addrs, as well as @addrs itself.
+ */
+void qio_dns_resolver_lookup_result(QIODNSResolver *resolver,
+                                    QIOTask *task,
+                                    size_t *naddrs,
+                                    SocketAddress ***addrs);
+
+#endif /* QIO_DNS_RESOLVER_H */
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index 5589e68..5f1bab9 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -32,6 +32,8 @@ int socket_set_fast_reuse(int fd);
  */
 typedef void NonBlockingConnectHandler(int fd, Error *err, void *opaque);
 
+int inet_ai_family_from_address(InetSocketAddress *addr,
+                                Error **errp);
 InetSocketAddress *inet_parse(const char *str, Error **errp);
 int inet_connect(const char *str, Error **errp);
 int inet_connect_saddr(InetSocketAddress *saddr, Error **errp,
diff --git a/io/Makefile.objs b/io/Makefile.objs
index 9d8337d..12983cc 100644
--- a/io/Makefile.objs
+++ b/io/Makefile.objs
@@ -7,4 +7,5 @@ io-obj-y += channel-tls.o
 io-obj-y += channel-watch.o
 io-obj-y += channel-websock.o
 io-obj-y += channel-util.o
+io-obj-y += dns-resolver.o
 io-obj-y += task.o
diff --git a/io/dns-resolver.c b/io/dns-resolver.c
new file mode 100644
index 0000000..58e050f
--- /dev/null
+++ b/io/dns-resolver.c
@@ -0,0 +1,267 @@
+/*
+ * QEMU DNS resolver
+ *
+ * Copyright (c) 2016 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 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/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "io/dns-resolver.h"
+#include "qapi/clone-visitor.h"
+#include "qemu/sockets.h"
+#include "qapi/error.h"
+#include "qemu/cutils.h"
+
+
+static QIODNSResolver *instance;
+
+QIODNSResolver *qio_dns_resolver_get_instance(void)
+{
+    return instance;
+}
+
+static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver,
+                                             SocketAddress *addr,
+                                             size_t *naddrs,
+                                             SocketAddress ***addrs,
+                                             Error **errp)
+{
+    struct addrinfo ai, *res, *e;
+    InetSocketAddress *iaddr = addr->u.inet.data;
+    char port[33];
+    char uaddr[INET6_ADDRSTRLEN + 1];
+    char uport[33];
+    int rc;
+    Error *err = NULL;
+    size_t i;
+
+    *naddrs = 0;
+    *addrs = NULL;
+
+    memset(&ai, 0, sizeof(ai));
+    ai.ai_flags = AI_PASSIVE;
+    if (iaddr->has_numeric && iaddr->numeric) {
+        ai.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
+    }
+    ai.ai_family = inet_ai_family_from_address(iaddr, &err);
+    ai.ai_socktype = SOCK_STREAM;
+
+    if (err) {
+        error_propagate(errp, err);
+        return -1;
+    }
+
+    if (iaddr->host == NULL) {
+        error_setg(errp, "host not specified");
+        return -1;
+    }
+    if (iaddr->port != NULL) {
+        pstrcpy(port, sizeof(port), iaddr->port);
+    } else {
+        port[0] = '\0';
+    }
+
+    rc = getaddrinfo(strlen(iaddr->host) ? iaddr->host : NULL,
+                     strlen(port) ? port : NULL, &ai, &res);
+    if (rc != 0) {
+        error_setg(errp, "address resolution failed for %s:%s: %s",
+                   iaddr->host, port, gai_strerror(rc));
+        return -1;
+    }
+
+    for (e = res; e != NULL; e = e->ai_next) {
+        (*naddrs)++;
+    }
+
+    *addrs = g_new0(SocketAddress *, *naddrs);
+
+    /* create socket + bind */
+    for (i = 0, e = res; e != NULL; i++, e = e->ai_next) {
+        SocketAddress *newaddr = g_new0(SocketAddress, 1);
+        InetSocketAddress *newiaddr = g_new0(InetSocketAddress, 1);
+        newaddr->u.inet.data = newiaddr;
+        newaddr->type = SOCKET_ADDRESS_KIND_INET;
+
+        getnameinfo((struct sockaddr *)e->ai_addr, e->ai_addrlen,
+                    uaddr, INET6_ADDRSTRLEN, uport, 32,
+                    NI_NUMERICHOST | NI_NUMERICSERV);
+
+        *newiaddr = (InetSocketAddress){
+            .host = g_strdup(uaddr),
+            .port = g_strdup(uport),
+            .has_numeric = true,
+            .numeric = true,
+            .has_to = iaddr->has_to,
+            .to = iaddr->to,
+            .has_ipv4 = false,
+            .has_ipv6 = false,
+        };
+
+        (*addrs)[i] = newaddr;
+    }
+    freeaddrinfo(res);
+    return 0;
+}
+
+
+static int qio_dns_resolver_lookup_sync_nop(QIODNSResolver *resolver,
+                                            SocketAddress *addr,
+                                            size_t *naddrs,
+                                            SocketAddress ***addrs,
+                                            Error **errp)
+{
+    *naddrs = 1;
+    *addrs = g_new0(SocketAddress *, 1);
+    (*addrs)[0] = QAPI_CLONE(SocketAddress, addr);
+
+    return 0;
+}
+
+
+int qio_dns_resolver_lookup_sync(QIODNSResolver *resolver,
+                                 SocketAddress *addr,
+                                 size_t *naddrs,
+                                 SocketAddress ***addrs,
+                                 Error **errp)
+{
+    switch (addr->type) {
+    case SOCKET_ADDRESS_KIND_INET:
+        return qio_dns_resolver_lookup_sync_inet(resolver,
+                                                 addr,
+                                                 naddrs,
+                                                 addrs,
+                                                 errp);
+
+    case SOCKET_ADDRESS_KIND_UNIX:
+    case SOCKET_ADDRESS_KIND_VSOCK:
+        return qio_dns_resolver_lookup_sync_nop(resolver,
+                                                addr,
+                                                naddrs,
+                                                addrs,
+                                                errp);
+
+    default:
+        error_setg(errp, "Unknown socket address kind");
+        return -1;
+    }
+}
+
+
+struct QIODNSResolverLookupData {
+    SocketAddress *addr;
+    SocketAddress **addrs;
+    size_t naddrs;
+};
+
+
+static void qio_dns_resolver_lookup_data_free(gpointer opaque)
+{
+    struct QIODNSResolverLookupData *data = opaque;
+    size_t i;
+
+    qapi_free_SocketAddress(data->addr);
+    for (i = 0; i < data->naddrs; i++) {
+        qapi_free_SocketAddress(data->addrs[i]);
+    }
+
+    g_free(data->addrs);
+    g_free(data);
+}
+
+
+static void qio_dns_resolver_lookup_worker(QIOTask *task,
+                                           gpointer opaque)
+{
+    QIODNSResolver *resolver = QIO_DNS_RESOLVER(qio_task_get_source(task));
+    struct QIODNSResolverLookupData *data = opaque;
+    Error *err = NULL;
+
+    qio_dns_resolver_lookup_sync(resolver,
+                                 data->addr,
+                                 &data->naddrs,
+                                 &data->addrs,
+                                 &err);
+    if (err) {
+        qio_task_set_error(task, err);
+    } else {
+        qio_task_set_result_pointer(task, opaque, NULL);
+    }
+
+    object_unref(OBJECT(resolver));
+}
+
+
+void qio_dns_resolver_lookup_async(QIODNSResolver *resolver,
+                                   SocketAddress *addr,
+                                   QIOTaskFunc func,
+                                   gpointer opaque,
+                                   GDestroyNotify notify)
+{
+    QIOTask *task;
+    struct QIODNSResolverLookupData *data =
+        g_new0(struct QIODNSResolverLookupData, 1);
+
+    data->addr = QAPI_CLONE(SocketAddress, addr);
+
+    task = qio_task_new(OBJECT(resolver), func, opaque, notify);
+
+    qio_task_run_in_thread(task,
+                           qio_dns_resolver_lookup_worker,
+                           data,
+                           qio_dns_resolver_lookup_data_free);
+}
+
+
+void qio_dns_resolver_lookup_result(QIODNSResolver *resolver,
+                                    QIOTask *task,
+                                    size_t *naddrs,
+                                    SocketAddress ***addrs)
+{
+    struct QIODNSResolverLookupData *data =
+        qio_task_get_result_pointer(task);
+    size_t i;
+
+    *naddrs = 0;
+    *addrs = NULL;
+    if (!data) {
+        return;
+    }
+
+    *naddrs = data->naddrs;
+    *addrs = g_new0(SocketAddress *, data->naddrs);
+    for (i = 0; i < data->naddrs; i++) {
+        (*addrs)[i] = QAPI_CLONE(SocketAddress, data->addrs[i]);
+    }
+}
+
+
+static const TypeInfo qio_dns_resolver_info = {
+    .parent = TYPE_OBJECT,
+    .name = TYPE_QIO_DNS_RESOLVER,
+    .instance_size = sizeof(QIODNSResolver),
+    .class_size = sizeof(QIODNSResolverClass),
+};
+
+
+static void qio_dns_resolver_register_types(void)
+{
+    type_register_static(&qio_dns_resolver_info);
+
+    instance = QIO_DNS_RESOLVER(object_new(TYPE_QIO_DNS_RESOLVER));
+}
+
+
+type_init(qio_dns_resolver_register_types);
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index d63b011..6a0cc24 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -110,8 +110,8 @@ NetworkAddressFamily inet_netfamily(int family)
  * outside scope of this method and not currently handled by
  * callers at all.
  */
-static int inet_ai_family_from_address(InetSocketAddress *addr,
-                                       Error **errp)
+int inet_ai_family_from_address(InetSocketAddress *addr,
+                                Error **errp)
 {
     if (addr->has_ipv6 && addr->has_ipv4 &&
         !addr->ipv6 && !addr->ipv4) {
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/8] sockets: add ability to disable DNS resolution for InetSocketAddress
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 1/8] sockets: add ability to disable DNS resolution for InetSocketAddress Daniel P. Berrange
@ 2017-01-10 14:25   ` Eric Blake
  0 siblings, 0 replies; 12+ messages in thread
From: Eric Blake @ 2017-01-10 14:25 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 681 bytes --]

On 01/09/2017 09:39 AM, Daniel P. Berrange wrote:
> Add a 'numeric' flag to the InetSocketAddress struct to allow the
> caller to indicate that DNS should be skipped for the host/port
> fields. This is useful if the caller knows the address is already
> numeric and wants to guarantee no (potentially blocking) DNS
> lookups are attempted.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  qapi-schema.json    | 5 +++++
>  util/qemu-sockets.c | 3 +++
>  2 files changed, 8 insertions(+)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH v2 5/8] io: add ability to associate an error with a task
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 5/8] io: add ability to associate an error " Daniel P. Berrange
@ 2017-01-10 14:55   ` Eric Blake
  0 siblings, 0 replies; 12+ messages in thread
From: Eric Blake @ 2017-01-10 14:55 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1239 bytes --]

On 01/09/2017 09:39 AM, Daniel P. Berrange wrote:
> Currently when a task fails, the error is never explicitly
> associated with the task object, it is just passed along
> through the completion callback. This adds the ability to
> explicitly associate an error with the task.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  include/io/task.h | 32 ++++++++++++++++++++++++++++++++
>  io/task.c         | 23 +++++++++++++++++++++++
>  2 files changed, 55 insertions(+)
> 

>  /**
> + * qio_task_set_error:
> + * @task: the task struct
> + * @err: pointer to the error, or NULL
> + *
> + * Associate an error with the task, which can later
> + * be retrieved with the qio_task_propagate_error()
> + * method. This method takes ownership of @err, so
> + * it is not valid to access it after this call
> + * completes. If @err is NULL this is a no-op. If
> + * this is call multiple times, only the first

s/call/called/

> + * provided @err will be recorded, later ones will
> + * be discarded and freed.
> + */

With the typo fix,
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Qemu-devel] [PATCH v2 8/8] io: introduce a DNS resolver API
  2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 8/8] io: introduce a DNS resolver API Daniel P. Berrange
@ 2017-01-10 15:01   ` Eric Blake
  0 siblings, 0 replies; 12+ messages in thread
From: Eric Blake @ 2017-01-10 15:01 UTC (permalink / raw)
  To: Daniel P. Berrange, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1427 bytes --]

On 01/09/2017 09:39 AM, Daniel P. Berrange wrote:
> Currently DNS resolution is done automatically as part
> of the creation of a QIOChannelSocket object instance.
> This works ok for network clients where you just end
> up a single network socket, but for servers, the results
> of DNS resolution may require creation of multiple
> sockets.
> 
> Introducing a DNS resolver API allows DNS resolution
> to be separated from the socket object creation. This
> will make it practical to create multiple QIOChannelSocket
> instances for servers.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  include/io/dns-resolver.h | 228 +++++++++++++++++++++++++++++++++++++++
>  include/qemu/sockets.h    |   2 +
>  io/Makefile.objs          |   1 +
>  io/dns-resolver.c         | 267 ++++++++++++++++++++++++++++++++++++++++++++++
>  util/qemu-sockets.c       |   4 +-
>  5 files changed, 500 insertions(+), 2 deletions(-)
>  create mode 100644 include/io/dns-resolver.h
>  create mode 100644 io/dns-resolver.c
> 

> +++ b/io/dns-resolver.c
> @@ -0,0 +1,267 @@
> +/*
> + * QEMU DNS resolver
> + *
> + * Copyright (c) 2016 Red Hat, Inc.

If you want to add 2017, go for it.

Looks like you addressed everything I spotted in v1.
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2017-01-10 15:01 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-09 15:39 [Qemu-devel] [PATCH v2 0/8] io: enable DNS resolving separately of socket create Daniel P. Berrange
2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 1/8] sockets: add ability to disable DNS resolution for InetSocketAddress Daniel P. Berrange
2017-01-10 14:25   ` Eric Blake
2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 2/8] io: stop incrementing reference in qio_task_get_source Daniel P. Berrange
2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 3/8] io: fix typo in docs for QIOTask Daniel P. Berrange
2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 4/8] io: add ability to associate an opaque "result" with with a task Daniel P. Berrange
2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 5/8] io: add ability to associate an error " Daniel P. Berrange
2017-01-10 14:55   ` Eric Blake
2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 6/8] io: change the QIOTask callback signature Daniel P. Berrange
2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 7/8] io: remove Error parameter from QIOTask thread worker Daniel P. Berrange
2017-01-09 15:39 ` [Qemu-devel] [PATCH v2 8/8] io: introduce a DNS resolver API Daniel P. Berrange
2017-01-10 15:01   ` Eric Blake

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.