|  | @@ -21,6 +21,9 @@
 | 
		
	
		
			
			| 21 | 21 |  #include <string.h>
 | 
		
	
		
			
			| 22 | 22 |  #include <errno.h>
 | 
		
	
		
			
			| 23 | 23 |  #include <gpxe/in.h>
 | 
		
	
		
			
			|  | 24 | +#include <gpxe/xfer.h>
 | 
		
	
		
			
			|  | 25 | +#include <gpxe/open.h>
 | 
		
	
		
			
			|  | 26 | +#include <gpxe/process.h>
 | 
		
	
		
			
			| 24 | 27 |  #include <gpxe/resolv.h>
 | 
		
	
		
			
			| 25 | 28 |  
 | 
		
	
		
			
			| 26 | 29 |  /** @file
 | 
		
	
	
		
			
			|  | @@ -29,7 +32,124 @@
 | 
		
	
		
			
			| 29 | 32 |   *
 | 
		
	
		
			
			| 30 | 33 |   */
 | 
		
	
		
			
			| 31 | 34 |  
 | 
		
	
		
			
			| 32 |  | -static struct async_operations resolv_async_operations;
 | 
		
	
		
			
			|  | 35 | +/***************************************************************************
 | 
		
	
		
			
			|  | 36 | + *
 | 
		
	
		
			
			|  | 37 | + * Name resolution interfaces
 | 
		
	
		
			
			|  | 38 | + *
 | 
		
	
		
			
			|  | 39 | + ***************************************************************************
 | 
		
	
		
			
			|  | 40 | + */
 | 
		
	
		
			
			|  | 41 | +
 | 
		
	
		
			
			|  | 42 | +/**
 | 
		
	
		
			
			|  | 43 | + * Name resolution completed
 | 
		
	
		
			
			|  | 44 | + *
 | 
		
	
		
			
			|  | 45 | + * @v resolv		Name resolution interface
 | 
		
	
		
			
			|  | 46 | + * @v sa		Completed socket address (if successful)
 | 
		
	
		
			
			|  | 47 | + * @v rc		Final status code
 | 
		
	
		
			
			|  | 48 | + */
 | 
		
	
		
			
			|  | 49 | +void resolv_done ( struct resolv_interface *resolv, struct sockaddr *sa,
 | 
		
	
		
			
			|  | 50 | +		   int rc ) {
 | 
		
	
		
			
			|  | 51 | +	struct resolv_interface *dest = resolv_get_dest ( resolv );
 | 
		
	
		
			
			|  | 52 | +
 | 
		
	
		
			
			|  | 53 | +	dest->op->done ( dest, sa, rc );
 | 
		
	
		
			
			|  | 54 | +	resolv_unplug ( resolv );
 | 
		
	
		
			
			|  | 55 | +	resolv_put ( dest );
 | 
		
	
		
			
			|  | 56 | +}
 | 
		
	
		
			
			|  | 57 | +
 | 
		
	
		
			
			|  | 58 | +/**
 | 
		
	
		
			
			|  | 59 | + * Ignore name resolution done() event
 | 
		
	
		
			
			|  | 60 | + *
 | 
		
	
		
			
			|  | 61 | + * @v resolv		Name resolution interface
 | 
		
	
		
			
			|  | 62 | + * @v sa		Completed socket address (if successful)
 | 
		
	
		
			
			|  | 63 | + * @v rc		Final status code
 | 
		
	
		
			
			|  | 64 | + */
 | 
		
	
		
			
			|  | 65 | +void ignore_resolv_done ( struct resolv_interface *resolv __unused,
 | 
		
	
		
			
			|  | 66 | +			  struct sockaddr *sa __unused, int rc __unused ) {
 | 
		
	
		
			
			|  | 67 | +	/* Do nothing */
 | 
		
	
		
			
			|  | 68 | +}
 | 
		
	
		
			
			|  | 69 | +
 | 
		
	
		
			
			|  | 70 | +/** Null name resolution interface operations */
 | 
		
	
		
			
			|  | 71 | +struct resolv_interface_operations null_resolv_ops = {
 | 
		
	
		
			
			|  | 72 | +	.done		= ignore_resolv_done,
 | 
		
	
		
			
			|  | 73 | +};
 | 
		
	
		
			
			|  | 74 | +
 | 
		
	
		
			
			|  | 75 | +/** Null name resolution interface */
 | 
		
	
		
			
			|  | 76 | +struct resolv_interface null_resolv = {
 | 
		
	
		
			
			|  | 77 | +	.intf = {
 | 
		
	
		
			
			|  | 78 | +		.dest = &null_resolv.intf,
 | 
		
	
		
			
			|  | 79 | +		.refcnt = NULL,
 | 
		
	
		
			
			|  | 80 | +	},
 | 
		
	
		
			
			|  | 81 | +	.op = &null_resolv_ops,
 | 
		
	
		
			
			|  | 82 | +};
 | 
		
	
		
			
			|  | 83 | +
 | 
		
	
		
			
			|  | 84 | +/***************************************************************************
 | 
		
	
		
			
			|  | 85 | + *
 | 
		
	
		
			
			|  | 86 | + * Numeric name resolver
 | 
		
	
		
			
			|  | 87 | + *
 | 
		
	
		
			
			|  | 88 | + ***************************************************************************
 | 
		
	
		
			
			|  | 89 | + */
 | 
		
	
		
			
			|  | 90 | +
 | 
		
	
		
			
			|  | 91 | +/** A numeric name resolver */
 | 
		
	
		
			
			|  | 92 | +struct numeric_resolv {
 | 
		
	
		
			
			|  | 93 | +	/** Reference counter */
 | 
		
	
		
			
			|  | 94 | +	struct refcnt refcnt;
 | 
		
	
		
			
			|  | 95 | +	/** Name resolution interface */
 | 
		
	
		
			
			|  | 96 | +	struct resolv_interface resolv;
 | 
		
	
		
			
			|  | 97 | +	/** Process */
 | 
		
	
		
			
			|  | 98 | +	struct process process;
 | 
		
	
		
			
			|  | 99 | +	/** Completed socket address */
 | 
		
	
		
			
			|  | 100 | +	struct sockaddr sa;
 | 
		
	
		
			
			|  | 101 | +	/** Overall status code */
 | 
		
	
		
			
			|  | 102 | +	int rc;
 | 
		
	
		
			
			|  | 103 | +};
 | 
		
	
		
			
			|  | 104 | +
 | 
		
	
		
			
			|  | 105 | +static void numeric_step ( struct process *process ) {
 | 
		
	
		
			
			|  | 106 | +	struct numeric_resolv *numeric =
 | 
		
	
		
			
			|  | 107 | +		container_of ( process, struct numeric_resolv, process );
 | 
		
	
		
			
			|  | 108 | +	
 | 
		
	
		
			
			|  | 109 | +	resolv_done ( &numeric->resolv, &numeric->sa, numeric->rc );
 | 
		
	
		
			
			|  | 110 | +	process_del ( process );
 | 
		
	
		
			
			|  | 111 | +}
 | 
		
	
		
			
			|  | 112 | +
 | 
		
	
		
			
			|  | 113 | +static int numeric_resolv ( struct resolv_interface *resolv,
 | 
		
	
		
			
			|  | 114 | +			    const char *name, struct sockaddr *sa ) {
 | 
		
	
		
			
			|  | 115 | +	struct numeric_resolv *numeric;
 | 
		
	
		
			
			|  | 116 | +	struct sockaddr_in *sin;
 | 
		
	
		
			
			|  | 117 | +
 | 
		
	
		
			
			|  | 118 | +	/* Allocate and initialise structure */
 | 
		
	
		
			
			|  | 119 | +	numeric = malloc ( sizeof ( *numeric ) );
 | 
		
	
		
			
			|  | 120 | +	if ( ! numeric )
 | 
		
	
		
			
			|  | 121 | +		return -ENOMEM;
 | 
		
	
		
			
			|  | 122 | +	memset ( numeric, 0, sizeof ( *numeric ) );
 | 
		
	
		
			
			|  | 123 | +	resolv_init ( &numeric->resolv, &null_resolv_ops, &numeric->refcnt );
 | 
		
	
		
			
			|  | 124 | +	process_init ( &numeric->process, numeric_step, &numeric->refcnt );
 | 
		
	
		
			
			|  | 125 | +	memcpy ( &numeric->sa, sa, sizeof ( numeric->sa ) );
 | 
		
	
		
			
			|  | 126 | +
 | 
		
	
		
			
			|  | 127 | +	DBGC ( numeric, "NUMERIC %p attempting to resolve \"%s\"\n",
 | 
		
	
		
			
			|  | 128 | +	       numeric, name );
 | 
		
	
		
			
			|  | 129 | +
 | 
		
	
		
			
			|  | 130 | +	/* Attempt to resolve name */
 | 
		
	
		
			
			|  | 131 | +	sin = ( ( struct sockaddr_in * ) &numeric->sa );
 | 
		
	
		
			
			|  | 132 | +	sin->sin_family = AF_INET;
 | 
		
	
		
			
			|  | 133 | +	if ( inet_aton ( name, &sin->sin_addr ) == 0 )
 | 
		
	
		
			
			|  | 134 | +		numeric->rc = -EINVAL;
 | 
		
	
		
			
			|  | 135 | +
 | 
		
	
		
			
			|  | 136 | +	/* Attach to parent interface, mortalise self, and return */
 | 
		
	
		
			
			|  | 137 | +	resolv_plug_plug ( &numeric->resolv, resolv );
 | 
		
	
		
			
			|  | 138 | +	ref_put ( &numeric->refcnt );
 | 
		
	
		
			
			|  | 139 | +	return 0;
 | 
		
	
		
			
			|  | 140 | +}
 | 
		
	
		
			
			|  | 141 | +
 | 
		
	
		
			
			|  | 142 | +struct resolver numeric_resolver __resolver ( RESOLV_NUMERIC ) = {
 | 
		
	
		
			
			|  | 143 | +	.name = "NUMERIC",
 | 
		
	
		
			
			|  | 144 | +	.resolv = numeric_resolv,
 | 
		
	
		
			
			|  | 145 | +};
 | 
		
	
		
			
			|  | 146 | +
 | 
		
	
		
			
			|  | 147 | +/***************************************************************************
 | 
		
	
		
			
			|  | 148 | + *
 | 
		
	
		
			
			|  | 149 | + * Name resolution multiplexer
 | 
		
	
		
			
			|  | 150 | + *
 | 
		
	
		
			
			|  | 151 | + ***************************************************************************
 | 
		
	
		
			
			|  | 152 | + */
 | 
		
	
		
			
			| 33 | 153 |  
 | 
		
	
		
			
			| 34 | 154 |  /** Registered name resolvers */
 | 
		
	
		
			
			| 35 | 155 |  static struct resolver resolvers[0]
 | 
		
	
	
		
			
			|  | @@ -37,104 +157,262 @@ static struct resolver resolvers[0]
 | 
		
	
		
			
			| 37 | 157 |  static struct resolver resolvers_end[0]
 | 
		
	
		
			
			| 38 | 158 |  	__table_end ( struct resolver, resolvers );
 | 
		
	
		
			
			| 39 | 159 |  
 | 
		
	
		
			
			|  | 160 | +/** A name resolution multiplexer */
 | 
		
	
		
			
			|  | 161 | +struct resolv_mux {
 | 
		
	
		
			
			|  | 162 | +	/** Reference counter */
 | 
		
	
		
			
			|  | 163 | +	struct refcnt refcnt;
 | 
		
	
		
			
			|  | 164 | +	/** Parent name resolution interface */
 | 
		
	
		
			
			|  | 165 | +	struct resolv_interface parent;
 | 
		
	
		
			
			|  | 166 | +
 | 
		
	
		
			
			|  | 167 | +	/** Child name resolution interface */
 | 
		
	
		
			
			|  | 168 | +	struct resolv_interface child;
 | 
		
	
		
			
			|  | 169 | +	/** Current child resolver */
 | 
		
	
		
			
			|  | 170 | +	struct resolver *resolver;
 | 
		
	
		
			
			|  | 171 | +
 | 
		
	
		
			
			|  | 172 | +	/** Socket address to complete */
 | 
		
	
		
			
			|  | 173 | +	struct sockaddr sa;
 | 
		
	
		
			
			|  | 174 | +	/** Name to be resolved
 | 
		
	
		
			
			|  | 175 | +	 *
 | 
		
	
		
			
			|  | 176 | +	 * Must be at end of structure
 | 
		
	
		
			
			|  | 177 | +	 */
 | 
		
	
		
			
			|  | 178 | +	char name[0];
 | 
		
	
		
			
			|  | 179 | +};
 | 
		
	
		
			
			|  | 180 | +
 | 
		
	
		
			
			| 40 | 181 |  /**
 | 
		
	
		
			
			| 41 |  | - * Start name resolution
 | 
		
	
		
			
			|  | 182 | + * Try current child name resolver
 | 
		
	
		
			
			| 42 | 183 |   *
 | 
		
	
		
			
			| 43 |  | - * @v name		Host name to resolve
 | 
		
	
		
			
			| 44 |  | - * @v sa		Socket address to fill in
 | 
		
	
		
			
			| 45 |  | - * @v parent		Parent asynchronous operation
 | 
		
	
		
			
			|  | 184 | + * @v mux		Name resolution multiplexer
 | 
		
	
		
			
			| 46 | 185 |   * @ret rc		Return status code
 | 
		
	
		
			
			| 47 | 186 |   */
 | 
		
	
		
			
			| 48 |  | -int resolv ( const char *name, struct sockaddr *sa, struct async *parent ) {
 | 
		
	
		
			
			| 49 |  | -	struct resolution *resolution;
 | 
		
	
		
			
			| 50 |  | -	struct resolver *resolver;
 | 
		
	
		
			
			| 51 |  | -	struct sockaddr_in *sin = ( struct sockaddr_in * ) sa;
 | 
		
	
		
			
			| 52 |  | -	struct in_addr in;
 | 
		
	
		
			
			| 53 |  | -	int rc = -ENXIO;
 | 
		
	
		
			
			|  | 187 | +static int resolv_mux_try ( struct resolv_mux *mux ) {
 | 
		
	
		
			
			|  | 188 | +	struct resolver *resolver = mux->resolver;
 | 
		
	
		
			
			|  | 189 | +	int rc;
 | 
		
	
		
			
			| 54 | 190 |  
 | 
		
	
		
			
			| 55 |  | -	/* Allocate and populate resolution structure */
 | 
		
	
		
			
			| 56 |  | -	resolution = malloc ( sizeof ( *resolution ) );
 | 
		
	
		
			
			| 57 |  | -	if ( ! resolution )
 | 
		
	
		
			
			| 58 |  | -		return -ENOMEM;
 | 
		
	
		
			
			| 59 |  | -	memset ( resolution, 0, sizeof ( *resolution ) );
 | 
		
	
		
			
			| 60 |  | -	async_init ( &resolution->async, &resolv_async_operations, parent );
 | 
		
	
		
			
			| 61 |  | -
 | 
		
	
		
			
			| 62 |  | -	/* Check for a dotted quad IP address first */
 | 
		
	
		
			
			| 63 |  | -	if ( inet_aton ( name, &in ) != 0 ) {
 | 
		
	
		
			
			| 64 |  | -		DBGC ( resolution, "RESOLV %p saw valid IP address %s\n",
 | 
		
	
		
			
			| 65 |  | -		       resolution, name );
 | 
		
	
		
			
			| 66 |  | -		sin->sin_family = AF_INET;
 | 
		
	
		
			
			| 67 |  | -		sin->sin_addr = in;
 | 
		
	
		
			
			| 68 |  | -		async_done ( &resolution->async, 0 );
 | 
		
	
		
			
			| 69 |  | -		return 0;
 | 
		
	
		
			
			| 70 |  | -	}
 | 
		
	
		
			
			|  | 191 | +	DBGC ( mux, "RESOLV %p trying method %s\n", mux, resolver->name );
 | 
		
	
		
			
			| 71 | 192 |  
 | 
		
	
		
			
			| 72 |  | -	/* Start up all resolvers */
 | 
		
	
		
			
			| 73 |  | -	for ( resolver = resolvers ; resolver < resolvers_end ; resolver++ ) {
 | 
		
	
		
			
			| 74 |  | -		if ( ( rc = resolver->resolv ( name, sa,
 | 
		
	
		
			
			| 75 |  | -					       &resolution->async ) ) != 0 ) {
 | 
		
	
		
			
			| 76 |  | -			DBGC ( resolution, "RESOLV %p could not start %s: "
 | 
		
	
		
			
			| 77 |  | -			       "%s\n", resolution, resolver->name,
 | 
		
	
		
			
			| 78 |  | -			       strerror ( rc ) );
 | 
		
	
		
			
			| 79 |  | -			/* Continue to try other resolvers */
 | 
		
	
		
			
			| 80 |  | -			continue;
 | 
		
	
		
			
			| 81 |  | -		}
 | 
		
	
		
			
			| 82 |  | -		(resolution->pending)++;
 | 
		
	
		
			
			|  | 193 | +	if ( ( rc = resolver->resolv ( &mux->child, mux->name,
 | 
		
	
		
			
			|  | 194 | +				       &mux->sa ) ) != 0 ) {
 | 
		
	
		
			
			|  | 195 | +		DBGC ( mux, "RESOLV %p could not use method %s: %s\n",
 | 
		
	
		
			
			|  | 196 | +		       mux, resolver->name, strerror ( rc ) );
 | 
		
	
		
			
			|  | 197 | +		return rc;
 | 
		
	
		
			
			| 83 | 198 |  	}
 | 
		
	
		
			
			| 84 |  | -	if ( ! resolution->pending )
 | 
		
	
		
			
			| 85 |  | -		goto err;
 | 
		
	
		
			
			| 86 | 199 |  
 | 
		
	
		
			
			| 87 | 200 |  	return 0;
 | 
		
	
		
			
			|  | 201 | +}
 | 
		
	
		
			
			| 88 | 202 |  
 | 
		
	
		
			
			| 89 |  | - err:
 | 
		
	
		
			
			| 90 |  | -	async_uninit ( &resolution->async );
 | 
		
	
		
			
			| 91 |  | -	free ( resolution );
 | 
		
	
		
			
			| 92 |  | -	return rc;
 | 
		
	
		
			
			|  | 203 | +/**
 | 
		
	
		
			
			|  | 204 | + * Handle done() event from child name resolver
 | 
		
	
		
			
			|  | 205 | + *
 | 
		
	
		
			
			|  | 206 | + * @v resolv		Child name resolution interface
 | 
		
	
		
			
			|  | 207 | + * @v sa		Completed socket address (if successful)
 | 
		
	
		
			
			|  | 208 | + * @v rc		Final status code
 | 
		
	
		
			
			|  | 209 | + */
 | 
		
	
		
			
			|  | 210 | +static void resolv_mux_done ( struct resolv_interface *resolv,
 | 
		
	
		
			
			|  | 211 | +			      struct sockaddr *sa, int rc ) {
 | 
		
	
		
			
			|  | 212 | +	struct resolv_mux *mux =
 | 
		
	
		
			
			|  | 213 | +		container_of ( resolv, struct resolv_mux, child );
 | 
		
	
		
			
			|  | 214 | +
 | 
		
	
		
			
			|  | 215 | +	/* Unplug child */
 | 
		
	
		
			
			|  | 216 | +	resolv_unplug ( &mux->child );
 | 
		
	
		
			
			|  | 217 | +
 | 
		
	
		
			
			|  | 218 | +	/* If this resolution succeeded, stop now */
 | 
		
	
		
			
			|  | 219 | +	if ( rc == 0 ) {
 | 
		
	
		
			
			|  | 220 | +		DBGC ( mux, "RESOLV %p succeeded using method %s\n",
 | 
		
	
		
			
			|  | 221 | +		       mux, mux->resolver->name );
 | 
		
	
		
			
			|  | 222 | +		goto finished;
 | 
		
	
		
			
			|  | 223 | +	}
 | 
		
	
		
			
			|  | 224 | +
 | 
		
	
		
			
			|  | 225 | +	/* Attempt next child resolver, if possible */
 | 
		
	
		
			
			|  | 226 | +	mux->resolver++;
 | 
		
	
		
			
			|  | 227 | +	if ( mux->resolver >= resolvers_end ) {
 | 
		
	
		
			
			|  | 228 | +		DBGC ( mux, "RESOLV %p failed to resolve name\n", mux );
 | 
		
	
		
			
			|  | 229 | +		goto finished;
 | 
		
	
		
			
			|  | 230 | +	}
 | 
		
	
		
			
			|  | 231 | +	if ( ( rc = resolv_mux_try ( mux ) ) != 0 )
 | 
		
	
		
			
			|  | 232 | +		goto finished;
 | 
		
	
		
			
			|  | 233 | +
 | 
		
	
		
			
			|  | 234 | +	/* Next resolver is now running */
 | 
		
	
		
			
			|  | 235 | +	return;
 | 
		
	
		
			
			|  | 236 | +	
 | 
		
	
		
			
			|  | 237 | + finished:
 | 
		
	
		
			
			|  | 238 | +	resolv_done ( &mux->parent, sa, rc );
 | 
		
	
		
			
			| 93 | 239 |  }
 | 
		
	
		
			
			| 94 | 240 |  
 | 
		
	
		
			
			|  | 241 | +/** Name resolution multiplexer operations */
 | 
		
	
		
			
			|  | 242 | +static struct resolv_interface_operations resolv_mux_child_ops = {
 | 
		
	
		
			
			|  | 243 | +	.done		= resolv_mux_done,
 | 
		
	
		
			
			|  | 244 | +};
 | 
		
	
		
			
			|  | 245 | +
 | 
		
	
		
			
			| 95 | 246 |  /**
 | 
		
	
		
			
			| 96 |  | - * Handle child name resolution completion
 | 
		
	
		
			
			|  | 247 | + * Start name resolution
 | 
		
	
		
			
			| 97 | 248 |   *
 | 
		
	
		
			
			| 98 |  | - * @v async		Name resolution asynchronous operation
 | 
		
	
		
			
			| 99 |  | - * @v signal		SIGCHLD
 | 
		
	
		
			
			|  | 249 | + * @v resolv		Name resolution interface
 | 
		
	
		
			
			|  | 250 | + * @v name		Name to resolve
 | 
		
	
		
			
			|  | 251 | + * @v sa		Socket address to complete
 | 
		
	
		
			
			|  | 252 | + * @ret rc		Return status code
 | 
		
	
		
			
			| 100 | 253 |   */
 | 
		
	
		
			
			| 101 |  | -static void resolv_sigchld ( struct async *async,
 | 
		
	
		
			
			| 102 |  | -			     enum signal signal __unused ) {
 | 
		
	
		
			
			| 103 |  | -	struct resolution *resolution =
 | 
		
	
		
			
			| 104 |  | -		container_of ( async, struct resolution, async );
 | 
		
	
		
			
			|  | 254 | +int resolv ( struct resolv_interface *resolv, const char *name,
 | 
		
	
		
			
			|  | 255 | +	     struct sockaddr *sa ) {
 | 
		
	
		
			
			|  | 256 | +	struct resolv_mux *mux;
 | 
		
	
		
			
			|  | 257 | +	size_t name_len = ( strlen ( name ) + 1 );
 | 
		
	
		
			
			| 105 | 258 |  	int rc;
 | 
		
	
		
			
			| 106 | 259 |  
 | 
		
	
		
			
			| 107 |  | -	/* Reap the child */
 | 
		
	
		
			
			| 108 |  | -	async_wait ( async, &rc, 1 );
 | 
		
	
		
			
			|  | 260 | +	/* Allocate and initialise structure */
 | 
		
	
		
			
			|  | 261 | +	mux = malloc ( sizeof ( *mux ) + name_len );
 | 
		
	
		
			
			|  | 262 | +	if ( ! mux )
 | 
		
	
		
			
			|  | 263 | +		return -ENOMEM;
 | 
		
	
		
			
			|  | 264 | +	memset ( mux, 0, sizeof ( *mux ) );
 | 
		
	
		
			
			|  | 265 | +	resolv_init ( &mux->parent, &null_resolv_ops, &mux->refcnt );
 | 
		
	
		
			
			|  | 266 | +	resolv_init ( &mux->child, &resolv_mux_child_ops, &mux->refcnt );
 | 
		
	
		
			
			|  | 267 | +	mux->resolver = resolvers;
 | 
		
	
		
			
			|  | 268 | +	memcpy ( &mux->sa, sa, sizeof ( mux->sa ) );
 | 
		
	
		
			
			|  | 269 | +	memcpy ( mux->name, name, name_len );
 | 
		
	
		
			
			|  | 270 | +
 | 
		
	
		
			
			|  | 271 | +	DBGC ( mux, "RESOLV %p attempting to resolve \"%s\"\n", mux, name );
 | 
		
	
		
			
			| 109 | 272 |  
 | 
		
	
		
			
			| 110 |  | -	/* If this child succeeded, kill all the others.  They should
 | 
		
	
		
			
			| 111 |  | -	 * immediately die (invoking resolv_sigchld() again, which
 | 
		
	
		
			
			| 112 |  | -	 * won't do anything because the exit status is non-zero and
 | 
		
	
		
			
			| 113 |  | -	 * the pending count won't reach zero until this instance
 | 
		
	
		
			
			| 114 |  | -	 * completes).
 | 
		
	
		
			
			|  | 273 | +	/* Start first resolver in chain.  There will always be at
 | 
		
	
		
			
			|  | 274 | +	 * least one resolver (the numeric resolver), so no need to
 | 
		
	
		
			
			|  | 275 | +	 * check for the zero-resolvers-available case.
 | 
		
	
		
			
			| 115 | 276 |  	 */
 | 
		
	
		
			
			| 116 |  | -	if ( rc == 0 )
 | 
		
	
		
			
			| 117 |  | -		async_signal_children ( async, SIGKILL );
 | 
		
	
		
			
			|  | 277 | +	if ( ( rc = resolv_mux_try ( mux ) ) != 0 )
 | 
		
	
		
			
			|  | 278 | +		goto err;
 | 
		
	
		
			
			|  | 279 | +
 | 
		
	
		
			
			|  | 280 | +	/* Attach parent interface, mortalise self, and return */
 | 
		
	
		
			
			|  | 281 | +	resolv_plug_plug ( &mux->parent, resolv );
 | 
		
	
		
			
			|  | 282 | +	ref_put ( &mux->refcnt );
 | 
		
	
		
			
			|  | 283 | +	return 0;
 | 
		
	
		
			
			| 118 | 284 |  
 | 
		
	
		
			
			| 119 |  | -	/* When we have no children left, exit */
 | 
		
	
		
			
			| 120 |  | -	if ( --(resolution->pending) == 0 )
 | 
		
	
		
			
			| 121 |  | -		async_done ( async, rc );
 | 
		
	
		
			
			|  | 285 | + err:
 | 
		
	
		
			
			|  | 286 | +	ref_put ( &mux->refcnt );
 | 
		
	
		
			
			|  | 287 | +	return rc;	
 | 
		
	
		
			
			| 122 | 288 |  }
 | 
		
	
		
			
			| 123 | 289 |  
 | 
		
	
		
			
			|  | 290 | +/***************************************************************************
 | 
		
	
		
			
			|  | 291 | + *
 | 
		
	
		
			
			|  | 292 | + * Named socket opening
 | 
		
	
		
			
			|  | 293 | + *
 | 
		
	
		
			
			|  | 294 | + ***************************************************************************
 | 
		
	
		
			
			|  | 295 | + */
 | 
		
	
		
			
			|  | 296 | +
 | 
		
	
		
			
			|  | 297 | +/** A named socket */
 | 
		
	
		
			
			|  | 298 | +struct named_socket {
 | 
		
	
		
			
			|  | 299 | +	/** Reference counter */
 | 
		
	
		
			
			|  | 300 | +	struct refcnt refcnt;
 | 
		
	
		
			
			|  | 301 | +	/** Data transfer interface */
 | 
		
	
		
			
			|  | 302 | +	struct xfer_interface xfer;
 | 
		
	
		
			
			|  | 303 | +	/** Name resolution interface */
 | 
		
	
		
			
			|  | 304 | +	struct resolv_interface resolv;
 | 
		
	
		
			
			|  | 305 | +	/** Communication semantics (e.g. SOCK_STREAM) */
 | 
		
	
		
			
			|  | 306 | +	int semantics;
 | 
		
	
		
			
			|  | 307 | +	/** Stored local socket address, if applicable */
 | 
		
	
		
			
			|  | 308 | +	struct sockaddr local;
 | 
		
	
		
			
			|  | 309 | +	/** Stored local socket address exists */
 | 
		
	
		
			
			|  | 310 | +	int have_local;
 | 
		
	
		
			
			|  | 311 | +};
 | 
		
	
		
			
			|  | 312 | +
 | 
		
	
		
			
			| 124 | 313 |  /**
 | 
		
	
		
			
			| 125 |  | - * Free name resolution structure
 | 
		
	
		
			
			|  | 314 | + * Handle seek() event
 | 
		
	
		
			
			| 126 | 315 |   *
 | 
		
	
		
			
			| 127 |  | - * @v async		Asynchronous operation
 | 
		
	
		
			
			|  | 316 | + * @v xfer		Data transfer interface
 | 
		
	
		
			
			|  | 317 | + * @v offset		Offset to new position
 | 
		
	
		
			
			|  | 318 | + * @v whence		Basis for new position
 | 
		
	
		
			
			|  | 319 | + * @ret rc		Return status code
 | 
		
	
		
			
			| 128 | 320 |   */
 | 
		
	
		
			
			| 129 |  | -static void resolv_reap ( struct async *async ) {
 | 
		
	
		
			
			| 130 |  | -	free ( container_of ( async, struct resolution, async ) );
 | 
		
	
		
			
			|  | 321 | +static int resolv_xfer_seek ( struct xfer_interface *xfer __unused,
 | 
		
	
		
			
			|  | 322 | +			      off_t offset __unused, int whence __unused ) {
 | 
		
	
		
			
			|  | 323 | +	/* Never ready to accept data */
 | 
		
	
		
			
			|  | 324 | +	return -EAGAIN;
 | 
		
	
		
			
			| 131 | 325 |  }
 | 
		
	
		
			
			| 132 | 326 |  
 | 
		
	
		
			
			| 133 |  | -/** Name resolution asynchronous operations */
 | 
		
	
		
			
			| 134 |  | -static struct async_operations resolv_async_operations = {
 | 
		
	
		
			
			| 135 |  | -	.reap = resolv_reap,
 | 
		
	
		
			
			| 136 |  | -	.signal = {
 | 
		
	
		
			
			| 137 |  | -		[SIGKILL] = async_signal_children,
 | 
		
	
		
			
			| 138 |  | -		[SIGCHLD] = resolv_sigchld,
 | 
		
	
		
			
			| 139 |  | -	},
 | 
		
	
		
			
			|  | 327 | +/** Named socket opener data transfer interface operations */
 | 
		
	
		
			
			|  | 328 | +static struct xfer_interface_operations named_xfer_ops = {
 | 
		
	
		
			
			|  | 329 | +	.close		= ignore_xfer_close,
 | 
		
	
		
			
			|  | 330 | +	.vredirect	= ignore_xfer_vredirect,
 | 
		
	
		
			
			|  | 331 | +	.request	= ignore_xfer_request,
 | 
		
	
		
			
			|  | 332 | +	.seek		= resolv_xfer_seek,
 | 
		
	
		
			
			|  | 333 | +	.alloc_iob	= default_xfer_alloc_iob,
 | 
		
	
		
			
			|  | 334 | +	.deliver_iob	= xfer_deliver_as_raw,
 | 
		
	
		
			
			|  | 335 | +	.deliver_raw	= ignore_xfer_deliver_raw,
 | 
		
	
		
			
			| 140 | 336 |  };
 | 
		
	
		
			
			|  | 337 | +
 | 
		
	
		
			
			|  | 338 | +/**
 | 
		
	
		
			
			|  | 339 | + * Handle done() event
 | 
		
	
		
			
			|  | 340 | + *
 | 
		
	
		
			
			|  | 341 | + * @v resolv		Name resolution interface
 | 
		
	
		
			
			|  | 342 | + * @v sa		Completed socket address (if successful)
 | 
		
	
		
			
			|  | 343 | + * @v rc		Final status code
 | 
		
	
		
			
			|  | 344 | + */
 | 
		
	
		
			
			|  | 345 | +static void named_resolv_done ( struct resolv_interface *resolv,
 | 
		
	
		
			
			|  | 346 | +				struct sockaddr *sa, int rc ) {
 | 
		
	
		
			
			|  | 347 | +	struct named_socket *named =
 | 
		
	
		
			
			|  | 348 | +		container_of ( resolv, struct named_socket, resolv );
 | 
		
	
		
			
			|  | 349 | +
 | 
		
	
		
			
			|  | 350 | +	/* Unplug resolver and nullify data transfer interface */
 | 
		
	
		
			
			|  | 351 | +	resolv_unplug ( &named->resolv );
 | 
		
	
		
			
			|  | 352 | +	xfer_nullify ( &named->xfer );
 | 
		
	
		
			
			|  | 353 | +
 | 
		
	
		
			
			|  | 354 | +	/* Redirect if name resolution was successful */
 | 
		
	
		
			
			|  | 355 | +	if ( rc == 0 ) {
 | 
		
	
		
			
			|  | 356 | +		rc = xfer_redirect ( &named->xfer, LOCATION_SOCKET,
 | 
		
	
		
			
			|  | 357 | +				     named->semantics, sa,
 | 
		
	
		
			
			|  | 358 | +				     ( named->have_local ?
 | 
		
	
		
			
			|  | 359 | +				       &named->local : NULL ) );
 | 
		
	
		
			
			|  | 360 | +	}
 | 
		
	
		
			
			|  | 361 | +
 | 
		
	
		
			
			|  | 362 | +	/* Close data transfer interface if redirection failed */
 | 
		
	
		
			
			|  | 363 | +	if ( rc != 0 )
 | 
		
	
		
			
			|  | 364 | +		xfer_close ( &named->xfer, rc );
 | 
		
	
		
			
			|  | 365 | +
 | 
		
	
		
			
			|  | 366 | +	/* Unplug data transfer interface */
 | 
		
	
		
			
			|  | 367 | +	xfer_unplug ( &named->xfer );
 | 
		
	
		
			
			|  | 368 | +}
 | 
		
	
		
			
			|  | 369 | +
 | 
		
	
		
			
			|  | 370 | +/** Named socket opener name resolution interface operations */
 | 
		
	
		
			
			|  | 371 | +static struct resolv_interface_operations named_resolv_ops = {
 | 
		
	
		
			
			|  | 372 | +	.done		= named_resolv_done,
 | 
		
	
		
			
			|  | 373 | +};
 | 
		
	
		
			
			|  | 374 | +
 | 
		
	
		
			
			|  | 375 | +/**
 | 
		
	
		
			
			|  | 376 | + * Open named socket
 | 
		
	
		
			
			|  | 377 | + *
 | 
		
	
		
			
			|  | 378 | + * @v semantics		Communication semantics (e.g. SOCK_STREAM)
 | 
		
	
		
			
			|  | 379 | + * @v peer		Peer socket address to complete
 | 
		
	
		
			
			|  | 380 | + * @v name		Name to resolve
 | 
		
	
		
			
			|  | 381 | + * @v local		Local socket address, or NULL
 | 
		
	
		
			
			|  | 382 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 383 | + */
 | 
		
	
		
			
			|  | 384 | +int xfer_open_named_socket ( struct xfer_interface *xfer, int semantics,
 | 
		
	
		
			
			|  | 385 | +			     struct sockaddr *peer, const char *name,
 | 
		
	
		
			
			|  | 386 | +			     struct sockaddr *local ) {
 | 
		
	
		
			
			|  | 387 | +	struct named_socket *named;
 | 
		
	
		
			
			|  | 388 | +	int rc;
 | 
		
	
		
			
			|  | 389 | +
 | 
		
	
		
			
			|  | 390 | +	/* Allocate and initialise structure */
 | 
		
	
		
			
			|  | 391 | +	named = malloc ( sizeof ( *named ) );
 | 
		
	
		
			
			|  | 392 | +	if ( ! named )
 | 
		
	
		
			
			|  | 393 | +		return -ENOMEM;
 | 
		
	
		
			
			|  | 394 | +	memset ( named, 0, sizeof ( *named ) );
 | 
		
	
		
			
			|  | 395 | +	xfer_init ( &named->xfer, &named_xfer_ops, &named->refcnt );
 | 
		
	
		
			
			|  | 396 | +	resolv_init ( &named->resolv, &named_resolv_ops, &named->refcnt );
 | 
		
	
		
			
			|  | 397 | +	named->semantics = semantics;
 | 
		
	
		
			
			|  | 398 | +	if ( local ) {
 | 
		
	
		
			
			|  | 399 | +		memcpy ( &named->local, local, sizeof ( named->local ) );
 | 
		
	
		
			
			|  | 400 | +		named->have_local = 1;
 | 
		
	
		
			
			|  | 401 | +	}
 | 
		
	
		
			
			|  | 402 | +
 | 
		
	
		
			
			|  | 403 | +	DBGC ( named, "RESOLV %p opening named socket \"%s\"\n",
 | 
		
	
		
			
			|  | 404 | +	       named, name );
 | 
		
	
		
			
			|  | 405 | +
 | 
		
	
		
			
			|  | 406 | +	/* Start name resolution */
 | 
		
	
		
			
			|  | 407 | +	if ( ( rc = resolv ( &named->resolv, name, peer ) ) != 0 )
 | 
		
	
		
			
			|  | 408 | +		goto err;
 | 
		
	
		
			
			|  | 409 | +
 | 
		
	
		
			
			|  | 410 | +	/* Attach parent interface, mortalise self, and return */
 | 
		
	
		
			
			|  | 411 | +	xfer_plug_plug ( &named->xfer, xfer );
 | 
		
	
		
			
			|  | 412 | +	ref_put ( &named->refcnt );
 | 
		
	
		
			
			|  | 413 | +	return 0;
 | 
		
	
		
			
			|  | 414 | +
 | 
		
	
		
			
			|  | 415 | + err:
 | 
		
	
		
			
			|  | 416 | +	ref_put ( &named->refcnt );
 | 
		
	
		
			
			|  | 417 | +	return rc;
 | 
		
	
		
			
			|  | 418 | +}
 |