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