Skip to content

Commit

Permalink
Merge branch 'release/v0.1.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
DerAndereAndi committed Dec 8, 2022
2 parents c379d19 + 95d2904 commit d142ee7
Show file tree
Hide file tree
Showing 42 changed files with 3,330 additions and 204 deletions.
4 changes: 1 addition & 3 deletions cmd/evse/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,7 @@ func (h *evse) run() {
h.myService.Start()
// defer h.myService.Shutdown()

remoteService := service.ServiceDetails{
SKI: remoteSki,
}
remoteService := service.NewServiceDetails(remoteSki)
h.myService.PairRemoteService(remoteService)
}

Expand Down
4 changes: 1 addition & 3 deletions cmd/hems/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,7 @@ func (h *hems) run() {
h.myService.Start()
// defer h.myService.Shutdown()

remoteService := service.ServiceDetails{
SKI: remoteSki,
}
remoteService := service.NewServiceDetails(remoteSki)
h.myService.PairRemoteService(remoteService)
}

Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ require (
github.com/rickb777/plural v1.4.1 // indirect
github.com/stretchr/objx v0.5.0 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/net v0.2.0 // indirect
golang.org/x/sys v0.2.0 // indirect
golang.org/x/tools v0.3.0 // indirect
golang.org/x/net v0.3.0 // indirect
golang.org/x/sys v0.3.0 // indirect
golang.org/x/tools v0.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

Expand Down
14 changes: 7 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
Expand All @@ -60,18 +60,18 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4=
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
File renamed without changes.
35 changes: 35 additions & 0 deletions service/cert_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package service

import (
"crypto/x509"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)

func TestCertSuite(t *testing.T) {
suite.Run(t, new(CertSuite))
}

type CertSuite struct {
suite.Suite
}

func (c *CertSuite) Test_CreateCertificate() {
cert, err := CreateCertificate("", "Org", "DE", "CN")
assert.Nil(c.T(), err)
assert.NotNil(c.T(), cert)
}

func (c *CertSuite) Test_SkiFromCertificate() {
cert, err := CreateCertificate("", "Org", "DE", "CN")
assert.Nil(c.T(), err)

leaf, err := x509.ParseCertificate(cert.Certificate[0])
assert.Nil(c.T(), err)

ski, err := skiFromCertificate(leaf)
assert.Nil(c.T(), err)
assert.NotNil(c.T(), ski)
}
105 changes: 49 additions & 56 deletions service/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/enbility/eebus-go/ship"
"github.com/enbility/eebus-go/spine"
"github.com/enbility/eebus-go/spine/model"
"github.com/enbility/eebus-go/util"
"github.com/gorilla/websocket"
)

