diff --git a/plc4go/internal/bacnetip/ApplicationLayer.go b/plc4go/internal/bacnetip/ApplicationLayer.go index 64997f075ab..09308feeb46 100644 --- a/plc4go/internal/bacnetip/ApplicationLayer.go +++ b/plc4go/internal/bacnetip/ApplicationLayer.go @@ -1592,21 +1592,17 @@ type StateMachineAccessPoint struct { dccEnableDisable readWriteModel.BACnetConfirmedServiceRequestDeviceCommunicationControlEnableDisable applicationTimeout uint + // pass through arguments + argSapID *int + argCid *int + log zerolog.Logger } -func NewStateMachineAccessPoint(localLog zerolog.Logger, localDevice *LocalDeviceObject, deviceInfoCache *DeviceInfoCache, sapID *int, cid *int) (*StateMachineAccessPoint, error) { - localLog.Debug(). - Stringer("localDevice", localDevice). - Stringer("deviceInfoCache", deviceInfoCache). - Interface("sapID", sapID). - Interface("cid", cid). - Msg("NewStateMachineAccessPoint") - +func NewStateMachineAccessPoint(localLog zerolog.Logger, localDevice *LocalDeviceObject, opts ...func(*StateMachineAccessPoint)) (*StateMachineAccessPoint, error) { s := &StateMachineAccessPoint{ // save a reference to the device information cache - localDevice: localDevice, - deviceInfoCache: deviceInfoCache, + localDevice: localDevice, // client settings nextInvokeId: 1, @@ -1635,20 +1631,50 @@ func NewStateMachineAccessPoint(localLog zerolog.Logger, localDevice *LocalDevic log: localLog, } + for _, opt := range opts { + opt(s) + } + localLog.Debug(). + Stringer("localDevice", localDevice). + Stringer("deviceInfoCache", s.deviceInfoCache). + Interface("sapID", s.argSapID). + Interface("cid", s.argCid). + Msg("NewStateMachineAccessPoint") // basic initialization - client, err := NewClient(localLog, cid, s) + client, err := NewClient(localLog, s, func(client *Client) { + client.clientID = s.argCid + }) if err != nil { - return nil, errors.Wrapf(err, "error building client for %d", cid) + return nil, errors.Wrapf(err, "error building client for %d", s.argCid) } s.Client = client - serviceAccessPoint, err := NewServiceAccessPoint(localLog, sapID, s) + serviceAccessPoint, err := NewServiceAccessPoint(localLog, s, func(point *ServiceAccessPoint) { + point.serviceID = s.argSapID + }) if err != nil { - return nil, errors.Wrapf(err, "error building serviceAccessPoint for %d", sapID) + return nil, errors.Wrapf(err, "error building serviceAccessPoint for %d", s.argSapID) } s.ServiceAccessPoint = serviceAccessPoint return s, nil } +func WithStateMachineAccessPointDeviceInfoCache(deviceInfoCache *DeviceInfoCache) func(*StateMachineAccessPoint) { + return func(s *StateMachineAccessPoint) { + s.deviceInfoCache = deviceInfoCache + } +} +func WithStateMachineAccessPointSapID(sapID int) func(*StateMachineAccessPoint) { + return func(s *StateMachineAccessPoint) { + s.argSapID = &sapID + } +} + +func WithStateMachineAccessPointCid(cid int) func(*StateMachineAccessPoint) { + return func(s *StateMachineAccessPoint) { + s.argCid = &cid + } +} + func (s *StateMachineAccessPoint) String() string { return fmt.Sprintf("StateMachineAccessPoint(TBD...)") // TODO: fill some info here } @@ -2008,19 +2034,30 @@ type ApplicationServiceAccessPoint struct { *ApplicationServiceElement *ServiceAccessPoint + // Pass through args + argAseID *int + argSapID *int + log zerolog.Logger } -func NewApplicationServiceAccessPoint(localLog zerolog.Logger, aseID *int, sapID *int) (*ApplicationServiceAccessPoint, error) { +func NewApplicationServiceAccessPoint(localLog zerolog.Logger, opts ...func(*ApplicationServiceAccessPoint)) (*ApplicationServiceAccessPoint, error) { a := &ApplicationServiceAccessPoint{ log: localLog, } - applicationServiceElement, err := NewApplicationServiceElement(localLog, aseID, a) + for _, opt := range opts { + opt(a) + } + applicationServiceElement, err := NewApplicationServiceElement(localLog, a, func(ase *ApplicationServiceElement) { + ase.elementID = a.argAseID + }) if err != nil { return nil, errors.Wrap(err, "error creating application service element") } a.ApplicationServiceElement = applicationServiceElement - serviceAccessPoint, err := NewServiceAccessPoint(localLog, sapID, a) + serviceAccessPoint, err := NewServiceAccessPoint(localLog, a, func(sap *ServiceAccessPoint) { + sap.serviceID = a.argSapID + }) if err != nil { return nil, errors.Wrap(err, "error creating service access point") } @@ -2028,6 +2065,18 @@ func NewApplicationServiceAccessPoint(localLog zerolog.Logger, aseID *int, sapID return a, nil } +func WithApplicationServiceAccessPointAseID(aseID int) func(*ApplicationServiceAccessPoint) { + return func(a *ApplicationServiceAccessPoint) { + a.argAseID = &aseID + } +} + +func WithApplicationServiceAccessPointSapID(sapID int) func(*ApplicationServiceAccessPoint) { + return func(a *ApplicationServiceAccessPoint) { + a.argSapID = &sapID + } +} + // TODO: big WIP func (a *ApplicationServiceAccessPoint) Indication(args Args, kwargs KWArgs) error { a.log.Debug().Stringer("Args", args).Stringer("KWArgs", kwargs).Msg("Indication") diff --git a/plc4go/internal/bacnetip/ApplicationModule.go b/plc4go/internal/bacnetip/ApplicationModule.go index d63b8c8ebe9..ad604bfdfeb 100644 --- a/plc4go/internal/bacnetip/ApplicationModule.go +++ b/plc4go/internal/bacnetip/ApplicationModule.go @@ -219,20 +219,28 @@ type Application struct { _startupDisabled bool + // pass through args + argAseID *int + log zerolog.Logger } -func NewApplication(localLog zerolog.Logger, localDevice *LocalDeviceObject, deviceInfoCache *DeviceInfoCache, aseID *int) (*Application, error) { - localLog.Debug(). - Interface("localDevice", localDevice). - Interface("deviceInfoCache", deviceInfoCache). - Interface("aseID", aseID). - Msg("NewApplication") +func NewApplication(localLog zerolog.Logger, localDevice *LocalDeviceObject, opts ...func(*Application)) (*Application, error) { a := &Application{ log: localLog, } + for _, opt := range opts { + opt(a) + } + localLog.Debug(). + Interface("localDevice", localDevice). + Interface("deviceInfoCache", a.deviceInfoCache). + Interface("aseID", a.argAseID). + Msg("NewApplication") var err error - a.ApplicationServiceElement, err = NewApplicationServiceElement(localLog, aseID, a) + a.ApplicationServiceElement, err = NewApplicationServiceElement(localLog, a, func(element *ApplicationServiceElement) { + element.elementID = a.argAseID + }) if err != nil { return nil, err } @@ -254,10 +262,9 @@ func NewApplication(localLog zerolog.Logger, localDevice *LocalDeviceObject, dev } // use the provided cache or make a default one - if deviceInfoCache == nil { - deviceInfoCache = NewDeviceInfoCache(localLog) + if a.deviceInfoCache == nil { + a.deviceInfoCache = NewDeviceInfoCache(localLog) } - a.deviceInfoCache = deviceInfoCache // controllers for managing confirmed requests as a client a.controllers = map[string]any{} @@ -275,6 +282,22 @@ func NewApplication(localLog zerolog.Logger, localDevice *LocalDeviceObject, dev return a, nil } +func WithApplicationAseID(aseID int) func(*Application) { + return func(a *Application) { + a.argAseID = &aseID + } +} + +func WithApplicationDeviceInfoCache(deviceInfoCache *DeviceInfoCache) func(*Application) { + return func(a *Application) { + a.deviceInfoCache = deviceInfoCache + } +} + +func (a *Application) GetDeviceInfoCache() *DeviceInfoCache { + return a.deviceInfoCache +} + func (a *Application) String() string { return fmt.Sprintf("Application(TBD...)") // TODO: fill some info here } @@ -423,33 +446,55 @@ func (a *Application) Indication(args Args, kwargs KWArgs) error { return nil } -// TODO: finish type ApplicationIOController struct { *IOController *Application + queueByAddress map[string]SieveQueue + // pass through args + argDeviceInfoCache *DeviceInfoCache + argAseID *int + log zerolog.Logger } -func NewApplicationIOController(localLog zerolog.Logger, localDevice *LocalDeviceObject, deviceInfoCache *DeviceInfoCache, aseID *int) (*ApplicationIOController, error) { +func NewApplicationIOController(localLog zerolog.Logger, localDevice *LocalDeviceObject, opts ...func(controller *ApplicationIOController)) (*ApplicationIOController, error) { a := &ApplicationIOController{ // queues for each address queueByAddress: make(map[string]SieveQueue), log: localLog, } + for _, opt := range opts { + opt(a) + } var err error a.IOController, err = NewIOController(localLog, "", a) if err != nil { return nil, errors.Wrap(err, "error creating io controller") } - a.Application, err = NewApplication(localLog, localDevice, deviceInfoCache, aseID) + a.Application, err = NewApplication(localLog, localDevice, func(application *Application) { + application.deviceInfoCache = a.argDeviceInfoCache + application.argAseID = a.argAseID + }) if err != nil { return nil, errors.Wrap(err, "error creating application") } return a, nil } +func WithApplicationIOControllerDeviceInfoCache(deviceInfoCache *DeviceInfoCache) func(*ApplicationIOController) { + return func(a *ApplicationIOController) { + a.argDeviceInfoCache = deviceInfoCache + } +} + +func WithApplicationIOControllerAseID(aseID *int) func(*ApplicationIOController) { + return func(a *ApplicationIOController) { + a.argAseID = aseID + } +} + func (a *ApplicationIOController) ProcessIO(iocb _IOCB) error { a.log.Debug().Stringer("iocb", iocb).Msg("ProcessIO") @@ -573,7 +618,7 @@ func NewBIPSimpleApplication(localLog zerolog.Logger, localDevice *LocalDeviceOb log: localLog, } var err error - b.ApplicationIOController, err = NewApplicationIOController(localLog, localDevice, deviceInfoCache, aseID) + b.ApplicationIOController, err = NewApplicationIOController(localLog, localDevice, WithApplicationIOControllerDeviceInfoCache(deviceInfoCache), WithApplicationIOControllerAseID(aseID)) if err != nil { return nil, errors.Wrap(err, "error creating io controller") } @@ -589,13 +634,13 @@ func NewBIPSimpleApplication(localLog zerolog.Logger, localDevice *LocalDeviceOb b.localAddress = localAddress // include a application decoder - b.asap, err = NewApplicationServiceAccessPoint(localLog, nil, nil) + b.asap, err = NewApplicationServiceAccessPoint(localLog) if err != nil { return nil, errors.Wrap(err, "error creating application service access point") } // pass the device object to the state machine access point, so it can know if it should support segmentation - b.smap, err = NewStateMachineAccessPoint(localLog, localDevice, deviceInfoCache, nil, nil) + b.smap, err = NewStateMachineAccessPoint(localLog, localDevice, WithStateMachineAccessPointDeviceInfoCache(deviceInfoCache)) if err != nil { return nil, errors.Wrap(err, "error creating state machine access point") } @@ -604,7 +649,7 @@ func NewBIPSimpleApplication(localLog zerolog.Logger, localDevice *LocalDeviceOb // Note: deviceInfoCache already passed above, so we don't need to do it again here // a network service access point will be needed - b.nsap, err = NewNetworkServiceAccessPoint(localLog, nil, nil, nil) + b.nsap, err = NewNetworkServiceAccessPoint(localLog) if err != nil { return nil, errors.Wrap(err, "error creating network service access point") } @@ -624,11 +669,11 @@ func NewBIPSimpleApplication(localLog zerolog.Logger, localDevice *LocalDeviceOb } // create a generic BIP stack, bound to the Annex J server on the UDP multiplexer - b.bip, err = NewBIPSimple(localLog, nil, nil, nil) + b.bip, err = NewBIPSimple(localLog) if err != nil { return nil, errors.Wrap(err, "error creating new bip") } - b.annexj, err = NewAnnexJCodec(localLog, nil, nil) + b.annexj, err = NewAnnexJCodec(localLog) if err != nil { return nil, errors.Wrap(err, "error creating new annex j codec") } @@ -643,7 +688,7 @@ func NewBIPSimpleApplication(localLog zerolog.Logger, localDevice *LocalDeviceOb } // bind the BIP stack to the network, no network number - if err := b.nsap.bind(b.bip, nil, &b.localAddress); err != nil { + if err := b.nsap.Bind(b.bip, nil, &b.localAddress); err != nil { return nil, err } @@ -678,7 +723,7 @@ func NewBIPForeignApplication(localLog zerolog.Logger, localDevice *LocalDeviceO log: localLog, } var err error - b.ApplicationIOController, err = NewApplicationIOController(localLog, localDevice, deviceInfoCache, aseID) + b.ApplicationIOController, err = NewApplicationIOController(localLog, localDevice, WithApplicationIOControllerDeviceInfoCache(deviceInfoCache), WithApplicationIOControllerAseID(aseID)) if err != nil { return nil, errors.Wrap(err, "error creating io controller") } @@ -694,13 +739,13 @@ func NewBIPForeignApplication(localLog zerolog.Logger, localDevice *LocalDeviceO b.localAddress = localAddress // include a application decoder - b.asap, err = NewApplicationServiceAccessPoint(localLog, nil, nil) + b.asap, err = NewApplicationServiceAccessPoint(localLog) if err != nil { return nil, errors.Wrap(err, "error creating application service access point") } // pass the device object to the state machine access point, so it can know if it should support segmentation - b.smap, err = NewStateMachineAccessPoint(localLog, localDevice, deviceInfoCache, nil, nil) + b.smap, err = NewStateMachineAccessPoint(localLog, localDevice, WithStateMachineAccessPointDeviceInfoCache(deviceInfoCache)) if err != nil { return nil, errors.Wrap(err, "error creating state machine access point") } @@ -709,7 +754,7 @@ func NewBIPForeignApplication(localLog zerolog.Logger, localDevice *LocalDeviceO // Note: deviceInfoCache already passed above, so we don't need to do it again here // a network service access point will be needed - b.nsap, err = NewNetworkServiceAccessPoint(localLog, nil, nil, nil) + b.nsap, err = NewNetworkServiceAccessPoint(localLog) if err != nil { return nil, errors.Wrap(err, "error creating network service access point") } @@ -729,11 +774,11 @@ func NewBIPForeignApplication(localLog zerolog.Logger, localDevice *LocalDeviceO } // create a generic BIP stack, bound to the Annex J server on the UDP multiplexer - b.bip, err = NewBIPForeign(localLog, bbmdAddress, bbmdTTL, nil, nil, nil) + b.bip, err = NewBIPForeign(localLog, bbmdAddress, bbmdTTL) if err != nil { return nil, errors.Wrap(err, "error creating new bip") } - b.annexj, err = NewAnnexJCodec(localLog, nil, nil) + b.annexj, err = NewAnnexJCodec(localLog) if err != nil { return nil, errors.Wrap(err, "error creating new annex j codec") } @@ -748,7 +793,7 @@ func NewBIPForeignApplication(localLog zerolog.Logger, localDevice *LocalDeviceO } // bind the BIP stack to the network, no network number - if err := b.nsap.bind(b.bip, nil, &b.localAddress); err != nil { + if err := b.nsap.Bind(b.bip, nil, &b.localAddress); err != nil { return nil, err } @@ -786,7 +831,7 @@ func NewBIPNetworkApplication(localLog zerolog.Logger, localAddress Address, bbm n.localAddress = localAddress // a network service access point will be needed - n.nsap, err = NewNetworkServiceAccessPoint(localLog, nil, nil, nil) + n.nsap, err = NewNetworkServiceAccessPoint(localLog) if err != nil { return nil, errors.Wrap(err, "error creating network service access point") } @@ -799,17 +844,17 @@ func NewBIPNetworkApplication(localLog zerolog.Logger, localAddress Address, bbm // create a generic BIP stack, bound to the Annex J server // on the UDP multiplexer if bbmdAddress == nil && bbmdTTL == nil { - n.bip, err = NewBIPSimple(localLog, nil, nil, nil) + n.bip, err = NewBIPSimple(localLog) if err != nil { return nil, errors.Wrap(err, "error creating BIPSimple") } } else { - n.bip, err = NewBIPForeign(localLog, bbmdAddress, bbmdTTL, nil, nil, nil) + n.bip, err = NewBIPForeign(localLog, bbmdAddress, bbmdTTL) if err != nil { return nil, errors.Wrap(err, "error creating BIPForeign") } } - n.annexj, err = NewAnnexJCodec(localLog, nil, nil) + n.annexj, err = NewAnnexJCodec(localLog) if err != nil { return nil, errors.Wrap(err, "error creating new annex j codec") } @@ -824,7 +869,7 @@ func NewBIPNetworkApplication(localLog zerolog.Logger, localAddress Address, bbm } // bind the BIP stack to the network, no network number - if err := n.nsap.bind(n.bip.(_Server), nil, &n.localAddress); err != nil { + if err := n.nsap.Bind(n.bip.(_Server), nil, &n.localAddress); err != nil { return nil, err } diff --git a/plc4go/internal/bacnetip/BACnetVirtualLinkLayerService.go b/plc4go/internal/bacnetip/BACnetVirtualLinkLayerService.go index 4c161f819f6..25cdbbec49f 100644 --- a/plc4go/internal/bacnetip/BACnetVirtualLinkLayerService.go +++ b/plc4go/internal/bacnetip/BACnetVirtualLinkLayerService.go @@ -39,7 +39,7 @@ func _New_MultiplexClient(localLog zerolog.Logger, multiplexer *UDPMultiplexer) multiplexer: multiplexer, } var err error - m.Client, err = NewClient(localLog, nil, m) + m.Client, err = NewClient(localLog, m) if err != nil { return nil, errors.Wrap(err, "error creating client") } @@ -60,7 +60,7 @@ func _New_MultiplexServer(localLog zerolog.Logger, multiplexer *UDPMultiplexer) multiplexer: multiplexer, } var err error - m.Server, err = NewServer(localLog, nil, m) + m.Server, err = NewServer(localLog, m) if err != nil { return nil, errors.Wrap(err, "error creating server") } @@ -132,7 +132,7 @@ func NewUDPMultiplexer(localLog zerolog.Logger, address any, noBroadcast bool) ( Stringer("address", u.address). Stringer("addrTuple", u.addrTuple). Stringer("addrBroadcastTuple", u.addrBroadcastTuple). - Bool("route_aware", settings.RouteAware). + Bool("route_aware", Settings.RouteAware). Msg("working with") // create and bind direct address @@ -271,23 +271,34 @@ type AnnexJCodec struct { *Client *Server + // pass through args + argCid *int + argSid *int + log zerolog.Logger } -func NewAnnexJCodec(localLog zerolog.Logger, cid *int, sid *int) (*AnnexJCodec, error) { - localLog.Debug(). - Interface("cid", cid). - Interface("sid", sid). - Msg("NewAnnexJCodec") +func NewAnnexJCodec(localLog zerolog.Logger, opts ...func(*AnnexJCodec)) (*AnnexJCodec, error) { a := &AnnexJCodec{ log: localLog, } - client, err := NewClient(localLog, cid, a) + for _, opt := range opts { + opt(a) + } + localLog.Debug(). + Interface("cid", a.argCid). + Interface("sid", a.argSid). + Msg("NewAnnexJCodec") + client, err := NewClient(localLog, a, func(client *Client) { + client.clientID = a.argSid + }) if err != nil { return nil, errors.Wrap(err, "error creating client") } a.Client = client - server, err := NewServer(localLog, sid, a) + server, err := NewServer(localLog, a, func(server *Server) { + server.serverID = a.argSid + }) if err != nil { return nil, errors.Wrap(err, "error creating server") } @@ -295,6 +306,17 @@ func NewAnnexJCodec(localLog zerolog.Logger, cid *int, sid *int) (*AnnexJCodec, return a, nil } +func WithAnnexJCodecCid(cid int) func(*AnnexJCodec) { + return func(a *AnnexJCodec) { + a.argCid = &cid + } +} +func WithAnnexJCodecSid(sid int) func(*AnnexJCodec) { + return func(a *AnnexJCodec) { + a.argSid = &sid + } +} + func (b *AnnexJCodec) String() string { return fmt.Sprintf("AnnexJCodec(client: %s, server: %s)", b.Client, b.Server) } @@ -318,18 +340,26 @@ type BIPSAP struct { *ServiceAccessPoint rootStruct _BIPSAP + // pass through args + argSapID *int + log zerolog.Logger } -func NewBIPSAP(localLog zerolog.Logger, sapID *int, rootStruct _BIPSAP) (*BIPSAP, error) { - localLog.Debug(). - Interface("sapID", sapID). - Interface("rootStruct", rootStruct). - Msg("NewBIPSAP") +func NewBIPSAP(localLog zerolog.Logger, rootStruct _BIPSAP, opts ...func(*BIPSAP)) (*BIPSAP, error) { b := &BIPSAP{ log: localLog, } - serviceAccessPoint, err := NewServiceAccessPoint(localLog, sapID, rootStruct) + for _, opt := range opts { + opt(b) + } + localLog.Debug(). + Interface("sapID", b.argSapID). + Interface("rootStruct", rootStruct). + Msg("NewBIPSAP") + serviceAccessPoint, err := NewServiceAccessPoint(localLog, rootStruct, func(point *ServiceAccessPoint) { + point.serviceID = b.argSapID + }) if err != nil { return nil, errors.Wrap(err, "Error creating service access point") } @@ -338,6 +368,12 @@ func NewBIPSAP(localLog zerolog.Logger, sapID *int, rootStruct _BIPSAP) (*BIPSAP return b, nil } +func WithBIPSAPSapID(sapID int) func(*BIPSAP) { + return func(point *BIPSAP) { + point.argSapID = &sapID + } +} + func (b *BIPSAP) String() string { return fmt.Sprintf("BIPSAP(SAP: %s)", b.ServiceAccessPoint) } @@ -359,27 +395,43 @@ type BIPSimple struct { *Client *Server + // pass through args + argSapID *int + argCid *int + argSid *int + log zerolog.Logger } -func NewBIPSimple(localLog zerolog.Logger, sapID *int, cid *int, sid *int) (*BIPSimple, error) { +func NewBIPSimple(localLog zerolog.Logger, opts ...func(simple *BIPSimple)) (*BIPSimple, error) { + b := &BIPSimple{ + log: localLog, + } + for _, opt := range opts { + opt(b) + } localLog.Debug(). - Interface("sapID", sapID). - Interface("cid", cid). - Interface("sid", sid). + Interface("sapID", b.argSapID). + Interface("cid", b.argCid). + Interface("sid", b.argSid). Msg("NewBIPSimple") - b := &BIPSimple{} - bipsap, err := NewBIPSAP(localLog, sapID, b) + bipsap, err := NewBIPSAP(localLog, b, func(bipsap *BIPSAP) { + bipsap.argSapID = b.argSapID + }) if err != nil { return nil, errors.Wrap(err, "error creating bisap") } b.BIPSAP = bipsap - client, err := NewClient(localLog, cid, b) + client, err := NewClient(localLog, b, func(client *Client) { + client.clientID = b.argCid + }) if err != nil { return nil, errors.Wrap(err, "error creating client") } b.Client = client - server, err := NewServer(localLog, sid, b) + server, err := NewServer(localLog, b, func(server *Server) { + server.serverID = b.argSid + }) if err != nil { return nil, errors.Wrap(err, "error creating server") } @@ -519,36 +571,51 @@ type BIPForeign struct { *Client *Server *OneShotTask + registrationStatus int bbmdAddress *Address bbmdTimeToLive *int registrationTimeoutTask *OneShotFunctionTask + // pass through args + argSapID *int + argCid *int + argSid *int + log zerolog.Logger } -func NewBIPForeign(localLog zerolog.Logger, addr *Address, ttl *int, sapID *int, cid *int, sid *int) (*BIPForeign, error) { +func NewBIPForeign(localLog zerolog.Logger, addr *Address, ttl *int, opts ...func(*BIPForeign)) (*BIPForeign, error) { + b := &BIPForeign{ + log: localLog, + } + for _, opt := range opts { + opt(b) + } localLog.Debug(). Stringer("addrs", addr). Interface("ttls", ttl). - Interface("sapIDs", sapID). - Interface("cids", cid). - Interface("sids", sid). + Interface("sapID", b.argSapID). + Interface("cid", b.argCid). + Interface("sid", b.argSid). Msg("NewBIPForeign") - b := &BIPForeign{ - log: localLog, - } - bipsap, err := NewBIPSAP(localLog, sapID, b) + bipsap, err := NewBIPSAP(localLog, b, func(bipsap *BIPSAP) { + bipsap.argSapID = b.argSapID + }) if err != nil { return nil, errors.Wrap(err, "error creating bisap") } b.BIPSAP = bipsap - client, err := NewClient(localLog, cid, b) + client, err := NewClient(localLog, b, func(client *Client) { + client.clientID = b.argCid + }) if err != nil { return nil, errors.Wrap(err, "error creating client") } b.Client = client - server, err := NewServer(localLog, sid, b) + server, err := NewServer(localLog, b, func(server *Server) { + server.serverID = b.argSid + }) if err != nil { return nil, errors.Wrap(err, "error creating server") } diff --git a/plc4go/internal/bacnetip/Capability.go b/plc4go/internal/bacnetip/Capability.go index 56e9f41b30f..438e63c15f1 100644 --- a/plc4go/internal/bacnetip/Capability.go +++ b/plc4go/internal/bacnetip/Capability.go @@ -31,7 +31,21 @@ func NewCapability() *Capability { type Collector struct { } +func NewCollector() *Collector { + return &Collector{} +} + +func (c *Collector) searchCapability() { + // TODO: implement + return +} + func (c *Collector) CapabilityFunctions(fn string) []func(args Args, kwargs KWArgs) error { // TODO: implement return nil } + +func (c *Collector) AddCapability(cls any) { + // TODO: implement + return +} diff --git a/plc4go/internal/bacnetip/CommunicationsModule.go b/plc4go/internal/bacnetip/CommunicationsModule.go index 83532dde3b0..2a93f7b44ec 100644 --- a/plc4go/internal/bacnetip/CommunicationsModule.go +++ b/plc4go/internal/bacnetip/CommunicationsModule.go @@ -88,21 +88,24 @@ type Client struct { log zerolog.Logger } -func NewClient(localLog zerolog.Logger, cid *int, rootStruct _Client) (*Client, error) { +func NewClient(localLog zerolog.Logger, rootStruct _Client, opts ...func(*Client)) (*Client, error) { c := &Client{ - clientID: cid, - log: localLog, + log: localLog, } - if cid != nil { - if _, ok := clientMap[*cid]; ok { - return nil, errors.Errorf("already a client %d", *cid) + for _, opt := range opts { + opt(c) + } + if c.clientID != nil { + cid := *c.clientID + if _, ok := clientMap[cid]; ok { + return nil, errors.Errorf("already a client %d", cid) } - clientMap[*cid] = c + clientMap[cid] = c // automatically bind - if server, ok := serverMap[*cid]; ok { + if server, ok := serverMap[cid]; ok { if server.serverPeer != nil { - return nil, errors.Errorf("server %d already bound", *cid) + return nil, errors.Errorf("server %d already bound", cid) } // Note: we need to pass the rootStruct (which should contain c as delegate) here @@ -114,6 +117,12 @@ func NewClient(localLog zerolog.Logger, cid *int, rootStruct _Client) (*Client, return c, nil } +func WithClientCid(cid int) func(*Client) { + return func(c *Client) { + c.clientID = &cid + } +} + func (c *Client) Request(args Args, kwargs KWArgs) error { c.log.Debug().Stringer("Args", args).Stringer("KWArgs", kwargs).Msg("Request") @@ -160,21 +169,24 @@ type Server struct { log zerolog.Logger } -func NewServer(localLog zerolog.Logger, sid *int, rootStruct _Server) (*Server, error) { +func NewServer(localLog zerolog.Logger, rootStruct _Server, opts ...func(server *Server)) (*Server, error) { s := &Server{ - serverID: sid, - log: localLog, + log: localLog, + } + for _, opt := range opts { + opt(s) } - if sid != nil { - if _, ok := serverMap[*sid]; ok { - return nil, errors.Errorf("already a server %d", *sid) + if s.serverID != nil { + sid := *s.serverID + if _, ok := serverMap[sid]; ok { + return nil, errors.Errorf("already a server %d", sid) } - serverMap[*sid] = s + serverMap[sid] = s // automatically bind - if client, ok := clientMap[*sid]; ok { + if client, ok := clientMap[sid]; ok { if client.clientPeer != nil { - return nil, errors.Errorf("client %d already bound", *sid) + return nil, errors.Errorf("client %d already bound", sid) } // Note: we need to pass the rootStruct (which should contain s as delegate) here @@ -186,9 +198,16 @@ func NewServer(localLog zerolog.Logger, sid *int, rootStruct _Server) (*Server, return s, nil } +func WithServerSID(sid int) func(*Server) { + return func(server *Server) { + server.serverID = &sid + } +} + func (s *Server) Indication(Args, KWArgs) error { panic("this should be implemented by outer struct") } + func (s *Server) Response(args Args, kwargs KWArgs) error { s.log.Debug().Stringer("Args", args).Stringer("KWArgs", kwargs).Msg("Response") @@ -230,20 +249,24 @@ type ServiceAccessPoint struct { log zerolog.Logger } -func NewServiceAccessPoint(localLog zerolog.Logger, sapID *int, rootStruct _ServiceAccessPoint) (*ServiceAccessPoint, error) { +func NewServiceAccessPoint(localLog zerolog.Logger, rootStruct _ServiceAccessPoint, opts ...func(point *ServiceAccessPoint)) (*ServiceAccessPoint, error) { s := &ServiceAccessPoint{ - serviceID: sapID, + log: localLog, } - if sapID != nil { - if _, ok := serviceMap[*sapID]; ok { - return nil, errors.Errorf("already a server %d", *sapID) + for _, opt := range opts { + opt(s) + } + if s.serviceID != nil { + sapID := *s.serviceID + if _, ok := serviceMap[sapID]; ok { + return nil, errors.Errorf("already a server %d", sapID) } - serviceMap[*sapID] = s + serviceMap[sapID] = s // automatically bind - if element, ok := elementMap[*sapID]; ok { + if element, ok := elementMap[sapID]; ok { if element.elementService != nil { - return nil, errors.Errorf("application service element %d already bound", *sapID) + return nil, errors.Errorf("application service element %d already bound", sapID) } // Note: we need to pass the rootStruct (which should contain s as delegate) here @@ -255,6 +278,12 @@ func NewServiceAccessPoint(localLog zerolog.Logger, sapID *int, rootStruct _Serv return s, nil } +func WithServiceAccessPointSapID(sapID int) func(*ServiceAccessPoint) { + return func(s *ServiceAccessPoint) { + s.serviceID = &sapID + } +} + func (s *ServiceAccessPoint) String() string { serviceID := "-" if s.serviceID != nil { @@ -309,21 +338,25 @@ type ApplicationServiceElement struct { log zerolog.Logger } -func NewApplicationServiceElement(localLog zerolog.Logger, aseID *int, rootStruct _ApplicationServiceElement) (*ApplicationServiceElement, error) { +func NewApplicationServiceElement(localLog zerolog.Logger, rootStruct _ApplicationServiceElement, opts ...func(*ApplicationServiceElement)) (*ApplicationServiceElement, error) { a := &ApplicationServiceElement{ - elementID: aseID, + log: localLog, + } + for _, opt := range opts { + opt(a) } - if aseID != nil { - if _, ok := elementMap[*aseID]; ok { - return nil, errors.Errorf("already an application service element %d", *aseID) + if a.elementID != nil { + aseID := *a.elementID + if _, ok := elementMap[aseID]; ok { + return nil, errors.Errorf("already an application service element %d", aseID) } - elementMap[*aseID] = a + elementMap[aseID] = a // automatically bind - if service, ok := serviceMap[*aseID]; ok { + if service, ok := serviceMap[aseID]; ok { if service.serviceElement != nil { - return nil, errors.Errorf("service access point %d already bound", *aseID) + return nil, errors.Errorf("service access point %d already bound", aseID) } // Note: we need to pass the rootStruct (which should contain a as delegate) here @@ -335,6 +368,12 @@ func NewApplicationServiceElement(localLog zerolog.Logger, aseID *int, rootStruc return a, nil } +func WithApplicationServiceElementAseID(aseID int) func(*ApplicationServiceElement) { + return func(s *ApplicationServiceElement) { + s.elementID = &aseID + } +} + func (a *ApplicationServiceElement) Request(args Args, kwargs KWArgs) error { a.log.Debug().Stringer("Args", args).Stringer("KWArgs", kwargs).Msg("Request") diff --git a/plc4go/internal/bacnetip/Device.go b/plc4go/internal/bacnetip/Device.go index 4c497fa2cdd..86b9b5014fe 100644 --- a/plc4go/internal/bacnetip/Device.go +++ b/plc4go/internal/bacnetip/Device.go @@ -182,11 +182,16 @@ func ObjectIdentifierStringToTuple(objectIdentifier string) (objectType uint16, if len(split) != 2 { panic("broken object identifier") } - parsedObjectType, err := strconv.Atoi(split[0]) - if err != nil { - panic(err) + bacnetObjectType, ok := model.BACnetObjectTypeByName(strings.ToUpper(split[0])) + if ok { + objectType = uint16(bacnetObjectType) + } else { + parsedObjectType, err := strconv.Atoi(split[0]) + if err != nil { + panic(err) + } + objectType = uint16(parsedObjectType) } - objectType = uint16(parsedObjectType) parsedInstance, err := strconv.Atoi(split[1]) if err != nil { panic(err) diff --git a/plc4go/internal/bacnetip/NetworkService.go b/plc4go/internal/bacnetip/NetworkService.go index 6660426adc5..a033dbcdbfb 100644 --- a/plc4go/internal/bacnetip/NetworkService.go +++ b/plc4go/internal/bacnetip/NetworkService.go @@ -112,10 +112,13 @@ type NetworkAdapter struct { adapterAddr *Address adapterNetConfigured *int + // pass through args + argCid *int + log zerolog.Logger } -func NewNetworkAdapter(localLog zerolog.Logger, sap *NetworkServiceAccessPoint, net *uint16, addr *Address, cid *int) (*NetworkAdapter, error) { +func NewNetworkAdapter(localLog zerolog.Logger, sap *NetworkServiceAccessPoint, net *uint16, addr *Address, opts ...func(*NetworkAdapter)) (*NetworkAdapter, error) { n := &NetworkAdapter{ adapterSAP: sap, adapterNet: net, @@ -123,8 +126,13 @@ func NewNetworkAdapter(localLog zerolog.Logger, sap *NetworkServiceAccessPoint, log: localLog, } + for _, opt := range opts { + opt(n) + } var err error - n.Client, err = NewClient(localLog, cid, n) + n.Client, err = NewClient(localLog, n, func(client *Client) { + client.clientID = n.argCid + }) if err != nil { return nil, errors.Wrap(err, "error creating client") } @@ -136,6 +144,12 @@ func NewNetworkAdapter(localLog zerolog.Logger, sap *NetworkServiceAccessPoint, return n, nil } +func WithNetworkAdapterCid(cid int) func(*NetworkAdapter) { + return func(na *NetworkAdapter) { + na.argCid = &cid + } +} + // Confirmation Decode upstream PDUs and pass them up to the service access point. func (n *NetworkAdapter) Confirmation(args Args, kwargs KWArgs) error { n.log.Debug(). @@ -172,19 +186,30 @@ type NetworkServiceAccessPoint struct { pendingNets map[*uint16][]PDU localAdapter *NetworkAdapter + // pass through args + argSapID *int + argSid *int + log zerolog.Logger } -func NewNetworkServiceAccessPoint(localLog zerolog.Logger, routerInfoCache *RouterInfoCache, sapID *int, sid *int) (*NetworkServiceAccessPoint, error) { +func NewNetworkServiceAccessPoint(localLog zerolog.Logger, opts ...func(*NetworkServiceAccessPoint)) (*NetworkServiceAccessPoint, error) { n := &NetworkServiceAccessPoint{ log: localLog, } + for _, opt := range opts { + opt(n) + } var err error - n.ServiceAccessPoint, err = NewServiceAccessPoint(localLog, sapID, n) + n.ServiceAccessPoint, err = NewServiceAccessPoint(localLog, n, func(point *ServiceAccessPoint) { + point.serviceID = n.argSapID + }) if err != nil { return nil, errors.Wrap(err, "error creating network service access point") } - n.Server, err = NewServer(localLog, sid, n) + n.Server, err = NewServer(localLog, n, func(server *Server) { + server.serverID = n.argSid + }) if err != nil { return nil, errors.Wrap(err, "error creating server") } @@ -193,10 +218,9 @@ func NewNetworkServiceAccessPoint(localLog zerolog.Logger, routerInfoCache *Rout n.adapters = make(map[*uint16]*NetworkAdapter) // use the provided cache or make a default one - if routerInfoCache == nil { - routerInfoCache = NewRouterInfoCache(localLog) + if n.routerInfoCache == nil { + n.routerInfoCache = NewRouterInfoCache(localLog) } - n.routerInfoCache = routerInfoCache // map to a list of application layer packets waiting for a path n.pendingNets = make(map[*uint16][]PDU) @@ -204,12 +228,30 @@ func NewNetworkServiceAccessPoint(localLog zerolog.Logger, routerInfoCache *Rout return n, nil } +func WithNetworkServiceAccessPointRouterInfoCache(routerInfoCache *RouterInfoCache) func(*NetworkServiceAccessPoint) { + return func(n *NetworkServiceAccessPoint) { + n.routerInfoCache = routerInfoCache + } +} + +func WithNetworkServiceAccessPointRouterSapID(sapID int) func(*NetworkServiceAccessPoint) { + return func(n *NetworkServiceAccessPoint) { + n.argSapID = &sapID + } +} + +func WithNetworkServiceAccessPointRouterSID(sid int) func(*NetworkServiceAccessPoint) { + return func(n *NetworkServiceAccessPoint) { + n.argSid = &sid + } +} + func (n *NetworkServiceAccessPoint) String() string { return fmt.Sprintf("NetworkServiceAccessPoint(TBD...)") // TODO: fill some info here } /* -bind creates a network adapter object and bind. +Bind creates a network adapter object and bind. bind(s, None, None) Called for simple applications, local network unknown, no specific @@ -226,7 +268,7 @@ bind creates a network adapter object and bind. Called for applications or routers, bind to the network, send up APDUs with a metching address. */ -func (n *NetworkServiceAccessPoint) bind(server _Server, net *uint16, address *Address) error { +func (n *NetworkServiceAccessPoint) Bind(server _Server, net *uint16, address *Address) error { n.log.Debug(). Interface("server", server). Interface("net", net). @@ -238,7 +280,7 @@ func (n *NetworkServiceAccessPoint) bind(server _Server, net *uint16, address *A return errors.Errorf("Allready bound: %v", net) } // create an adapter object, add it to our map - adapter, err := NewNetworkAdapter(n.log, n, net, address, nil) + adapter, err := NewNetworkAdapter(n.log, n, net, address) if err != nil { return errors.Wrap(err, "error creating adapter") } @@ -327,7 +369,7 @@ func (n *NetworkServiceAccessPoint) Indication(args Args, kwargs KWArgs) error { hopCount := uint8(0xff) // if this is route aware, use it for the destination - if settings.RouteAware && pduDestination.AddrRoute != nil { + if Settings.RouteAware && pduDestination.AddrRoute != nil { // always a local station for now, in theory this could also be // a local broadcast address, remote station, or remote broadcast // but that is not supported by the patterns @@ -639,7 +681,7 @@ func (n *NetworkServiceAccessPoint) ProcessNPDU(adapter *NetworkAdapter, pdu PDU } else { apdu.pduSource = sourceAddress } - if settings.RouteAware { + if Settings.RouteAware { apdu.pduSource.AddrRoute = pdu.GetPDUSource() } @@ -657,7 +699,7 @@ func (n *NetworkServiceAccessPoint) ProcessNPDU(adapter *NetworkAdapter, pdu PDU // combine the source address if npdu.GetControl().GetSourceSpecified() { apdu.pduSource = sourceAddress - if settings.RouteAware { + if Settings.RouteAware { n.log.Debug().Msg("adding route") apdu.pduSource = pdu.GetPDUSource() } @@ -906,7 +948,9 @@ func NewNetworkServiceElement(localLog zerolog.Logger, eid *int, startupDisabled log: localLog, } var err error - n.ApplicationServiceElement, err = NewApplicationServiceElement(localLog, eid, n) + n.ApplicationServiceElement, err = NewApplicationServiceElement(localLog, n, func(element *ApplicationServiceElement) { + element.elementID = eid + }) if err != nil { return nil, errors.Wrap(err, "error creating application service element") } diff --git a/plc4go/internal/bacnetip/Object.go b/plc4go/internal/bacnetip/Object.go index 742a16176a8..ef347e3d60e 100644 --- a/plc4go/internal/bacnetip/Object.go +++ b/plc4go/internal/bacnetip/Object.go @@ -26,3 +26,7 @@ func NewReadWritePropertyServices() (*ReadWritePropertyServices, error) { // TODO: implement me return nil, nil } + +type Property struct { + //TODO: implement me +} diff --git a/plc4go/internal/bacnetip/PDU.go b/plc4go/internal/bacnetip/PDU.go index 510a4813e48..301fa79137d 100644 --- a/plc4go/internal/bacnetip/PDU.go +++ b/plc4go/internal/bacnetip/PDU.go @@ -180,12 +180,16 @@ func (a *Address) decodeAddress(addr any) error { port := uint16(udpAddr.Port) a.AddrPort = &port addr.String() - case int: + 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) + } a.log.Debug().Msg("int") - if addr < 0 || addr > 255 { + if iaddr < 0 || iaddr > 255 { return errors.New("address out of range") } - a.AddrAddress = []byte{byte(addr)} + a.AddrAddress = []byte{byte(iaddr)} length := uint8(1) a.AddrLen = &length case []byte: @@ -323,14 +327,17 @@ func (a *Address) decodeAddress(addr any) error { a.AddrLen = &addrLen } - if !settings.RouteAware && (routeAddr != "" || routeIpAddr != "") { + if !Settings.RouteAware && (routeAddr != "" || routeIpAddr != "") { a.log.Warn().Msgf("route provided but not route aware: %v", addr) } if routeAddr != "" { if strings.HasPrefix(routeAddr, "0x") { - var err error - a.AddrRoute, err = NewAddress(a.log, routeAddr[2:]) + xtob, err := Xtob(routeAddr[2:]) + if err != nil { + return errors.Wrap(err, "can't parse route addr") + } + a.AddrRoute, err = NewAddress(a.log, xtob) if err != nil { return errors.Wrap(err, "can't parse route") } @@ -350,7 +357,8 @@ func (a *Address) decodeAddress(addr any) error { routeIpPort = "47808" } var err error - a.AddrRoute, err = NewAddress(a.log, routeIpAddr, routeIpPort) + tuple := &AddressTuple[string, string]{routeIpAddr, routeIpPort} + a.AddrRoute, err = NewAddress(a.log, tuple) if err != nil { return errors.Wrap(err, "can't create route") } @@ -360,19 +368,168 @@ func (a *Address) decodeAddress(addr any) error { } if ethernet_re.MatchString(addr) { - panic("implement me") // TODO: + a.log.Trace().Msg("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 } - // TODO: "^\d+$" - // TODO: "^\d+:[*]$" - // TODO: "^\d+:\d+$" - // TODO: "^0x([0-9A-Fa-f][0-9A-Fa-f])+$" - // TODO: "^X'([0-9A-Fa-f][0-9A-Fa-f])+'$" - // TODO: "^\d+:0x([0-9A-Fa-f][0-9A-Fa-f])+$" - // TODO: "^\d+:X'([0-9A-Fa-f][0-9A-Fa-f])+'$" + intR := regexp.MustCompile(`^\d+$`) + if intR.MatchString(addr) { + a.log.Trace().Msg("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) { + a.log.Trace().Msg("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) { + a.log.Trace().Msg("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) { + a.log.Trace().Msg("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) { + a.log.Trace().Msg("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) { + a.log.Trace().Msg("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) { + a.log.Trace().Msg("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) { - panic("implement me") // TODO: + a.log.Trace().Msg("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") @@ -401,6 +558,39 @@ func (a *Address) decodeAddress(addr any) error { 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} + a.log.Debug().Hex("addrstr", addrstr).Msg("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 @@ -470,7 +660,7 @@ func (a *Address) String() string { for i, address := range a.AddrAddress[0:4] { octests[i] = fmt.Sprintf("%d", address) } - result += fmt.Sprintf("%v:%v", strings.Join(octests, "."), port) + result += fmt.Sprintf("%v", strings.Join(octests, ".")) if port != 47808 { result += fmt.Sprintf(":%v", port) } @@ -479,9 +669,9 @@ func (a *Address) String() string { } } } else if a.AddrType == REMOTE_BROADCAST_ADDRESS { - result = fmt.Sprintf("%d", *a.AddrNet) + result = fmt.Sprintf("%d:*", *a.AddrNet) } else if a.AddrType == REMOTE_STATION_ADDRESS { - result = fmt.Sprintf("%d", *a.AddrNet) + result = fmt.Sprintf("%d:", *a.AddrNet) if a.AddrLen != nil && *a.AddrLen == 1 { result += fmt.Sprintf("%v", a.AddrAddress[0]) } else { @@ -491,7 +681,7 @@ func (a *Address) String() string { for i, address := range a.AddrAddress[0:4] { octests[i] = fmt.Sprintf("%d", address) } - result += fmt.Sprintf("%v:%v", strings.Join(octests, "."), port) + result += fmt.Sprintf("%v", strings.Join(octests, ".")) if port != 47808 { result += fmt.Sprintf(":%v", port) } @@ -506,7 +696,7 @@ func (a *Address) String() string { } if a.AddrRoute != nil { - result += fmt.Sprintf("@%v", *a.AddrRoute) + result += fmt.Sprintf("@%s", a.AddrRoute) } return result } @@ -643,10 +833,10 @@ func NewLocalBroadcast(route *Address) *Address { return l } -func NewRemoteBroadcast(net *uint16, route *Address) *Address { +func NewRemoteBroadcast(net uint16, route *Address) *Address { r := &Address{} r.AddrType = REMOTE_BROADCAST_ADDRESS - r.AddrNet = net + r.AddrNet = &net r.AddrRoute = route return r } diff --git a/plc4go/internal/bacnetip/Settings.go b/plc4go/internal/bacnetip/Settings.go index d27cc72c71f..96b894e277d 100644 --- a/plc4go/internal/bacnetip/Settings.go +++ b/plc4go/internal/bacnetip/Settings.go @@ -19,7 +19,7 @@ package bacnetip -type Settings struct { +type settings struct { Debug bool Color bool DebugFile string @@ -28,7 +28,7 @@ type Settings struct { RouteAware bool } -var settings = Settings{ +var Settings = settings{ Debug: false, Color: false, DebugFile: "", diff --git a/plc4go/internal/bacnetip/UDPCommunicationsModule.go b/plc4go/internal/bacnetip/UDPCommunicationsModule.go index 5bd77cc8387..489ff668b30 100644 --- a/plc4go/internal/bacnetip/UDPCommunicationsModule.go +++ b/plc4go/internal/bacnetip/UDPCommunicationsModule.go @@ -131,11 +131,15 @@ type UDPDirector struct { func NewUDPDirector(localLog zerolog.Logger, address AddressTuple[string, uint16], timeout *int, reuse *bool, sid *int, sapID *int) (*UDPDirector, error) { d := &UDPDirector{} var err error - d.Server, err = NewServer(localLog, sid, d) + d.Server, err = NewServer(localLog, d, func(server *Server) { + server.serverID = sid + }) if err != nil { return nil, errors.Wrap(err, "error creating server") } - d.ServiceAccessPoint, err = NewServiceAccessPoint(localLog, sapID, d) + d.ServiceAccessPoint, err = NewServiceAccessPoint(localLog, d, func(point *ServiceAccessPoint) { + point.serviceID = sapID + }) if err != nil { return nil, errors.Wrap(err, "error creating service access point") } diff --git a/plc4go/internal/bacnetip/debugging.go b/plc4go/internal/bacnetip/debugging.go index f430407e61d..5c11427494f 100644 --- a/plc4go/internal/bacnetip/debugging.go +++ b/plc4go/internal/bacnetip/debugging.go @@ -36,3 +36,7 @@ func Xtob(hexString string) ([]byte, error) { } return decodeString, nil } + +type DebugContents struct { + // TODO: implement me +} diff --git a/plc4go/internal/bacnetip/service/cov.go b/plc4go/internal/bacnetip/service/cov.go new file mode 100644 index 00000000000..1b080f2ac89 --- /dev/null +++ b/plc4go/internal/bacnetip/service/cov.go @@ -0,0 +1,84 @@ +/* + * 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 service + +import "github.com/apache/plc4x/plc4go/internal/bacnetip" + +type SubscriptionList struct { + //TODO: implement me +} + +type Subscription struct { + *bacnetip.OneShotTask + *bacnetip.DebugContents + //TODO: implement me +} + +type COVDetection struct { + *DetectionAlgorithm + //TODO: implement me +} + +type GenericCriteria struct { + *COVDetection + //TODO: implement me +} + +type COVIncrementCriteria struct { + *COVDetection + //TODO: implement me +} + +type AccessDoorCriteria struct { + *COVDetection + //TODO: implement me +} + +type AccessPointCriteria struct { + *COVDetection + //TODO: implement me +} + +type CredentialDataInputCriteria struct { + *COVDetection + //TODO: implement me +} + +type LoadControlCriteria struct { + *COVDetection + //TODO: implement me +} + +type PulseConverterCriteria struct { + *COVIncrementCriteria + //TODO: implement me +} + +var criteriaTypeMap any //TODO: implement me + +type ActiveCOVSubscription struct { + *bacnetip.Property + //TODO: implement me +} + +type ChangeOfValuesServices struct { + *bacnetip.Capability + //TODO: implement me +} diff --git a/plc4go/internal/bacnetip/service/detect.go b/plc4go/internal/bacnetip/service/detect.go new file mode 100644 index 00000000000..22d2d210a3a --- /dev/null +++ b/plc4go/internal/bacnetip/service/detect.go @@ -0,0 +1,24 @@ +/* + * 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 service + +type DetectionAlgorithm struct { + //TODO: implement me +} diff --git a/plc4go/internal/bacnetip/vlan.go b/plc4go/internal/bacnetip/vlan.go index 5eb955a0ad5..79042112be5 100644 --- a/plc4go/internal/bacnetip/vlan.go +++ b/plc4go/internal/bacnetip/vlan.go @@ -41,7 +41,8 @@ type NetworkNode interface { } type Network struct { - name string + name string + nodes []NetworkNode broadcastAddress *Address @@ -52,13 +53,37 @@ type Network struct { log zerolog.Logger } -func NewNetwork(name string, localLog zerolog.Logger, trafficLogger TrafficLogger, broadcastAddress *Address, dropPercent float32) *Network { - return &Network{ - name: name, - broadcastAddress: broadcastAddress, - dropPercent: dropPercent, - trafficLogger: trafficLogger, - log: localLog, +func NewNetwork(localLog zerolog.Logger, opts ...func(*Network)) *Network { + network := &Network{ + log: localLog, + } + for _, opt := range opts { + opt(network) + } + return network +} + +func WithNetworkName(name string) func(*Network) { + return func(n *Network) { + n.name = name + } +} + +func WithNetworkBroadcastAddress(broadcastAddress *Address) func(*Network) { + return func(n *Network) { + n.broadcastAddress = broadcastAddress + } +} + +func WithNetworkDropPercent(dropPercent float32) func(*Network) { + return func(n *Network) { + n.dropPercent = dropPercent + } +} + +func WithNetworkTrafficLogger(trafficLogger TrafficLogger) func(*Network) { + return func(n *Network) { + n.trafficLogger = trafficLogger } } @@ -147,18 +172,27 @@ type Node struct { promiscuous bool spoofing bool + // pass through args + argSid *int + log zerolog.Logger } -func NewNode(localLog zerolog.Logger, addr *Address, lan NodeNetworkReference, name string, promiscuous bool, spoofing bool, sid *int) (*Node, error) { +func NewNode(localLog zerolog.Logger, addr *Address, lan NodeNetworkReference, opts ...func(*Node)) (*Node, error) { n := &Node{ - lan: nil, address: addr, - name: name, - log: localLog.With().Str("name", name).Logger(), + log: localLog, + } + for _, opt := range opts { + opt(n) + } + if n.name == "" { + n.log = n.log.With().Str("name", n.name).Logger() } var err error - n.Server, err = NewServer(localLog, sid, n) + n.Server, err = NewServer(localLog, n, func(server *Server) { + server.serverID = n.argSid + }) if err != nil { return nil, errors.Wrap(err, "error creating server") } @@ -168,13 +202,33 @@ func NewNode(localLog zerolog.Logger, addr *Address, lan NodeNetworkReference, n n.bind(lan) } - // might receive all packets and might spoof - n.promiscuous = promiscuous - n.spoofing = spoofing - return n, nil } +func WithNodeName(name string) func(*Node) { + return func(n *Node) { + n.name = name + } +} + +func WithNodePromiscuous(promiscuous bool) func(*Node) { + return func(n *Node) { + n.promiscuous = promiscuous + } +} + +func WithNodeSpoofing(spoofing bool) func(*Node) { + return func(n *Node) { + n.spoofing = spoofing + } +} + +func WithNodeSid(sid int) func(*Node) { + return func(n *Node) { + n.argSid = &sid + } +} + func (n *Node) setLan(lan *Network) { n.lan = lan } @@ -246,9 +300,9 @@ type IPNetwork struct { *Network } -func NewIPNetwork(name string, localLog zerolog.Logger, trafficLogger TrafficLogger, broadcastAddress *Address, dropPercent float32) *IPNetwork { +func NewIPNetwork(localLog zerolog.Logger, opts ...func(*Network)) *IPNetwork { return &IPNetwork{ - Network: NewNetwork(name, localLog, trafficLogger, broadcastAddress, dropPercent), + Network: NewNetwork(localLog, opts...), } } @@ -283,18 +337,18 @@ type IPNode struct { addrBroadcastTuple *AddressTuple[string, uint16] } -func NewIPNode(localLog zerolog.Logger, addr *Address, lan *IPNetwork, promiscuous bool, spoofing bool, sid *int) (*IPNode, error) { +func NewIPNode(localLog zerolog.Logger, addr *Address, lan *IPNetwork, opts ...func(*Node)) (*IPNode, error) { i := &IPNode{ // save the address information addrTuple: addr.AddrTuple, addrBroadcastTuple: addr.AddrBroadcastTuple, } var err error - i.Node, err = NewNode(localLog, addr, nil, "", promiscuous, spoofing, sid) + i.Node, err = NewNode(localLog, addr, nil, opts...) if err != nil { return nil, errors.Wrap(err, "error creating node") } - i.bind(lan) // TODO: we bind here otherwise we bind the contained node + i.bind(lan) // bind here otherwise we bind the contained node return i, nil } @@ -315,21 +369,33 @@ type IPRouterNode struct { node *IPNode addrMask *uint32 addrSubnet *uint32 + + // pass through args + argCid *int + + log zerolog.Logger } -func NewIPRouterNode(localLog zerolog.Logger, cid *int, router *IPRouter, addr *Address, lan *IPNetwork) (*IPRouterNode, error) { +func NewIPRouterNode(localLog zerolog.Logger, router *IPRouter, addr *Address, lan *IPNetwork, opts ...func(*IPRouterNode)) (*IPRouterNode, error) { i := &IPRouterNode{ // save the references to the router for packets and the lan for debugging router: router, lan: lan, + + log: localLog, + } + for _, opt := range opts { + opt(i) } var err error - i.Client, err = NewClient(localLog, cid, i) + i.Client, err = NewClient(localLog, i, func(client *Client) { + client.clientID = i.argCid + }) if err != nil { return nil, errors.Wrap(err, "error building client") } // make ourselves an IPNode and bind to it - i.node, err = NewIPNode(localLog, addr, lan, true, true, nil) + i.node, err = NewIPNode(localLog, addr, lan, WithNodePromiscuous(true), WithNodeSpoofing(true)) if err != nil { return nil, errors.Wrap(err, "error building IPNode") } @@ -343,6 +409,12 @@ func NewIPRouterNode(localLog zerolog.Logger, cid *int, router *IPRouter, addr * return i, nil } +func WithIPRouterNodeCid(cid int) func(*IPRouterNode) { + return func(n *IPRouterNode) { + n.argCid = &cid + } +} + func (n *IPRouterNode) Confirmation(args Args, kwargs KWArgs) error { pdu := args.Get0PDU() n.log.Debug().Stringer("pdu", pdu).Msg("confirmation") @@ -374,7 +446,7 @@ func NewIPRouter(localLog zerolog.Logger) *IPRouter { func (n *IPRouter) AddNetwork(addr *Address, lan *IPNetwork) { n.log.Debug().Stringer("addr", addr).Stringer("lan", lan).Msg("adding network") - node, err := NewIPRouterNode(n.log, nil, n, addr, lan) + node, err := NewIPRouterNode(n.log, n, addr, lan) if err != nil { n.log.Error().Err(err).Msg("error creating IPRouterNode") return