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 "vdagent-virtio-port.h"
31 #define VDP_LAST_PORT VDP_SERVER_PORT
33 struct vdagent_virtio_port_buf
{
39 struct vdagent_virtio_port_buf
*next
;
42 /* Data to keep track of the assembling of vdagent messages per chunk port,
43 for de-multiplexing the messages */
44 struct vdagent_virtio_port_chunk_port_data
{
45 int message_header_read
;
47 VDAgentMessage message_header
;
48 uint8_t *message_data
;
51 struct vdagent_virtio_port
{
55 /* Chunk read stuff, single buffer, separate header and data buffer */
56 int chunk_header_read
;
58 VDIChunkHeader chunk_header
;
59 uint8_t chunk_data
[VD_AGENT_MAX_DATA_SIZE
];
61 /* Per chunk port data */
62 struct vdagent_virtio_port_chunk_port_data port_data
[VDP_LAST_PORT
+ 1];
64 /* Writes are stored in a linked list of buffers, with both the header
65 + data for a single message in 1 buffer. */
66 struct vdagent_virtio_port_buf
*write_buf
;
69 vdagent_virtio_port_read_callback read_callback
;
70 vdagent_virtio_port_disconnect_callback disconnect_callback
;
73 static void vdagent_virtio_port_do_write(struct vdagent_virtio_port
**vportp
);
74 static void vdagent_virtio_port_do_read(struct vdagent_virtio_port
**vportp
);
76 struct vdagent_virtio_port
*vdagent_virtio_port_create(const char *portname
,
77 vdagent_virtio_port_read_callback read_callback
,
78 vdagent_virtio_port_disconnect_callback disconnect_callback
)
80 struct vdagent_virtio_port
*vport
;
82 vport
= calloc(1, sizeof(*vport
));
86 vport
->fd
= open(portname
, O_RDWR
);
87 if (vport
->fd
== -1) {
88 syslog(LOG_ERR
, "open %s: %m", portname
);
94 vport
->read_callback
= read_callback
;
95 vport
->disconnect_callback
= disconnect_callback
;
100 void vdagent_virtio_port_destroy(struct vdagent_virtio_port
**vportp
)
102 struct vdagent_virtio_port_buf
*wbuf
, *next_wbuf
;
103 struct vdagent_virtio_port
*vport
= *vportp
;
109 if (vport
->disconnect_callback
)
110 vport
->disconnect_callback(vport
);
112 wbuf
= vport
->write_buf
;
114 next_wbuf
= wbuf
->next
;
120 for (i
= 0; i
<= VDP_LAST_PORT
; i
++) {
121 free(vport
->port_data
[i
].message_data
);
129 int vdagent_virtio_port_fill_fds(struct vdagent_virtio_port
*vport
,
130 fd_set
*readfds
, fd_set
*writefds
)
135 FD_SET(vport
->fd
, readfds
);
136 if (vport
->write_buf
)
137 FD_SET(vport
->fd
, writefds
);
139 return vport
->fd
+ 1;
142 void vdagent_virtio_port_handle_fds(struct vdagent_virtio_port
**vportp
,
143 fd_set
*readfds
, fd_set
*writefds
)
148 if (FD_ISSET((*vportp
)->fd
, readfds
))
149 vdagent_virtio_port_do_read(vportp
);
151 if (*vportp
&& FD_ISSET((*vportp
)->fd
, writefds
))
152 vdagent_virtio_port_do_write(vportp
);
155 static struct vdagent_virtio_port_buf
* vdagent_virtio_port_get_last_wbuf(
156 struct vdagent_virtio_port
*vport
)
158 struct vdagent_virtio_port_buf
*wbuf
;
160 wbuf
= vport
->write_buf
;
170 int vdagent_virtio_port_write_start(
171 struct vdagent_virtio_port
*vport
,
173 uint32_t message_type
,
174 uint32_t message_opaque
,
177 struct vdagent_virtio_port_buf
*wbuf
, *new_wbuf
;
178 VDIChunkHeader chunk_header
;
179 VDAgentMessage message_header
;
181 new_wbuf
= malloc(sizeof(*new_wbuf
));
186 new_wbuf
->write_pos
= 0;
187 new_wbuf
->size
= sizeof(chunk_header
) + sizeof(message_header
) + data_size
;
188 new_wbuf
->next
= NULL
;
189 new_wbuf
->buf
= malloc(new_wbuf
->size
);
190 if (!new_wbuf
->buf
) {
195 chunk_header
.port
= port_nr
;
196 chunk_header
.size
= sizeof(message_header
) + data_size
;
197 memcpy(new_wbuf
->buf
+ new_wbuf
->write_pos
, &chunk_header
,
198 sizeof(chunk_header
));
199 new_wbuf
->write_pos
+= sizeof(chunk_header
);
201 message_header
.protocol
= VD_AGENT_PROTOCOL
;
202 message_header
.type
= message_type
;
203 message_header
.opaque
= message_opaque
;
204 message_header
.size
= data_size
;
205 memcpy(new_wbuf
->buf
+ new_wbuf
->write_pos
, &message_header
,
206 sizeof(message_header
));
207 new_wbuf
->write_pos
+= sizeof(message_header
);
209 if (!vport
->write_buf
) {
210 vport
->write_buf
= new_wbuf
;
214 wbuf
= vdagent_virtio_port_get_last_wbuf(vport
);
215 wbuf
->next
= new_wbuf
;
220 int vdagent_virtio_port_write_append(struct vdagent_virtio_port
*vport
,
221 const uint8_t *data
, uint32_t size
)
223 struct vdagent_virtio_port_buf
*wbuf
;
225 wbuf
= vdagent_virtio_port_get_last_wbuf(vport
);
227 syslog(LOG_ERR
, "can't append without a buffer");
231 if (wbuf
->size
- wbuf
->write_pos
< size
) {
232 syslog(LOG_ERR
, "can't append to full buffer");
236 memcpy(wbuf
->buf
+ wbuf
->write_pos
, data
, size
);
237 wbuf
->write_pos
+= size
;
241 int vdagent_virtio_port_write(
242 struct vdagent_virtio_port
*vport
,
244 uint32_t message_type
,
245 uint32_t message_opaque
,
249 if (vdagent_virtio_port_write_start(vport
, port_nr
, message_type
,
250 message_opaque
, data_size
)) {
253 vdagent_virtio_port_write_append(vport
, data
, data_size
);
257 void vdagent_virtio_port_flush(struct vdagent_virtio_port
**vportp
)
259 while (*vportp
&& (*vportp
)->write_buf
)
260 vdagent_virtio_port_do_write(vportp
);
263 static void vdagent_virtio_port_do_chunk(struct vdagent_virtio_port
**vportp
)
265 int avail
, read
, pos
= 0;
266 struct vdagent_virtio_port
*vport
= *vportp
;
267 struct vdagent_virtio_port_chunk_port_data
*port
=
268 &vport
->port_data
[vport
->chunk_header
.port
];
270 if (port
->message_header_read
< sizeof(port
->message_header
)) {
271 read
= sizeof(port
->message_header
) - port
->message_header_read
;
272 if (read
> vport
->chunk_header
.size
) {
273 read
= vport
->chunk_header
.size
;
275 memcpy((uint8_t *)&port
->message_header
+ port
->message_header_read
,
276 vport
->chunk_data
, read
);
277 port
->message_header_read
+= read
;
278 if (port
->message_header_read
== sizeof(port
->message_header
) &&
279 port
->message_header
.size
) {
280 port
->message_data
= malloc(port
->message_header
.size
);
281 if (!port
->message_data
) {
282 syslog(LOG_ERR
, "out of memory, disconnecting virtio");
283 vdagent_virtio_port_destroy(vportp
);
290 if (port
->message_header_read
== sizeof(port
->message_header
)) {
291 read
= port
->message_header
.size
- port
->message_data_pos
;
292 avail
= vport
->chunk_header
.size
- pos
;
295 syslog(LOG_ERR
, "chunk larger then message, lost sync?");
296 vdagent_virtio_port_destroy(vportp
);
304 memcpy(port
->message_data
+ port
->message_data_pos
,
305 vport
->chunk_data
+ pos
, read
);
306 port
->message_data_pos
+= read
;
309 if (port
->message_data_pos
== port
->message_header
.size
) {
310 if (vport
->read_callback
) {
311 int r
= vport
->read_callback(vport
, vport
->chunk_header
.port
,
312 &port
->message_header
, port
->message_data
);
314 vdagent_virtio_port_destroy(vportp
);
318 port
->message_header_read
= 0;
319 port
->message_data_pos
= 0;
320 free(port
->message_data
);
321 port
->message_data
= NULL
;
326 static void vdagent_virtio_port_do_read(struct vdagent_virtio_port
**vportp
)
331 struct vdagent_virtio_port
*vport
= *vportp
;
333 if (vport
->chunk_header_read
< sizeof(vport
->chunk_header
)) {
334 to_read
= sizeof(vport
->chunk_header
) - vport
->chunk_header_read
;
335 dest
= (uint8_t *)&vport
->chunk_header
+ vport
->chunk_header_read
;
337 to_read
= vport
->chunk_header
.size
- vport
->chunk_data_pos
;
338 dest
= vport
->chunk_data
+ vport
->chunk_data_pos
;
341 n
= read(vport
->fd
, dest
, to_read
);
345 syslog(LOG_ERR
, "reading from vdagent virtio port: %m");
347 if (n
== 0 && vport
->opening
) {
348 /* When we open the virtio serial port, the following happens:
349 1) The linux kernel virtio_console driver sends a
350 VIRTIO_CONSOLE_PORT_OPEN message to qemu
351 2) qemu's spicevmc chardev driver calls qemu_spice_add_interface to
352 register the agent chardev with the spice-server
353 3) spice-server then calls the spicevmc chardev driver's state
354 callback to let it know it is ready to receive data
355 4) The state callback sends a CHR_EVENT_OPENED to the virtio-console
357 5) The virtio-console chardev backend sends VIRTIO_CONSOLE_PORT_OPEN
358 to the linux kernel virtio_console driver
360 Until steps 1 - 5 have completed the linux kernel virtio_console
361 driver sees the virtio serial port as being in a disconnected state
362 and read will return 0 ! So if we blindly assume that a read 0 means
363 that the channel is closed we will hit a race here.
365 Therefore we ignore read returning 0 until we've successfully read
366 or written some data. If we hit this race we also sleep a bit here
367 to avoid busy waiting until the above steps complete */
372 vdagent_virtio_port_destroy(vportp
);
377 if (vport
->chunk_header_read
< sizeof(vport
->chunk_header
)) {
378 vport
->chunk_header_read
+= n
;
379 if (vport
->chunk_header_read
== sizeof(vport
->chunk_header
)) {
380 if (vport
->chunk_header
.size
> VD_AGENT_MAX_DATA_SIZE
) {
381 syslog(LOG_ERR
, "chunk size too large");
382 vdagent_virtio_port_destroy(vportp
);
385 if (vport
->chunk_header
.port
> VDP_LAST_PORT
) {
386 syslog(LOG_ERR
, "chunk port out of range");
387 vdagent_virtio_port_destroy(vportp
);
392 vport
->chunk_data_pos
+= n
;
393 if (vport
->chunk_data_pos
== vport
->chunk_header
.size
) {
394 vdagent_virtio_port_do_chunk(vportp
);
395 vport
->chunk_header_read
= 0;
396 vport
->chunk_data_pos
= 0;
401 static void vdagent_virtio_port_do_write(struct vdagent_virtio_port
**vportp
)
405 struct vdagent_virtio_port
*vport
= *vportp
;
407 struct vdagent_virtio_port_buf
* wbuf
= vport
->write_buf
;
409 syslog(LOG_ERR
, "do_write called on a port without a write buf ?!");
413 if (wbuf
->write_pos
!= wbuf
->size
) {
414 syslog(LOG_ERR
, "do_write: buffer is incomplete!!");
418 to_write
= wbuf
->size
- wbuf
->pos
;
419 n
= write(vport
->fd
, wbuf
->buf
+ wbuf
->pos
, to_write
);
423 syslog(LOG_ERR
, "writing to vdagent virtio port: %m");
424 vdagent_virtio_port_destroy(vportp
);
431 if (wbuf
->pos
== wbuf
->size
) {
432 vport
->write_buf
= wbuf
->next
;