Annotation of qemu/qga/channel-posix.c, revision 1.1.1.1

1.1       root        1: #include <glib.h>
                      2: #include <termios.h>
                      3: #include "qemu_socket.h"
                      4: #include "qga/channel.h"
                      5: 
                      6: #ifdef CONFIG_SOLARIS
                      7: #include <stropts.h>
                      8: #endif
                      9: 
                     10: #define GA_CHANNEL_BAUDRATE_DEFAULT B38400 /* for isa-serial channels */
                     11: 
                     12: struct GAChannel {
                     13:     GIOChannel *listen_channel;
                     14:     GIOChannel *client_channel;
                     15:     GAChannelMethod method;
                     16:     GAChannelCallback event_cb;
                     17:     gpointer user_data;
                     18: };
                     19: 
                     20: static int ga_channel_client_add(GAChannel *c, int fd);
                     21: 
                     22: static gboolean ga_channel_listen_accept(GIOChannel *channel,
                     23:                                          GIOCondition condition, gpointer data)
                     24: {
                     25:     GAChannel *c = data;
                     26:     int ret, client_fd;
                     27:     bool accepted = false;
                     28:     struct sockaddr_un addr;
                     29:     socklen_t addrlen = sizeof(addr);
                     30: 
                     31:     g_assert(channel != NULL);
                     32: 
                     33:     client_fd = qemu_accept(g_io_channel_unix_get_fd(channel),
                     34:                             (struct sockaddr *)&addr, &addrlen);
                     35:     if (client_fd == -1) {
                     36:         g_warning("error converting fd to gsocket: %s", strerror(errno));
                     37:         goto out;
                     38:     }
                     39:     fcntl(client_fd, F_SETFL, O_NONBLOCK);
                     40:     ret = ga_channel_client_add(c, client_fd);
                     41:     if (ret) {
                     42:         g_warning("error setting up connection");
                     43:         goto out;
                     44:     }
                     45:     accepted = true;
                     46: 
                     47: out:
                     48:     /* only accept 1 connection at a time */
                     49:     return !accepted;
                     50: }
                     51: 
                     52: /* start polling for readable events on listen fd, new==true
                     53:  * indicates we should use the existing s->listen_channel
                     54:  */
                     55: static void ga_channel_listen_add(GAChannel *c, int listen_fd, bool create)
                     56: {
                     57:     if (create) {
                     58:         c->listen_channel = g_io_channel_unix_new(listen_fd);
                     59:     }
                     60:     g_io_add_watch(c->listen_channel, G_IO_IN, ga_channel_listen_accept, c);
                     61: }
                     62: 
                     63: static void ga_channel_listen_close(GAChannel *c)
                     64: {
                     65:     g_assert(c->method == GA_CHANNEL_UNIX_LISTEN);
                     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:  */
                     75: static 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->method == GA_CHANNEL_UNIX_LISTEN && c->listen_channel) {
                     82:         ga_channel_listen_add(c, 0, false);
                     83:     }
                     84: }
                     85: 
                     86: static 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: 
                    103: static 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: 
                    123: static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod method)
                    124: {
                    125:     int ret;
                    126:     c->method = method;
                    127: 
                    128:     switch (c->method) {
                    129:     case GA_CHANNEL_VIRTIO_SERIAL: {
                    130:         int fd = qemu_open(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:             exit(EXIT_FAILURE);
                    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:             exit(EXIT_FAILURE);
                    145:         }
                    146: #endif
                    147:         ret = ga_channel_client_add(c, fd);
                    148:         if (ret) {
                    149:             g_critical("error adding channel to main loop");
                    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:             exit(EXIT_FAILURE);
                    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_error("error adding channel to main loop");
                    180:         }
                    181:         break;
                    182:     }
                    183:     case GA_CHANNEL_UNIX_LISTEN: {
                    184:         int fd = unix_listen(path, NULL, strlen(path));
                    185:         if (fd == -1) {
                    186:             g_critical("error opening path: %s", strerror(errno));
                    187:             return false;
                    188:         }
                    189:         ga_channel_listen_add(c, fd, true);
                    190:         break;
                    191:     }
                    192:     default:
                    193:         g_critical("error binding/listening to specified socket");
                    194:         return false;
                    195:     }
                    196: 
                    197:     return true;
                    198: }
                    199: 
                    200: GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size)
                    201: {
                    202:     GError *err = NULL;
                    203:     gsize written = 0;
                    204:     GIOStatus status = G_IO_STATUS_NORMAL;
                    205: 
                    206:     while (size) {
                    207:         status = g_io_channel_write_chars(c->client_channel, buf, size,
                    208:                                           &written, &err);
                    209:         g_debug("sending data, count: %d", (int)size);
                    210:         if (err != NULL) {
                    211:             g_warning("error writing to channel: %s", err->message);
                    212:             return G_IO_STATUS_ERROR;
                    213:         }
                    214:         if (status != G_IO_STATUS_NORMAL) {
                    215:             break;
                    216:         }
                    217:         size -= written;
                    218:     }
                    219: 
                    220:     if (status == G_IO_STATUS_NORMAL) {
                    221:         status = g_io_channel_flush(c->client_channel, &err);
                    222:         if (err != NULL) {
                    223:             g_warning("error flushing channel: %s", err->message);
                    224:             return G_IO_STATUS_ERROR;
                    225:         }
                    226:     }
                    227: 
                    228:     return status;
                    229: }
                    230: 
                    231: GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count)
                    232: {
                    233:     return g_io_channel_read_chars(c->client_channel, buf, size, count, NULL);
                    234: }
                    235: 
                    236: GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
                    237:                           GAChannelCallback cb, gpointer opaque)
                    238: {
                    239:     GAChannel *c = g_malloc0(sizeof(GAChannel));
                    240:     c->event_cb = cb;
                    241:     c->user_data = opaque;
                    242: 
                    243:     if (!ga_channel_open(c, path, method)) {
                    244:         g_critical("error opening channel");
                    245:         ga_channel_free(c);
                    246:         return NULL;
                    247:     }
                    248: 
                    249:     return c;
                    250: }
                    251: 
                    252: void ga_channel_free(GAChannel *c)
                    253: {
                    254:     if (c->method == GA_CHANNEL_UNIX_LISTEN
                    255:         && c->listen_channel) {
                    256:         ga_channel_listen_close(c);
                    257:     }
                    258:     if (c->client_channel) {
                    259:         ga_channel_client_close(c);
                    260:     }
                    261:     g_free(c);
                    262: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.