plc4go/internal/bacnetip/bacgopes/pdu/pdu_Address.go (795 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package pdu
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"net/netip"
"regexp"
"strconv"
"strings"
"github.com/pkg/errors"
. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes"
. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/comp"
. "github.com/apache/plc4x/plc4go/internal/bacnetip/bacgopes/debugging"
)
type AddressType int
const (
NULL_ADDRESS AddressType = iota
LOCAL_BROADCAST_ADDRESS
LOCAL_STATION_ADDRESS
REMOTE_BROADCAST_ADDRESS
REMOTE_STATION_ADDRESS
GLOBAL_BROADCAST_ADDRESS
)
func (a AddressType) String() string {
switch a {
case NULL_ADDRESS:
return "NULL_ADDRESS"
case LOCAL_BROADCAST_ADDRESS:
return "LOCAL_BROADCAST_ADDRESS"
case LOCAL_STATION_ADDRESS:
return "LOCAL_STATION_ADDRESS"
case REMOTE_BROADCAST_ADDRESS:
return "REMOTE_BROADCAST_ADDRESS"
case REMOTE_STATION_ADDRESS:
return "REMOTE_STATION_ADDRESS"
case GLOBAL_BROADCAST_ADDRESS:
return "GLOBAL_BROADCAST_ADDRESS"
default:
return "Unknown"
}
}
type AddressTuple[L any, R any] struct {
Left L
Right R
}
func NewAddressTuple[L any, R any](l L, r R) *AddressTuple[L, R] {
return &AddressTuple[L, R]{l, r}
}
func (a *AddressTuple[L, R]) deepCopy() *AddressTuple[L, R] {
if a == nil {
return nil
}
// TODO: check if that works like intended (might just fail for pointer types)
return &AddressTuple[L, R]{*CopyPtr[L](&a.Left), *CopyPtr[R](&a.Right)}
}
func (a *AddressTuple[L, R]) DeepCopy() any {
return a.deepCopy()
}
func (a *AddressTuple[L, R]) Format(s fmt.State, v rune) {
switch v {
case 's', 'v', 'r':
_, _ = fmt.Fprint(s, a.String())
}
}
func (a *AddressTuple[L, R]) String() string {
return fmt.Sprintf("(%v, %v)", a.Left, a.Right)
}
var _field_address = regexp.MustCompile(`((?:\d+)|(?:0x(?:[0-9A-Fa-f][0-9A-Fa-f])+))`)
var _ip_address_port = regexp.MustCompile(`(\d+\.\d+\.\d+\.\d+)(?::(\d+))?`)
var _ip_address_mask_port = regexp.MustCompile(`(\d+\.\d+\.\d+\.\d+)(?:/(\d+))?(?::(\d+))?`)
var _net_ip_address_port = regexp.MustCompile(`(\d+):` + _ip_address_port.String())
var _at_route = regexp.MustCompile(`(?:[@](?:` + _field_address.String() + `|` + _ip_address_port.String() + `))?`)
var field_address_re = regexp.MustCompile(`^` + _field_address.String() + `$`)
var ip_address_port_re = regexp.MustCompile(`^` + _ip_address_port.String() + `$`)
var ip_address_mask_port_re = regexp.MustCompile(`^` + _ip_address_mask_port.String() + `$`)
var net_ip_address_port_re = regexp.MustCompile(`^` + _net_ip_address_port.String() + `$`)
var net_ip_address_mask_port_re = regexp.MustCompile(`^` + _net_ip_address_port.String() + `$`)
var ethernet_re = regexp.MustCompile(`^([0-9A-Fa-f][0-9A-Fa-f][:]){5}([0-9A-Fa-f][0-9A-Fa-f])$`)
var interface_re = regexp.MustCompile(`^(?:([\w]+))(?::(\d+))?$`)
var net_broadcast_route_re = regexp.MustCompile(`^([0-9])+:[*]` + _at_route.String() + `$`)
var net_station_route_re = regexp.MustCompile(`^([0-9])+:` + _field_address.String() + _at_route.String() + `$`)
var net_ip_address_route_re = regexp.MustCompile(`^([0-9])+:` + _ip_address_port.String() + _at_route.String() + `$`)
var CombinedPattern = regexp.MustCompile(`^(?:(?:([0-9]+)|([*])):)?(?:([*])|` + _field_address.String() + `|` + _ip_address_mask_port.String() + `)` + _at_route.String() + `$`)
//go:generate go tool plc4xGenerator -type=Address -prefix=pdu_
type Address struct {
AddrType AddressType
AddrNet *uint16
AddrAddress []byte
AddrLen *uint8
AddrRoute *Address
AddrIP *uint32
AddrMask *uint32
AddrHost *uint32
AddrSubnet *uint32
AddrPort *uint16
AddrTuple *AddressTuple[string, uint16]
AddrBroadcastTuple *AddressTuple[string, uint16]
_leafName string
}
func NewAddress(args Args) (*Address, error) {
if _debug != nil {
_debug("__init__ %r", args)
}
a := &Address{
_leafName: "Address", // TODO: usually this is done by extract, we leaf address for now as this would imply changing type to an interface and that is a big change.
}
a.AddrNet = nil
a.AddrAddress = nil
a.AddrLen = nil
a.AddrRoute = nil
switch len(args) {
case 1:
if err := a.decodeAddress(args[0]); err != nil {
return nil, errors.Wrap(err, "decodeAddress")
}
case 2:
if err := a.decodeAddress(args[1]); err != nil {
return nil, errors.Wrap(err, "decodeAddress")
}
switch a.AddrType {
case LOCAL_STATION_ADDRESS:
a.AddrType = REMOTE_STATION_ADDRESS
var addrNet *uint16
switch arg0 := args[0].(type) {
case uint16:
addrNet = &arg0
case *uint16:
addrNet = arg0
}
a.AddrNet = addrNet
case LOCAL_BROADCAST_ADDRESS:
a.AddrType = REMOTE_BROADCAST_ADDRESS
var addrNet *uint16
switch arg0 := args[0].(type) {
case uint16:
addrNet = &arg0
case *uint16:
addrNet = arg0
}
a.AddrNet = addrNet
default:
return nil, errors.New("unrecognized address ctor form")
}
}
return a, nil
}
// decodeAddress Initialize the address from a string. Lots of different forms are supported
func (a *Address) decodeAddress(addr any) error {
if _debug != nil {
_debug("decode_address %r %T", addr, addr)
}
// start out assuming this is a local station and didn't get routed
a.AddrType = LOCAL_STATION_ADDRESS
a.AddrNet = nil
a.AddrAddress = nil
a.AddrLen = nil
a.AddrRoute = nil
switch {
case addr == "*":
if _debug != nil {
_debug(" - localBroadcast")
}
a.AddrType = LOCAL_BROADCAST_ADDRESS
case addr == "*:*":
if _debug != nil {
_debug(" - globalBroadcast")
}
a.AddrType = GLOBAL_BROADCAST_ADDRESS
default:
switch addr := addr.(type) {
case net.Addr:
// TODO: hacked in udp support
udpAddr := addr.(*net.UDPAddr)
a.AddrAddress = udpAddr.IP.To4()
if a.AddrAddress == nil {
a.AddrAddress = udpAddr.IP.To16()
}
length := uint8(len(a.AddrAddress))
a.AddrLen = &length
port := uint16(udpAddr.Port)
a.AddrPort = &port
addr.String()
case int, int32, int64, uint, uint32, uint64:
iaddr, err := strconv.ParseInt(fmt.Sprintf("%v", addr), 10, 64) // TODO: bit ugly but better than repeating all of it
if err != nil {
panic(err)
}
if _debug != nil {
_debug(" - int")
}
if iaddr < 0 || iaddr > 255 {
return errors.New("address out of range")
}
a.AddrAddress = []byte{byte(iaddr)}
length := uint8(1)
a.AddrLen = &length
case []byte:
if _debug != nil {
_debug(" - bytes or bytearray")
}
a.AddrAddress = addr
length := uint8(len(addr))
a.AddrLen = &length
if *a.AddrLen == 6 {
ip := ipv4ToUint32(addr[:4])
a.AddrIP = &ip
mask := uint32((1 << 32) - 1)
a.AddrMask = &mask
host := *a.AddrIP & ^(*a.AddrMask)
a.AddrHost = &host
subnet := *a.AddrIP & *a.AddrMask
a.AddrSubnet = &subnet
port := portToUint16(addr[4:])
a.AddrPort = &port
a.AddrTuple = &AddressTuple[string, uint16]{uint32ToIpv4(*a.AddrIP).String(), *a.AddrPort}
a.AddrBroadcastTuple = &AddressTuple[string, uint16]{"255.255.255.255", *a.AddrPort}
}
case string:
if _debug != nil {
_debug(" - str")
}
m := CombinedPattern.MatchString(addr)
if m {
if _debug != nil {
_debug(" - combined pattern")
}
groups := CombinedPattern.FindStringSubmatch(addr)
_net := groups[1]
globalBroadcast := groups[2]
localBroadcast := groups[3]
localAddr := groups[4]
localIpAddr := groups[5]
localIpNet := groups[6]
localIpPort := groups[7]
routeAddr := groups[8]
routeIpAddr := groups[9]
routeIpPort := groups[10]
if globalBroadcast != "" && localBroadcast != "" {
if _debug != nil {
_debug(" - global broadcast")
}
a.AddrType = GLOBAL_BROADCAST_ADDRESS
} else if _net != "" && localBroadcast != "" {
if _debug != nil {
_debug(" - remote broadcast")
}
netAddr, err := strconv.ParseUint(_net, 10, 16)
if err != nil {
return errors.Wrap(err, "can't parse net")
}
a.AddrType = REMOTE_BROADCAST_ADDRESS
var netAddr16 = uint16(netAddr)
a.AddrNet = &netAddr16
} else if localBroadcast != "" {
if _debug != nil {
_debug(" - local broadcast")
}
a.AddrType = LOCAL_BROADCAST_ADDRESS
} else if _net != "" {
if _debug != nil {
_debug(" - remote station")
}
netAddr, err := strconv.ParseUint(_net, 10, 16)
if err != nil {
return errors.Wrap(err, "can't parse net")
}
a.AddrType = REMOTE_STATION_ADDRESS
var netAddr16 = uint16(netAddr)
a.AddrNet = &netAddr16
}
if localAddr != "" {
if _debug != nil {
_debug(" - simple address")
}
if strings.HasPrefix(localAddr, "0x") {
var err error
a.AddrAddress, err = Xtob(localAddr[2:])
if err != nil {
return errors.Wrap(err, "can't parse local address")
}
addrLen := uint8(len(a.AddrAddress))
a.AddrLen = &addrLen
} else {
localAddr, err := strconv.ParseUint(localAddr, 10, 8)
if err != nil {
return errors.Wrap(err, "can't parse local addr")
}
a.AddrAddress = []byte{byte(localAddr)}
addrLen := uint8(1)
a.AddrLen = &addrLen
}
}
if localIpAddr != "" {
if _debug != nil {
_debug(" - ip address")
}
if localIpPort == "" {
localIpPort = "47808"
}
if localIpNet == "" {
localIpNet = "32"
}
localIpPortParse, err := strconv.ParseUint(localIpPort, 10, 16)
if err != nil {
return errors.Wrap(err, "can't parse local addr")
}
localIpPort16 := uint16(localIpPortParse)
a.AddrPort = &localIpPort16
a.AddrTuple = &AddressTuple[string, uint16]{localIpAddr, *a.AddrPort}
if _debug != nil {
_debug(" - addrTuple: %r", a.AddrTuple)
}
parseAddr, err := netip.ParseAddr(localIpAddr)
if err != nil {
return errors.Wrap(err, "can't parse local addr")
}
addrIp := binary.BigEndian.Uint32(parseAddr.AsSlice())
a.AddrIP = &addrIp
localIpNetParse, err := strconv.ParseUint(localIpNet, 10, 16)
if err != nil {
return errors.Wrap(err, "can't parse local addr")
}
localNetPort16 := uint16(localIpNetParse)
mask := uint32((_longMask << (32 - localNetPort16)) & _longMask)
a.AddrMask = &mask
addrHost := *a.AddrIP &^ (*a.AddrMask)
a.AddrHost = &addrHost
addrSubnet := *a.AddrIP & (*a.AddrMask)
a.AddrSubnet = &addrSubnet
bcast := *a.AddrSubnet | ^(*a.AddrMask)
bcastIpReverse := make(net.IP, 4)
binary.BigEndian.PutUint32(bcastIpReverse, bcast&uint32(_longMask))
a.AddrBroadcastTuple = &AddressTuple[string, uint16]{bcastIpReverse.String(), *a.AddrPort}
if _debug != nil {
_debug(" - addrBroadcastTuple: %r", a.AddrBroadcastTuple)
}
portReverse := make([]byte, 2)
binary.BigEndian.PutUint16(portReverse, *a.AddrPort&uint16(_shortMask))
a.AddrAddress = append(parseAddr.AsSlice(), portReverse...)
addrLen := uint8(6)
a.AddrLen = &addrLen
}
if !Settings.RouteAware && (routeAddr != "" || routeIpAddr != "") {
if _debug != nil {
_debug("route provided but not route aware: %v", addr)
}
}
if routeAddr != "" {
if strings.HasPrefix(routeAddr, "0x") {
xtob, err := Xtob(routeAddr[2:])
if err != nil {
return errors.Wrap(err, "can't parse route addr")
}
a.AddrRoute, err = NewAddress(NA(xtob))
if err != nil {
return errors.Wrap(err, "can't parse route")
}
} else {
routeAddr, err := strconv.ParseUint(routeAddr, 10, 32)
if err != nil {
return errors.Wrap(err, "can't parse route addr")
}
a.AddrRoute, err = NewAddress(NA(routeAddr))
if err != nil {
return errors.Wrap(err, "can't create route")
}
if _debug != nil {
_debug(" - addrRoute: %r", a.AddrRoute)
}
}
} else if routeIpAddr != "" {
if routeIpPort == "" {
routeIpPort = "47808"
}
var err error
tuple := &AddressTuple[string, string]{routeIpAddr, routeIpPort}
a.AddrRoute, err = NewAddress(NA(tuple))
if err != nil {
return errors.Wrap(err, "can't create route")
}
}
return nil
}
if ethernet_re.MatchString(addr) {
if _debug != nil {
_debug(" - ethernet")
}
var err error
a.AddrAddress, err = Xtob(addr)
if err != nil {
return errors.Wrap(err, "can't parse address")
}
addrLen := uint8(len(a.AddrAddress))
a.AddrLen = &addrLen
return nil
}
intR := regexp.MustCompile(`^\d+$`)
if intR.MatchString(addr) {
if _debug != nil {
_debug(" - int")
}
parseUint, err := strconv.ParseUint(addr, 10, 8)
if err != nil {
return errors.Wrap(err, "can't parse int")
}
a.AddrAddress = []byte{byte(parseUint)}
addrLen := uint8(len(a.AddrAddress))
a.AddrLen = &addrLen
return nil
}
remoteBroadcast := regexp.MustCompile(`^\d+:[*]$`)
if remoteBroadcast.MatchString(addr) {
if _debug != nil {
_debug(" - remote broadcast")
}
parseUint, err := strconv.ParseUint(addr[:len(addr)-2], 10, 16)
if err != nil {
return errors.Wrap(err, "can't parse int")
}
a.AddrType = REMOTE_BROADCAST_ADDRESS
addrNet := uint16(parseUint)
a.AddrNet = &addrNet
a.AddrAddress = nil
a.AddrLen = nil
return nil
}
remoteStation := regexp.MustCompile(`^\d+:[*]$`)
if remoteStation.MatchString(addr) {
if _debug != nil {
_debug(" - remote station")
}
split := strings.Split(addr, ":")
_net, _addr := split[0], split[1]
parseNetUint, err := strconv.ParseUint(_net, 10, 16)
if err != nil {
return errors.Wrap(err, "can't parse int")
}
parseAddrUint, err := strconv.ParseUint(_addr, 10, 8)
if err != nil {
return errors.Wrap(err, "can't parse int")
}
a.AddrType = REMOTE_STATION_ADDRESS
addrNet := uint16(parseNetUint)
a.AddrNet = &addrNet
a.AddrAddress = []byte{byte(parseAddrUint)}
addrLen := uint8(len(a.AddrAddress))
a.AddrLen = &addrLen
return nil
}
modernHexString := regexp.MustCompile(`^0x([0-9A-Fa-f][0-9A-Fa-f])+$`)
if modernHexString.MatchString(addr) {
if _debug != nil {
_debug(" - modern hex string")
}
var err error
a.AddrAddress, err = Xtob(addr[2:])
if err != nil {
return errors.Wrap(err, "can't parse address")
}
addrLen := uint8(len(a.AddrAddress))
a.AddrLen = &addrLen
return nil
}
oldSchoolHexString := regexp.MustCompile(`^X'([0-9A-Fa-f][0-9A-Fa-f])+'$`)
if oldSchoolHexString.MatchString(addr) {
if _debug != nil {
_debug(" - modern hex string")
}
var err error
a.AddrAddress, err = Xtob(addr[2 : len(addr)-1])
if err != nil {
return errors.Wrap(err, "can't parse address")
}
addrLen := uint8(len(a.AddrAddress))
a.AddrLen = &addrLen
return nil
}
remoteStationWithModernHexString := regexp.MustCompile(`^\d+:0x([0-9A-Fa-f][0-9A-Fa-f])+$`)
if remoteStationWithModernHexString.MatchString(addr) {
if _debug != nil {
_debug(" - remote station with modern hex string")
}
split := strings.Split(addr, ":")
_net, _addr := split[0], split[1]
parseNetUint, err := strconv.ParseUint(_net, 10, 16)
if err != nil {
return errors.Wrap(err, "can't parse int")
}
a.AddrType = REMOTE_STATION_ADDRESS
addrNet := uint16(parseNetUint)
a.AddrNet = &addrNet
a.AddrAddress, err = Xtob(_addr[2:])
if err != nil {
return errors.Wrap(err, "can't parse addr")
}
addrLen := uint8(len(a.AddrAddress))
a.AddrLen = &addrLen
return nil
}
remoteStationWithOldHexString := regexp.MustCompile(`^\d+:X'([0-9A-Fa-f][0-9A-Fa-f])+'$`)
if remoteStationWithOldHexString.MatchString(addr) {
if _debug != nil {
_debug(" - remote station with modern hex string")
}
split := strings.Split(addr, ":")
_net, _addr := split[0], split[1]
parseNetUint, err := strconv.ParseUint(_net, 10, 16)
if err != nil {
return errors.Wrap(err, "can't parse int")
}
a.AddrType = REMOTE_STATION_ADDRESS
addrNet := uint16(parseNetUint)
a.AddrNet = &addrNet
a.AddrAddress, err = Xtob(_addr[2 : len(_addr)-1])
if err != nil {
return errors.Wrap(err, "can't parse addr")
}
addrLen := uint8(len(a.AddrAddress))
a.AddrLen = &addrLen
return nil
}
if interface_re.MatchString(addr) {
if _debug != nil {
_debug(" - interface name with optional port")
}
groups := interface_re.FindStringSubmatch(addr)
_interface := groups[1]
_port := groups[2]
if _port != "" {
parseUint, err := strconv.ParseUint(_port, 10, 16)
if err != nil {
return errors.Wrap(err, "can't parse port")
}
port := uint16(parseUint)
a.AddrPort = &port
} else {
port := uint16(47808)
a.AddrPort = &port
}
_ = _interface
_ = _port
panic("implement me")
return nil
}
return errors.New("unrecognized format")
case *AddressTuple[string, uint16]:
uaddr, port := addr.Left, addr.Right
a.AddrPort = &port
var addrstr []byte
if uaddr == "" {
// when ('', n) is passed it is the local host address, but that could be more than one on a multi homed machine,
// the empty string # means "any".
addrstr = make([]byte, 4)
} else {
addrstr = net.ParseIP(uaddr).To4()
}
a.AddrTuple = &AddressTuple[string, uint16]{uaddr, *a.AddrPort}
if _debug != nil {
_debug(" - addrstr: %v", addrstr)
}
ip := ipv4ToUint32(addrstr)
a.AddrIP = &ip
mask := uint32(0xFFFFFFFF)
a.AddrMask = &mask
host := uint32(0)
a.AddrHost = &host
subnet := uint32(0)
a.AddrSubnet = &subnet
a.AddrBroadcastTuple = a.AddrTuple
a.AddrAddress = append(addrstr, Uint16ToPort(*a.AddrPort)...)
length := uint8(6)
a.AddrLen = &length
case *AddressTuple[string, string]:
uaddr, port := addr.Left, addr.Right
portParse, err := strconv.ParseUint(port, 10, 16)
if err != nil {
return errors.Wrap(err, "can't parse port")
}
portInt := uint16(portParse)
a.AddrPort = &portInt
var addrstr []byte
if uaddr == "" {
// when ('', n) is passed it is the local host address, but that could be more than one on a multi homed machine,
// the empty string # means "any".
addrstr = make([]byte, 4)
} else {
addrstr = net.ParseIP(uaddr).To4()
}
a.AddrTuple = &AddressTuple[string, uint16]{uaddr, *a.AddrPort}
if _debug != nil {
_debug(" - addrstr: %r", addrstr)
}
ip := ipv4ToUint32(addrstr)
a.AddrIP = &ip
mask := uint32(0xFFFFFFFF)
a.AddrMask = &mask
host := uint32(0)
a.AddrHost = &host
subnet := uint32(0)
a.AddrSubnet = &subnet
a.AddrBroadcastTuple = a.AddrTuple
a.AddrAddress = append(addrstr, Uint16ToPort(*a.AddrPort)...)
length := uint8(6)
a.AddrLen = &length
case *AddressTuple[int, uint16]:
uaddr, port := addr.Left, addr.Right
a.AddrPort = &port
addrstr := uint32ToIpv4(uint32(uaddr))
a.AddrTuple = &AddressTuple[string, uint16]{addrstr.String(), *a.AddrPort}
if _debug != nil {
_debug(" - addrstr: %r", addrstr)
}
ip := ipv4ToUint32(addrstr)
a.AddrIP = &ip
mask := uint32(0xFFFFFFFF)
a.AddrMask = &mask
host := uint32(0)
a.AddrHost = &host
subnet := uint32(0)
a.AddrSubnet = &subnet
a.AddrBroadcastTuple = a.AddrTuple
a.AddrAddress = append(addrstr, Uint16ToPort(*a.AddrPort)...)
length := uint8(6)
a.AddrLen = &length
default:
return errors.Errorf("integer, string or tuple required (Actual %T)", addr)
}
}
return nil
}
func (a *Address) Equals(other any) bool {
if a == nil && other == nil {
return true
} else if a == nil && other != nil {
return false
}
switch other := other.(type) {
case *Address:
if a == other {
return true
}
thisString := a.String()
otherString := other.String()
equals := thisString == otherString
if !equals {
if _debug != nil {
_debug("Mismatch %v != %v", thisString, otherString)
}
}
return equals
case Address:
thisString := a.String()
otherString := other.String()
equals := thisString == otherString
if !equals {
if _debug != nil {
_debug("Mismatch %v != %v", thisString, otherString)
}
}
return equals
case AddressTuple[string, uint16]:
thisString := a.AddrTuple.String()
otherString := other.String()
equals := thisString == otherString
if !equals {
if _debug != nil {
_debug("Mismatch %v != %v", thisString, otherString)
}
}
return equals
case *AddressTuple[string, uint16]:
thisString := a.AddrTuple.String()
otherString := other.String()
equals := thisString == otherString
if !equals {
if _debug != nil {
_debug("Mismatch %v != %v", thisString, otherString)
}
}
return equals
case AddressTuple[string, int]:
thisString := a.AddrTuple.String()
otherString := other.String()
equals := thisString == otherString
if !equals {
if _debug != nil {
_debug("Mismatch %v != %v", thisString, otherString)
}
}
return equals
case *AddressTuple[string, int]:
thisString := a.AddrTuple.String()
otherString := other.String()
equals := thisString == otherString
if !equals {
if _debug != nil {
_debug("Mismatch %v != %v", thisString, otherString)
}
}
return equals
default:
if _debug != nil {
_debug("Unmapped type comparison %T", other)
}
return false
}
}
func (a *Address) Format(s fmt.State, v rune) {
if a == nil {
_, _ = fmt.Fprint(s, "<nil>")
return
}
switch v {
case 'r':
_, _ = fmt.Fprintf(s, "<%s %s>", a._leafName, a.String())
case 'v', 's':
_, _ = fmt.Fprint(s, a.String())
}
}
func (a *Address) deepCopy() *Address {
if a == nil {
return nil
}
return &Address{
a.AddrType,
CopyPtr(a.AddrNet),
bytes.Clone(a.AddrAddress),
CopyPtr(a.AddrLen),
a.AddrRoute.deepCopy(),
CopyPtr(a.AddrIP),
CopyPtr(a.AddrMask),
CopyPtr(a.AddrHost),
CopyPtr(a.AddrSubnet),
CopyPtr(a.AddrPort),
a.AddrTuple.deepCopy(),
a.AddrBroadcastTuple.deepCopy(),
a._leafName,
}
}
func (a *Address) DeepCopy() any {
return a.deepCopy()
}
func (a *Address) AlternateString() (string, bool) {
if IsDebuggingActive() || true { // TODO: figure out what to do when we want the below string in testing etc...
if a == nil {
return "<nil>", true
}
result := ""
if a.AddrType == NULL_ADDRESS {
result = "Null"
} else if a.AddrType == LOCAL_BROADCAST_ADDRESS {
result = "*"
} else if a.AddrType == LOCAL_STATION_ADDRESS {
if a.AddrLen != nil && *a.AddrLen == 1 {
result += fmt.Sprintf("%v", a.AddrAddress[0])
} else {
port := binary.BigEndian.Uint16(a.AddrAddress[len(a.AddrAddress)-2:])
if len(a.AddrAddress) == 6 && port >= 47808 && port <= 47823 {
var octests = make([]string, 4)
for i, address := range a.AddrAddress[0:4] {
octests[i] = fmt.Sprintf("%d", address)
}
result += fmt.Sprintf("%v", strings.Join(octests, "."))
if port != 47808 {
result += fmt.Sprintf(":%v", port)
}
} else {
result += fmt.Sprintf("0x%x", a.AddrAddress)
}
}
} else if a.AddrType == REMOTE_BROADCAST_ADDRESS {
result = fmt.Sprintf("%d:*", *a.AddrNet)
} else if a.AddrType == REMOTE_STATION_ADDRESS {
result = fmt.Sprintf("%d:", *a.AddrNet)
if a.AddrLen != nil && *a.AddrLen == 1 {
result += fmt.Sprintf("%v", a.AddrAddress[0])
} else {
port := binary.BigEndian.Uint16(a.AddrAddress[len(a.AddrAddress)-2:])
if len(a.AddrAddress) == 6 && port >= 47808 && port <= 47823 {
var octests = make([]string, 4)
for i, address := range a.AddrAddress[0:4] {
octests[i] = fmt.Sprintf("%d", address)
}
result += fmt.Sprintf("%v", strings.Join(octests, "."))
if port != 47808 {
result += fmt.Sprintf(":%v", port)
}
} else {
result += fmt.Sprintf("0x%x", a.AddrAddress)
}
}
} else if a.AddrType == GLOBAL_BROADCAST_ADDRESS {
result = "*:*"
} else {
panic("Unknown address type: " + a.AddrType.String())
}
if a.AddrRoute != nil {
result += fmt.Sprintf("@%s", a.AddrRoute)
}
return result, true
}
return "", false
}