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 struct vdagent_virtio_port_buf
{
36 struct vdagent_virtio_port_buf
*next
;
39 struct vdagent_virtio_port
{
42 /* Read stuff, single buffer, separate header and data buffer */
43 int chunk_header_read
;
44 int message_header_read
;
45 VDIChunkHeader chunk_header
;
46 VDAgentMessage message_header
;
47 struct vdagent_virtio_port_buf data
;
49 /* Writes are stored in a linked list of buffers, with both the header
50 + data for a single message in 1 buffer. */
51 struct vdagent_virtio_port_buf
*write_buf
;
54 vdagent_virtio_port_read_callback read_callback
;
55 vdagent_virtio_port_disconnect_callback disconnect_callback
;
58 static void vdagent_virtio_port_do_write(struct vdagent_virtio_port
**portp
);
59 static void vdagent_virtio_port_do_read(struct vdagent_virtio_port
**portp
);
61 struct vdagent_virtio_port
*vdagent_virtio_port_create(const char *portname
,
62 vdagent_virtio_port_read_callback read_callback
,
63 vdagent_virtio_port_disconnect_callback disconnect_callback
)
65 struct vdagent_virtio_port
*port
;
67 port
= calloc(1, sizeof(*port
));
71 port
->fd
= open(portname
, O_RDWR
);
73 fprintf(stderr
, "open %s: %s\n", portname
, strerror(errno
));
78 port
->read_callback
= read_callback
;
79 port
->disconnect_callback
= disconnect_callback
;
84 void vdagent_virtio_port_destroy(struct vdagent_virtio_port
**portp
)
86 struct vdagent_virtio_port_buf
*wbuf
, *next_wbuf
;
87 struct vdagent_virtio_port
*port
= *portp
;
92 if (port
->disconnect_callback
)
93 port
->disconnect_callback(port
);
95 wbuf
= port
->write_buf
;
97 next_wbuf
= wbuf
->next
;
103 free(port
->data
.buf
);
110 int vdagent_virtio_port_fill_fds(struct vdagent_virtio_port
*port
,
111 fd_set
*readfds
, fd_set
*writefds
)
116 FD_SET(port
->fd
, readfds
);
118 FD_SET(port
->fd
, writefds
);
123 void vdagent_virtio_port_handle_fds(struct vdagent_virtio_port
**portp
,
124 fd_set
*readfds
, fd_set
*writefds
)
129 if (FD_ISSET((*portp
)->fd
, readfds
))
130 vdagent_virtio_port_do_read(portp
);
132 if (*portp
&& FD_ISSET((*portp
)->fd
, writefds
))
133 vdagent_virtio_port_do_write(portp
);
136 int vdagent_virtio_port_write(
137 struct vdagent_virtio_port
*port
,
138 VDIChunkHeader
*chunk_header
,
139 VDAgentMessage
*message_header
,
142 struct vdagent_virtio_port_buf
*wbuf
, *new_wbuf
;
144 if (message_header
->size
!=
145 (chunk_header
->size
- sizeof(*message_header
))) {
146 fprintf(stderr
, "write: chunk vs message header size mismatch\n");
150 new_wbuf
= malloc(sizeof(*new_wbuf
));
155 new_wbuf
->size
= sizeof(*chunk_header
) + sizeof(*message_header
) +
156 message_header
->size
;
157 new_wbuf
->next
= NULL
;
158 new_wbuf
->buf
= malloc(new_wbuf
->size
);
159 if (!new_wbuf
->buf
) {
164 memcpy(new_wbuf
->buf
, chunk_header
, sizeof(*chunk_header
));
165 memcpy(new_wbuf
->buf
+ sizeof(*chunk_header
), message_header
,
166 sizeof(*message_header
));
167 memcpy(new_wbuf
->buf
+ sizeof(*chunk_header
) + sizeof(*message_header
),
168 data
, message_header
->size
);
170 if (!port
->write_buf
) {
171 port
->write_buf
= new_wbuf
;
175 /* FIXME maybe limit the write_buf stack depth ? */
176 wbuf
= port
->write_buf
;
185 static void vdagent_virtio_port_do_read(struct vdagent_virtio_port
**portp
)
191 struct vdagent_virtio_port
*port
= *portp
;
193 if (port
->chunk_header_read
< sizeof(port
->chunk_header
)) {
194 to_read
= sizeof(port
->chunk_header
) - port
->chunk_header_read
;
195 dest
= (uint8_t *)&port
->chunk_header
+ port
->chunk_header_read
;
196 } else if (port
->message_header_read
< sizeof(port
->message_header
)) {
197 to_read
= sizeof(port
->message_header
) - port
->message_header_read
;
198 dest
= (uint8_t *)&port
->message_header
+ port
->message_header_read
;
200 to_read
= port
->data
.size
- port
->data
.pos
;
201 dest
= port
->data
.buf
+ port
->data
.pos
;
204 n
= read(port
->fd
, dest
, to_read
);
208 perror("reading from vdagent virtio port");
211 vdagent_virtio_port_destroy(portp
);
215 if (port
->chunk_header_read
< sizeof(port
->chunk_header
)) {
216 port
->chunk_header_read
+= n
;
217 if (port
->chunk_header_read
== sizeof(port
->chunk_header
)) {
218 if (port
->chunk_header
.size
< sizeof(port
->message_header
)) {
219 fprintf(stderr
, "chunk size < message header size\n");
220 vdagent_virtio_port_destroy(portp
);
223 port
->message_header_read
= 0;
225 } else if (port
->message_header_read
< sizeof(port
->message_header
)) {
226 port
->message_header_read
+= n
;
227 if (port
->message_header_read
== sizeof(port
->message_header
)) {
228 if (port
->message_header
.size
!=
229 (port
->chunk_header
.size
- sizeof(port
->message_header
))) {
231 "read: chunk vs message header size mismatch\n");
232 vdagent_virtio_port_destroy(portp
);
235 if (port
->message_header
.size
== 0) {
236 if (port
->read_callback
) {
237 r
= port
->read_callback(port
, &port
->chunk_header
,
238 &port
->message_header
, NULL
);
240 vdagent_virtio_port_destroy(portp
);
244 port
->chunk_header_read
= 0;
245 port
->message_header_read
= 0;
248 port
->data
.size
= port
->message_header
.size
;
249 port
->data
.buf
= malloc(port
->data
.size
);
250 if (!port
->data
.buf
) {
251 fprintf(stderr
, "out of memory, disportecting client\n");
252 vdagent_virtio_port_destroy(portp
);
259 if (port
->data
.pos
== port
->data
.size
) {
260 if (port
->read_callback
) {
261 r
= port
->read_callback(port
, &port
->chunk_header
,
262 &port
->message_header
, port
->data
.buf
);
264 vdagent_virtio_port_destroy(portp
);
268 free(port
->data
.buf
);
269 port
->chunk_header_read
= 0;
270 port
->message_header_read
= 0;
271 memset(&port
->data
, 0, sizeof(port
->data
));
276 static void vdagent_virtio_port_do_write(struct vdagent_virtio_port
**portp
)
280 struct vdagent_virtio_port
*port
= *portp
;
282 struct vdagent_virtio_port_buf
* wbuf
= port
->write_buf
;
285 "do_write called on a port without a write buf ?!\n");
289 to_write
= wbuf
->size
- wbuf
->pos
;
290 n
= write(port
->fd
, wbuf
->buf
+ wbuf
->pos
, to_write
);
294 perror("writing to vdagent virtio port");
295 vdagent_virtio_port_destroy(portp
);
300 if (wbuf
->pos
== wbuf
->size
) {
301 port
->write_buf
= wbuf
->next
;