Skip to content

Commit 7381536

Browse files
authored
fix of silently stop notifications (#183)
fixes #179 implemented according to https://tools.ietf.org/html/rfc7641#section-3.4
1 parent d99754a commit 7381536

File tree

4 files changed

+148
-10
lines changed

4 files changed

+148
-10
lines changed

net/observation/observation.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package observation
2+
3+
import (
4+
"time"
5+
)
6+
7+
// ObservationSequenceTimeout defines how long is sequence number is valid. https://tools.ietf.org/html/rfc7641#section-3.4
8+
const ObservationSequenceTimeout = 128 * time.Second
9+
10+
// ValidSequenceNumber implements conditions in https://tools.ietf.org/html/rfc7641#section-3.4
11+
func ValidSequenceNumber(old, new uint32, lastEventOccurs time.Time, now time.Time) bool {
12+
if old < new && (new-old) < (1<<23) {
13+
return true
14+
}
15+
if old > new && (old-new) > (1<<23) {
16+
return true
17+
}
18+
if now.Sub(lastEventOccurs) > ObservationSequenceTimeout {
19+
return true
20+
}
21+
return false
22+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package observation
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestValidSequenceNumber(t *testing.T) {
11+
type args struct {
12+
old uint32
13+
new uint32
14+
lastEventOccurs time.Time
15+
now time.Time
16+
}
17+
tests := []struct {
18+
name string
19+
args args
20+
want bool
21+
}{
22+
{
23+
name: "(1 << 25)-1, 0, now-1s, now",
24+
args: args{
25+
old: (1 << 25)-1,
26+
new: 0,
27+
lastEventOccurs: time.Now().Add(-time.Second),
28+
now: time.Now(),
29+
},
30+
want: true,
31+
},
32+
{
33+
name: "0, 1, 0, now",
34+
args: args{
35+
new: 1,
36+
now: time.Now(),
37+
},
38+
want: true,
39+
},
40+
{
41+
name: "1582, 1583, now-1s, now",
42+
args: args{
43+
old: 1582,
44+
new: 1583,
45+
lastEventOccurs: time.Now().Add(-time.Second),
46+
now: time.Now(),
47+
},
48+
want: true,
49+
},
50+
{
51+
name: "1582, 1, now-129s, now",
52+
args: args{
53+
old: 1582,
54+
new: 1,
55+
lastEventOccurs: time.Now().Add(-time.Second * 129),
56+
now: time.Now(),
57+
},
58+
want: true,
59+
},
60+
{
61+
name: "1582, 1, now-125s, now",
62+
args: args{
63+
old: 1582,
64+
new: 1,
65+
lastEventOccurs: time.Now().Add(-time.Second * 125),
66+
now: time.Now(),
67+
},
68+
want: false,
69+
},
70+
{
71+
name: "1 << 23, 0, now-1s, now",
72+
args: args{
73+
old: 1 << 23,
74+
new: 0,
75+
lastEventOccurs: time.Now().Add(-time.Second),
76+
now: time.Now(),
77+
},
78+
want: false,
79+
},
80+
{
81+
name: "0, 1 << 23+1, now-1s, now",
82+
args: args{
83+
old: 0,
84+
new: 1 << 23+1,
85+
lastEventOccurs: time.Now().Add(-time.Second),
86+
now: time.Now(),
87+
},
88+
want: false,
89+
},
90+
{
91+
name: "1582, 1582, now-1s, now",
92+
args: args{
93+
old: 1582,
94+
new: 1582,
95+
lastEventOccurs: time.Now().Add(-time.Second),
96+
now: time.Now(),
97+
},
98+
want: false,
99+
},
100+
}
101+
for _, tt := range tests {
102+
t.Run(tt.name, func(t *testing.T) {
103+
got := ValidSequenceNumber(tt.args.old, tt.args.new, tt.args.lastEventOccurs, tt.args.now)
104+
assert.Equal(t, tt.want, got)
105+
})
106+
}
107+
}

tcp/clientobserve.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import (
55
"fmt"
66
"sync"
77
"sync/atomic"
8+
"time"
89

910
"github.com/plgd-dev/go-coap/v2/message"
1011
"github.com/plgd-dev/go-coap/v2/message/codes"
12+
"github.com/plgd-dev/go-coap/v2/net/observation"
1113
"github.com/plgd-dev/go-coap/v2/tcp/message/pool"
1214
)
1315

@@ -18,6 +20,7 @@ type Observation struct {
1820
obsSequence uint32
1921
etag []byte
2022
cc *ClientConn
23+
lastEvent time.Time
2124

2225
mutex sync.Mutex
2326
}
@@ -67,16 +70,17 @@ func (o *Observation) wantBeNotified(r *pool.Message) bool {
6770
if err != nil {
6871
return true
6972
}
73+
now := time.Now()
7074

7175
o.mutex.Lock()
7276
defer o.mutex.Unlock()
73-
//obs starts with 0, after that check obsSequence
74-
if obsSequence != 0 && o.obsSequence > obsSequence {
75-
return false
77+
if observation.ValidSequenceNumber(o.obsSequence, obsSequence, o.lastEvent, now) {
78+
o.obsSequence = obsSequence
79+
o.lastEvent = now
80+
return true
7681
}
77-
o.obsSequence = obsSequence
7882

79-
return true
83+
return false
8084
}
8185

8286
// Observe subscribes for every change of resource on path.

udp/client/clientobserve.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import (
55
"fmt"
66
"sync"
77
"sync/atomic"
8+
"time"
89

910
"github.com/plgd-dev/go-coap/v2/message"
1011
"github.com/plgd-dev/go-coap/v2/message/codes"
12+
"github.com/plgd-dev/go-coap/v2/net/observation"
1113
"github.com/plgd-dev/go-coap/v2/udp/message/pool"
1214
)
1315

@@ -18,6 +20,7 @@ type Observation struct {
1820
obsSequence uint32
1921
etag []byte
2022
cc *ClientConn
23+
lastEvent time.Time
2124

2225
mutex sync.Mutex
2326
}
@@ -72,16 +75,18 @@ func (o *Observation) wantBeNotified(r *pool.Message) bool {
7275
if err != nil {
7376
return true
7477
}
78+
now := time.Now()
7579

7680
o.mutex.Lock()
7781
defer o.mutex.Unlock()
78-
//obs starts with 0, after that check obsSequence
79-
if obsSequence != 0 && o.obsSequence > obsSequence {
80-
return false
82+
83+
if observation.ValidSequenceNumber(o.obsSequence, obsSequence, o.lastEvent, now) {
84+
o.obsSequence = obsSequence
85+
o.lastEvent = now
86+
return true
8187
}
82-
o.obsSequence = obsSequence
8388

84-
return true
89+
return false
8590
}
8691

8792
// Observe subscribes for every change of resource on path.

0 commit comments

Comments
 (0)