From 6918cf9e9e67e5b0fb79cae2f9da921b81cac399 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 11 Jan 2007 04:51:20 +0000 Subject: [PATCH] Change FTP to use a data buffer rather than a callback function. --- src/include/gpxe/ftp.h | 15 ++++++--------- src/net/tcp/ftp.c | 41 +++++++++++++++++++++++++++-------------- src/tests/ftptest.c | 16 ++++++++++++++-- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/include/gpxe/ftp.h b/src/include/gpxe/ftp.h index c3eafb670..e296021dd 100644 --- a/src/include/gpxe/ftp.h +++ b/src/include/gpxe/ftp.h @@ -11,6 +11,8 @@ #include #include +struct buffer; + /** FTP default port */ #define FTP_PORT 21 @@ -40,15 +42,8 @@ struct ftp_request { struct sockaddr_tcpip server; /** File to download */ const char *filename; - /** Callback function - * - * @v data Received data - * @v len Length of received data - * - * This function is called for all data received from the - * remote server. - */ - void ( *callback ) ( char *data, size_t len ); + /** Data buffer to fill */ + struct buffer *buffer; /** Current state */ enum ftp_state state; @@ -62,6 +57,8 @@ struct ftp_request { char status_text[4]; /** Passive-mode parameters, as text */ char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */ + /** Amount of data received */ + size_t data_rcvd; /** TCP application for the control channel */ struct tcp_application tcp; diff --git a/src/net/tcp/ftp.c b/src/net/tcp/ftp.c index e345a65d9..ef5423a9c 100644 --- a/src/net/tcp/ftp.c +++ b/src/net/tcp/ftp.c @@ -5,6 +5,7 @@ #include #include #include +#include #include /** @file @@ -268,14 +269,14 @@ static void ftp_senddata ( struct tcp_application *app, * When the control channel is closed, the data channel must also be * closed, if it is currently open. */ -static void ftp_closed ( struct tcp_application *app, int status ) { +static void ftp_closed ( struct tcp_application *app, int rc ) { struct ftp_request *ftp = tcp_to_ftp ( app ); - DBGC ( ftp, "FTP %p control connection closed (status %d)\n", - ftp, status ); + DBGC ( ftp, "FTP %p control connection closed: %s\n", + ftp, strerror ( rc ) ); /* Complete FTP operation */ - ftp_done ( ftp, status ); + ftp_done ( ftp, rc ); } /** FTP control channel operations */ @@ -314,15 +315,15 @@ tcp_to_ftp_data ( struct tcp_application *app ) { * * If the data channel is closed due to an error, we abort the request. */ -static void ftp_data_closed ( struct tcp_application *app, int status ) { +static void ftp_data_closed ( struct tcp_application *app, int rc ) { struct ftp_request *ftp = tcp_to_ftp_data ( app ); - DBGC ( ftp, "FTP %p data connection closed (status %d)\n", - ftp, status ); + DBGC ( ftp, "FTP %p data connection closed: %s\n", + ftp, strerror ( rc ) ); /* If there was an error, close control channel and record status */ - if ( status ) - ftp_done ( ftp, status ); + if ( rc ) + ftp_done ( ftp, rc ); } /** @@ -331,14 +332,23 @@ static void ftp_data_closed ( struct tcp_application *app, int status ) { * @v app TCP application * @v data New data * @v len Length of new data - * - * Data is handed off to the callback registered in the FTP request. */ static void ftp_data_newdata ( struct tcp_application *app, void *data, size_t len ) { struct ftp_request *ftp = tcp_to_ftp_data ( app ); + int rc; - ftp->callback ( data, len ); + /* Fill data buffer */ + if ( ( rc = fill_buffer ( ftp->buffer, data, + ftp->data_rcvd, len ) ) != 0 ){ + DBGC ( ftp, "FTP %p failed to fill data buffer: %s\n", + ftp, strerror ( rc ) ); + ftp_done ( ftp, rc ); + return; + } + + /* Update received data total */ + ftp->data_rcvd += len; } /** FTP data channel operations */ @@ -363,10 +373,13 @@ struct async_operation * ftp_get ( struct ftp_request *ftp ) { DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->filename ); - ftp->tcp.tcp_op = &ftp_tcp_operations; - ftp->tcp_data.tcp_op = &ftp_data_tcp_operations; + ftp->state = FTP_CONNECT; + ftp->already_sent = 0; ftp->recvbuf = ftp->status_text; ftp->recvsize = sizeof ( ftp->status_text ) - 1; + ftp->data_rcvd = 0; + ftp->tcp.tcp_op = &ftp_tcp_operations; + ftp->tcp_data.tcp_op = &ftp_data_tcp_operations; if ( ( rc = tcp_connect ( &ftp->tcp, &ftp->server, 0 ) ) != 0 ) ftp_done ( ftp, rc ); diff --git a/src/tests/ftptest.c b/src/tests/ftptest.c index c4795c04c..d7208f94f 100644 --- a/src/tests/ftptest.c +++ b/src/tests/ftptest.c @@ -4,9 +4,10 @@ #include #include #include +#include #include -static void test_ftp_callback ( char *data, size_t len ) { +static void print_ftp_response ( char *data, size_t len ) { unsigned int i; char c; @@ -23,18 +24,29 @@ static void test_ftp_callback ( char *data, size_t len ) { } void test_ftp ( struct sockaddr_tcpip *server, const char *filename ) { + char data[256]; + struct buffer buffer; struct ftp_request ftp; int rc; printf ( "FTP fetching %s\n", filename ); + memset ( &buffer, 0, sizeof ( buffer ) ); + buffer.addr = virt_to_phys ( data ); + buffer.len = sizeof ( data ); + memset ( &ftp, 0, sizeof ( ftp ) ); memcpy ( &ftp.server, server, sizeof ( ftp.server ) ); ftp.filename = filename; - ftp.callback = test_ftp_callback; + ftp.buffer = &buffer; rc = async_wait ( ftp_get ( &ftp ) ); if ( rc ) { printf ( "FTP fetch failed\n" ); + return; } + + printf ( "FTP received %d bytes\n", buffer.fill ); + + print_ftp_response ( data, buffer.fill ); }