Browse Source

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 18 years ago
parent
commit
4e20d73bb5

+ 309
- 17
src/core/async.c View File

16
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
  */
17
  */
18
 
18
 
19
+#include <string.h>
19
 #include <errno.h>
20
 #include <errno.h>
21
+#include <assert.h>
20
 #include <gpxe/process.h>
22
 #include <gpxe/process.h>
21
 #include <gpxe/async.h>
23
 #include <gpxe/async.h>
22
 
24
 
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 View File

36
 			 struct ata_command *command ) {
36
 			 struct ata_command *command ) {
37
 	struct aoe_device *aoedev
37
 	struct aoe_device *aoedev
38
 		= container_of ( ata, struct aoe_device, ata );
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 View File

36
 			   struct scsi_command *command ) {
36
 			   struct scsi_command *command ) {
37
 	struct iscsi_device *iscsidev
37
 	struct iscsi_device *iscsidev
38
 		= container_of ( scsi, struct iscsi_device, scsi );
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 View File

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

+ 4
- 3
src/include/gpxe/aoe.h View File

107
 	/** Byte offset within command's data buffer */
107
 	/** Byte offset within command's data buffer */
108
 	unsigned int command_offset;
108
 	unsigned int command_offset;
109
 	/** Asynchronous operation for this command */
109
 	/** Asynchronous operation for this command */
110
-	struct async_operation aop;
110
+	struct async async;
111
 
111
 
112
 	/** Retransmission timer */
112
 	/** Retransmission timer */
113
 	struct retry_timer timer;
113
 	struct retry_timer timer;
121
 
121
 
122
 extern void aoe_open ( struct aoe_session *aoe );
122
 extern void aoe_open ( struct aoe_session *aoe );
123
 extern void aoe_close ( struct aoe_session *aoe );
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
 /** An AoE device */
128
 /** An AoE device */
128
 struct aoe_device {
129
 struct aoe_device {

+ 146
- 38
src/include/gpxe/async.h View File

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
 #endif /* _GPXE_ASYNC_H */
170
 #endif /* _GPXE_ASYNC_H */

+ 2
- 2
src/include/gpxe/dhcp.h View File

466
 	 */
466
 	 */
467
 	int state;
467
 	int state;
468
 	/** Asynchronous operation for this DHCP session */
468
 	/** Asynchronous operation for this DHCP session */
469
-	struct async_operation aop;
469
+	struct async async;
470
 	/** Retransmission timer */
470
 	/** Retransmission timer */
471
 	struct retry_timer timer;
471
 	struct retry_timer timer;
472
 };
472
 };
504
 				struct dhcp_packet *dhcppkt );
504
 				struct dhcp_packet *dhcppkt );
