1 // Copyright 2019 The gVisor Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 14 package stack
15 16 import (
17 "fmt"
18 "io"
19 20 "gvisor.dev/gvisor/pkg/buffer"
21 "gvisor.dev/gvisor/pkg/sync"
22 "gvisor.dev/gvisor/pkg/tcpip"
23 "gvisor.dev/gvisor/pkg/tcpip/header"
24 )
25 26 type headerType int
27 28 const (
29 virtioNetHeader headerType = iota
30 linkHeader
31 networkHeader
32 transportHeader
33 numHeaderType
34 )
35 36 var pkPool = sync.Pool{
37 New: func() any {
38 return &PacketBuffer{}
39 },
40 }
41 42 // PacketBufferOptions specifies options for PacketBuffer creation.
43 type PacketBufferOptions struct {
44 // ReserveHeaderBytes is the number of bytes to reserve for headers. Total
45 // number of bytes pushed onto the headers must not exceed this value.
46 ReserveHeaderBytes int
47 48 // Payload is the initial unparsed data for the new packet. If set, it will
49 // be owned by the new packet.
50 Payload buffer.Buffer
51 52 // IsForwardedPacket identifies that the PacketBuffer being created is for a
53 // forwarded packet.
54 IsForwardedPacket bool
55 56 // OnRelease is a function to be run when the packet buffer is no longer
57 // referenced (released back to the pool).
58 OnRelease func()
59 }
60 61 // A PacketBuffer contains all the data of a network packet.
62 //
63 // As a PacketBuffer traverses up the stack, it may be necessary to pass it to
64 // multiple endpoints.
65 //
66 // The whole packet is expected to be a series of bytes in the following order:
67 // LinkHeader, NetworkHeader, TransportHeader, and Data. Any of them can be
68 // empty. Use of PacketBuffer in any other order is unsupported.
69 //
70 // PacketBuffer must be created with NewPacketBuffer, which sets the initial
71 // reference count to 1. Owners should call `DecRef()` when they are finished
72 // with the buffer to return it to the pool.
73 //
74 // Internal structure: A PacketBuffer holds a pointer to buffer.Buffer, which
75 // exposes a logically-contiguous byte storage. The underlying storage structure
76 // is abstracted out, and should not be a concern here for most of the time.
77 //
78 // |- reserved ->|
79 // |--->| consumed (incoming)
80 // 0 V V
81 // +--------+----+----+--------------------+
82 // | | | | current data ... | (buf)
83 // +--------+----+----+--------------------+
84 // ^ |
85 // |<---| pushed (outgoing)
86 //
87 // When a PacketBuffer is created, a `reserved` header region can be specified,
88 // which stack pushes headers in this region for an outgoing packet. There could
89 // be no such region for an incoming packet, and `reserved` is 0. The value of
90 // `reserved` never changes in the entire lifetime of the packet.
91 //
92 // Outgoing Packet: When a header is pushed, `pushed` gets incremented by the
93 // pushed length, and the current value is stored for each header. PacketBuffer
94 // subtracts this value from `reserved` to compute the starting offset of each
95 // header in `buf`.
96 //
97 // Incoming Packet: When a header is consumed (a.k.a. parsed), the current
98 // `consumed` value is stored for each header, and it gets incremented by the
99 // consumed length. PacketBuffer adds this value to `reserved` to compute the
100 // starting offset of each header in `buf`.
101 //
102 // +stateify savable
103 type PacketBuffer struct {
104 _ sync.NoCopy
105 106 packetBufferRefs
107 108 // buf is the underlying buffer for the packet. See struct level docs for
109 // details.
110 buf buffer.Buffer
111 reserved int
112 pushed int
113 consumed int
114 115 // headers stores metadata about each header.
116 headers [numHeaderType]headerInfo
117 118 // NetworkProtocolNumber is only valid when NetworkHeader().View().IsEmpty()
119 // returns false.
120 // TODO(gvisor.dev/issue/3574): Remove the separately passed protocol
121 // numbers in registration APIs that take a PacketBuffer.
122 NetworkProtocolNumber tcpip.NetworkProtocolNumber
123 124 // TransportProtocol is only valid if it is non zero.
125 // TODO(gvisor.dev/issue/3810): This and the network protocol number should
126 // be moved into the headerinfo. This should resolve the validity issue.
127 TransportProtocolNumber tcpip.TransportProtocolNumber
128 129 // Hash is the transport layer hash of this packet. A value of zero
130 // indicates no valid hash has been set.
131 Hash uint32
132 133 // Owner is implemented by task to get the uid and gid.
134 // Only set for locally generated packets.
135 Owner tcpip.PacketOwner
136 137 // The following fields are only set by the qdisc layer when the packet
138 // is added to a queue.
139 EgressRoute RouteInfo
140 GSOOptions GSO
141 142 // snatDone indicates if the packet's source has been manipulated as per
143 // iptables NAT table.
144 snatDone bool
145 146 // dnatDone indicates if the packet's destination has been manipulated as per
147 // iptables NAT table.
148 dnatDone bool
149 150 // PktType indicates the SockAddrLink.PacketType of the packet as defined in
151 // https://www.man7.org/linux/man-pages/man7/packet.7.html.
152 PktType tcpip.PacketType
153 154 // NICID is the ID of the last interface the network packet was handled at.
155 NICID tcpip.NICID
156 157 // RXChecksumValidated indicates that checksum verification may be
158 // safely skipped.
159 RXChecksumValidated bool
160 161 // NetworkPacketInfo holds an incoming packet's network-layer information.
162 NetworkPacketInfo NetworkPacketInfo
163 164 tuple *tuple
165 166 // onRelease is a function to be run when the packet buffer is no longer
167 // referenced (released back to the pool).
168 onRelease func() `state:"nosave"`
169 }
170 171 // NewPacketBuffer creates a new PacketBuffer with opts.
172 func NewPacketBuffer(opts PacketBufferOptions) *PacketBuffer {
173 pk := pkPool.Get().(*PacketBuffer)
174 pk.reset()
175 if opts.ReserveHeaderBytes != 0 {
176 v := buffer.NewViewSize(opts.ReserveHeaderBytes)
177 pk.buf.Append(v)
178 pk.reserved = opts.ReserveHeaderBytes
179 }
180 if opts.Payload.Size() > 0 {
181 pk.buf.Merge(&opts.Payload)
182 }
183 pk.NetworkPacketInfo.IsForwardedPacket = opts.IsForwardedPacket
184 pk.onRelease = opts.OnRelease
185 pk.InitRefs()
186 return pk
187 }
188 189 // IncRef increments the PacketBuffer's refcount.
190 func (pk *PacketBuffer) IncRef() *PacketBuffer {
191 pk.packetBufferRefs.IncRef()
192 return pk
193 }
194 195 // DecRef decrements the PacketBuffer's refcount. If the refcount is
196 // decremented to zero, the PacketBuffer is returned to the PacketBuffer
197 // pool.
198 func (pk *PacketBuffer) DecRef() {
199 pk.packetBufferRefs.DecRef(func() {
200 if pk.onRelease != nil {
201 pk.onRelease()
202 }
203 204 pk.buf.Release()
205 pkPool.Put(pk)
206 })
207 }
208 209 func (pk *PacketBuffer) reset() {
210 *pk = PacketBuffer{}
211 }
212 213 // ReservedHeaderBytes returns the number of bytes initially reserved for
214 // headers.
215 func (pk *PacketBuffer) ReservedHeaderBytes() int {
216 return pk.reserved
217 }
218 219 // AvailableHeaderBytes returns the number of bytes currently available for
220 // headers. This is relevant to PacketHeader.Push method only.
221 func (pk *PacketBuffer) AvailableHeaderBytes() int {
222 return pk.reserved - pk.pushed
223 }
224 225 // VirtioNetHeader returns the handle to virtio-layer header.
226 func (pk *PacketBuffer) VirtioNetHeader() PacketHeader {
227 return PacketHeader{
228 pk: pk,
229 typ: virtioNetHeader,
230 }
231 }
232 233 // LinkHeader returns the handle to link-layer header.
234 func (pk *PacketBuffer) LinkHeader() PacketHeader {
235 return PacketHeader{
236 pk: pk,
237 typ: linkHeader,
238 }
239 }
240 241 // NetworkHeader returns the handle to network-layer header.
242 func (pk *PacketBuffer) NetworkHeader() PacketHeader {
243 return PacketHeader{
244 pk: pk,
245 typ: networkHeader,
246 }
247 }
248 249 // TransportHeader returns the handle to transport-layer header.
250 func (pk *PacketBuffer) TransportHeader() PacketHeader {
251 return PacketHeader{
252 pk: pk,
253 typ: transportHeader,
254 }
255 }
256 257 // HeaderSize returns the total size of all headers in bytes.
258 func (pk *PacketBuffer) HeaderSize() int {
259 return pk.pushed + pk.consumed
260 }
261 262 // Size returns the size of packet in bytes.
263 func (pk *PacketBuffer) Size() int {
264 return int(pk.buf.Size()) - pk.headerOffset()
265 }
266 267 // MemSize returns the estimation size of the pk in memory, including backing
268 // buffer data.
269 func (pk *PacketBuffer) MemSize() int {
270 return int(pk.buf.Size()) + PacketBufferStructSize
271 }
272 273 // Data returns the handle to data portion of pk.
274 func (pk *PacketBuffer) Data() PacketData {
275 return PacketData{pk: pk}
276 }
277 278 // AsSlices returns the underlying storage of the whole packet.
279 //
280 // Note that AsSlices can allocate a lot. In hot paths it may be preferable to
281 // iterate over a PacketBuffer's data via AsViewList.
282 func (pk *PacketBuffer) AsSlices() [][]byte {
283 vl := pk.buf.AsViewList()
284 views := make([][]byte, 0, vl.Len())
285 offset := pk.headerOffset()
286 pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v *buffer.View) {
287 views = append(views, v.AsSlice())
288 })
289 return views
290 }
291 292 // AsViewList returns the list of Views backing the PacketBuffer along with the
293 // header offset into them. Users may not save or modify the ViewList returned.
294 func (pk *PacketBuffer) AsViewList() (buffer.ViewList, int) {
295 return pk.buf.AsViewList(), pk.headerOffset()
296 }
297 298 // ToBuffer returns a caller-owned copy of the underlying storage of the whole
299 // packet.
300 func (pk *PacketBuffer) ToBuffer() buffer.Buffer {
301 b := pk.buf.Clone()
302 b.TrimFront(int64(pk.headerOffset()))
303 return b
304 }
305 306 // ToView returns a caller-owned copy of the underlying storage of the whole
307 // packet as a view.
308 func (pk *PacketBuffer) ToView() *buffer.View {
309 p := buffer.NewView(int(pk.buf.Size()))
310 offset := pk.headerOffset()
311 pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v *buffer.View) {
312 p.Write(v.AsSlice())
313 })
314 return p
315 }
316 317 func (pk *PacketBuffer) headerOffset() int {
318 return pk.reserved - pk.pushed
319 }
320 321 func (pk *PacketBuffer) headerOffsetOf(typ headerType) int {
322 return pk.reserved + pk.headers[typ].offset
323 }
324 325 func (pk *PacketBuffer) dataOffset() int {
326 return pk.reserved + pk.consumed
327 }
328 329 func (pk *PacketBuffer) push(typ headerType, size int) []byte {
330 h := &pk.headers[typ]
331 if h.length > 0 {
332 panic(fmt.Sprintf("push(%s, %d) called after previous push", typ, size))
333 }
334 if pk.pushed+size > pk.reserved {
335 panic(fmt.Sprintf("push(%s, %d) overflows; pushed=%d reserved=%d", typ, size, pk.pushed, pk.reserved))
336 }
337 pk.pushed += size
338 h.offset = -pk.pushed
339 h.length = size
340 view := pk.headerView(typ)
341 return view.AsSlice()
342 }
343 344 func (pk *PacketBuffer) consume(typ headerType, size int) (v []byte, consumed bool) {
345 h := &pk.headers[typ]
346 if h.length > 0 {
347 panic(fmt.Sprintf("consume must not be called twice: type %s", typ))
348 }
349 if pk.reserved+pk.consumed+size > int(pk.buf.Size()) {
350 return nil, false
351 }
352 h.offset = pk.consumed
353 h.length = size
354 pk.consumed += size
355 view := pk.headerView(typ)
356 return view.AsSlice(), true
357 }
358 359 func (pk *PacketBuffer) headerView(typ headerType) buffer.View {
360 h := &pk.headers[typ]
361 if h.length == 0 {
362 return buffer.View{}
363 }
364 v, ok := pk.buf.PullUp(pk.headerOffsetOf(typ), h.length)
365 if !ok {
366 panic("PullUp failed")
367 }
368 return v
369 }
370 371 // Clone makes a semi-deep copy of pk. The underlying packet payload is
372 // shared. Hence, no modifications is done to underlying packet payload.
373 func (pk *PacketBuffer) Clone() *PacketBuffer {
374 newPk := pkPool.Get().(*PacketBuffer)
375 newPk.reset()
376 newPk.buf = pk.buf.Clone()
377 newPk.reserved = pk.reserved
378 newPk.pushed = pk.pushed
379 newPk.consumed = pk.consumed
380 newPk.headers = pk.headers
381 newPk.Hash = pk.Hash
382 newPk.Owner = pk.Owner
383 newPk.GSOOptions = pk.GSOOptions
384 newPk.EgressRoute = pk.EgressRoute
385 newPk.NetworkProtocolNumber = pk.NetworkProtocolNumber
386 newPk.dnatDone = pk.dnatDone
387 newPk.snatDone = pk.snatDone
388 newPk.TransportProtocolNumber = pk.TransportProtocolNumber
389 newPk.PktType = pk.PktType
390 newPk.NICID = pk.NICID
391 newPk.RXChecksumValidated = pk.RXChecksumValidated
392 newPk.NetworkPacketInfo = pk.NetworkPacketInfo
393 newPk.tuple = pk.tuple
394 newPk.InitRefs()
395 return newPk
396 }
397 398 // ReserveHeaderBytes prepends reserved space for headers at the front
399 // of the underlying buf. Can only be called once per packet.
400 func (pk *PacketBuffer) ReserveHeaderBytes(reserved int) {
401 if pk.reserved != 0 {
402 panic(fmt.Sprintf("ReserveHeaderBytes(...) called on packet with reserved=%d, want reserved=0", pk.reserved))
403 }
404 pk.reserved = reserved
405 pk.buf.Prepend(buffer.NewViewSize(reserved))
406 }
407 408 // Network returns the network header as a header.Network.
409 //
410 // Network should only be called when NetworkHeader has been set.
411 func (pk *PacketBuffer) Network() header.Network {
412 switch netProto := pk.NetworkProtocolNumber; netProto {
413 case header.IPv4ProtocolNumber:
414 return header.IPv4(pk.NetworkHeader().Slice())
415 case header.IPv6ProtocolNumber:
416 return header.IPv6(pk.NetworkHeader().Slice())
417 default:
418 panic(fmt.Sprintf("unknown network protocol number %d", netProto))
419 }
420 }
421 422 // CloneToInbound makes a semi-deep copy of the packet buffer (similar to
423 // Clone) to be used as an inbound packet.
424 //
425 // See PacketBuffer.Data for details about how a packet buffer holds an inbound
426 // packet.
427 func (pk *PacketBuffer) CloneToInbound() *PacketBuffer {
428 newPk := pkPool.Get().(*PacketBuffer)
429 newPk.reset()
430 newPk.buf = pk.buf.Clone()
431 newPk.InitRefs()
432 // Treat unfilled header portion as reserved.
433 newPk.reserved = pk.AvailableHeaderBytes()
434 newPk.tuple = pk.tuple
435 return newPk
436 }
437 438 // DeepCopyForForwarding creates a deep copy of the packet buffer for
439 // forwarding.
440 //
441 // The returned packet buffer will have the network and transport headers
442 // set if the original packet buffer did.
443 func (pk *PacketBuffer) DeepCopyForForwarding(reservedHeaderBytes int) *PacketBuffer {
444 payload := BufferSince(pk.NetworkHeader())
445 defer payload.Release()
446 newPk := NewPacketBuffer(PacketBufferOptions{
447 ReserveHeaderBytes: reservedHeaderBytes,
448 Payload: payload.DeepClone(),
449 IsForwardedPacket: true,
450 })
451 452 {
453 consumeBytes := len(pk.NetworkHeader().Slice())
454 if _, consumed := newPk.NetworkHeader().Consume(consumeBytes); !consumed {
455 panic(fmt.Sprintf("expected to consume network header %d bytes from new packet", consumeBytes))
456 }
457 newPk.NetworkProtocolNumber = pk.NetworkProtocolNumber
458 }
459 460 {
461 consumeBytes := len(pk.TransportHeader().Slice())
462 if _, consumed := newPk.TransportHeader().Consume(consumeBytes); !consumed {
463 panic(fmt.Sprintf("expected to consume transport header %d bytes from new packet", consumeBytes))
464 }
465 newPk.TransportProtocolNumber = pk.TransportProtocolNumber
466 }
467 468 newPk.tuple = pk.tuple
469 470 return newPk
471 }
472 473 // headerInfo stores metadata about a header in a packet.
474 //
475 // +stateify savable
476 type headerInfo struct {
477 // offset is the offset of the header in pk.buf relative to
478 // pk.buf[pk.reserved]. See the PacketBuffer struct for details.
479 offset int
480 481 // length is the length of this header.
482 length int
483 }
484 485 // PacketHeader is a handle object to a header in the underlying packet.
486 type PacketHeader struct {
487 pk *PacketBuffer
488 typ headerType
489 }
490 491 // View returns an caller-owned copy of the underlying storage of h as a
492 // *buffer.View.
493 func (h PacketHeader) View() *buffer.View {
494 view := h.pk.headerView(h.typ)
495 if view.Size() == 0 {
496 return nil
497 }
498 return view.Clone()
499 }
500 501 // Slice returns the underlying storage of h as a []byte. The returned slice
502 // should not be modified if the underlying packet could be shared, cloned, or
503 // borrowed.
504 func (h PacketHeader) Slice() []byte {
505 view := h.pk.headerView(h.typ)
506 return view.AsSlice()
507 }
508 509 // Push pushes size bytes in the front of its residing packet, and returns the
510 // backing storage. Callers may only call one of Push or Consume once on each
511 // header in the lifetime of the underlying packet.
512 func (h PacketHeader) Push(size int) []byte {
513 return h.pk.push(h.typ, size)
514 }
515 516 // Consume moves the first size bytes of the unparsed data portion in the packet
517 // to h, and returns the backing storage. In the case of data is shorter than
518 // size, consumed will be false, and the state of h will not be affected.
519 // Callers may only call one of Push or Consume once on each header in the
520 // lifetime of the underlying packet.
521 func (h PacketHeader) Consume(size int) (v []byte, consumed bool) {
522 return h.pk.consume(h.typ, size)
523 }
524 525 // PacketData represents the data portion of a PacketBuffer.
526 //
527 // +stateify savable
528 type PacketData struct {
529 pk *PacketBuffer
530 }
531 532 // PullUp returns a contiguous slice of size bytes from the beginning of d.
533 // Callers should not keep the view for later use. Callers can write to the
534 // returned slice if they have singular ownership over the underlying
535 // Buffer.
536 func (d PacketData) PullUp(size int) (b []byte, ok bool) {
537 view, ok := d.pk.buf.PullUp(d.pk.dataOffset(), size)
538 return view.AsSlice(), ok
539 }
540 541 // Consume is the same as PullUp except that is additionally consumes the
542 // returned bytes. Subsequent PullUp or Consume will not return these bytes.
543 func (d PacketData) Consume(size int) ([]byte, bool) {
544 v, ok := d.PullUp(size)
545 if ok {
546 d.pk.consumed += size
547 }
548 return v, ok
549 }
550 551 // ReadTo reads bytes from d to dst. It also removes these bytes from d
552 // unless peek is true.
553 func (d PacketData) ReadTo(dst io.Writer, peek bool) (int, error) {
554 var (
555 err error
556 done int
557 )
558 offset := d.pk.dataOffset()
559 d.pk.buf.SubApply(offset, int(d.pk.buf.Size())-offset, func(v *buffer.View) {
560 if err != nil {
561 return
562 }
563 var n int
564 n, err = dst.Write(v.AsSlice())
565 done += n
566 if err != nil {
567 return
568 }
569 if n != v.Size() {
570 panic(fmt.Sprintf("io.Writer.Write succeeded with incomplete write: %d != %d", n, v.Size()))
571 }
572 })
573 if !peek {
574 d.pk.buf.TrimFront(int64(done))
575 }
576 return done, err
577 }
578 579 // CapLength reduces d to at most length bytes.
580 func (d PacketData) CapLength(length int) {
581 if length < 0 {
582 panic("length < 0")
583 }
584 d.pk.buf.Truncate(int64(length + d.pk.dataOffset()))
585 }
586 587 // ToBuffer returns the underlying storage of d in a buffer.Buffer.
588 func (d PacketData) ToBuffer() buffer.Buffer {
589 buf := d.pk.buf.Clone()
590 offset := d.pk.dataOffset()
591 buf.TrimFront(int64(offset))
592 return buf
593 }
594 595 // AppendView appends v into d, taking the ownership of v.
596 func (d PacketData) AppendView(v *buffer.View) {
597 d.pk.buf.Append(v)
598 }
599 600 // MergeBuffer merges b into d and clears b.
601 func (d PacketData) MergeBuffer(b *buffer.Buffer) {
602 d.pk.buf.Merge(b)
603 }
604 605 // MergeFragment appends the data portion of frag to dst. It modifies
606 // frag and frag should not be used again.
607 func MergeFragment(dst, frag *PacketBuffer) {
608 frag.buf.TrimFront(int64(frag.dataOffset()))
609 dst.buf.Merge(&frag.buf)
610 }
611 612 // ReadFrom moves at most count bytes from the beginning of src to the end
613 // of d and returns the number of bytes moved.
614 func (d PacketData) ReadFrom(src *buffer.Buffer, count int) int {
615 toRead := int64(count)
616 if toRead > src.Size() {
617 toRead = src.Size()
618 }
619 clone := src.Clone()
620 clone.Truncate(toRead)
621 d.pk.buf.Merge(&clone)
622 src.TrimFront(toRead)
623 return int(toRead)
624 }
625 626 // ReadFromPacketData moves count bytes from the beginning of oth to the end of
627 // d.
628 func (d PacketData) ReadFromPacketData(oth PacketData, count int) {
629 buf := oth.ToBuffer()
630 buf.Truncate(int64(count))
631 d.MergeBuffer(&buf)
632 oth.TrimFront(count)
633 buf.Release()
634 }
635 636 // Merge clears headers in oth and merges its data with d.
637 func (d PacketData) Merge(oth PacketData) {
638 oth.pk.buf.TrimFront(int64(oth.pk.dataOffset()))
639 d.pk.buf.Merge(&oth.pk.buf)
640 }
641 642 // TrimFront removes up to count bytes from the front of d's payload.
643 func (d PacketData) TrimFront(count int) {
644 if count > d.Size() {
645 count = d.Size()
646 }
647 buf := d.pk.Data().ToBuffer()
648 buf.TrimFront(int64(count))
649 d.pk.buf.Truncate(int64(d.pk.dataOffset()))
650 d.pk.buf.Merge(&buf)
651 }
652 653 // Size returns the number of bytes in the data payload of the packet.
654 func (d PacketData) Size() int {
655 return int(d.pk.buf.Size()) - d.pk.dataOffset()
656 }
657 658 // AsRange returns a Range representing the current data payload of the packet.
659 func (d PacketData) AsRange() Range {
660 return Range{
661 pk: d.pk,
662 offset: d.pk.dataOffset(),
663 length: d.Size(),
664 }
665 }
666 667 // Checksum returns a checksum over the data payload of the packet.
668 func (d PacketData) Checksum() uint16 {
669 return d.pk.buf.Checksum(d.pk.dataOffset())
670 }
671 672 // ChecksumAtOffset returns a checksum over the data payload of the packet
673 // starting from offset.
674 func (d PacketData) ChecksumAtOffset(offset int) uint16 {
675 return d.pk.buf.Checksum(offset)
676 }
677 678 // Range represents a contiguous subportion of a PacketBuffer.
679 type Range struct {
680 pk *PacketBuffer
681 offset int
682 length int
683 }
684 685 // Size returns the number of bytes in r.
686 func (r Range) Size() int {
687 return r.length
688 }
689 690 // SubRange returns a new Range starting at off bytes of r. It returns an empty
691 // range if off is out-of-bounds.
692 func (r Range) SubRange(off int) Range {
693 if off > r.length {
694 return Range{pk: r.pk}
695 }
696 return Range{
697 pk: r.pk,
698 offset: r.offset + off,
699 length: r.length - off,
700 }
701 }
702 703 // Capped returns a new Range with the same starting point of r and length
704 // capped at max.
705 func (r Range) Capped(max int) Range {
706 if r.length <= max {
707 return r
708 }
709 return Range{
710 pk: r.pk,
711 offset: r.offset,
712 length: max,
713 }
714 }
715 716 // ToSlice returns a caller-owned copy of data in r.
717 func (r Range) ToSlice() []byte {
718 if r.length == 0 {
719 return nil
720 }
721 all := make([]byte, 0, r.length)
722 r.iterate(func(v *buffer.View) {
723 all = append(all, v.AsSlice()...)
724 })
725 return all
726 }
727 728 // ToView returns a caller-owned copy of data in r.
729 func (r Range) ToView() *buffer.View {
730 if r.length == 0 {
731 return nil
732 }
733 newV := buffer.NewView(r.length)
734 r.iterate(func(v *buffer.View) {
735 newV.Write(v.AsSlice())
736 })
737 return newV
738 }
739 740 // iterate calls fn for each piece in r. fn is always called with a non-empty
741 // slice.
742 func (r Range) iterate(fn func(*buffer.View)) {
743 r.pk.buf.SubApply(r.offset, r.length, fn)
744 }
745 746 // PayloadSince returns a caller-owned view containing the payload starting from
747 // and including a particular header.
748 func PayloadSince(h PacketHeader) *buffer.View {
749 offset := h.pk.headerOffset()
750 for i := headerType(0); i < h.typ; i++ {
751 offset += h.pk.headers[i].length
752 }
753 return Range{
754 pk: h.pk,
755 offset: offset,
756 length: int(h.pk.buf.Size()) - offset,
757 }.ToView()
758 }
759 760 // BufferSince returns a caller-owned view containing the packet payload
761 // starting from and including a particular header.
762 func BufferSince(h PacketHeader) buffer.Buffer {
763 offset := h.pk.headerOffset()
764 for i := headerType(0); i < h.typ; i++ {
765 offset += h.pk.headers[i].length
766 }
767 clone := h.pk.buf.Clone()
768 clone.TrimFront(int64(offset))
769 return clone
770 }
771