syslinux/gpxe/src/core/xfer.c
<<
>>
Prefs
   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
  19FILE_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 */
  38static 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 */
  46void 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 */
  67int 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 */
  91int 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 */
 107size_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 */
 124struct 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 */
 147int 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 */
 173int 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 */
 185int 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 */
 211int 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 */
 234int 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 */
 252int 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 */
 284void 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 */
 297int 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 */
 311size_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 */
 324size_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 */
 335struct io_buffer *
 336default_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 */
 351int 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 */
 372int 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 */
 392int 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 */
 401struct 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 */
 417struct xfer_interface null_xfer = XFER_INIT ( &null_xfer_ops );
 418
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.