sockaddr.go 5.2 KB

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