sockaddr.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. package sockaddr
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. type SockAddrType int
  7. type AttrName string
  8. const (
  9. TypeUnknown SockAddrType = 0x0
  10. TypeUnix = 0x1
  11. TypeIPv4 = 0x2
  12. TypeIPv6 = 0x4
  13. // TypeIP is the union of TypeIPv4 and TypeIPv6
  14. TypeIP = 0x6
  15. )
  16. type SockAddr interface {
  17. // CmpRFC returns 0 if SockAddr exactly matches one of the matched RFC
  18. // networks, -1 if the receiver is contained within the RFC network, or
  19. // 1 if the address is not contained within the RFC.
  20. CmpRFC(rfcNum uint, sa SockAddr) int
  21. // Contains returns true if the SockAddr arg is contained within the
  22. // receiver
  23. Contains(SockAddr) bool
  24. // Equal allows for the comparison of two SockAddrs
  25. Equal(SockAddr) bool
  26. DialPacketArgs() (string, string)
  27. DialStreamArgs() (string, string)
  28. ListenPacketArgs() (string, string)
  29. ListenStreamArgs() (string, string)
  30. // String returns the string representation of SockAddr
  31. String() string
  32. // Type returns the SockAddrType
  33. Type() SockAddrType
  34. }
  35. // sockAddrAttrMap is a map of the SockAddr type-specific attributes.
  36. var sockAddrAttrMap map[AttrName]func(SockAddr) string
  37. var sockAddrAttrs []AttrName
  38. func init() {
  39. sockAddrInit()
  40. }
  41. // New creates a new SockAddr from the string. The order in which New()
  42. // attempts to construct a SockAddr is: IPv4Addr, IPv6Addr, SockAddrUnix.
  43. //
  44. // NOTE: New() relies on the heuristic wherein if the path begins with either a
  45. // '.' or '/' character before creating a new UnixSock. For UNIX sockets that
  46. // are absolute paths or are nested within a sub-directory, this works as
  47. // expected, however if the UNIX socket is contained in the current working
  48. // directory, this will fail unless the path begins with "./"
  49. // (e.g. "./my-local-socket"). Calls directly to NewUnixSock() do not suffer
  50. // this limitation. Invalid IP addresses such as "256.0.0.0/-1" will run afoul
  51. // of this heuristic and be assumed to be a valid UNIX socket path (which they
  52. // are, but it is probably not what you want and you won't realize it until you
  53. // stat(2) the file system to discover it doesn't exist).
  54. func NewSockAddr(s string) (SockAddr, error) {
  55. ipv4Addr, err := NewIPv4Addr(s)
  56. if err == nil {
  57. return ipv4Addr, nil
  58. }
  59. ipv6Addr, err := NewIPv6Addr(s)
  60. if err == nil {
  61. return ipv6Addr, nil
  62. }
  63. // Check to make sure the string begins with either a '.' or '/', or
  64. // contains a '/'.
  65. if len(s) > 1 && (strings.IndexAny(s[0:1], "./") != -1 || strings.IndexByte(s, '/') != -1) {
  66. unixSock, err := NewUnixSock(s)
  67. if err == nil {
  68. return unixSock, nil
  69. }
  70. }
  71. return nil, fmt.Errorf("Unable to convert %q to an IPv4 or IPv6 address, or a UNIX Socket", s)
  72. }
  73. // ToIPAddr returns an IPAddr type or nil if the type conversion fails.
  74. func ToIPAddr(sa SockAddr) *IPAddr {
  75. ipa, ok := sa.(IPAddr)
  76. if !ok {
  77. return nil
  78. }
  79. return &ipa
  80. }
  81. // ToIPv4Addr returns an IPv4Addr type or nil if the type conversion fails.
  82. func ToIPv4Addr(sa SockAddr) *IPv4Addr {
  83. switch v := sa.(type) {
  84. case IPv4Addr:
  85. return &v
  86. default:
  87. return nil
  88. }
  89. }
  90. // ToIPv6Addr returns an IPv6Addr type or nil if the type conversion fails.
  91. func ToIPv6Addr(sa SockAddr) *IPv6Addr {
  92. switch v := sa.(type) {
  93. case IPv6Addr:
  94. return &v
  95. default:
  96. return nil
  97. }
  98. }
  99. // ToUnixSock returns a UnixSock type or nil if the type conversion fails.
  100. func ToUnixSock(sa SockAddr) *UnixSock {
  101. switch v := sa.(type) {
  102. case UnixSock:
  103. return &v
  104. default:
  105. return nil
  106. }
  107. }
  108. // SockAddrAttr returns a string representation of an attribute for the given
  109. // SockAddr.
  110. func SockAddrAttr(sa SockAddr, selector AttrName) string {
  111. fn, found := sockAddrAttrMap[selector]
  112. if !found {
  113. return ""
  114. }
  115. return fn(sa)
  116. }
  117. // String() for SockAddrType returns a string representation of the
  118. // SockAddrType (e.g. "IPv4", "IPv6", "UNIX", "IP", or "unknown").
  119. func (sat SockAddrType) String() string {
  120. switch sat {
  121. case TypeIPv4:
  122. return "IPv4"
  123. case TypeIPv6:
  124. return "IPv6"
  125. // There is no concrete "IP" type. Leaving here as a reminder.
  126. // case TypeIP:
  127. // return "IP"
  128. case TypeUnix:
  129. return "UNIX"
  130. default:
  131. panic("unsupported type")
  132. }
  133. }
  134. // sockAddrInit is called once at init()
  135. func sockAddrInit() {
  136. sockAddrAttrs = []AttrName{
  137. "type", // type should be first
  138. "string",
  139. }
  140. sockAddrAttrMap = map[AttrName]func(sa SockAddr) string{
  141. "string": func(sa SockAddr) string {
  142. return sa.String()
  143. },
  144. "type": func(sa SockAddr) string {
  145. return sa.Type().String()
  146. },
  147. }
  148. }
  149. // UnixSockAttrs returns a list of attributes supported by the UnixSock type
  150. func SockAddrAttrs() []AttrName {
  151. return sockAddrAttrs
  152. }