uploaded spice-vdagent
[platform/adaptation/emulator/spice-vdagent.git] / src / vdagent-virtio-port.c
1 /*  vdagent-virtio-port.c virtio port communication code
2
3     Copyright 2010 Red Hat, Inc.
4
5     Red Hat Authors:
6     Hans de Goede <hdegoede@redhat.com>
7
8     This program is free software: you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation, either version 3 of the License, or   
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of 
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <syslog.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/select.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31
32 #include "vdagent-virtio-port.h"
33
34 #define VDP_LAST_PORT VDP_SERVER_PORT
35
36 struct vdagent_virtio_port_buf {
37     uint8_t *buf;
38     size_t pos;
39     size_t size;
40     size_t write_pos;
41
42     struct vdagent_virtio_port_buf *next;
43 };
44
45 /* Data to keep track of the assembling of vdagent messages per chunk port,
46    for de-multiplexing the messages */
47 struct vdagent_virtio_port_chunk_port_data {
48     int message_header_read;
49     int message_data_pos;
50     VDAgentMessage message_header;
51     uint8_t *message_data;
52 };
53
54 struct vdagent_virtio_port {
55     int fd;
56     int opening;
57     int is_uds;
58
59     /* Chunk read stuff, single buffer, separate header and data buffer */
60     int chunk_header_read;
61     int chunk_data_pos;
62     VDIChunkHeader chunk_header;
63     uint8_t chunk_data[VD_AGENT_MAX_DATA_SIZE];
64
65     /* Per chunk port data */
66     struct vdagent_virtio_port_chunk_port_data port_data[VDP_LAST_PORT + 1];
67
68     /* Writes are stored in a linked list of buffers, with both the header
69        + data for a single message in 1 buffer. */
70     struct vdagent_virtio_port_buf *write_buf;
71
72     /* Callbacks */
73     vdagent_virtio_port_read_callback read_callback;
74     vdagent_virtio_port_disconnect_callback disconnect_callback;
75 };
76
77 static void vdagent_virtio_port_do_write(struct vdagent_virtio_port **vportp);
78 static void vdagent_virtio_port_do_read(struct vdagent_virtio_port **vportp);
79
80 struct vdagent_virtio_port *vdagent_virtio_port_create(const char *portname,
81     vdagent_virtio_port_read_callback read_callback,
82     vdagent_virtio_port_disconnect_callback disconnect_callback)
83 {
84     struct vdagent_virtio_port *vport;
85     struct sockaddr_un address;
86     int c;
87
88     vport = calloc(1, sizeof(*vport));
89     if (!vport)
90         return 0;
91
92     vport->fd = open(portname, O_RDWR);
93     if (vport->fd == -1) {
94         vport->fd = socket(PF_UNIX, SOCK_STREAM, 0);
95         if (vport->fd == -1) {
96             goto error;
97         }
98         address.sun_family = AF_UNIX;
99         snprintf(address.sun_path, sizeof(address.sun_path), "%s", portname);
100         c = connect(vport->fd, (struct sockaddr *)&address, sizeof(address));
101         if (c == 0) {
102             vport->is_uds = 1;
103         } else {
104             goto error;
105         }
106     } else {
107         vport->is_uds = 0;
108     }
109     vport->opening = 1;
110
111     vport->read_callback = read_callback;
112     vport->disconnect_callback = disconnect_callback;
113
114     return vport;
115
116 error:
117     syslog(LOG_ERR, "open %s: %m", portname);
118     if (vport->fd != -1) {
119         close(vport->fd);
120     }
121     free(vport);
122     return NULL;
123 }
124
125 void vdagent_virtio_port_destroy(struct vdagent_virtio_port **vportp)
126 {
127     struct vdagent_virtio_port_buf *wbuf, *next_wbuf;
128     struct vdagent_virtio_port *vport = *vportp;
129     int i;
130
131     if (!vport)
132         return;
133
134     if (vport->disconnect_callback)
135         vport->disconnect_callback(vport);
136
137     wbuf = vport->write_buf;
138     while (wbuf) {
139         next_wbuf = wbuf->next;
140         free(wbuf->buf);
141         free(wbuf);
142         wbuf = next_wbuf;
143     }
144
145     for (i = 0; i <= VDP_LAST_PORT; i++) {
146         free(vport->port_data[i].message_data);
147     }
148
149     close(vport->fd);
150     free(vport);
151     *vportp = NULL;
152 }
153
154 int vdagent_virtio_port_fill_fds(struct vdagent_virtio_port *vport,
155         fd_set *readfds, fd_set *writefds)
156 {
157     if (!vport)
158         return -1;
159
160     FD_SET(vport->fd, readfds);
161     if (vport->write_buf)
162         FD_SET(vport->fd, writefds);
163
164     return vport->fd + 1;
165 }
166
167 void vdagent_virtio_port_handle_fds(struct vdagent_virtio_port **vportp,
168         fd_set *readfds, fd_set *writefds)
169 {
170     if (!*vportp)
171         return;
172
173     if (FD_ISSET((*vportp)->fd, readfds))
174         vdagent_virtio_port_do_read(vportp);
175
176     if (*vportp && FD_ISSET((*vportp)->fd, writefds))
177         vdagent_virtio_port_do_write(vportp);
178 }
179
180 static struct vdagent_virtio_port_buf* vdagent_virtio_port_get_last_wbuf(
181     struct vdagent_virtio_port *vport)
182 {
183     struct vdagent_virtio_port_buf *wbuf;
184
185     wbuf = vport->write_buf;
186     if (!wbuf)
187         return NULL;
188
189     while (wbuf->next)
190         wbuf = wbuf->next;
191
192     return wbuf;
193 }
194
195 int vdagent_virtio_port_write_start(
196         struct vdagent_virtio_port *vport,
197         uint32_t port_nr,
198         uint32_t message_type,
199         uint32_t message_opaque,
200         uint32_t data_size)
201 {
202     struct vdagent_virtio_port_buf *wbuf, *new_wbuf;
203     VDIChunkHeader chunk_header;
204     VDAgentMessage message_header;
205
206     new_wbuf = malloc(sizeof(*new_wbuf));
207     if (!new_wbuf)
208         return -1;
209
210     new_wbuf->pos = 0;
211     new_wbuf->write_pos = 0;
212     new_wbuf->size = sizeof(chunk_header) + sizeof(message_header) + data_size;
213     new_wbuf->next = NULL;
214     new_wbuf->buf = malloc(new_wbuf->size);
215     if (!new_wbuf->buf) {
216         free(new_wbuf);
217         return -1;
218     }
219
220     chunk_header.port = port_nr;
221     chunk_header.size = sizeof(message_header) + data_size;
222     memcpy(new_wbuf->buf + new_wbuf->write_pos, &chunk_header,
223            sizeof(chunk_header));
224     new_wbuf->write_pos += sizeof(chunk_header);
225     
226     message_header.protocol = VD_AGENT_PROTOCOL;
227     message_header.type = message_type;
228     message_header.opaque = message_opaque;
229     message_header.size = data_size;
230     memcpy(new_wbuf->buf + new_wbuf->write_pos, &message_header,
231            sizeof(message_header));
232     new_wbuf->write_pos += sizeof(message_header);
233
234     if (!vport->write_buf) {
235         vport->write_buf = new_wbuf;
236         return 0;
237     }
238
239     wbuf = vdagent_virtio_port_get_last_wbuf(vport);
240     wbuf->next = new_wbuf;
241
242     return 0;
243 }
244
245 int vdagent_virtio_port_write_append(struct vdagent_virtio_port *vport,
246                                      const uint8_t *data, uint32_t size)
247 {
248     struct vdagent_virtio_port_buf *wbuf;
249
250     wbuf = vdagent_virtio_port_get_last_wbuf(vport);
251     if (!wbuf) {
252         syslog(LOG_ERR, "can't append without a buffer");
253         return -1;
254     }
255
256     if (wbuf->size - wbuf->write_pos < size) {
257         syslog(LOG_ERR, "can't append to full buffer");
258         return -1;
259     }
260
261     memcpy(wbuf->buf + wbuf->write_pos, data, size);
262     wbuf->write_pos += size;
263     return 0;
264 }
265
266 int vdagent_virtio_port_write(
267         struct vdagent_virtio_port *vport,
268         uint32_t port_nr,
269         uint32_t message_type,
270         uint32_t message_opaque,
271         const uint8_t *data,
272         uint32_t data_size)
273 {
274     if (vdagent_virtio_port_write_start(vport, port_nr, message_type,
275                                         message_opaque, data_size)) {
276         return -1;
277     }
278     vdagent_virtio_port_write_append(vport, data, data_size);
279     return 0;
280 }
281
282 void vdagent_virtio_port_flush(struct vdagent_virtio_port **vportp)
283 {
284     while (*vportp && (*vportp)->write_buf)
285         vdagent_virtio_port_do_write(vportp);
286 }
287
288 void vdagent_virtio_port_reset(struct vdagent_virtio_port *vport, int port)
289 {
290     if (port > VDP_LAST_PORT) {
291         syslog(LOG_ERR, "vdagent_virtio_port_reset port out of range");
292         return;
293     }
294     free(vport->port_data[port].message_data);
295     memset(&vport->port_data[port], 0, sizeof(vport->port_data[0]));
296 }
297
298 static void vdagent_virtio_port_do_chunk(struct vdagent_virtio_port **vportp)
299 {
300     int avail, read, pos = 0;
301     struct vdagent_virtio_port *vport = *vportp;
302     struct vdagent_virtio_port_chunk_port_data *port =
303         &vport->port_data[vport->chunk_header.port];
304
305     if (port->message_header_read < sizeof(port->message_header)) {
306         read = sizeof(port->message_header) - port->message_header_read;
307         if (read > vport->chunk_header.size) {
308             read = vport->chunk_header.size;
309         }
310         memcpy((uint8_t *)&port->message_header + port->message_header_read,
311                vport->chunk_data, read);
312         port->message_header_read += read;
313         if (port->message_header_read == sizeof(port->message_header) &&
314                 port->message_header.size) {
315             port->message_data = malloc(port->message_header.size);
316             if (!port->message_data) {
317                 syslog(LOG_ERR, "out of memory, disconnecting virtio");
318                 vdagent_virtio_port_destroy(vportp);
319                 return;
320             }
321         }
322         pos = read;
323     }
324
325     if (port->message_header_read == sizeof(port->message_header)) {
326         read  = port->message_header.size - port->message_data_pos;
327         avail = vport->chunk_header.size - pos;
328
329         if (avail > read) {
330             syslog(LOG_ERR, "chunk larger then message, lost sync?");
331             vdagent_virtio_port_destroy(vportp);
332             return;
333         }
334
335         if (avail < read)
336             read = avail;
337
338         if (read) {
339             memcpy(port->message_data + port->message_data_pos,
340                    vport->chunk_data + pos, read);
341             port->message_data_pos += read;
342         }
343
344         if (port->message_data_pos == port->message_header.size) {
345             if (vport->read_callback) {
346                 int r = vport->read_callback(vport, vport->chunk_header.port,
347                                  &port->message_header, port->message_data);
348                 if (r == -1) {
349                     vdagent_virtio_port_destroy(vportp);
350                     return;
351                 }
352             }
353             port->message_header_read = 0;
354             port->message_data_pos = 0;
355             free(port->message_data);
356             port->message_data = NULL;
357         }
358     }
359 }
360
361 static int vport_read(struct vdagent_virtio_port *vport, uint8_t *buf, int len)
362 {
363     if (vport->is_uds) {
364         return recv(vport->fd, buf, len, 0);
365     } else {
366         return read(vport->fd, buf, len);
367     }
368 }
369
370 static void vdagent_virtio_port_do_read(struct vdagent_virtio_port **vportp)
371 {
372     ssize_t n;
373     size_t to_read;
374     uint8_t *dest;
375     struct vdagent_virtio_port *vport = *vportp;
376
377     if (vport->chunk_header_read < sizeof(vport->chunk_header)) {
378         to_read = sizeof(vport->chunk_header) - vport->chunk_header_read;
379         dest = (uint8_t *)&vport->chunk_header + vport->chunk_header_read;
380     } else {
381         to_read = vport->chunk_header.size - vport->chunk_data_pos;
382         dest = vport->chunk_data + vport->chunk_data_pos;
383     }
384
385     n = vport_read(vport, dest, to_read);
386     if (n < 0) {
387         if (errno == EINTR)
388             return;
389         syslog(LOG_ERR, "reading from vdagent virtio port: %m");
390     }
391     if (n == 0 && vport->opening) {
392         /* When we open the virtio serial port, the following happens:
393            1) The linux kernel virtio_console driver sends a
394               VIRTIO_CONSOLE_PORT_OPEN message to qemu
395            2) qemu's spicevmc chardev driver calls qemu_spice_add_interface to
396               register the agent chardev with the spice-server
397            3) spice-server then calls the spicevmc chardev driver's state
398               callback to let it know it is ready to receive data
399            4) The state callback sends a CHR_EVENT_OPENED to the virtio-console
400               chardev backend
401            5) The virtio-console chardev backend sends VIRTIO_CONSOLE_PORT_OPEN
402               to the linux kernel virtio_console driver
403
404            Until steps 1 - 5 have completed the linux kernel virtio_console
405            driver sees the virtio serial port as being in a disconnected state
406            and read will return 0 ! So if we blindly assume that a read 0 means
407            that the channel is closed we will hit a race here.
408
409            Therefore we ignore read returning 0 until we've successfully read
410            or written some data. If we hit this race we also sleep a bit here
411            to avoid busy waiting until the above steps complete */
412         usleep(10000);
413         return;
414     }
415     if (n <= 0) {
416         vdagent_virtio_port_destroy(vportp);
417         return;
418     }
419     vport->opening = 0;
420
421     if (vport->chunk_header_read < sizeof(vport->chunk_header)) {
422         vport->chunk_header_read += n;
423         if (vport->chunk_header_read == sizeof(vport->chunk_header)) {
424             if (vport->chunk_header.size > VD_AGENT_MAX_DATA_SIZE) {
425                 syslog(LOG_ERR, "chunk size %u too large",
426                        vport->chunk_header.size);
427                 vdagent_virtio_port_destroy(vportp);
428                 return;
429             }
430             if (vport->chunk_header.port > VDP_LAST_PORT) {
431                 syslog(LOG_ERR, "chunk port %u out of range",
432                        vport->chunk_header.port);
433                 vdagent_virtio_port_destroy(vportp);
434                 return;
435             }
436         }
437     } else {
438         vport->chunk_data_pos += n;
439         if (vport->chunk_data_pos == vport->chunk_header.size) {
440             vdagent_virtio_port_do_chunk(vportp);
441             if (!*vportp)
442                 return;
443             vport->chunk_header_read = 0;
444             vport->chunk_data_pos = 0;
445         }
446     }
447 }
448
449 static int vport_write(struct vdagent_virtio_port *vport, uint8_t *buf, int len)
450 {
451     if (vport->is_uds) {
452         return send(vport->fd, buf, len, 0);
453     } else {
454         return write(vport->fd, buf, len);
455     }
456 }
457
458 static void vdagent_virtio_port_do_write(struct vdagent_virtio_port **vportp)
459 {
460     ssize_t n;
461     size_t to_write;
462     struct vdagent_virtio_port *vport = *vportp;
463
464     struct vdagent_virtio_port_buf* wbuf = vport->write_buf;
465     if (!wbuf) {
466         syslog(LOG_ERR, "do_write called on a port without a write buf ?!");
467         return;
468     }
469
470     if (wbuf->write_pos != wbuf->size) {
471         syslog(LOG_ERR, "do_write: buffer is incomplete!!");
472         return;
473     }
474
475     to_write = wbuf->size - wbuf->pos;
476     n = vport_write(vport, wbuf->buf + wbuf->pos, to_write);
477     if (n < 0) {
478         if (errno == EINTR)
479             return;
480         syslog(LOG_ERR, "writing to vdagent virtio port: %m");
481         vdagent_virtio_port_destroy(vportp);
482         return;
483     }
484     if (n > 0)
485         vport->opening = 0;
486
487     wbuf->pos += n;
488     if (wbuf->pos == wbuf->size) {
489         vport->write_buf = wbuf->next;
490         free(wbuf->buf);
491         free(wbuf);
492     }
493 }