Expand Down Expand Up @@ -71,13 +70,13 @@ type connectionsHub struct {
serviceProvider serviceProvider

// The list of paired devices
pairedServices []ServiceDetails
pairedServices []*ServiceDetails

// The web server for handling incoming websocket connections
httpServer *http.Server

// Handling mDNS related tasks
mdns *mdns
mdns MdnsService

// the SPINE local device
spineLocalDevice *spine.DeviceLocalImpl
Expand All @@ -88,40 +87,38 @@ type connectionsHub struct {
muxMdns sync.Mutex
}

func newConnectionsHub(serviceProvider serviceProvider, spineLocalDevice *spine.DeviceLocalImpl, configuration *Configuration, localService *ServiceDetails) (*connectionsHub, error) {
func newConnectionsHub(serviceProvider serviceProvider, mdns MdnsService, spineLocalDevice *spine.DeviceLocalImpl, configuration *Configuration, localService *ServiceDetails) *connectionsHub {
hub := &connectionsHub{
connections: make(map[string]*ship.ShipConnection),
connectionAttemptCounter: make(map[string]int),
connectionAttemptRunning: make(map[string]bool),
pairedServices: make([]ServiceDetails, 0),
pairedServices: make([]*ServiceDetails, 0),
serviceProvider: serviceProvider,
spineLocalDevice: spineLocalDevice,
configuration: configuration,
localService: localService,
mdns: mdns,
}

localService.SKI = util.NormalizeSKI(localService.SKI)

mdns, err := newMDNS(localService.SKI, configuration)
if err != nil {
return nil, err
}

hub.mdns = mdns

return hub, nil
return hub
}

// start the ConnectionsHub with all its services
func (h *connectionsHub) start() {
// start mDNS
err := h.mdns.SetupMdnsService()
if err != nil {
logging.Log.Error("error during mdns setup:", err)
}

// start the websocket server
go func() {
if err := h.startWebsocketServer(); err != nil {
logging.Log.Error("error during websocket server starting:", err)
}
}()

if err := h.mdns.Announce(); err != nil {
if err := h.mdns.AnnounceMdnsEntry(); err != nil {
logging.Log.Error("error registering mDNS Service:", err)
}
}
Expand Down Expand Up @@ -171,7 +168,7 @@ func (h *connectionsHub) checkRestartMdnsSearch() {
if countPairedServices > countConnections {
// if this is not a CEM also start the mDNS announcement
if h.localService.deviceType != model.DeviceTypeTypeEnergyManagementSystem {
_ = h.mdns.Announce()
_ = h.mdns.AnnounceMdnsEntry()
}

logging.Log.Debug("restarting mdns search")
Expand Down Expand Up @@ -209,7 +206,7 @@ func (h *connectionsHub) registerConnection(connection *ship.ShipConnection) {

// shutdown mDNS if this is not a CEM
if h.localService.deviceType != model.DeviceTypeTypeEnergyManagementSystem {
h.mdns.Unannounce()
h.mdns.UnannounceMdnsEntry()
h.mdns.UnregisterMdnsSearch(h)
}
}
Expand All @@ -231,7 +228,7 @@ func (h *connectionsHub) shutdown() {
h.muxCon.Lock()
defer h.muxCon.Unlock()

h.mdns.shutdown()
h.mdns.ShutdownMdnsService()
for _, c := range h.connections {
c.CloseConnection(false, "")
}
Expand Down Expand Up @@ -328,31 +325,29 @@ func (h *connectionsHub) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}

ski = util.NormalizeSKI(ski)
logging.Log.Debug("incoming connection request from", ski)
// normalize the incoming SKI
remoteService := NewServiceDetails(ski)
logging.Log.Debug("incoming connection request from", remoteService.SKI())

// Check if the remote service is paired
_, err = h.PairedServiceForSKI(ski)
_, err = h.PairedServiceForSKI(remoteService.SKI())
if err != nil {
logging.Log.Debug("ski", ski, "is not paired, closing the connection")
return
}

remoteService := &ServiceDetails{
SKI: ski,
}
// check if we already know this remote service
if remoteS, err := h.PairedServiceForSKI(ski); err == nil {
if remoteS, err := h.PairedServiceForSKI(remoteService.SKI()); err == nil {
remoteService = remoteS
}

// don't allow a second connection
if !h.keepThisConnection(conn, true, remoteService.SKI) {
if !h.keepThisConnection(conn, true, remoteService) {
return
}

dataHandler := ship.NewWebsocketConnection(conn, remoteService.SKI)
shipConnection := ship.NewConnectionHandler(h, dataHandler, h.spineLocalDevice, ship.ShipRoleServer, h.localService.ShipID, remoteService.SKI, remoteService.ShipID)
dataHandler := ship.NewWebsocketConnection(conn, remoteService.SKI())
shipConnection := ship.NewConnectionHandler(h, dataHandler, h.spineLocalDevice, ship.ShipRoleServer, h.localService.ShipID(), remoteService.SKI(), remoteService.ShipID())
shipConnection.Run()

h.registerConnection(shipConnection)
Expand All @@ -362,7 +357,7 @@ func (h *connectionsHub) ServeHTTP(w http.ResponseWriter, r *http.Request) {
//
// returns error contains a reason for failing the connection or nil if no further tries should be processed
func (h *connectionsHub) connectFoundService(remoteService *ServiceDetails, host, port string) error {
if h.isSkiConnected(remoteService.SKI) {
if h.isSkiConnected(remoteService.SKI()) {
return nil
}

Expand Down Expand Up @@ -391,33 +386,33 @@ func (h *connectionsHub) connectFoundService(remoteService *ServiceDetails, host

if len(remoteCerts) == 0 || remoteCerts[0].SubjectKeyId == nil {
// Close connection as we couldn't get the remote SKI
errorString := fmt.Sprintf("closing connection to %s: could not get remote SKI from certificate", remoteService.SKI)
errorString := fmt.Sprintf("closing connection to %s: could not get remote SKI from certificate", remoteService.SKI())
conn.Close()
return errors.New(errorString)
}

if _, err := skiFromCertificate(remoteCerts[0]); err != nil {
// Close connection as the remote SKI can't be correct
errorString := fmt.Sprintf("closing connection to %s: %s", remoteService.SKI, err)
errorString := fmt.Sprintf("closing connection to %s: %s", remoteService.SKI(), err)
conn.Close()
return errors.New(errorString)
}

remoteSKI := fmt.Sprintf("%0x", remoteCerts[0].SubjectKeyId)

if remoteSKI != remoteService.SKI {
errorString := fmt.Sprintf("closing connection to %s: SKI does not match %s", remoteService.SKI, remoteSKI)
if remoteSKI != remoteService.SKI() {
errorString := fmt.Sprintf("closing connection to %s: SKI does not match %s", remoteService.SKI(), remoteSKI)
conn.Close()
return errors.New(errorString)
}

if !h.keepThisConnection(conn, false, remoteService.SKI) {
errorString := fmt.Sprintf("closing connection to %s: ignoring this connection", remoteService.SKI)
if !h.keepThisConnection(conn, false, remoteService) {
errorString := fmt.Sprintf("closing connection to %s: ignoring this connection", remoteService.SKI())
return errors.New(errorString)
}

dataHandler := ship.NewWebsocketConnection(conn, remoteService.SKI)
shipConnection := ship.NewConnectionHandler(h, dataHandler, h.spineLocalDevice, ship.ShipRoleClient, h.localService.ShipID, remoteService.SKI, remoteService.ShipID)
dataHandler := ship.NewWebsocketConnection(conn, remoteService.SKI())
shipConnection := ship.NewConnectionHandler(h, dataHandler, h.spineLocalDevice, ship.ShipRoleClient, h.localService.ShipID(), remoteService.SKI(), remoteService.ShipID())
shipConnection.Run()

h.registerConnection(shipConnection)
Expand All @@ -430,7 +425,7 @@ func (h *connectionsHub) connectFoundService(remoteService *ServiceDetails, host
//
// returns true if this connection is fine to be continue
// returns false if this connection should not be established or kept
func (h *connectionsHub) keepThisConnection(conn *websocket.Conn, incomingRequest bool, remoteSKI string) bool {
func (h *connectionsHub) keepThisConnection(conn *websocket.Conn, incomingRequest bool, remoteService *ServiceDetails) bool {
// SHIP 12.2.2 defines:
// prevent double connections with SKI Comparison
// the node with the hight SKI value kees the most recent connection and
Expand All @@ -439,16 +434,17 @@ func (h *connectionsHub) keepThisConnection(conn *websocket.Conn, incomingReques
// This is hard to implement without any flaws. Therefor I chose a
// different approach: The connection initiated by the higher SKI will be kept

remoteSKI := remoteService.SKI()
existingC := h.connectionForSKI(remoteSKI)
if existingC == nil {
return true
}

keep := false
if incomingRequest {
keep = remoteSKI > h.localService.SKI
keep = remoteSKI > h.localService.SKI()
} else {
keep = h.localService.SKI > remoteSKI
keep = h.localService.SKI() > remoteSKI
}

if keep {
Expand All @@ -475,29 +471,26 @@ func (h *connectionsHub) keepThisConnection(conn *websocket.Conn, incomingReques
func (h *connectionsHub) PairedServiceForSKI(ski string) (*ServiceDetails, error) {
h.muxReg.Lock()
defer h.muxReg.Unlock()

for _, service := range h.pairedServices {
if service.SKI == ski {
return &service, nil
if service.SKI() == ski {
return service, nil
}
}
return &ServiceDetails{}, fmt.Errorf("no registered service found for SKI %s", ski)
return nil, fmt.Errorf("no registered service found for SKI %s", ski)
}

// Adds a new device to the list of known devices which can be connected to
// and connect it if it is currently not connected
func (h *connectionsHub) PairRemoteService(service ServiceDetails) {

// standardize the provided SKI strings
service.SKI = util.NormalizeSKI(service.SKI)

func (h *connectionsHub) PairRemoteService(service *ServiceDetails) {
// check if it is already registered
if _, err := h.PairedServiceForSKI(service.SKI); err != nil {
if _, err := h.PairedServiceForSKI(service.SKI()); err != nil {
h.muxReg.Lock()
h.pairedServices = append(h.pairedServices, service)
h.muxReg.Unlock()
}

if !h.isSkiConnected(service.SKI) {
if !h.isSkiConnected(service.SKI()) {
h.mdns.RegisterMdnsSearch(h)
}
}
Expand All @@ -507,11 +500,11 @@ func (h *connectionsHub) PairRemoteService(service ServiceDetails) {
func (h *connectionsHub) UnpairRemoteService(ski string) error {
h.removeConnectionAttemptCounter(ski)

newRegisteredDevice := make([]ServiceDetails, 0)
newRegisteredDevice := make([]*ServiceDetails, 0)

h.muxReg.Lock()
for _, device := range h.pairedServices {
if device.SKI != ski {
if device.SKI() != ski {
newRegisteredDevice = append(newRegisteredDevice, device)
}
}
Expand Down Expand Up @@ -543,8 +536,8 @@ func (h *connectionsHub) ReportMdnsEntries(entries map[string]MdnsEntry) {
}

// patch the addresses list if an IPv4 address was provided
if remoteService.IPv4 != "" {
if ip := net.ParseIP(remoteService.IPv4); ip != nil {
if remoteService.IPv4() != "" {
if ip := net.ParseIP(remoteService.IPv4()); ip != nil {
entry.Addresses = []net.IP{ip}
}
}
Expand Down Expand Up @@ -682,7 +675,7 @@ func (h *connectionsHub) getConnectionInitiationDelayTime(ski string) (int, time

// seed with the local SKI for initializing rand
i := new(big.Int)
hex := fmt.Sprintf("0x%s", h.localService.SKI)
hex := fmt.Sprintf("0x%s", h.localService.SKI())
if _, err := fmt.Sscan(hex, i); err == nil {
rand.Seed(i.Int64() + time.Now().UnixNano())
} else {
Expand Down
Loading

0 comments on commit d142ee7

Please sign in to comment.