2007-04-27 00:44:52 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
|
2009-05-01 16:41:06 +02:00
|
|
|
FILE_LICENCE ( GPL2_OR_LATER );
|
|
|
|
|
2007-04-27 02:02:23 +02:00
|
|
|
#include <string.h>
|
2007-05-28 22:09:44 +02:00
|
|
|
#include <stdio.h>
|
2007-04-27 00:44:52 +02:00
|
|
|
#include <errno.h>
|
2010-06-16 02:31:29 +02:00
|
|
|
#include <ipxe/iobuf.h>
|
2010-04-19 21:16:01 +02:00
|
|
|
#include <ipxe/xfer.h>
|
2010-06-16 02:31:29 +02:00
|
|
|
#include <ipxe/open.h>
|
2007-04-27 00:44:52 +02:00
|
|
|
|
|
|
|
/** @file
|
|
|
|
*
|
|
|
|
* Data transfer interfaces
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2009-02-15 09:41:46 +01:00
|
|
|
/**
|
|
|
|
* Dummy transfer metadata
|
|
|
|
*
|
2010-07-25 02:49:00 +02:00
|
|
|
* This gets passed to xfer_interface::deliver() and equivalents when
|
|
|
|
* no metadata is available.
|
2009-02-15 09:41:46 +01:00
|
|
|
*/
|
|
|
|
static struct xfer_metadata dummy_metadata;
|
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* Data transfer interface operations
|
2007-04-29 04:03:58 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2007-04-28 22:56:24 +02:00
|
|
|
/**
|
|
|
|
* Send redirection event
|
|
|
|
*
|
2010-06-16 02:31:29 +02:00
|
|
|
* @v intf Data transfer interface
|
2007-04-28 22:56:24 +02:00
|
|
|
* @v type New location type
|
|
|
|
* @v args Remaining arguments depend upon location type
|
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
2010-06-16 02:31:29 +02:00
|
|
|
int xfer_vredirect ( struct interface *intf, int type, va_list args ) {
|
|
|
|
struct interface *dest;
|
|
|
|
xfer_vredirect_TYPE ( void * ) *op =
|
[interface] Allow for non-pass-through interface methods
xfer_vredirect() should not be allowed to propagate to a pass-through
interface. For example, when an HTTPS connection is opened, the
redirect message should cause the TLS layer to reopen the TCP socket,
rather than causing the HTTP layer to disconnect from the TLS layer.
Fix by allowing for non-pass-through interface methods, and setting
xfer_vredirect() to be one such method.
This is slightly ugly, in that it complicates the notion of an
interface method call by adding a "pass-through" / "non-pass-through"
piece of metadata. However, the only current user of xfer_vredirect()
is iscsi.c, which uses it only because we don't yet have an
ioctl()-style call for retrieving the underlying socket address.
The new interface infrastructure allows for such a call to be created,
at which time this sole user of xfer_vredirect() can be removed,
xfer_vredirect() can cease to be an interface method and become simply
a wrapper around xfer_vreopen(), and the concept of a non-pass-through
interface method can be reverted.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2010-06-22 20:12:40 +02:00
|
|
|
intf_get_dest_op_no_passthru ( intf, xfer_vredirect, &dest );
|
2010-06-16 02:31:29 +02:00
|
|
|
void *object = intf_object ( dest );
|
2007-05-15 18:53:46 +02:00
|
|
|
int rc;
|
2007-04-28 22:56:24 +02:00
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " redirect\n",
|
|
|
|
INTF_INTF_DBG ( intf, dest ) );
|
2007-05-26 17:04:36 +02:00
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
if ( op ) {
|
|
|
|
rc = op ( object, type, args );
|
|
|
|
} else {
|
|
|
|
/* Default is to reopen the interface as instructed */
|
|
|
|
rc = xfer_vreopen ( dest, type, args );
|
|
|
|
}
|
2007-05-26 17:04:36 +02:00
|
|
|
|
|
|
|
if ( rc != 0 ) {
|
2010-06-16 02:31:29 +02:00
|
|
|
DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " redirect "
|
|
|
|
"failed: %s\n", INTF_INTF_DBG ( intf, dest ),
|
2007-05-26 17:04:36 +02:00
|
|
|
strerror ( rc ) );
|
|
|
|
}
|
2007-04-28 22:56:24 +02:00
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
intf_put ( dest );
|
2007-04-28 22:56:24 +02:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2007-07-08 15:11:07 +02:00
|
|
|
/**
|
|
|
|
* Check flow control window
|
|
|
|
*
|
2010-06-16 02:31:29 +02:00
|
|
|
* @v intf Data transfer interface
|
2007-07-08 15:11:07 +02:00
|
|
|
* @ret len Length of window
|
|
|
|
*/
|
2010-06-16 02:31:29 +02:00
|
|
|
size_t xfer_window ( struct interface *intf ) {
|
|
|
|
struct interface *dest;
|
|
|
|
xfer_window_TYPE ( void * ) *op =
|
|
|
|
intf_get_dest_op ( intf, xfer_window, &dest );
|
|
|
|
void *object = intf_object ( dest );
|
2007-07-08 15:11:07 +02:00
|
|
|
size_t len;
|
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
if ( op ) {
|
|
|
|
len = op ( object );
|
|
|
|
} else {
|
|
|
|
/* Default is to provide an unlimited window */
|
|
|
|
len = ~( ( size_t ) 0 );
|
|
|
|
}
|
2007-07-08 15:11:07 +02:00
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
intf_put ( dest );
|
2007-07-08 15:11:07 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2010-09-05 02:16:29 +02:00
|
|
|
/**
|
|
|
|
* Report change of flow control window
|
|
|
|
*
|
|
|
|
* @v intf Data transfer interface
|
|
|
|
*
|
|
|
|
* Note that this method is used to indicate only unsolicited changes
|
|
|
|
* in the flow control window. In particular, this method must not be
|
|
|
|
* called as part of the response to xfer_deliver(), since that could
|
|
|
|
* easily lead to an infinite loop. Callers of xfer_deliver() should
|
|
|
|
* assume that the flow control window will have changed without
|
|
|
|
* generating an xfer_window_changed() message.
|
|
|
|
*/
|
|
|
|
void xfer_window_changed ( struct interface *intf ) {
|
|
|
|
struct interface *dest;
|
|
|
|
xfer_window_changed_TYPE ( void * ) *op =
|
|
|
|
intf_get_dest_op ( intf, xfer_window_changed, &dest );
|
|
|
|
void *object = intf_object ( dest );
|
|
|
|
|
|
|
|
if ( op ) {
|
|
|
|
op ( object );
|
|
|
|
} else {
|
|
|
|
/* Default is to do nothing */
|
|
|
|
}
|
|
|
|
|
|
|
|
intf_put ( dest );
|
|
|
|
}
|
|
|
|
|
2007-05-15 17:23:09 +02:00
|
|
|
/**
|
|
|
|
* Allocate I/O buffer
|
|
|
|
*
|
2010-06-16 02:31:29 +02:00
|
|
|
* @v intf Data transfer interface
|
2007-05-15 17:23:09 +02:00
|
|
|
* @v len I/O buffer payload length
|
|
|
|
* @ret iobuf I/O buffer
|
|
|
|
*/
|
2010-06-16 02:31:29 +02:00
|
|
|
struct io_buffer * xfer_alloc_iob ( struct interface *intf, size_t len ) {
|
|
|
|
struct interface *dest;
|
|
|
|
xfer_alloc_iob_TYPE ( void * ) *op =
|
|
|
|
intf_get_dest_op ( intf, xfer_alloc_iob, &dest );
|
|
|
|
void *object = intf_object ( dest );
|
2007-05-15 18:53:46 +02:00
|
|
|
struct io_buffer *iobuf;
|
2007-05-15 17:23:09 +02:00
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " alloc_iob %zd\n",
|
|
|
|
INTF_INTF_DBG ( intf, dest ), len );
|
2007-05-26 17:04:36 +02:00
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
if ( op ) {
|
|
|
|
iobuf = op ( object, len );
|
|
|
|
} else {
|
|
|
|
/* Default is to allocate an I/O buffer with no
|
|
|
|
* reserved space.
|
|
|
|
*/
|
|
|
|
iobuf = alloc_iob ( len );
|
|
|
|
}
|
2007-05-26 17:04:36 +02:00
|
|
|
|
|
|
|
if ( ! iobuf ) {
|
2010-06-16 02:31:29 +02:00
|
|
|
DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " alloc_iob "
|
|
|
|
"failed\n", INTF_INTF_DBG ( intf, dest ) );
|
2007-05-26 17:04:36 +02:00
|
|
|
}
|
2010-06-16 02:31:29 +02:00
|
|
|
|
|
|
|
intf_put ( dest );
|
2007-05-15 18:53:46 +02:00
|
|
|
return iobuf;
|
2007-05-15 17:23:09 +02:00
|
|
|
}
|
|
|
|
|
2007-04-27 00:44:52 +02:00
|
|
|
/**
|
2010-06-16 02:31:29 +02:00
|
|
|
* Deliver datagram
|
2007-04-27 00:44:52 +02:00
|
|
|
*
|
2010-06-16 02:31:29 +02:00
|
|
|
* @v intf Data transfer interface
|
2007-04-27 00:44:52 +02:00
|
|
|
* @v iobuf Datagram I/O buffer
|
2008-01-08 17:46:55 +01:00
|
|
|
* @v meta Data transfer metadata
|
2007-04-27 00:44:52 +02:00
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
2010-06-16 02:31:29 +02:00
|
|
|
int xfer_deliver ( struct interface *intf,
|
|
|
|
struct io_buffer *iobuf,
|
|
|
|
struct xfer_metadata *meta ) {
|
|
|
|
struct interface *dest;
|
|
|
|
xfer_deliver_TYPE ( void * ) *op =
|
|
|
|
intf_get_dest_op ( intf, xfer_deliver, &dest );
|
|
|
|
void *object = intf_object ( dest );
|
2007-05-15 18:53:46 +02:00
|
|
|
int rc;
|
2007-04-27 00:44:52 +02:00
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " deliver %zd\n",
|
|
|
|
INTF_INTF_DBG ( intf, dest ), iob_len ( iobuf ) );
|
2007-05-26 17:04:36 +02:00
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
if ( op ) {
|
|
|
|
rc = op ( object, iobuf, meta );
|
|
|
|
} else {
|
|
|
|
/* Default is to discard the I/O buffer */
|
|
|
|
free_iob ( iobuf );
|
|
|
|
rc = -EPIPE;
|
|
|
|
}
|
2007-05-26 17:04:36 +02:00
|
|
|
|
|
|
|
if ( rc != 0 ) {
|
2010-06-16 02:31:29 +02:00
|
|
|
DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT
|
|
|
|
" deliver failed: %s\n",
|
|
|
|
INTF_INTF_DBG ( intf, dest ), strerror ( rc ) );
|
2007-05-26 17:04:36 +02:00
|
|
|
}
|
2010-06-16 02:31:29 +02:00
|
|
|
|
|
|
|
intf_put ( dest );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* Data transfer interface helper functions
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send redirection event
|
|
|
|
*
|
|
|
|
* @v intf Data transfer interface
|
|
|
|
* @v type New location type
|
|
|
|
* @v ... Remaining arguments depend upon location type
|
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
|
|
|
int xfer_redirect ( struct interface *intf, int type, ... ) {
|
|
|
|
va_list args;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
va_start ( args, type );
|
|
|
|
rc = xfer_vredirect ( intf, type, args );
|
|
|
|
va_end ( args );
|
2007-05-15 18:53:46 +02:00
|
|
|
return rc;
|
2007-04-28 22:56:24 +02:00
|
|
|
}
|
|
|
|
|
2007-06-11 16:04:39 +02:00
|
|
|
/**
|
2010-06-16 02:31:29 +02:00
|
|
|
* Deliver datagram as I/O buffer without metadata
|
2007-06-11 16:04:39 +02:00
|
|
|
*
|
2010-06-16 02:31:29 +02:00
|
|
|
* @v intf Data transfer interface
|
2007-06-11 16:04:39 +02:00
|
|
|
* @v iobuf Datagram I/O buffer
|
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
2010-06-16 02:31:29 +02:00
|
|
|
int xfer_deliver_iob ( struct interface *intf, struct io_buffer *iobuf ) {
|
|
|
|
return xfer_deliver ( intf, iobuf, &dummy_metadata );
|
2007-06-11 16:04:39 +02:00
|
|
|
}
|
|
|
|
|
2007-04-28 22:56:24 +02:00
|
|
|
/**
|
|
|
|
* Deliver datagram as raw data
|
|
|
|
*
|
2010-06-16 02:31:29 +02:00
|
|
|
* @v intf Data transfer interface
|
2010-07-25 02:49:00 +02:00
|
|
|
* @v data Data
|
|
|
|
* @v len Length of data
|
|
|
|
* @v meta Data transfer metadata
|
2007-04-28 22:56:24 +02:00
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
2010-07-25 02:49:00 +02:00
|
|
|
int xfer_deliver_raw_meta ( struct interface *intf, const void *data,
|
|
|
|
size_t len, struct xfer_metadata *meta ) {
|
2010-06-16 02:31:29 +02:00
|
|
|
struct io_buffer *iobuf;
|
2007-05-26 17:04:36 +02:00
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
iobuf = xfer_alloc_iob ( intf, len );
|
|
|
|
if ( ! iobuf )
|
|
|
|
return -ENOMEM;
|
2007-05-26 17:04:36 +02:00
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
memcpy ( iob_put ( iobuf, len ), data, len );
|
2010-07-25 02:49:00 +02:00
|
|
|
return xfer_deliver ( intf, iobuf, meta );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Deliver datagram as raw data without metadata
|
|
|
|
*
|
|
|
|
* @v intf Data transfer interface
|
|
|
|
* @v data Data
|
|
|
|
* @v len Length of data
|
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
|
|
|
int xfer_deliver_raw ( struct interface *intf, const void *data, size_t len ) {
|
|
|
|
return xfer_deliver_raw_meta ( intf, data, len, &dummy_metadata );
|
2007-04-27 00:44:52 +02:00
|
|
|
}
|
|
|
|
|
2007-05-28 22:09:44 +02:00
|
|
|
/**
|
|
|
|
* Deliver formatted string
|
|
|
|
*
|
2010-06-16 02:31:29 +02:00
|
|
|
* @v intf Data transfer interface
|
2007-05-28 22:09:44 +02:00
|
|
|
* @v format Format string
|
|
|
|
* @v args Arguments corresponding to the format string
|
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
2010-06-16 02:31:29 +02:00
|
|
|
int xfer_vprintf ( struct interface *intf, const char *format,
|
2007-05-28 22:09:44 +02:00
|
|
|
va_list args ) {
|
|
|
|
size_t len;
|
|
|
|
va_list args_tmp;
|
|
|
|
|
|
|
|
va_copy ( args_tmp, args );
|
|
|
|
len = vsnprintf ( NULL, 0, format, args );
|
|
|
|
{
|
|
|
|
char buf[len + 1];
|
|
|
|
vsnprintf ( buf, sizeof ( buf ), format, args_tmp );
|
2007-06-03 04:11:25 +02:00
|
|
|
va_end ( args_tmp );
|
2010-06-16 02:31:29 +02:00
|
|
|
return xfer_deliver_raw ( intf, buf, len );
|
2007-05-28 22:09:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Deliver formatted string
|
|
|
|
*
|
2010-06-16 02:31:29 +02:00
|
|
|
* @v intf Data transfer interface
|
2007-05-28 22:09:44 +02:00
|
|
|
* @v format Format string
|
|
|
|
* @v ... Arguments corresponding to the format string
|
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
2010-06-16 02:31:29 +02:00
|
|
|
int xfer_printf ( struct interface *intf, const char *format, ... ) {
|
2007-05-28 22:09:44 +02:00
|
|
|
va_list args;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
va_start ( args, format );
|
2010-06-16 02:31:29 +02:00
|
|
|
rc = xfer_vprintf ( intf, format, args );
|
2007-05-28 22:09:44 +02:00
|
|
|
va_end ( args );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-01-08 17:46:55 +01:00
|
|
|
/**
|
|
|
|
* Seek to position
|
|
|
|
*
|
2010-06-16 02:31:29 +02:00
|
|
|
* @v intf Data transfer interface
|
2008-01-08 17:46:55 +01:00
|
|
|
* @v offset Offset to new position
|
|
|
|
* @ret rc Return status code
|
|
|
|
*/
|
2010-07-02 13:12:16 +02:00
|
|
|
int xfer_seek ( struct interface *intf, off_t offset ) {
|
2008-01-08 17:46:55 +01:00
|
|
|
struct io_buffer *iobuf;
|
|
|
|
struct xfer_metadata meta = {
|
2010-07-02 13:12:16 +02:00
|
|
|
.flags = XFER_FL_ABS_OFFSET,
|
2008-01-08 17:46:55 +01:00
|
|
|
.offset = offset,
|
|
|
|
};
|
|
|
|
|
2010-07-02 13:12:16 +02:00
|
|
|
DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " seek to %ld\n",
|
|
|
|
INTF_DBG ( intf ), offset );
|
2008-01-08 17:46:55 +01:00
|
|
|
|
|
|
|
/* Allocate and send a zero-length data buffer */
|
2010-06-16 02:31:29 +02:00
|
|
|
iobuf = xfer_alloc_iob ( intf, 0 );
|
2008-01-08 17:46:55 +01:00
|
|
|
if ( ! iobuf )
|
|
|
|
return -ENOMEM;
|
2007-04-28 22:56:24 +02:00
|
|
|
|
2010-06-16 02:31:29 +02:00
|
|
|
return xfer_deliver ( intf, iobuf, &meta );
|
2007-04-29 04:03:58 +02:00
|
|
|
}
|