Procházet zdrojové kódy

Gave asynchronous operations approximate POSIX signal semantics. This

will enable us to cascade async operations, which is necessary in order to
properly support DNS.  (For example, an HTTP request may have to redirect
to a new location and will have to perform a new DNS lookup, so we can't
just rely on doing the name lookup at the time of parsing the initial
URL).

Anything other than HTTP is probably broken right now; I'll fix the others
up asap.
tags/v0.9.3
Michael Brown před 17 roky
rodič
revize
4e20d73bb5

+ 309
- 17
src/core/async.c Zobrazit soubor

@@ -16,7 +16,9 @@
16 16
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 17
  */
18 18
 
19
+#include <string.h>
19 20
 #include <errno.h>
21
+#include <assert.h>
20 22
 #include <gpxe/process.h>
21 23
 #include <gpxe/async.h>
22 24
 
@@ -27,26 +29,316 @@
27 29
  */
28 30
 
29 31
 /**
30
- * Wait for asynchronous operation to complete
32
+ * Name signal
31 33
  *
32
- * @v aop		Asynchronous operation
33
- * @ret rc		Return status code
34
+ * @v signal		Signal number
35
+ * @ret name		Name of signal
36
+ */
37
+static inline __attribute__ (( always_inline )) const char *
38
+signal_name ( enum signal signal ) {
39
+	switch ( signal ) {
40
+	case SIGCHLD:		return "SIGCHLD";
41
+	case SIGKILL:		return "SIGKILL";
42
+	case SIGUPDATE:		return "SIGUPDATE";
43
+	default:		return "SIG<UNKNOWN>";
44
+	}
45
+}
46
+
47
+/**
48
+ * Initialise an asynchronous operation
49
+ *
50
+ * @v async		Asynchronous operation
51
+ * @v aop		Asynchronous operation operations to use
52
+ * @v parent		Parent asynchronous operation, or NULL
53
+ * @ret aid		Asynchronous operation ID
34 54
  *
35
- * Blocks until the specified asynchronous operation has completed.
36
- * The return status is the return status of the asynchronous
37
- * operation itself.
55
+ * It is valid to create an asynchronous operation with no parent
56
+ * operation; see async_init_orphan().
38 57
  */
