Skip to content

Commit 1c39cd3

Browse files
committed
New server experiment fixing some design issues
Send response with the request token for matching query/answer. Add the capability to choose between piggy backend answer or seperate acking. Abstract request answering for being able to plug multiple transport (UDP, TCP, websockets, (D)TLS)
1 parent 7413cca commit 1c39cd3

File tree

2 files changed

+162
-0
lines changed

2 files changed

+162
-0
lines changed

example/newserver/coap_server.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package main
2+
3+
import (
4+
"log"
5+
6+
"github.com/dustin/go-coap"
7+
)
8+
9+
func main() {
10+
11+
log.Fatal(coap.UdpListenAndServe("udp", ":5683",
12+
coap.FuncRqHandler(func(rq coap.Request) error {
13+
log.Printf("Got message path=%q: %#v from %v", rq.Message().Path(), rq.Message(), rq.Addr())
14+
rq.Respond(coap.Content, []byte("Yeah!"), nil)
15+
return nil
16+
})))
17+
}

serverNew.go

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package coap
2+
3+
import (
4+
"log"
5+
"math/rand"
6+
"net"
7+
)
8+
9+
var nextMID uint16 = uint16(rand.Int())
10+
11+
type Request interface {
12+
Message() *Message
13+
Addr() net.Addr
14+
Ack() error
15+
16+
RespondCode(code COAPCode) error
17+
18+
Respond(code COAPCode, content []byte, contentType *MediaType) error
19+
}
20+
21+
type RequestHandler interface {
22+
// Handle the message and optionally return a response message.
23+
Handle(rq Request) error
24+
}
25+
type funcRqHandler func(rq Request) error
26+
27+
func (f funcRqHandler) Handle(rq Request) error {
28+
return f(rq)
29+
}
30+
31+
// FuncRqHandler builds a handler from a function.
32+
func FuncRqHandler(f func(rq Request) error) RequestHandler {
33+
return funcRqHandler(f)
34+
}
35+
36+
func UdpListenAndServe(n, addr string, rh RequestHandler) error {
37+
38+
uaddr, err := net.ResolveUDPAddr(n, addr)
39+
if err != nil {
40+
return err
41+
}
42+
43+
l, err := net.ListenUDP(n, uaddr)
44+
if err != nil {
45+
return err
46+
}
47+
48+
// init retransmission facilities
49+
retrans := NewRetransmitter(l)
50+
51+
buf := make([]byte, maxPktLen)
52+
for {
53+
nr, addr, err := l.ReadFromUDP(buf)
54+
if err == nil {
55+
msg, err := parseMessage(buf[:nr])
56+
if err != nil {
57+
log.Printf("Error parsing %v", err)
58+
}
59+
go handleRequest(&msg, addr, l, rh, retrans)
60+
}
61+
}
62+
63+
return nil
64+
}
65+
66+
func handleRequest(msg *Message, addr *net.UDPAddr, s *net.UDPConn, rh RequestHandler, retrans *Retransmitter) {
67+
rq := UDPRequest{
68+
msg: msg,
69+
addr: addr,
70+
s: s,
71+
acked: false,
72+
retrans: retrans,
73+
}
74+
75+
rh.Handle(&rq)
76+
}
77+
78+
type UDPRequest struct {
79+
msg *Message
80+
addr *net.UDPAddr
81+
s *net.UDPConn
82+
acked bool
83+
retrans *Retransmitter
84+
}
85+
86+
func (rq *UDPRequest) Message() *Message {
87+
return rq.msg
88+
}
89+
90+
func (rq *UDPRequest) Addr() net.Addr {
91+
return rq.addr
92+
}
93+
94+
func (rq *UDPRequest) Ack() error {
95+
// if it's not an ackable message or it was already acked
96+
// just do nothing silently
97+
if rq.msg.Type != Confirmable || rq.acked {
98+
return nil
99+
}
100+
101+
ackMsg := Message{
102+
Type: Acknowledgement,
103+
Code: 0,
104+
MessageID: rq.msg.MessageID,
105+
Payload: nil,
106+
}
107+
108+
if err := Transmit(rq.s, rq.addr, ackMsg); err != nil {
109+
return err
110+
}
111+
rq.acked = true
112+
return nil
113+
}
114+
func (rq *UDPRequest) RespondCode(code COAPCode) error {
115+
return rq.Respond(code, []byte{}, nil)
116+
117+
}
118+
119+
func (rq *UDPRequest) Respond(code COAPCode, content []byte, contentType *MediaType) error {
120+
var msg Message
121+
122+
if rq.acked {
123+
// answer after ack
124+
// generate a new MID
125+
msg = Message{
126+
Type: NonConfirmable,
127+
Code: code,
128+
MessageID: nextMID,
129+
Payload: content,
130+
Token: rq.msg.Token,
131+
}
132+
nextMID = nextMID + 1
133+
} else {
134+
// piggybacked answer
135+
msg = Message{
136+
Type: Acknowledgement,
137+
Code: code,
138+
MessageID: rq.msg.MessageID,
139+
Payload: content,
140+
Token: rq.msg.Token,
141+
}
142+
}
143+
144+
return rq.retrans.Record(msg, rq.addr)
145+
}

0 commit comments

Comments
 (0)