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