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