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