505
 extern int copy_dhcp_packet_options ( struct dhcp_packet *dhcppkt,
505
 extern int copy_dhcp_packet_options ( struct dhcp_packet *dhcppkt,
506
 				      struct dhcp_option_block *options );
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
 #endif /* _GPXE_DHCP_H */
509
 #endif /* _GPXE_DHCP_H */

+ 1
- 1
src/include/gpxe/ftp.h View File

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

+ 1
- 1
src/include/gpxe/hello.h View File

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

+ 9
- 12
src/include/gpxe/http.h View File

11
 #include <gpxe/tcp.h>
11
 #include <gpxe/tcp.h>
12
 #include <gpxe/async.h>
12
 #include <gpxe/async.h>
13
 #include <gpxe/linebuf.h>
13
 #include <gpxe/linebuf.h>
14
+#include <gpxe/uri.h>
14
 
15
 
15
 /** HTTP default port */
16
 /** HTTP default port */
16
 #define HTTP_PORT 80
17
 #define HTTP_PORT 80
28
  *
29
  *
29
  */
30
  */
30
 struct http_request {
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
 	/** Data buffer to fill */
34
 	/** Data buffer to fill */
38
 	struct buffer *buffer;
35
 	struct buffer *buffer;
36
+	/** Asynchronous operation */
37
+	struct async async;
39
 
38
 
40
 	/** HTTP response code */
39
 	/** HTTP response code */
41
 	unsigned int response;
40
 	unsigned int response;
42
 	/** HTTP Content-Length */
41
 	/** HTTP Content-Length */
43
 	size_t content_length;
42
 	size_t content_length;
44
 
43
 
44
+	/** TCP application for this request */
45
+	struct tcp_application tcp;
45
 	/** Number of bytes already sent */
46
 	/** Number of bytes already sent */
46
 	size_t tx_offset;
47
 	size_t tx_offset;
47
 	/** RX state */
48
 	/** RX state */
48
 	enum http_rx_state rx_state;
49
 	enum http_rx_state rx_state;
49
 	/** Line buffer for received header lines */
50
 	/** Line buffer for received header lines */
50
 	struct line_buffer linebuf;
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
 #endif /* _GPXE_HTTP_H */
57
 #endif /* _GPXE_HTTP_H */

+ 4
- 3
src/include/gpxe/iscsi.h View File

591
 	 */
591
 	 */
592
 	struct scsi_command *command;
592
 	struct scsi_command *command;
593
 	/** Asynchronous operation for the current iSCSI operation */
593
 	/** Asynchronous operation for the current iSCSI operation */
594
-	struct async_operation aop;
594
+	struct async async;
595
 	/** Instant return code
595
 	/** Instant return code
596
 	 *
596
 	 *
597
 	 * Set to a non-zero value if all requests should return
597
 	 * Set to a non-zero value if all requests should return
637
 /** Maximum number of retries at connecting */
637
 /** Maximum number of retries at connecting */
638
 #define ISCSI_MAX_RETRIES 2
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
 extern void iscsi_shutdown ( struct iscsi_session *iscsi );
643
 extern void iscsi_shutdown ( struct iscsi_session *iscsi );
643
 
644
 
644
 /** An iSCSI device */
645
 /** An iSCSI device */

+ 1
- 1
src/include/gpxe/tftp.h View File

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

+ 1
- 1
src/include/usr/fetch.h View File

11
 #include <stdint.h>
11
 #include <stdint.h>
12
 #include <gpxe/uaccess.h>
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
 #endif /* _USR_FETCH_H */
16
 #endif /* _USR_FETCH_H */

+ 7
- 5
src/net/aoe.c View File

56
 	aoe->command = NULL;
56
 	aoe->command = NULL;
57
 
57
 
58
 	/* Mark async operation as complete */
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
  *
309
  *
310
  * @v aoe		AoE session
310
  * @v aoe		AoE session
311
  * @v command		ATA command
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
  * Only one command may be issued concurrently per session.  This call
315
  * Only one command may be issued concurrently per session.  This call
315
  * is non-blocking; use async_wait() to wait for the command to
316
  * is non-blocking; use async_wait() to wait for the command to
316
  * complete.
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
 	aoe->command = command;
321
 	aoe->command = command;
321
 	aoe->status = 0;
322
 	aoe->status = 0;
322
 	aoe->command_offset = 0;
323
 	aoe->command_offset = 0;
323
 	aoe_send_command ( aoe );
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 View File

83
 	tcp_close ( &ftp->tcp_data );
83
 	tcp_close ( &ftp->tcp_data );
84
 
84
 
85
 	/* Mark asynchronous operation as complete */
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
 	if ( ( rc = tcp_connect ( &ftp->tcp, &ftp->server, 0 ) ) != 0 )
379
 	if ( ( rc = tcp_connect ( &ftp->tcp, &ftp->server, 0 ) ) != 0 )
380
 		ftp_done ( ftp, rc );
380
 		ftp_done ( ftp, rc );
381
 
381
 
382
-	return &ftp->aop;
382
+	return &ftp->async;
383
 }
383
 }

+ 3
- 3
src/net/tcp/hello.c View File

