a9bcb4d7bb06e488abee3e5b5b86bba2210cdc67
[people/peper/gpxe.git] / src / core / xfer.c
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 FILE_LICENCE ( GPL2_OR_LATER );
20
21 #include <string.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <gpxe/xfer.h>
25
26 /** @file
27  *
28  * Data transfer interfaces
29  *
30  */
31
32 /**
33  * Dummy transfer metadata
34  *
35  * This gets passed to xfer_interface::deliver_iob() and equivalents
36  * when no metadata is available.
37  */
38 static struct xfer_metadata dummy_metadata;
39
40 /**
41  * Close data transfer interface
42  *
43  * @v xfer              Data transfer interface
44  * @v rc                Reason for close
45  */
46 void xfer_close ( struct xfer_interface *xfer, int rc ) {
47         struct xfer_interface *dest = xfer_get_dest ( xfer );
48
49         DBGC ( xfer, "XFER %p->%p close\n", xfer, dest );
50
51         xfer_unplug ( xfer );
52         dest->op->close ( dest, rc );
53         xfer_put ( dest );
54 }
55
56 /**
57  * Send redirection event
58  *
59  * @v xfer              Data transfer interface
60  * @v type              New location type
61  * @v args              Remaining arguments depend upon location type
62  * @ret rc              Return status code
63  */
64 int xfer_vredirect ( struct xfer_interface *xfer, int type, va_list args ) {
65         struct xfer_interface *dest = xfer_get_dest ( xfer );
66         int rc;
67
68         DBGC ( xfer, "XFER %p->%p redirect\n", xfer, dest );
69
70         rc = dest->op->vredirect ( dest, type, args );
71
72         if ( rc != 0 ) {
73                 DBGC ( xfer, "XFER %p<-%p redirect: %s\n", xfer, dest,
74                        strerror ( rc ) );
75         }
76         xfer_put ( dest );
77         return rc;
78 }
79
80 /**
81  * Send redirection event
82  *
83  * @v xfer              Data transfer interface
84  * @v type              New location type
85  * @v ...               Remaining arguments depend upon location type
86  * @ret rc              Return status code
87  */
88 int xfer_redirect ( struct xfer_interface *xfer, int type, ... ) {
89         va_list args;
90         int rc;
91
92         va_start ( args, type );
93         rc = xfer_vredirect ( xfer, type, args );
94         va_end ( args );
95         return rc;
96 }
97
98 /**
99  * Check flow control window
100  *
101  * @v xfer              Data transfer interface
102  * @ret len             Length of window
103  */
104 size_t xfer_window ( struct xfer_interface *xfer ) {
105         struct xfer_interface *dest = xfer_get_dest ( xfer );
106         size_t len;
107
108         len = dest->op->window ( dest );
109
110         xfer_put ( dest );
111         return len;
112 }
113
114 /**
115  * Allocate I/O buffer
116  *
117  * @v xfer              Data transfer interface
118  * @v len               I/O buffer payload length
119  * @ret iobuf           I/O buffer
120  */
121 struct io_buffer * xfer_alloc_iob ( struct xfer_interface *xfer, size_t len ) {
122         struct xfer_interface *dest = xfer_get_dest ( xfer );
123         struct io_buffer *iobuf;
124
125         DBGC ( xfer, "XFER %p->%p alloc_iob %zd\n", xfer, dest, len );
126
127         iobuf = dest->op->alloc_iob ( dest, len );
128
129         if ( ! iobuf ) {
130                 DBGC ( xfer, "XFER %p<-%p alloc_iob failed\n", xfer, dest );
131         }
132         xfer_put ( dest );
133         return iobuf;
134 }
135
136 /**
137  * Deliver datagram as I/O buffer with metadata
138  *
139  * @v xfer              Data transfer interface
140  * @v iobuf             Datagram I/O buffer
141  * @v meta              Data transfer metadata
142  * @ret rc              Return status code
143  */
144 int xfer_deliver_iob_meta ( struct xfer_interface *xfer,
145                             struct io_buffer *iobuf,
146                             struct xfer_metadata *meta ) {
147         struct xfer_interface *dest = xfer_get_dest ( xfer );
148         int rc;
149
150         DBGC ( xfer, "XFER %p->%p deliver_iob %zd\n", xfer, dest,
151                iob_len ( iobuf ) );
152
153         rc = dest->op->deliver_iob ( dest, iobuf, meta );
154
155         if ( rc != 0 ) {
156                 DBGC ( xfer, "XFER %p<-%p deliver_iob: %s\n", xfer, dest,
157                        strerror ( rc ) );
158         }
159         xfer_put ( dest );
160         return rc;
161 }
162
163 /**
164  * Deliver datagram as I/O buffer with metadata
165  *
166  * @v xfer              Data transfer interface
167  * @v iobuf             Datagram I/O buffer
168  * @ret rc              Return status code
169  */
170 int xfer_deliver_iob ( struct xfer_interface *xfer,
171                        struct io_buffer *iobuf ) {
172         return xfer_deliver_iob_meta ( xfer, iobuf, &dummy_metadata );
173 }
174
175 /**
176  * Deliver datagram as raw data
177  *
178  * @v xfer              Data transfer interface
179  * @v iobuf             Datagram I/O buffer
180  * @ret rc              Return status code
181  */
182 int xfer_deliver_raw ( struct xfer_interface *xfer,
183                        const void *data, size_t len ) {
184         struct xfer_interface *dest = xfer_get_dest ( xfer );
185         int rc;
186
187         DBGC ( xfer, "XFER %p->%p deliver_raw %p+%zd\n", xfer, dest,
188                data, len );
189
190         rc = dest->op->deliver_raw ( dest, data, len );
191
192         if ( rc != 0 ) {
193                 DBGC ( xfer, "XFER %p<-%p deliver_raw: %s\n", xfer, dest,
194                        strerror ( rc ) );
195         }
196         xfer_put ( dest );
197         return rc;
198 }
199
200 /**
201  * Deliver formatted string
202  *
203  * @v xfer              Data transfer interface
204  * @v format            Format string
205  * @v args              Arguments corresponding to the format string
206  * @ret rc              Return status code
207  */
208 int xfer_vprintf ( struct xfer_interface *xfer, const char *format,
209                    va_list args ) {
210         size_t len;
211         va_list args_tmp;
212
213         va_copy ( args_tmp, args );
214         len = vsnprintf ( NULL, 0, format, args );
215         {
216                 char buf[len + 1];
217                 vsnprintf ( buf, sizeof ( buf ), format, args_tmp );
218                 va_end ( args_tmp );
219                 return xfer_deliver_raw ( xfer, buf, len );
220         }
221 }
222
223 /**
224  * Deliver formatted string
225  *
226  * @v xfer              Data transfer interface
227  * @v format            Format string
228  * @v ...               Arguments corresponding to the format string
229  * @ret rc              Return status code
230  */
231 int xfer_printf ( struct xfer_interface *xfer, const char *format, ... ) {
232         va_list args;
233         int rc;
234
235         va_start ( args, format );
236         rc = xfer_vprintf ( xfer, format, args );
237         va_end ( args );
238         return rc;
239 }
240
241 /**
242  * Seek to position
243  *
244  * @v xfer              Data transfer interface
245  * @v offset            Offset to new position
246  * @v whence            Basis for new position
247  * @ret rc              Return status code
248  */
249 int xfer_seek ( struct xfer_interface *xfer, off_t offset, int whence ) {
250         struct io_buffer *iobuf;
251         struct xfer_metadata meta = {
252                 .offset = offset,
253                 .whence = whence,
254         };
255
256         DBGC ( xfer, "XFER %p seek %s+%ld\n", xfer,
257                whence_text ( whence ), offset );
258
259         /* Allocate and send a zero-length data buffer */
260         iobuf = xfer_alloc_iob ( xfer, 0 );
261         if ( ! iobuf )
262                 return -ENOMEM;
263         return xfer_deliver_iob_meta ( xfer, iobuf, &meta );
264 }
265
266 /****************************************************************************
267  *
268  * Helper methods
269  *
270  * These functions are designed to be used as methods in the
271  * xfer_interface_operations table.
272  *
273  */
274
275 /**
276  * Ignore close() event
277  *
278  * @v xfer              Data transfer interface
279  * @v rc                Reason for close
280  */
281 void ignore_xfer_close ( struct xfer_interface *xfer __unused,
282                          int rc __unused ) {
283         /* Nothing to do */
284 }
285
286 /**
287  * Ignore vredirect() event
288  *
289  * @v xfer              Data transfer interface
290  * @v type              New location type
291  * @v args              Remaining arguments depend upon location type
292  * @ret rc              Return status code
293  */
294 int ignore_xfer_vredirect ( struct xfer_interface *xfer __unused,
295                             int type __unused, va_list args __unused ) {
296         return 0;
297 }
298
299 /**
300  * Unlimited flow control window
301  *
302  * @v xfer              Data transfer interface
303  * @ret len             Length of window
304  *
305  * This handler indicates that the interface is always ready to accept
306  * data.
307  */
308 size_t unlimited_xfer_window ( struct xfer_interface *xfer __unused ) {
309         return ~( ( size_t ) 0 );
310 }
311
312 /**
313  * No flow control window
314  *
315  * @v xfer              Data transfer interface
316  * @ret len             Length of window
317  *
318  * This handler indicates that the interface is never ready to accept
319  * data.
320  */
321 size_t no_xfer_window ( struct xfer_interface *xfer __unused ) {
322         return 0;
323 }
324
325 /**
326  * Allocate I/O buffer
327  *
328  * @v xfer              Data transfer interface
329  * @v len               I/O buffer payload length
330  * @ret iobuf           I/O buffer
331  */
332 struct io_buffer *
333 default_xfer_alloc_iob ( struct xfer_interface *xfer __unused, size_t len ) {
334         return alloc_iob ( len );
335 }
336
337 /**
338  * Deliver datagram as raw data
339  *
340  * @v xfer              Data transfer interface
341  * @v iobuf             Datagram I/O buffer
342  * @v meta              Data transfer metadata
343  * @ret rc              Return status code
344  *
345  * This function is intended to be used as the deliver() method for
346  * data transfer interfaces that prefer to handle raw data.
347  */
348 int xfer_deliver_as_raw ( struct xfer_interface *xfer,
349                           struct io_buffer *iobuf,
350                           struct xfer_metadata *meta __unused ) {
351         int rc;
352
353         rc = xfer->op->deliver_raw ( xfer, iobuf->data, iob_len ( iobuf ) );
354         free_iob ( iobuf );
355         return rc;
356 }
357
358 /**
359  * Deliver datagram as I/O buffer
360  *
361  * @v xfer              Data transfer interface
362  * @v data              Data buffer
363  * @v len               Length of data buffer
364  * @ret rc              Return status code
365  *
366  * This function is intended to be used as the deliver_raw() method
367  * for data transfer interfaces that prefer to handle I/O buffers.
368  */
369 int xfer_deliver_as_iob ( struct xfer_interface *xfer,
370                           const void *data, size_t len ) {
371         struct io_buffer *iobuf;
372
373         iobuf = xfer->op->alloc_iob ( xfer, len );
374         if ( ! iobuf )
375                 return -ENOMEM;
376
377         memcpy ( iob_put ( iobuf, len ), data, len );
378         return xfer->op->deliver_iob ( xfer, iobuf, &dummy_metadata );
379 }
380
381 /**
382  * Ignore datagram as raw data event
383  *
384  * @v xfer              Data transfer interface
385  * @v data              Data buffer
386  * @v len               Length of data buffer
387  * @ret rc              Return status code
388  */
389 int ignore_xfer_deliver_raw ( struct xfer_interface *xfer,
390                               const void *data __unused, size_t len ) {
391         DBGC ( xfer, "XFER %p %zd bytes delivered %s\n", xfer, len,
392                ( ( xfer == &null_xfer ) ?
393                  "before connection" : "after termination" ) );
394         return 0;
395 }
396
397 /** Null data transfer interface operations */
398 struct xfer_interface_operations null_xfer_ops = {
399         .close          = ignore_xfer_close,
400         .vredirect      = ignore_xfer_vredirect,
401         .window         = unlimited_xfer_window,
402         .alloc_iob      = default_xfer_alloc_iob,
403         .deliver_iob    = xfer_deliver_as_raw,
404         .deliver_raw    = ignore_xfer_deliver_raw,
405 };
406
407 /**
408  * Null data transfer interface
409  *
410  * This is the interface to which data transfer interfaces are
411  * connected when unplugged.  It will never generate messages, and
412  * will silently absorb all received messages.
413  */
414 struct xfer_interface null_xfer = XFER_INIT ( &null_xfer_ops );