2 * Copyright (C) 2012-2014 Andre Noll <maan@tuebingen.mpg.de>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file sideband.c Implementation of the sideband API. */
14 #include "portable_io.h"
18 /** Each sideband packet consists of a header and a data part. */
19 #define SIDEBAND_HEADER_SIZE 5
22 char header[SIDEBAND_HEADER_SIZE];
23 size_t bytes_dispatched; /* including header */
24 sb_transformation trafo;
32 * Prepare to receive a sideband packet.
34 * \param max_size Do not allocate more than this many bytes.
35 * \param t Optional sideband transformation.
36 * \param trafo_context Passed verbatim to \a t.
38 * \a trafo_context is ignored if \a t is \p NULL.
40 * \return An opaque sideband handle.
42 struct sb_context *sb_new_recv(size_t max_size, sb_transformation t,
45 struct sb_context *c = para_calloc(sizeof(*c));
47 c->max_size = max_size;
49 c->trafo_context = trafo_context;
54 * Prepare to write a sideband packet.
56 * \param sbb Data and meta data to send.
57 * \param dont_free Do not try to deallocate the sideband buffer.
58 * \param t See \ref sb_new_recv().
59 * \param trafo_context See \ref sb_new_recv().
61 * It's OK to supply a zero-sized buffer in \a sbb. In this case only the band
62 * designator is sent through the sideband channel. Otherwise, if \a dont_free
63 * is false, the buffer of \a sbb is freed after the data has been sent.
65 * \return See \ref sb_new_recv().
67 struct sb_context *sb_new_send(struct sb_buffer *sbb, bool dont_free,
68 sb_transformation t, void *trafo_context)
70 struct sb_context *c = para_calloc(sizeof(*c));
71 struct iovec src, dst, *srcp, *dstp;
75 c->trafo_context = trafo_context;
76 c->dont_free = dont_free;
78 write_u32(c->header, sbb->iov.iov_len);
79 write_u8(c->header + 4, sbb->band);
82 src = (typeof(src)){.iov_base = c->header, .iov_len = SIDEBAND_HEADER_SIZE};
83 t(&src, &dst, trafo_context);
84 if (src.iov_base != dst.iov_base) {
85 memcpy(c->header, dst.iov_base, SIDEBAND_HEADER_SIZE);
88 if (!iov_valid(&sbb->iov))
92 t(srcp, dstp, trafo_context);
93 if (srcp->iov_base != dstp->iov_base) {
103 * Deallocate all memory associated with a sideband handle.
105 * \param c The sideband handle.
107 * \a c must point to a handle previously returned by \ref sb_new_recv() or
108 * \ref sb_new_send(). It \a c is \p NULL, the function does nothing.
110 void sb_free(struct sb_context *c)
115 free(c->sbb.iov.iov_base);
120 * Obtain pointer(s) to the sideband send buffer(s).
122 * \param c The sideband handle.
123 * \param iov Array of two I/O vectors.
125 * \return The number of buffers that need to be sent, either 1 or 2.
127 * This function fills out the buffers described by \a iov. The result can be
128 * passed to \ref xwritev() or similar.
130 * \sa \ref sb_get_recv_buffer().
132 int sb_get_send_buffers(struct sb_context *c, struct iovec iov[2])
134 struct sb_buffer *sbb = &c->sbb;
135 size_t n = c->bytes_dispatched;
137 if (n < SIDEBAND_HEADER_SIZE) {
138 iov[0].iov_base = c->header + n;
139 iov[0].iov_len = SIDEBAND_HEADER_SIZE - n;
140 if (!iov_valid(&sbb->iov))
145 n -= SIDEBAND_HEADER_SIZE;
146 assert(n < sbb->iov.iov_len);
147 iov[0].iov_base = sbb->iov.iov_base + n;
148 iov[0].iov_len = sbb->iov.iov_len - n;
150 iov[1].iov_base = NULL;
156 * Update the sideband context after data has been sent.
158 * \param c The sideband handle.
159 * \param nbytes The number of sent bytes.
161 * \return False if more data must be sent to complete the sideband transfer,
162 * true if the transfer is complete. In this case all resources are freed and
163 * the sideband handle must not be used any more.
165 bool sb_sent(struct sb_context *c, size_t nbytes)
167 struct sb_buffer *sbb = &c->sbb;
168 size_t sz = SIDEBAND_HEADER_SIZE + sbb->iov.iov_len;
170 assert(c->bytes_dispatched + nbytes <= sz);
171 c->bytes_dispatched += nbytes;
172 if (c->bytes_dispatched < sz)
179 * Obtain a pointer to the next sideband read buffer.
181 * \param c The sideband handle.
182 * \param iov Result IO vector.
184 * This fills in \a iov to point to the buffer to which the next chunk of
185 * received data should be written.
187 void sb_get_recv_buffer(struct sb_context *c, struct iovec *iov)
189 struct sb_buffer *sbb = &c->sbb;
190 size_t n = c->bytes_dispatched;
192 if (n < SIDEBAND_HEADER_SIZE) {
193 iov->iov_base = c->header + n;
194 iov->iov_len = SIDEBAND_HEADER_SIZE - n;
197 n -= SIDEBAND_HEADER_SIZE;
198 assert(sbb->iov.iov_base);
199 assert(sbb->iov.iov_len > n);
200 iov->iov_base = sbb->iov.iov_base + n;
201 iov->iov_len = sbb->iov.iov_len - n;
205 * Update the sideband context after data has been received.
207 * \param c The sideband handle.
208 * \param nbytes The number of bytes that have been received.
209 * \param result The received sideband packet.
211 * \return Negative on errors, zero if more data needs to be read to complete
212 * this sideband packet, one if the sideband packet has been received
215 * Only if the function returns one, the sideband buffer pointed to by \a
216 * result is set to point to the received data.
218 int sb_received(struct sb_context *c, size_t nbytes, struct sb_buffer *result)
220 struct sb_buffer *sbb = &c->sbb;
221 size_t n = c->bytes_dispatched,
222 sz = SIDEBAND_HEADER_SIZE + sbb->iov.iov_len;
224 assert(n + nbytes <= sz);
225 c->bytes_dispatched += nbytes;
226 if (c->bytes_dispatched < SIDEBAND_HEADER_SIZE)
228 if (n >= SIDEBAND_HEADER_SIZE) { /* header has already been received */
229 if (c->bytes_dispatched < sz) /* need to recv more body data */
231 /* received everything, decrypt and return sbb */
234 c->trafo(&sbb->iov, &dst, c->trafo_context);
235 if (sbb->iov.iov_base != dst.iov_base) {
236 free(sbb->iov.iov_base);
237 sbb->iov.iov_base = dst.iov_base;
240 ((char *)(sbb->iov.iov_base))[sbb->iov.iov_len] = '\0';
243 /* header has been received, decrypt and decode it */
244 if (c->trafo) { /* decrypt */
245 struct iovec dst, src = (typeof(src)) {
246 .iov_base = c->header,
247 .iov_len = SIDEBAND_HEADER_SIZE
249 c->trafo(&src, &dst, c->trafo_context);
250 if (src.iov_base != dst.iov_base) {
251 memcpy(c->header, dst.iov_base,
252 SIDEBAND_HEADER_SIZE);
256 /* Decode header, setup sbb */
257 sbb->iov.iov_len = read_u32(c->header);
258 sbb->band = read_u8(c->header + 4);
259 sbb->iov.iov_base = NULL;
260 if (sbb->iov.iov_len == 0) /* zero-sized msg */
262 if (c->max_size > 0 && sbb->iov.iov_len > c->max_size) {
263 PARA_ERROR_LOG("packet too big (is %zu, max %zu)\n",
264 sbb->iov.iov_len, c->max_size);
265 return -E_SB_PACKET_SIZE;
268 * We like to reserve one extra byte for the terminating NULL
269 * character. However, we must make sure the +1 below does not
272 if (sbb->iov.iov_len == (size_t)-1)
273 return -E_SB_PACKET_SIZE;
274 sbb->iov.iov_base = para_malloc(sbb->iov.iov_len + 1);
275 return 0; /* ready to read body */