diff mbox

io: introduce helper for creating channels from file descriptors

Message ID 1454511327-4812-1-git-send-email-berrange@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Daniel P. Berrangé Feb. 3, 2016, 2:55 p.m. UTC
Depending on what object a file descriptor refers to a different
type of IO channel will be needed - either a QIOChannelFile or
a QIOChannelSocket. Introduce a qio_channel_new_fd() method
which will return the appropriate channel implementation.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---

Suggested during review of migration TLS patch series

  https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg00607.html

and will be used by next posting of it.

 include/io/channel-util.h      | 52 ++++++++++++++++++++++++++++++++++++++++++
 io/Makefile.objs               |  1 +
 io/channel-util.c              | 50 ++++++++++++++++++++++++++++++++++++++++
 tests/test-io-channel-file.c   | 22 ++++++++++++++++++
 tests/test-io-channel-socket.c | 21 +++++++++++++++++
 5 files changed, 146 insertions(+)
 create mode 100644 include/io/channel-util.h
 create mode 100644 io/channel-util.c

Comments

Eric Blake Feb. 3, 2016, 4:17 p.m. UTC | #1
On 02/03/2016 07:55 AM, Daniel P. Berrange wrote:
> Depending on what object a file descriptor refers to a different
> type of IO channel will be needed - either a QIOChannelFile or
> a QIOChannelSocket. Introduce a qio_channel_new_fd() method
> which will return the appropriate channel implementation.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
> 
> Suggested during review of migration TLS patch series
> 
>   https://lists.gnu.org/archive/html/qemu-devel/2016-02/msg00607.html
> 
> and will be used by next posting of it.
> 
>  include/io/channel-util.h      | 52 ++++++++++++++++++++++++++++++++++++++++++
>  io/Makefile.objs               |  1 +
>  io/channel-util.c              | 50 ++++++++++++++++++++++++++++++++++++++++
>  tests/test-io-channel-file.c   | 22 ++++++++++++++++++
>  tests/test-io-channel-socket.c | 21 +++++++++++++++++
>  5 files changed, 146 insertions(+)
>  create mode 100644 include/io/channel-util.h
>  create mode 100644 io/channel-util.c
> 
> diff --git a/include/io/channel-util.h b/include/io/channel-util.h
> new file mode 100644
> index 0000000..6fb2baf
> --- /dev/null
> +++ b/include/io/channel-util.h
> @@ -0,0 +1,52 @@
> +/*
> + * QEMU I/O channels utility APIs
> + *
> + * Copyright (c) 2015 Red Hat, Inc.

2016?

> +++ b/io/channel-util.c
> @@ -0,0 +1,50 @@
> +/*
> + * QEMU I/O channels utility APIs
> + *
> + * Copyright (c) 2015 Red Hat, Inc.

and again

Otherwise,
Reviewed-by: Eric Blake <eblake@redhat.com>
diff mbox

Patch

diff --git a/include/io/channel-util.h b/include/io/channel-util.h
new file mode 100644
index 0000000..6fb2baf
--- /dev/null
+++ b/include/io/channel-util.h
@@ -0,0 +1,52 @@ 
+/*
+ * QEMU I/O channels utility APIs
+ *
+ * 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 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_CHANNEL_UTIL_H__
+#define QIO_CHANNEL_UTIL_H__
+
+#include "io/channel.h"
+
+/*
+ * This module provides helper functions that are useful when dealing
+ * with QIOChannel objects
+ */
+
+
+/**
+ * qio_channel_new_fd:
+ * @fd: the file descriptor
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Create a channel for performing I/O on the file
+ * descriptor @fd. The particular subclass of QIOChannel
+ * that is returned will depend on what underlying object
+ * the file descriptor is associated with. It may be either
+ * a QIOChannelSocket or a QIOChannelFile instance. Upon
+ * success, the returned QIOChannel instance will own
+ * the @fd file descriptor, and take responsibility for
+ * closing it when no longer required. On failure, the
+ * caller is responsible for closing @fd.
+ *
+ * Returns: the channel object, or NULL on error
+ */
+QIOChannel *qio_channel_new_fd(int fd,
+                               Error **errp);
+
+#endif /* QIO_CHANNEL_UTIL_H__ */
diff --git a/io/Makefile.objs b/io/Makefile.objs
index 0e3de31..9d8337d 100644
--- a/io/Makefile.objs
+++ b/io/Makefile.objs
@@ -6,4 +6,5 @@  io-obj-y += channel-socket.o
 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 += task.o
