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 "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
  30    g_assert(channel != NULL);
  31
  32    client_fd = qemu_accept(g_io_channel_unix_get_fd(channel), NULL, NULL);
  33    if (client_fd == -1) {
  34        g_warning("error converting fd to gsocket: %s", strerror(errno));
  35        goto out;
  36    }
  37    qemu_set_nonblock(client_fd);
  38    ret = ga_channel_client_add(c, client_fd);
  39    if (ret) {
  40        g_warning("error setting up connection");
  41        close(client_fd);
  42        goto out;
  43    }
  44    accepted = true;
  45
  46out:
  47    /* only accept 1 connection at a time */
  48    return !accepted;
  49}
  50
  51/* start polling for readable events on listen fd, new==true
  52 * indicates we should use the existing s->listen_channel
  53 */
  54static void ga_channel_listen_add(GAChannel *c, int listen_fd, bool create)
  55{
  56    if (create) {
  57        c->listen_channel = g_io_channel_unix_new(listen_fd);
  58    }
  59    g_io_add_watch(c->listen_channel, G_IO_IN, ga_channel_listen_accept, c);
  60}
  61
  62static void ga_channel_listen_close(GAChannel *c)
  63{
  64    g_assert(c->listen_channel);
  65    g_io_channel_shutdown(c->listen_channel, true, NULL);
  66    g_io_channel_unref(c->listen_channel);
  67    c->listen_channel = NULL;
  68}
  69
  70/* cleanup state for closed connection/session, start accepting new
  71 * connections if we're in listening mode
  72 */
  73static void ga_channel_client_close(GAChannel *c)
  74{
  75    g_assert(c->client_channel);
  76    g_io_channel_shutdown(c->client_channel, true, NULL);
  77    g_io_channel_unref(c->client_channel);
  78    c->client_channel = NULL;
  79    if (c->listen_channel) {
  80        ga_channel_listen_add(c, 0, false);
  81    }
  82}
  83
  84static gboolean ga_channel_client_event(GIOChannel *channel,
  85                                        GIOCondition condition, gpointer data)
  86{
  87    GAChannel *c = data;
  88    gboolean client_cont;
  89
  90    g_assert(c);
  91    if (c->event_cb) {
  92        client_cont = c->event_cb(condition, c->user_data);
  93        if (!client_cont) {
  94            ga_channel_client_close(c);
  95            return false;
  96        }
  97    }
  98    return true;
  99}
 100
 101static int ga_channel_client_add(GAChannel *c, int fd)
 102{
 103    GIOChannel *client_channel;
 104    GError *err = NULL;
 105
 106    g_assert(c && !c->client_channel);
 107    client_channel = g_io_channel_unix_new(fd);
 108    g_assert(client_channel);
 109    g_io_channel_set_encoding(client_channel, NULL, &err);
 110    if (err != NULL) {
 111        g_warning("error setting channel encoding to binary");
 112        g_error_free(err);
 113        return -1;
 114    }
 115    g_io_add_watch(client_channel, G_IO_IN | G_IO_HUP,
 116                   ga_channel_client_event, c);
 117    c->client_channel = client_channel;
 118    return 0;
 119}
 120
 121static gboolean ga_channel_open(GAChannel *c, const gchar *path,
 122                                GAChannelMethod method, int fd)
 123{
 124    int ret;
 125    c->method = method;
 126
 127    switch (c->method) {
 128    case GA_CHANNEL_VIRTIO_SERIAL: {
 129        assert(fd < 0);
 130        fd = qemu_open_old(path, O_RDWR | O_NONBLOCK
 131#ifndef CONFIG_SOLARIS
 132                           | O_ASYNC
 133#endif
 134                           );
 135        if (fd == -1) {
 136            g_critical("error opening channel: %s", strerror(errno));
 137            return false;
 138        }
 139#ifdef CONFIG_SOLARIS
 140        ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI);
 141        if (ret == -1) {
 142            g_critical("error setting event mask for channel: %s",
 143                       strerror(errno));
 144            close(fd);
 145            return false;
 146        }
 147#endif
 148        ret = ga_channel_client_add(c, fd);
 149        if (ret) {
 150            g_critical("error adding channel to main loop");
 151            close(fd);
 152            return false;
 153        }
 154        break;
 155    }
 156    case GA_CHANNEL_ISA_SERIAL: {
 157        struct termios tio;
 158
 159        assert(fd < 0);
 160        fd = qemu_open_old(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        if (fd < 0) {
 191            Error *local_err = NULL;
 192
 193            fd = unix_listen(path, &local_err);
 194            if (local_err != NULL) {
 195                g_critical("%s", error_get_pretty(local_err));
 196                error_free(local_err);
 197                return false;
 198            }
 199        }
 200        ga_channel_listen_add(c, fd, true);
 201        break;
 202    }
 203    case GA_CHANNEL_VSOCK_LISTEN: {
 204        if (fd < 0) {
 205            Error *local_err = NULL;
 206            SocketAddress *addr;
 207            char *addr_str;
 208
 209            addr_str = g_strdup_printf("vsock:%s", path);
 210            addr = socket_parse(addr_str, &local_err);
 211            g_free(addr_str);
 212            if (local_err != NULL) {
 213                g_critical("%s", error_get_pretty(local_err));
 214                error_free(local_err);
 215                return false;
 216            }
 217
 218            fd = socket_listen(addr, 1, &local_err);
 219            qapi_free_SocketAddress(addr);
 220            if (local_err != NULL) {
 221                g_critical("%s", error_get_pretty(local_err));
 222                error_free(local_err);
 223                return false;
 224            }
 225        }
 226        ga_channel_listen_add(c, fd, true);
 227        break;
 228    }
 229    default:
 230        g_critical("error binding/listening to specified socket");
 231        return false;
 232    }
 233
 234    return true;
 235}
 236
 237GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size)
 238{
 239    GError *err = NULL;
 240    gsize written = 0;
 241    GIOStatus status = G_IO_STATUS_NORMAL;
 242
 243    while (size) {
 244        g_debug("sending data, count: %d", (int)size);
 245        status = g_io_channel_write_chars(c->client_channel, buf, size,
 246                                          &written, &err);
 247        if (status == G_IO_STATUS_NORMAL) {
 248            size -= written;
 249            buf += written;
 250        } else if (status != G_IO_STATUS_AGAIN) {
 251            g_warning("error writing to channel: %s", err->message);
 252            return status;
 253        }
 254    }
 255
 256    do {
 257        status = g_io_channel_flush(c->client_channel, &err);
 258    } while (status == G_IO_STATUS_AGAIN);
 259
 260    if (status != G_IO_STATUS_NORMAL) {
 261        g_warning("error flushing channel: %s", err->message);
 262    }
 263
 264    return status;
 265}
 266
 267GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count)
 268{
 269    return g_io_channel_read_chars(c->client_channel, buf, size, count, NULL);
 270}
 271
 272GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
 273                          int listen_fd, GAChannelCallback cb, gpointer opaque)
 274{
 275    GAChannel *c = g_new0(GAChannel, 1);
 276    c->event_cb = cb;
 277    c->user_data = opaque;
 278
 279    if (!ga_channel_open(c, path, method, listen_fd)) {
 280        g_critical("error opening channel");
 281        ga_channel_free(c);
 282        return NULL;
 283    }
 284
 285    return c;
 286}
 287
 288void ga_channel_free(GAChannel *c)
 289{
 290    if (c->listen_channel) {
 291        ga_channel_listen_close(c);
 292    }
 293    if (c->client_channel) {
 294        ga_channel_client_close(c);
 295    }
 296    g_free(c);
 297}
 298