xref: /openbmc/qemu/qga/channel-posix.c (revision 4a09d0bb)
1 #include "qemu/osdep.h"
2 #include <termios.h>
3 #include "qapi/error.h"
4 #include "qemu/sockets.h"
5 #include "qga/channel.h"
6 
7 #ifdef CONFIG_SOLARIS
8 #include <stropts.h>
9 #endif
10 
11 #define GA_CHANNEL_BAUDRATE_DEFAULT B38400 /* for isa-serial channels */
12 
13 struct GAChannel {
14     GIOChannel *listen_channel;
15     GIOChannel *client_channel;
16     GAChannelMethod method;
17     GAChannelCallback event_cb;
18     gpointer user_data;
19 };
20 
21 static int ga_channel_client_add(GAChannel *c, int fd);
22 
23 static gboolean ga_channel_listen_accept(GIOChannel *channel,
24                                          GIOCondition condition, gpointer data)
25 {
26     GAChannel *c = data;
27     int ret, client_fd;
28     bool accepted = false;
29 
30     g_assert(channel != NULL);
31 
32     client_fd = qemu_accept(g_io_channel_unix_get_fd(channel), NULL, NULL);
33     if (client_fd == -1) {
34         g_warning("error converting fd to gsocket: %s", strerror(errno));
35         goto out;
36     }
37     qemu_set_nonblock(client_fd);
38     ret = ga_channel_client_add(c, client_fd);
39     if (ret) {
40         g_warning("error setting up connection");
41         close(client_fd);
42         goto out;
43     }
44     accepted = true;
45 
46 out:
47     /* only accept 1 connection at a time */
48     return !accepted;
49 }
50 
51 /* start polling for readable events on listen fd, new==true
52  * indicates we should use the existing s->listen_channel
53  */
54 static void ga_channel_listen_add(GAChannel *c, int listen_fd, bool create)
55 {
56     if (create) {
57         c->listen_channel = g_io_channel_unix_new(listen_fd);
58     }
59     g_io_add_watch(c->listen_channel, G_IO_IN, ga_channel_listen_accept, c);
60 }
61 
62 static void ga_channel_listen_close(GAChannel *c)
63 {
64     g_assert(c->listen_channel);
65     g_io_channel_shutdown(c->listen_channel, true, NULL);
66     g_io_channel_unref(c->listen_channel);
67     c->listen_channel = NULL;
68 }
69 
70 /* cleanup state for closed connection/session, start accepting new
71  * connections if we're in listening mode
72  */
73 static void ga_channel_client_close(GAChannel *c)
74 {
75     g_assert(c->client_channel);
76     g_io_channel_shutdown(c->client_channel, true, NULL);
77     g_io_channel_unref(c->client_channel);
78     c->client_channel = NULL;
79     if (c->listen_channel) {
80         ga_channel_listen_add(c, 0, false);
81     }
82 }
83 
84 static gboolean ga_channel_client_event(GIOChannel *channel,
85                                         GIOCondition condition, gpointer data)
86 {
87     GAChannel *c = data;
88     gboolean client_cont;
89 
90     g_assert(c);
91     if (c->event_cb) {
92         client_cont = c->event_cb(condition, c->user_data);
93         if (!client_cont) {
94             ga_channel_client_close(c);
95             return false;
96         }
97     }
98     return true;
99 }
100 
101 static int ga_channel_client_add(GAChannel *c, int fd)
102 {
103     GIOChannel *client_channel;
104     GError *err = NULL;
105 
106     g_assert(c && !c->client_channel);
107     client_channel = g_io_channel_unix_new(fd);
108     g_assert(client_channel);
109     g_io_channel_set_encoding(client_channel, NULL, &err);
110     if (err != NULL) {
111         g_warning("error setting channel encoding to binary");
112         g_error_free(err);
113         return -1;
114     }
115     g_io_add_watch(client_channel, G_IO_IN | G_IO_HUP,
116                    ga_channel_client_event, c);
117     c->client_channel = client_channel;
118     return 0;
119 }
120 
121 static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod method)
122 {
123     int ret;
124     c->method = method;
125 
126     switch (c->method) {
127     case GA_CHANNEL_VIRTIO_SERIAL: {
128         int fd = qemu_open(path, O_RDWR | O_NONBLOCK
129 #ifndef CONFIG_SOLARIS
130                            | O_ASYNC
131 #endif
132                            );
133         if (fd == -1) {
134             g_critical("error opening channel: %s", strerror(errno));
135             return false;
136         }
137 #ifdef CONFIG_SOLARIS
138         ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI);
139         if (ret == -1) {
140             g_critical("error setting event mask for channel: %s",
141                        strerror(errno));
142             close(fd);
143             return false;
144         }
145 #endif
146         ret = ga_channel_client_add(c, fd);
147         if (ret) {
148             g_critical("error adding channel to main loop");
149             close(fd);
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             return false;
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_critical("error adding channel to main loop");
180             close(fd);
181             return false;
182         }
183         break;
184     }
185     case GA_CHANNEL_UNIX_LISTEN: {
186         Error *local_err = NULL;
187         int fd = unix_listen(path, NULL, strlen(path), &local_err);
188         if (local_err != NULL) {
189             g_critical("%s", error_get_pretty(local_err));
190             error_free(local_err);
191             return false;
192         }
193         ga_channel_listen_add(c, fd, true);
194         break;
195     }
196     case GA_CHANNEL_VSOCK_LISTEN: {
197         Error *local_err = NULL;
198         SocketAddress *addr;
199         char *addr_str;
200         int fd;
201 
202         addr_str = g_strdup_printf("vsock:%s", path);
203         addr = socket_parse(addr_str, &local_err);
204         g_free(addr_str);
205         if (local_err != NULL) {
206             g_critical("%s", error_get_pretty(local_err));
207             error_free(local_err);
208             return false;
209         }
210 
211         fd = socket_listen(addr, &local_err);
212         qapi_free_SocketAddress(addr);
213         if (local_err != NULL) {
214             g_critical("%s", error_get_pretty(local_err));
215             error_free(local_err);
216             return false;
217         }
218         ga_channel_listen_add(c, fd, true);
219         break;
220     }
221     default:
222         g_critical("error binding/listening to specified socket");
223         return false;
224     }
225 
226     return true;
227 }
228 
229 GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size)
230 {
231     GError *err = NULL;
232     gsize written = 0;
233     GIOStatus status = G_IO_STATUS_NORMAL;
234 
235     while (size) {
236         g_debug("sending data, count: %d", (int)size);
237         status = g_io_channel_write_chars(c->client_channel, buf, size,
238                                           &written, &err);
239         if (status == G_IO_STATUS_NORMAL) {
240             size -= written;
241             buf += written;
242         } else if (status != G_IO_STATUS_AGAIN) {
243             g_warning("error writing to channel: %s", err->message);
244             return status;
245         }
246     }
247 
248     do {
249         status = g_io_channel_flush(c->client_channel, &err);
250     } while (status == G_IO_STATUS_AGAIN);
251 
252     if (status != G_IO_STATUS_NORMAL) {
253         g_warning("error flushing channel: %s", err->message);
254     }
255 
256     return status;
257 }
258 
259 GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count)
260 {
261     return g_io_channel_read_chars(c->client_channel, buf, size, count, NULL);
262 }
263 
264 GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
265                           GAChannelCallback cb, gpointer opaque)
266 {
267     GAChannel *c = g_new0(GAChannel, 1);
268     c->event_cb = cb;
269     c->user_data = opaque;
270 
271     if (!ga_channel_open(c, path, method)) {
272         g_critical("error opening channel");
273         ga_channel_free(c);
274         return NULL;
275     }
276 
277     return c;
278 }
279 
280 void ga_channel_free(GAChannel *c)
281 {
282     if (c->listen_channel) {
283         ga_channel_listen_close(c);
284     }
285     if (c->client_channel) {
286         ga_channel_client_close(c);
287     }
288     g_free(c);
289 }
290