39
-int async_wait ( struct async_operation *aop ) {
40
-	int rc;
58
+aid_t async_init ( struct async *async, struct async_operations *aop,
59
+		   struct async *parent ) {
60
+	static aid_t aid = 1;
41 61
 
42
-	/* Wait for operation to complete */
43
-	do {
44
-		step();
45
-		rc = async_status ( aop );
46
-	} while ( rc == -EINPROGRESS );
47
-	
48
-	/* Prepare for next call to async_wait() */
49
-	async_set_status ( aop, -EINPROGRESS );
62
+	/* Assign identifier.  Negative IDs are used to indicate
63
+	 * errors, so avoid assigning them.
64
+	 */
65
+	++aid;
66
+	aid &= ( ( ~( ( aid_t ) 0 ) ) >> 1 );
67
+
68
+	DBGC ( async, "ASYNC %p (type %p) initialising as", async, aop );
69
+	if ( parent ) {
70
+		DBGC ( async, " child of ASYNC %p", parent );
71
+	} else {
72
+		DBGC ( async, " orphan" );
73
+	}
74
+	DBGC ( async, " with ID %ld\n", aid );
75
+
76
+	assert ( async != NULL );
77
+	assert ( aop != NULL );
78
+
79
+	/* Add to hierarchy */
80
+	if ( parent ) {
81
+		async->parent = parent;
82
+		list_add ( &async->siblings, &parent->children );
83
+	}
84
+	INIT_LIST_HEAD ( &async->children );
85
+
86
+	/* Initialise fields */
87
+	async->rc = -EINPROGRESS;
88
+	async->completed = 0;
89
+	async->total = 0;
90
+	async->aop = aop;
91
+	async->aid = aid;
92
+
93
+	return async->aid;
94
+}
50 95
 
51
-	return rc;
96
+/**
97
+ * SIGCHLD 'ignore' handler
98
+ *
99
+ * @v async		Asynchronous operation
100
+ * @v signal		Signal received
101
+ */
102
+static void async_ignore_sigchld ( struct async *async, enum signal signal ) {
103
+	aid_t waited_aid;
104
+
105
+	assert ( async != NULL );
106
+	assert ( signal == SIGCHLD );
107
+
108
+	/* Reap the child */
109
+	waited_aid = async_wait ( async, NULL, 0 );
110
+	assert ( waited_aid >= 0 );
52 111
 }
112
+
113
+/**
114
+ * 'Ignore' signal handler
115
+ *
116
+ * @v async		Asynchronous operation
117
+ * @v signal		Signal received
118
+ */
119
+void async_ignore_signal ( struct async *async, enum signal signal ) {
120
+
121
+	DBGC ( async, "ASYNC %p using ignore handler for %s\n",
122
+	       async, signal_name ( signal ) );
123
+
124
+	assert ( async != NULL );
125
+
126
+	switch ( signal ) {
127
+	case SIGCHLD:
128
+		async_ignore_sigchld ( async, signal );
129
+		break;
130
+	case SIGKILL:
131
+	case SIGUPDATE:
132
+	default:
133
+		/* Nothing to do */
134
+		break;
135
+	}
136
+}
137
+
138
+/**
139
+ * Default signal handler
140
+ *
141
+ * @v async		Asynchronous operation
142
+ * @v signal		Signal received
143
+ */
144
+static void async_default_signal ( struct async *async, enum signal signal ) {
145
+
146
+	DBGC ( async, "ASYNC %p using default handler for %s\n",
147
+	       async, signal_name ( signal ) );
148
+
149
+	assert ( async != NULL );
150
+
151
+	switch ( signal ) {
152
+	case SIGCHLD:
153
+	case SIGKILL:
154
+	case SIGUPDATE:
155
+	default:
156
+		/* Nothing to do */
157
+		break;
158
+	}
159
+}
160
+
161
+/**
162
+ * Send signal to asynchronous operation
163
+ *
164
+ * @v async		Asynchronous operation
165
+ * @v signal		Signal to send
166
+ */
167
+void async_signal ( struct async *async, enum signal signal ) {
168
+	signal_handler_t handler;
169
+
170
+	DBGC ( async, "ASYNC %p receiving %s\n",
171
+	       async, signal_name ( signal ) );
172
+
173
+	assert ( async != NULL );
174
+	assert ( async->aop != NULL );
175
+	assert ( signal < SIGMAX );
176
+
177
+	handler = async->aop->signal[signal];
178
+	if ( handler ) {
179
+		/* Use the asynchronous operation's signal handler */
180
+		handler ( async, signal );
181
+	} else {
182
+		/* Use the default handler */
183
+		async_default_signal ( async, signal );
184
+	}
185
+}
186
+
187
+/**
188
+ * Send signal to all child asynchronous operations
189
+ *
190
+ * @v async		Asynchronous operation
191
+ * @v signal		Signal to send
192
+ */
193
+void async_signal_children ( struct async *async, enum signal signal ) {
194
+	struct async *child;
195
+	struct async *tmp;
196
+
197
+	assert ( async != NULL );
198
+
199
+	list_for_each_entry_safe ( child, tmp, &async->children, siblings ) {
200
+		async_signal ( child, signal );
201
+	}
202
+}
203
+
204
+/**
205
+ * Mark asynchronous operation as complete
206
+ *
207
+ * @v async		Asynchronous operation
208
+ * @v rc		Return status code
209
+ *
210
+ * An asynchronous operation should call this once it has completed.
211
+ * After calling async_done(), it must be prepared to be reaped by
212
+ * having its reap() method called.
213
+ */
214
+void async_done ( struct async *async, int rc ) {
215
+
216
+	DBGC ( async, "ASYNC %p completing with status %d (%s)\n",
217
+	       async, rc, strerror ( rc ) );
218
+
219
+	assert ( async != NULL );
220
+	assert ( async->parent != NULL );
221
+	assert ( rc != -EINPROGRESS );
222
+
223
+	/* Store return status code */
224
+	async->rc = rc;
225
+
226
+	/* Send SIGCHLD to parent.  Guard against NULL pointer dereferences */
227
+	if ( async->parent )
228
+		async_signal ( async->parent, SIGCHLD );
229
+}
230
+
231
+/**
232
+ * Reap default handler
233
+ *
234
+ * @v async		Asynchronous operation
235
+ */
236
+static void async_reap_default ( struct async *async ) {
237
+
238
+	DBGC ( async, "ASYNC %p ignoring REAP\n", async );
239
+
240
+	assert ( async != NULL );
241
+
242
+	/* Nothing to do */
243
+}
244
+
245
+/**
246
+ * Wait for any child asynchronous operation to complete
247
+ * 
248
+ * @v child		Child asynchronous operation
249
+ * @v rc		Child exit status to fill in, or NULL
250
+ * @v block		Block waiting for child operation to complete
251
+ * @ret aid		Asynchronous operation ID, or -1 on error
252
+ */
253
+aid_t async_wait ( struct async *async, int *rc, int block ) {
254
+	struct async *child;
255
+	aid_t child_aid;
256
+	int dummy_rc;
257
+
258
+	DBGC ( async, "ASYNC %p performing %sblocking wait%s\n", async,
259
+	       ( block ? "" : "non-" ), ( rc ? "" : " (ignoring status)" ) );
260
+
261
+	assert ( async != NULL );
262
+
263
+	/* Avoid multiple tests for "if ( rc )" */
264
+	if ( ! rc )
265
+		rc = &dummy_rc;
266
+
267
+	while ( 1 ) {
268
+
269
+		/* Return immediately if we have no children */
270
+		if ( list_empty ( &async->children ) ) {
271
+			DBGC ( async, "ASYNC %p has no more children\n",
272
+			       async );
273
+			*rc = -ECHILD;
274
+			return -1;
275
+		}
276
+
277
+		/* Look for a completed child */
278
+		list_for_each_entry ( child, &async->children, siblings ) {
279
+			if ( child->rc == -EINPROGRESS )
280
+				continue;
281
+
282
+			/* Found a completed child */
283
+			*rc = child->rc;
284
+			child_aid = child->aid;
285
+
286
+			DBGC ( async, "ASYNC %p reaping child ASYNC %p (ID "
287
+			       "%ld), exit status %d (%s)\n", async, child,
288
+			       child_aid, child->rc, strerror ( child->rc ) );
289
+
290
+			/* Reap the child */
291
+			assert ( child->aop != NULL );
292
+			assert ( list_empty ( &child->children ) );
293
+
294
+			/* Unlink from operations hierarchy */
295
+			list_del ( &child->siblings );
296
+			child->parent = NULL;
297
+
298
+			/* Release all resources */
299
+			if ( child->aop->reap ) {
300
+				child->aop->reap ( child );
301
+			} else {
302
+				async_reap_default ( child );
303
+			}
304
+
305
+			return child_aid;
306
+		}
307
+
308
+		/* Return immediately if non-blocking */
309
+		if ( ! block ) {
310
+			*rc = -EINPROGRESS;
311
+			return -1;
312
+		}
313
+
314
+		/* Allow processes to run */
315
+		step();
316
+	}
317
+}
318
+
319
+/**
320
+ * Default asynchronous operations
321
+ *
322
+ * The default is to ignore SIGCHLD (i.e. to automatically reap
323
+ * children) and to use the default handler (i.e. do nothing) for all
324
+ * other signals.
325
+ */
326
+struct async_operations default_async_operations = {
327
+	.signal = {
328
+		[SIGCHLD] = SIG_IGN,
329
+	},
330
+};
331
+
332
+/**
333
+ * Default asynchronous operations for orphan asynchronous operations
334
+ *
335
+ * The default for orphan asynchronous operations is to do nothing for
336
+ * SIGCHLD (i.e. to not automatically reap children), on the
337
+ * assumption that you're probably creating the orphan solely in order
338
+ * to async_wait() on it.
339
+ */
340
+struct async_operations orphan_async_operations = {
341
+	.signal = {
342
+		[SIGCHLD] = SIG_DFL,
343
+	},
344
+};

+ 7
- 2
src/drivers/ata/aoedev.c Zobrazit soubor

@@ -36,9 +36,14 @@ static int aoe_command ( struct ata_device *ata,
36 36
 			 struct ata_command *command ) {
37 37
 	struct aoe_device *aoedev
38 38
 		= container_of ( ata, struct aoe_device, ata );
39
+	struct async async;
40
+	int rc;
39 41
 
40
-	aoe_issue ( &aoedev->aoe, command );
41
-	return async_wait ( &aoedev->aoe.aop );
42
+	async_init_orphan ( &async );
43
+	if ( ( rc = aoe_issue ( &aoedev->aoe, command, &async ) ) != 0 )
44
+		return rc;
45
+	async_wait ( &async, &rc, 1 );
46
+	return rc;
42 47
 }
43 48
 
44 49
 /**

+ 7
- 1
src/drivers/scsi/iscsidev.c Zobrazit soubor

@@ -36,8 +36,14 @@ static int iscsi_command ( struct scsi_device *scsi,
36 36
 			   struct scsi_command *command ) {
37 37
 	struct iscsi_device *iscsidev
38 38
 		= container_of ( scsi, struct iscsi_device, scsi );
39
+	struct async async;
40
+	int rc;
39 41
 
40
-	return async_wait ( iscsi_issue ( &iscsidev->iscsi, command ) );
42
+	async_init_orphan ( &async );
43
+	if ( ( rc = iscsi_issue ( &iscsidev->iscsi, command, &async ) ) != 0 )
44
+		return rc;
45
+	async_wait ( &async, &rc, 1 );
46
+	return rc;
41 47
 }
42 48
 
43 49
 /**

+ 3
- 2
src/include/errno.h Zobrazit soubor

@@ -125,6 +125,7 @@
125 125
 #define EBUSY		0xd4	/**< Device or resource busy */
126 126
 /** Operation cancelled */
127 127
 #define ECANCELED	PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE
128
+#define ECHILD		ENOENT	/**< No child processes */
128 129
 #define ECONNABORTED	0xd5	/**< Software caused connection abort */
129 130
 #define ECONNREFUSED	0xd6	/**< Connection refused */
130 131
 #define ECONNRESET	0xd7	/**< Connection reset by peer */
@@ -157,10 +158,10 @@
157 158
 #define ENOSYS		0xee	/**< Function not implemented */
158 159
 #define ENOTCONN	0xef	/**< Transport endpoint is not connected */
159 160
 #define ENOTSOCK	0xf0	/**< Socket operation on non-socket */
160
-#define EOPNOTSUPP	0xf1	/**< Operation not supported */
161
-#define ENOTSUP		EOPNOTSUPP /**< Not supported */
161
+#define ENOTSUP		0xf1	/**< Not supported */
162 162
 #define ENOTTY		0xf2	/**< Inappropriate ioctl for device */
163 163
 #define ENXIO		ENODEV	/**< No such device or address */
164
+#define EOPNOTSUPP	ENOTSUP	/**< Operation not supported */
164 165
 #define EOVERFLOW	0xf3	/**< Result too large */
165 166
 #define EPERM		EACCES	/**< Operation not permitted */
166 167
 #define EPROTO		0xf4	/**< Protocol error */

+ 4
- 3
src/include/gpxe/aoe.h Zobrazit soubor

@@ -107,7 +107,7 @@ struct aoe_session {
107 107
 	/** Byte offset within command's data buffer */
108 108
 	unsigned int command_offset;
109 109
 	/** Asynchronous operation for this command */
110
-	struct async_operation aop;
110
+	struct async async;
111 111
 
112 112
 	/** Retransmission timer */
113 113
 	struct retry_timer timer;
@@ -121,8 +121,9 @@ struct aoe_session {
121 121
 
122 122
 extern void aoe_open ( struct aoe_session *aoe );
123 123
 extern void aoe_close ( struct aoe_session *aoe );
124
-extern struct async_operation * aoe_issue ( struct aoe_session *aoe,
125
-					    struct ata_command *command );
124
+extern int aoe_issue ( struct aoe_session *aoe,
125
+		       struct ata_command *command,
126
+		       struct async *parent );
126 127
 
127 128
 /** An AoE device */
128 129
 struct aoe_device {

+ 146
- 38
src/include/gpxe/async.h Zobrazit soubor

@@ -7,56 +7,164 @@
7 7
  *
8 8
  */
9 9
 
10
-#include <errno.h>
11
-#include <assert.h>
10
+#include <gpxe/list.h>
12 11
 
13
-/** An asynchronous operation */
14
-struct async_operation {
15
-	/** Operation status
16
-	 *
17
-	 * This is an error code as defined in errno.h, plus an offset
18
-	 * of EINPROGRESS.  This means that a status value of 0
19
-	 * corresponds to a return status code of -EINPROGRESS,
20
-	 * i.e. that the default state of an asynchronous operation is
21
-	 * "not yet completed".
22
-	 */
23
-	int status;
24
-};
12
+struct async;
25 13
 
26
-/**
27
- * Set asynchronous operation status
14
+/** An asynchronous operation ID
28 15
  *
29
- * @v aop	Asynchronous operation
30
- * @v rc	Return status code
16
+ * Only positive identifiers are valid; negative values are used to
17
+ * indicate errors.
31 18
  */
32
-static inline __attribute__ (( always_inline )) void
33
-async_set_status ( struct async_operation *aop, int rc ) {
34
-	aop->status = ( rc + EINPROGRESS );
35
-}
19
+typedef long aid_t;
20
+
21
+/** Signals that can be delivered to asynchronous operations */
22
+enum signal {
23
+	/** A child asynchronous operation has completed
24
+	 *
25
+	 * The parent should call async_wait() to reap the completed
26
+	 * child.  async_wait() will return the exit status and
27
+	 * operation identifier of the child.
28
+	 *
29
+	 * The handler for this signal can be set to @c NULL; if it
30
+	 * is, then the children will accumulate as zombies until
31
+	 * async_wait() is called.
32
+	 *
33
+	 * The handler for this signal can also be set to @c SIG_IGN;
34
+	 * if it is, then the children will automatically be reaped.
35
+	 * Note that if you use @c SIG_IGN then you will not be able
36
+	 * to retrieve the return status of the children; the call to
37
+	 * async_wait() will simply return -ECHILD.
38
+	 */
39
+	SIGCHLD = 0,
40
+	/** Cancel asynchronous operation
41
+	 *
42
+	 * This signal should trigger the asynchronous operation to
43
+	 * cancel itself (including killing all its own children, if
44
+	 * any), and then call async_done().  The asynchronous
45
+	 * operation is allowed to not complete immediately.
46
+	 *
47
+	 * The handler for this signal can be set to @c NULL; if it
48
+	 * is, then attempts to cancel the asynchronous operation will
49
+	 * fail and the operation will complete normally.  Anything
50
+	 * waiting for the operation to cancel will block.
51
+	 */
52
+	SIGKILL,
53
+	/** Update progress of asynchronous operation
54
+	 *
55
+	 * This signal should cause the asynchronous operation to
56
+	 * immediately update the @c completed and @c total fields.
57
+	 *
58
+	 * The handler for this signal can be set to @c NULL; if it
59
+	 * is, then the asynchronous operation is expected to keep its
60
+	 * @c completed and @c total fields up to date at all times.
61
+	 */
62
+	SIGUPDATE,
63
+	SIGMAX
64
+};
36 65
 
37 66
 /**
38
- * Get asynchronous operation status
67
+ * A signal handler
39 68
  *
40
- * @v aop	Asynchronous operation
41
- * @ret rc	Return status code
69
+ * @v async		Asynchronous operation
70
+ * @v signal		Signal received
42 71
  */
43
-static inline __attribute__ (( always_inline )) int
44
-async_status ( struct async_operation *aop ) {
45
-	return ( aop->status - EINPROGRESS );
46
-}
72
+typedef void ( * signal_handler_t ) ( struct async *async,
73
+				      enum signal signal );
74
+
75
+/** Asynchronous operation operations */
76
+struct async_operations {
77
+	/** Reap asynchronous operation
78
+	 *
79
+	 * @v async		Asynchronous operation
80
+	 *
81
+	 * Release all resources associated with the asynchronous
82
+	 * operation.  This will be called only after the asynchronous
83
+	 * operation itself calls async_done(), so the only remaining
84
+	 * resources will probably be the memory used by the struct
85
+	 * async itself.
86
+	 *
87
+	 * This method can be set to @c NULL; if it is, then no
88
+	 * resources will be freed.  This may be suitable for
89
+	 * asynchronous operations that consume no dynamically
90
+	 * allocated memory.
91
+	 */
92
+	void ( * reap ) ( struct async *async );
93
+	/** Handle signals */
94
+	signal_handler_t signal[SIGMAX];
95
+};
96
+
97
+/** An asynchronous operation */
98
+struct async {
99
+	/** Other asynchronous operations with the same parent */
100
+	struct list_head siblings;
101
+	/** Child asynchronous operations */
102
+	struct list_head children;
103
+	/** Parent asynchronous operation
104
+	 *
105
+	 * This field is optional; if left to NULL then the owner must
106
+	 * never call async_done().
107
+	 */
108
+	struct async *parent;
109
+	/** Asynchronous operation ID */
110
+	aid_t aid;
111
+	/** Final return status code */
112
+	int rc;
113
+
114
+	/** Amount of operation completed so far
115
+	 *
116
+	 * The units for this quantity are arbitrary.  @c completed
117
+	 * divded by @total should give something which approximately
118
+	 * represents the progress through the operation.  For a
119
+	 * download operation, using byte counts would make sense.
120
+	 *
121
+	 * This progress indicator should also incorporate the status
122
+	 * of any child asynchronous operations.
123
+	 */
124
+	unsigned long completed;
125
+	/** Total operation size
126
+	 *
127
+	 * See @c completed.  A zero value means "total size unknown"
128
+	 * and is explcitly permitted; users should take this into
129
+	 * account before calculating @c completed/total.
130
+	 */
131
+	unsigned long total;
132
+
133
+	struct async_operations *aop;
134
+};
135
+
136
+extern struct async_operations default_async_operations;
137
+extern struct async_operations orphan_async_operations;
138
+
139
+extern aid_t async_init ( struct async *async, struct async_operations *aop,
140
+			  struct async *parent );
141
+extern void async_ignore_signal ( struct async *async, enum signal signal );
142
+extern void async_signal ( struct async *async, enum signal signal );
143
+extern void async_signal_children ( struct async *async, enum signal signal );
144
+extern void async_done ( struct async *async, int rc );
145
+extern aid_t async_wait ( struct async *async, int *rc, int block );
146
+
147
+/** Default signal handler */
148
+#define SIG_DFL NULL
149
+
150
+/** Ignore signal */
151
+#define SIG_IGN async_ignore_signal
47 152
 
48 153
 /**
49
- * Flag asynchronous operation as complete
154
+ * Initialise orphan asynchronous operation
50 155
  *
51
- * @v aop	Asynchronous operation
52
- * @v rc	Return status code
156
+ * @v async		Asynchronous operation
157
+ * @ret aid		Asynchronous operation ID
158
+ *
159
+ * An orphan asynchronous operation can act as a context for child
160
+ * operations.  However, you must not call async_done() on such an
161
+ * operation, since this would attempt to send a signal to its
162
+ * (non-existent) parent.  Instead, simply free the structure (after
163
+ * calling async_wait() to ensure that any child operations have
164
+ * completed).
53 165
  */
54
-static inline __attribute__ (( always_inline )) void
55
-async_done ( struct async_operation *aop, int rc ) {
56
-	assert ( rc != -EINPROGRESS );
57
-	async_set_status ( aop, rc );
166
+static inline aid_t async_init_orphan ( struct async *async ) {
167
+	return async_init ( async, &orphan_async_operations, NULL );
58 168
 }
59 169
 
60
-extern int async_wait ( struct async_operation *aop );
61
-
62 170
 #endif /* _GPXE_ASYNC_H */

+ 2
- 2
src/include/gpxe/dhcp.h Zobrazit soubor

@@ -466,7 +466,7 @@ struct dhcp_session {
466 466
 	 */
467 467
 	int state;
468 468
 	/** Asynchronous operation for this DHCP session */
469
-	struct async_operation aop;
469
+	struct async async;
470 470
 	/** Retransmission timer */
471 471
 	struct retry_timer timer;
472 472
 };
@@ -504,6 +504,6 @@ extern int create_dhcp_packet ( struct net_device *netdev, uint8_t msgtype,
504 504
 				struct dhcp_packet *dhcppkt );
505 505
 extern int copy_dhcp_packet_options ( struct dhcp_packet *dhcppkt,
506 506
 				      struct dhcp_option_block *options );
507
-extern struct async_operation * start_dhcp ( struct dhcp_session *dhcp );
507
+extern int start_dhcp ( struct dhcp_session *dhcp, struct async *parent );
508 508
 
509 509
 #endif /* _GPXE_DHCP_H */

+ 1
- 1
src/include/gpxe/ftp.h Zobrazit soubor

@@ -64,7 +64,7 @@ struct ftp_request {
64 64
 	struct tcp_application tcp_data;
65 65
 
66 66
 	/** Asynchronous operation for this FTP operation */
67
-	struct async_operation aop;
67
+	struct async async;
68 68
 };
69 69
 
70 70
 struct async_operation * ftp_get ( struct ftp_request *ftp );

+ 1
- 1
src/include/gpxe/hello.h Zobrazit soubor

@@ -44,7 +44,7 @@ struct hello_request {
44 44
 	struct tcp_application tcp;
45 45
 
46 46
 	/** Asynchronous operation */
47
-	struct async_operation aop;
47
+	struct async async;
48 48
 };
49 49
 
50 50
 extern struct async_operation * say_hello ( struct hello_request *hello );

+ 9
- 12
src/include/gpxe/http.h Zobrazit soubor

@@ -11,6 +11,7 @@
11 11
 #include <gpxe/tcp.h>
12 12
 #include <gpxe/async.h>
13 13
 #include <gpxe/linebuf.h>
14
+#include <gpxe/uri.h>
14 15
 
15 16
 /** HTTP default port */
16 17
 #define HTTP_PORT 80
@@ -28,33 +29,29 @@ enum http_rx_state {
28 29
  *
29 30
  */
30 31
 struct http_request {
31
-	/** Server address */
32
-	struct sockaddr_tcpip server;
33
-	/** Server host name */
34
-	const char *hostname;
35
-	/** Filename */
36
-	const char *filename;
32
+	/** URI being fetched */
33
+	struct uri *uri;
37 34
 	/** Data buffer to fill */
38 35
 	struct buffer *buffer;
36
+	/** Asynchronous operation */
37
+	struct async async;
39 38
 
40 39
 	/** HTTP response code */
41 40
 	unsigned int response;
42 41
 	/** HTTP Content-Length */
43 42
 	size_t content_length;
44 43
 
44
+	/** TCP application for this request */
45
+	struct tcp_application tcp;
45 46
 	/** Number of bytes already sent */
46 47
 	size_t tx_offset;
47 48
 	/** RX state */
48 49
 	enum http_rx_state rx_state;
49 50
 	/** Line buffer for received header lines */
50 51
 	struct line_buffer linebuf;
51
-
52
-	/** TCP application for this request */
53
-	struct tcp_application tcp;
54
-	/** Asynchronous operation */
55
-	struct async_operation aop;
56 52
 };
57 53
 
58
-extern struct async_operation * http_get ( struct http_request *http );
54
+extern int http_get ( struct uri *uri, struct buffer *buffer,
55
+		      struct async *parent );
59 56
 
60 57
 #endif /* _GPXE_HTTP_H */

+ 4
- 3
src/include/gpxe/iscsi.h Zobrazit soubor

@@ -591,7 +591,7 @@ struct iscsi_session {
591 591
 	 */
592 592
 	struct scsi_command *command;
593 593
 	/** Asynchronous operation for the current iSCSI operation */
594
-	struct async_operation aop;
594
+	struct async async;
595 595
 	/** Instant return code
596 596
 	 *
597 597
 	 * Set to a non-zero value if all requests should return
@@ -637,8 +637,9 @@ struct iscsi_session {
637 637
 /** Maximum number of retries at connecting */
638 638
 #define ISCSI_MAX_RETRIES 2
639 639
 
640
-extern struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
641
-					      struct scsi_command *command );
640
+extern int iscsi_issue ( struct iscsi_session *iscsi,
641
+			 struct scsi_command *command,
642
+			 struct async *parent );
642 643
 extern void iscsi_shutdown ( struct iscsi_session *iscsi );
643 644
 
644 645
 /** An iSCSI device */

+ 1
- 1
src/include/gpxe/tftp.h Zobrazit soubor

@@ -135,7 +135,7 @@ struct tftp_session {
135 135
 	int state;
136 136
 	
137 137
 	/** Asynchronous operation for this session */
138
-	struct async_operation aop;
138
+	struct async async;
139 139
 	/** Retransmission timer */
140 140
 	struct retry_timer timer;
141 141
 };

+ 1
- 1
src/include/usr/fetch.h Zobrazit soubor

@@ -11,6 +11,6 @@
11 11
 #include <stdint.h>
12 12
 #include <gpxe/uaccess.h>
13 13
 
14
-extern int fetch ( const char *filename, userptr_t *data, size_t *len );
14
+extern int fetch ( const char *uri_string, userptr_t *data, size_t *len );
15 15
 
16 16
 #endif /* _USR_FETCH_H */

+ 7
- 5
src/net/aoe.c Zobrazit soubor

@@ -56,7 +56,7 @@ static void aoe_done ( struct aoe_session *aoe, int rc ) {
56 56
 	aoe->command = NULL;
57 57
 
58 58
 	/* Mark async operation as complete */
59
-	async_done ( &aoe->aop, rc );
59
+	async_done ( &aoe->async, rc );
60 60
 }
61 61
 
62 62
 /**
@@ -309,17 +309,19 @@ void aoe_close ( struct aoe_session *aoe ) {
309 309
  *
310 310
  * @v aoe		AoE session
311 311
  * @v command		ATA command
312
- * @ret aop		Asynchronous operation
312
+ * @v parent		Parent asynchronous operation
313
+ * @ret rc		Return status code
313 314
  *
314 315
  * Only one command may be issued concurrently per session.  This call
315 316
  * is non-blocking; use async_wait() to wait for the command to
316 317
  * complete.
317 318
  */
318
-struct async_operation * aoe_issue ( struct aoe_session *aoe,
319
-				     struct ata_command *command ) {
319
+int aoe_issue ( struct aoe_session *aoe, struct ata_command *command,
320
+		struct async *parent ) {
320 321
 	aoe->command = command;
321 322
 	aoe->status = 0;
322 323
 	aoe->command_offset = 0;
323 324
 	aoe_send_command ( aoe );
324
-	return &aoe->aop;
325
+	async_init ( &aoe->async, &default_async_operations, parent );
326
+	return 0;
325 327
 }

+ 2
- 2
src/net/tcp/ftp.c Zobrazit soubor

@@ -83,7 +83,7 @@ static void ftp_done ( struct ftp_request *ftp, int rc ) {
83 83
 	tcp_close ( &ftp->tcp_data );
84 84
 
85 85
 	/* Mark asynchronous operation as complete */
86
-	async_done ( &ftp->aop, rc );
86
+	async_done ( &ftp->async, rc );
87 87
 }
88 88
 
89 89
 /**
@@ -379,5 +379,5 @@ struct async_operation * ftp_get ( struct ftp_request *ftp ) {
379 379
 	if ( ( rc = tcp_connect ( &ftp->tcp, &ftp->server, 0 ) ) != 0 )
380 380
 		ftp_done ( ftp, rc );
381 381
 
382
-	return &ftp->aop;
382
+	return &ftp->async;
383 383
 }

+ 3
- 3
src/net/tcp/hello.c Zobrazit soubor

@@ -51,7 +51,7 @@ tcp_to_hello ( struct tcp_application *app ) {
51 51
 static void hello_closed ( struct tcp_application *app, int status ) {
52 52
 	struct hello_request *hello = tcp_to_hello ( app );
53 53
 
54
-	async_done ( &hello->aop, status );
54
+	async_done ( &hello->async, status );
55 55
 }
56 56
 
57 57
 static void hello_connected ( struct tcp_application *app ) {
@@ -116,7 +116,7 @@ struct async_operation * say_hello ( struct hello_request *hello ) {
116 116
 
117 117
 	hello->tcp.tcp_op = &hello_tcp_operations;
118 118
 	if ( ( rc = tcp_connect ( &hello->tcp, &hello->server, 0 ) ) != 0 )
119
-		async_done ( &hello->aop, rc );
119
+		async_done ( &hello->async, rc );
120 120
 
121
-	return &hello->aop;
121
+	return &hello->async;
122 122
 }

+ 75
- 9
src/net/tcp/http.c Zobrazit soubor

@@ -27,9 +27,11 @@
27 27
 #include <stdlib.h>
28 28
 #include <string.h>
29 29
 #include <strings.h>
30
-#include <vsprintf.h>
30
+#include <errno.h>
31 31
 #include <assert.h>
32
+#include <vsprintf.h>
32 33
 #include <gpxe/async.h>
34
+#include <gpxe/uri.h>
33 35
 #include <gpxe/buffer.h>
34 36
 #include <gpxe/http.h>
35 37
 
@@ -67,7 +69,7 @@ static void http_done ( struct http_request *http, int rc ) {
67 69
 	}
68 70
 
69 71
 	/* Mark async operation as complete */
70
-	async_done ( &http->aop, rc );
72
+	async_done ( &http->async, rc );
71 73
 }
72 74
 
73 75
 /**
@@ -303,12 +305,21 @@ static void http_newdata ( struct tcp_application *app,
303 305
 static void http_senddata ( struct tcp_application *app,
304 306
 			    void *buf, size_t len ) {
305 307
 	struct http_request *http = tcp_to_http ( app );
308
+	const char *path = http->uri->path;
309
+	const char *host = http->uri->host;
310
+
311
+	if ( ! path )
312
+		path = "/";
313
+
314
+	if ( ! host )
315
+		host = "";
306 316
 
307 317
 	len = snprintf ( buf, len,
308
-			 "GET /%s HTTP/1.1\r\n"
318
+			 "GET %s HTTP/1.1\r\n"
309 319
 			 "User-Agent: gPXE/" VERSION "\r\n"
310 320
 			 "Host: %s\r\n"
311
-			 "\r\n", http->filename, http->hostname );
321
+			 "\r\n", path, host );
322
+
312 323
 	tcp_send ( app, ( buf + http->tx_offset ), ( len - http->tx_offset ) );
313 324
 }
314 325
 
@@ -346,17 +357,72 @@ static struct tcp_operations http_tcp_operations = {
346 357
 	.senddata	= http_senddata,
347 358
 };
348 359
 
360
+/**
361
+ * Reap asynchronous operation
362
+ *
363
+ * @v async		Asynchronous operation
364
+ */
365
+static void http_reap ( struct async *async ) {
366
+	struct http_request *http =
367
+		container_of ( async, struct http_request, async );
368
+
369
+	free_uri ( http->uri );
370
+	free ( http );
371
+}
372
+
373
+/** HTTP asynchronous operations */
374
+static struct async_operations http_async_operations = {
375
+	.reap			= http_reap,
376
+};
377
+
378
+#warning "Quick name resolution hack"
379
+#include <byteswap.h>
380
+
349 381
 /**
350 382
  * Initiate a HTTP connection
351 383
  *
352
- * @v http	a HTTP request
384
+ * @v uri		Uniform Resource Identifier
385
+ * @v buffer		Buffer into which to download file
386
+ * @v parent		Parent asynchronous operation
387
+ * @ret rc		Return status code
388
+ *
389
+ * If it returns success, this function takes ownership of the URI.
353 390
  */
354
-struct async_operation * http_get ( struct http_request *http ) {
391
+int http_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
392
+	struct http_request *http;
355 393
 	int rc;
356 394
 
395
+	/* Allocate and populate HTTP structure */
396
+	http = malloc ( sizeof ( *http ) );
397
+	if ( ! http ) {
398
+		rc = -ENOMEM;
399
+		goto err;
400
+	}
401
+	memset ( http, 0, sizeof ( *http ) );
402
+	http->uri = uri;
403
+	http->buffer = buffer;
357 404
 	http->tcp.tcp_op = &http_tcp_operations;
358
-	if ( ( rc = tcp_connect ( &http->tcp, &http->server, 0 ) ) != 0 )
359
-		async_done ( &http->aop, rc );
360 405
 
361
-	return &http->aop;
406
+#warning "Quick name resolution hack"
407
+	union {
408
+		struct sockaddr_tcpip st;
409
+		struct sockaddr_in sin;
410
+	} server;
411
+	server.sin.sin_port = htons ( HTTP_PORT );
412
+	server.sin.sin_family = AF_INET;
413
+	if ( inet_aton ( uri->host, &server.sin.sin_addr ) == 0 ) {
414
+		rc = -EINVAL;
415
+		goto err;
416
+	}
417
+
418
+	if ( ( rc = tcp_connect ( &http->tcp, &server.st, 0 ) ) != 0 )
419
+		goto err;
420
+
421
+	async_init ( &http->async, &http_async_operations, parent );
422
+	return 0;
423
+
424
+ err:
425
+	DBGC ( http, "HTTP %p could not create request: %s\n", 
426
+	       http, strerror ( rc ) );
427
+	return rc;
362 428
 }

+ 9
- 7
src/net/tcp/iscsi.c Zobrazit soubor

@@ -121,7 +121,7 @@ static void iscsi_done ( struct iscsi_session *iscsi, int rc ) {
121 121
 	iscsi->command = NULL;
122 122
 
123 123
 	/* Mark asynchronous operation as complete */
124
-	async_done ( &iscsi->aop, rc );
124
+	async_done ( &iscsi->async, rc );
125 125
 }
126 126
 
127 127
 /****************************************************************************
@@ -1208,10 +1208,11 @@ static struct tcp_operations iscsi_tcp_operations = {
1208 1208
  *
1209 1209
  * @v iscsi		iSCSI session
1210 1210
  * @v command		SCSI command
1211
- * @ret aop		Asynchronous operation for this SCSI command
1211
+ * @v parent		Parent asynchronous operation
1212
+ * @ret rc		Return status code
1212 1213
  */
1213
-struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
1214
-				       struct scsi_command *command ) {
1214
+int iscsi_issue ( struct iscsi_session *iscsi, struct scsi_command *command,
1215
+		  struct async *parent ) {
1215 1216
 	int rc;
1216 1217
 
1217 1218
 	assert ( iscsi->command == NULL );
@@ -1219,7 +1220,7 @@ struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
1219 1220
 
1220 1221
 	if ( iscsi->instant_rc ) {
1221 1222
 		/* Abort immediately rather than retrying */
1222
-		iscsi_done ( iscsi, iscsi->instant_rc );
1223
+		return iscsi->instant_rc;
1223 1224
 	} else if ( iscsi->status ) {
1224 1225
 		/* Session already open: issue command */
1225 1226
 		iscsi_start_command ( iscsi );
@@ -1231,11 +1232,12 @@ struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
1231 1232
 					  0 ) ) != 0 ) {
1232 1233
 			DBGC ( iscsi, "iSCSI %p could not open TCP "
1233 1234
 			       "connection: %s\n", iscsi, strerror ( rc ) );
1234
-			iscsi_done ( iscsi, rc );
1235
+			return rc;
1235 1236
 		}
1236 1237
 	}
1237 1238
 
1238
-	return &iscsi->aop;
1239
+	async_init ( &iscsi->async, &default_async_operations, parent );
1240
+	return 0;
1239 1241
 }
1240 1242
 
1241 1243
 /**

+ 8
- 9
src/net/udp/dhcp.c Zobrazit soubor

@@ -517,7 +517,7 @@ static void dhcp_done ( struct dhcp_session *dhcp, int rc ) {
517 517
 	ref_del ( &dhcp->netdev_ref );
518 518
 
519 519
 	/* Mark async operation as complete */
520
-	async_done ( &dhcp->aop, rc );
520
+	async_done ( &dhcp->async, rc );
521 521
 }
522 522
 
523 523
 /** Address for transmitting DHCP requests */
@@ -713,14 +713,15 @@ static void dhcp_forget_netdev ( struct reference *ref ) {
713 713
  * Initiate DHCP on a network interface
714 714
  *
715 715
  * @v dhcp		DHCP session
716
- * @ret aop		Asynchronous operation
716
+ * @v parent		Parent asynchronous operation
717
+ * @ret rc		Return status code
717 718
  *
718 719
  * If the DHCP operation completes successfully, the
719 720
  * dhcp_session::options field will be filled in with the resulting
720 721
  * options block.  The caller takes responsibility for eventually
721 722
  * calling free_dhcp_options().
722 723
  */
723
-struct async_operation * start_dhcp ( struct dhcp_session *dhcp ) {
724
+int start_dhcp ( struct dhcp_session *dhcp, struct async *parent ) {
724 725
 	int rc;
725 726
 
726 727
 	/* Initialise DHCP session */
@@ -729,10 +730,8 @@ struct async_operation * start_dhcp ( struct dhcp_session *dhcp ) {
729 730
 	dhcp->state = DHCPDISCOVER;
730 731
 
731 732
 	/* Bind to local port */
732
-	if ( ( rc = udp_open ( &dhcp->udp, htons ( BOOTPC_PORT ) ) ) != 0 ) {
733
-		async_done ( &dhcp->aop, rc );
734
-		goto out;
735
-	}
733
+	if ( ( rc = udp_open ( &dhcp->udp, htons ( BOOTPC_PORT ) ) ) != 0 )
734
+		return rc;
736 735
 
737 736
 	/* Add persistent reference to net device */
738 737
 	dhcp->netdev_ref.forget = dhcp_forget_netdev;
@@ -741,6 +740,6 @@ struct async_operation * start_dhcp ( struct dhcp_session *dhcp ) {
741 740
 	/* Proof of concept: just send a single DHCPDISCOVER */
742 741
 	dhcp_send_request ( dhcp );
743 742
 
744
- out:
745
-	return &dhcp->aop;
743
+	async_init ( &dhcp->async, &default_async_operations, parent );
744
+	return 0;
746 745
 }

+ 3
- 3
src/net/udp/tftp.c Zobrazit soubor

@@ -142,7 +142,7 @@ static void tftp_done ( struct tftp_session *tftp, int rc ) {
142 142
 	udp_close ( &tftp->udp );
143 143
 
144 144
 	/* Mark async operation as complete */
145
-	async_done ( &tftp->aop, rc );
145
+	async_done ( &tftp->async, rc );
146 146
 }
147 147
 
148 148
 /**
@@ -477,7 +477,7 @@ struct async_operation * tftp_get ( struct tftp_session *tftp ) {
477 477
 
478 478
 	/* Open UDP connection */
479 479
 	if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 ) {
480
-		async_done ( &tftp->aop, rc );
480
+		async_done ( &tftp->async, rc );
481 481
 		goto out;
482 482
 	}
483 483
 
@@ -485,5 +485,5 @@ struct async_operation * tftp_get ( struct tftp_session *tftp ) {
485 485
 	tftp_send_packet ( tftp );
486 486
 
487 487
  out:
488
-	return &tftp->aop;
488
+	return &tftp->async;
489 489
 }

+ 1
- 0
src/tests/aoeboot.c Zobrazit soubor

@@ -1,5 +1,6 @@
1 1
 #include <stdint.h>
2 2
 #include <stdlib.h>
3
+#include <errno.h>
3 4
 #include <vsprintf.h>
4 5
 #include <console.h>
5 6
 #include <gpxe/netdevice.h>

+ 5
- 0
src/tests/dhcptest.c Zobrazit soubor

@@ -1,5 +1,6 @@
1 1
 #include <string.h>
2 2
 #include <stdlib.h>
3
+#include <errno.h>
3 4
 #include <vsprintf.h>
4 5
 #include <byteswap.h>
5 6
 #include <gpxe/ip.h>
@@ -7,6 +8,8 @@
7 8
 #include <gpxe/iscsi.h>
8 9
 #include <gpxe/netdevice.h>
9 10
 
11
+#if 0
12
+
10 13
 static int test_dhcp_aoe_boot ( struct net_device *netdev,
11 14
 				char *aoename ) {
12 15
 	unsigned int drivenum;
@@ -263,3 +266,5 @@ int test_dhcp ( struct net_device *netdev ) {
263 266
  out_no_del_ipv4:
264 267
 	return rc;
265 268
 }
269
+
270
+#endif

+ 0
- 52
src/tests/ftptest.c Zobrazit soubor

@@ -1,52 +0,0 @@
1
-#include <stdint.h>
2
-#include <string.h>
3
-#include <byteswap.h>
4
-#include <console.h>
5
-#include <vsprintf.h>
6
-#include <gpxe/async.h>
7
-#include <gpxe/buffer.h>
8
-#include <gpxe/ftp.h>
9
-
10
-static void print_ftp_response ( char *data, size_t len ) {
11
-	unsigned int i;
12
-	char c;
13
-
14
-	for ( i = 0 ; i < len ; i++ ) {
15
-		c = data[i];
16
-		if ( c == '\r' ) {
17
-			/* Print nothing */
18
-		} else if ( ( c == '\n' ) || ( c >= 32 ) || ( c <= 126 ) ) {
19
-			putchar ( c );
20
-		} else {
21
-			putchar ( '.' );
22
-		}
23
-	}
24
-}
25
-
26
-void test_ftp ( struct sockaddr_tcpip *server, const char *filename ) {
27
-	char data[256];
28
-	struct buffer buffer;
29
-	struct ftp_request ftp;
30
-	int rc;
31
-
32
-	printf ( "FTP fetching %s\n", filename );
33
-	
34
-	memset ( &buffer, 0, sizeof ( buffer ) );
35
-	buffer.addr = virt_to_user ( data );
36
-	buffer.len = sizeof ( data );
37
-
38
-	memset ( &ftp, 0, sizeof ( ftp ) );
39
-	memcpy ( &ftp.server, server, sizeof ( ftp.server ) );
40
-	ftp.filename = filename;
41
-	ftp.buffer = &buffer;
42
-
43
-	rc = async_wait ( ftp_get ( &ftp ) );
44
-	if ( rc ) {
45
-		printf ( "FTP fetch failed\n" );
46
-		return;
47
-	}
48
-
49
-	printf ( "FTP received %d bytes\n", buffer.fill );
50
-
51
-	print_ftp_response ( data, buffer.fill );
52
-}

+ 0
- 43
src/tests/hellotest.c Zobrazit soubor

@@ -1,43 +0,0 @@
1
-#include <stdint.h>
2
-#include <string.h>
3
-#include <byteswap.h>
4
-#include <console.h>
5
-#include <vsprintf.h>
6
-#include <gpxe/async.h>
7
-#include <gpxe/hello.h>
8
-
9
-static void test_hello_callback ( char *data, size_t len ) {
10
-	unsigned int i;
11
-	char c;
12
-
13
-	for ( i = 0 ; i < len ; i++ ) {
14
-		c = data[i];
15
-		if ( c == '\r' ) {
16
-			/* Print nothing */
17
-		} else if ( ( c == '\n' ) || ( c >= 32 ) || ( c <= 126 ) ) {
18
-			putchar ( c );
19
-		} else {
20
-			putchar ( '.' );
21
-		}
22
-	}
23
-}
24
-
25
-void test_hello ( struct sockaddr_tcpip *server, const char *message ) {
26
-	/* Quick and dirty hack */
27
-	struct sockaddr_in *sin = ( struct sockaddr_in * ) server;
28
-	struct hello_request hello;
29
-	int rc;
30
-
31
-	printf ( "Saying \"%s\" to %s:%d\n", message,
32
-		 inet_ntoa ( sin->sin_addr ), ntohs ( sin->sin_port ) );
33
-	
34
-	memset ( &hello, 0, sizeof ( hello ) );
35
-	memcpy ( &hello.server, server, sizeof ( hello.server ) );
36
-	hello.message = message;
37
-	hello.callback = test_hello_callback;
38
-
39
-	rc = async_wait ( say_hello ( &hello ) );
40
-	if ( rc ) {
41
-		printf ( "HELLO fetch failed\n" );
42
-	}
43
-}

+ 10
- 2
src/usr/dhcpmgmt.c Zobrazit soubor

@@ -23,6 +23,7 @@
23 23
 #include <gpxe/dhcp.h>
24 24
 #include <gpxe/async.h>
25 25
 #include <gpxe/netdevice.h>
26
+#include <usr/ifmgmt.h>
26 27
 #include <usr/dhcpmgmt.h>
27 28
 
28 29
 /** @file
@@ -43,6 +44,7 @@ int dhcp ( struct net_device *netdev ) {
43 44
 	struct in_addr address = { htonl ( 0 ) };
44 45
 	struct in_addr netmask = { htonl ( 0 ) };
45 46
 	struct in_addr gateway = { INADDR_NONE };
47
+	struct async async;
46 48
 	int rc;
47 49
 
48 50
 	/* Check we can open the interface first */
@@ -60,8 +62,14 @@ int dhcp ( struct net_device *netdev ) {
60 62
 	printf ( "DHCP (%s %s)...", netdev->name, netdev_hwaddr ( netdev ) );
61 63
 	memset ( &dhcp, 0, sizeof ( dhcp ) );
62 64
 	dhcp.netdev = netdev;
63
-	if ( ( rc = async_wait ( start_dhcp ( &dhcp ) ) ) != 0 ) {
64
-		printf ( "failed\n" );
65
+	async_init_orphan ( &async );
66
+	if ( ( rc = start_dhcp ( &dhcp, &async ) ) != 0 ) {
67
+		printf ( "could not start (%s)\n", strerror ( rc ) );
68
+		return rc;
69
+	}
70
+	async_wait ( &async, &rc, 1 );	
71
+	if ( rc != 0 ) {
72
+		printf ( "failed (%s)\n", strerror ( rc ) );
65 73
 		return rc;
66 74
 	}
67 75
 	printf ( "done\n" );

+ 36
- 27
src/usr/fetch.c Zobrazit soubor

@@ -23,10 +23,12 @@
23 23
  *
24 24
  */
25 25
 
26
+#include <errno.h>
26 27
 #include <vsprintf.h>
27 28
 #include <gpxe/emalloc.h>
28 29
 #include <gpxe/ebuffer.h>
29 30
 #include <gpxe/image.h>
31
+#include <gpxe/uri.h>
30 32
 #include <usr/fetch.h>
31 33
 
32 34
 #include <byteswap.h>
@@ -46,32 +48,30 @@
46 48
  * caller is responsible for eventually freeing the buffer with
47 49
  * efree().
48 50
  */
49
-int fetch ( const char *filename, userptr_t *data, size_t *len ) {
51
+int fetch ( const char *uri_string, userptr_t *data, size_t *len ) {
52
+	struct uri *uri;
50 53
 	struct buffer buffer;
51 54
 	int rc;
52 55
 
56
+	/* Parse the URI */
57
+	uri = parse_uri ( uri_string );
58
+	if ( ! uri ) {
59
+		rc = -ENOMEM;
60
+		goto err_parse_uri;
61
+	}
62
+
53 63
 	/* Allocate an expandable buffer to hold the file */
54
-	if ( ( rc = ebuffer_alloc ( &buffer, 0 ) ) != 0 )
55
-		return rc;
64
+	if ( ( rc = ebuffer_alloc ( &buffer, 0 ) ) != 0 ) {
65
+		goto err_ebuffer_alloc;
66
+	}
56 67
 
57 68
 #warning "Temporary pseudo-URL parsing code"
58 69
 
59 70
 	/* Retrieve the file */
60
-	union {
61
-		struct sockaddr_tcpip st;
62
-		struct sockaddr_in sin;
63
-	} server;
64
-	struct tftp_session tftp;
65
-	struct http_request http;
66
-	struct async_operation *aop;
67
-
68
-	memset ( &tftp, 0, sizeof ( tftp ) );
69
-	memset ( &http, 0, sizeof ( http ) );
70
-	memset ( &server, 0, sizeof ( server ) );
71
-	server.sin.sin_family = AF_INET;
72
-	find_global_dhcp_ipv4_option ( DHCP_EB_SIADDR,
73
-				       &server.sin.sin_addr );
71
+	struct async async;
74 72
 
73
+	int ( * download ) ( struct uri *uri, struct buffer *buffer,
74
+			     struct async *parent );
75 75
 
76 76
 #if 0
77 77
 	server.sin.sin_port = htons ( TFTP_PORT );
@@ -80,22 +80,31 @@ int fetch ( const char *filename, userptr_t *data, size_t *len ) {
80 80
 	tftp.buffer = &buffer;
81 81
 	aop = tftp_get ( &tftp );
82 82
 #else
83
-	server.sin.sin_port = htons ( HTTP_PORT );
84
-	memcpy ( &http.server, &server, sizeof ( http.server ) );
85
-	http.hostname = inet_ntoa ( server.sin.sin_addr );
86
-	http.filename = filename;
87
-	http.buffer = &buffer;
88
-	aop = http_get ( &http );
83
+	download = http_get;
89 84
 #endif
90 85
 
91
-	if ( ( rc = async_wait ( aop ) ) != 0 ) {
92
-		efree ( buffer.addr );
93
-		return rc;
94
-	}
86
+	async_init_orphan ( &async );
87
+	if ( ( rc = download ( uri, &buffer, &async ) ) != 0 )
88
+		goto err;
89
+	uri = NULL;
90
+	async_wait ( &async, &rc, 1 );
91
+	if ( rc != 0 )
92
+		goto err;
95 93
 
96 94
 	/* Fill in buffer address and length */
97 95
 	*data = buffer.addr;
98 96
 	*len = buffer.fill;
99 97
 
98
+	/* Release temporary resources.  The ebuffer storage is now
99
+	 * owned by our caller, so we don't free it.
100
+	 */
101
+
100 102
 	return 0;
103
+
104
+ err:
105
+	efree ( buffer.addr );
106
+ err_ebuffer_alloc:
107
+	free_uri ( uri );
108
+ err_parse_uri:
109
+	return rc;
101 110
 }

Načítá se…
Zrušit
Uložit