| package sockaddr |
| |
| import ( |
| "fmt" |
| "strings" |
| ) |
| |
| type SockAddrType int |
| type AttrName string |
| |
| const ( |
| TypeUnknown SockAddrType = 0x0 |
| TypeUnix = 0x1 |
| TypeIPv4 = 0x2 |
| TypeIPv6 = 0x4 |
| |
| // TypeIP is the union of TypeIPv4 and TypeIPv6 |
| TypeIP = 0x6 |
| ) |
| |
| type SockAddr interface { |
| // CmpRFC returns 0 if SockAddr exactly matches one of the matched RFC |
| // networks, -1 if the receiver is contained within the RFC network, or |
| // 1 if the address is not contained within the RFC. |
| CmpRFC(rfcNum uint, sa SockAddr) int |
| |
| // Contains returns true if the SockAddr arg is contained within the |
| // receiver |
| Contains(SockAddr) bool |
| |
| // Equal allows for the comparison of two SockAddrs |
| Equal(SockAddr) bool |
| |
| DialPacketArgs() (string, string) |
| DialStreamArgs() (string, string) |
| ListenPacketArgs() (string, string) |
| ListenStreamArgs() (string, string) |
| |
| // String returns the string representation of SockAddr |
| String() string |
| |
| // Type returns the SockAddrType |
| Type() SockAddrType |
| } |
| |
| // sockAddrAttrMap is a map of the SockAddr type-specific attributes. |
| var sockAddrAttrMap map[AttrName]func(SockAddr) string |
| var sockAddrAttrs []AttrName |
| |
| func init() { |
| sockAddrInit() |
| } |
| |
| // New creates a new SockAddr from the string. The order in which New() |
| // attempts to construct a SockAddr is: IPv4Addr, IPv6Addr, SockAddrUnix. |
| // |
| // NOTE: New() relies on the heuristic wherein if the path begins with either a |
| // '.' or '/' character before creating a new UnixSock. For UNIX sockets that |
| // are absolute paths or are nested within a sub-directory, this works as |
| // expected, however if the UNIX socket is contained in the current working |
| // directory, this will fail unless the path begins with "./" |
| // (e.g. "./my-local-socket"). Calls directly to NewUnixSock() do not suffer |
| // this limitation. Invalid IP addresses such as "256.0.0.0/-1" will run afoul |
| // of this heuristic and be assumed to be a valid UNIX socket path (which they |
| // are, but it is probably not what you want and you won't realize it until you |
| // stat(2) the file system to discover it doesn't exist). |
| func NewSockAddr(s string) (SockAddr, error) { |
| ipv4Addr, err := NewIPv4Addr(s) |
| if err == nil { |
| return ipv4Addr, nil |
| } |
| |
| ipv6Addr, err := NewIPv6Addr(s) |
| if err == nil { |
| return ipv6Addr, nil |
| } |
| |
| // Check to make sure the string begins with either a '.' or '/', or |
| // contains a '/'. |
| if len(s) > 1 && (strings.IndexAny(s[0:1], "./") != -1 || strings.IndexByte(s, '/') != -1) { |
| unixSock, err := NewUnixSock(s) |
| if err == nil { |
| return unixSock, nil |
| } |
| } |
| |
| return nil, fmt.Errorf("Unable to convert %q to an IPv4 or IPv6 address, or a UNIX Socket", s) |
| } |
| |
| // ToIPAddr returns an IPAddr type or nil if the type conversion fails. |
| func ToIPAddr(sa SockAddr) *IPAddr { |
| ipa, ok := sa.(IPAddr) |
| if !ok { |
| return nil |
| } |
| return &ipa |
| } |
| |
| // ToIPv4Addr returns an IPv4Addr type or nil if the type conversion fails. |
| func ToIPv4Addr(sa SockAddr) *IPv4Addr { |
| switch v := sa.(type) { |
| case IPv4Addr: |
| return &v |
| default: |
| return nil |
| } |
| } |
| |
| // ToIPv6Addr returns an IPv6Addr type or nil if the type conversion fails. |
| func ToIPv6Addr(sa SockAddr) *IPv6Addr { |
| switch v := sa.(type) { |
| case IPv6Addr: |
| return &v |
| default: |
| return nil |
| } |
| } |
| |
| // ToUnixSock returns a UnixSock type or nil if the type conversion fails. |
| func ToUnixSock(sa SockAddr) *UnixSock { |
| switch v := sa.(type) { |
| case UnixSock: |
| return &v |
| default: |
| return nil |
| } |
| } |
| |
| // SockAddrAttr returns a string representation of an attribute for the given |
| // SockAddr. |
| func SockAddrAttr(sa SockAddr, selector AttrName) string { |
| fn, found := sockAddrAttrMap[selector] |
| if !found { |
| return "" |
| } |
| |
| return fn(sa) |
| } |
| |
| // String() for SockAddrType returns a string representation of the |
| // SockAddrType (e.g. "IPv4", "IPv6", "UNIX", "IP", or "unknown"). |
| func (sat SockAddrType) String() string { |
| switch sat { |
| case TypeIPv4: |
| return "IPv4" |
| case TypeIPv6: |
| return "IPv6" |
| // There is no concrete "IP" type. Leaving here as a reminder. |
| // case TypeIP: |
| // return "IP" |
| case TypeUnix: |
| return "UNIX" |
| default: |
| panic("unsupported type") |
| } |
| } |
| |
| // sockAddrInit is called once at init() |
| func sockAddrInit() { |
| sockAddrAttrs = []AttrName{ |
| "type", // type should be first |
| "string", |
| } |
| |
| sockAddrAttrMap = map[AttrName]func(sa SockAddr) string{ |
| "string": func(sa SockAddr) string { |
| return sa.String() |
| }, |
| "type": func(sa SockAddr) string { |
| return sa.Type().String() |
| }, |
| } |
| } |
| |
| // UnixSockAttrs returns a list of attributes supported by the UnixSock type |
| func SockAddrAttrs() []AttrName { |
| return sockAddrAttrs |
| } |