diff --git a/io/channel-util.c b/io/channel-util.c
new file mode 100644
index 0000000..0cbfef6
--- /dev/null
+++ b/io/channel-util.c
@@ -0,0 +1,50 @@ 
+/*
+ * QEMU I/O channels utility APIs
+ *
+ * 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 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 "io/channel-util.h"
+#include "io/channel-file.h"
+#include "io/channel-socket.h"
+
+
+static bool fd_is_socket(int fd)
+{
+    int optval;
+    socklen_t optlen;
+    optlen = sizeof(optval);
+    return qemu_getsockopt(fd,
+                           SOL_SOCKET,
+                           SO_TYPE,
+                           (char *)&optval,
+                           &optlen) == 0;
+}
+
+
+QIOChannel *qio_channel_new_fd(int fd,
+                               Error **errp)
+{
+    QIOChannel *ioc;
+
+    if (fd_is_socket(fd)) {
+        ioc = QIO_CHANNEL(qio_channel_socket_new_fd(fd, errp));
+    } else {
+        ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
+    }
+    return ioc;
+}
diff --git a/tests/test-io-channel-file.c b/tests/test-io-channel-file.c
index f276a32..45e6990 100644
--- a/tests/test-io-channel-file.c
+++ b/tests/test-io-channel-file.c
@@ -19,6 +19,7 @@ 
  */
 
 #include "io/channel-file.h"
+#include "io/channel-util.h"
 #include "io-channel-helpers.h"
 
 
@@ -49,6 +50,26 @@  static void test_io_channel_file(void)
 }
 
 
+static void test_io_channel_fd(void)
+{
+    QIOChannel *ioc;
+    int fd = -1;
+
+#define TEST_FILE "tests/test-io-channel-file.txt"
+    fd = open(TEST_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+    g_assert_cmpint(fd, >, -1);
+
+    ioc = qio_channel_new_fd(fd, &error_abort);
+
+    g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
+                    ==,
+                    TYPE_QIO_CHANNEL_FILE);
+
+    unlink(TEST_FILE);
+    object_unref(OBJECT(ioc));
+}
+
+
 #ifndef _WIN32
 static void test_io_channel_pipe(bool async)
 {
@@ -92,6 +113,7 @@  int main(int argc, char **argv)
     g_test_init(&argc, &argv, NULL);
 
     g_test_add_func("/io/channel/file", test_io_channel_file);
+    g_test_add_func("/io/channel/file/fd", test_io_channel_fd);
 #ifndef _WIN32
     g_test_add_func("/io/channel/pipe/sync", test_io_channel_pipe_sync);
     g_test_add_func("/io/channel/pipe/async", test_io_channel_pipe_async);
diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c
index 1a36a3c..e28e40f 100644
--- a/tests/test-io-channel-socket.c
+++ b/tests/test-io-channel-socket.c
@@ -19,6 +19,7 @@ 
  */
 
 #include "io/channel-socket.h"
+#include "io/channel-util.h"
 #include "io-channel-helpers.h"
 #ifdef HAVE_IFADDRS_H
 #include <ifaddrs.h>
@@ -473,6 +474,24 @@  static void test_io_channel_unix_fd_pass(void)
 #endif /* _WIN32 */
 
 
+static void test_io_channel_ipv4_fd(void)
+{
+    QIOChannel *ioc;
+    int fd = -1;
+
+    fd = socket(AF_INET, SOCK_STREAM, 0);
+    g_assert_cmpint(fd, >, -1);
+
+    ioc = qio_channel_new_fd(fd, &error_abort);
+
+    g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
+                    ==,
+                    TYPE_QIO_CHANNEL_SOCKET);
+
+    object_unref(OBJECT(ioc));
+}
+
+
 int main(int argc, char **argv)
 {
     bool has_ipv4, has_ipv6;
@@ -495,6 +514,8 @@  int main(int argc, char **argv)
                         test_io_channel_ipv4_sync);
         g_test_add_func("/io/channel/socket/ipv4-async",
                         test_io_channel_ipv4_async);
+        g_test_add_func("/io/channel/socket/ipv4-fd",
+                        test_io_channel_ipv4_fd);
     }
     if (has_ipv6) {
         g_test_add_func("/io/channel/socket/ipv6-sync",