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