[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 07 of 15 v4] blktap3/libblktapctl: Introduce tapdisk message exchange functionality
This patch introduces file conrol/tap-ctl-ipc.c, where the functionality of talking to a tapdisk process is implemented. This file is imported from the existing blktap2 implementation, with most changes coming from blktap2 living in github. Signed-off-by: Thanos Makatos <thanos.makatos@xxxxxxxxxx> --- Changed since v2: * Check for unexpected response in tap_ctl_send_and_receive. * If the message has been served but an error occurred, the error in the message is returned by the function in order to simplify error checking/handling by the caller. Changed since v3: * Removed wrong way of checking for errors in order to provide more verbose logging, as not all messages contain an error field. diff --git a/tools/blktap3/control/tap-ctl-ipc.c b/tools/blktap3/control/tap-ctl-ipc.c new file mode 100644 --- /dev/null +++ b/tools/blktap3/control/tap-ctl-ipc.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2008, XenSource Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of XenSource Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/un.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <assert.h> + +#include "tap-ctl.h" +#include "blktap3.h" + +int tap_ctl_debug = 0; + +int +tap_ctl_read_raw(int fd, void *buf, size_t size, struct timeval *timeout) +{ + fd_set readfds; + size_t offset = 0; + int ret; + + while (offset < size) { + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + ret = select(fd + 1, &readfds, NULL, NULL, timeout); + if (ret == -1) + break; + else if (FD_ISSET(fd, &readfds)) { + ret = read(fd, buf + offset, size - offset); + if (ret <= 0) + break; + offset += ret; + } else + break; + } + + if (offset != size) { + EPRINTF("failure reading data %zd/%zd\n", offset, size); + return -EIO; + } + + return 0; +} + +int +tap_ctl_write_message(int fd, tapdisk_message_t * message, + struct timeval *timeout) +{ + fd_set writefds; + int ret, len, offset; + + offset = 0; + len = sizeof(tapdisk_message_t); + + DBG("sending '%s' message (uuid = %u)\n", + tapdisk_message_name(message->type), message->cookie); + + while (offset < len) { + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + + /* we don't bother reinitializing tv. at worst, it will wait a + * bit more time than expected. */ + + ret = select(fd + 1, NULL, &writefds, NULL, timeout); + if (ret == -1) + break; + else if (FD_ISSET(fd, &writefds)) { + ret = write(fd, message + offset, len - offset); + if (ret <= 0) + break; + offset += ret; + } else + break; + } + + if (offset != len) { + EPRINTF("failure writing message\n"); + return -EIO; + } + + return 0; +} + +int +tap_ctl_send_and_receive(const int sfd, tapdisk_message_t * const message, + struct timeval *timeout) +{ + int err; + td_msg_id_t msg_type; + + assert(message); + + msg_type = message->type; + + err = tap_ctl_write_message(sfd, message, timeout); + if (err) { + EPRINTF("failed to send '%s' message\n", + tapdisk_message_name(message->type)); + return err; + } + + err = tap_ctl_read_message(sfd, message, timeout); + if (err) { + /* + * TODO If there are messages for which a response is not required + * and failure to receive a reply is expected, this print is bogus. + */ + EPRINTF("failed to receive '%s' message\n", + tapdisk_message_name(message->type)); + return err; + } + + if (tapdisk_message_is_rsp_paired(msg_type)) { + if (message->type - msg_type != 1) { + err = EINVAL; + EPRINTF("invalid response '%s' to message '%s'\n", + tapdisk_message_name(message->type), + tapdisk_message_name(msg_type)); + } + else + err = 0; + } + + return err; +} + +char * +tap_ctl_socket_name(int id) +{ + char *name; + + if (asprintf(&name, "%s/%s%d", + BLKTAP3_CONTROL_DIR, BLKTAP3_CONTROL_SOCKET, id) == -1) + return NULL; + + return name; +} + +int +tap_ctl_connect(const char *name, int *sfd) +{ + int fd, err; + struct sockaddr_un saddr; + + *sfd = -1; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + EPRINTF("couldn't create socket for %s: %d\n", name, errno); + return -errno; + } + + memset(&saddr, 0, sizeof(saddr)); + saddr.sun_family = AF_UNIX; + strcpy(saddr.sun_path, name); + + err = connect(fd, (const struct sockaddr *)&saddr, sizeof(saddr)); + if (err) { + EPRINTF("couldn't connect to %s: %d\n", name, errno); + close(fd); + return -errno; + } + + *sfd = fd; + return 0; +} + +int +tap_ctl_connect_id(int id, int *sfd) +{ + int err; + char *name; + + *sfd = -1; + + if (id < 0) { + EPRINTF("invalid id %d\n", id); + return -EINVAL; + } + + name = tap_ctl_socket_name(id); + if (!name) { + EPRINTF("couldn't name socket for %d\n", id); + return -ENOMEM; + } + + err = tap_ctl_connect(name, sfd); + free(name); + + return err; +} + +int +tap_ctl_connect_send_and_receive(int id, tapdisk_message_t * message, + struct timeval *timeout) +{ + int err, sfd; + + err = tap_ctl_connect_id(id, &sfd); + if (err) + return err; + + err = tap_ctl_send_and_receive(sfd, message, timeout); + + close(sfd); + return err; +} + +int +tap_ctl_read_message(int fd, tapdisk_message_t * message, + struct timeval *timeout) +{ + size_t size = sizeof(tapdisk_message_t); + int err; + + err = tap_ctl_read_raw(fd, message, size, timeout); + if (err) + return err; + + DBG("received '%s' message (uuid = %u)\n", + tapdisk_message_name(message->type), message->cookie); + + return 0; +} _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |