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.
This commit is contained in:
Michael Brown
2007-01-15 08:49:10 +00:00
parent ec75b269d3
commit 4e20d73bb5
26 changed files with 656 additions and 248 deletions

View File

@@ -56,7 +56,7 @@ static void aoe_done ( struct aoe_session *aoe, int rc ) {
aoe->command = NULL;
/* Mark async operation as complete */
async_done ( &aoe->aop, rc );
async_done ( &aoe->async, rc );
}
/**
@@ -309,17 +309,19 @@ void aoe_close ( struct aoe_session *aoe ) {
*
* @v aoe AoE session
* @v command ATA command
* @ret aop Asynchronous operation
* @v parent Parent asynchronous operation
* @ret rc Return status code
*
* Only one command may be issued concurrently per session. This call
* is non-blocking; use async_wait() to wait for the command to
* complete.
*/
struct async_operation * aoe_issue ( struct aoe_session *aoe,
struct ata_command *command ) {
int aoe_issue ( struct aoe_session *aoe, struct ata_command *command,
struct async *parent ) {
aoe->command = command;
aoe->status = 0;
aoe->command_offset = 0;
aoe_send_command ( aoe );
return &aoe->aop;
async_init ( &aoe->async, &default_async_operations, parent );
return 0;
}

View File

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

View File

@@ -51,7 +51,7 @@ tcp_to_hello ( struct tcp_application *app ) {
static void hello_closed ( struct tcp_application *app, int status ) {
struct hello_request *hello = tcp_to_hello ( app );
async_done ( &hello->aop, status );
async_done ( &hello->async, status );
}
static void hello_connected ( struct tcp_application *app ) {
@@ -116,7 +116,7 @@ struct async_operation * say_hello ( struct hello_request *hello ) {
hello->tcp.tcp_op = &hello_tcp_operations;
if ( ( rc = tcp_connect ( &hello->tcp, &hello->server, 0 ) ) != 0 )
async_done ( &hello->aop, rc );
async_done ( &hello->async, rc );
return &hello->aop;
return &hello->async;
}

View File

@@ -27,9 +27,11 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <vsprintf.h>
#include <errno.h>
#include <assert.h>
#include <vsprintf.h>
#include <gpxe/async.h>
#include <gpxe/uri.h>
#include <gpxe/buffer.h>
#include <gpxe/http.h>
@@ -67,7 +69,7 @@ static void http_done ( struct http_request *http, int rc ) {
}
/* Mark async operation as complete */
async_done ( &http->aop, rc );
async_done ( &http->async, rc );
}
/**
@@ -303,12 +305,21 @@ static void http_newdata ( struct tcp_application *app,
static void http_senddata ( struct tcp_application *app,
void *buf, size_t len ) {
struct http_request *http = tcp_to_http ( app );
const char *path = http->uri->path;
const char *host = http->uri->host;
if ( ! path )
path = "/";
if ( ! host )
host = "";
len = snprintf ( buf, len,
"GET /%s HTTP/1.1\r\n"
"GET %s HTTP/1.1\r\n"
"User-Agent: gPXE/" VERSION "\r\n"
"Host: %s\r\n"
"\r\n", http->filename, http->hostname );
"\r\n", path, host );
tcp_send ( app, ( buf + http->tx_offset ), ( len - http->tx_offset ) );
}
@@ -346,17 +357,72 @@ static struct tcp_operations http_tcp_operations = {
.senddata = http_senddata,
};
/**
* Reap asynchronous operation
*
* @v async Asynchronous operation
*/
static void http_reap ( struct async *async ) {
struct http_request *http =
container_of ( async, struct http_request, async );
free_uri ( http->uri );
free ( http );
}
/** HTTP asynchronous operations */
static struct async_operations http_async_operations = {
.reap = http_reap,
};
#warning "Quick name resolution hack"
#include <byteswap.h>
/**
* Initiate a HTTP connection
*
* @v http a HTTP request
* @v uri Uniform Resource Identifier
* @v buffer Buffer into which to download file
* @v parent Parent asynchronous operation
* @ret rc Return status code
*
* If it returns success, this function takes ownership of the URI.
*/
struct async_operation * http_get ( struct http_request *http ) {
int http_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
struct http_request *http;
int rc;
/* Allocate and populate HTTP structure */
http = malloc ( sizeof ( *http ) );
if ( ! http ) {
rc = -ENOMEM;
goto err;
}
memset ( http, 0, sizeof ( *http ) );
http->uri = uri;
http->buffer = buffer;
http->tcp.tcp_op = &http_tcp_operations;
if ( ( rc = tcp_connect ( &http->tcp, &http->server, 0 ) ) != 0 )
async_done ( &http->aop, rc );
return &http->aop;
#warning "Quick name resolution hack"
union {
struct sockaddr_tcpip st;
struct sockaddr_in sin;
} server;
server.sin.sin_port = htons ( HTTP_PORT );
server.sin.sin_family = AF_INET;
if ( inet_aton ( uri->host, &server.sin.sin_addr ) == 0 ) {
rc = -EINVAL;
goto err;
}
if ( ( rc = tcp_connect ( &http->tcp, &server.st, 0 ) ) != 0 )
goto err;
async_init ( &http->async, &http_async_operations, parent );
return 0;
err:
DBGC ( http, "HTTP %p could not create request: %s\n",
http, strerror ( rc ) );
return rc;
}

View File

@@ -121,7 +121,7 @@ static void iscsi_done ( struct iscsi_session *iscsi, int rc ) {
iscsi->command = NULL;
/* Mark asynchronous operation as complete */
async_done ( &iscsi->aop, rc );
async_done ( &iscsi->async, rc );
}
/****************************************************************************
@@ -1208,10 +1208,11 @@ static struct tcp_operations iscsi_tcp_operations = {
*
* @v iscsi iSCSI session
* @v command SCSI command
* @ret aop Asynchronous operation for this SCSI command
* @v parent Parent asynchronous operation
* @ret rc Return status code
*/
struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
struct scsi_command *command ) {
int iscsi_issue ( struct iscsi_session *iscsi, struct scsi_command *command,
struct async *parent ) {
int rc;
assert ( iscsi->command == NULL );
@@ -1219,7 +1220,7 @@ struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
if ( iscsi->instant_rc ) {
/* Abort immediately rather than retrying */
iscsi_done ( iscsi, iscsi->instant_rc );
return iscsi->instant_rc;
} else if ( iscsi->status ) {
/* Session already open: issue command */
iscsi_start_command ( iscsi );
@@ -1231,11 +1232,12 @@ struct async_operation * iscsi_issue ( struct iscsi_session *iscsi,
0 ) ) != 0 ) {
DBGC ( iscsi, "iSCSI %p could not open TCP "
"connection: %s\n", iscsi, strerror ( rc ) );
iscsi_done ( iscsi, rc );
return rc;
}
}
return &iscsi->aop;
async_init ( &iscsi->async, &default_async_operations, parent );
return 0;
}
/**

View File

@@ -517,7 +517,7 @@ static void dhcp_done ( struct dhcp_session *dhcp, int rc ) {
ref_del ( &dhcp->netdev_ref );
/* Mark async operation as complete */
async_done ( &dhcp->aop, rc );
async_done ( &dhcp->async, rc );
}
/** Address for transmitting DHCP requests */
@@ -713,14 +713,15 @@ static void dhcp_forget_netdev ( struct reference *ref ) {
* Initiate DHCP on a network interface
*
* @v dhcp DHCP session
* @ret aop Asynchronous operation
* @v parent Parent asynchronous operation
* @ret rc Return status code
*
* If the DHCP operation completes successfully, the
* dhcp_session::options field will be filled in with the resulting
* options block. The caller takes responsibility for eventually
* calling free_dhcp_options().
*/
struct async_operation * start_dhcp ( struct dhcp_session *dhcp ) {
int start_dhcp ( struct dhcp_session *dhcp, struct async *parent ) {
int rc;
/* Initialise DHCP session */
@@ -729,10 +730,8 @@ struct async_operation * start_dhcp ( struct dhcp_session *dhcp ) {
dhcp->state = DHCPDISCOVER;
/* Bind to local port */
if ( ( rc = udp_open ( &dhcp->udp, htons ( BOOTPC_PORT ) ) ) != 0 ) {
async_done ( &dhcp->aop, rc );
goto out;
}
if ( ( rc = udp_open ( &dhcp->udp, htons ( BOOTPC_PORT ) ) ) != 0 )
return rc;
/* Add persistent reference to net device */
dhcp->netdev_ref.forget = dhcp_forget_netdev;
@@ -741,6 +740,6 @@ struct async_operation * start_dhcp ( struct dhcp_session *dhcp ) {
/* Proof of concept: just send a single DHCPDISCOVER */
dhcp_send_request ( dhcp );
out:
return &dhcp->aop;
async_init ( &dhcp->async, &default_async_operations, parent );
return 0;
}

View File

@@ -142,7 +142,7 @@ static void tftp_done ( struct tftp_session *tftp, int rc ) {
udp_close ( &tftp->udp );
/* Mark async operation as complete */
async_done ( &tftp->aop, rc );
async_done ( &tftp->async, rc );
}
/**
@@ -477,7 +477,7 @@ struct async_operation * tftp_get ( struct tftp_session *tftp ) {
/* Open UDP connection */
if ( ( rc = udp_open ( &tftp->udp, 0 ) ) != 0 ) {
async_done ( &tftp->aop, rc );
async_done ( &tftp->async, rc );
goto out;
}
@@ -485,5 +485,5 @@ struct async_operation * tftp_get ( struct tftp_session *tftp ) {
tftp_send_packet ( tftp );
out:
return &tftp->aop;
return &tftp->async;
}