|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.