51
 static void hello_closed ( struct tcp_application *app, int status ) {
51
 static void hello_closed ( struct tcp_application *app, int status ) {
52
 	struct hello_request *hello = tcp_to_hello ( app );
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
 static void hello_connected ( struct tcp_application *app ) {
57
 static void hello_connected ( struct tcp_application *app ) {
116
 
116
 
117
 	hello->tcp.tcp_op = &hello_tcp_operations;
117
 	hello->tcp.tcp_op = &hello_tcp_operations;
118
 	if ( ( rc = tcp_connect ( &hello->tcp, &hello->server, 0 ) ) != 0 )
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 View File

27
 #include <stdlib.h>
27
 #include <stdlib.h>
28
 #include <string.h>
28
 #include <string.h>
29
 #include <strings.h>
29
 #include <strings.h>
30
-#include <vsprintf.h>
30
+#include <errno.h>
31
 #include <assert.h>
31
 #include <assert.h>
32
+#include <vsprintf.h>
32
 #include <gpxe/async.h>
33
 #include <gpxe/async.h>
34
+#include <gpxe/uri.h>
33
 #include <gpxe/buffer.h>
35
 #include <gpxe/buffer.h>
34
 #include <gpxe/http.h>
36
 #include <gpxe/http.h>
35
 
37
 
67
 	}
69
 	}
68
 
70
 
69
 	/* Mark async operation as complete */
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
 static void http_senddata ( struct tcp_application *app,
305
 static void http_senddata ( struct tcp_application *app,
304
 			    void *buf, size_t len ) {
306
 			    void *buf, size_t len ) {
305
 	struct http_request *http = tcp_to_http ( app );
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
 	len = snprintf ( buf, len,
317
 	len = snprintf ( buf, len,
308
-			 "GET /%s HTTP/1.1\r\n"
318
+			 "GET %s HTTP/1.1\r\n"
309
 			 "User-Agent: gPXE/" VERSION "\r\n"
319
 			 "User-Agent: gPXE/" VERSION "\r\n"
310
 			 "Host: %s\r\n"
320
 			 "Host: %s\r\n"
311
-			 "\r\n", http->filename, http->hostname );
321
+			 "\r\n", path, host );
322
+
312
 	tcp_send ( app, ( buf + http->tx_offset ), ( len - http->tx_offset ) );
323
 	tcp_send ( app, ( buf + http->tx_offset ), ( len - http->tx_offset ) );
313
 }
324
 }
314
 
325
 
346
 	.senddata	= http_senddata,
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
  * Initiate a HTTP connection
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
 	int rc;
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
 	http->tcp.tcp_op = &http_tcp_operations;
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 View File

121
 	iscsi->command = NULL;
121
 	iscsi->command = NULL;
122
 
122
 
123
 	/* Mark asynchronous operation as complete */
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
  *
1208
  *
1209
  * @v iscsi		iSCSI session
1209
  * @v iscsi		iSCSI session
1210
  * @v command		SCSI command
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
 	int rc;
1216
 	int rc;
1216
 
1217
 
1217
 	assert ( iscsi->command == NULL );
1218
 	assert ( iscsi->command == NULL );
1219
 
1220
 
1220
 	if ( iscsi->instant_rc ) {
1221
 	if ( iscsi->instant_rc ) {
1221
 		/* Abort immediately rather than retrying */
1222
 		/* Abort immediately rather than retrying */
1222
-		iscsi_done ( iscsi, iscsi->instant_rc );
1223
+		return iscsi->instant_rc;
1223
 	} else if ( iscsi->status ) {
1224
 	} else if ( iscsi->status ) {
1224
 		/* Session already open: issue command */
1225
 		/* Session already open: issue command */
1225
 		iscsi_start_command ( iscsi );
1226
 		iscsi_start_command ( iscsi );
1231
 					  0 ) ) != 0 ) {
1232
 					  0 ) ) != 0 ) {
1232
 			DBGC ( iscsi, "iSCSI %p could not open TCP "
1233
 			DBGC ( iscsi, "iSCSI %p could not open TCP "
1233
 			       "connection: %s\n", iscsi, strerror ( rc ) );
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 View File

517
 	ref_del ( &dhcp->netdev_ref );
517
 	ref_del ( &dhcp->netdev_ref );
518
 
518
 
519
 	/* Mark async operation as complete */
519
 	/* Mark async operation as complete */
520
-	async_done ( &dhcp->aop, rc );
520
+	async_done ( &dhcp->async, rc );
521
 }
521
 }
522
 
522
 
523
 /** Address for transmitting DHCP requests */
523
 /** Address for transmitting DHCP requests */
713
  * Initiate DHCP on a network interface
713
  * Initiate DHCP on a network interface
714
  *
714
  *
715
  * @v dhcp		DHCP session
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
  * If the DHCP operation completes successfully, the
719
  * If the DHCP operation completes successfully, the
719
  * dhcp_session::options field will be filled in with the resulting
720
  * dhcp_session::options field will be filled in with the resulting
720
  * options block.  The caller takes responsibility for eventually
721
  * options block.  The caller takes responsibility for eventually
721
  * calling free_dhcp_options().
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
 	int rc;
725
 	int rc;
725
 
726
 
726
 	/* Initialise DHCP session */
727
 	/* Initialise DHCP session */
729
 	dhcp->state = DHCPDISCOVER;
730
 	dhcp->state = DHCPDISCOVER;
730
 
731
 
731
 	/* Bind to local port */
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
 	/* Add persistent reference to net device */
736
 	/* Add persistent reference to net device */
738
 	dhcp->netdev_ref.forget = dhcp_forget_netdev;
737
 	dhcp->netdev_ref.forget = dhcp_forget_netdev;
741
 	/* Proof of concept: just send a single DHCPDISCOVER */
