Annotation of qemu/qga/channel-posix.c, revision 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.