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