1 /* vdagent-virtio-port.c virtio port communication code
3 Copyright 2010 Red Hat, Inc.
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/>.
28 #include <sys/select.h>
29 #include <sys/socket.h>
32 #include "vdagent-virtio-port.h"
34 #define VDP_LAST_PORT VDP_SERVER_PORT
36 struct vdagent_virtio_port_buf {
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;
50 VDAgentMessage message_header;
51 uint8_t *message_data;
54 struct vdagent_virtio_port {
59 /* Chunk read stuff, single buffer, separate header and data buffer */
60 int chunk_header_read;
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_LAST_PORT + 1];
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;
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;
88 vport = calloc(1, sizeof(*vport));
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) {
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));
111 vport->read_callback = read_callback;
112 vport->disconnect_callback = disconnect_callback;
117 syslog(LOG_ERR, "open %s: %m", portname);
118 if (vport->fd != -1) {
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;
134 if (vport->disconnect_callback)
135 vport->disconnect_callback(vport);
137 wbuf = vport->write_buf;
139 next_wbuf = wbuf->next;
145 for (i = 0; i <= VDP_LAST_PORT; i++) {
146 free(vport->port_data[i].message_data);
154 int vdagent_virtio_port_fill_fds(struct vdagent_virtio_port *vport,
155 fd_set *readfds, fd_set *writefds)
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)
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;
195 int vdagent_virtio_port_write_start(
196 struct vdagent_virtio_port *vport,
198 uint32_t message_type,
199 uint32_t message_opaque,
202 struct vdagent_virtio_port_buf *wbuf, *new_wbuf;
203 VDIChunkHeader chunk_header;
204 VDAgentMessage message_header;
206 new_wbuf = malloc(sizeof(*new_wbuf));
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) {
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);
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);
234 if (!vport->write_buf) {
235 vport->write_buf = new_wbuf;
239 wbuf = vdagent_virtio_port_get_last_wbuf(vport);
240 wbuf->next = new_wbuf;
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);
252 syslog(LOG_ERR, "can't append without a buffer");
256 if (wbuf->size - wbuf->write_pos < size) {
257 syslog(LOG_ERR, "can't append to full buffer");
261 memcpy(wbuf->buf + wbuf->write_pos, data, size);
262 wbuf->write_pos += size;
266 int vdagent_virtio_port_write(
267 struct vdagent_virtio_port *vport,
269 uint32_t message_type,
270 uint32_t message_opaque,
274 if (vdagent_virtio_port_write_start(vport, port_nr, message_type,
275 message_opaque, data_size)) {
278 vdagent_virtio_port_write_append(vport, data, data_size);
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_LAST_PORT) {
291 syslog(LOG_ERR, "vdagent_virtio_port_reset port out of range");
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) &&
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);
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;
330 syslog(LOG_ERR, "chunk larger then message, lost sync?");
331 vdagent_virtio_port_destroy(vportp);
339 memcpy(port->message_data + port->message_data_pos,
340 vport->chunk_data + pos, read);
341 port->message_data_pos += read;
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);
349 vdagent_virtio_port_destroy(vportp);
353 port->message_header_read = 0;
354 port->message_data_pos = 0;
355 free(port->message_data);
356 port->message_data = NULL;
361 static int vport_read(struct vdagent_virtio_port *vport, uint8_t *buf, int len)
364 return recv(vport->fd, buf, len, 0);
366 return read(vport->fd, buf, len);
370 static void vdagent_virtio_port_do_read(struct vdagent_virtio_port **vportp)
375 struct vdagent_virtio_port *vport = *vportp;
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;
381 to_read = vport->chunk_header.size - vport->chunk_data_pos;
382 dest = vport->chunk_data + vport->chunk_data_pos;
385 n = vport_read(vport, dest, to_read);
389 syslog(LOG_ERR, "reading from vdagent virtio port: %m");
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
401 5) The virtio-console chardev backend sends VIRTIO_CONSOLE_PORT_OPEN
402 to the linux kernel virtio_console driver
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.
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 */
416 vdagent_virtio_port_destroy(vportp);
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);
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);
438 vport->chunk_data_pos += n;
439 if (vport->chunk_data_pos == vport->chunk_header.size) {
440 vdagent_virtio_port_do_chunk(vportp);
443 vport->chunk_header_read = 0;
444 vport->chunk_data_pos = 0;
449 static int vport_write(struct vdagent_virtio_port *vport, uint8_t *buf, int len)
452 return send(vport->fd, buf, len, 0);
454 return write(vport->fd, buf, len);
458 static void vdagent_virtio_port_do_write(struct vdagent_virtio_port **vportp)
462 struct vdagent_virtio_port *vport = *vportp;
464 struct vdagent_virtio_port_buf* wbuf = vport->write_buf;
466 syslog(LOG_ERR, "do_write called on a port without a write buf ?!");
470 if (wbuf->write_pos != wbuf->size) {
471 syslog(LOG_ERR, "do_write: buffer is incomplete!!");
475 to_write = wbuf->size - wbuf->pos;
476 n = vport_write(vport, wbuf->buf + wbuf->pos, to_write);
480 syslog(LOG_ERR, "writing to vdagent virtio port: %m");
481 vdagent_virtio_port_destroy(vportp);
488 if (wbuf->pos == wbuf->size) {
489 vport->write_buf = wbuf->next;