Browse Source

Introduce name resolution interface and named socket opener.

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
63719deea9
3 changed files with 485 additions and 95 deletions
  1. 352
    74
      src/core/resolv.c
  2. 132
    20
      src/include/gpxe/resolv.h
  3. 1
    1
      src/net/udp/dns.c

+ 352
- 74
src/core/resolv.c View File

@@ -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
+}

+ 132
- 20
src/include/gpxe/resolv.h View File

@@ -7,10 +7,126 @@
7 7
  *
8 8
  */
9 9
 
10
+#include <gpxe/refcnt.h>
11
+#include <gpxe/interface.h>
12
+#include <gpxe/tables.h>
13
+
10 14
 struct sockaddr;
15
+struct resolv_interface;
11 16
 
12
-#include <gpxe/async.h>
13
-#include <gpxe/tables.h>
17
+/** Name resolution interface operations */
18
+struct resolv_interface_operations {
19
+	/** Name resolution completed
20
+	 *
21
+	 * @v resolv		Name resolution interface
22
+	 * @v sa		Completed socket address (if successful)
23
+	 * @v rc		Final status code
24
+	 */
25
+	void ( * done ) ( struct resolv_interface *resolv,
26
+			  struct sockaddr *sa, int rc );
27
+};
28
+
29
+/** A name resolution interface */
30
+struct resolv_interface {
31
+	/** Generic object communication interface */
32
+	struct interface intf;
33
+	/** Operations for received messages */
34
+	struct resolv_interface_operations *op;
35
+};
36
+
37
+extern struct resolv_interface null_resolv;
38
+extern struct resolv_interface_operations null_resolv_ops;
39
+
40
+/**
41
+ * Initialise a name resolution interface
42
+ *
43
+ * @v resolv		Name resolution interface
44
+ * @v op		Name resolution interface operations
45
+ * @v refcnt		Containing object reference counter, or NULL
46
+ */
47
+static inline void resolv_init ( struct resolv_interface *resolv,
48
+				 struct resolv_interface_operations *op,
49
+				 struct refcnt *refcnt ) {
50
+	resolv->intf.dest = &null_resolv.intf;
51
+	resolv->intf.refcnt = refcnt;
52
+	resolv->op = op;
53
+}
54
+
55
+/**
56
+ * Get name resolution interface from generic object communication interface
57
+ *
58
+ * @v intf		Generic object communication interface
59
+ * @ret resolv		Name resolution interface
60
+ */
61
+static inline __attribute__ (( always_inline )) struct resolv_interface *
62
+intf_to_resolv ( struct interface *intf ) {
63
+	return container_of ( intf, struct resolv_interface, intf );
64
+}
65
+
66
+/**
67
+ * Get reference to destination name resolution interface
68
+ *
69
+ * @v resolv		Name resolution interface
70
+ * @ret dest		Destination interface
71
+ */
72
+static inline __attribute__ (( always_inline )) struct resolv_interface *
73
+resolv_get_dest ( struct resolv_interface *resolv ) {
74
+	return intf_to_resolv ( intf_get ( resolv->intf.dest ) );
75
+}
76
+
77
+/**
78
+ * Drop reference to name resolution interface
79
+ *
80
+ * @v resolv		name resolution interface
81
+ */
82
+static inline __attribute__ (( always_inline )) void
83
+resolv_put ( struct resolv_interface *resolv ) {
84
+	intf_put ( &resolv->intf );
85
+}
86
+
87
+/**
88
+ * Plug a name resolution interface into a new destination interface
89
+ *
90
+ * @v resolv		Name resolution interface
91
+ * @v dest		New destination interface
92
+ */
93
+static inline __attribute__ (( always_inline )) void
94
+resolv_plug ( struct resolv_interface *resolv, struct resolv_interface *dest ) {
95
+	plug ( &resolv->intf, &dest->intf );
96
+}
97
+
98
+/**
99
+ * Plug two name resolution interfaces together
100
+ *
101
+ * @v a			Name resolution interface A
102
+ * @v b			Name resolution interface B
103
+ */
104
+static inline __attribute__ (( always_inline )) void
105
+resolv_plug_plug ( struct resolv_interface *a, struct resolv_interface *b ) {
106
+	plug_plug ( &a->intf, &b->intf );
107
+}
108
+
109
+/**
110
+ * Unplug a name resolution interface
111
+ *
112
+ * @v resolv		Name resolution interface
113
+ */
114
+static inline __attribute__ (( always_inline )) void
115
+resolv_unplug ( struct resolv_interface *resolv ) {
116
+	plug ( &resolv->intf, &null_resolv.intf );
117
+}
118
+
119
+/**
120
+ * Stop using a name resolution interface
121
+ *
122
+ * @v resolv		Name resolution interface
123
+ *
124
+ * After calling this method, no further messages will be received via
125
+ * the interface.
126
+ */
127
+static inline void resolv_nullify ( struct resolv_interface *resolv ) {
128
+	resolv->op = &null_resolv_ops;
129
+};
14 130
 
15 131
 /** A name resolver */
16 132
 struct resolver {
@@ -18,30 +134,26 @@ struct resolver {
18 134
 	const char *name;
19 135
 	/** Start name resolution
20 136
 	 *
21
-	 * @v name		Host name to resolve
22
-	 * @v sa		Socket address to fill in
23
-	 * @v parent		Parent asynchronous operation
137
+	 * @v resolv		Name resolution interface
138
+	 * @v name		Name to resolve
139
+	 * @v sa		Socket address to complete
24 140
 	 * @ret rc		Return status code
25
-	 *
26
-	 * The asynchronous process must be prepared to accept
27
-	 * SIGKILL.
28 141
 	 */
29
-	int ( * resolv ) ( const char *name, struct sockaddr *sa,
30
-			   struct async *parent );
142
+	int ( * resolv ) ( struct resolv_interface *resolv, const char *name,
143
+			   struct sockaddr *sa );
31 144
 };
32 145
 
33
-/** A name resolution in progress */
34
-struct resolution {
35
-	/** Asynchronous operation */
36
-	struct async async;
37
-	/** Numner of active child resolvers */
38
-	unsigned int pending;
39
-};
146
+/** Numeric resolver priority */
147
+#define RESOLV_NUMERIC 01
148
+
149
+/** Normal resolver priority */
150
+#define RESOLV_NORMAL 02
40 151
 
41 152
 /** Register as a name resolver */
42
-#define __resolver __table ( struct resolver, resolvers, 01 )
153
+#define __resolver( resolv_order ) \
154
+	__table ( struct resolver, resolvers, resolv_order )
43 155
 
44
-extern int resolv ( const char *name, struct sockaddr *sa,
45
-		    struct async *parent );
156
+extern int resolv ( struct resolv_interface *resolv, const char *name,
157
+		    struct sockaddr *sa );
46 158
 
47 159
 #endif /* _GPXE_RESOLV_H */

+ 1
- 1
src/net/udp/dns.c View File

@@ -486,7 +486,7 @@ int dns_resolv ( const char *name, struct sockaddr *sa,
486 486
 }
487 487
 
488 488
 /** DNS name resolver */
489
-struct resolver dns_resolver __resolver = {
489
+struct resolver dns_resolver __resolver ( RESOLV_NORMAL ) = {
490 490
 	.name = "DNS",
491 491
 	.resolv = dns_resolv,
492 492
 };

Loading…
Cancel
Save