vdagentd: Do endian swapping.
[vd_agent/hramrach.git] / src / vdagentd / virtio-port.c
blobef3de901dcaea504d0c852dade0634f5be5b7674
1 /* vdagent-virtio-port.c virtio port communication code
3 Copyright 2010 Red Hat, Inc.
5 Red Hat Authors:
6 Hans de Goede <hdegoede@redhat.com>
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.
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.
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/>.
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 #include <glib.h>
33 #include "virtio-port.h"
36 struct vdagent_virtio_port_buf {
37 uint8_t *buf;
38 size_t pos;
39 size_t size;
40 size_t write_pos;
42 struct vdagent_virtio_port_buf *next;
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;
54 struct vdagent_virtio_port {
55 int fd;
56 int opening;
57 int is_uds;
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];
65 /* Per chunk port data */
66 struct vdagent_virtio_port_chunk_port_data port_data[VDP_END_PORT];
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;
72 /* Callbacks */
73 vdagent_virtio_port_read_callback read_callback;
74 vdagent_virtio_port_disconnect_callback disconnect_callback;
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);
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)
84 struct vdagent_virtio_port *vport;
85 struct sockaddr_un address;
86 int c;
88 vport = calloc(1, sizeof(*vport));
89 if (!vport)
90 return 0;
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;
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;
106 } else {
107 vport->is_uds = 0;
109 vport->opening = 1;
111 vport->read_callback = read_callback;
112 vport->disconnect_callback = disconnect_callback;
114 return vport;
116 error:
117 syslog(LOG_ERR, "open %s: %m", portname);
118 if (vport->fd != -1) {
119 close(vport->fd);
121 free(vport);
122 return NULL;
125 void vdagent_virtio_port_destroy(struct vdagent_virtio_port **vportp)
127 struct vdagent_virtio_port_buf *wbuf, *next_wbuf;
128 struct vdagent_virtio_port *vport = *vportp;
129 int i;
131 if (!vport)
132 return;
134 if (vport->disconnect_callback)
135 vport->disconnect_callback(vport);
137 wbuf = vport->write_buf;
138 while (wbuf) {
139 next_wbuf = wbuf->next;
140 free(wbuf->buf);
141 free(wbuf);
142 wbuf = next_wbuf;
145 for (i = 0; i < VDP_END_PORT; i++) {
146 free(vport->port_data[i].message_data);
149 close(vport->fd);
150 free(vport);
151 *vportp = NULL;
154 int vdagent_virtio_port_fill_fds(struct vdagent_virtio_port *vport,
155 fd_set *readfds, fd_set *writefds)
157 if (!vport)
158 return -1;
160 FD_SET(vport->fd, readfds);
161 if (vport->write_buf)
162 FD_SET(vport->fd, writefds);
164 return vport->fd + 1;
167 void vdagent_virtio_port_handle_fds(struct vdagent_virtio_port **vportp,
168 fd_set *readfds, fd_set *writefds)
170 if (!*vportp)
171 return;
173 if (FD_ISSET((*vportp)->fd, readfds))
174 vdagent_virtio_port_do_read(vportp);
176 if (*vportp && FD_ISSET((*vportp)->fd, writefds))
177 vdagent_virtio_port_do_write(vportp);
180 static struct vdagent_virtio_port_buf* vdagent_virtio_port_get_last_wbuf(
181 struct vdagent_virtio_port *vport)
183 struct vdagent_virtio_port_buf *wbuf;
185 wbuf = vport->write_buf;
186 if (!wbuf)
187 return NULL;
189 while (wbuf->next)
190 wbuf = wbuf->next;
192 return wbuf;
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)
202 struct vdagent_virtio_port_buf *wbuf, *new_wbuf;
203 VDIChunkHeader chunk_header;
204 VDAgentMessage message_header;
206 new_wbuf = malloc(sizeof(*new_wbuf));
207 if (!new_wbuf)
208 return -1;
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;
220 chunk_header.port = GUINT32_TO_LE(port_nr);
221 chunk_header.size = GUINT32_TO_LE(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);
226 message_header.protocol = GUINT32_TO_LE(VD_AGENT_PROTOCOL);
227 message_header.type = GUINT32_TO_LE(message_type);
228 message_header.opaque = GUINT64_TO_LE(message_opaque);
229 message_header.size = GUINT32_TO_LE(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);
234 if (!vport->write_buf) {
235 vport->write_buf = new_wbuf;
236 return 0;
239 wbuf = vdagent_virtio_port_get_last_wbuf(vport);
240 wbuf->next = new_wbuf;
242 return 0;
245 int vdagent_virtio_port_write_append(struct vdagent_virtio_port *vport,
246 const uint8_t *data, uint32_t size)
248 struct vdagent_virtio_port_buf *wbuf;
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;
256 if (wbuf->size - wbuf->write_pos < size) {
257 syslog(LOG_ERR, "can't append to full buffer");
258 return -1;
261 memcpy(wbuf->buf + wbuf->write_pos, data, size);
262 wbuf->write_pos += size;
263 return 0;
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)
274 if (vdagent_virtio_port_write_start(vport, port_nr, message_type,
275 message_opaque, data_size)) {
276 return -1;
278 vdagent_virtio_port_write_append(vport, data, data_size);
279 return 0;
282 void vdagent_virtio_port_flush(struct vdagent_virtio_port **vportp)
284 while (*vportp && (*vportp)->write_buf)
285 vdagent_virtio_port_do_write(vportp);
288 void vdagent_virtio_port_reset(struct vdagent_virtio_port *vport, int port)
290 if (port >= VDP_END_PORT) {
291 syslog(LOG_ERR, "vdagent_virtio_port_reset port out of range");
292 return;
294 free(vport->port_data[port].message_data);
295 memset(&vport->port_data[port], 0, sizeof(vport->port_data[0]));
298 static void vdagent_virtio_port_do_chunk(struct vdagent_virtio_port **vportp)
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];
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;
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)) {
315 port->message_header.protocol = GUINT32_FROM_LE(port->message_header.protocol);
316 port->message_header.type = GUINT32_FROM_LE(port->message_header.type);
317 port->message_header.opaque = GUINT64_FROM_LE(port->message_header.opaque);
318 port->message_header.size = GUINT32_FROM_LE(port->message_header.size);
320 if (port->message_header.size) {
321 port->message_data = malloc(port->message_header.size);
322 if (!port->message_data) {
323 syslog(LOG_ERR, "out of memory, disconnecting virtio");
324 vdagent_virtio_port_destroy(vportp);
325 return;
329 pos = read;
332 if (port->message_header_read == sizeof(port->message_header)) {
333 read = port->message_header.size - port->message_data_pos;
334 avail = vport->chunk_header.size - pos;
336 if (avail > read) {
337 syslog(LOG_ERR, "chunk larger then message, lost sync?");
338 vdagent_virtio_port_destroy(vportp);
339 return;
342 if (avail < read)
343 read = avail;
345 if (read) {
346 memcpy(port->message_data + port->message_data_pos,
347 vport->chunk_data + pos, read);
348 port->message_data_pos += read;
351 if (port->message_data_pos == port->message_header.size) {
352 if (vport->read_callback) {
353 int r = vport->read_callback(vport, vport->chunk_header.port,
354 &port->message_header, port->message_data);
355 if (r == -1) {
356 vdagent_virtio_port_destroy(vportp);
357 return;
360 port->message_header_read = 0;
361 port->message_data_pos = 0;
362 free(port->message_data);
363 port->message_data = NULL;
368 static int vport_read(struct vdagent_virtio_port *vport, uint8_t *buf, int len)
370 if (vport->is_uds) {
371 return recv(vport->fd, buf, len, 0);
372 } else {
373 return read(vport->fd, buf, len);
377 static void vdagent_virtio_port_do_read(struct vdagent_virtio_port **vportp)
379 ssize_t n;
380 size_t to_read;
381 uint8_t *dest;
382 struct vdagent_virtio_port *vport = *vportp;
384 if (vport->chunk_header_read < sizeof(vport->chunk_header)) {
385 to_read = sizeof(vport->chunk_header) - vport->chunk_header_read;
386 dest = (uint8_t *)&vport->chunk_header + vport->chunk_header_read;
387 } else {
388 to_read = vport->chunk_header.size - vport->chunk_data_pos;
389 dest = vport->chunk_data + vport->chunk_data_pos;
392 n = vport_read(vport, dest, to_read);
393 if (n < 0) {
394 if (errno == EINTR)
395 return;
396 syslog(LOG_ERR, "reading from vdagent virtio port: %m");
398 if (n == 0 && vport->opening) {
399 /* When we open the virtio serial port, the following happens:
400 1) The linux kernel virtio_console driver sends a
401 VIRTIO_CONSOLE_PORT_OPEN message to qemu
402 2) qemu's spicevmc chardev driver calls qemu_spice_add_interface to
403 register the agent chardev with the spice-server
404 3) spice-server then calls the spicevmc chardev driver's state
405 callback to let it know it is ready to receive data
406 4) The state callback sends a CHR_EVENT_OPENED to the virtio-console
407 chardev backend
408 5) The virtio-console chardev backend sends VIRTIO_CONSOLE_PORT_OPEN
409 to the linux kernel virtio_console driver
411 Until steps 1 - 5 have completed the linux kernel virtio_console
412 driver sees the virtio serial port as being in a disconnected state
413 and read will return 0 ! So if we blindly assume that a read 0 means
414 that the channel is closed we will hit a race here.
416 Therefore we ignore read returning 0 until we've successfully read
417 or written some data. If we hit this race we also sleep a bit here
418 to avoid busy waiting until the above steps complete */
419 usleep(10000);
420 return;
422 if (n <= 0) {
423 vdagent_virtio_port_destroy(vportp);
424 return;
426 vport->opening = 0;
428 if (vport->chunk_header_read < sizeof(vport->chunk_header)) {
429 vport->chunk_header_read += n;
430 if (vport->chunk_header_read == sizeof(vport->chunk_header)) {
431 vport->chunk_header.size = GUINT32_FROM_LE(vport->chunk_header.size);
432 vport->chunk_header.port = GUINT32_FROM_LE(vport->chunk_header.port);
433 if (vport->chunk_header.size > VD_AGENT_MAX_DATA_SIZE) {
434 syslog(LOG_ERR, "chunk size %u too large",
435 vport->chunk_header.size);
436 vdagent_virtio_port_destroy(vportp);
437 return;
439 if (vport->chunk_header.port >= VDP_END_PORT) {
440 syslog(LOG_ERR, "chunk port %u out of range",
441 vport->chunk_header.port);
442 vdagent_virtio_port_destroy(vportp);
443 return;
446 } else {
447 vport->chunk_data_pos += n;
448 if (vport->chunk_data_pos == vport->chunk_header.size) {
449 vdagent_virtio_port_do_chunk(vportp);
450 if (!*vportp)
451 return;
452 vport->chunk_header_read = 0;
453 vport->chunk_data_pos = 0;
458 static int vport_write(struct vdagent_virtio_port *vport, uint8_t *buf, int len)
460 if (vport->is_uds) {
461 return send(vport->fd, buf, len, 0);
462 } else {
463 return write(vport->fd, buf, len);
467 static void vdagent_virtio_port_do_write(struct vdagent_virtio_port **vportp)
469 ssize_t n;
470 size_t to_write;
471 struct vdagent_virtio_port *vport = *vportp;
473 struct vdagent_virtio_port_buf* wbuf = vport->write_buf;
474 if (!wbuf) {
475 syslog(LOG_ERR, "do_write called on a port without a write buf ?!");
476 return;
479 if (wbuf->write_pos != wbuf->size) {
480 syslog(LOG_ERR, "do_write: buffer is incomplete!!");
481 return;
484 to_write = wbuf->size - wbuf->pos;
485 n = vport_write(vport, wbuf->buf + wbuf->pos, to_write);
486 if (n < 0) {
487 if (errno == EINTR)
488 return;
489 syslog(LOG_ERR, "writing to vdagent virtio port: %m");
490 vdagent_virtio_port_destroy(vportp);
491 return;
493 if (n > 0)
494 vport->opening = 0;
496 wbuf->pos += n;
497 if (wbuf->pos == wbuf->size) {
498 vport->write_buf = wbuf->next;
499 free(wbuf->buf);
500 free(wbuf);