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. */
13 #include "portable_io.h"
17 /** Each sideband packet consists of a header and a data part. */
18 #define SIDEBAND_HEADER_SIZE 5
21 char header[SIDEBAND_HEADER_SIZE];
22 size_t bytes_dispatched; /* including header */
23 sb_transformation trafo;
31 * Prepare to receive a sideband packet.
33 * \param max_size Do not allocate more than this many bytes.
34 * \param t Optional sideband transformation.
35 * \param trafo_context Passed verbatim to \a t.
37 * \a trafo_context is ignored if \a t is \p NULL.
39 * \return An opaque sideband handle.
41 struct sb_context *sb_new_recv(size_t max_size, sb_transformation t,
44 struct sb_context *c = para_calloc(sizeof(*c));
46 c->max_size = max_size;
48 c->trafo_context = trafo_context;
53 * Prepare to write a sideband packet.
55 * \param sbb Data and meta data to send.
56 * \param dont_free Do not try to deallocate the sideband buffer.
57 * \param t See \ref sb_new_recv().
58 * \param trafo_context See \ref sb_new_recv().
60 * It's OK to supply a zero-sized buffer in \a sbb. In this case only the band
61 * designator is sent through the sideband channel. Otherwise, if \a dont_free
62 * is false, the buffer of \a sbb is freed after the data has been sent.
64 * \return See \ref sb_new_recv().
66 struct sb_context *sb_new_send(struct sb_buffer *sbb, bool dont_free,
67 sb_transformation t, void *trafo_context)
69 struct sb_context *c = para_calloc(sizeof(*c));
70 struct iovec src, dst, *srcp, *dstp;
74 c->trafo_context = trafo_context;
75 c->dont_free = dont_free;
77 write_u32(c->header, sbb->iov.iov_len);
78 write_u8(c->header + 4, sbb->band);
81 src = (typeof(src)){.iov_base = c->header, .iov_len = SIDEBAND_HEADER_SIZE};
82 t(&src, &dst, trafo_context);
83 if (src.iov_base != dst.iov_base) {
84 memcpy(c->header, dst.iov_base, SIDEBAND_HEADER_SIZE);
87 if (!iov_valid(&sbb->iov))
91 t(srcp, dstp, trafo_context);
92 if (srcp->iov_base != dstp->iov_base) {
102 * Deallocate all memory associated with a sideband handle.
104 * \param c The sideband handle.
106 * \a c must point to a handle previously returned by \ref sb_new_recv() or
107 * \ref sb_new_send(). It \a c is \p NULL, the function does nothing.
109 void sb_free(struct sb_context *c)
114 free(c->sbb.iov.iov_base);
119 * Obtain pointer(s) to the sideband send buffer(s).
121 * \param c The sideband handle.
122 * \param iov Array of two I/O vectors.
124 * \return The number of buffers that need to be sent, either 1 or 2.
126 * This function fills out the buffers described by \a iov. The result can be
127 * passed to \ref xwritev() or similar.
129 * \sa \ref sb_get_recv_buffer().
131 int sb_get_send_buffers(struct sb_context *c, struct iovec iov[2])
133 struct sb_buffer *sbb = &c->sbb;
134 size_t n = c->bytes_dispatched;
136 if (n < SIDEBAND_HEADER_SIZE) {
137 iov[0].iov_base = c->header + n;
138 iov[0].iov_len = SIDEBAND_HEADER_SIZE - n;
139 if (!iov_valid(&sbb->iov))
144 n -= SIDEBAND_HEADER_SIZE;
145 assert(n < sbb->iov.iov_len);
146 iov[0].iov_base = sbb->iov.iov_base + n;
147 iov[0].iov_len = sbb->iov.iov_len - n;
149 iov[1].iov_base = NULL;
155 * Update the sideband context after data has been sent.
157 * \param c The sideband handle.
158 * \param nbytes The number of sent bytes.
160 * \return False if more data must be sent to complete the sideband transfer,
161 * true if the transfer is complete. In this case all resources are freed and
162 * the sideband handle must not be used any more.
164 bool sb_sent(struct sb_context *c, size_t nbytes)
166 struct sb_buffer *sbb = &c->sbb;
167 size_t sz = SIDEBAND_HEADER_SIZE + sbb->iov.iov_len;
169 assert(c->bytes_dispatched + nbytes <= sz);
170 c->bytes_dispatched += nbytes;
171 if (c->bytes_dispatched < sz)
178 * Obtain a pointer to the next sideband read buffer.
180 * \param c The sideband handle.
181 * \param iov Result IO vector.
183 * This fills in \a iov to point to the buffer to which the next chunk of
184 * received data should be written.
186 void sb_get_recv_buffer(struct sb_context *c, struct iovec *iov)
188 struct sb_buffer *sbb = &c->sbb;
189 size_t n = c->bytes_dispatched;
191 if (n < SIDEBAND_HEADER_SIZE) {
192 iov->iov_base = c->header + n;
193 iov->iov_len = SIDEBAND_HEADER_SIZE - n;
196 n -= SIDEBAND_HEADER_SIZE;
197 assert(sbb->iov.iov_base);
198 assert(sbb->iov.iov_len > n);
199 iov->iov_base = sbb->iov.iov_base + n;
200 iov->iov_len = sbb->iov.iov_len - n;
204 * Update the sideband context after data has been received.
206 * \param c The sideband handle.
207 * \param nbytes The number of bytes that have been received.
208 * \param result The received sideband packet.
210 * \return Negative on errors, zero if more data needs to be read to complete
211 * this sideband packet, one if the sideband packet has been received
214 * Only if the function returns one, the sideband buffer pointed to by \a
215 * result is set to point to the received data.
217 int sb_received(struct sb_context *c, size_t nbytes, struct sb_buffer *result)
219 struct sb_buffer *sbb = &c->sbb;
220 size_t n = c->bytes_dispatched,
221 sz = SIDEBAND_HEADER_SIZE + sbb->iov.iov_len;
223 assert(n + nbytes <= sz);
224 c->bytes_dispatched += nbytes;
225 if (c->bytes_dispatched < SIDEBAND_HEADER_SIZE)
227 if (n >= SIDEBAND_HEADER_SIZE) { /* header has already been received */
228 if (c->bytes_dispatched < sz) /* need to recv more body data */
230 /* received everything, decrypt and return sbb */
233 c->trafo(&sbb->iov, &dst, c->trafo_context);
234 if (sbb->iov.iov_base != dst.iov_base) {
235 free(sbb->iov.iov_base);
236 sbb->iov.iov_base = dst.iov_base;
239 ((char *)(sbb->iov.iov_base))[sbb->iov.iov_len] = '\0';
242 /* header has been received, decrypt and decode it */
243 if (c->trafo) { /* decrypt */
244 struct iovec dst, src = (typeof(src)) {
245 .iov_base = c->header,
246 .iov_len = SIDEBAND_HEADER_SIZE
248 c->trafo(&src, &dst, c->trafo_context);
249 if (src.iov_base != dst.iov_base) {
250 memcpy(c->header, dst.iov_base,
251 SIDEBAND_HEADER_SIZE);
255 /* Decode header, setup sbb */
256 sbb->iov.iov_len = read_u32(c->header);
257 sbb->band = read_u8(c->header + 4);
258 sbb->iov.iov_base = NULL;
259 if (sbb->iov.iov_len == 0) /* zero-sized msg */
261 if (c->max_size > 0 && sbb->iov.iov_len > c->max_size) {
262 PARA_ERROR_LOG("packet too big (is %zu, max %zu)\n",
263 sbb->iov.iov_len, c->max_size);
264 return -E_SB_PACKET_SIZE;
267 * We like to reserve one extra byte for the terminating NULL
268 * character. However, we must make sure the +1 below does not
271 if (sbb->iov.iov_len == (size_t)-1)
272 return -E_SB_PACKET_SIZE;
273 sbb->iov.iov_base = para_malloc(sbb->iov.iov_len + 1);
274 return 0; /* ready to read body */