Skip to content

Commit aece473

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 aece473

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-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: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
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+
retrans.Received(&msg, addr)
60+
go handleRequest(&msg, addr, l, rh, retrans)
61+
}
62+
}
63+
64+
return nil
65+
}
66+
67+
func handleRequest(msg *Message, addr *net.UDPAddr, s *net.UDPConn, rh RequestHandler, retrans *Retransmitter) {
68+
rq := UDPRequest{
69+
msg: msg,
70+
addr: addr,
71+
s: s,
72+
acked: false,
73+
retrans: retrans,
74+
}
75+
76+
rh.Handle(&rq)
77+
}
78+
79+
type UDPRequest struct {
80+
msg *Message
81+
addr *net.UDPAddr
82+
s *net.UDPConn
83+
acked bool
84+
retrans *Retransmitter
85+
}
86+
87+
func (rq *UDPRequest) Message() *Message {
88+
return rq.msg
89+
}
90+
91+
func (rq *UDPRequest) Addr() net.Addr {
92+
return rq.addr
93+
}
94+
95+
func (rq *UDPRequest) Ack() error {
96+
// if it's not an ackable message or it was already acked
97+
// just do nothing silently
98+
if rq.msg.Type != Confirmable || rq.acked {
99+
return nil
100+
}
101+
102+
ackMsg := Message{
103+
Type: Acknowledgement,
104+
Code: 0,
105+
MessageID: rq.msg.MessageID,
106+
Payload: nil,
107+
}
108+
109+
if err := Transmit(rq.s, rq.addr, ackMsg); err != nil {
110+
return err
111+
}
112+
rq.acked = true
113+
return nil
114+
}
115+
func (rq *UDPRequest) RespondCode(code COAPCode) error {
116+
return rq.Respond(code, []byte{}, nil)
117+
118+
}
119+
120+
func (rq *UDPRequest) Respond(code COAPCode, content []byte, contentType *MediaType) error {
121+
var msg Message
122+
123+
if rq.acked {
124+
// answer after ack
125+
// generate a new MID
126+
msg = Message{
127+
Type: NonConfirmable,
128+
Code: code,
129+
MessageID: nextMID,
130+
Payload: content,
131+
Token: rq.msg.Token,
132+
}
133+
nextMID = nextMID + 1
134+
} else {
135+
// piggybacked answer
136+
msg = Message{
137+
Type: Acknowledgement,
138+
Code: code,
139+
MessageID: rq.msg.MessageID,
140+
Payload: content,
141+
Token: rq.msg.Token,
142+
}
143+
}
144+
145+
return rq.retrans.Record(msg, rq.addr)
146+
}

0 commit comments

Comments
 (0)