diff --git a/src/core/interface.c b/src/core/interface.c new file mode 100644 index 00000000..15df49d3 --- /dev/null +++ b/src/core/interface.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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. + */ + +#include +#include + +/** @file + * + * Object communication interfaces + * + */ + +/** + * Obtain reference to interface + * + * @v intf Interface + * @ret intf Interface + * + * Increases the reference count on the interface. + */ +static struct interface * intf_get ( struct interface *intf ) { + intf->refcnt ( intf, +1 ); + return intf; +} + +/** + * Drop reference to interface + * + * @v intf Interface + * + * Decreases the reference count on the interface. + */ +static void intf_put ( struct interface *intf ) { + intf->refcnt ( intf, -1 ); +} + +/** + * Plug an interface into a new destination interface + * + * @v intf Interface + * @v dest New destination interface + * + * The reference to the existing destination interface is dropped, a + * reference to the new destination interface is obtained, and the + * interface is updated to point to the new destination interface. + * + * Note that there is no "unplug" call; instead you must plug the + * interface into a null interface. + */ +void plug ( struct interface *intf, struct interface *dest ) { + intf_put ( intf->dest ); + intf->dest = intf_get ( dest ); +} + +/** + * Null update reference count + * + * @v intf Interface + * @v delta Change to apply to reference count + * + * Use this as the refcnt() method for an interface that does not need + * to support reference counting. + */ +void null_refcnt ( struct interface *intf __unused, int delta __unused ) { + /* Do nothing */ +} diff --git a/src/core/xfer.c b/src/core/xfer.c new file mode 100644 index 00000000..d08b3b86 --- /dev/null +++ b/src/core/xfer.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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. + */ + +#include +#include + +/** @file + * + * Data transfer interfaces + * + */ + +/** + * Deliver datagram + * + * @v xfer Data-transfer interface + * @v iobuf Datagram I/O buffer + * @ret rc Return status code + */ +int deliver ( struct xfer_interface *xfer, struct io_buffer *iobuf ) { + struct xfer_interface *dest = xfer_dest ( xfer ); + + return dest->op->deliver ( dest, xfer, iobuf ); +} + +/** + * Null deliver datagram + * + * @v xfer Data-transfer interface + * @v src Source interface + * @v iobuf Datagram I/O buffer + * @ret rc Return status code + */ +static int null_deliver ( struct xfer_interface *xfer __unused, + struct xfer_interface *src __unused, + struct io_buffer *iobuf ) { + free_iob ( iobuf ); + return -EPIPE; +} + +/** Null data transfer interface operations */ +struct xfer_interface_operations null_xfer_ops = { + .deliver = null_deliver, +}; + +/** + * Null data transfer interface + * + * This is the interface to which data transfer interfaces are + * connected when unplugged. It will never generate messages, and + * will silently absorb all received messages. + */ +struct xfer_interface null_xfer = { + .intf = { + .dest = &null_xfer.intf, + .refcnt = null_refcnt, + }, + .op = &null_xfer_ops, +}; diff --git a/src/include/gpxe/interface.h b/src/include/gpxe/interface.h new file mode 100644 index 00000000..38e62721 --- /dev/null +++ b/src/include/gpxe/interface.h @@ -0,0 +1,36 @@ +#ifndef _GPXE_INTERFACE_H +#define _GPXE_INTERFACE_H + +/** @file + * + * Object communication interfaces + * + */ + +/** An object communication interface */ +struct interface { + /** Destination interface + * + * When messages are sent via this interface, they will be + * delivered to the destination interface. + * + * This pointer may never be NULL. When the interface is + * unplugged, it should point to a null interface. + */ + struct interface *dest; + /** Update reference count + * + * @v intf Interface + * @v delta Change to apply to reference count + * + * This method updates the reference count for the object + * containing the interface. + */ + void ( * refcnt ) ( struct interface *intf, int delta ); +}; + +extern void plug ( struct interface *intf, struct interface *dest ); + +extern void null_refcnt ( struct interface *intf, int delta ); + +#endif /* _GPXE_INTERFACE_H */ diff --git a/src/include/gpxe/iobuf.h b/src/include/gpxe/iobuf.h new file mode 100644 index 00000000..cf99050d --- /dev/null +++ b/src/include/gpxe/iobuf.h @@ -0,0 +1,148 @@ +#ifndef _GPXE_IOBUF_H +#define _GPXE_IOBUF_H + +/** @file + * + * I/O buffers + * + */ + +#include +#include +#include + +/** + * A persistent I/O buffer + * + * This data structure encapsulates a long-lived I/O buffer. The + * buffer may be passed between multiple owners, queued for possible + * retransmission, etc. + */ +struct io_buffer { + /** List of which this buffer is a member + * + * The list must belong to the current owner of the buffer. + * Different owners may maintain different lists (e.g. a + * retransmission list for TCP). + */ + struct list_head list; + + /** Start of the buffer */ + void *head; + /** Start of data */ + void *data; + /** End of data */ + void *tail; + /** End of the buffer */ + void *end; +}; + +/** + * Reserve space at start of I/O buffer + * + * @v iob I/O buffer + * @v len Length to reserve + * @ret data Pointer to new start of buffer + */ +static inline void * iob_reserve ( struct io_buffer *iob, size_t len ) { + iob->data += len; + iob->tail += len; + assert ( iob->tail <= iob->end ); + return iob->data; +} + +/** + * Add data to start of I/O buffer + * + * @v iob I/O buffer + * @v len Length to add + * @ret data Pointer to new start of buffer + */ +static inline void * iob_push ( struct io_buffer *iob, size_t len ) { + iob->data -= len; + assert ( iob->data >= iob->head ); + return iob->data; +} + +/** + * Remove data from start of I/O buffer + * + * @v iob I/O buffer + * @v len Length to remove + * @ret data Pointer to new start of buffer + */ +static inline void * iob_pull ( struct io_buffer *iob, size_t len ) { + iob->data += len; + assert ( iob->data <= iob->tail ); + return iob->data; +} + +/** + * Add data to end of I/O buffer + * + * @v iob I/O buffer + * @v len Length to add + * @ret data Pointer to newly added space + */ +static inline void * iob_put ( struct io_buffer *iob, size_t len ) { + void *old_tail = iob->tail; + iob->tail += len; + assert ( iob->tail <= iob->end ); + return old_tail; +} + +/** + * Remove data from end of I/O buffer + * + * @v iob I/O buffer + * @v len Length to remove + */ +static inline void iob_unput ( struct io_buffer *iob, size_t len ) { + iob->tail -= len; + assert ( iob->tail >= iob->data ); +} + +/** + * Empty an I/O buffer + * + * @v iob I/O buffer + */ +static inline void iob_empty ( struct io_buffer *iob ) { + iob->tail = iob->data; +} + +/** + * Calculate length of data in an I/O buffer + * + * @v iob I/O buffer + * @ret len Length of data in buffer + */ +static inline size_t iob_len ( struct io_buffer *iob ) { + return ( iob->tail - iob->data ); +} + +/** + * Calculate available space at start of an I/O buffer + * + * @v iob I/O buffer + * @ret len Length of data available at start of buffer + */ +static inline size_t iob_headroom ( struct io_buffer *iob ) { + return ( iob->data - iob->head ); +} + +/** + * Calculate available space at end of an I/O buffer + * + * @v iob I/O buffer + * @ret len Length of data available at end of buffer + */ +static inline size_t iob_tailroom ( struct io_buffer *iob ) { + return ( iob->end - iob->tail ); +} + +extern struct io_buffer * alloc_iob ( size_t len ); +extern void free_iob ( struct io_buffer *iob ); +extern void iob_pad ( struct io_buffer *iob, size_t min_len ); + +#endif /* _GPXE_IOBUF_H */ diff --git a/src/include/gpxe/xfer.h b/src/include/gpxe/xfer.h new file mode 100644 index 00000000..0e577e93 --- /dev/null +++ b/src/include/gpxe/xfer.h @@ -0,0 +1,78 @@ +#ifndef _GPXE_XFER_H +#define _GPXE_XFER_H + +/** @file + * + * Data transfer interfaces + * + */ + +#include +#include +#include + +struct xfer_interface; + +/** Data transfer interface operations */ +struct xfer_interface_operations { + /** Deliver datagram + * + * @v xfer Data-transfer interface + * @v src Source interface + * @v iobuf Datagram I/O buffer + * @ret rc Return status code + */ + int ( * deliver ) ( struct xfer_interface *xfer, + struct xfer_interface *src, + struct io_buffer *iobuf ); +}; + +/** A data transfer interface */ +struct xfer_interface { + /** Generic object communication interface */ + struct interface intf; + /** Operations for received messages */ + struct xfer_interface_operations *op; +}; + +extern struct xfer_interface null_xfer; +extern struct xfer_interface_operations null_xfer_ops; + +static inline struct xfer_interface * +xfer_dest ( struct xfer_interface *xfer ) { + return container_of ( xfer->intf.dest, struct xfer_interface, intf ); +} + +/** + * Plug a data-transfer interface into a new destination interface + * + * @v xfer Data-transfer interface + * @v dest New destination interface + */ +static inline void xfer_plug ( struct xfer_interface *xfer, + struct xfer_interface *dest ) { + plug ( &xfer->intf, &dest->intf ); +} + +/** + * Unplug a data-transfer interface + * + * @v xfer Data-transfer interface + */ +static inline void xfer_unplug ( struct xfer_interface *xfer ) { + plug ( &xfer->intf, &null_xfer.intf ); +} + +/** + * Terminate a data-transfer interface + * + * @v xfer Data-transfer interface + * + * After calling this method, no further messages will be received via + * the interface. + */ +static inline void xfer_terminate ( struct xfer_interface *xfer ) { + xfer->op = &null_xfer_ops; +}; + +#endif /* _GPXE_XFER_H */