1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef QUICHE_QUIC_CORE_BATCH_WRITER_QUIC_BATCH_WRITER_BUFFER_H_
6 #define QUICHE_QUIC_CORE_BATCH_WRITER_QUIC_BATCH_WRITER_BUFFER_H_
7 
8 #include "absl/base/optimization.h"
9 #include "quiche/quic/core/quic_linux_socket_utils.h"
10 #include "quiche/quic/core/quic_packet_writer.h"
11 #include "quiche/quic/platform/api/quic_ip_address.h"
12 #include "quiche/quic/platform/api/quic_socket_address.h"
13 #include "quiche/common/quiche_circular_deque.h"
14 
15 namespace quic {
16 
17 // QuicBatchWriterBuffer manages an internal buffer to hold data from multiple
18 // packets. Packet data are placed continuously within the internal buffer such
19 // that they can be sent by a QuicGsoBatchWriter.
20 // This class can also be used by a QuicBatchWriter which uses sendmmsg,
21 // although it is not optimized for that use case.
22 class QUICHE_EXPORT QuicBatchWriterBuffer {
23  public:
24   QuicBatchWriterBuffer();
25 
26   // Clear all buffered writes, but leave the internal buffer intact.
27   void Clear();
28 
29   char* GetNextWriteLocation() const;
30 
31   // Push a buffered write to the back.
32   struct QUICHE_EXPORT PushResult {
33     bool succeeded;
34     // True in one of the following cases:
35     // 1) The packet buffer is external and copied to the internal buffer, or
36     // 2) The packet buffer is from the internal buffer and moved within it.
37     //    This only happens if PopBufferedWrite is called in the middle of a
38     //    in-place push.
39     // Only valid if |succeeded| is true.
40     bool buffer_copied;
41     // The batch ID of the packet. Only valid if |succeeded|.
42     uint32_t batch_id = 0;
43   };
44 
45   PushResult PushBufferedWrite(const char* buffer, size_t buf_len,
46                                const QuicIpAddress& self_address,
47                                const QuicSocketAddress& peer_address,
48                                const PerPacketOptions* options,
49                                const QuicPacketWriterParams& params,
50                                uint64_t release_time);
51 
52   void UndoLastPush();
53 
54   // Pop |num_buffered_writes| buffered writes from the front.
55   // |num_buffered_writes| will be capped to [0, buffered_writes().size()]
56   // before it is used.
57   struct QUICHE_EXPORT PopResult {
58     int32_t num_buffers_popped;
59     // True if after |num_buffers_popped| buffers are popped from front, the
60     // remaining buffers are moved to the beginning of the internal buffer.
61     // This should normally be false.
62     bool moved_remaining_buffers;
63   };
64   PopResult PopBufferedWrite(int32_t num_buffered_writes);
65 
buffered_writes()66   const quiche::QuicheCircularDeque<BufferedWrite>& buffered_writes() const {
67     return buffered_writes_;
68   }
69 
IsExternalBuffer(const char * buffer,size_t buf_len)70   bool IsExternalBuffer(const char* buffer, size_t buf_len) const {
71     return (buffer + buf_len) <= buffer_ || buffer >= buffer_end();
72   }
IsInternalBuffer(const char * buffer,size_t buf_len)73   bool IsInternalBuffer(const char* buffer, size_t buf_len) const {
74     return buffer >= buffer_ && (buffer + buf_len) <= buffer_end();
75   }
76 
77   // Number of bytes used in |buffer_|.
78   // PushBufferedWrite() increases this; PopBufferedWrite decreases this.
79   size_t SizeInUse() const;
80 
81   // Rounded up from |kMaxGsoPacketSize|, which is the maximum allowed
82   // size of a GSO packet.
83   static const size_t kBufferSize = 64 * 1024;
84 
85   std::string DebugString() const;
86 
87  protected:
88   // Whether the invariants of the buffer are upheld. For debug & test only.
89   bool Invariants() const;
buffer_end()90   const char* buffer_end() const { return buffer_ + sizeof(buffer_); }
91   ABSL_CACHELINE_ALIGNED char buffer_[kBufferSize];
92   quiche::QuicheCircularDeque<BufferedWrite> buffered_writes_;
93   // 0 if a batch has never started. Otherwise
94   // - If |buffered_writes_| is empty, this is the ID of the previous batch.
95   // - If |buffered_writes_| is not empty, this is the ID of the current batch.
96   // For debugging only.
97   uint32_t batch_id_ = 0;
98 };
99 
100 }  // namespace quic
101 
102 #endif  // QUICHE_QUIC_CORE_BATCH_WRITER_QUIC_BATCH_WRITER_BUFFER_H_
103