Skip to content

Commit

Permalink
io: introduce helper for creating channels from file descriptors
Browse files Browse the repository at this point in the history
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: Eric Blake <[email protected]>
Signed-off-by: Daniel P. Berrange <[email protected]>
  • Loading branch information
berrange committed Feb 15, 2016
1 parent fe81e93 commit c767ae6
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 0 deletions.
52 changes: 52 additions & 0 deletions include/io/channel-util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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 change: 1 addition & 0 deletions io/Makefile.objs
Original file line number Diff line number Diff line change
Expand Up @@ -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
50 changes: 50 additions & 0 deletions io/channel-util.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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 changes: 22 additions & 0 deletions tests/test-io-channel-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/

#include "io/channel-file.h"
#include "io/channel-util.h"
#include "io-channel-helpers.h"


Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down
21 changes: 21 additions & 0 deletions tests/test-io-channel-socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand All @@ -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",
Expand Down

0 comments on commit c767ae6

Please sign in to comment.