Statistics
| Branch: | Revision:

root / qga / channel-posix.c @ 1de7afc9

History | View | Annotate | Download (7.6 kB)

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