]> git.proxmox.com Git - qemu.git/blame - qga/channel-posix.c
Merge branch 'ppc-for-upstream' of git://repo.or.cz/qemu/agraf
[qemu.git] / qga / channel-posix.c
CommitLineData
125b310e
MR
1#include <glib.h>
2#include <termios.h>
4d4922c3
EH
3#include <errno.h>
4#include <unistd.h>
5#include <fcntl.h>
6#include <stdlib.h>
1d57db19 7#include <string.h>
1de7afc9
PB
8#include "qemu/osdep.h"
9#include "qemu/sockets.h"
125b310e
MR
10#include "qga/channel.h"
11
e61ab1da
AF
12#ifdef CONFIG_SOLARIS
13#include <stropts.h>
14#endif
15
125b310e
MR
16#define GA_CHANNEL_BAUDRATE_DEFAULT B38400 /* for isa-serial channels */
17
18struct GAChannel {
19 GIOChannel *listen_channel;
20 GIOChannel *client_channel;
21 GAChannelMethod method;
22 GAChannelCallback event_cb;
23 gpointer user_data;
24};
25
26static int ga_channel_client_add(GAChannel *c, int fd);
27
28static gboolean ga_channel_listen_accept(GIOChannel *channel,
29 GIOCondition condition, gpointer data)
30{
31 GAChannel *c = data;
32 int ret, client_fd;
33 bool accepted = false;
34 struct sockaddr_un addr;
35 socklen_t addrlen = sizeof(addr);
36
37 g_assert(channel != NULL);
38
39 client_fd = qemu_accept(g_io_channel_unix_get_fd(channel),
40 (struct sockaddr *)&addr, &addrlen);
41 if (client_fd == -1) {
42 g_warning("error converting fd to gsocket: %s", strerror(errno));
43 goto out;
44 }
45 fcntl(client_fd, F_SETFL, O_NONBLOCK);
46 ret = ga_channel_client_add(c, client_fd);
47 if (ret) {
48 g_warning("error setting up connection");
49 goto out;
50 }
51 accepted = true;
52
53out:
54 /* only accept 1 connection at a time */
55 return !accepted;
56}
57
58/* start polling for readable events on listen fd, new==true
59 * indicates we should use the existing s->listen_channel
60 */
61static void ga_channel_listen_add(GAChannel *c, int listen_fd, bool create)
62{
63 if (create) {
64 c->listen_channel = g_io_channel_unix_new(listen_fd);
65 }
66 g_io_add_watch(c->listen_channel, G_IO_IN, ga_channel_listen_accept, c);
67}
68
69static void ga_channel_listen_close(GAChannel *c)
70{
71 g_assert(c->method == GA_CHANNEL_UNIX_LISTEN);
72 g_assert(c->listen_channel);
73 g_io_channel_shutdown(c->listen_channel, true, NULL);
74 g_io_channel_unref(c->listen_channel);
75 c->listen_channel = NULL;
76}
77
78/* cleanup state for closed connection/session, start accepting new
79 * connections if we're in listening mode
80 */
81static void ga_channel_client_close(GAChannel *c)
82{
83 g_assert(c->client_channel);
84 g_io_channel_shutdown(c->client_channel, true, NULL);
85 g_io_channel_unref(c->client_channel);
86 c->client_channel = NULL;
87 if (c->method == GA_CHANNEL_UNIX_LISTEN && c->listen_channel) {
88 ga_channel_listen_add(c, 0, false);
89 }
90}
91
92static gboolean ga_channel_client_event(GIOChannel *channel,
93 GIOCondition condition, gpointer data)
94{
95 GAChannel *c = data;
96 gboolean client_cont;
97
98 g_assert(c);
99 if (c->event_cb) {
100 client_cont = c->event_cb(condition, c->user_data);
101 if (!client_cont) {
102 ga_channel_client_close(c);
103 return false;
104 }
105 }
106 return true;
107}
108
109static int ga_channel_client_add(GAChannel *c, int fd)
110{
111 GIOChannel *client_channel;
112 GError *err = NULL;
113
114 g_assert(c && !c->client_channel);
115 client_channel = g_io_channel_unix_new(fd);
116 g_assert(client_channel);
117 g_io_channel_set_encoding(client_channel, NULL, &err);
118 if (err != NULL) {
119 g_warning("error setting channel encoding to binary");
120 g_error_free(err);
121 return -1;
122 }
123 g_io_add_watch(client_channel, G_IO_IN | G_IO_HUP,
124 ga_channel_client_event, c);
125 c->client_channel = client_channel;
126 return 0;
127}
128
129static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod method)
130{
131 int ret;
132 c->method = method;
133
134 switch (c->method) {
135 case GA_CHANNEL_VIRTIO_SERIAL: {
e61ab1da
AF
136 int fd = qemu_open(path, O_RDWR | O_NONBLOCK
137#ifndef CONFIG_SOLARIS
138 | O_ASYNC
139#endif
140 );
125b310e
MR
141 if (fd == -1) {
142 g_critical("error opening channel: %s", strerror(errno));
143 exit(EXIT_FAILURE);
144 }
e61ab1da
AF
145#ifdef CONFIG_SOLARIS
146 ret = ioctl(fd, I_SETSIG, S_OUTPUT | S_INPUT | S_HIPRI);
147 if (ret == -1) {
148 g_critical("error setting event mask for channel: %s",
149 strerror(errno));
150 exit(EXIT_FAILURE);
151 }
152#endif
125b310e
MR
153 ret = ga_channel_client_add(c, fd);
154 if (ret) {
155 g_critical("error adding channel to main loop");
156 return false;
157 }
158 break;
159 }
160 case GA_CHANNEL_ISA_SERIAL: {
161 struct termios tio;
162 int fd = qemu_open(path, O_RDWR | O_NOCTTY | O_NONBLOCK);
163 if (fd == -1) {
164 g_critical("error opening channel: %s", strerror(errno));
165 exit(EXIT_FAILURE);
166 }
167 tcgetattr(fd, &tio);
168 /* set up serial port for non-canonical, dumb byte streaming */
169 tio.c_iflag &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP |
170 INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY |
171 IMAXBEL);
172 tio.c_oflag = 0;
173 tio.c_lflag = 0;
174 tio.c_cflag |= GA_CHANNEL_BAUDRATE_DEFAULT;
175 /* 1 available byte min or reads will block (we'll set non-blocking
176 * elsewhere, else we have to deal with read()=0 instead)
177 */
178 tio.c_cc[VMIN] = 1;
179 tio.c_cc[VTIME] = 0;
180 /* flush everything waiting for read/xmit, it's garbage at this point */
181 tcflush(fd, TCIFLUSH);
182 tcsetattr(fd, TCSANOW, &tio);
183 ret = ga_channel_client_add(c, fd);
184 if (ret) {
185 g_error("error adding channel to main loop");
186 }
187 break;
188 }
189 case GA_CHANNEL_UNIX_LISTEN: {
90119816
PB
190 Error *local_err = NULL;
191 int fd = unix_listen(path, NULL, strlen(path), &local_err);
192 if (local_err != NULL) {
193 g_critical("%s", error_get_pretty(local_err));
194 error_free(local_err);
125b310e
MR
195 return false;
196 }
197 ga_channel_listen_add(c, fd, true);
198 break;
199 }
200 default:
201 g_critical("error binding/listening to specified socket");
202 return false;
203 }
204
205 return true;
206}
207
208GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size)
209{
210 GError *err = NULL;
211 gsize written = 0;
212 GIOStatus status = G_IO_STATUS_NORMAL;
213
214 while (size) {
215 status = g_io_channel_write_chars(c->client_channel, buf, size,
216 &written, &err);
217 g_debug("sending data, count: %d", (int)size);
218 if (err != NULL) {
219 g_warning("error writing to channel: %s", err->message);
220 return G_IO_STATUS_ERROR;
221 }
222 if (status != G_IO_STATUS_NORMAL) {
223 break;
224 }
225 size -= written;
226 }
227
228 if (status == G_IO_STATUS_NORMAL) {
229 status = g_io_channel_flush(c->client_channel, &err);
230 if (err != NULL) {
231 g_warning("error flushing channel: %s", err->message);
232 return G_IO_STATUS_ERROR;
233 }
234 }
235
236 return status;
237}
238
239GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count)
240{
241 return g_io_channel_read_chars(c->client_channel, buf, size, count, NULL);
242}
243
244GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,
245 GAChannelCallback cb, gpointer opaque)
246{
247 GAChannel *c = g_malloc0(sizeof(GAChannel));
248 c->event_cb = cb;
249 c->user_data = opaque;
250
251 if (!ga_channel_open(c, path, method)) {
252 g_critical("error opening channel");
253 ga_channel_free(c);
254 return NULL;
255 }
256
257 return c;
258}
259
260void ga_channel_free(GAChannel *c)
261{
262 if (c->method == GA_CHANNEL_UNIX_LISTEN
263 && c->listen_channel) {
264 ga_channel_listen_close(c);
265 }
266 if (c->client_channel) {
267 ga_channel_client_close(c);
268 }
269 g_free(c);
270}