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