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