You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
2.9 KiB

  1. // Copyright 2011 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. // +build darwin dragonfly freebsd linux netbsd openbsd solaris
  5. // Socket control messages
  6. package unix
  7. import "unsafe"
  8. // Round the length of a raw sockaddr up to align it properly.
  9. func cmsgAlignOf(salen int) int {
  10. salign := sizeofPtr
  11. // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
  12. // still require 32-bit aligned access to network subsystem.
  13. if darwin64Bit || dragonfly64Bit {
  14. salign = 4
  15. }
  16. return (salen + salign - 1) & ^(salign - 1)
  17. }
  18. // CmsgLen returns the value to store in the Len field of the Cmsghdr
  19. // structure, taking into account any necessary alignment.
  20. func CmsgLen(datalen int) int {
  21. return cmsgAlignOf(SizeofCmsghdr) + datalen
  22. }
  23. // CmsgSpace returns the number of bytes an ancillary element with
  24. // payload of the passed data length occupies.
  25. func CmsgSpace(datalen int) int {
  26. return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
  27. }
  28. func cmsgData(h *Cmsghdr) unsafe.Pointer {
  29. return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
  30. }
  31. // SocketControlMessage represents a socket control message.
  32. type SocketControlMessage struct {
  33. Header Cmsghdr
  34. Data []byte
  35. }
  36. // ParseSocketControlMessage parses b as an array of socket control
  37. // messages.
  38. func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
  39. var msgs []SocketControlMessage
  40. i := 0
  41. for i+CmsgLen(0) <= len(b) {
  42. h, dbuf, err := socketControlMessageHeaderAndData(b[i:])
  43. if err != nil {
  44. return nil, err
  45. }
  46. m := SocketControlMessage{Header: *h, Data: dbuf}
  47. msgs = append(msgs, m)
  48. i += cmsgAlignOf(int(h.Len))
  49. }
  50. return msgs, nil
  51. }
  52. func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
  53. h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
  54. if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) {
  55. return nil, nil, EINVAL
  56. }
  57. return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil
  58. }
  59. // UnixRights encodes a set of open file descriptors into a socket
  60. // control message for sending to another process.
  61. func UnixRights(fds ...int) []byte {
  62. datalen := len(fds) * 4
  63. b := make([]byte, CmsgSpace(datalen))
  64. h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
  65. h.Level = SOL_SOCKET
  66. h.Type = SCM_RIGHTS
  67. h.SetLen(CmsgLen(datalen))
  68. data := cmsgData(h)
  69. for _, fd := range fds {
  70. *(*int32)(data) = int32(fd)
  71. data = unsafe.Pointer(uintptr(data) + 4)
  72. }
  73. return b
  74. }
  75. // ParseUnixRights decodes a socket control message that contains an
  76. // integer array of open file descriptors from another process.
  77. func ParseUnixRights(m *SocketControlMessage) ([]int, error) {
  78. if m.Header.Level != SOL_SOCKET {
  79. return nil, EINVAL
  80. }
  81. if m.Header.Type != SCM_RIGHTS {
  82. return nil, EINVAL
  83. }
  84. fds := make([]int, len(m.Data)>>2)
  85. for i, j := 0, 0; i < len(m.Data); i += 4 {
  86. fds[j] = int(*(*int32)(unsafe.Pointer(&m.Data[i])))
  87. j++
  88. }
  89. return fds, nil
  90. }