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 '%s'", path);
 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#ifdef __FreeBSD__
 153        /*
 154         * In the default state channel sends echo of every command to a
 155         * client. The client programm doesn't expect this and raises an
 156         * error. Suppress echo by resetting ECHO terminal flag.
 157         */
 158        struct termios tio;
 159        if (tcgetattr(fd, &tio) < 0) {
 160            error_setg_errno(errp, errno, "error getting channel termios attrs");
 161            close(fd);
 162            return false;
 163        }
 164        tio.c_lflag &= ~ECHO;
 165        if (tcsetattr(fd, TCSAFLUSH, &tio) < 0) {
 166            error_setg_errno(errp, errno, "error setting channel termios attrs");
 167            close(fd);
 168            return false;
 169        }
 170#endif /* __FreeBSD__ */
 171        ret = ga_channel_client_add(c, fd);
 172        if (ret) {
 173            error_setg(errp, "error adding channel to main loop");
 174            close(fd);
 175            return false;
 176        }
 177        break;
 178    }
 179    case GA_CHANNEL_ISA_SERIAL: {
 180        struct termios tio;
 181
 182        assert(fd < 0);
 183        fd = qga_open_cloexec(path, O_RDWR | O_NOCTTY | O_NONBLOCK, 0);
 184        if (fd == -1) {
 185            error_setg_errno(errp, errno, "error opening channel '%s'", path);
 186            return false;
 187        }
 188        tcgetattr(fd, &tio);
 189        /* set up serial port for non-canonical, dumb byte streaming */
 190        tio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP |
 191                         INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY |
 192                         IMAXBEL);
 193        tio.c_oflag = 0;
 194        tio.c_lflag = 0;
 195        tio.c_cflag |= GA_CHANNEL_BAUDRATE_DEFAULT;
 196        /* 1 available byte min or reads will block (we'll set non-blocking
 197         * elsewhere, else we have to deal with read()=0 instead)
 198         */
 199        tio.c_cc[VMIN] = 1;
 200        tio.c_cc[VTIME] = 0;
 201        /* flush everything waiting for read/xmit, it's garbage at this point */
 202        tcflush(fd, TCIFLUSH);
 203        tcsetattr(fd, TCSANOW, &tio);
 204        ret = ga_channel_client_add(c, fd);
 205        if (ret) {
 206            error_setg(errp, "error adding channel to main loop");
 207            close(fd);
 208            return false;
 209        }
 210        break;
 211    }
 212    case GA_CHANNEL_UNIX_LISTEN: {
 213        if (fd < 0) {
 214            fd = unix_listen(path, errp);
 215            if (fd < 0) {
 216                return false;
 217            }
 218        }
 219        ga_channel_listen_add(c, fd, true);
 220        break;
 221    }
 222    case GA_CHANNEL_VSOCK_LISTEN: {
 223        if (fd < 0) {
 224            SocketAddress *addr;
 225            char *addr_str;
 226
 227            addr_str = g_strdup_printf("vsock:%s", path);
 228            addr = socket_parse(addr_str, errp);
 229            g_free(addr_str);
 230            if (!addr) {
 231                return false;
 232            }
 233
 234            fd = socket_listen(addr, 1, errp);
 235            qapi_free_SocketAddress(addr);
 236            if (fd < 0) {
 237                return false;
 238            }
 239        }
 240        ga_channel_listen_add(c, fd, true);
 241        break;
 242    }
 243    default:
 244        error_setg(errp, "error binding/listening to specified socket");
 245        return false;
 246    }
 247
 248    return true;
 249}
 250
 251GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size)
 252{
 253    GError *err = NULL;
 254    gsize written = 0;
 255    GIOStatus status = G_IO_STATUS_NORMAL;
 256
 257    while (size) {
 258        g_debug("sending data, count: %d", (int)size);
 259        status = g_io_channel_write_chars(c->client_channel, buf, size,
 260                                          &written, &err);
 261        if (status == G_IO_STATUS_NORMAL) {
 262            size -= written;
 263            buf += written;
 264        } else if (status != G_IO_STATUS_AGAIN) {
 265            g_warning("error writing to channel: %s", err->message);
 266            return status;
 267        }
 268    }
 269
 270    do {
 271        status = g_io_channel_flush(c->client_channel, &err);
 272    } while (status == G_IO_STATUS_AGAIN);
 273
 274    if (status != G_IO_STATUS_NORMAL) {
 275        g_warning("error flushing channel: %s", err->message);
 276    }
 277
 278    return status;
 279}
 280
 281GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count)
 282{
 283    return g_io_channel_read_chars(c->client_channel, buf, size, count, NULL);
 284}
 285
 286GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
 287                          int listen_fd, GAChannelCallback cb, gpointer opaque)
 288{
 289    Error *err = NULL;
 290    GAChannel *c = g_new0(GAChannel, 1);
 291    c->event_cb = cb;
 292    c->user_data = opaque;
 293
 294    if (!ga_channel_open(c, path, method, listen_fd, &err)) {
 295        g_critical("%s", error_get_pretty(err));
 296        error_free(err);
 297        ga_channel_free(c);
 298        return NULL;
 299    }
 300
 301    return c;
 302}
 303
 304void ga_channel_free(GAChannel *c)
 305{
 306    if (c->listen_channel) {
 307        ga_channel_listen_close(c);
 308    }
 309    if (c->client_channel) {
 310        ga_channel_client_close(c);
 311    }
 312    g_free(c);
 313}
 314