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