1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
/**
* @file
* @section AUTHORS
*
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
*
* Authors:
* Rafal Wojtczuk <rafal@invisiblethingslab.com>
* Daniel De Graaf <dgdegra@tycho.nsa.gov>
*
* @section LICENSE
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; If not, see <http://www.gnu.org/licenses/>.
*
* @section DESCRIPTION
*
* Originally borrowed from the Qubes OS Project, http://www.qubes-os.org,
* this code has been substantially rewritten to use the gntdev and gntalloc
* devices instead of raw MFNs and map_foreign_range.
*
* This is a library for inter-domain communication. A standard Xen ring
* buffer is used, with a datagram-based interface built on top. The grant
* reference and event channels are shared in XenStore under the path
* /local/domain/<srv-id>/data/vchan/<cli-id>/<port>/{ring-ref,event-channel}
*
* The ring.h macros define an asymmetric interface to a shared data structure
* that assumes all rings reside in a single contiguous memory space. This is
* not suitable for vchan because the interface to the ring is symmetric except
* for the setup. Unlike the producer-consumer rings defined in ring.h, the
* size of the rings used in vchan are determined at execution time instead of
* compile time, so the macros in ring.h cannot be used to access the rings.
*/
#include <xen/io/libxenvchan.h>
#include <xen/sys/evtchn.h>
#include <xenctrl.h>
struct libxenvchan_ring {
/* Pointer into the shared page. Offsets into buffer. */
struct ring_shared* shr;
/* ring data; may be its own shared page(s) depending on order */
void* buffer;
/**
* The size of the ring is (1 << order); offsets wrap around when they
* exceed this. This copy is required because we can't trust the order
* in the shared page to remain constant.
*/
int order;
};
/**
* struct libxenvchan: control structure passed to all library calls
*/
struct libxenvchan {
/* Mapping handle for shared ring page */
union {
xc_gntshr *gntshr; /* for server */
xc_gnttab *gnttab; /* for client */
};
/* Pointer to shared ring page */
struct vchan_interface *ring;
/* event channel interface */
xc_evtchn *event;
uint32_t event_port;
/* informative flags: are we acting as server? */
int is_server:1;
/* true if server remains active when client closes (allows reconnection) */
int server_persist:1;
/* true if operations should block instead of returning 0 */
int blocking:1;
/* communication rings */
struct libxenvchan_ring read, write;
};
/**
* Set up a vchan, including granting pages
* @param logger Logger for libxc errors
* @param domain The peer domain that will be connecting
* @param xs_path Base xenstore path for storing ring/event data
* @param send_min The minimum size (in bytes) of the send ring (left)
* @param recv_min The minimum size (in bytes) of the receive ring (right)
* @return The structure, or NULL in case of an error
*/
struct libxenvchan *libxenvchan_server_init(xentoollog_logger *logger, int domain, const char* xs_path, size_t read_min, size_t write_min);
/**
* Connect to an existing vchan. Note: you can reconnect to an existing vchan
* safely, however no locking is performed, so you must prevent multiple clients
* from connecting to a single server.
*
* @param logger Logger for libxc errors
* @param domain The peer domain to connect to
* @param xs_path Base xenstore path for storing ring/event data
* @return The structure, or NULL in case of an error
*/
struct libxenvchan *libxenvchan_client_init(xentoollog_logger *logger, int domain, const char* xs_path);
/**
* Close a vchan. This deallocates the vchan and attempts to free its
* resources. The other side is notified of the close, but can still read any
* data pending prior to the close.
*/
void libxenvchan_close(struct libxenvchan *ctrl);
/**
* Packet-based receive: always reads exactly $size bytes.
* @param ctrl The vchan control structure
* @param data Buffer for data that was read
* @param size Size of the buffer and amount of data to read
* @return -1 on error, 0 if nonblocking and insufficient data is available, or $size
*/
int libxenvchan_recv(struct libxenvchan *ctrl, void *data, size_t size);
/**
* Stream-based receive: reads as much data as possible.
* @param ctrl The vchan control structure
* @param data Buffer for data that was read
* @param size Size of the buffer
* @return -1 on error, otherwise the amount of data read (which may be zero if
* the vchan is nonblocking)
*/
int libxenvchan_read(struct libxenvchan *ctrl, void *data, size_t size);
/**
* Packet-based send: send entire buffer if possible
* @param ctrl The vchan control structure
* @param data Buffer for data to send
* @param size Size of the buffer and amount of data to send
* @return -1 on error, 0 if nonblocking and insufficient space is available, or $size
*/
int libxenvchan_send(struct libxenvchan *ctrl, const void *data, size_t size);
/**
* Stream-based send: send as much data as possible.
* @param ctrl The vchan control structure
* @param data Buffer for data to send
* @param size Size of the buffer
* @return -1 on error, otherwise the amount of data sent (which may be zero if
* the vchan is nonblocking)
*/
int libxenvchan_write(struct libxenvchan *ctrl, const void *data, size_t size);
/**
* Waits for reads or writes to unblock, or for a close
*/
int libxenvchan_wait(struct libxenvchan *ctrl);
/**
* Returns the event file descriptor for this vchan. When this FD is readable,
* libxenvchan_wait() will not block, and the state of the vchan has changed since
* the last invocation of libxenvchan_wait().
*/
int libxenvchan_fd_for_select(struct libxenvchan *ctrl);
/**
* Query the state of the vchan shared page:
* return 0 when one side has called libxenvchan_close() or crashed
* return 1 when both sides are open
* return 2 [server only] when no client has yet connected
*/
int libxenvchan_is_open(struct libxenvchan* ctrl);
/** Amount of data ready to read, in bytes */
int libxenvchan_data_ready(struct libxenvchan *ctrl);
/** Amount of data it is possible to send without blocking */
int libxenvchan_buffer_space(struct libxenvchan *ctrl);
|