qemu/qga/channel-posix.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include <termios.h>
   3#include "qapi/error.h"
   4#include "qemu/sockets.h"
   5#include "qga/channel.h"
   6
   7#ifdef CONFIG_SOLARIS
   8#include <stropts.h>
   9#endif
  10
  11#define GA_CHANNEL_BAUDRATE_DEFAULT B38400 /* for isa-serial channels */
  12
  13struct GAChannel {
  14    GIOChannel *listen_channel;
  15    GIOChannel *client_channel;
  16    GAChannelMethod method;
  17    GAChannelCallback event_cb;
  18    gpointer user_data;
  19};
  20
  21static int ga_channel_client_add(GAChannel *c, int fd);
  22
  23static gboolean ga_channel_listen_accept(GIOChannel *channel,
  24                                         GIOCondition condition, gpointer data)
  25{
  26    GAChannel *c = data;
  27    int ret, client_fd;
  28    bool accepted = false;
  29    struct sockaddr_un addr;
  30    socklen_t addrlen = sizeof(addr);
  31
  32    g_assert(channel != NULL);
  33
  34    client_fd = qemu_accept(g_io_channel_unix_get_fd(channel),
  35                            (struct sockaddr *)&addr, &addrlen);
  36    if (client_fd == -1) {
  37        g_warning("error converting fd to gsocket: %s", strerror(errno));
  38        goto out;
  39    }
  40    qemu_set_nonblock(client_fd);
  41    ret = ga_channel_client_add(c, client_fd);
  42    if (ret) {
  43        g_warning("error setting up connection");
  44        close(client_fd);
  45        goto out;
  46    }
  47    accepted = true;
  48
  49out:
  50    /* only accept 1 connection at a time */
  51    return !accepted;
  52}
  53
  54/* start polling for readable events on listen fd, new==true
  55 * indicates we should use the existing s->listen_channel
  56 */
  57static void ga_channel_listen_add(GAChannel *c, int listen_fd, bool create)
  58{
  59    if (create) {
  60        c->listen_channel = g_io_channel_unix_new(listen_fd);
  61    }
  62    g_io_add_watch(c->listen_channel, G_IO_IN, ga_channel_listen_accept, c);
  63}
  64
  65static void ga_channel_listen_close(GAChannel *c)
  66{
  67    g_assert(c->method == GA_CHANNEL_UNIX_LISTEN);
  68    g_assert(c->listen_channel);
  69    g_io_channel_shutdown(c->listen_channel, true, NULL);
  70    g_io_channel_unref(c->listen_channel);
  71    c->listen_channel = NULL;
  72}
  73
  74/* cleanup state for closed connection/session, start accepting new
  75 * connections if we're in listening mode
  76 */
  77static void ga_channel_client_close(GAChannel *c)
  78{
  79    g_assert(c->client_channel);
  80    g_io_channel_shutdown(c->client_channel, true, NULL);
  81    g_io_channel_unref(c->client_channel);
  82    c->client_channel = NULL;
  83    if (c->method == GA_CHANNEL_UNIX_LISTEN && c->listen_channel) {
  84        ga_channel_listen_add(c, 0, false);
  85    }
  86}
  87
  88static gboolean ga_channel_client_event(GIOChannel *channel,
  89                                        GIOCondition condition, gpointer data)
  90{
  91    GAChannel *c = data;
  92    gboolean client_cont;
  93
  94    g_assert(c);
  95    if (c->event_cb) {
  96        client_cont = c->event_cb(condition, c->user_data);
  97        if (!client_cont) {
  98            ga_channel_client_close(c);
  99            return false;
 100        }
 101    }
 102    return true;
 103}
 104
 105static int ga_channel_client_add(GAChannel *c, int fd)
 106{
 107    GIOChannel *client_channel;
 108    GError *err = NULL;
 109
 110    g_assert(c && !c->client_channel);
 111    client_channel = g_io_channel_unix_new(fd);
 112    g_assert(client_channel);
 113    g_io_channel_set_encoding(client_channel, NULL, &err);
 114    if (err != NULL) {
 115        g_warning("error setting channel encoding to binary");
 116        g_error_free(err);
 117        return -1;
 118    }
 119    g_io_add_watch(client_channel, G_IO_IN | G_IO_HUP,
 120                   ga_channel_client_event, c);
 121    c->client_channel = client_channel;
 122    return 0;
 123}
 124
 125static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod method)
 126{
 127    int ret;
 128    c->method = method;
 129
 130    switch (c->method) {
 131    case GA_CHANNEL_VIRTIO_SERIAL: {
 132        int fd = qemu_open(path, O_RDWR | O_NONBLOCK
 133#ifndef CONFIG_SOLARIS
 134                           | O_ASYNC
 135#endif
 136                           );
 137        if (fd == -1) {
 138            g_critical("error opening channel: %s", strerror(errno));
 139            return false;
 140        }
 141#ifdef CONFIG_SOLARIS
 142        ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI);
 143        if (ret == -1) {
 144            g_critical("error setting event mask for channel: %s",
 145                       strerror(errno));
 146            close(fd);
 147            return false;
 148        }
 149#endif
 150        ret = ga_channel_client_add(c, fd);
 151        if (ret) {
 152            g_critical("error adding channel to main loop");
 153            close(fd);
 154            return false;
 155        }
 156        break;
 157    }
 158    case GA_CHANNEL_ISA_SERIAL: {
 159        struct termios tio;
 160        int fd = qemu_open(path, O_RDWR | O_NOCTTY | O_NONBLOCK);
 161        if (fd == -1) {
 162            g_critical("error opening channel: %s", strerror(errno));
 163            return false;
 164        }
 165        tcgetattr(fd, &tio);
 166        /* set up serial port for non-canonical, dumb byte streaming */
 167        tio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP |
 168                         INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY |
 169                         IMAXBEL);
 170        tio.c_oflag = 0;
 171        tio.c_lflag = 0;
 172        tio.c_cflag |= GA_CHANNEL_BAUDRATE_DEFAULT;
 173        /* 1 available byte min or reads will block (we'll set non-blocking
 174         * elsewhere, else we have to deal with read()=0 instead)
 175         */
 176        tio.c_cc[VMIN] = 1;
 177        tio.c_cc[VTIME] = 0;
 178        /* flush everything waiting for read/xmit, it's garbage at this point */
 179        tcflush(fd, TCIFLUSH);
 180        tcsetattr(fd, TCSANOW, &tio);
 181        ret = ga_channel_client_add(c, fd);
 182        if (ret) {
 183            g_critical("error adding channel to main loop");
 184            close(fd);
 185            return false;
 186        }
 187        break;
 188    }
 189    case GA_CHANNEL_UNIX_LISTEN: {
 190        Error *local_err = NULL;
 191        int fd = unix_listen(path, NULL, strlen(path), &local_err);
 192        if (local_err != NULL) {
 193            g_critical("%s", error_get_pretty(local_err));
 194            error_free(local_err);
 195            return false;
 196        }
 197        ga_channel_listen_add(c, fd, true);
 198        break;
 199    }
 200    default:
 201        g_critical("error binding/listening to specified socket");
 202        return false;
 203    }
 204
 205    return true;
 206}
 207
 208GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size)
 209{
 210    GError *err = NULL;
 211    gsize written = 0;
 212    GIOStatus status = G_IO_STATUS_NORMAL;
 213
 214    while (size) {
 215        g_debug("sending data, count: %d", (int)size);
 216        status = g_io_channel_write_chars(c->client_channel, buf, size,
 217                                          &written, &err);
 218        if (status == G_IO_STATUS_NORMAL) {
 219            size -= written;
 220            buf += written;
 221        } else if (status != G_IO_STATUS_AGAIN) {
 222            g_warning("error writing to channel: %s", err->message);
 223            return status;
 224        }
 225    }
 226
 227    do {
 228        status = g_io_channel_flush(c->client_channel, &err);
 229    } while (status == G_IO_STATUS_AGAIN);
 230
 231    if (status != G_IO_STATUS_NORMAL) {
 232        g_warning("error flushing channel: %s", err->message);
 233    }
 234
 235    return status;
 236}
 237
 238GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count)
 239{
 240    return g_io_channel_read_chars(c->client_channel, buf, size, count, NULL);
 241}
 242
 243GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
 244                          GAChannelCallback cb, gpointer opaque)
 245{
 246    GAChannel *c = g_new0(GAChannel, 1);
 247    c->event_cb = cb;
 248    c->user_data = opaque;
 249
 250    if (!ga_channel_open(c, path, method)) {
 251        g_critical("error opening channel");
 252        ga_channel_free(c);
 253        return NULL;
 254    }
 255
 256    return c;
 257}
 258
 259void ga_channel_free(GAChannel *c)
 260{
 261    if (c->method == GA_CHANNEL_UNIX_LISTEN
 262        && c->listen_channel) {
 263        ga_channel_listen_close(c);
 264    }
 265    if (c->client_channel) {
 266        ga_channel_client_close(c);
 267    }
 268    g_free(c);
 269}
 270