740
 	/* Proof of concept: just send a single DHCPDISCOVER */
742
 	dhcp_send_request ( dhcp );
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 View File

142
 	udp_close ( &tftp->udp );
142
 	udp_close ( &tftp->udp );
143
 
143
 
144
 	/* Mark async operation as complete */
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
 
477
 
478
 	/* Open UDP connection */
478
 	/* Open UDP connection */
479
 	if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 ) {
479
 	if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 ) {
480
-		async_done ( &tftp->aop, rc );
480
+		async_done ( &tftp->async, rc );
481
 		goto out;
481
 		goto out;
482
 	}
482
 	}
483
 
483
 
485
 	tftp_send_packet ( tftp );
485
 	tftp_send_packet ( tftp );
486
 
486
 
487
  out:
487
  out:
488
-	return &tftp->aop;
488
+	return &tftp->async;
489
 }
489
 }

+ 1
- 0
src/tests/aoeboot.c View File

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

+ 5
- 0
src/tests/dhcptest.c View File

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

+ 0
- 52
src/tests/ftptest.c View File

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 View File

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 View File

23
 #include <gpxe/dhcp.h>
23
 #include <gpxe/dhcp.h>
24
 #include <gpxe/async.h>
24
 #include <gpxe/async.h>
25
 #include <gpxe/netdevice.h>
25
 #include <gpxe/netdevice.h>
26
+#include <usr/ifmgmt.h>
26
 #include <usr/dhcpmgmt.h>
27
 #include <usr/dhcpmgmt.h>
27
 
28
 
28
 /** @file
29
 /** @file
43
 	struct in_addr address = { htonl ( 0 ) };
44
 	struct in_addr address = { htonl ( 0 ) };
44
 	struct in_addr netmask = { htonl ( 0 ) };
45
 	struct in_addr netmask = { htonl ( 0 ) };
45
 	struct in_addr gateway = { INADDR_NONE };
46
 	struct in_addr gateway = { INADDR_NONE };
47
+	struct async async;
46
 	int rc;
48
 	int rc;
47
 
49
 
48
 	/* Check we can open the interface first */
50
 	/* Check we can open the interface first */
60
 	printf ( "DHCP (%s %s)...", netdev->name, netdev_hwaddr ( netdev ) );
62
 	printf ( "DHCP (%s %s)...", netdev->name, netdev_hwaddr ( netdev ) );
61
 	memset ( &dhcp, 0, sizeof ( dhcp ) );
63
 	memset ( &dhcp, 0, sizeof ( dhcp ) );
62
 	dhcp.netdev = netdev;
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
 		return rc;
73
 		return rc;
66
 	}
74
 	}
67
 	printf ( "done\n" );
75
 	printf ( "done\n" );

+ 36
- 27
src/usr/fetch.c View File

23
  *
23
  *
24
  */
24
  */
25
 
25
 
26
+#include <errno.h>
26
 #include <vsprintf.h>
27
 #include <vsprintf.h>
27
 #include <gpxe/emalloc.h>
28
 #include <gpxe/emalloc.h>
28
 #include <gpxe/ebuffer.h>
29
 #include <gpxe/ebuffer.h>
29
 #include <gpxe/image.h>
30
 #include <gpxe/image.h>
31
+#include <gpxe/uri.h>
30
 #include <usr/fetch.h>
32
 #include <usr/fetch.h>
31
 
33
 
32
 #include <byteswap.h>
34
 #include <byteswap.h>
46
  * caller is responsible for eventually freeing the buffer with
48
  * caller is responsible for eventually freeing the buffer with
47
  * efree().
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
 	struct buffer buffer;
53
 	struct buffer buffer;
51
 	int rc;
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
 	/* Allocate an expandable buffer to hold the file */
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
 #warning "Temporary pseudo-URL parsing code"
68
 #warning "Temporary pseudo-URL parsing code"
58
 
69
 
59
 	/* Retrieve the file */
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
 #if 0
76
 #if 0
77
 	server.sin.sin_port = htons ( TFTP_PORT );
77
 	server.sin.sin_port = htons ( TFTP_PORT );
80
 	tftp.buffer = &buffer;
80
 	tftp.buffer = &buffer;
81
 	aop = tftp_get ( &tftp );
81
 	aop = tftp_get ( &tftp );
82
 #else
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
 #endif
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
 	/* Fill in buffer address and length */
94
 	/* Fill in buffer address and length */
97
 	*data = buffer.addr;
95
 	*data = buffer.addr;
98
 	*len = buffer.fill;
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
 	return 0;
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
 }

Loading…
Cancel
Save