Statistics
| Branch: | Revision:

root / qga / channel-posix.c @ 82b11662

History | View | Annotate | Download (7.4 kB)

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
}