]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Implement flow control for tftp.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 22 Jun 2012 12:17:46 +0000 (14:17 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 22 Jun 2012 12:17:46 +0000 (14:17 +0200)
* 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'.

ChangeLog
grub-core/net/http.c
grub-core/net/net.c
grub-core/net/tftp.c
include/grub/net.h

index e88bb4c7dbd4c471c210f276cc56caca7d417619..13af513e3e2574f8f085b8661d6dba3bccab8e90 100644 (file)
--- a/ChangeLog
+++ b/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>
 
        * grub-core/net/net.c (receive_packets): Stop after 100 packets to let
index be9dafacd8af9764fa87b0dec2cfc5e1504e243c..fc8f3babd265080ca08e5f0667d4aa5d2074458a 100644 (file)
@@ -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)
        {
          file->device->net->eof = 1;
+         file->device->net->stall = 1;
          if (file->size == GRUB_FILE_SIZE_UNKNOWN)
            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);
   file->device->net->eof = 1;
+  file->device->net->stall = 1;
   if (file->size == GRUB_FILE_SIZE_UNKNOWN)
     file->size = have_ahead (file);
 }
index dbfc9dba43b5498125e6518332a6b91c90ac2d32..ae7340cb2c0cf21d6eedebb6ac0d2620ddadeb68 100644 (file)
@@ -1309,7 +1309,7 @@ grub_net_fs_close (grub_file_t file)
 }
 
 static void
-receive_packets (struct grub_net_card *card)
+receive_packets (struct grub_net_card *card, int *stop_condition)
 {
   int received = 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.  */ 
       struct grub_net_buff *nb;
 
-      if (received > 100)
+      if (received > 10 && stop_condition && *stop_condition)
        break;
 
       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
         && (!stop_condition || !*stop_condition))
     FOR_NET_CARDS (card)
-      receive_packets (card);
+      receive_packets (card, stop_condition);
   grub_net_tcp_retransmit ();
 }
 
@@ -1376,7 +1376,7 @@ grub_net_poll_cards_idle_real (void)
 
     if (ctime < card->last_poll
        || ctime >= card->last_poll + card->idle_poll_delay_ms)
-      receive_packets (card);
+      receive_packets (card, 0);
   }
   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;
 
          if (!len)
-           return total;
+           {
+             if (net->protocol->packets_pulled)
+               net->protocol->packets_pulled (file);
+             return total;
+           }
        }
+      if (net->protocol->packets_pulled)
+       net->protocol->packets_pulled (file);
+
       if (!net->eof)
        {
          try++;
-         grub_net_poll_cards (GRUB_NET_INTERVAL, &net->eof);
+         grub_net_poll_cards (GRUB_NET_INTERVAL, &net->stall);
        }
       else
        return total;
index abd5395d6a4e1a04df534142fa4d349fd955b54d..45a908c7de013a0fe819c210bb71a0e7a0ad7b57 100644 (file)
@@ -102,6 +102,7 @@ typedef struct tftp_data
   grub_uint64_t file_size;
   grub_uint64_t block;
   grub_uint32_t block_size;
+  grub_uint32_t ack_sent;
   int have_oack;
   struct grub_error_saved save_err;
   grub_net_udp_socket_t sock;
@@ -124,7 +125,7 @@ cmp (const void *a__, const void *b__)
 }
 
 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;
   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->u.ack.block = block;
 
-  err = grub_net_send_udp_packet (sock, &nb_ack);
-  return err;
+  err = grub_net_send_udp_packet (data->sock, &nb_ack);
+  if (err)
+    return err;
+  data->ack_sent = block;
+  return GRUB_ERR_NONE;
 }
 
 static grub_err_t
@@ -185,7 +189,7 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
        }
       data->block = 0;
       grub_netbuff_free (nb);
-      err = ack (data->sock, 0);
+      err = ack (data, 0);
       grub_error_save (&data->save_err);
       return GRUB_ERR_NONE;
     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");
          return GRUB_ERR_NONE;
        }
-      err = ack (data->sock, tftph->u.data.block);
-      if (err)
-       return err;
 
       err = grub_priority_queue_push (data->pq, &nb);
       if (err)
@@ -223,6 +224,16 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
 
            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) +
                                     sizeof (tftph->u.data.block));
            if (err)
@@ -233,6 +244,7 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
            if (size < data->block_size)
              {
                file->device->net->eof = 1;
+               file->device->net->stall = 1;
                grub_net_udp_close (data->sock);
                data->sock = NULL;
              }
@@ -435,11 +447,26 @@ tftp_close (struct grub_file *file)
   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 = 
   {
     .name = "tftp",
     .open = tftp_open,
-    .close = tftp_close
+    .close = tftp_close,
+    .packets_pulled = tftp_packets_pulled
   };
 
 GRUB_MOD_INIT (tftp)
index 1db05e8064ea1c316806978bfedaba218bd899b2..3877451da1f405222d284db826818ce33774f490 100644 (file)
@@ -93,6 +93,7 @@ typedef struct grub_net_packets
 {
   grub_net_packet_t *first;
   grub_net_packet_t *last;
+  grub_size_t count;
 } grub_net_packets_t;
 
 #ifdef GRUB_MACHINE_EFI
@@ -204,12 +205,16 @@ grub_net_put_packet (grub_net_packets_t *pkts, struct grub_net_buff *nb)
   else
     pkts->first = pkts->last = n;
 
+  pkts->count++;
+
   return GRUB_ERR_NONE;
 }
 
 static inline void
 grub_net_remove_packet (grub_net_packet_t *pkt)
 {
+  pkt->up->count--;
+
   if (pkt->prev)
     pkt->prev->next = pkt->next;
   else
@@ -236,6 +241,7 @@ struct grub_net_app_protocol
   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 (*close) (struct grub_file *file);
+  grub_err_t (*packets_pulled) (struct grub_file *file);
 };
 
 typedef struct grub_net
@@ -247,6 +253,7 @@ typedef struct grub_net
   grub_off_t offset;
   grub_fs_t fs;
   int eof;
+  int stall;
 } *grub_net_t;
 
 extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name);