Commit c767ae62 authored by Daniel P. Berrangé's avatar Daniel P. Berrangé
Browse files

io: introduce helper for creating channels from file descriptors



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.

Reviewed-by: default avatarEric Blake <eblake@redhat.com>
Signed-off-by: default avatarDaniel P. Berrange <berrange@redhat.com>
parent fe81e932
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
/*
 * QEMU I/O channels utility APIs
 *
 * 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/>.
 *
 */

#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__ */
+1 −0
Original line number Diff line number Diff line
@@ -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

io/channel-util.c

0 → 100644
+50 −0
Original line number Diff line number Diff line
/*
 * QEMU I/O channels utility APIs
 *
 * 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 "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;
}
+22 −0
Original line number Diff line number Diff line
@@ -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);
+21 −0
Original line number Diff line number Diff line
@@ -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",