| 459 | type setGSOFunc func(control *[]byte, gsoSize uint16) |
| 460 | |
| 461 | func coalesceMessages(addr *net.UDPAddr, ep *StdNetEndpoint, bufs [][]byte, msgs []ipv6.Message, setGSO setGSOFunc) int { |
| 462 | var ( |
| 463 | base = -1 // index of msg we are currently coalescing into |
| 464 | gsoSize int // segmentation size of msgs[base] |
| 465 | dgramCnt int // number of dgrams coalesced into msgs[base] |
| 466 | endBatch bool // tracking flag to start a new batch on next iteration of bufs |
| 467 | ) |
| 468 | maxPayloadLen := maxIPv4PayloadLen |
| 469 | if ep.DstIP().Is6() { |
| 470 | maxPayloadLen = maxIPv6PayloadLen |
| 471 | } |
| 472 | for i, buf := range bufs { |
| 473 | if i > 0 { |
| 474 | msgLen := len(buf) |
| 475 | baseLenBefore := len(msgs[base].Buffers[0]) |
| 476 | freeBaseCap := cap(msgs[base].Buffers[0]) - baseLenBefore |
| 477 | if msgLen+baseLenBefore <= maxPayloadLen && |
| 478 | msgLen <= gsoSize && |
| 479 | msgLen <= freeBaseCap && |
| 480 | dgramCnt < udpSegmentMaxDatagrams && |
| 481 | !endBatch { |
| 482 | msgs[base].Buffers[0] = append(msgs[base].Buffers[0], buf...) |
| 483 | if i == len(bufs)-1 { |
| 484 | setGSO(&msgs[base].OOB, uint16(gsoSize)) |
| 485 | } |
| 486 | dgramCnt++ |
| 487 | if msgLen < gsoSize { |
| 488 | // A smaller than gsoSize packet on the tail is legal, but |
| 489 | // it must end the batch. |
| 490 | endBatch = true |
| 491 | } |
| 492 | continue |
| 493 | } |
| 494 | } |
| 495 | if dgramCnt > 1 { |
| 496 | setGSO(&msgs[base].OOB, uint16(gsoSize)) |
| 497 | } |
| 498 | // Reset prior to incrementing base since we are preparing to start a |
| 499 | // new potential batch. |
| 500 | endBatch = false |
| 501 | base++ |
| 502 | gsoSize = len(buf) |
| 503 | setSrcControl(&msgs[base].OOB, ep) |
| 504 | msgs[base].Buffers[0] = buf |
| 505 | msgs[base].Addr = addr |
| 506 | dgramCnt = 1 |
| 507 | } |
| 508 | return base + 1 |
| 509 | } |
| 510 | |
| 511 | type getGSOFunc func(control []byte) (int, error) |
| 512 | |