Implement flow control for tftp.
* grub-core/net/net.c (receive_packets): Decrease the stop to 10 packets but stop only if stop condition is satisfied. (grub_net_fs_read_real): Call packets_pulled after real read. Use `stall' instead of `eof' as stop condition. * grub-core/net/http.c (parse_line): Set `stall' on EOF. (http_err): Likewise. * grub-core/net/tftp.c (ack): Replace the first argument with data instead of socket. (tftp_receive): Stall if too many packets are in wait queue. (tftp_packets_pulled): New function. (grub_tftp_protocol): Set packets_pulled. * include/grub/net.h (grub_net_packets): New field count. (grub_net_put_packet): Increment count. (grub_net_remove_packet): Likewise. (grub_net_app_protocol): New field `packets_pulled'. (grub_net): New field `stall'.
This commit is contained in:
parent
6b9cfac683
commit
b27069e06d
5 changed files with 78 additions and 14 deletions
21
ChangeLog
21
ChangeLog
|
@ -1,3 +1,24 @@
|
||||||
|
2012-06-22 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
|
Implement flow control for tftp.
|
||||||
|
|
||||||
|
* grub-core/net/net.c (receive_packets): Decrease the stop to 10
|
||||||
|
packets but stop only if stop condition is satisfied.
|
||||||
|
(grub_net_fs_read_real): Call packets_pulled after real read. Use
|
||||||
|
`stall' instead of `eof' as stop condition.
|
||||||
|
* grub-core/net/http.c (parse_line): Set `stall' on EOF.
|
||||||
|
(http_err): Likewise.
|
||||||
|
* grub-core/net/tftp.c (ack): Replace the first argument with data
|
||||||
|
instead of socket.
|
||||||
|
(tftp_receive): Stall if too many packets are in wait queue.
|
||||||
|
(tftp_packets_pulled): New function.
|
||||||
|
(grub_tftp_protocol): Set packets_pulled.
|
||||||
|
* include/grub/net.h (grub_net_packets): New field count.
|
||||||
|
(grub_net_put_packet): Increment count.
|
||||||
|
(grub_net_remove_packet): Likewise.
|
||||||
|
(grub_net_app_protocol): New field `packets_pulled'.
|
||||||
|
(grub_net): New field `stall'.
|
||||||
|
|
||||||
2012-06-22 Vladimir Serbinenko <phcoder@gmail.com>
|
2012-06-22 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
* grub-core/net/net.c (receive_packets): Stop after 100 packets to let
|
* grub-core/net/net.c (receive_packets): Stop after 100 packets to let
|
||||||
|
|
|
@ -82,6 +82,7 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
|
||||||
if (data->chunk_rem == 0)
|
if (data->chunk_rem == 0)
|
||||||
{
|
{
|
||||||
file->device->net->eof = 1;
|
file->device->net->eof = 1;
|
||||||
|
file->device->net->stall = 1;
|
||||||
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
|
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
|
||||||
file->size = have_ahead (file);
|
file->size = have_ahead (file);
|
||||||
}
|
}
|
||||||
|
@ -156,6 +157,7 @@ http_err (grub_net_tcp_socket_t sock __attribute__ ((unused)),
|
||||||
grub_free (data->current_line);
|
grub_free (data->current_line);
|
||||||
grub_free (data);
|
grub_free (data);
|
||||||
file->device->net->eof = 1;
|
file->device->net->eof = 1;
|
||||||
|
file->device->net->stall = 1;
|
||||||
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
|
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
|
||||||
file->size = have_ahead (file);
|
file->size = have_ahead (file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1309,7 +1309,7 @@ grub_net_fs_close (grub_file_t file)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
receive_packets (struct grub_net_card *card)
|
receive_packets (struct grub_net_card *card, int *stop_condition)
|
||||||
{
|
{
|
||||||
int received = 0;
|
int received = 0;
|
||||||
if (card->num_ifaces == 0)
|
if (card->num_ifaces == 0)
|
||||||
|
@ -1332,7 +1332,7 @@ receive_packets (struct grub_net_card *card)
|
||||||
and just mark them as used and not used. */
|
and just mark them as used and not used. */
|
||||||
struct grub_net_buff *nb;
|
struct grub_net_buff *nb;
|
||||||
|
|
||||||
if (received > 100)
|
if (received > 10 && stop_condition && *stop_condition)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
nb = card->driver->recv (card);
|
nb = card->driver->recv (card);
|
||||||
|
@ -1362,7 +1362,7 @@ grub_net_poll_cards (unsigned time, int *stop_condition)
|
||||||
while ((grub_get_time_ms () - start_time) < time
|
while ((grub_get_time_ms () - start_time) < time
|
||||||
&& (!stop_condition || !*stop_condition))
|
&& (!stop_condition || !*stop_condition))
|
||||||
FOR_NET_CARDS (card)
|
FOR_NET_CARDS (card)
|
||||||
receive_packets (card);
|
receive_packets (card, stop_condition);
|
||||||
grub_net_tcp_retransmit ();
|
grub_net_tcp_retransmit ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1376,7 +1376,7 @@ grub_net_poll_cards_idle_real (void)
|
||||||
|
|
||||||
if (ctime < card->last_poll
|
if (ctime < card->last_poll
|
||||||
|| ctime >= card->last_poll + card->idle_poll_delay_ms)
|
|| ctime >= card->last_poll + card->idle_poll_delay_ms)
|
||||||
receive_packets (card);
|
receive_packets (card, 0);
|
||||||
}
|
}
|
||||||
grub_net_tcp_retransmit ();
|
grub_net_tcp_retransmit ();
|
||||||
}
|
}
|
||||||
|
@ -1417,12 +1417,19 @@ grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len)
|
||||||
nb->data += amount;
|
nb->data += amount;
|
||||||
|
|
||||||
if (!len)
|
if (!len)
|
||||||
|
{
|
||||||
|
if (net->protocol->packets_pulled)
|
||||||
|
net->protocol->packets_pulled (file);
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (net->protocol->packets_pulled)
|
||||||
|
net->protocol->packets_pulled (file);
|
||||||
|
|
||||||
if (!net->eof)
|
if (!net->eof)
|
||||||
{
|
{
|
||||||
try++;
|
try++;
|
||||||
grub_net_poll_cards (GRUB_NET_INTERVAL, &net->eof);
|
grub_net_poll_cards (GRUB_NET_INTERVAL, &net->stall);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return total;
|
return total;
|
||||||
|
|
|
@ -102,6 +102,7 @@ typedef struct tftp_data
|
||||||
grub_uint64_t file_size;
|
grub_uint64_t file_size;
|
||||||
grub_uint64_t block;
|
grub_uint64_t block;
|
||||||
grub_uint32_t block_size;
|
grub_uint32_t block_size;
|
||||||
|
grub_uint32_t ack_sent;
|
||||||
int have_oack;
|
int have_oack;
|
||||||
struct grub_error_saved save_err;
|
struct grub_error_saved save_err;
|
||||||
grub_net_udp_socket_t sock;
|
grub_net_udp_socket_t sock;
|
||||||
|
@ -124,7 +125,7 @@ cmp (const void *a__, const void *b__)
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
ack (grub_net_udp_socket_t sock, grub_uint16_t block)
|
ack (tftp_data_t data, grub_uint16_t block)
|
||||||
{
|
{
|
||||||
struct tftphdr *tftph_ack;
|
struct tftphdr *tftph_ack;
|
||||||
grub_uint8_t nbdata[512];
|
grub_uint8_t nbdata[512];
|
||||||
|
@ -144,8 +145,11 @@ ack (grub_net_udp_socket_t sock, grub_uint16_t block)
|
||||||
tftph_ack->opcode = grub_cpu_to_be16 (TFTP_ACK);
|
tftph_ack->opcode = grub_cpu_to_be16 (TFTP_ACK);
|
||||||
tftph_ack->u.ack.block = block;
|
tftph_ack->u.ack.block = block;
|
||||||
|
|
||||||
err = grub_net_send_udp_packet (sock, &nb_ack);
|
err = grub_net_send_udp_packet (data->sock, &nb_ack);
|
||||||
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
data->ack_sent = block;
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
|
@ -185,7 +189,7 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||||
}
|
}
|
||||||
data->block = 0;
|
data->block = 0;
|
||||||
grub_netbuff_free (nb);
|
grub_netbuff_free (nb);
|
||||||
err = ack (data->sock, 0);
|
err = ack (data, 0);
|
||||||
grub_error_save (&data->save_err);
|
grub_error_save (&data->save_err);
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
case TFTP_DATA:
|
case TFTP_DATA:
|
||||||
|
@ -195,9 +199,6 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||||
grub_dprintf ("tftp", "TFTP packet too small\n");
|
grub_dprintf ("tftp", "TFTP packet too small\n");
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
err = ack (data->sock, tftph->u.data.block);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = grub_priority_queue_push (data->pq, &nb);
|
err = grub_priority_queue_push (data->pq, &nb);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -223,6 +224,16 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||||
|
|
||||||
grub_priority_queue_pop (data->pq);
|
grub_priority_queue_pop (data->pq);
|
||||||
|
|
||||||
|
if (file->device->net->packs.count < 200)
|
||||||
|
err = ack (data, tftph->u.data.block);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file->device->net->stall = 1;
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
err = grub_netbuff_pull (nb_top, sizeof (tftph->opcode) +
|
err = grub_netbuff_pull (nb_top, sizeof (tftph->opcode) +
|
||||||
sizeof (tftph->u.data.block));
|
sizeof (tftph->u.data.block));
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -233,6 +244,7 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||||
if (size < data->block_size)
|
if (size < data->block_size)
|
||||||
{
|
{
|
||||||
file->device->net->eof = 1;
|
file->device->net->eof = 1;
|
||||||
|
file->device->net->stall = 1;
|
||||||
grub_net_udp_close (data->sock);
|
grub_net_udp_close (data->sock);
|
||||||
data->sock = NULL;
|
data->sock = NULL;
|
||||||
}
|
}
|
||||||
|
@ -435,11 +447,26 @@ tftp_close (struct grub_file *file)
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static grub_err_t
|
||||||
|
tftp_packets_pulled (struct grub_file *file)
|
||||||
|
{
|
||||||
|
tftp_data_t data = file->data;
|
||||||
|
if (file->device->net->packs.count >= 200)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!file->device->net->eof)
|
||||||
|
file->device->net->stall = 0;
|
||||||
|
if (data->ack_sent >= data->block)
|
||||||
|
return 0;
|
||||||
|
return ack (data, data->block);
|
||||||
|
}
|
||||||
|
|
||||||
static struct grub_net_app_protocol grub_tftp_protocol =
|
static struct grub_net_app_protocol grub_tftp_protocol =
|
||||||
{
|
{
|
||||||
.name = "tftp",
|
.name = "tftp",
|
||||||
.open = tftp_open,
|
.open = tftp_open,
|
||||||
.close = tftp_close
|
.close = tftp_close,
|
||||||
|
.packets_pulled = tftp_packets_pulled
|
||||||
};
|
};
|
||||||
|
|
||||||
GRUB_MOD_INIT (tftp)
|
GRUB_MOD_INIT (tftp)
|
||||||
|
|
|
@ -93,6 +93,7 @@ typedef struct grub_net_packets
|
||||||
{
|
{
|
||||||
grub_net_packet_t *first;
|
grub_net_packet_t *first;
|
||||||
grub_net_packet_t *last;
|
grub_net_packet_t *last;
|
||||||
|
grub_size_t count;
|
||||||
} grub_net_packets_t;
|
} grub_net_packets_t;
|
||||||
|
|
||||||
#ifdef GRUB_MACHINE_EFI
|
#ifdef GRUB_MACHINE_EFI
|
||||||
|
@ -204,12 +205,16 @@ grub_net_put_packet (grub_net_packets_t *pkts, struct grub_net_buff *nb)
|
||||||
else
|
else
|
||||||
pkts->first = pkts->last = n;
|
pkts->first = pkts->last = n;
|
||||||
|
|
||||||
|
pkts->count++;
|
||||||
|
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
grub_net_remove_packet (grub_net_packet_t *pkt)
|
grub_net_remove_packet (grub_net_packet_t *pkt)
|
||||||
{
|
{
|
||||||
|
pkt->up->count--;
|
||||||
|
|
||||||
if (pkt->prev)
|
if (pkt->prev)
|
||||||
pkt->prev->next = pkt->next;
|
pkt->prev->next = pkt->next;
|
||||||
else
|
else
|
||||||
|
@ -236,6 +241,7 @@ struct grub_net_app_protocol
|
||||||
grub_err_t (*open) (struct grub_file *file, const char *filename);
|
grub_err_t (*open) (struct grub_file *file, const char *filename);
|
||||||
grub_err_t (*seek) (struct grub_file *file, grub_off_t off);
|
grub_err_t (*seek) (struct grub_file *file, grub_off_t off);
|
||||||
grub_err_t (*close) (struct grub_file *file);
|
grub_err_t (*close) (struct grub_file *file);
|
||||||
|
grub_err_t (*packets_pulled) (struct grub_file *file);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct grub_net
|
typedef struct grub_net
|
||||||
|
@ -247,6 +253,7 @@ typedef struct grub_net
|
||||||
grub_off_t offset;
|
grub_off_t offset;
|
||||||
grub_fs_t fs;
|
grub_fs_t fs;
|
||||||
int eof;
|
int eof;
|
||||||
|
int stall;
|
||||||
} *grub_net_t;
|
} *grub_net_t;
|
||||||
|
|
||||||
extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);
|
extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);
|
||||||
|
|
Loading…
Reference in a new issue