14459bf38SPeter Maydell #include "qemu/osdep.h"
2b9947c9cSMarc-André Lureau #include "qemu/cutils.h"
3125b310eSMichael Roth #include <termios.h>
4da34e65cSMarkus Armbruster #include "qapi/error.h"
51de7afc9SPaolo Bonzini #include "qemu/sockets.h"
6dc03272dSMichael S. Tsirkin #include "channel.h"
7b9947c9cSMarc-André Lureau #include "cutils.h"
8125b310eSMichael Roth
9e61ab1daSAndreas Färber #ifdef CONFIG_SOLARIS
10e61ab1daSAndreas Färber #include <stropts.h>
11e61ab1daSAndreas Färber #endif
12e61ab1daSAndreas Färber
13125b310eSMichael Roth #define GA_CHANNEL_BAUDRATE_DEFAULT B38400 /* for isa-serial channels */
14125b310eSMichael Roth
15125b310eSMichael Roth struct GAChannel {
16125b310eSMichael Roth GIOChannel *listen_channel;
17125b310eSMichael Roth GIOChannel *client_channel;
18125b310eSMichael Roth GAChannelMethod method;
19125b310eSMichael Roth GAChannelCallback event_cb;
20125b310eSMichael Roth gpointer user_data;
21125b310eSMichael Roth };
22125b310eSMichael Roth
23125b310eSMichael Roth static int ga_channel_client_add(GAChannel *c, int fd);
24125b310eSMichael Roth
ga_channel_listen_accept(GIOChannel * channel,GIOCondition condition,gpointer data)25125b310eSMichael Roth static gboolean ga_channel_listen_accept(GIOChannel *channel,
26125b310eSMichael Roth GIOCondition condition, gpointer data)
27125b310eSMichael Roth {
28125b310eSMichael Roth GAChannel *c = data;
29125b310eSMichael Roth int ret, client_fd;
30125b310eSMichael Roth bool accepted = false;
31125b310eSMichael Roth
32125b310eSMichael Roth g_assert(channel != NULL);
33125b310eSMichael Roth
34b8093d38SStefan Hajnoczi client_fd = qemu_accept(g_io_channel_unix_get_fd(channel), NULL, NULL);
35125b310eSMichael Roth if (client_fd == -1) {
36125b310eSMichael Roth g_warning("error converting fd to gsocket: %s", strerror(errno));
37125b310eSMichael Roth goto out;
38125b310eSMichael Roth }
39ff5927baSMarc-André Lureau qemu_socket_set_nonblock(client_fd);
40125b310eSMichael Roth ret = ga_channel_client_add(c, client_fd);
41125b310eSMichael Roth if (ret) {
42125b310eSMichael Roth g_warning("error setting up connection");
4332c16620SMarkus Armbruster close(client_fd);
44125b310eSMichael Roth goto out;
45125b310eSMichael Roth }
46125b310eSMichael Roth accepted = true;
47125b310eSMichael Roth
48125b310eSMichael Roth out:
49125b310eSMichael Roth /* only accept 1 connection at a time */
50125b310eSMichael Roth return !accepted;
51125b310eSMichael Roth }
52125b310eSMichael Roth
53125b310eSMichael Roth /* start polling for readable events on listen fd, new==true
54125b310eSMichael Roth * indicates we should use the existing s->listen_channel
55125b310eSMichael Roth */
ga_channel_listen_add(GAChannel * c,int listen_fd,bool create)56125b310eSMichael Roth static void ga_channel_listen_add(GAChannel *c, int listen_fd, bool create)
57125b310eSMichael Roth {
58125b310eSMichael Roth if (create) {
59125b310eSMichael Roth c->listen_channel = g_io_channel_unix_new(listen_fd);
60125b310eSMichael Roth }
61125b310eSMichael Roth g_io_add_watch(c->listen_channel, G_IO_IN, ga_channel_listen_accept, c);
62125b310eSMichael Roth }
63125b310eSMichael Roth
ga_channel_listen_close(GAChannel * c)64125b310eSMichael Roth static void ga_channel_listen_close(GAChannel *c)
65125b310eSMichael Roth {
66125b310eSMichael Roth g_assert(c->listen_channel);
67125b310eSMichael Roth g_io_channel_shutdown(c->listen_channel, true, NULL);
68125b310eSMichael Roth g_io_channel_unref(c->listen_channel);
69125b310eSMichael Roth c->listen_channel = NULL;
70125b310eSMichael Roth }
71125b310eSMichael Roth
72125b310eSMichael Roth /* cleanup state for closed connection/session, start accepting new
73125b310eSMichael Roth * connections if we're in listening mode
74125b310eSMichael Roth */
ga_channel_client_close(GAChannel * c)75125b310eSMichael Roth static void ga_channel_client_close(GAChannel *c)
76125b310eSMichael Roth {
77125b310eSMichael Roth g_assert(c->client_channel);
78125b310eSMichael Roth g_io_channel_shutdown(c->client_channel, true, NULL);
79125b310eSMichael Roth g_io_channel_unref(c->client_channel);
80125b310eSMichael Roth c->client_channel = NULL;
81f06b2031SStefan Hajnoczi if (c->listen_channel) {
82125b310eSMichael Roth ga_channel_listen_add(c, 0, false);
83125b310eSMichael Roth }
84125b310eSMichael Roth }
85125b310eSMichael Roth
ga_channel_client_event(GIOChannel * channel,GIOCondition condition,gpointer data)86125b310eSMichael Roth static gboolean ga_channel_client_event(GIOChannel *channel,
87125b310eSMichael Roth GIOCondition condition, gpointer data)
88125b310eSMichael Roth {
89125b310eSMichael Roth GAChannel *c = data;
90125b310eSMichael Roth gboolean client_cont;
91125b310eSMichael Roth
92125b310eSMichael Roth g_assert(c);
93125b310eSMichael Roth if (c->event_cb) {
94125b310eSMichael Roth client_cont = c->event_cb(condition, c->user_data);
95125b310eSMichael Roth if (!client_cont) {
96125b310eSMichael Roth ga_channel_client_close(c);
97125b310eSMichael Roth return false;
98125b310eSMichael Roth }
99125b310eSMichael Roth }
100125b310eSMichael Roth return true;
101125b310eSMichael Roth }
102125b310eSMichael Roth
ga_channel_client_add(GAChannel * c,int fd)103125b310eSMichael Roth static int ga_channel_client_add(GAChannel *c, int fd)
104125b310eSMichael Roth {
105125b310eSMichael Roth GIOChannel *client_channel;
106125b310eSMichael Roth GError *err = NULL;
107125b310eSMichael Roth
108125b310eSMichael Roth g_assert(c && !c->client_channel);
109125b310eSMichael Roth client_channel = g_io_channel_unix_new(fd);
110125b310eSMichael Roth g_assert(client_channel);
111125b310eSMichael Roth g_io_channel_set_encoding(client_channel, NULL, &err);
112125b310eSMichael Roth if (err != NULL) {
113125b310eSMichael Roth g_warning("error setting channel encoding to binary");
114125b310eSMichael Roth g_error_free(err);
115125b310eSMichael Roth return -1;
116125b310eSMichael Roth }
117125b310eSMichael Roth g_io_add_watch(client_channel, G_IO_IN | G_IO_HUP,
118125b310eSMichael Roth ga_channel_client_event, c);
119125b310eSMichael Roth c->client_channel = client_channel;
120125b310eSMichael Roth return 0;
121125b310eSMichael Roth }
122125b310eSMichael Roth
ga_channel_open(GAChannel * c,const gchar * path,GAChannelMethod method,int fd,Error ** errp)12326de2296SStefan Hajnoczi static gboolean ga_channel_open(GAChannel *c, const gchar *path,
12487ed8b2cSMarc-André Lureau GAChannelMethod method, int fd, Error **errp)
125125b310eSMichael Roth {
126125b310eSMichael Roth int ret;
127125b310eSMichael Roth c->method = method;
128125b310eSMichael Roth
129125b310eSMichael Roth switch (c->method) {
130125b310eSMichael Roth case GA_CHANNEL_VIRTIO_SERIAL: {
13126de2296SStefan Hajnoczi assert(fd < 0);
132b9947c9cSMarc-André Lureau fd = qga_open_cloexec(
133b9947c9cSMarc-André Lureau path,
134e61ab1daSAndreas Färber #ifndef CONFIG_SOLARIS
135b9947c9cSMarc-André Lureau O_ASYNC |
136e61ab1daSAndreas Färber #endif
137b9947c9cSMarc-André Lureau O_RDWR | O_NONBLOCK,
138b9947c9cSMarc-André Lureau 0
139e61ab1daSAndreas Färber );
140125b310eSMichael Roth if (fd == -1) {
1413845ffffSBjørn Forsman error_setg_errno(errp, errno, "error opening channel '%s'", path);
1427868181fSMarkus Armbruster return false;
143125b310eSMichael Roth }
144e61ab1daSAndreas Färber #ifdef CONFIG_SOLARIS
145e61ab1daSAndreas Färber ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI);
146e61ab1daSAndreas Färber if (ret == -1) {
14787ed8b2cSMarc-André Lureau error_setg_errno(errp, errno, "error setting event mask for channel");
1487868181fSMarkus Armbruster close(fd);
1497868181fSMarkus Armbruster return false;
150e61ab1daSAndreas Färber }
151e61ab1daSAndreas Färber #endif
152c6cd588bSAlexander Ivanov #ifdef __FreeBSD__
153c6cd588bSAlexander Ivanov /*
154c6cd588bSAlexander Ivanov * In the default state channel sends echo of every command to a
155*01dc0651SMichael Tokarev * client. The client program doesn't expect this and raises an
156c6cd588bSAlexander Ivanov * error. Suppress echo by resetting ECHO terminal flag.
157c6cd588bSAlexander Ivanov */
158c6cd588bSAlexander Ivanov struct termios tio;
159c6cd588bSAlexander Ivanov if (tcgetattr(fd, &tio) < 0) {
160c6cd588bSAlexander Ivanov error_setg_errno(errp, errno, "error getting channel termios attrs");
161c6cd588bSAlexander Ivanov close(fd);
162c6cd588bSAlexander Ivanov return false;
163c6cd588bSAlexander Ivanov }
164c6cd588bSAlexander Ivanov tio.c_lflag &= ~ECHO;
165c6cd588bSAlexander Ivanov if (tcsetattr(fd, TCSAFLUSH, &tio) < 0) {
166c6cd588bSAlexander Ivanov error_setg_errno(errp, errno, "error setting channel termios attrs");
167c6cd588bSAlexander Ivanov close(fd);
168c6cd588bSAlexander Ivanov return false;
169c6cd588bSAlexander Ivanov }
170c6cd588bSAlexander Ivanov #endif /* __FreeBSD__ */
171125b310eSMichael Roth ret = ga_channel_client_add(c, fd);
172125b310eSMichael Roth if (ret) {
17387ed8b2cSMarc-André Lureau error_setg(errp, "error adding channel to main loop");
174d4f4a3efSMarkus Armbruster close(fd);
175125b310eSMichael Roth return false;
176125b310eSMichael Roth }
177125b310eSMichael Roth break;
178125b310eSMichael Roth }
179125b310eSMichael Roth case GA_CHANNEL_ISA_SERIAL: {
180125b310eSMichael Roth struct termios tio;
18126de2296SStefan Hajnoczi
18226de2296SStefan Hajnoczi assert(fd < 0);
183b9947c9cSMarc-André Lureau fd = qga_open_cloexec(path, O_RDWR | O_NOCTTY | O_NONBLOCK, 0);
184125b310eSMichael Roth if (fd == -1) {
1853845ffffSBjørn Forsman error_setg_errno(errp, errno, "error opening channel '%s'", path);
1867868181fSMarkus Armbruster return false;
187125b310eSMichael Roth }
188125b310eSMichael Roth tcgetattr(fd, &tio);
189125b310eSMichael Roth /* set up serial port for non-canonical, dumb byte streaming */
190125b310eSMichael Roth tio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP |
191125b310eSMichael Roth INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY |
192125b310eSMichael Roth IMAXBEL);
193125b310eSMichael Roth tio.c_oflag = 0;
194125b310eSMichael Roth tio.c_lflag = 0;
195125b310eSMichael Roth tio.c_cflag |= GA_CHANNEL_BAUDRATE_DEFAULT;
196125b310eSMichael Roth /* 1 available byte min or reads will block (we'll set non-blocking
197125b310eSMichael Roth * elsewhere, else we have to deal with read()=0 instead)
198125b310eSMichael Roth */
199125b310eSMichael Roth tio.c_cc[VMIN] = 1;
200125b310eSMichael Roth tio.c_cc[VTIME] = 0;
201125b310eSMichael Roth /* flush everything waiting for read/xmit, it's garbage at this point */
202125b310eSMichael Roth tcflush(fd, TCIFLUSH);
203125b310eSMichael Roth tcsetattr(fd, TCSANOW, &tio);
204125b310eSMichael Roth ret = ga_channel_client_add(c, fd);
205125b310eSMichael Roth if (ret) {
20687ed8b2cSMarc-André Lureau error_setg(errp, "error adding channel to main loop");
2077868181fSMarkus Armbruster close(fd);
2087868181fSMarkus Armbruster return false;
209125b310eSMichael Roth }
210125b310eSMichael Roth break;
211125b310eSMichael Roth }
212125b310eSMichael Roth case GA_CHANNEL_UNIX_LISTEN: {
21326de2296SStefan Hajnoczi if (fd < 0) {
21487ed8b2cSMarc-André Lureau fd = unix_listen(path, errp);
21587ed8b2cSMarc-André Lureau if (fd < 0) {
216125b310eSMichael Roth return false;
217125b310eSMichael Roth }
21826de2296SStefan Hajnoczi }
219125b310eSMichael Roth ga_channel_listen_add(c, fd, true);
220125b310eSMichael Roth break;
221125b310eSMichael Roth }
222586ef5deSStefan Hajnoczi case GA_CHANNEL_VSOCK_LISTEN: {
22326de2296SStefan Hajnoczi if (fd < 0) {
224586ef5deSStefan Hajnoczi SocketAddress *addr;
225586ef5deSStefan Hajnoczi char *addr_str;
226586ef5deSStefan Hajnoczi
227586ef5deSStefan Hajnoczi addr_str = g_strdup_printf("vsock:%s", path);
22887ed8b2cSMarc-André Lureau addr = socket_parse(addr_str, errp);
229586ef5deSStefan Hajnoczi g_free(addr_str);
23087ed8b2cSMarc-André Lureau if (!addr) {
231586ef5deSStefan Hajnoczi return false;
232586ef5deSStefan Hajnoczi }
233586ef5deSStefan Hajnoczi
23487ed8b2cSMarc-André Lureau fd = socket_listen(addr, 1, errp);
235586ef5deSStefan Hajnoczi qapi_free_SocketAddress(addr);
23687ed8b2cSMarc-André Lureau if (fd < 0) {
237586ef5deSStefan Hajnoczi return false;
238586ef5deSStefan Hajnoczi }
23926de2296SStefan Hajnoczi }
240586ef5deSStefan Hajnoczi ga_channel_listen_add(c, fd, true);
241586ef5deSStefan Hajnoczi break;
242586ef5deSStefan Hajnoczi }
243125b310eSMichael Roth default:
24487ed8b2cSMarc-André Lureau error_setg(errp, "error binding/listening to specified socket");
245125b310eSMichael Roth return false;
246125b310eSMichael Roth }
247125b310eSMichael Roth
248125b310eSMichael Roth return true;
249125b310eSMichael Roth }
250125b310eSMichael Roth
ga_channel_write_all(GAChannel * c,const gchar * buf,gsize size)251125b310eSMichael Roth GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size)
252125b310eSMichael Roth {
253125b310eSMichael Roth GError *err = NULL;
254125b310eSMichael Roth gsize written = 0;
255125b310eSMichael Roth GIOStatus status = G_IO_STATUS_NORMAL;
256125b310eSMichael Roth
257125b310eSMichael Roth while (size) {
258f74df9bfSYuri Pudgorodskiy g_debug("sending data, count: %d", (int)size);
259125b310eSMichael Roth status = g_io_channel_write_chars(c->client_channel, buf, size,
260125b310eSMichael Roth &written, &err);
261f74df9bfSYuri Pudgorodskiy if (status == G_IO_STATUS_NORMAL) {
262125b310eSMichael Roth size -= written;
263f74df9bfSYuri Pudgorodskiy buf += written;
264f74df9bfSYuri Pudgorodskiy } else if (status != G_IO_STATUS_AGAIN) {
265f74df9bfSYuri Pudgorodskiy g_warning("error writing to channel: %s", err->message);
266f74df9bfSYuri Pudgorodskiy return status;
267f74df9bfSYuri Pudgorodskiy }
268125b310eSMichael Roth }
269125b310eSMichael Roth
270f74df9bfSYuri Pudgorodskiy do {
271125b310eSMichael Roth status = g_io_channel_flush(c->client_channel, &err);
272f74df9bfSYuri Pudgorodskiy } while (status == G_IO_STATUS_AGAIN);
273f74df9bfSYuri Pudgorodskiy
274f74df9bfSYuri Pudgorodskiy if (status != G_IO_STATUS_NORMAL) {
275125b310eSMichael Roth g_warning("error flushing channel: %s", err->message);
276125b310eSMichael Roth }
277125b310eSMichael Roth
278125b310eSMichael Roth return status;
279125b310eSMichael Roth }
280125b310eSMichael Roth
ga_channel_read(GAChannel * c,gchar * buf,gsize size,gsize * count)281125b310eSMichael Roth GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count)
282125b310eSMichael Roth {
283125b310eSMichael Roth return g_io_channel_read_chars(c->client_channel, buf, size, count, NULL);
284125b310eSMichael Roth }
285125b310eSMichael Roth
ga_channel_new(GAChannelMethod method,const gchar * path,int listen_fd,GAChannelCallback cb,gpointer opaque)286125b310eSMichael Roth GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
28726de2296SStefan Hajnoczi int listen_fd, GAChannelCallback cb, gpointer opaque)
288125b310eSMichael Roth {
28987ed8b2cSMarc-André Lureau Error *err = NULL;
290f3a06403SMarkus Armbruster GAChannel *c = g_new0(GAChannel, 1);
291125b310eSMichael Roth c->event_cb = cb;
292125b310eSMichael Roth c->user_data = opaque;
293125b310eSMichael Roth
29487ed8b2cSMarc-André Lureau if (!ga_channel_open(c, path, method, listen_fd, &err)) {
29587ed8b2cSMarc-André Lureau g_critical("%s", error_get_pretty(err));
29687ed8b2cSMarc-André Lureau error_free(err);
297125b310eSMichael Roth ga_channel_free(c);
298125b310eSMichael Roth return NULL;
299125b310eSMichael Roth }
300125b310eSMichael Roth
301125b310eSMichael Roth return c;
302125b310eSMichael Roth }
303125b310eSMichael Roth
ga_channel_free(GAChannel * c)304125b310eSMichael Roth void ga_channel_free(GAChannel *c)
305125b310eSMichael Roth {
306f06b2031SStefan Hajnoczi if (c->listen_channel) {
307125b310eSMichael Roth ga_channel_listen_close(c);
308125b310eSMichael Roth }
309125b310eSMichael Roth if (c->client_channel) {
310125b310eSMichael Roth ga_channel_client_close(c);
311125b310eSMichael Roth }
312125b310eSMichael Roth g_free(c);
313125b310eSMichael Roth }
314