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
  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, GAChannelMethod method)
 122{
 123    int ret;
 124    c->method = method;
 125
 126    switch (c->method) {
 127    case GA_CHANNEL_VIRTIO_SERIAL: {
 128        int fd = qemu_open(path, O_RDWR | O_NONBLOCK
 129#ifndef CONFIG_SOLARIS
 130                           | O_ASYNC
 131#endif
 132                           );
 133        if (fd == -1) {
 134            g_critical("error opening channel: %s", strerror(errno));
 135            return false;
 136        }
 137#ifdef CONFIG_SOLARIS
 138        ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI);
 139        if (ret == -1) {
 140            g_critical("error setting event mask for channel: %s",
 141                       strerror(errno));
 142            close(fd);
 143            return false;
 144        }
 145#endif
 146        ret = ga_channel_client_add(c, fd);
 147        if (ret) {
 148            g_critical("error adding channel to main loop");
 149            close(fd);
 150            return false;
 151        }
 152        break;
 153    }
 154    case GA_CHANNEL_ISA_SERIAL: {
 155        struct termios tio;
 156        int fd = qemu_open(path, O_RDWR | O_NOCTTY | O_NONBLOCK);
 157        if (fd == -1) {
 158            g_critical("error opening channel: %s", strerror(errno));
 159            return false;
 160        }
 161        tcgetattr(fd, &tio);
 162        /* set up serial port for non-canonical, dumb byte streaming */
 163        tio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP |
 164                         INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY |
 165                         IMAXBEL);
 166        tio.c_oflag = 0;
 167        tio.c_lflag = 0;
 168        tio.c_cflag |= GA_CHANNEL_BAUDRATE_DEFAULT;
 169        /* 1 available byte min or reads will block (we'll set non-blocking
 170         * elsewhere, else we have to deal with read()=0 instead)
 171         */
 172        tio.c_cc[VMIN] = 1;
 173        tio.c_cc[VTIME] = 0;
 174        /* flush everything waiting for read/xmit, it's garbage at this point */
 175        tcflush(fd, TCIFLUSH);
 176        tcsetattr(fd, TCSANOW, &tio);
 177        ret = ga_channel_client_add(c, fd);
 178        if (ret) {
 179            g_critical("error adding channel to main loop");
 180            close(fd);
 181            return false;
 182        }
 183        break;
 184    }
 185    case GA_CHANNEL_UNIX_LISTEN: {
 186        Error *local_err = NULL;
 187        int fd = unix_listen(path, NULL, strlen(path), &local_err);
 188        if (local_err != NULL) {
 189            g_critical("%s", error_get_pretty(local_err));
 190            error_free(local_err);
 191            return false;
 192        }
 193        ga_channel_listen_add(c, fd, true);
 194        break;
 195    }
 196    case GA_CHANNEL_VSOCK_LISTEN: {
 197        Error *local_err = NULL;
 198        SocketAddress *addr;
 199        char *addr_str;
 200        int fd;
 201
 202        addr_str = g_strdup_printf("vsock:%s", path);
 203        addr = socket_parse(addr_str, &local_err);
 204        g_free(addr_str);
 205        if (local_err != NULL) {
 206            g_critical("%s", error_get_pretty(local_err));
 207            error_free(local_err);
 208            return false;
 209        }
 210
 211        fd = socket_listen(addr, &local_err);
 212        qapi_free_SocketAddress(addr);
 213        if (local_err != NULL) {
 214            g_critical("%s", error_get_pretty(local_err));
 215            error_free(local_err);
 216            return false;
 217        }
 218        ga_channel_listen_add(c, fd, true);
 219        break;
 220    }
 221    default:
 222        g_critical("error binding/listening to specified socket");
 223        return false;
 224    }
 225
 226    return true;
 227}
 228
 229GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size)
 230{
 231    GError *err = NULL;
 232    gsize written = 0;
 233    GIOStatus status = G_IO_STATUS_NORMAL;
 234
 235    while (size) {
 236        g_debug("sending data, count: %d", (int)size);
 237        status = g_io_channel_write_chars(c->client_channel, buf, size,
 238                                          &written, &err);
 239        if (status == G_IO_STATUS_NORMAL) {
 240            size -= written;
 241            buf += written;
 242        } else if (status != G_IO_STATUS_AGAIN) {
 243            g_warning("error writing to channel: %s", err->message);
 244            return status;
 245        }
 246    }
 247
 248    do {
 249        status = g_io_channel_flush(c->client_channel, &err);
 250    } while (status == G_IO_STATUS_AGAIN);
 251
 252    if (status != G_IO_STATUS_NORMAL) {
 253        g_warning("error flushing channel: %s", err->message);
 254    }
 255
 256    return status;
 257}
 258
 259GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count)
 260{
 261    return g_io_channel_read_chars(c->client_channel, buf, size, count, NULL);
 262}
 263
 264GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
 265                          GAChannelCallback cb, gpointer opaque)
 266{
 267    GAChannel *c = g_new0(GAChannel, 1);
 268    c->event_cb = cb;
 269    c->user_data = opaque;
 270
 271    if (!ga_channel_open(c, path, method)) {
 272        g_critical("error opening channel");
 273        ga_channel_free(c);
 274        return NULL;
 275    }
 276
 277    return c;
 278}
 279
 280void ga_channel_free(GAChannel *c)
 281{
 282    if (c->listen_channel) {
 283        ga_channel_listen_close(c);
 284    }
 285    if (c->client_channel) {
 286        ga_channel_client_close(c);
 287    }
 288    g_free(c);
 289}
 290