/** * Deliver datagram * * @v intf Data transfer interface * @v iobuf Datagram I/O buffer * @v meta Data transfer metadata * @ret rc Return status code */ 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 ); int rc; DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " deliver %zd\n", INTF_INTF_DBG ( intf, dest ), iob_len ( iobuf ) ); if ( op ) { rc = op ( object, iobuf, meta ); } else { /* Default is to discard the I/O buffer */ free_iob ( iobuf ); rc = -EPIPE; } if ( rc != 0 ) { DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " deliver failed: %s\n", INTF_INTF_DBG ( intf, dest ), strerror ( rc ) ); } intf_put ( dest ); return rc; }
/** * Allocate I/O buffer * * @v intf Data transfer interface * @v len I/O buffer payload length * @ret iobuf I/O buffer */ 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 ); struct io_buffer *iobuf; DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " alloc_iob %zd\n", INTF_INTF_DBG ( intf, dest ), len ); if ( op ) { iobuf = op ( object, len ); } else { /* Default is to allocate an I/O buffer with no * reserved space. */ iobuf = alloc_iob ( len ); } if ( ! iobuf ) { DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " alloc_iob " "failed\n", INTF_INTF_DBG ( intf, dest ) ); } intf_put ( dest ); return iobuf; }
/** * Open location * * @v intf Data transfer interface * @v type Location type * @v args Remaining arguments depend upon location type * @ret rc Return status code */ int xfer_vopen ( struct interface *intf, int type, va_list args ) { switch ( type ) { case LOCATION_URI_STRING: { const char *uri_string = va_arg ( args, const char * ); return xfer_open_uri_string ( intf, uri_string ); } case LOCATION_URI: { struct uri *uri = va_arg ( args, struct uri * ); return xfer_open_uri ( intf, uri ); } case LOCATION_SOCKET: { int semantics = va_arg ( args, int ); struct sockaddr *peer = va_arg ( args, struct sockaddr * ); struct sockaddr *local = va_arg ( args, struct sockaddr * ); return xfer_open_socket ( intf, semantics, peer, local ); } default: DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to " "open unsupported location type %d\n", INTF_DBG ( intf ), type ); return -ENOTSUP; } }
/** * Plug an object interface into a new destination object interface * * @v intf Object interface * @v dest New destination object 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 intf_plug ( struct interface *intf, struct interface *dest ) { DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " replug to " INTF_FMT "\n", INTF_INTF_DBG ( intf, intf->dest ), INTF_DBG ( dest ) ); intf_get ( dest ); intf_put ( intf->dest ); intf->dest = dest; }
/** * Send redirection event * * @v intf Data transfer interface * @v type New location type * @v args Remaining arguments depend upon location type * @ret rc Return status code */ int xfer_vredirect ( struct interface *intf, int type, va_list args ) { struct interface tmp = INTF_INIT ( null_intf_desc ); struct interface *dest; xfer_vredirect_TYPE ( void * ) *op = intf_get_dest_op_no_passthru ( intf, xfer_vredirect, &dest ); void *object = intf_object ( dest ); int rc; DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " redirect\n", INTF_INTF_DBG ( intf, dest ) ); if ( op ) { rc = op ( object, type, args ); } else { /* Default is to reopen the interface as instructed, * then send xfer_window_changed() messages to both * new child and parent interfaces. Since our * original child interface is likely to be closed and * unplugged as a result of the call to * xfer_vreopen(), we create a temporary interface in * order to be able to send xfer_window_changed() to * the parent. */ intf_plug ( &tmp, dest ); rc = xfer_vreopen ( dest, type, args ); if ( rc == 0 ) { xfer_window_changed ( dest ); xfer_window_changed ( &tmp ); } intf_unplug ( &tmp ); } if ( rc != 0 ) { DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " redirect " "failed: %s\n", INTF_INTF_DBG ( intf, dest ), strerror ( rc ) ); } intf_put ( dest ); return rc; }
/** * Open socket * * @v intf Data transfer interface * @v semantics Communication semantics (e.g. SOCK_STREAM) * @v peer Peer socket address * @v local Local socket address, or NULL * @ret rc Return status code */ int xfer_open_socket ( struct interface *intf, int semantics, struct sockaddr *peer, struct sockaddr *local ) { struct socket_opener *opener; DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " opening (%s,%s) socket\n", INTF_DBG ( intf ), socket_semantics_name ( semantics ), socket_family_name ( peer->sa_family ) ); for_each_table_entry ( opener, SOCKET_OPENERS ) { if ( ( opener->semantics == semantics ) && ( opener->family == peer->sa_family ) ) { return opener->open ( intf, peer, local ); } } DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to open " "unsupported socket type (%s,%s)\n", INTF_DBG ( intf ), socket_semantics_name ( semantics ), socket_family_name ( peer->sa_family ) ); return -ENOTSUP; }
/** * Shut down an object interface * * @v intf Object interface * @v rc Reason for close * * Blocks further operations from being received via the interface, * executes a close operation on the destination interface, and * unplugs the interface. */ void intf_shutdown ( struct interface *intf, int rc ) { DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " shutting down (%s)\n", INTF_DBG ( intf ), strerror ( rc ) ); /* Block further operations */ intf_nullify ( intf ); /* Notify destination of close */ intf_close ( intf, rc ); /* Unplug interface */ intf_unplug ( intf ); }
/** * Open URI * * @v intf Data transfer interface * @v uri URI * @ret rc Return status code * * The URI will be regarded as being relative to the current working * URI (see churi()). */ int xfer_open_uri ( struct interface *intf, struct uri *uri ) { struct uri_opener *opener; struct uri *resolved_uri; int rc; /* Resolve URI */ resolved_uri = resolve_uri ( cwuri, uri ); if ( ! resolved_uri ) { rc = -ENOMEM; goto err_resolve_uri; } /* Find opener which supports this URI scheme */ opener = xfer_uri_opener ( resolved_uri->scheme ); if ( ! opener ) { DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to open " "unsupported URI scheme \"%s\"\n", INTF_DBG ( intf ), resolved_uri->scheme ); rc = -ENOTSUP; goto err_opener; } /* Call opener */ DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " opening %s URI\n", INTF_DBG ( intf ), resolved_uri->scheme ); if ( ( rc = opener->open ( intf, resolved_uri ) ) != 0 ) { DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " could not open: " "%s\n", INTF_DBG ( intf ), strerror ( rc ) ); goto err_open; } err_open: err_opener: uri_put ( resolved_uri ); err_resolve_uri: return rc; }
/** * Open URI string * * @v intf Data transfer interface * @v uri_string URI string (e.g. "http://ipxe.org/kernel") * @ret rc Return status code * * The URI will be regarded as being relative to the current working * URI (see churi()). */ int xfer_open_uri_string ( struct interface *intf, const char *uri_string ) { struct uri *uri; int rc; DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " opening URI %s\n", INTF_DBG ( intf ), uri_string ); uri = parse_uri ( uri_string ); if ( ! uri ) return -ENOMEM; rc = xfer_open_uri ( intf, uri ); uri_put ( uri ); return rc; }
/** * Name resolved * * @v intf Object interface * @v sa Completed socket address (if successful) */ void resolv_done ( struct interface *intf, struct sockaddr *sa ) { struct interface *dest; resolv_done_TYPE ( void * ) *op = intf_get_dest_op ( intf, resolv_done, &dest ); void *object = intf_object ( dest ); DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " resolv_done\n", INTF_INTF_DBG ( intf, dest ) ); if ( op ) { op ( object, sa ); } else { /* Default is to ignore resolutions */ } intf_put ( dest ); }
/** * Shut down and restart an object interface * * @v intf Object interface * @v rc Reason for close * * Shuts down the interface, then unblocks operations that were * blocked during shutdown. */ void intf_restart ( struct interface *intf, int rc ) { struct interface_descriptor *desc = intf->desc; /* Shut down the interface */ intf_shutdown ( intf, rc ); DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " restarting\n", INTF_DBG ( intf ) ); /* Restore the interface descriptor. Must be done after * shutdown (rather than inhibiting intf_shutdown() from * nullifying the descriptor) in order to avoid a potential * infinite loop as the intf_close() operations on each side * of the link call each other recursively. */ intf->desc = desc; }
/** * Close an object interface * * @v intf Object interface * @v rc Reason for close * * Note that this function merely informs the destination object that * the interface is about to be closed; it doesn't actually disconnect * the interface. In most cases, you probably want to use * intf_shutdown() or intf_restart() instead. */ void intf_close ( struct interface *intf, int rc ) { struct interface *dest; intf_close_TYPE ( void * ) *op = intf_get_dest_op ( intf, intf_close, &dest ); void *object = intf_object ( dest ); DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " close (%s)\n", INTF_INTF_DBG ( intf, dest ), strerror ( rc ) ); if ( op ) { op ( object, rc ); } else { /* Default is to ignore intf_close() */ } intf_put ( dest ); }
/** * Seek to position * * @v intf Data transfer interface * @v offset Offset to new position * @ret rc Return status code */ int xfer_seek ( struct interface *intf, off_t offset ) { struct io_buffer *iobuf; struct xfer_metadata meta = { .flags = XFER_FL_ABS_OFFSET, .offset = offset, }; DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " seek to %ld\n", INTF_DBG ( intf ), offset ); /* Allocate and send a zero-length data buffer */ iobuf = xfer_alloc_iob ( intf, 0 ); if ( ! iobuf ) return -ENOMEM; return xfer_deliver ( intf, iobuf, &meta ); }