mmsghdr_unix.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // Copyright 2017 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. //go:build aix || linux || netbsd
  5. // +build aix linux netbsd
  6. package socket
  7. import (
  8. "net"
  9. "sync"
  10. )
  11. type mmsghdrs []mmsghdr
  12. func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
  13. for i := range hs {
  14. ms[i].N = int(hs[i].Len)
  15. ms[i].NN = hs[i].Hdr.controllen()
  16. ms[i].Flags = hs[i].Hdr.flags()
  17. if parseFn != nil {
  18. var err error
  19. ms[i].Addr, err = parseFn(hs[i].Hdr.name(), hint)
  20. if err != nil {
  21. return err
  22. }
  23. }
  24. }
  25. return nil
  26. }
  27. // mmsghdrsPacker packs Message-slices into mmsghdrs (re-)using pre-allocated buffers.
  28. type mmsghdrsPacker struct {
  29. // hs are the pre-allocated mmsghdrs.
  30. hs mmsghdrs
  31. // sockaddrs is the pre-allocated buffer for the Hdr.Name buffers.
  32. // We use one large buffer for all messages and slice it up.
  33. sockaddrs []byte
  34. // vs are the pre-allocated iovecs.
  35. // We allocate one large buffer for all messages and slice it up. This allows to reuse the buffer
  36. // if the number of buffers per message is distributed differently between calls.
  37. vs []iovec
  38. }
  39. func (p *mmsghdrsPacker) prepare(ms []Message) {
  40. n := len(ms)
  41. if n <= cap(p.hs) {
  42. p.hs = p.hs[:n]
  43. } else {
  44. p.hs = make(mmsghdrs, n)
  45. }
  46. if n*sizeofSockaddrInet6 <= cap(p.sockaddrs) {
  47. p.sockaddrs = p.sockaddrs[:n*sizeofSockaddrInet6]
  48. } else {
  49. p.sockaddrs = make([]byte, n*sizeofSockaddrInet6)
  50. }
  51. nb := 0
  52. for _, m := range ms {
  53. nb += len(m.Buffers)
  54. }
  55. if nb <= cap(p.vs) {
  56. p.vs = p.vs[:nb]
  57. } else {
  58. p.vs = make([]iovec, nb)
  59. }
  60. }
  61. func (p *mmsghdrsPacker) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr, []byte) int) mmsghdrs {
  62. p.prepare(ms)
  63. hs := p.hs
  64. vsRest := p.vs
  65. saRest := p.sockaddrs
  66. for i := range hs {
  67. nvs := len(ms[i].Buffers)
  68. vs := vsRest[:nvs]
  69. vsRest = vsRest[nvs:]
  70. var sa []byte
  71. if parseFn != nil {
  72. sa = saRest[:sizeofSockaddrInet6]
  73. saRest = saRest[sizeofSockaddrInet6:]
  74. } else if marshalFn != nil {
  75. n := marshalFn(ms[i].Addr, saRest)
  76. if n > 0 {
  77. sa = saRest[:n]
  78. saRest = saRest[n:]
  79. }
  80. }
  81. hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
  82. }
  83. return hs
  84. }
  85. var defaultMmsghdrsPool = mmsghdrsPool{
  86. p: sync.Pool{
  87. New: func() interface{} {
  88. return new(mmsghdrsPacker)
  89. },
  90. },
  91. }
  92. type mmsghdrsPool struct {
  93. p sync.Pool
  94. }
  95. func (p *mmsghdrsPool) Get() *mmsghdrsPacker {
  96. return p.p.Get().(*mmsghdrsPacker)
  97. }
  98. func (p *mmsghdrsPool) Put(packer *mmsghdrsPacker) {
  99. p.p.Put(packer)
  100. }